• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The Chromium Authors
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 "base/fuchsia/scoped_fx_logger.h"
6 
7 #include <lib/component/incoming/cpp/protocol.h>
8 #include <lib/fdio/directory.h>
9 #include <stdio.h>
10 
11 #include <string_view>
12 
13 #include "base/command_line.h"
14 #include "base/files/file_path.h"
15 #include "base/fuchsia/fuchsia_component_connect.h"
16 #include "base/fuchsia/fuchsia_logging.h"
17 #include "base/process/process.h"
18 #include "base/threading/platform_thread.h"
19 
20 namespace base {
21 
22 namespace {
23 
LogSeverityToFuchsiaLogSeverity(logging::LogSeverity severity)24 inline FuchsiaLogSeverity LogSeverityToFuchsiaLogSeverity(
25     logging::LogSeverity severity) {
26   switch (severity) {
27     case logging::LOGGING_INFO:
28       return FUCHSIA_LOG_INFO;
29     case logging::LOGGING_WARNING:
30       return FUCHSIA_LOG_WARNING;
31     case logging::LOGGING_ERROR:
32       return FUCHSIA_LOG_ERROR;
33     case logging::LOGGING_FATAL:
34       // Don't use FX_LOG_FATAL, otherwise fx_logger_log() will abort().
35       return FUCHSIA_LOG_ERROR;
36   }
37   if (severity > -3) {
38     // LOGGING_VERBOSE levels 1 and 2.
39     return FUCHSIA_LOG_DEBUG;
40   }
41   // LOGGING_VERBOSE levels 3 and higher, or incorrect levels.
42   return FUCHSIA_LOG_TRACE;
43 }
44 
45 }  // namespace
46 
47 ScopedFxLogger::ScopedFxLogger() = default;
48 ScopedFxLogger::~ScopedFxLogger() = default;
49 
50 ScopedFxLogger::ScopedFxLogger(ScopedFxLogger&& other) = default;
51 ScopedFxLogger& ScopedFxLogger::operator=(ScopedFxLogger&& other) = default;
52 
53 // static
CreateForProcess(std::vector<std::string_view> tags)54 ScopedFxLogger ScopedFxLogger::CreateForProcess(
55     std::vector<std::string_view> tags) {
56   // CHECK()ing or LOG()ing inside this function is safe, since it is only
57   // called to initialize logging, not during individual logging operations.
58 
59   auto log_sink_client_end = component::Connect<fuchsia_logger::LogSink>();
60   if (log_sink_client_end.is_error()) {
61     LOG(ERROR) << FidlConnectionErrorMessage(log_sink_client_end);
62     return {};
63   }
64 
65   // Rather than relying on automatic LogSink attribution via COMPONENT_NAME,
66   // prepend a tag based on the calling process' name.  COMPONENT_NAME may be
67   // mis-attributed, in some Component configurations, to a parent or caller
68   // component, from which the process' LogSink service is routed.
69   std::string program_name = base::CommandLine::ForCurrentProcess()
70                                  ->GetProgram()
71                                  .BaseName()
72                                  .AsUTF8Unsafe();
73   tags.insert(tags.begin(), program_name);
74 
75   return CreateFromLogSink(std::move(log_sink_client_end.value()),
76                            std::move(tags));
77 }
78 
79 // static
CreateFromLogSink(fidl::ClientEnd<fuchsia_logger::LogSink> log_sink_client_end,std::vector<std::string_view> tags)80 ScopedFxLogger ScopedFxLogger::CreateFromLogSink(
81     fidl::ClientEnd<fuchsia_logger::LogSink> log_sink_client_end,
82     std::vector<std::string_view> tags) {
83   // CHECK()ing or LOG()ing inside this function is safe, since it is only
84   // called to initialize logging, not during individual logging operations.
85 
86   // Attempts to create a kernel socket object should never fail.
87   zx::socket local, remote;
88   zx_status_t socket_status =
89       zx::socket::create(ZX_SOCKET_DATAGRAM, &local, &remote);
90   ZX_CHECK(socket_status == ZX_OK, socket_status)
91       << "zx_socket_create() failed";
92 
93   // ConnectStructured() may fail if e.g. the LogSink has disconnected already.
94   fidl::SyncClient log_sink(std::move(log_sink_client_end));
95   auto connect_structured_result =
96       log_sink->ConnectStructured(std::move(remote));
97   if (connect_structured_result.is_error()) {
98     ZX_LOG(ERROR, connect_structured_result.error_value().status())
99         << "ConnectStructured() failed";
100     return {};
101   }
102 
103   return ScopedFxLogger(std::move(tags), std::move(local));
104 }
105 
LogMessage(std::string_view file,uint32_t line_number,std::string_view msg,logging::LogSeverity severity)106 void ScopedFxLogger::LogMessage(std::string_view file,
107                                 uint32_t line_number,
108                                 std::string_view msg,
109                                 logging::LogSeverity severity) {
110   if (!socket_.is_valid())
111     return;
112 
113   auto fuchsia_severity = LogSeverityToFuchsiaLogSeverity(severity);
114 
115   // It is not safe to use e.g. CHECK() or LOG() macros here, since those
116   // may result in reentrancy if this instance is used for routing process-
117   // global logs to the system logger.
118 
119   fuchsia_syslog::LogBuffer buffer;
120   buffer.BeginRecord(
121       fuchsia_severity, cpp17::string_view(file.data(), file.size()),
122       line_number, cpp17::string_view(msg.data(), msg.size()), socket_.borrow(),
123       0, base::Process::Current().Pid(), base::PlatformThread::CurrentId());
124   for (const auto& tag : tags_) {
125     buffer.WriteKeyValue("tag", tag);
126   }
127   if (!buffer.FlushRecord())
128     fprintf(stderr, "fuchsia_syslog.LogBuffer.FlushRecord() failed\n");
129 }
130 
ScopedFxLogger(std::vector<std::string_view> tags,zx::socket socket)131 ScopedFxLogger::ScopedFxLogger(std::vector<std::string_view> tags,
132                                zx::socket socket)
133     : tags_(tags.begin(), tags.end()), socket_(std::move(socket)) {}
134 
135 }  // namespace base
136