From ed8433f67ce81a9c7edf4a06c29d7fe0c13cd1cc Mon Sep 17 00:00:00 2001 From: Siva Renganathan Date: Tue, 18 Jan 2022 20:51:58 +0530 Subject: [PATCH 1/2] Human readable timestamp for traffic_ctl config status This converts the date from the traffic_ctl config status from epoch to a datetime representation, making it human readable. --- src/traffic_ctl/CtrlCommands.cc | 2 +- src/traffic_ctl/CtrlPrinters.cc | 83 +++++++++++++++++++++++---------- src/traffic_ctl/CtrlPrinters.h | 8 ++++ 3 files changed, 67 insertions(+), 26 deletions(-) diff --git a/src/traffic_ctl/CtrlCommands.cc b/src/traffic_ctl/CtrlCommands.cc index cbfbdb41c4b..94f8ce82f31 100644 --- a/src/traffic_ctl/CtrlCommands.cc +++ b/src/traffic_ctl/CtrlCommands.cc @@ -136,7 +136,7 @@ ConfigCommand::ConfigCommand(ts::Arguments *args) : RecordCommand(args) _printer = std::make_unique(printOpts); _invoked_func = [&]() { config_set(); }; } else if (args->get(STATUS_STR)) { - _printer = std::make_unique(printOpts); + _printer = std::make_unique(printOpts); _invoked_func = [&]() { config_status(); }; } else if (args->get(RELOAD_STR)) { _printer = std::make_unique(printOpts); diff --git a/src/traffic_ctl/CtrlPrinters.cc b/src/traffic_ctl/CtrlPrinters.cc index 900d1232f71..b4f8e20c07c 100644 --- a/src/traffic_ctl/CtrlPrinters.cc +++ b/src/traffic_ctl/CtrlPrinters.cc @@ -25,7 +25,9 @@ #include "jsonrpc/ctrl_yaml_codecs.h" #include "tscpp/util/ts_meta.h" -#include +#include +#include +#include #include "PrintUtils.h" //------------------------------------------------------------------------------------------------------------------------------------ @@ -116,8 +118,8 @@ RecordPrinter::write_output_legacy(shared::rpc::RecordLookUpResponse const &resp if (!_printAsRecords) { std::cout << recordInfo.name << ": " << recordInfo.currentValue << '\n'; } else { - std::cout << ts::bwprint(text, "{} {} {} {} # default: {}\n", rec_labelof(recordInfo.rclass), recordInfo.name, - recordInfo.dataType, recordInfo.currentValue, recordInfo.defaultValue); + std::cout << swoc::bwprint(text, "{} {} {} {} # default: {}\n", rec_labelof(recordInfo.rclass), recordInfo.name, + recordInfo.dataType, recordInfo.currentValue, recordInfo.defaultValue); } } // we print errors if found. @@ -150,12 +152,12 @@ DiffConfigPrinter::write_output(YAML::Node const &result) const bool hasChanged = (currentValue != defaultValue); if (hasChanged) { if (!_printAsRecords) { - std::cout << ts::bwprint(text, "{} has changed\n", recordInfo.name); - std::cout << ts::bwprint(text, "\tCurrent Value: {}\n", currentValue); - std::cout << ts::bwprint(text, "\tDefault Value: {}\n", defaultValue); + std::cout << swoc::bwprint(text, "{} has changed\n", recordInfo.name); + std::cout << swoc::bwprint(text, "\tCurrent Value: {}\n", currentValue); + std::cout << swoc::bwprint(text, "\tDefault Value: {}\n", defaultValue); } else { - std::cout << ts::bwprint(text, "{} {} {} {} # default: {}\n", rec_labelof(recordInfo.rclass), recordInfo.name, - recordInfo.dataType, recordInfo.currentValue, recordInfo.defaultValue); + std::cout << swoc::bwprint(text, "{} {} {} {} # default: {}\n", rec_labelof(recordInfo.rclass), recordInfo.name, + recordInfo.dataType, recordInfo.currentValue, recordInfo.defaultValue); } } } @@ -208,14 +210,45 @@ ConfigSetPrinter::write_output(YAML::Node const &result) for (auto &&updatedRec : response.data) { if (auto search = Update_Type_To_String_Message.find(updatedRec.updateType); search != std::end(Update_Type_To_String_Message)) { - std::cout << ts::bwprint(text, search->second, updatedRec.recName) << '\n'; + std::cout << swoc::bwprint(text, search->second, updatedRec.recName) << '\n'; } else { std::cout << "Oops we don't know how to handle the update status for '" << updatedRec.recName << "' [" << updatedRec.updateType << "]\n"; } } } catch (std::exception const &ex) { - std::cout << ts::bwprint(text, "Unexpected error found {}", ex.what()); + std::cout << swoc::bwprint(text, "Unexpected error found {}", ex.what()); + } +} +//----------------------------------------------------------------------------------------------------------------------------------- + +void +ConfigStatusPrinter::write_output(YAML::Node const &result) +{ + auto const &response = result.as(); + std::string text, recordName; + try { + for (auto &&recordInfo : response.recordList) { + recordName = recordInfo.name; + if (recordName == "proxy.process.version.server.long") { + std::cout << "Version: " << recordInfo.currentValue << "\n"; + } else if (recordName == "proxy.node.restarts.proxy.start_time") { + std::cout << swoc::bwprint( + text, "{}: {}\n", "Started at", + swoc::bwf::Date(static_cast(std::stod(recordInfo.currentValue)), "%a %d %b %Y %H:%M:%S")); + } else if (recordName == "proxy.node.config.reconfigure_time") { + std::cout << swoc::bwprint( + text, "{}: {}\n", "Reconfigured at", + swoc::bwf::Date(static_cast(std::stod(recordInfo.currentValue)), "%a %d %b %Y %H:%M:%S")); + } else if (recordName == "proxy.node.config.reconfigure_required") { + std::cout << "Reconfigure required: " << ((recordInfo.currentValue == "1") ? "yes" : "no") << "\n"; + } else if (recordName == "proxy.node.config.restart_required.proxy") { + std::cout << "Restart required: " << ((recordInfo.currentValue == "1") ? "yes" : "no") << "\n"; + } + } + } catch (...) { + std::cout << recordName << ": " + << "\n"; } } //------------------------------------------------------------------------------------------------------------------------------------ @@ -240,33 +273,33 @@ RecordDescribePrinter::write_output_legacy(shared::rpc::RecordLookUpResponse con << ": Unrecognized configuration value. Record is a configuration name/value but is not registered\n"; continue; } - std::cout << ts::bwprint(text, "{:16s}: {}\n", "Name", recordInfo.name); - std::cout << ts::bwprint(text, "{:16s}: {}\n", "Current Value ", recordInfo.currentValue); - std::cout << ts::bwprint(text, "{:16s}: {}\n", "Default Value ", recordInfo.defaultValue); - std::cout << ts::bwprint(text, "{:16s}: {}\n", "Record Type ", rec_labelof(recordInfo.rclass)); - std::cout << ts::bwprint(text, "{:16s}: {}\n", "Data Type ", recordInfo.dataType); + std::cout << swoc::bwprint(text, "{:16s}: {}\n", "Name", recordInfo.name); + std::cout << swoc::bwprint(text, "{:16s}: {}\n", "Current Value ", recordInfo.currentValue); + std::cout << swoc::bwprint(text, "{:16s}: {}\n", "Default Value ", recordInfo.defaultValue); + std::cout << swoc::bwprint(text, "{:16s}: {}\n", "Record Type ", rec_labelof(recordInfo.rclass)); + std::cout << swoc::bwprint(text, "{:16s}: {}\n", "Data Type ", recordInfo.dataType); std::visit(ts::meta::overloaded{ [&](shared::rpc::RecordLookUpResponse::RecordParamInfo::ConfigMeta const &meta) { - std::cout << ts::bwprint(text, "{:16s}: {}\n", "Access Control ", rec_accessof(meta.accessType)); - std::cout << ts::bwprint(text, "{:16s}: {}\n", "Update Type ", rec_updateof(meta.updateType)); - std::cout << ts::bwprint(text, "{:16s}: {}\n", "Update Status ", meta.updateStatus); - std::cout << ts::bwprint(text, "{:16s}: {}\n", "Source ", rec_sourceof(meta.source)); + std::cout << swoc::bwprint(text, "{:16s}: {}\n", "Access Control ", rec_accessof(meta.accessType)); + std::cout << swoc::bwprint(text, "{:16s}: {}\n", "Update Type ", rec_updateof(meta.updateType)); + std::cout << swoc::bwprint(text, "{:16s}: {}\n", "Update Status ", meta.updateStatus); + std::cout << swoc::bwprint(text, "{:16s}: {}\n", "Source ", rec_sourceof(meta.source)); - std::cout << ts::bwprint(text, "{:16s}: {}\n", "Syntax Check ", meta.checkExpr); + std::cout << swoc::bwprint(text, "{:16s}: {}\n", "Syntax Check ", meta.checkExpr); }, [&](shared::rpc::RecordLookUpResponse::RecordParamInfo::StatMeta const &meta) { // This may not be what we want, as for a metric we may not need to print all the same info. In that case // just create a new printer for this. - std::cout << ts::bwprint(text, "{:16s}: {}\n", "Persist Type ", meta.persistType); + std::cout << swoc::bwprint(text, "{:16s}: {}\n", "Persist Type ", meta.persistType); }, }, recordInfo.meta); - std::cout << ts::bwprint(text, "{:16s}: {}\n", "Overridable", (recordInfo.overridable ? "yes" : "no")); - std::cout << ts::bwprint(text, "{:16s}: {}\n", "Version ", recordInfo.version); - std::cout << ts::bwprint(text, "{:16s}: {}\n", "Order ", recordInfo.order); - std::cout << ts::bwprint(text, "{:16s}: {}\n", "Raw Stat Block ", recordInfo.rsb); + std::cout << swoc::bwprint(text, "{:16s}: {}\n", "Overridable", (recordInfo.overridable ? "yes" : "no")); + std::cout << swoc::bwprint(text, "{:16s}: {}\n", "Version ", recordInfo.version); + std::cout << swoc::bwprint(text, "{:16s}: {}\n", "Order ", recordInfo.order); + std::cout << swoc::bwprint(text, "{:16s}: {}\n", "Raw Stat Block ", recordInfo.rsb); } // also print errors. diff --git a/src/traffic_ctl/CtrlPrinters.h b/src/traffic_ctl/CtrlPrinters.h index c641f5b6f6f..1761338533a 100644 --- a/src/traffic_ctl/CtrlPrinters.h +++ b/src/traffic_ctl/CtrlPrinters.h @@ -190,6 +190,14 @@ 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; }; From 7cf745b383c687ae8e661c4039ebfafd18f9ebac Mon Sep 17 00:00:00 2001 From: Brian Neradt Date: Wed, 1 Mar 2023 22:56:49 +0000 Subject: [PATCH 2/2] Create a FloatDate wrapper for string_view time representations --- src/traffic_ctl/CtrlPrinters.cc | 14 ++++++++------ src/traffic_ctl/CtrlPrinters.h | 27 +++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/src/traffic_ctl/CtrlPrinters.cc b/src/traffic_ctl/CtrlPrinters.cc index b4f8e20c07c..118a7d5f7bc 100644 --- a/src/traffic_ctl/CtrlPrinters.cc +++ b/src/traffic_ctl/CtrlPrinters.cc @@ -30,6 +30,12 @@ #include #include "PrintUtils.h" +swoc::BufferWriter & +bwformat(swoc::BufferWriter &w, swoc::bwf::Spec const &spec, FloatDate const &wrap) +{ + return bwformat(w, spec, swoc::bwf::Date(static_cast(swoc::svtod(wrap._src)), wrap._fmt)); +} + //------------------------------------------------------------------------------------------------------------------------------------ namespace @@ -233,13 +239,9 @@ ConfigStatusPrinter::write_output(YAML::Node const &result) if (recordName == "proxy.process.version.server.long") { std::cout << "Version: " << recordInfo.currentValue << "\n"; } else if (recordName == "proxy.node.restarts.proxy.start_time") { - std::cout << swoc::bwprint( - text, "{}: {}\n", "Started at", - swoc::bwf::Date(static_cast(std::stod(recordInfo.currentValue)), "%a %d %b %Y %H:%M:%S")); + std::cout << swoc::bwprint(text, "{}: {}\n", "Started at", FloatDate(recordInfo.currentValue, "%a %d %b %Y %H:%M:%S")); } else if (recordName == "proxy.node.config.reconfigure_time") { - std::cout << swoc::bwprint( - text, "{}: {}\n", "Reconfigured at", - swoc::bwf::Date(static_cast(std::stod(recordInfo.currentValue)), "%a %d %b %Y %H:%M:%S")); + std::cout << swoc::bwprint(text, "{}: {}\n", "Reconfigured at", FloatDate(recordInfo.currentValue, "%a %d %b %Y %H:%M:%S")); } else if (recordName == "proxy.node.config.reconfigure_required") { std::cout << "Reconfigure required: " << ((recordInfo.currentValue == "1") ? "yes" : "no") << "\n"; } else if (recordName == "proxy.node.config.restart_required.proxy") { diff --git a/src/traffic_ctl/CtrlPrinters.h b/src/traffic_ctl/CtrlPrinters.h index 1761338533a..edbe3075ebf 100644 --- a/src/traffic_ctl/CtrlPrinters.h +++ b/src/traffic_ctl/CtrlPrinters.h @@ -21,9 +21,36 @@ #pragma once #include +#include #include #include "shared/rpc/RPCRequests.h" +#include + +/** 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); //------------------------------------------------------------------------------------------------------------------------------------ ///