1f4fb521f074ff9463c4543cc1d7284d00cdcff6
[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_file_apply_log(const struct subreader_logger *srl, const struct dlogutil_entry *due)
21 {
22         assert(srl);
23         assert(due);
24
25         struct subreader_logger_file *const srlf = (struct subreader_logger_file *) srl->sub_userdata;
26         assert(srlf);
27
28         logfile_write_with_rotation(due, &srlf->file, DLOGUTIL_SORT_SENT_REAL);
29 }
30
31 static void subreader_logger_file_free(void *userdata)
32 {
33         struct subreader_logger_file *const srlf = (struct subreader_logger_file *) userdata;
34         assert(srlf);
35
36         logfile_free(&srlf->file);
37 }
38
39 static void subreader_logger_free(void *sub, void *userdata)
40 {
41         struct subreader_logger *const srl = (struct subreader_logger *) sub;
42         assert(srl);
43         assert(userdata == NULL);
44
45         srl->sub_destroy(srl->sub_userdata);
46         if (srl->filter)
47                 log_filter_free(srl->filter);
48         free(srl->sub_userdata);
49 }
50
51 static void subreader_logger_apply_log(void *sub, void *userdata)
52 {
53         struct subreader_logger *const srl = (struct subreader_logger *) sub;
54         assert(srl);
55
56         const struct dlogutil_entry *const due = (const struct dlogutil_entry *) userdata;
57         assert(due);
58
59         if (!log_should_print_line(srl->filter, due))
60                 return;
61
62         srl->sub_apply_log(srl, due);
63 }
64 void reader_logger_free(struct reader_logger *reader)
65 {
66         if (!reader)
67                 return;
68
69         reader_deinit_common(&reader->common);
70         list_clear_custom(&reader->subs, NULL, subreader_logger_free);
71         free(reader);
72 }
73
74 void reader_logger_cleanup(struct reader_logger *const *ptr)
75 {
76         assert(ptr);
77         reader_logger_free(*ptr);
78 }
79
80 /**
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
87  */
88 int service_reader_logger(struct reader_logger* reader, struct now_t time)
89 {
90         assert(reader);
91
92         struct dlogutil_entry_with_msg entry;
93         static char buffer[sizeof entry + 1];
94         buffer[sizeof buffer - 1] = '\0';
95
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));
106                 if (r == 0)
107                         break;
108                 else if (r == -1) {
109                         if (errno == EAGAIN) // no data left in the buffer
110                                 break;
111                         else
112                                 return -errno;
113                 } else {
114                         if (reader->skip_count > 0) {
115                                 reader->skip_count -= r;
116                                 continue;
117                         }
118
119                         buffer[r] = '\0';
120                         parse_androidlogger_message((struct android_logger_entry *) buffer, &entry.header, r);
121                         add_recv_timestamp(&entry.header, time);
122
123                         list_foreach(reader->subs, &entry.header, subreader_logger_apply_log);
124                 }
125         }
126
127         return 0;
128 }
129
130 static struct reader_logger *reader_logger_alloc()
131 {
132         struct reader_logger *const ret = calloc(1, sizeof *ret);
133         if (!ret)
134                 return NULL;
135
136         ret->buf_id = LOG_ID_INVALID;
137
138         return ret;
139 }
140
141 int reader_logger_add_subreader_file(struct reader_logger *reader, dlogutil_filter_options_s *filter, struct log_file *file)
142 {
143         assert(reader);
144         assert(filter);
145
146         struct subreader_logger *const srl = malloc(sizeof *srl);
147         struct subreader_logger_file *const srlf = malloc(sizeof *srlf);
148         if (!srl || !srlf) {
149                 free(srl);
150                 free(srlf);
151                 return -ENOMEM;
152         }
153
154         logfile_move(&srlf->file, file);
155
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);
160
161         list_add(&reader->subs, srl);
162
163         return 0;
164 }
165
166 int reader_logger_add_subreader_metrics(struct reader_logger *reader, struct qos_module *qos)
167 {
168         assert(reader);
169         assert(qos);
170
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")) {
175                 free(srl);
176                 free(srlm);
177                 log_filter_free(filter);
178                 return -ENOMEM;
179         }
180
181         srlm->qos = qos;
182
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;
187
188         list_add(&reader->subs, srl);
189
190         return 0;
191 }
192
193 static void dispatch_event_reader_logger(struct logger *server, struct epoll_event *event, void *userdata)
194 {
195         struct reader_logger *const rl = (struct reader_logger *) userdata;
196         assert(rl);
197
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);
202                 return;
203         }
204
205         int r = service_reader_logger(rl, server->time);
206         if (r != 0) {
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);
210         }
211 }
212
213 int reader_logger_init(struct reader_logger **reader, log_id_t buf_id, struct logger *server, bool skip)
214 {
215         assert(reader);
216         assert(buf_id > LOG_ID_INVALID);
217         assert(buf_id < LOG_ID_MAX);
218         assert(is_core_buffer(buf_id));
219         assert(server);
220
221         __attribute__((cleanup(reader_logger_cleanup))) struct reader_logger *ret = reader_logger_alloc();
222         if (!ret)
223                 return -ENOMEM;
224
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)
228                 return -ENOENT;
229         ret->buf_id = buf_id;
230
231         int read_fd = -1;
232         int r = logger_open_buffer(buf_id, config_list, O_RDONLY | O_NONBLOCK, &read_fd);
233         if (r <= 0)
234                 return r;
235
236         ret->skip_count = skip ? logger_get_log_len(read_fd) : 0;
237
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);
241
242         *reader = ret;
243         ret = NULL;
244         return 0;
245 }
246