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