blob: 45a4cd279073be9bff4903093fe63741937cbedd [file] [log] [blame]
John Park33858a32018-09-28 23:05:48 -07001#ifndef AOS_LOGGING_REPLAY_H_
2#define AOS_LOGGING_REPLAY_H_
Brian Silvermand0575692015-02-21 16:24:02 -05003
4#include <unordered_map>
5#include <string>
6#include <functional>
7#include <memory>
8
Austin Schuhdf6cbb12019-02-02 13:46:52 -08009#include "aos/events/event-loop.h"
10#include "aos/ipc_lib/queue.h"
John Park33858a32018-09-28 23:05:48 -070011#include "aos/logging/binary_log_file.h"
John Park33858a32018-09-28 23:05:48 -070012#include "aos/logging/logging.h"
James Kuszmaulf5f50dd2019-03-23 12:43:15 -070013#include "aos/logging/queue_logging.h"
John Park33858a32018-09-28 23:05:48 -070014#include "aos/macros.h"
Austin Schuhdf6cbb12019-02-02 13:46:52 -080015#include "aos/queue.h"
John Park33858a32018-09-28 23:05:48 -070016#include "aos/queue_types.h"
Brian Silvermand0575692015-02-21 16:24:02 -050017
18namespace aos {
19namespace logging {
20namespace linux_code {
21
22// Manages pulling logged queue messages out of log files.
23//
24// Basic usage:
25// - Use the Add* methods to register handlers for various message sources.
26// - Call OpenFile to open a log file.
27// - Call ProcessMessage repeatedly until it returns true.
28//
29// This code could do something to adapt similar-but-not-identical
30// messages to the current versions, but currently it will LOG(FATAL) if any of
31// the messages don't match up exactly.
32class LogReplayer {
33 public:
34 LogReplayer() {}
35
36 // Gets ready to read messages from fd.
37 // Does not take ownership of fd.
38 void OpenFile(int fd) {
39 reader_.reset(new LogFileReader(fd));
40 }
41 // Closes the currently open file.
42 void CloseCurrentFile() { reader_.reset(); }
43 // Returns true if we have a file which is currently open.
44 bool HasCurrentFile() const { return reader_.get() != nullptr; }
45
46 // Processes a single message from the currently open file.
47 // Returns true if there are no more messages in the file.
48 // This will not call any of the handlers if the next message either has no
49 // registered handlers or is not a queue message.
50 bool ProcessMessage();
51
52 // Adds a handler for messages with a certain string from a certain process.
53 // T must be a Message with the same format as the messages generated by
54 // the .q files.
55 // LOG(FATAL)s for duplicate handlers.
56 template <class T>
57 void AddHandler(const ::std::string &process_name,
58 const ::std::string &log_message,
59 ::std::function<void(const T &message)> handler) {
60 CHECK(handlers_.emplace(
61 ::std::piecewise_construct,
62 ::std::forward_as_tuple(process_name, log_message),
63 ::std::forward_as_tuple(::std::unique_ptr<StructHandlerInterface>(
64 new TypedStructHandler<T>(handler)))).second);
65 }
66
67 // Adds a handler which takes messages and places them directly on a queue.
68 // T must be a Message with the same format as the messages generated by
69 // the .q files.
70 template <class T>
71 void AddDirectQueueSender(const ::std::string &process_name,
72 const ::std::string &log_message,
Austin Schuhdf6cbb12019-02-02 13:46:52 -080073 const ::std::string &name) {
Brian Silvermand0575692015-02-21 16:24:02 -050074 AddHandler(process_name, log_message,
75 ::std::function<void(const T &)>(
Austin Schuhdf6cbb12019-02-02 13:46:52 -080076 QueueDumpStructHandler<T>(name.c_str())));
Brian Silvermand0575692015-02-21 16:24:02 -050077 }
78
79 private:
80 // A generic handler of struct log messages.
81 class StructHandlerInterface {
82 public:
83 virtual ~StructHandlerInterface() {}
84
Austin Schuhf2a50ba2016-12-24 16:16:26 -080085 virtual void HandleStruct(::aos::monotonic_clock::time_point log_time,
86 uint32_t type_id, const void *data,
87 size_t data_size) = 0;
Brian Silvermand0575692015-02-21 16:24:02 -050088 };
89
90 // Converts struct log messages to a message type and passes it to an
91 // ::std::function.
92 template <class T>
93 class TypedStructHandler : public StructHandlerInterface {
94 public:
95 TypedStructHandler(::std::function<void(const T &message)> handler)
96 : handler_(handler) {}
97
Austin Schuhf2a50ba2016-12-24 16:16:26 -080098 void HandleStruct(::aos::monotonic_clock::time_point log_time,
99 uint32_t type_id, const void *data,
100 size_t data_size) override {
Brian Silvermand0575692015-02-21 16:24:02 -0500101 CHECK_EQ(type_id, T::GetType()->id);
102 T message;
103 CHECK_EQ(data_size, T::Size());
104 CHECK_EQ(data_size, message.Deserialize(static_cast<const char *>(data)));
105 message.sent_time = log_time;
106 handler_(message);
107 }
108
109 private:
110 const ::std::function<void(T message)> handler_;
111 };
112
113 // A callable class which dumps messages straight to a queue.
114 template <class T>
115 class QueueDumpStructHandler {
116 public:
117 QueueDumpStructHandler(const ::std::string &queue_name)
118 : queue_(RawQueue::Fetch(queue_name.c_str(), sizeof(T), T::kHash,
119 T::kQueueLength)) {}
120
121 void operator()(const T &message) {
122 LOG_STRUCT(DEBUG, "re-sending", message);
123 void *raw_message = queue_->GetMessage();
124 CHECK_NOTNULL(raw_message);
125 memcpy(raw_message, &message, sizeof(message));
126 CHECK(queue_->WriteMessage(raw_message, RawQueue::kOverride));
127 }
128
129 private:
130 ::aos::RawQueue *const queue_;
131 };
132
133 // A key for specifying log messages to give to a certain handler.
134 struct Key {
135 Key(const ::std::string &process_name, const ::std::string &log_message)
136 : process_name(process_name), log_message(log_message) {}
137
138 ::std::string process_name;
139 ::std::string log_message;
140 };
141
142 struct KeyHash {
143 size_t operator()(const Key &key) const {
144 return string_hash(key.process_name) ^
145 (string_hash(key.log_message) << 1);
146 }
147
148 private:
149 const ::std::hash<::std::string> string_hash = ::std::hash<::std::string>();
150 };
151 struct KeyEqual {
152 bool operator()(const Key &a, const Key &b) const {
153 return a.process_name == b.process_name && a.log_message == b.log_message;
154 }
155 };
156
157 ::std::unordered_map<const Key, ::std::unique_ptr<StructHandlerInterface>,
158 KeyHash, KeyEqual> handlers_;
159 ::std::unique_ptr<LogFileReader> reader_;
160
161 DISALLOW_COPY_AND_ASSIGN(LogReplayer);
162};
163
164} // namespace linux_code
165} // namespace logging
166} // namespace aos
167
John Park33858a32018-09-28 23:05:48 -0700168#endif // AOS_LOGGING_REPLAY_H_