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