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