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_file_apply_log(const struct subreader_logger *srl, const struct dlogutil_entry *due)
25 struct subreader_logger_file *const srlf = (struct subreader_logger_file *) srl->sub_userdata;
28 logfile_write_with_rotation(due, &srlf->file, DLOGUTIL_SORT_SENT_REAL);
31 static void subreader_logger_file_free(void *userdata)
33 struct subreader_logger_file *const srlf = (struct subreader_logger_file *) userdata;
36 logfile_free(&srlf->file);
39 static void subreader_logger_free(void *sub, void *userdata)
41 struct subreader_logger *const srl = (struct subreader_logger *) sub;
43 assert(userdata == NULL);
45 srl->sub_destroy(srl->sub_userdata);
47 log_filter_free(srl->filter);
48 free(srl->sub_userdata);
51 static void subreader_logger_apply_log(void *sub, void *userdata)
53 struct subreader_logger *const srl = (struct subreader_logger *) sub;
56 const struct dlogutil_entry *const due = (const struct dlogutil_entry *) userdata;
59 if (!log_should_print_line(srl->filter, due))
62 srl->sub_apply_log(srl, due);
64 void reader_logger_free(struct reader_logger *reader)
69 reader_deinit_common(&reader->common);
70 list_clear_custom(&reader->subs, NULL, subreader_logger_free);
74 void reader_logger_cleanup(struct reader_logger *const *ptr)
77 reader_logger_free(*ptr);
81 * @brief Service reader file
82 * @details Handles readers reading directly from file
83 * @param[in] reader The reader to service
84 * @param[in] time Timestamps
85 * @return 0 on success, else an errno value
86 * @return 1 if the reader is to be removed, 0 if kept, -errno on error
88 int service_reader_logger(struct reader_logger* reader, struct now_t time)
92 struct dlogutil_entry_with_msg entry;
93 static char buffer[sizeof entry + 1];
94 buffer[sizeof buffer - 1] = '\0';
96 /* The devices for the Android Logger only return one log per read().
97 * So using an 'if' here would be wasteful and, more importantly, too slow in the case where other logs come in.
98 * However, with an unlimited loop, if there are extreme amounts of logs incoming,
99 * the loop handles them slower than they come so the program stays in the loop
100 * for a very long time, starving all other log sources. Using a limited loop
101 * makes sure that the daemon works efficiently in the usual case while preventing
102 * starvation under heavy load. */
103 int max_loop_iterations = g_backend.logger_device_throttling[reader->buf_id];
104 while (max_loop_iterations--) {
105 int r = TEMP_FAILURE_RETRY(read(reader->common.fd_entity_source.fd, buffer, sizeof buffer - 1));
109 if (errno == EAGAIN) // no data left in the buffer
114 if (reader->skip_count > 0) {
115 reader->skip_count -= r;
120 parse_androidlogger_message((struct android_logger_entry *) buffer, &entry.header, r);
121 add_recv_timestamp(&entry.header, time);
123 list_foreach(reader->subs, &entry.header, subreader_logger_apply_log);
130 static struct reader_logger *reader_logger_alloc()
132 struct reader_logger *const ret = calloc(1, sizeof *ret);
136 ret->buf_id = LOG_ID_INVALID;
141 int reader_logger_add_subreader_file(struct reader_logger *reader, dlogutil_filter_options_s *filter, struct log_file *file)
146 struct subreader_logger *const srl = malloc(sizeof *srl);
147 struct subreader_logger_file *const srlf = malloc(sizeof *srlf);
154 logfile_move(&srlf->file, file);
156 srl->sub_userdata = srlf;
157 srl->sub_destroy = subreader_logger_file_free;
158 srl->sub_apply_log = subreader_logger_file_apply_log;
159 srl->filter = log_filter_move(filter);
161 list_add(&reader->subs, srl);
166 int reader_logger_add_subreader_metrics(struct reader_logger *reader, struct qos_module *qos)
171 struct subreader_logger *const srl = malloc(sizeof *srl);
172 struct subreader_logger_metrics *const srlm = malloc(sizeof *srlm);
173 dlogutil_filter_options_s *const filter = log_filter_new();
174 if (!srl || !srlm || !filter || dlogutil_filter_options_set_filterspec(filter, "*:V")) {
177 log_filter_free(filter);
183 srl->sub_userdata = srlm;
184 srl->sub_destroy = subreader_logger_metrics_free;
185 srl->sub_apply_log = subreader_logger_metrics_apply_log;
186 srl->filter = filter;
188 list_add(&reader->subs, srl);
193 static void dispatch_event_reader_logger(struct logger *server, struct epoll_event *event, void *userdata)
195 struct reader_logger *const rl = (struct reader_logger *) userdata;
198 if (event->events & (EPOLLHUP | EPOLLERR)) {
199 remove_reader_fd_entities(server, &rl->common);
200 list_remove(&server->readers_logger, rl);
201 reader_logger_free(rl);
205 int r = service_reader_logger(rl, server->time);
207 /* TODO: There is no reason not to free the reader in full. However, when I do so, some tests start to
208 * fail without any reasonable reason. You are welcome to *try* to figure out why does this happen. */
209 remove_reader_fd_entities(server, &rl->common);
213 int reader_logger_init(struct reader_logger **reader, log_id_t buf_id, struct logger *server, bool skip)
216 assert(buf_id > LOG_ID_INVALID);
217 assert(buf_id < LOG_ID_MAX);
218 assert(is_core_buffer(buf_id));
221 __attribute__((cleanup(reader_logger_cleanup))) struct reader_logger *ret = reader_logger_alloc();
225 assert(buf_id >= 0 && (unsigned) buf_id < NELEMS(g_backend.logger_devices));
226 char const *config_list = g_backend.logger_devices[buf_id];
227 if (strlen(config_list) == 0)
229 ret->buf_id = buf_id;
232 int r = logger_open_buffer(buf_id, config_list, O_RDONLY | O_NONBLOCK, &read_fd);
236 ret->skip_count = skip ? logger_get_log_len(read_fd) : 0;
238 init_fd_entity(&ret->common.fd_entity_sink, dispatch_event_reader_logger, ret);
239 init_fd_entity(&ret->common.fd_entity_source, dispatch_event_reader_logger, ret);
240 set_read_fd_entity(&ret->common.fd_entity_source, read_fd);