blob: 6604591468862eab38fe8aee2b3007499490a327 [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) {
Austin Schuhf257f3c2019-10-27 21:00:43 -070060 AOS_CHECK(handlers_
61 .emplace(::std::piecewise_construct,
62 ::std::forward_as_tuple(process_name, log_message),
63 ::std::forward_as_tuple(
64 ::std::unique_ptr<StructHandlerInterface>(
65 new TypedStructHandler<T>(handler))))
66 .second);
Brian Silvermand0575692015-02-21 16:24:02 -050067 }
68
69 // Adds a handler which takes messages and places them directly on a queue.
70 // T must be a Message with the same format as the messages generated by
71 // the .q files.
72 template <class T>
73 void AddDirectQueueSender(const ::std::string &process_name,
74 const ::std::string &log_message,
Austin Schuhdf6cbb12019-02-02 13:46:52 -080075 const ::std::string &name) {
Brian Silvermand0575692015-02-21 16:24:02 -050076 AddHandler(process_name, log_message,
77 ::std::function<void(const T &)>(
Austin Schuhdf6cbb12019-02-02 13:46:52 -080078 QueueDumpStructHandler<T>(name.c_str())));
Brian Silvermand0575692015-02-21 16:24:02 -050079 }
80
81 private:
82 // A generic handler of struct log messages.
83 class StructHandlerInterface {
84 public:
85 virtual ~StructHandlerInterface() {}
86
Austin Schuhf2a50ba2016-12-24 16:16:26 -080087 virtual void HandleStruct(::aos::monotonic_clock::time_point log_time,
88 uint32_t type_id, const void *data,
89 size_t data_size) = 0;
Brian Silvermand0575692015-02-21 16:24:02 -050090 };
91
92 // Converts struct log messages to a message type and passes it to an
93 // ::std::function.
94 template <class T>
95 class TypedStructHandler : public StructHandlerInterface {
96 public:
97 TypedStructHandler(::std::function<void(const T &message)> handler)
98 : handler_(handler) {}
99
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800100 void HandleStruct(::aos::monotonic_clock::time_point log_time,
101 uint32_t type_id, const void *data,
102 size_t data_size) override {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700103 AOS_CHECK_EQ(type_id, T::GetType()->id);
Brian Silvermand0575692015-02-21 16:24:02 -0500104 T message;
Austin Schuhf257f3c2019-10-27 21:00:43 -0700105 AOS_CHECK_EQ(data_size, T::Size());
106 AOS_CHECK_EQ(data_size,
107 message.Deserialize(static_cast<const char *>(data)));
Brian Silvermand0575692015-02-21 16:24:02 -0500108 message.sent_time = log_time;
109 handler_(message);
110 }
111
112 private:
113 const ::std::function<void(T message)> handler_;
114 };
115
116 // A callable class which dumps messages straight to a queue.
117 template <class T>
118 class QueueDumpStructHandler {
119 public:
120 QueueDumpStructHandler(const ::std::string &queue_name)
121 : queue_(RawQueue::Fetch(queue_name.c_str(), sizeof(T), T::kHash,
122 T::kQueueLength)) {}
123
124 void operator()(const T &message) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700125 AOS_LOG_STRUCT(DEBUG, "re-sending", message);
Brian Silvermand0575692015-02-21 16:24:02 -0500126 void *raw_message = queue_->GetMessage();
Austin Schuhf257f3c2019-10-27 21:00:43 -0700127 AOS_CHECK_NOTNULL(raw_message);
Brian Silvermand0575692015-02-21 16:24:02 -0500128 memcpy(raw_message, &message, sizeof(message));
Austin Schuhf257f3c2019-10-27 21:00:43 -0700129 AOS_CHECK(queue_->WriteMessage(raw_message, RawQueue::kOverride));
Brian Silvermand0575692015-02-21 16:24:02 -0500130 }
131
132 private:
133 ::aos::RawQueue *const queue_;
134 };
135
136 // A key for specifying log messages to give to a certain handler.
137 struct Key {
138 Key(const ::std::string &process_name, const ::std::string &log_message)
139 : process_name(process_name), log_message(log_message) {}
140
141 ::std::string process_name;
142 ::std::string log_message;
143 };
144
145 struct KeyHash {
146 size_t operator()(const Key &key) const {
147 return string_hash(key.process_name) ^
148 (string_hash(key.log_message) << 1);
149 }
150
151 private:
152 const ::std::hash<::std::string> string_hash = ::std::hash<::std::string>();
153 };
154 struct KeyEqual {
155 bool operator()(const Key &a, const Key &b) const {
156 return a.process_name == b.process_name && a.log_message == b.log_message;
157 }
158 };
159
160 ::std::unordered_map<const Key, ::std::unique_ptr<StructHandlerInterface>,
161 KeyHash, KeyEqual> handlers_;
162 ::std::unique_ptr<LogFileReader> reader_;
163
164 DISALLOW_COPY_AND_ASSIGN(LogReplayer);
165};
166
167} // namespace linux_code
168} // namespace logging
169} // namespace aos
170
John Park33858a32018-09-28 23:05:48 -0700171#endif // AOS_LOGGING_REPLAY_H_