| /** @file |
| |
| @section license License |
| |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| */ |
| #pragma once |
| |
| #include <iostream> |
| #include <string_view> |
| #include <yaml-cpp/yaml.h> |
| |
| #include "jsonrpc/CtrlRPCRequests.h" |
| #include "jsonrpc/ctrl_yaml_codecs.h" |
| #include "shared/rpc/RPCRequests.h" |
| #include <swoc/BufferWriter.h> |
| |
| /** Format wrapper for floating point time stamps represented as strings. |
| * If the time isn't provided, the current epoch time is used. If the format string isn't |
| * provided a format like "2017 Jun 29 14:11:29" is used. |
| */ |
| struct FloatDate { |
| std::string_view _src; |
| std::string_view _fmt; |
| |
| /** Constructor. |
| * |
| * @param src A string's representation of a floating point timestamp. |
| * @param fmt The format specification for the date string. |
| */ |
| FloatDate(std::string_view src, std::string_view fmt) : _src{src}, _fmt{fmt} {} |
| }; |
| |
| /** Format a timestamp wrapped in a @c FloatDate. |
| * |
| * @param w Output. |
| * @param spec Format specifier. |
| * @param wrap Timestamp string_view wrapper. |
| * @return @a w |
| */ |
| swoc::BufferWriter &bwformat(swoc::BufferWriter &w, swoc::bwf::Spec const &spec, FloatDate const &wrap); |
| |
| //------------------------------------------------------------------------------------------------------------------------------------ |
| /// |
| /// Base class that implements the basic output format. |
| /// |
| /// Every command will print out specific details depending on the nature of the message. This base class models the basic API. |
| /// @c _format member should be set when the object is created, this member should be used to decide the way we want to generate |
| /// the output and possibly(TODO) where we want it(stdout, stderr, etc.). If no output is needed GenericPrinter can be used which is |
| /// muted. |
| class BasePrinter |
| { |
| public: |
| /// This enum maps the --format flag coming from traffic_ctl. (also --records is included here, see comments down below.) |
| struct Options { |
| enum FormatFlags { |
| NOT_SET = 0, // nothing set. |
| JSON = 1 << 0, // Json formatting |
| RECORDS = 1 << 1, // only valid for configs, but it's handy to have it here. |
| RPC = 1 << 2, // Print JSONRPC request and response + default output. |
| SHOW_DEFAULT = 1 << 3 // Add the default values alongside with the actual value. |
| }; |
| Options() = default; |
| Options(FormatFlags flags) : _format(flags) {} |
| mutable FormatFlags _format{FormatFlags::NOT_SET}; //!< selected(passed) format. |
| }; |
| |
| /// Printer constructor. Needs the format as it will be used by derived classes. |
| BasePrinter(Options opts) : _printOpt(opts) {} |
| |
| BasePrinter() = default; |
| virtual ~BasePrinter() = default; |
| |
| /// |
| /// Function that will generate the expected output based on the response result. |
| /// |
| /// If the response contains any high level error, it will be print and the the specific derived class @c write_output() will not |
| /// be called. |
| /// @param response the server response. |
| /// |
| /// @note If there is an error, App_Exit_Status_Code will be set to CTRL_EX_ERROR. |
| /// |
| void write_output(shared::rpc::JSONRPCResponse const &response); |
| |
| /// |
| /// Write output based on the response values. |
| /// |
| /// Implement this one so you deal with the expected output, @c _format will be already set to the right |
| /// selected type so you can decide what to print. |
| /// |
| /// @param result jsonrpc result structure. No format specified by us, it's the one specified by the actual jsonrpc |
| /// response. |
| /// |
| virtual void write_output(YAML::Node const &result) = 0; |
| |
| virtual void write_output(std::string_view output) const; |
| virtual void write_debug(std::string_view output) const; |
| |
| /// FormatFlags getters. |
| Options::FormatFlags get_format() const; |
| bool print_rpc_message() const; |
| bool is_json_format() const; |
| void disable_json_format(); |
| |
| bool is_records_format() const; |
| bool should_include_default() const; |
| |
| /// In case a derived class needs to call derived class functions. Ugly but works. |
| /// Note: CRTP may worth a try. |
| template <typename Derived> // TODO, move it down the file. |
| const Derived *as() const; |
| template <typename Derived> Derived *as(); |
| |
| protected: |
| void write_output_json(YAML::Node const &node) const; |
| Options _printOpt; |
| }; |
| |
| constexpr enum BasePrinter::Options::FormatFlags |
| operator|(const enum BasePrinter::Options::FormatFlags rhs, const enum BasePrinter::Options::FormatFlags lhs) |
| { |
| return static_cast<BasePrinter::Options::FormatFlags>(static_cast<uint32_t>(rhs) | static_cast<uint32_t>(lhs)); |
| } |
| |
| constexpr enum BasePrinter::Options::FormatFlags & |
| operator|=(BasePrinter::Options::FormatFlags &rhs, BasePrinter::Options::FormatFlags lhs) |
| { |
| return rhs = rhs | lhs; |
| } |
| |
| constexpr enum BasePrinter::Options::FormatFlags |
| operator&(BasePrinter::Options::FormatFlags rhs, BasePrinter::Options::FormatFlags lhs) |
| { |
| return static_cast<BasePrinter::Options::FormatFlags>(static_cast<uint32_t>(rhs) & static_cast<uint32_t>(lhs)); |
| } |
| |
| inline BasePrinter::Options::FormatFlags |
| BasePrinter::get_format() const |
| { |
| return _printOpt._format; |
| } |
| |
| inline bool |
| BasePrinter::print_rpc_message() const |
| { |
| return _printOpt._format & Options::FormatFlags::RPC; |
| } |
| |
| inline bool |
| BasePrinter::is_json_format() const |
| { |
| return _printOpt._format & Options::FormatFlags::JSON; |
| } |
| |
| inline void |
| BasePrinter::disable_json_format() |
| { |
| _printOpt._format = static_cast<Options::FormatFlags>(_printOpt._format & ~Options::FormatFlags::JSON); |
| } |
| |
| inline bool |
| BasePrinter::is_records_format() const |
| { |
| return _printOpt._format & Options::FormatFlags::RECORDS; |
| } |
| inline bool |
| BasePrinter::should_include_default() const |
| { |
| return _printOpt._format & Options::FormatFlags::SHOW_DEFAULT; |
| } |
| //------------------------------------------------------------------------------------------------------------------------------------ |
| class GenericPrinter : public BasePrinter |
| { |
| void |
| write_output([[maybe_unused]] YAML::Node const &result) override |
| { |
| /* muted */ |
| } |
| |
| public: |
| GenericPrinter(BasePrinter::Options opt) : BasePrinter(opt) {} |
| }; |
| //------------------------------------------------------------------------------------------------------------------------------------ |
| class RecordPrinter : public BasePrinter |
| { |
| void write_output(YAML::Node const &result) override; |
| |
| public: |
| RecordPrinter(Options opt) : BasePrinter(opt) {} |
| |
| protected: |
| }; |
| |
| class MetricRecordPrinter : public BasePrinter |
| { |
| void write_output(YAML::Node const &result) override; |
| |
| public: |
| MetricRecordPrinter(BasePrinter::Options opt) : BasePrinter(opt) {} |
| }; |
| //------------------------------------------------------------------------------------------------------------------------------------ |
| class DiffConfigPrinter : public RecordPrinter |
| { |
| void write_output(YAML::Node const &result) override; |
| |
| public: |
| DiffConfigPrinter(BasePrinter::Options opt) : RecordPrinter(opt) {} |
| }; |
| //------------------------------------------------------------------------------------------------------------------------------------ |
| class ConfigReloadPrinter : public BasePrinter |
| { |
| void write_output(YAML::Node const &result) override; |
| |
| DiagsLevel _min_level{DL_Undefined}; |
| |
| public: |
| ConfigReloadPrinter(BasePrinter::Options opt) : BasePrinter(opt) {} |
| |
| void |
| set_min_level(DiagsLevel level) |
| { |
| _min_level = level; |
| } |
| DiagsLevel |
| min_level() const |
| { |
| return _min_level; |
| } |
| |
| void print_reload_report(const ConfigReloadResponse::ReloadInfo &info, bool full_report = false); |
| void write_progress_line(const ConfigReloadResponse::ReloadInfo &info); |
| }; |
| //------------------------------------------------------------------------------------------------------------------------------------ |
| class ConfigShowFileRegistryPrinter : public BasePrinter |
| { |
| void write_output(YAML::Node const &result) override; |
| |
| public: |
| using BasePrinter::BasePrinter; |
| }; |
| //------------------------------------------------------------------------------------------------------------------------------------ |
| class ConfigSetPrinter : public BasePrinter |
| { |
| void write_output(YAML::Node const &result) override; |
| |
| public: |
| using BasePrinter::BasePrinter; |
| }; |
| //------------------------------------------------------------------------------------------------------------------------------------ |
| class ConfigStatusPrinter : public BasePrinter |
| { |
| void write_output(YAML::Node const &result) override; |
| |
| public: |
| using BasePrinter::BasePrinter; |
| }; |
| //------------------------------------------------------------------------------------------------------------------------------------ |
| class RecordDescribePrinter : public BasePrinter |
| { |
| void write_output(YAML::Node const &result) override; |
| |
| public: |
| RecordDescribePrinter(BasePrinter::Options opt) : BasePrinter(opt) {} |
| }; |
| //------------------------------------------------------------------------------------------------------------------------------------ |
| class GetHostStatusPrinter : public BasePrinter |
| { |
| void write_output(YAML::Node const &result) override; |
| |
| public: |
| GetHostStatusPrinter(BasePrinter::Options opt) : BasePrinter(opt) {} |
| }; |
| //------------------------------------------------------------------------------------------------------------------------------------ |
| class SetHostStatusPrinter : public BasePrinter |
| { |
| void write_output(YAML::Node const &result) override; |
| |
| public: |
| SetHostStatusPrinter(BasePrinter::Options opt) : BasePrinter(opt) {} |
| }; |
| //------------------------------------------------------------------------------------------------------------------------------------ |
| class HostDBStatusPrinter : public BasePrinter |
| { |
| void write_output(YAML::Node const &result) override; |
| |
| public: |
| HostDBStatusPrinter(BasePrinter::Options opt) : BasePrinter(opt) {} |
| }; |
| //------------------------------------------------------------------------------------------------------------------------------------ |
| class CacheDiskStoragePrinter : public BasePrinter |
| { |
| void write_output(YAML::Node const &result) override; |
| |
| public: |
| CacheDiskStoragePrinter(BasePrinter::Options opt) : BasePrinter(opt) {} |
| }; |
| //------------------------------------------------------------------------------------------------------------------------------------ |
| class CacheDiskStorageOfflinePrinter : public BasePrinter |
| { |
| void write_output(YAML::Node const &result) override; |
| |
| public: |
| CacheDiskStorageOfflinePrinter(BasePrinter::Options opt) : BasePrinter(opt) {} |
| }; |
| //------------------------------------------------------------------------------------------------------------------------------------ |
| class RPCAPIPrinter : public BasePrinter |
| { |
| void write_output(YAML::Node const &result) override; |
| |
| public: |
| RPCAPIPrinter(BasePrinter::Options opt) : BasePrinter(opt) {} |
| }; |
| //------------------------------------------------------------------------------------------------------------------------------------ |
| class ServerStatusPrinter : public BasePrinter |
| { |
| void write_output(YAML::Node const &result) override; |
| |
| public: |
| ServerStatusPrinter(BasePrinter::Options opt) : BasePrinter(opt) {} |
| }; |
| //------------------------------------------------------------------------------------------------------------------------------------ |
| class PluginListPrinter : public BasePrinter |
| { |
| void write_output(YAML::Node const &result) override; |
| |
| public: |
| PluginListPrinter(BasePrinter::Options opt) : BasePrinter(opt) {} |
| }; |
| //------------------------------------------------------------------------------------------------------------------------------------ |
| |
| /// In case a derived class needs to call derived class functions. Ugly but works. |
| /// Note: CRTP may worth a try. |
| template <typename Derived> // TODO, move it down the file. |
| const Derived * |
| BasePrinter::as() const |
| { |
| auto r = dynamic_cast<const Derived *>(this); |
| if (!r) { |
| throw std::runtime_error("Internal error: Couldn't get Derived instance"); |
| } |
| return r; |
| } |
| template <typename Derived> |
| Derived * |
| BasePrinter::as() |
| { |
| auto r = dynamic_cast<Derived *>(this); |
| if (!r) { |
| throw std::runtime_error("Internal error: Couldn't get Derived instance"); |
| } |
| return r; |
| } |