9442bffb098c1ad17c09d89921650387b42d01cd
[platform/core/system/dlog.git] / src / logger / reader_logger.c
1 #include "reader_logger.h"
2 #include "logger_internal.h"
3
4 static void subreader_logger_metrics_apply_log(const struct subreader_logger *srl, const struct dlogutil_entry *due)
5 {
6         assert(srl);
7         assert(due);
8
9         struct subreader_logger_metrics *const srlm = (struct subreader_logger_metrics *) srl->sub_userdata;
10         assert(srlm);
11
12         qos_add_log(srlm->qos, due);
13 }
14
15 static void subreader_logger_metrics_free(void *userdata)
16 {
17         // nothing to do; we're just a wrapper over a weak (shared) pointer
18 }
19
20 static void subreader_logger_metrics_flush(void *userdata, struct timespec ts, int flush_time)
21 {
22         // nothing to do either; no such concept as flushing metrics
23 }
24
25 static void subreader_logger_file_apply_log(const struct subreader_logger *srl, const struct dlogutil_entry *due)
26 {
27         assert(srl);
28         assert(due);
29
30         struct subreader_logger_file *const srlf = (struct subreader_logger_file *) srl->sub_userdata;
31         assert(srlf);
32
33         logfile_write_with_rotation(due, &srlf->file, DLOGUTIL_SORT_SENT_REAL);
34 }
35
36 static void subreader_logger_file_free(void *userdata)
37 {
38         struct subreader_logger_file *const srlf = (struct subreader_logger_file *) userdata;
39         assert(srlf);
40
41         logfile_free(&srlf->file);
42 }
43
44 static void subreader_logger_file_flush(void *userdata, struct timespec ts, int flush_time)
45 {
46         struct subreader_logger_file *const srlf = (struct subreader_logger_file *) userdata;
47         assert(srlf);
48
49         flush_logfile_timely(&srlf->file, ts, flush_time);
50 }
51
52 static void subreader_logger_free(void *sub, void *userdata)
53 {
54         struct subreader_logger *const srl = (struct subreader_logger *) sub;
55         assert(srl);
56         assert(userdata == NULL);
57
58         srl->sub_destroy(srl->sub_userdata);
59         if (srl->filter)
60                 log_filter_free(srl->filter);
61         free(srl->sub_userdata);
62 }
63
64 static void subreader_logger_apply_log(void *sub, void *userdata)
65 {
66         struct subreader_logger *const srl = (struct subreader_logger *) sub;
67         assert(srl);
68
69         const struct dlogutil_entry *const due = (const struct dlogutil_entry *) userdata;
70         assert(due);
71
72         if (!log_should_print_line(srl->filter, due))
73                 return;
74
75         srl->sub_apply_log(srl, due);
76 }
77
78 struct flush_args {
79         struct timespec ts;
80         int flush_time;
81 };
82
83 static void subreader_logger_flush(void *sub, void *userdata)
84 {
85         struct subreader_logger *const srl = (struct subreader_logger *) sub;
86         assert(srl);
87         assert(srl->sub_flush);
88
89         struct flush_args *const args = (struct flush_args *) userdata;
90
91         srl->sub_flush(srl->sub_userdata, args->ts, args->flush_time);
92 }
93
94 void reader_logger_free(struct reader_logger *reader)
95 {
96         if (!reader)
97                 return;
98
99         reader_deinit_common(&reader->common);
100         list_clear_custom(&reader->subs, NULL, subreader_logger_free);
101         free(reader);
102 }
103
104 void reader_logger_cleanup(struct reader_logger *const *ptr)
105 {
106         assert(ptr);
107         reader_logger_free(*ptr);
108 }
109
110 /**
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
117  */
118 int service_reader_logger(struct reader_logger *reader, struct now_t time)
119 {
120         assert(reader);
121
122         struct dlogutil_entry_with_msg entry;
123         static char buffer[sizeof entry + 1];
124         buffer[sizeof buffer - 1] = '\0';
125
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));
136                 if (r == 0)
137                         break;
138                 else if (r == -1) {
139                         if (errno == EAGAIN) // no data left in the buffer
140                                 break;
141                         else
142                                 return -errno;
143                 } else {
144                         if (reader->skip_count > 0) {
145                                 reader->skip_count -= r;
146                                 continue;
147                         }
148
149                         buffer[r] = '\0';
150                         parse_androidlogger_message((struct android_logger_entry *) buffer, &entry.header, r);
151                         add_recv_timestamp(&entry.header, time);
152
153                         list_foreach(reader->subs, &entry.header, subreader_logger_apply_log);
154                 }
155         }
156
157         return 0;
158 }
159
160 static struct reader_logger *reader_logger_alloc()
161 {
162         struct reader_logger *const ret = calloc(1, sizeof *ret);
163         if (!ret)
164                 return NULL;
165
166         ret->buf_id = LOG_ID_INVALID;
167
168         return ret;
169 }
170
171 int reader_logger_add_subreader_file(struct reader_logger *reader, struct log_filter *filter, struct log_file *file)
172 {
173         assert(reader);
174         assert(filter);
175
176         struct subreader_logger *const srl = malloc(sizeof *srl);
177         struct subreader_logger_file *const srlf = malloc(sizeof *srlf);
178         if (!srl || !srlf) {
179                 free(srl);
180                 free(srlf);
181                 return -ENOMEM;
182         }
183
184         logfile_move(&srlf->file, file);
185
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);
191
192         list_add(&reader->subs, srl);
193
194         return 0;
195 }
196
197 int reader_logger_add_subreader_metrics(struct reader_logger *reader, struct qos_module *qos)
198 {
199         assert(reader);
200         assert(qos);
201
202         struct subreader_logger *const srl = malloc(sizeof *srl);
203         struct subreader_logger_metrics *const srlm = malloc(sizeof *srlm);
204         struct log_filter *const filter = log_filter_new();
205         if (!srl || !srlm || !filter || log_filter_set_filterspec(filter, "*:V")) {
206                 free(srl);
207                 free(srlm);
208                 log_filter_free(filter);
209                 return -ENOMEM;
210         }
211
212         srlm->qos = qos;
213
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_metrics_flush;
218         srl->filter = filter;
219
220         list_add(&reader->subs, srl);
221
222         return 0;
223 }
224
225 static void dispatch_event_reader_logger(struct logger *server, struct epoll_event *event, void *userdata)
226 {
227         struct reader_logger *const rl = (struct reader_logger *) userdata;
228         assert(rl);
229
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);
234                 return;
235         }
236
237         int r = service_reader_logger(rl, server->time);
238         if (r != 0) {
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);
242         }
243 }
244
245 int reader_logger_init(struct reader_logger **reader, log_id_t buf_id, struct logger *server, bool skip)
246 {
247         assert(reader);
248         assert(buf_id > LOG_ID_INVALID);
249         assert(buf_id < LOG_ID_MAX);
250         assert(is_core_buffer(buf_id));
251         assert(server);
252
253         __attribute__((cleanup(reader_logger_cleanup))) struct reader_logger *ret = reader_logger_alloc();
254         if (!ret)
255                 return -ENOMEM;
256
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)
260                 return -ENOENT;
261         ret->buf_id = buf_id;
262
263         int read_fd = -1;
264         int r = logger_open_buffer(buf_id, config_list, O_RDONLY | O_NONBLOCK, &read_fd);
265         if (r <= 0)
266                 return r;
267
268         ret->skip_count = skip ? logger_get_log_len(read_fd) : 0;
269
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);
273
274         *reader = ret;
275         ret = NULL;
276         return 0;
277 }
278
279 void reader_logger_flush(struct reader_logger *reader, struct timespec now_mono, int flush)
280 {
281         list_foreach(reader->subs, &(struct flush_args) {
282                 .ts = now_mono,
283                 .flush_time = flush,
284         }, subreader_logger_flush);
285 }