diff --git a/doc/operators/node_output.rst b/doc/operators/node_output.rst index a18fe51a0..44b315f84 100644 --- a/doc/operators/node_output.rst +++ b/doc/operators/node_output.rst @@ -22,7 +22,7 @@ Note that your app's logging entries will be interleaved (line-by-line) with the JSON Formatting --------------- -There is an option to further generate machine-readable logs for monitoring. To enable this pass `--json-log-path ` when creating a node (in either ``start`` or ``join`` mode). The generated logs will be in JSON format as displayed below. +There is an option to generate machine-readable logs for monitoring. To enable this pass `--json-format-json` when creating a node (in either ``start`` or ``join`` mode). The generated logs will be in JSON format as displayed below. .. code-block:: json diff --git a/src/apps/lua_generic/test/lua_generic_test.cpp b/src/apps/lua_generic/test/lua_generic_test.cpp index 5e0c36197..6cfeee3ff 100644 --- a/src/apps/lua_generic/test/lua_generic_test.cpp +++ b/src/apps/lua_generic/test/lua_generic_test.cpp @@ -80,10 +80,10 @@ void set_whitelists(GenesisGenerator& gen) gen.set_whitelist(wl.first, wl.second); } -class LuaLogger : public logger::JsonLogger +class LuaLogger : public logger::JsonConsoleLogger { public: - LuaLogger() : JsonLogger("") {} + LuaLogger() : JsonConsoleLogger() {} void write(const std::string& log_line) override { diff --git a/src/ds/logger.h b/src/ds/logger.h index 1d8cd86a6..79d15d752 100644 --- a/src/ds/logger.h +++ b/src/ds/logger.h @@ -78,11 +78,9 @@ namespace logger } }; - class JsonLogger : public AbstractLogger + class JsonConsoleLogger : public AbstractLogger { public: - JsonLogger(std::string log_path) : AbstractLogger(log_path) {} - std::string format( const std::string& file_name, size_t line_number, @@ -129,9 +127,14 @@ namespace logger j["m"].dump()); } - void write(const std::string& log_line) override + virtual void write(const std::string& log_line) override { - dump(log_line); + std::cout << log_line; + } + + std::ostream& get_stream() override + { + return std::cout; } }; @@ -222,16 +225,24 @@ namespace logger static inline std::vector>& loggers() { - static std::vector> the_loggers; - static bool initialized = false; - if (!initialized) - { - initialized = true; - the_loggers.emplace_back(std::make_unique()); - } + std::vector>& the_loggers = get_loggers(); + try_initialize(); return the_loggers; } + static inline void initialize_with_json_console() + { + std::vector>& the_loggers = get_loggers(); + if (the_loggers.size() > 0) + { + the_loggers.front() = std::move(std::make_unique()); + } + else + { + the_loggers.emplace_back(std::make_unique()); + } + } + static inline Level& level() { static Level the_level = @@ -296,6 +307,22 @@ namespace logger { return l >= level(); } + + private: + static inline void try_initialize() + { + std::vector>& the_loggers = get_loggers(); + if (the_loggers.size() == 0) + { + the_loggers.emplace_back(std::make_unique()); + } + } + + static inline std::vector>& get_loggers() + { + static std::vector> the_loggers; + return the_loggers; + } }; class LogLine diff --git a/src/ds/test/logger_bench.cpp b/src/ds/test/logger_bench.cpp index a094340a7..6b064f53a 100644 --- a/src/ds/test/logger_bench.cpp +++ b/src/ds/test/logger_bench.cpp @@ -29,7 +29,7 @@ static void prepare_loggers() if constexpr ((LK & LoggerKind::JSON) != 0) { logger::config::loggers().emplace_back( - std::make_unique("./custom_json_logger")); + std::make_unique()); } if constexpr (Absorb) diff --git a/src/ds/test/logger_json_test.cpp b/src/ds/test/logger_json_test.cpp index e748ebcfb..53583fe0b 100644 --- a/src/ds/test/logger_json_test.cpp +++ b/src/ds/test/logger_json_test.cpp @@ -11,15 +11,23 @@ TEST_CASE("Test custom log format") { std::string test_log_file = "./test_json_logger.txt"; remove(test_log_file.c_str()); - logger::config::loggers().emplace_back( - std::make_unique(test_log_file)); + logger::config::initialize_with_json_console(); logger::config::level() = logger::DEBUG; std::string log_msg_dbg = "log_msg_dbg"; std::string log_msg_fail = "log_msg_fail"; + std::ofstream out(test_log_file.c_str()); + std::streambuf* coutbuf = std::cout.rdbuf(); + std::cout.rdbuf(out.rdbuf()); + LOG_DEBUG_FMT(log_msg_dbg); LOG_TRACE_FMT(log_msg_fail); + out.flush(); + out.close(); + + std::cout.rdbuf(coutbuf); + std::ifstream f(test_log_file); std::string line; size_t line_count = 0; diff --git a/src/host/main.cpp b/src/host/main.cpp index eeeb37243..9c0478475 100644 --- a/src/host/main.cpp +++ b/src/host/main.cpp @@ -136,11 +136,9 @@ int main(int argc, char** argv) ->capture_default_str() ->transform(CLI::CheckedTransformer(level_map, CLI::ignore_case)); - std::optional json_log_path; - app.add_option( - "--json-log-path", - json_log_path, - "Path to file where the json logs will be written"); + bool log_format_json = false; + app.add_flag( + "--log-format-json", log_format_json, "Set node stdout log format to JSON"); std::string node_cert_file("nodecert.pem"); app @@ -387,6 +385,12 @@ int main(int argc, char** argv) public_rpc_address = rpc_address; } + // set json log formatter to write to std::out + if (log_format_json) + { + logger::config::initialize_with_json_console(); + } + uint32_t oe_flags = 0; try { @@ -463,12 +467,6 @@ int main(int argc, char** argv) // set the host log level logger::config::level() = host_log_level; - // set the custom log formatter path - if (json_log_path.has_value()) - { - logger::config::loggers().emplace_back( - std::make_unique(json_log_path.value())); - } // create the enclave host::Enclave enclave(enclave_file, oe_flags); diff --git a/tests/infra/ccf.py b/tests/infra/ccf.py index e556f2f93..0780ed3e8 100644 --- a/tests/infra/ccf.py +++ b/tests/infra/ccf.py @@ -68,7 +68,7 @@ class Network: "consensus", "memory_reserve_startup", "notify_server", - "json_log_path", + "log_format_json", "gov_script", "join_timer", "worker_threads", diff --git a/tests/infra/e2e_args.py b/tests/infra/e2e_args.py index 6dbc7ef09..22db2a53d 100644 --- a/tests/infra/e2e_args.py +++ b/tests/infra/e2e_args.py @@ -46,10 +46,10 @@ def cli_args(add=lambda x: None, parser=None, accept_unknown=False): choices=("trace", "debug", "info", "fail", "fatal"), ) parser.add_argument( - "--json-log-path", - help="Path to directory where the json logger output will be sent to. \ - The json logs will be dumped into a file named /{label}_{node_id}", - default=os.getenv("JSON_LOG_PATH", None), + "--log-format-json", + help="Set node stdout log format to JSON", + action="store_true", + default=False, ) parser.add_argument( "-g", "--gov-script", help="Path to governance script", diff --git a/tests/infra/remote.py b/tests/infra/remote.py index 72c7750ad..6a5981f99 100644 --- a/tests/infra/remote.py +++ b/tests/infra/remote.py @@ -120,7 +120,7 @@ class SSHRemote(CmdMixin): label, common_dir, env=None, - json_log_path=None, + log_format_json=None, ): """ Runs a command on a remote host, through an SSH connection. A temporary @@ -368,7 +368,7 @@ class LocalRemote(CmdMixin): label, common_dir, env=None, - json_log_path=None, + log_format_json=None, ): """ Local Equivalent to the SSHRemote @@ -527,7 +527,7 @@ class CCFRemote(object): notify_server=None, gov_script=None, ledger_file=None, - json_log_path=None, + log_format_json=None, binary_dir=".", domain=None, ): @@ -580,9 +580,8 @@ class CCFRemote(object): f"--worker-threads={worker_threads}", ] - if json_log_path: - log_file = f"{label}_{local_node_id}" - cmd += [f"--json-log-path={os.path.join(json_log_path, log_file)}"] + if log_format_json: + cmd += ["--log-format-json"] if sig_max_tx: cmd += [f"--sig-max-tx={sig_max_tx}"] @@ -662,7 +661,7 @@ class CCFRemote(object): label, common_dir, env, - json_log_path, + log_format_json, ) def setup(self):