| // Copyright 2019 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "glib-bridge/glib_logger.h" |
| |
| #include <glib.h> |
| |
| #include <base/check.h> |
| #include <base/logging.h> |
| #include <base/optional.h> |
| #include <base/strings/string_number_conversions.h> |
| |
| namespace glib_bridge { |
| |
| // Used for testing. |
| uint64_t g_num_logs = 0; |
| |
| namespace { |
| |
| // Structured logging uses syslog priority levels. See |
| // http://man7.org/linux/man-pages/man3/syslog.3.html#DESCRIPTION |
| // Note that LOG_ERR is used in g_error which is expected to |
| // abort execution, so the levels seem to be one off from normal |
| // Chrome usage. |
| // Also, since there are conflicts between the syslog macros and |
| // Chrome log levels, these are given as bare ints. |
| logging::LogSeverity GetLogSeverity(int priority) { |
| switch (priority) { |
| case 0: // EMERG |
| case 1: // ALERT |
| case 2: // CRIT |
| case 3: // ERROR |
| return logging::LOGGING_FATAL; |
| case 4: // WARNING |
| return logging::LOGGING_ERROR; |
| case 5: // NOTICE |
| return logging::LOGGING_WARNING; |
| case 6: // INFO |
| return logging::LOGGING_INFO; |
| case 7: // DEBUG |
| default: |
| return logging::LOGGING_VERBOSE; |
| } |
| } |
| |
| base::Optional<int> ParseIntField(const char* value) { |
| int parsed; |
| if (base::StringToInt(value, &parsed)) |
| return parsed; |
| return base::nullopt; |
| } |
| |
| GLogWriterOutput LogHandler(GLogLevelFlags log_level, |
| const GLogField* fields, |
| gsize n_fields, |
| gpointer user_data) { |
| base::Optional<std::string> message; |
| base::Optional<int> priority; |
| base::Optional<std::string> code_file; |
| base::Optional<int> code_line; |
| base::Optional<int> log_errno; |
| |
| for (int i = 0; i < n_fields; i++) { |
| const char* key = fields[i].key; |
| const char* value = static_cast<const char*>(fields[i].value); |
| if (strcmp(key, "MESSAGE") == 0) { |
| message = std::string(value); |
| } else if (strcmp(key, "PRIORITY") == 0) { |
| priority = ParseIntField(value); |
| } else if (strcmp(key, "CODE_FILE") == 0) { |
| code_file = std::string(value); |
| } else if (strcmp(key, "CODE_LINE") == 0) { |
| code_line = ParseIntField(value); |
| } else if (strcmp(key, "ERRNO") == 0) { |
| log_errno = ParseIntField(value); |
| } |
| // Possibly explore using key CODE_FUNC as well. |
| } |
| |
| // glib guarantees that logs will have a message and priority. |
| CHECK(message.has_value() && priority.has_value()); |
| |
| // Give defaults for code file/line if they were not found. |
| if (!code_file.has_value()) |
| code_file = std::string(__FILE__); |
| if (!code_line.has_value()) |
| code_line = 0; |
| |
| logging::LogSeverity severity = GetLogSeverity(priority.value()); |
| |
| if (log_errno.has_value()) { |
| logging::ErrnoLogMessage logger(code_file.value().c_str(), |
| code_line.value(), severity, |
| log_errno.value()); |
| logger.stream() << message.value(); |
| } else { |
| logging::LogMessage logger(code_file.value().c_str(), code_line.value(), |
| severity); |
| logger.stream() << message.value(); |
| } |
| |
| g_num_logs++; |
| return G_LOG_WRITER_HANDLED; |
| } |
| |
| } // namespace |
| |
| void ForwardLogs() { |
| g_log_set_writer_func(LogHandler, nullptr, nullptr); |
| } |
| |
| } // namespace glib_bridge |