1 #include "reader_logger.h"
2 #include "logger_internal.h"
4 static void subreader_logger_metrics_apply_log(const struct subreader_logger *srl, const struct dlogutil_entry *due)
9 struct subreader_logger_metrics *const srlm = (struct subreader_logger_metrics *) srl->sub_userdata;
12 qos_add_log(srlm->qos, due);
15 static void subreader_logger_metrics_free(void *userdata)
17 // nothing to do; we're just a wrapper over a weak (shared) pointer
20 static void subreader_logger_metrics_flush(void *userdata, struct timespec ts, int flush_time)
22 // nothing to do either; no such concept as flushing metrics
25 static void subreader_logger_file_apply_log(const struct subreader_logger *srl, const struct dlogutil_entry *due)
30 struct subreader_logger_file *const srlf = (struct subreader_logger_file *) srl->sub_userdata;
33 logfile_write_with_rotation(due, &srlf->file, DLOGUTIL_SORT_SENT_REAL);
36 static void subreader_logger_file_free(void *userdata)
38 struct subreader_logger_file *const srlf = (struct subreader_logger_file *) userdata;
41 logfile_free(&srlf->file);
44 static void subreader_logger_file_flush(void *userdata, struct timespec ts, int flush_time)
46 struct subreader_logger_file *const srlf = (struct subreader_logger_file *) userdata;
49 flush_logfile_timely(&srlf->file, ts, flush_time);
52 static void subreader_logger_free(void *sub, void *userdata)
54 struct subreader_logger *const srl = (struct subreader_logger *) sub;
56 assert(userdata == NULL);
58 srl->sub_destroy(srl->sub_userdata);
60 log_filter_free(srl->filter);
61 free(srl->sub_userdata);
64 static void subreader_logger_apply_log(void *sub, void *userdata)
66 struct subreader_logger *const srl = (struct subreader_logger *) sub;
69 const struct dlogutil_entry *const due = (const struct dlogutil_entry *) userdata;
72 if (!log_should_print_line(srl->filter, due))
75 srl->sub_apply_log(srl, due);
83 static void subreader_logger_flush(void *sub, void *userdata)
85 struct subreader_logger *const srl = (struct subreader_logger *) sub;
87 assert(srl->sub_flush);
89 struct flush_args *const args = (struct flush_args *) userdata;
91 srl->sub_flush(srl->sub_userdata, args->ts, args->flush_time);
94 void reader_logger_free(struct reader_logger *reader)
99 reader_deinit_common(&reader->common);
100 list_clear_custom(&reader->subs, NULL, subreader_logger_free);
104 void reader_logger_cleanup(struct reader_logger *const *ptr)
107 reader_logger_free(*ptr);
111 * @brief Service reader file
112 * @details Handles readers reading directly from file
113 * @param[in] reader The reader to service
114 * @param[in] time Timestamps
115 * @return 0 on success, else an errno value
116 * @return 1 if the reader is to be removed, 0 if kept, -errno on error
118 int service_reader_logger(struct reader_logger* reader, struct now_t time)
122 struct dlogutil_entry_with_msg entry;
123 static char buffer[sizeof entry + 1];
124 buffer[sizeof buffer - 1] = '\0';
126 /* The devices for the Android Logger only return one log per read().
127 * So using an 'if' here would be wasteful and, more importantly, too slow in the case where other logs come in.
128 * However, with an unlimited loop, if there are extreme amounts of logs incoming,
129 * the loop handles them slower than they come so the program stays in the loop
130 * for a very long time, starving all other log sources. Using a limited loop
131 * makes sure that the daemon works efficiently in the usual case while preventing
132 * starvation under heavy load. */
133 int max_loop_iterations = g_backend.logger_device_throttling[reader->buf_id];
134 while (max_loop_iterations--) {
135 int r = TEMP_FAILURE_RETRY(read(reader->common.fd_entity_source.fd, buffer, sizeof buffer - 1));
139 if (errno == EAGAIN) // no data left in the buffer
144 if (reader->skip_count > 0) {
145 reader->skip_count -= r;
150 parse_androidlogger_message((struct android_logger_entry *) buffer, &entry.header, r);
151 add_recv_timestamp(&entry.header, time);
153 list_foreach(reader->subs, &entry.header, subreader_logger_apply_log);
160 static struct reader_logger *reader_logger_alloc()
162 struct reader_logger *const ret = calloc(1, sizeof *ret);
166 ret->buf_id = LOG_ID_INVALID;
171 int reader_logger_add_subreader_file(struct reader_logger *reader, dlogutil_filter_options_s *filter, struct log_file *file)
176 struct subreader_logger *const srl = malloc(sizeof *srl);
177 struct subreader_logger_file *const srlf = malloc(sizeof *srlf);
184 logfile_move(&srlf->file, file);
186 srl->sub_userdata = srlf;
187 srl->sub_destroy = subreader_logger_file_free;
188 srl->sub_apply_log = subreader_logger_file_apply_log;
189 srl->sub_flush = subreader_logger_file_flush;
190 srl->filter = log_filter_move(filter);
192 list_add(&reader->subs, srl);
197 int reader_logger_add_subreader_metrics(struct reader_logger *reader, struct qos_module *qos)
202 struct subreader_logger *const srl = malloc(sizeof *srl);
203 struct subreader_logger_metrics *const srlm = malloc(sizeof *srlm);
204 dlogutil_filter_options_s *const filter = log_filter_new();
205 if (!srl || !srlm || !filter || dlogutil_filter_options_set_filterspec(filter, "*:V")) {
208 log_filter_free(filter);
214 srl->sub_userdata = srlm;
215 srl->sub_destroy = subreader_logger_metrics_free;
216 srl->sub_apply_log = subreader_logger_metrics_apply_log;
217 srl->sub_flush = subreader_logger_file_flush;
218 srl->filter = filter;
220 list_add(&reader->subs, srl);
225 static void dispatch_event_reader_logger(struct logger *server, struct epoll_event *event, void *userdata)
227 struct reader_logger *const rl = (struct reader_logger *) userdata;
230 if (event->events & (EPOLLHUP | EPOLLERR)) {
231 remove_reader_fd_entities(server, &rl->common);
232 list_remove(&server->readers_logger, rl);
233 reader_logger_free(rl);
237 int r = service_reader_logger(rl, server->time);
239 /* TODO: There is no reason not to free the reader in full. However, when I do so, some tests start to
240 * fail without any reasonable reason. You are welcome to *try* to figure out why does this happen. */
241 remove_reader_fd_entities(server, &rl->common);
245 int reader_logger_init(struct reader_logger **reader, log_id_t buf_id, struct logger *server, bool skip)
248 assert(buf_id > LOG_ID_INVALID);
249 assert(buf_id < LOG_ID_MAX);
250 assert(is_core_buffer(buf_id));
253 __attribute__((cleanup(reader_logger_cleanup))) struct reader_logger *ret = reader_logger_alloc();
257 assert(buf_id >= 0 && (unsigned) buf_id < NELEMS(g_backend.logger_devices));
258 char const *config_list = g_backend.logger_devices[buf_id];
259 if (strlen(config_list) == 0)
261 ret->buf_id = buf_id;
264 int r = logger_open_buffer(buf_id, config_list, O_RDONLY | O_NONBLOCK, &read_fd);
268 ret->skip_count = skip ? logger_get_log_len(read_fd) : 0;
270 init_fd_entity(&ret->common.fd_entity_sink, dispatch_event_reader_logger, ret);
271 init_fd_entity(&ret->common.fd_entity_source, dispatch_event_reader_logger, ret);
272 set_read_fd_entity(&ret->common.fd_entity_source, read_fd);
279 void reader_logger_flush(struct reader_logger *reader, struct timespec now_mono, int flush)
281 list_foreach(reader->subs, &(struct flush_args) {
284 }, subreader_logger_flush);