blob: d3648a92664d940eb97bbe1876bd65f35a815ace [file] [log] [blame]
Eric Carusoea9f10e2019-05-01 09:52:01 -07001// Copyright 2019 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "glib-bridge/glib_logger.h"
6
7#include <glib.h>
8
Qijiang Fan713061e2021-03-08 15:45:12 +09009#include <base/check.h>
Eric Carusoea9f10e2019-05-01 09:52:01 -070010#include <base/logging.h>
11#include <base/optional.h>
12#include <base/strings/string_number_conversions.h>
13
14namespace glib_bridge {
15
16// Used for testing.
17uint64_t g_num_logs = 0;
18
19namespace {
20
21// Structured logging uses syslog priority levels. See
22// http://man7.org/linux/man-pages/man3/syslog.3.html#DESCRIPTION
23// Note that LOG_ERR is used in g_error which is expected to
24// abort execution, so the levels seem to be one off from normal
25// Chrome usage.
26// Also, since there are conflicts between the syslog macros and
27// Chrome log levels, these are given as bare ints.
28logging::LogSeverity GetLogSeverity(int priority) {
29 switch (priority) {
30 case 0: // EMERG
31 case 1: // ALERT
32 case 2: // CRIT
33 case 3: // ERROR
hschame6711302020-11-20 17:08:14 +090034 return logging::LOGGING_FATAL;
Eric Carusoea9f10e2019-05-01 09:52:01 -070035 case 4: // WARNING
hschame6711302020-11-20 17:08:14 +090036 return logging::LOGGING_ERROR;
Eric Carusoea9f10e2019-05-01 09:52:01 -070037 case 5: // NOTICE
hschame6711302020-11-20 17:08:14 +090038 return logging::LOGGING_WARNING;
Eric Carusoea9f10e2019-05-01 09:52:01 -070039 case 6: // INFO
hschame6711302020-11-20 17:08:14 +090040 return logging::LOGGING_INFO;
Eric Carusoea9f10e2019-05-01 09:52:01 -070041 case 7: // DEBUG
42 default:
hschame6711302020-11-20 17:08:14 +090043 return logging::LOGGING_VERBOSE;
Eric Carusoea9f10e2019-05-01 09:52:01 -070044 }
45}
46
47base::Optional<int> ParseIntField(const char* value) {
48 int parsed;
49 if (base::StringToInt(value, &parsed))
50 return parsed;
51 return base::nullopt;
52}
53
54GLogWriterOutput LogHandler(GLogLevelFlags log_level,
55 const GLogField* fields,
56 gsize n_fields,
57 gpointer user_data) {
58 base::Optional<std::string> message;
59 base::Optional<int> priority;
60 base::Optional<std::string> code_file;
61 base::Optional<int> code_line;
62 base::Optional<int> log_errno;
63
64 for (int i = 0; i < n_fields; i++) {
65 const char* key = fields[i].key;
66 const char* value = static_cast<const char*>(fields[i].value);
67 if (strcmp(key, "MESSAGE") == 0) {
68 message = std::string(value);
69 } else if (strcmp(key, "PRIORITY") == 0) {
70 priority = ParseIntField(value);
71 } else if (strcmp(key, "CODE_FILE") == 0) {
72 code_file = std::string(value);
73 } else if (strcmp(key, "CODE_LINE") == 0) {
74 code_line = ParseIntField(value);
75 } else if (strcmp(key, "ERRNO") == 0) {
76 log_errno = ParseIntField(value);
77 }
78 // Possibly explore using key CODE_FUNC as well.
79 }
80
81 // glib guarantees that logs will have a message and priority.
82 CHECK(message.has_value() && priority.has_value());
83
84 // Give defaults for code file/line if they were not found.
85 if (!code_file.has_value())
86 code_file = std::string(__FILE__);
87 if (!code_line.has_value())
88 code_line = 0;
89
90 logging::LogSeverity severity = GetLogSeverity(priority.value());
91
92 if (log_errno.has_value()) {
93 logging::ErrnoLogMessage logger(code_file.value().c_str(),
94 code_line.value(), severity,
95 log_errno.value());
96 logger.stream() << message.value();
97 } else {
98 logging::LogMessage logger(code_file.value().c_str(), code_line.value(),
99 severity);
100 logger.stream() << message.value();
101 }
102
103 g_num_logs++;
104 return G_LOG_WRITER_HANDLED;
105}
106
107} // namespace
108
109void ForwardLogs() {
110 g_log_set_writer_func(LogHandler, nullptr, nullptr);
111}
112
113} // namespace glib_bridge