xref: /aosp_15_r20/external/cronet/base/fuchsia/scoped_fx_logger.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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 ScopedFxLogger::ScopedFxLogger() = default;
23 ScopedFxLogger::~ScopedFxLogger() = default;
24 
25 ScopedFxLogger::ScopedFxLogger(ScopedFxLogger&& other) = default;
26 ScopedFxLogger& ScopedFxLogger::operator=(ScopedFxLogger&& other) = default;
27 
28 // static
CreateForProcess(std::vector<std::string_view> tags)29 ScopedFxLogger ScopedFxLogger::CreateForProcess(
30     std::vector<std::string_view> tags) {
31   // CHECK()ing or LOG()ing inside this function is safe, since it is only
32   // called to initialize logging, not during individual logging operations.
33 
34   auto log_sink_client_end = component::Connect<fuchsia_logger::LogSink>();
35   if (log_sink_client_end.is_error()) {
36     LOG(ERROR) << FidlConnectionErrorMessage(log_sink_client_end);
37     return {};
38   }
39 
40   // Rather than relying on automatic LogSink attribution via COMPONENT_NAME,
41   // prepend a tag based on the calling process' name.  COMPONENT_NAME may be
42   // mis-attributed, in some Component configurations, to a parent or caller
43   // component, from which the process' LogSink service is routed.
44   std::string program_name = base::CommandLine::ForCurrentProcess()
45                                  ->GetProgram()
46                                  .BaseName()
47                                  .AsUTF8Unsafe();
48   tags.insert(tags.begin(), program_name);
49 
50   return CreateFromLogSink(std::move(log_sink_client_end.value()),
51                            std::move(tags));
52 }
53 
54 // static
CreateFromLogSink(fidl::ClientEnd<fuchsia_logger::LogSink> log_sink_client_end,std::vector<std::string_view> tags)55 ScopedFxLogger ScopedFxLogger::CreateFromLogSink(
56     fidl::ClientEnd<fuchsia_logger::LogSink> log_sink_client_end,
57     std::vector<std::string_view> tags) {
58   // CHECK()ing or LOG()ing inside this function is safe, since it is only
59   // called to initialize logging, not during individual logging operations.
60 
61   // Attempts to create a kernel socket object should never fail.
62   zx::socket local, remote;
63   zx_status_t socket_status =
64       zx::socket::create(ZX_SOCKET_DATAGRAM, &local, &remote);
65   ZX_CHECK(socket_status == ZX_OK, socket_status)
66       << "zx_socket_create() failed";
67 
68   // ConnectStructured() may fail if e.g. the LogSink has disconnected already.
69   fidl::SyncClient log_sink(std::move(log_sink_client_end));
70   auto connect_structured_result =
71       log_sink->ConnectStructured(std::move(remote));
72   if (connect_structured_result.is_error()) {
73     ZX_LOG(ERROR, connect_structured_result.error_value().status())
74         << "ConnectStructured() failed";
75     return {};
76   }
77 
78   return ScopedFxLogger(std::move(tags), std::move(local));
79 }
80 
LogMessage(std::string_view file,uint32_t line_number,std::string_view msg,FuchsiaLogSeverity severity)81 void ScopedFxLogger::LogMessage(std::string_view file,
82                                 uint32_t line_number,
83                                 std::string_view msg,
84                                 FuchsiaLogSeverity severity) {
85   if (!socket_.is_valid())
86     return;
87 
88   // It is not safe to use e.g. CHECK() or LOG() macros here, since those
89   // may result in reentrancy if this instance is used for routing process-
90   // global logs to the system logger.
91 
92   fuchsia_syslog::LogBuffer buffer;
93   buffer.BeginRecord(severity, cpp17::string_view(file.data(), file.size()),
94                      line_number, cpp17::string_view(msg.data(), msg.size()),
95                      socket_.borrow(), 0, base::Process::Current().Pid(),
96                      base::PlatformThread::CurrentId());
97   for (const auto& tag : tags_) {
98     buffer.WriteKeyValue("tag", tag);
99   }
100   if (!buffer.FlushRecord())
101     fprintf(stderr, "fuchsia_syslog.LogBuffer.FlushRecord() failed\n");
102 }
103 
ScopedFxLogger(std::vector<std::string_view> tags,zx::socket socket)104 ScopedFxLogger::ScopedFxLogger(std::vector<std::string_view> tags,
105                                zx::socket socket)
106     : tags_(tags.begin(), tags.end()), socket_(std::move(socket)) {}
107 
108 }  // namespace base
109