1 // Copyright 2018 The Fuchsia 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 // Code for listening to logger service and dumping the logs.
6 // This implements LogListener interface for logger fidl @ //zircon/system/fidl/fuchsia-logger.
7 
8 #ifndef ZIRCON_SYSTEM_ULIB_RUNTESTS_UTILS_INCLUDE_RUNTESTS_UTILS_LOG_EXPORTER_H_
9 #define ZIRCON_SYSTEM_ULIB_RUNTESTS_UTILS_INCLUDE_RUNTESTS_UTILS_LOG_EXPORTER_H_
10 
11 #include <fbl/string.h>
12 #include <fbl/vector.h>
13 #include <lib/async-loop/cpp/loop.h>
14 #include <lib/async/cpp/wait.h>
15 #include <lib/fidl/cpp/message_buffer.h>
16 #include <lib/zx/channel.h>
17 #include <stdint.h>
18 
19 // TODO(FIDL-182): Remove this once fixed.
20 typedef zx_handle_t fuchsia_logger_LogListener;
21 #include <fuchsia/logger/c/fidl.h>
22 
23 #include <utility>
24 
25 namespace runtests {
26 
27 // Error while launching LogExporter.
28 enum ExporterLaunchError {
29     OPEN_FILE,
30     CREATE_CHANNEL,
31     FIDL_ERROR,
32     CONNECT_TO_LOGGER_SERVICE,
33     START_LISTENER,
34     NO_ERROR,
35 };
36 
37 // Listens to channel messages, converts them fidl log object and writes them to
38 // passed file object.
39 // This implements LogListener fidl interface.
40 // Example:
41 //    FILE* f = fopen("file", "w");
42 //    zx::channel channel;
43 //    //init above channel to link to logger service
44 //    ...
45 //    LogExporter l(std::move(channel), f);
46 //    l->StartThread();
47 class LogExporter {
48 public:
49     using ErrorHandler = fbl::Function<void(zx_status_t)>;
50     using FileErrorHandler = fbl::Function<void(const char* error)>;
51 
52     // Creates object and starts listening for msgs on channel written by Log
53     // interface in logger fidl.
54     //
55     // |channel| channel to read log messages from.
56     // |output_file| file to write logs to.
57     //
58     LogExporter(zx::channel channel, FILE* output_file);
59     ~LogExporter();
60 
61     // Starts LogListener service on a seperate thread.
62     //
63     // Returns result of loop_.StartThread().
64     zx_status_t StartThread();
65 
66     // Runs LogListener service until message loop is idle.
67     //
68     // Returns result of loop_.RunUntilIdle().
69     zx_status_t RunUntilIdle();
70 
71     // Sets Error handler which would be called when there is an error
72     // while serving |channel_|. If an error occurs, the channel will close and
73     // the listener thread will stop.
set_error_handler(ErrorHandler error_handler)74     void set_error_handler(ErrorHandler error_handler) {
75         error_handler_ = std::move(error_handler);
76     }
77 
78     // Sets Error handler which would be called whenever there is an error
79     // writing to file. If an error occurs, the channel will close and the
80     // listener thread will stop.
set_file_error_handler(FileErrorHandler error_handler)81     void set_file_error_handler(FileErrorHandler error_handler) {
82         file_error_handler_ = std::move(error_handler);
83     }
84 
85 private:
86     // Keeps track of the count of dropped logs for a process.
87     struct DroppedLogs {
88         uint64_t pid;
89         uint32_t dropped_logs;
90     };
91 
92     void OnHandleReady(async_dispatcher_t* dispatcher, async::WaitBase* wait, zx_status_t status,
93                        const zx_packet_signal_t* signal);
94 
95     // Decodes channel message and dispatches to correct handler.
96     zx_status_t ReadAndDispatchMessage(fidl::MessageBuffer* buffer);
97 
98     // Implementation of LogListener Log method.
99     zx_status_t Log(fidl::Message message);
100 
101     // Implementation of LogListener LogMany method.
102     zx_status_t LogMany(fidl::Message message);
103 
104     // Helper method to log |message| to file.
105     int LogMessage(fuchsia_logger_LogMessage* message);
106 
107     // Helper method to call |error_handler_|.
108     void NotifyError(zx_status_t error);
109 
110     // Helper method to call |error_handler_|.
111     void NotifyFileError(const char* error);
112 
113     // Helper method to write severity string.
114     int WriteSeverity(int32_t severity);
115 
116     async::Loop loop_;
117     zx::channel channel_;
118     async::WaitMethod<LogExporter, &LogExporter::OnHandleReady> wait_;
119     ErrorHandler error_handler_;
120     FileErrorHandler file_error_handler_;
121 
122     FILE* output_file_;
123 
124     // Vector to keep track of dropped logs per pid
125     fbl::Vector<DroppedLogs> dropped_logs_;
126 };
127 
128 // Launches Log Exporter.
129 //
130 // Starts message loop on a seperate thread.
131 //
132 // |syslog_path| file path where to write logs.
133 // |error| error to set in case of failure.
134 //
135 // Returns nullptr if it is not possible to launch Log Exporter.
136 fbl::unique_ptr<LogExporter> LaunchLogExporter(fbl::StringPiece syslog_path,
137                                                ExporterLaunchError* error);
138 
139 } // namespace runtests
140 
141 #endif // ZIRCON_SYSTEM_ULIB_RUNTESTS_UTILS_INCLUDE_RUNTESTS_UTILS_LOG_EXPORTER_H_
142