#ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include "common/swaglog.h" #include #include #include #include #include #include #include "third_party/json11/json11.hpp" #include "common/version.h" #include "system/hardware/hw.h" class SwaglogState { public: SwaglogState() { zctx = zmq_ctx_new(); sock = zmq_socket(zctx, ZMQ_PUSH); // Timeout on shutdown for messages to be received by the logging process int timeout = 100; zmq_setsockopt(sock, ZMQ_LINGER, &timeout, sizeof(timeout)); zmq_connect(sock, Path::swaglog_ipc().c_str()); print_level = CLOUDLOG_WARNING; if (const char* print_lvl = getenv("LOGPRINT")) { if (strcmp(print_lvl, "debug") == 0) { print_level = CLOUDLOG_DEBUG; } else if (strcmp(print_lvl, "info") == 0) { print_level = CLOUDLOG_INFO; } else if (strcmp(print_lvl, "warning") == 0) { print_level = CLOUDLOG_WARNING; } } ctx_j = json11::Json::object{}; if (char* dongle_id = getenv("DONGLE_ID")) { ctx_j["dongle_id"] = dongle_id; } if (char* daemon_name = getenv("MANAGER_DAEMON")) { ctx_j["daemon"] = daemon_name; } ctx_j["version"] = COMMA_VERSION; ctx_j["dirty"] = !getenv("CLEAN"); ctx_j["device"] = Hardware::get_name(); } ~SwaglogState() { zmq_close(sock); zmq_ctx_destroy(zctx); } void log(int levelnum, const char* filename, int lineno, const char* func, const char* msg, const std::string& log_s) { std::lock_guard lk(lock); if (levelnum >= print_level) { printf("%s: %s\n", filename, msg); } zmq_send(sock, log_s.data(), log_s.length(), ZMQ_NOBLOCK); } std::mutex lock; void* zctx = nullptr; void* sock = nullptr; int print_level; json11::Json::object ctx_j; }; bool LOG_TIMESTAMPS = getenv("LOG_TIMESTAMPS"); uint32_t NO_FRAME_ID = std::numeric_limits::max(); static void cloudlog_common(int levelnum, const char* filename, int lineno, const char* func, char* msg_buf, const json11::Json::object &msg_j={}) { static SwaglogState s; json11::Json::object log_j = json11::Json::object { {"ctx", s.ctx_j}, {"levelnum", levelnum}, {"filename", filename}, {"lineno", lineno}, {"funcname", func}, {"created", seconds_since_epoch()} }; if (msg_j.empty()) { log_j["msg"] = msg_buf; } else { log_j["msg"] = msg_j; } std::string log_s; log_s += (char)levelnum; ((json11::Json)log_j).dump(log_s); s.log(levelnum, filename, lineno, func, msg_buf, log_s); free(msg_buf); } void cloudlog_e(int levelnum, const char* filename, int lineno, const char* func, const char* fmt, ...) { va_list args; va_start(args, fmt); char* msg_buf = nullptr; int ret = vasprintf(&msg_buf, fmt, args); va_end(args); if (ret <= 0 || !msg_buf) return; cloudlog_common(levelnum, filename, lineno, func, msg_buf); } void cloudlog_t_common(int levelnum, const char* filename, int lineno, const char* func, uint32_t frame_id, const char* fmt, va_list args) { if (!LOG_TIMESTAMPS) return; char* msg_buf = nullptr; int ret = vasprintf(&msg_buf, fmt, args); if (ret <= 0 || !msg_buf) return; json11::Json::object tspt_j = json11::Json::object{ {"event", msg_buf}, {"time", std::to_string(nanos_since_boot())} }; if (frame_id < NO_FRAME_ID) { tspt_j["frame_id"] = std::to_string(frame_id); } tspt_j = json11::Json::object{{"timestamp", tspt_j}}; cloudlog_common(levelnum, filename, lineno, func, msg_buf, tspt_j); } void cloudlog_te(int levelnum, const char* filename, int lineno, const char* func, const char* fmt, ...) { va_list args; va_start(args, fmt); cloudlog_t_common(levelnum, filename, lineno, func, NO_FRAME_ID, fmt, args); va_end(args); } void cloudlog_te(int levelnum, const char* filename, int lineno, const char* func, uint32_t frame_id, const char* fmt, ...) { va_list args; va_start(args, fmt); cloudlog_t_common(levelnum, filename, lineno, func, frame_id, fmt, args); va_end(args); }