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