Austin Schuh | e309d2a | 2019-11-29 13:25:21 -0800 | [diff] [blame] | 1 | #ifndef AOS_EVENTS_LOGGER_H_ |
| 2 | #define AOS_EVENTS_LOGGER_H_ |
| 3 | |
| 4 | #include <deque> |
| 5 | #include <vector> |
Austin Schuh | 05b7047 | 2020-01-01 17:11:17 -0800 | [diff] [blame] | 6 | #include <string_view> |
Austin Schuh | e309d2a | 2019-11-29 13:25:21 -0800 | [diff] [blame] | 7 | |
Austin Schuh | e309d2a | 2019-11-29 13:25:21 -0800 | [diff] [blame] | 8 | #include "absl/types/span.h" |
| 9 | #include "aos/events/event_loop.h" |
Austin Schuh | a36c890 | 2019-12-30 18:07:15 -0800 | [diff] [blame] | 10 | #include "aos/events/logging/logfile_utils.h" |
James Kuszmaul | 38735e8 | 2019-12-07 16:42:06 -0800 | [diff] [blame] | 11 | #include "aos/events/logging/logger_generated.h" |
Austin Schuh | 9254752 | 2019-12-28 14:33:43 -0800 | [diff] [blame] | 12 | #include "aos/events/simulated_event_loop.h" |
Austin Schuh | e309d2a | 2019-11-29 13:25:21 -0800 | [diff] [blame] | 13 | #include "aos/time/time.h" |
| 14 | #include "flatbuffers/flatbuffers.h" |
| 15 | |
| 16 | namespace aos { |
| 17 | namespace logger { |
| 18 | |
Austin Schuh | e309d2a | 2019-11-29 13:25:21 -0800 | [diff] [blame] | 19 | // Logs all channels available in the event loop to disk every 100 ms. |
| 20 | // Start by logging one message per channel to capture any state and |
| 21 | // configuration that is sent rately on a channel and would affect execution. |
| 22 | class Logger { |
| 23 | public: |
| 24 | Logger(DetachedBufferWriter *writer, EventLoop *event_loop, |
| 25 | std::chrono::milliseconds polling_period = |
| 26 | std::chrono::milliseconds(100)); |
| 27 | |
Austin Schuh | fa89589 | 2020-01-07 20:07:41 -0800 | [diff] [blame^] | 28 | // Rotates the log file with the new writer. This writes out the header |
| 29 | // again, but keeps going as if nothing else happened. |
| 30 | void Rotate(DetachedBufferWriter *writer); |
| 31 | |
Austin Schuh | e309d2a | 2019-11-29 13:25:21 -0800 | [diff] [blame] | 32 | private: |
Austin Schuh | fa89589 | 2020-01-07 20:07:41 -0800 | [diff] [blame^] | 33 | void WriteHeader(); |
| 34 | |
Austin Schuh | e309d2a | 2019-11-29 13:25:21 -0800 | [diff] [blame] | 35 | void DoLogData(); |
| 36 | |
| 37 | EventLoop *event_loop_; |
| 38 | DetachedBufferWriter *writer_; |
| 39 | |
| 40 | // Structure to track both a fetcher, and if the data fetched has been |
| 41 | // written. We may want to delay writing data to disk so that we don't let |
| 42 | // data get too far out of order when written to disk so we can avoid making |
| 43 | // it too hard to sort when reading. |
| 44 | struct FetcherStruct { |
| 45 | std::unique_ptr<RawFetcher> fetcher; |
| 46 | bool written = false; |
Austin Schuh | 15649d6 | 2019-12-28 16:36:38 -0800 | [diff] [blame] | 47 | |
| 48 | LogType log_type; |
Austin Schuh | e309d2a | 2019-11-29 13:25:21 -0800 | [diff] [blame] | 49 | }; |
| 50 | |
| 51 | std::vector<FetcherStruct> fetchers_; |
| 52 | TimerHandler *timer_handler_; |
| 53 | |
| 54 | // Period to poll the channels. |
| 55 | const std::chrono::milliseconds polling_period_; |
| 56 | |
| 57 | // Last time that data was written for all channels to disk. |
| 58 | monotonic_clock::time_point last_synchronized_time_; |
| 59 | |
Austin Schuh | fa89589 | 2020-01-07 20:07:41 -0800 | [diff] [blame^] | 60 | monotonic_clock::time_point monotonic_start_time_; |
| 61 | realtime_clock::time_point realtime_start_time_; |
| 62 | |
Austin Schuh | e309d2a | 2019-11-29 13:25:21 -0800 | [diff] [blame] | 63 | // Max size that the header has consumed. This much extra data will be |
| 64 | // reserved in the builder to avoid reallocating. |
| 65 | size_t max_header_size_ = 0; |
| 66 | }; |
| 67 | |
| 68 | // Replays all the channels in the logfile to the event loop. |
| 69 | class LogReader { |
| 70 | public: |
James Kuszmaul | c7bbb3e | 2020-01-03 20:01:00 -0800 | [diff] [blame] | 71 | // If you want to supply a new configuration that will be used for replay |
| 72 | // (e.g., to change message rates, or to populate an updated schema), then |
| 73 | // pass it in here. It must provide all the channels that the original logged |
| 74 | // config did. |
| 75 | LogReader(std::string_view filename, |
| 76 | const Configuration *replay_configuration = nullptr); |
Austin Schuh | fa89589 | 2020-01-07 20:07:41 -0800 | [diff] [blame^] | 77 | LogReader(const std::vector<std::string> &filename, |
| 78 | const Configuration *replay_configuration = nullptr); |
James Kuszmaul | 7daef36 | 2019-12-31 18:28:17 -0800 | [diff] [blame] | 79 | ~LogReader(); |
Austin Schuh | e309d2a | 2019-11-29 13:25:21 -0800 | [diff] [blame] | 80 | |
Austin Schuh | 6331ef9 | 2020-01-07 18:28:09 -0800 | [diff] [blame] | 81 | // Registers all the callbacks to send the log file data out on an event loop |
| 82 | // created in event_loop_factory. This also updates time to be at the start |
| 83 | // of the log file by running until the log file starts. |
| 84 | // Note: the configuration used in the factory should be configuration() |
| 85 | // below, but can be anything as long as the locations needed to send |
| 86 | // everything are available. |
James Kuszmaul | 84ff3e5 | 2020-01-03 19:48:53 -0800 | [diff] [blame] | 87 | void Register(SimulatedEventLoopFactory *event_loop_factory); |
Austin Schuh | 6331ef9 | 2020-01-07 18:28:09 -0800 | [diff] [blame] | 88 | // Creates an SimulatedEventLoopFactory accessible via event_loop_factory(), |
| 89 | // and then calls Register. |
| 90 | void Register(); |
| 91 | // Registers callbacks for all the events after the log file starts. This is |
| 92 | // only useful when replaying live. |
Austin Schuh | e309d2a | 2019-11-29 13:25:21 -0800 | [diff] [blame] | 93 | void Register(EventLoop *event_loop); |
Austin Schuh | 6331ef9 | 2020-01-07 18:28:09 -0800 | [diff] [blame] | 94 | |
James Kuszmaul | 84ff3e5 | 2020-01-03 19:48:53 -0800 | [diff] [blame] | 95 | // Unregisters the senders. You only need to call this if you separately |
| 96 | // supplied an event loop or event loop factory and the lifetimes are such |
| 97 | // that they need to be explicitly destroyed before the LogReader destructor |
| 98 | // gets called. |
Austin Schuh | e309d2a | 2019-11-29 13:25:21 -0800 | [diff] [blame] | 99 | void Deregister(); |
| 100 | |
Austin Schuh | e309d2a | 2019-11-29 13:25:21 -0800 | [diff] [blame] | 101 | // Returns the configuration from the log file. |
James Kuszmaul | c7bbb3e | 2020-01-03 20:01:00 -0800 | [diff] [blame] | 102 | const Configuration *logged_configuration() const; |
| 103 | // Returns the configuration being used for replay. |
Austin Schuh | 15649d6 | 2019-12-28 16:36:38 -0800 | [diff] [blame] | 104 | const Configuration *configuration() const; |
| 105 | |
Austin Schuh | 6331ef9 | 2020-01-07 18:28:09 -0800 | [diff] [blame] | 106 | const LogFileHeader *log_file_header() const { |
| 107 | return sorted_message_reader_.log_file_header(); |
| 108 | } |
| 109 | |
| 110 | // Returns the node that this log file was created on. This is a pointer to a |
| 111 | // node in the nodes() list inside configuration(). |
Austin Schuh | 15649d6 | 2019-12-28 16:36:38 -0800 | [diff] [blame] | 112 | const Node *node() const; |
Austin Schuh | e309d2a | 2019-11-29 13:25:21 -0800 | [diff] [blame] | 113 | |
| 114 | // Returns the starting timestamp for the log file. |
| 115 | monotonic_clock::time_point monotonic_start_time(); |
| 116 | realtime_clock::time_point realtime_start_time(); |
| 117 | |
James Kuszmaul | c7bbb3e | 2020-01-03 20:01:00 -0800 | [diff] [blame] | 118 | // Causes the logger to publish the provided channel on a different name so |
| 119 | // that replayed applications can publish on the proper channel name without |
| 120 | // interference. This operates on raw channel names, without any node or |
| 121 | // application specific mappings. |
| 122 | void RemapLoggedChannel(std::string_view name, std::string_view type, |
| 123 | std::string_view add_prefix = "/original"); |
| 124 | template <typename T> |
| 125 | void RemapLoggedChannel(std::string_view name, |
| 126 | std::string_view add_prefix = "/original") { |
| 127 | RemapLoggedChannel(name, T::GetFullyQualifiedName(), add_prefix); |
| 128 | } |
| 129 | |
James Kuszmaul | 84ff3e5 | 2020-01-03 19:48:53 -0800 | [diff] [blame] | 130 | SimulatedEventLoopFactory *event_loop_factory() { |
| 131 | return event_loop_factory_; |
| 132 | } |
| 133 | |
Austin Schuh | e309d2a | 2019-11-29 13:25:21 -0800 | [diff] [blame] | 134 | // TODO(austin): Add the ability to re-publish the fetched messages. Add 2 |
| 135 | // options, one which publishes them *now*, and another which publishes them |
| 136 | // to the simulated event loop factory back in time where they actually |
| 137 | // happened. |
| 138 | |
| 139 | private: |
Austin Schuh | e309d2a | 2019-11-29 13:25:21 -0800 | [diff] [blame] | 140 | // Queues at least max_out_of_order_duration_ messages into channels_. |
| 141 | void QueueMessages(); |
James Kuszmaul | c7bbb3e | 2020-01-03 20:01:00 -0800 | [diff] [blame] | 142 | // Handle constructing a configuration with all the additional remapped |
| 143 | // channels from calls to RemapLoggedChannel. |
| 144 | void MakeRemappedConfig(); |
Austin Schuh | e309d2a | 2019-11-29 13:25:21 -0800 | [diff] [blame] | 145 | |
Austin Schuh | 05b7047 | 2020-01-01 17:11:17 -0800 | [diff] [blame] | 146 | // Log chunk reader. |
| 147 | SortedMessageReader sorted_message_reader_; |
Austin Schuh | e309d2a | 2019-11-29 13:25:21 -0800 | [diff] [blame] | 148 | |
James Kuszmaul | 84ff3e5 | 2020-01-03 19:48:53 -0800 | [diff] [blame] | 149 | std::unique_ptr<FlatbufferDetachedBuffer<Configuration>> |
| 150 | remapped_configuration_buffer_; |
| 151 | |
Austin Schuh | 05b7047 | 2020-01-01 17:11:17 -0800 | [diff] [blame] | 152 | std::vector<std::unique_ptr<RawSender>> channels_; |
Austin Schuh | e309d2a | 2019-11-29 13:25:21 -0800 | [diff] [blame] | 153 | |
Austin Schuh | 9254752 | 2019-12-28 14:33:43 -0800 | [diff] [blame] | 154 | std::unique_ptr<EventLoop> event_loop_unique_ptr_; |
| 155 | EventLoop *event_loop_ = nullptr; |
Austin Schuh | e309d2a | 2019-11-29 13:25:21 -0800 | [diff] [blame] | 156 | TimerHandler *timer_handler_; |
James Kuszmaul | 84ff3e5 | 2020-01-03 19:48:53 -0800 | [diff] [blame] | 157 | |
| 158 | std::unique_ptr<SimulatedEventLoopFactory> event_loop_factory_unique_ptr_; |
| 159 | SimulatedEventLoopFactory *event_loop_factory_ = nullptr; |
James Kuszmaul | c7bbb3e | 2020-01-03 20:01:00 -0800 | [diff] [blame] | 160 | |
| 161 | // Map of channel indices to new name. The channel index will be an index into |
| 162 | // logged_configuration(), and the string key will be the name of the channel |
| 163 | // to send on instead of the logged channel name. |
| 164 | std::map<size_t, std::string> remapped_channels_; |
| 165 | |
| 166 | const Configuration *remapped_configuration_ = nullptr; |
| 167 | const Configuration *replay_configuration_ = nullptr; |
Austin Schuh | e309d2a | 2019-11-29 13:25:21 -0800 | [diff] [blame] | 168 | }; |
| 169 | |
| 170 | } // namespace logger |
| 171 | } // namespace aos |
| 172 | |
| 173 | #endif // AOS_EVENTS_LOGGER_H_ |