2 * Copyright (c) 2016, Samsung Electronics Co., Ltd. All rights reserved.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
21 #include "logger_internal.h"
22 #include "logger_privileges.h"
26 #include <dynamic_config.h>
27 #include <qos_defaults.h>
30 * @addtogroup DLOG_IMPLEMENTATION
32 * @defgroup DLOG_LOGGER Logger
33 * @brief Logger daemon
34 * @details The logger is the core component of the logging framework. It is responsible for collecting, processing and exposing logs.
38 // function prototypes
39 static int initialize_epoll_size(struct epoll_event **events, unsigned *size);
41 /** global state when logger is not interrupted by any handled signals */
42 static volatile sig_atomic_t g_logger_run = 1;
44 static const int DEFAULT_EPOLL_TIME_MS = 1000;
46 static const int DEFAULT_LAZY_POLLING_TOTAL_MS = 0;
47 static const int DEFAULT_LAZY_POLLING_SLEEP_MS = 1000;
49 static const int S_TO_MS = 1000;
50 static const int MS_TO_NS = 1000000;
52 struct backend_data g_backend = {};
54 static bool cond_reader_logger_free(void *ptr, void *user_data)
56 struct reader_logger *reader = (struct reader_logger *)ptr;
57 struct logger *logger = (struct logger *)user_data;
59 // TODO: This is absurd, why isn't this in the reader_logger_free function?
60 if (reader->common.fd_entity_sink.fd >= 0)
61 remove_fd_entity(&logger->epoll_common, &reader->common.fd_entity_sink);
62 if (reader->common.fd_entity_source.fd >= 0)
63 remove_fd_entity(&logger->epoll_common, &reader->common.fd_entity_source);
64 reader_logger_free(reader);
68 // TODO: Consider inlining struct now_t everywhere
69 int get_now(struct now_t *now)
71 if (clock_gettime(CLOCK_MONOTONIC, &now->mono))
73 if (clock_gettime(CLOCK_REALTIME, &now->real))
78 void qos_periodic_check(struct logger *server)
80 struct qos_module *const qos = &server->qos;
81 struct timespec ts_mono;
82 if (clock_gettime(CLOCK_MONOTONIC, &ts_mono))
85 if (ts_mono.tv_sec < qos->cancel_limits_at.tv_sec)
87 if (ts_mono.tv_sec == qos->cancel_limits_at.tv_sec
88 && ts_mono.tv_nsec < qos->cancel_limits_at.tv_nsec)
91 if (metrics_get_total(qos->log_metrics) >= qos->threshold)
92 qos_apply_limits(qos);
94 qos_relax_limits(qos);
96 qos_set_next_update_time(qos, ts_mono);
97 metrics_clear(qos->log_metrics);
101 * @brief FD limit handler
102 * @details Checks whether the FD limit was reached and leaves logs about it if so
103 * @param[in] server The logger server
104 * @param[in] err errno from the call that failed to create an FD
106 void check_if_fd_limit_reached(struct logger *server, int err)
110 if (err != ENFILE && err != EMFILE)
113 printf("ERROR: dlog_logger fd limit reached!\n");
115 /* pick one representative buffer to send the log to;
116 * no point spamming all the buffers, especially since
117 * default dlogutil invocations display 3 buffers so
118 * it would appear multiple times */
119 struct log_buffer *const buf = server->buffers[LOG_ID_MAIN];
123 struct dlogutil_entry_with_msg entry;
124 create_pipe_message(&entry,
125 DLOG_FATAL, /* not really FATAL, but since we're at the FD limit
126 * there are thousands of logging programs so this one
127 * would likely get lost in the flood since developers
128 * tend to overuse ERROR (and FATAL is the one above) */
130 "\x1b[31m DLOG DAEMON FD LIMIT REACHED \x1b[0m" // make it stand out
133 int r = get_now(&now);
136 set_pipe_message_sent_timestamp((struct pipe_logger_entry *) &entry, &now.mono, &now.real);
138 if (buffer_append(&entry.header, buf))
139 printf("ERROR: not enough memory either, please check platform settings as the daemon is seriously resource-starved!\n");
142 void flush_logfile_timely(struct log_file *file, struct timespec ts, int flush_time)
144 if (file->buffer.position > 0) {
145 if (ts.tv_sec - file->buffer.oldest_log.tv_sec +
146 (ts.tv_nsec > file->buffer.oldest_log.tv_nsec ? 1 : 0) >
152 void reader_notify_losing_log(const dlogutil_entry_s *le, void *reader_)
154 struct reader_pipe *reader = (struct reader_pipe *) reader_;
157 reader_print_out_single_log(reader, (dlogutil_entry_s *)le);
161 * @brief Add reader to log buffer
162 * @details Adds a reader to the log buffers reader list
163 * @param[in] log_buffer The buffer whither to add the reader
164 * @param[in] reader The reader to add to the buffer
165 * @return 0 on success, -ENOMEM on memory allocation error
167 int add_buffer_reader(struct log_buffer *buffer, struct reader_pipe *reader)
172 reader->log_storage_reader_ptr = log_storage_new_reader(buffer->log_storage_ptr,
173 reader->is_dumping, reader->monitor, reader_notify_losing_log, reader);
175 if (!reader->log_storage_reader_ptr)
178 return list_add(&buffer->readers_pipe, reader) ? 0 : -ENOMEM;
181 int add_reader_pipe(struct logger *server, struct reader_pipe *reader)
186 if (reader->common.fd_entity_sink.fd >= 0) {
187 /* Readers who write to file have no sink FD entity (or, strictly
188 * speaking, they do have one but it is not filled) since a file
189 * is not eligible to be added to epoll. However, the entity primarily
190 * serves to handle pipes getting clogged mid-write (which cannot
191 * happen for files) and is not involved in starting a write,
192 * which is handled by the source FD entity, not sink (and which is
193 * also done periodically for all readers anyway regardless
194 * of whether they've been added to epoll or not). The other use
195 * case for epoll - the one where connection FDs leak for unused
196 * buffers - is not a problem here because the daemon is not
197 * supposed to ever stop writing to files. */
199 int r = add_fd_entity(&server->epoll_common, &reader->common.fd_entity_sink);
205 ret = add_buffer_reader(reader->buf_ptr, reader);
206 if (ret < 0 && reader->common.fd_entity_sink.fd >= 0)
207 remove_fd_entity(&server->epoll_common, &reader->common.fd_entity_sink);
212 static int add_reader_logger(struct logger *server, struct reader_logger *reader)
217 if (reader->common.fd_entity_sink.fd >= 0) {
218 /* Readers who write to file have no sink FD entity (or, strictly
219 * speaking, they do have one but it is not filled) since a file
220 * is not eligible to be added to epoll. However, the entity primarily
221 * serves to handle pipes getting clogged mid-write (which cannot
222 * happen for files) and is not involved in starting a write,
223 * which is handled by the source FD entity, not sink (and which is
224 * also done periodically for all readers anyway regardless
225 * of whether they've been added to epoll or not). The other use
226 * case for epoll - the one where connection FDs leak for unused
227 * buffers - is not a problem here because the daemon is not
228 * supposed to ever stop writing to files. */
230 int r = add_fd_entity(&server->epoll_common, &reader->common.fd_entity_sink);
237 assert(reader->common.fd_entity_source.fd >= 0);
238 ret = add_fd_entity(&server->epoll_common, &reader->common.fd_entity_source);
242 if (!list_add(&server->readers_logger, reader)) {
243 remove_fd_entity(&server->epoll_common, &reader->common.fd_entity_source);
251 if (reader->common.fd_entity_sink.fd >= 0)
252 remove_fd_entity(&server->epoll_common, &reader->common.fd_entity_sink);
257 int create_fifo_fds(struct logger *server, int pipe_fd[2], int flags, bool dump)
259 int ret = get_nonblocking_fifo(pipe_fd, flags);
263 /* Speed up dumping dlogutils by increasing their pipe size,
264 * as otherwise this pipe's size becomes a major bottleneck.
266 * Continuous connections don't really care if the initial
267 * burst of "historic" logs is slow and the following flow
268 * of logs is just fine with a small pipe. Meanwhile they
269 * live for a long time during which they would take away
270 * from the valuable total pipe size. */
272 if (fcntl(pipe_fd[1], F_SETPIPE_SZ, DUMPING_READER_PIPE_SIZE) < 0) {
273 /* Ignore; this is just a performance optimisation
274 * and doesn't affect functionality so while errors
275 * are worrisome they not a big deal or something
276 * we can do anything about, at any rate. */
282 static int create_logger_subreader_from_dlogutil_line(struct dlogutil_line_params *params)
284 if (params->file_path) {
285 int retval = logfile_set_path(¶ms->file, params->file_path);
289 retval = logfile_open(¶ms->file);
294 if (params->buf_id == LOG_ID_INVALID)
297 if (params->file.path == NULL)
300 struct reader_logger *const reader = g_backend.logger_readers[params->buf_id];
304 return reader_logger_add_subreader_file(reader, params->filter, ¶ms->file);
307 static int create_reader_pipe_from_dlogutil_line(struct dlogutil_line_params *params, struct logger *server, struct reader_pipe **rd)
312 __attribute__((cleanup(reader_pipe_cleanup))) struct reader_pipe *reader = NULL;
315 if (params->file_path) {
316 retval = logfile_set_path(¶ms->file, params->file_path);
320 retval = logfile_open(¶ms->file);
325 if (params->buf_id == LOG_ID_INVALID)
328 if (params->file.path == NULL)
331 retval = reader_pipe_init(&reader, params->buf_id, server, params->filter, ¶ms->file, params->monitor, params->is_dumping);
342 * @brief Service a socket request
343 * @details Handle a socket request
344 * @param[in] server The logger server
345 * @param[in] wr The writer who sent the request
346 * @param[in] event The event containing the request
347 * @return 0 on success, else -errno
349 int service_writer_socket(struct logger *server, struct writer *wr, struct epoll_event *event)
354 struct dlog_control_msg *const msg = (struct dlog_control_msg *) wr->buffer;
357 if (event->events & EPOLLIN)
358 r = read(wr->fd_entity.fd, wr->buffer + wr->readed, sizeof wr->buffer - wr->readed);
360 if ((r == 0 || r == -1) && event->events & EPOLLHUP)
367 /* The socket is SOCK_STREAM (see `listen_fd_create`), so one message
368 * could be split into chunks returned across multiple read() calls. */
369 if (wr->readed < sizeof(msg->length)
370 || wr->readed < msg->length)
371 goto dont_process_yet_and_read_more_data;
373 assert(wr->service_socket);
374 r = wr->service_socket(server, wr, msg);
378 dont_process_yet_and_read_more_data:
379 r = read(wr->fd_entity.fd, wr->buffer + wr->readed, sizeof wr->buffer - wr->readed);
380 } while (r > 0 || ((wr->readed >= sizeof(msg->length) && wr->readed >= msg->length)));
382 return (r >= 0 || errno == EAGAIN) ? 0 : r;
386 * @brief Service /dev/kmsg
387 * @details Read from the /dev/kmsg device
388 * @param[in] server The logger server
389 * @param[in] wr The writer who sent the request
390 * @param[in] event The relevant event
391 * @return 0 on success, else -errno
393 int service_writer_kmsg(struct logger *server, struct writer *wr, struct epoll_event *event)
396 if (event->events & EPOLLHUP)
398 if (!(event->events & EPOLLIN))
401 /* The KMSG device returns just 1 log per read() so it is done in a loop.
402 * In theory this could starve everything else out if logs appeared faster
403 * than the daemon could process them, which would then necessitate some
404 * sort of throttling. In practice, KMSG doesn't really get flooded with
405 * logs the same way Android Logger devices are so the throttling is mostly
406 * there because we get it for free anyway and consistency doesn't hurt. */
408 int max_loop_iterations = g_backend.logger_device_throttling[LOG_ID_KMSG];
409 while (max_loop_iterations--) {
410 int r = read(wr->fd_entity.fd, wr->buffer, sizeof wr->buffer - 1);
412 if (r == -1 && (errno == EAGAIN || errno == EPIPE))
414 else if ((r == 0 || r == -1) && event->events & EPOLLHUP)
421 wr->buffer[r] = '\0';
422 struct dlogutil_entry_with_msg lem;
423 if (parse_kmsg_message(wr->buffer, &lem, r)) {
424 // don't signal an error: KMSG writer is too important to remove; besides, it would not get fixed that way.
432 add_recv_timestamp(&lem.header, now);
434 r = buffer_append(&lem.header, wr->buf_ptr);
442 void remove_reader_fd_entities(struct logger *server, struct reader *reader)
446 if (reader->fd_entity_sink.fd >= 0)
447 remove_fd_entity(&server->epoll_common, &reader->fd_entity_sink);
448 if (reader->fd_entity_source.fd >= 0)
449 remove_fd_entity(&server->epoll_common, &reader->fd_entity_source);
452 static bool cond_service_reader_pipe(void *ptr, void *user_data)
456 struct reader_pipe *reader = (struct reader_pipe *)ptr;
457 struct logger *logger = (struct logger *)user_data;
460 int r = get_now(&now);
462 remove_reader_fd_entities(logger, &reader->common);
463 reader_pipe_free(reader);
466 r = print_out_logs(reader, now);
468 remove_reader_fd_entities(logger, &reader->common);
469 reader_pipe_free(reader);
473 /* `service_reader()` returns -1 if everything was flushed, or 0 if
474 * a mild error happened that can be recovered from simply by waiting,
475 * the prime example being the pipe getting clogged. As soon as the
476 * reader is available again, we'd like to know about it to ensure
477 * logs are flushed as quickly as possible, which is why the EPOLLOUT.
479 * On the other hand, we don't want to remove readers from epoll even
480 * if they successfully flushed and have no logs to wait for. Consider
481 * the case where a buffer is unused (for example through libdlog's
482 * buffer disabling feature). If we relied on receiving an error on
483 * calling `write()` to learn that the connection had been closed,
484 * we would never learn about it because there would be no incoming
485 * logs to trigger the flush and so any FDs representing connections
486 * to such buffer would leak until a log finally arrived (which could
487 * be never). This is why waiting is also done on EPOLLHUP. */
488 if (modify_fd_entity(&logger->epoll_common, &reader->common.fd_entity_sink, (r == 0) ? EPOLLOUT : EPOLLHUP) < 0) {
489 /* ignore, can't really happen and it's not
490 * like we can do anything about it either */
493 flush_logfile_timely(&reader->file, now.mono, logger->buf_params.time);
498 static bool cond_service_reader_logger(void *ptr, void *user_data)
502 struct reader_logger *reader = (struct reader_logger *)ptr;
503 struct logger *logger = (struct logger *)user_data;
506 int r = get_now(&now);
508 remove_reader_fd_entities(logger, &reader->common);
509 reader_logger_free(reader);
513 r = service_reader_logger(reader, now);
516 remove_reader_fd_entities(logger, &reader->common);
517 reader_logger_free(reader);
521 /* `service_reader()` returns -1 if everything was flushed, or 0 if
522 * a mild error happened that can be recovered from simply by waiting,
523 * the prime example being the pipe getting clogged. As soon as the
524 * reader is available again, we'd like to know about it to ensure
525 * logs are flushed as quickly as possible, which is why the EPOLLOUT.
527 * On the other hand, we don't want to remove readers from epoll even
528 * if they successfully flushed and have no logs to wait for. Consider
529 * the case where a buffer is unused (for example through libdlog's
530 * buffer disabling feature). If we relied on receiving an error on
531 * calling `write()` to learn that the connection had been closed,
532 * we would never learn about it because there would be no incoming
533 * logs to trigger the flush and so any FDs representing connections
534 * to such buffer would leak until a log finally arrived (which could
535 * be never). This is why waiting is also done on EPOLLHUP. */
536 if (modify_fd_entity(&logger->epoll_common, &reader->common.fd_entity_sink, (r == 0) ? EPOLLOUT : EPOLLHUP) < 0) {
537 /* ignore, can't really happen and it's not
538 * like we can do anything about it either */
541 reader_logger_flush(reader, now.mono, logger->buf_params.time);
546 * @brief Service syslog
547 * @details Read from the syslog socket
548 * @param[in] server The logger server
549 * @param[in] wr The writer who sent the request
550 * @param[in] event The relevant event
551 * @return 0 on success, else -errno
553 int service_writer_syslog(struct logger *server, struct writer *wr, struct epoll_event *event)
555 if (event->events & EPOLLHUP)
557 if (!(event->events & EPOLLIN))
560 int r = read(wr->fd_entity.fd, wr->buffer, sizeof wr->buffer - 1);
562 if (r == -1 && (errno == EAGAIN || errno == EPIPE))
564 else if ((r == 0 || r == -1) && event->events & EPOLLHUP)
571 wr->buffer[r] = '\0';
573 struct dlogutil_entry_with_msg lem;
574 if (parse_syslog_datagram(wr->buffer, r + 1, &lem.header)) {
575 /* don't return parse error as writers are removed then */
583 add_recv_timestamp(&lem.header, now);
585 return buffer_append(&lem.header, wr->buf_ptr);
589 * @brief Service all readers
590 * @details Update all readers with latest data
591 * @param[in] server The logger server
592 * @param[in] force_push Whether to force logs to be pushed to the readers
594 static void service_all_readers(struct logger *server)
596 for (int i = 0; i < LOG_ID_MAX; i++) {
597 struct log_buffer *const buffer = server->buffers[i];
601 list_remove_if(&buffer->readers_pipe, server, cond_service_reader_pipe);
603 list_remove_if(&server->readers_logger, server, cond_service_reader_logger);
607 * @brief Add writer to server
608 * @details Adds a writer to the server's witers list and registers its event to epoll loop
609 * @param[in] l The server to add the writer to
610 * @param[in] writer The writer to add to the server and register its working_fd to epoll loop
612 void logger_add_writer(struct logger *l, struct writer *wr)
617 list_add(&l->writers, wr);
618 add_fd_entity(&l->epoll_common, &wr->fd_entity);
621 int epoll_metadata_initialize(struct epoll_metadata *metadata)
623 metadata->fd = epoll_create1(0);
624 if (metadata->fd < 0)
627 int r = initialize_epoll_size(&metadata->events, &metadata->events_size);
638 void epoll_metadata_destroy(struct epoll_metadata *metadata)
640 if (metadata->fd >= 0)
643 free(metadata->events);
647 * @brief Create the logger server
648 * @details Allocate the logger server's auxiliary structures (buffers etc.)
649 * @param[in] data Initialisation data
650 * @param[out] l The logger server
651 * @return 0 on success, -errno on failure
656 int logger_create(struct logger_config_data *data, struct logger *l)
658 memset(l, 0, sizeof *l);
659 l->epoll_socket.fd = -1;
661 int r = epoll_metadata_initialize(&l->epoll_common);
664 r = epoll_metadata_initialize(&l->epoll_socket);
668 l->epolltime = data->epoll_time;
670 l->lazy_polling_total = data->lazy_polling_total;
671 l->lazy_polling_sleep = data->lazy_polling_sleep;
673 l->buf_params = data->buf_params;
675 l->qos.log_metrics = metrics_create();
676 if (!l->qos.log_metrics)
679 l->qos.max_throughput = data->qos_max_throughput;
680 l->qos.threshold = data->qos_threshold;
681 l->qos.threshold_reapply = data->qos_threshold_reapply;
682 l->qos.limit_duration = data->qos_limit_duration;
683 l->qos.file_path = data->qos_file_path;
684 data->qos_file_path = NULL;
686 // Check if the daemon is being launched for the first time since reboot
688 if (data->first_time_file_path) {
689 int fd = open(data->first_time_file_path, O_CREAT | O_EXCL | O_RDONLY, 0644);
700 // If no path, assume first time
703 if (g_backend.use_logger_by_default)
704 for (log_id_t id = 0; id < LOG_ID_MAX; ++id) {
705 if (!is_core_buffer(id))
708 int r = reader_logger_init(g_backend.logger_readers + id, id, l, !first_time);
711 if (!g_backend.logger_readers[id])
714 if (qos_is_enabled(&l->qos)) {
715 r = reader_logger_add_subreader_metrics(g_backend.logger_readers[id], &l->qos);
720 r = add_reader_logger(l, g_backend.logger_readers[id]);
725 for (log_id_t id = 0; id < LOG_ID_MAX; id++)
726 if (data->is_buffer_enabled[id]) {
727 int r = buffer_create(&l->buffers[id], id, data->buffers + id);
732 for (log_id_t id = 0; id < LOG_ID_MAX; id++)
733 if (l->buffers[id]) {
734 add_fd_entity(&l->epoll_common, &l->buffers[id]->sock_ctl.fd_entity);
735 add_fd_entity(&l->epoll_common, &l->buffers[id]->sock_conn.fd_entity);
737 add_fd_entity(&l->epoll_socket, &l->buffers[id]->sock_ctl.fd_entity);
738 add_fd_entity(&l->epoll_socket, &l->buffers[id]->sock_conn.fd_entity);
741 /* TODO: make writers creation optional/configurable */
742 int (*writers_factories[LOG_ID_MAX])(struct writer **writer, struct log_buffer *log_buf) = {
743 [LOG_ID_KMSG] = create_kmsg_writer,
744 [LOG_ID_SYSLOG] = create_syslog_writer,
746 for (unsigned u = 0; u < NELEMS(writers_factories); ++u)
747 if (writers_factories[u] && data->is_buffer_enabled[u]) {
749 int r = writers_factories[u](&wr, l->buffers[u]);
753 logger_add_writer(l, wr);
759 static bool cond_writer_free(void *ptr, void *user_data)
761 writer_free((struct writer *)ptr, (struct logger *)user_data);
767 * @details Deallocate the logger and its auxiliary structures
768 * @param[in] l The logger server
773 void logger_free(struct logger *l)
777 list_remove_if(&l->writers, l, cond_writer_free);
778 list_remove_if(&l->readers_logger, l, cond_reader_logger_free);
781 for (j = 0; j < LOG_ID_MAX; j++)
783 buffer_free(l->buffers[j], l);
785 epoll_metadata_destroy(&l->epoll_common);
786 epoll_metadata_destroy(&l->epoll_socket);
792 * @brief Handle interrupting/terminating signals
793 * @details Clears global flag to stop main loop
794 * @param[in] signo signal number
796 static void handle_signals(int signo)
802 static void ensure_epoll_size(struct epoll_event **events, unsigned *size, unsigned wanted_size)
807 if (wanted_size <= *size)
810 typeof(*events) temp = realloc(*events, wanted_size * sizeof **events);
818 static int initialize_epoll_size(struct epoll_event **events, unsigned *size)
823 static const size_t default_size = 16U;
824 typeof(*events) ev = malloc(default_size * sizeof *ev);
829 *size = default_size;
833 void dispatch_epoll_event(struct logger *server, struct epoll_event *event)
835 struct fd_entity *const entity = (struct fd_entity *) event->data.ptr;
836 assert(entity->dispatch_event);
837 entity->dispatch_event(server, event, entity->dispatch_data);
840 int handle_epoll_events(struct logger *server, struct epoll_metadata *metadata, int timeout)
842 ensure_epoll_size(&metadata->events, &metadata->events_size, metadata->cnt);
844 int nfds = epoll_wait(metadata->fd, metadata->events, metadata->events_size, timeout);
846 return errno == EINTR ? 0 : -errno;
848 for (int i = 0; i < nfds; i++)
849 dispatch_epoll_event(server, metadata->events + i);
854 int sleep_while_handling_socket(struct logger *server, struct epoll_metadata *metadata, int timeout)
856 struct timespec ts_start;
857 if (clock_gettime(CLOCK_MONOTONIC, &ts_start))
859 struct timespec ts_current;
862 int r = handle_epoll_events(server, metadata, timeout);
865 if (clock_gettime(CLOCK_MONOTONIC, &ts_current))
868 timeout > (ts_current.tv_sec - ts_start.tv_sec ) * S_TO_MS
869 + (ts_current.tv_nsec - ts_start.tv_nsec) / MS_TO_NS
875 void setup_signals(struct logger *server)
877 struct sigaction action = {
878 .sa_handler = handle_signals,
881 sigemptyset(&action.sa_mask);
883 static const int handled_signals[] = { SIGINT, SIGTERM };
884 for (unsigned u = 0; u < NELEMS(handled_signals); ++u)
885 sigaction(handled_signals[u], &action, NULL);
890 * @details The main logging loop
891 * @param[in] server The logger server
892 * @return 0 on success, else -errno
897 int do_logger(struct logger *server)
899 setup_signals(server);
901 bool use_lazy_polling = true;
902 while (g_logger_run) {
903 if (server->lazy_polling_total >= 0) {
904 server->lazy_polling_total -= server->lazy_polling_sleep;
905 use_lazy_polling = (server->lazy_polling_total >= 0);
907 if (use_lazy_polling)
908 sleep_while_handling_socket(server, &server->epoll_socket, server->lazy_polling_sleep);
910 int r = handle_epoll_events(server, &server->epoll_common, server->epolltime * !use_lazy_polling);
914 service_all_readers(server);
915 qos_periodic_check(server);
918 /* ensure all logs are written no matter when the program was interrupted */
920 service_all_readers(server);
926 * @brief Prepare socket data
927 * @details Extracts initialisation data specific to each socket
928 * @param[in] conf Config database
929 * @param[out] data Socket init config data
930 * @param[in] buf_name The name of the buffer the socket belongs to
931 * @param[in] type The name of the buffer type
932 * @return 0 on success, -errno on failure
934 int prepare_socket_data(const struct log_config *conf, struct socket_config_data *data, char *buf_name, const char *type)
936 char conf_key[MAX_CONF_KEY_LEN];
939 r = snprintf(conf_key, MAX_CONF_KEY_LEN, "%s_%s_sock", buf_name, type);
942 const char * const path = log_config_get(conf, conf_key);
944 r = snprintf(conf_key, MAX_CONF_KEY_LEN, "%s_%s_sock_rights", buf_name, type);
947 const char * const permissions_str = log_config_get(conf, conf_key);
949 if (!permissions_str || !path)
952 data->permissions = parse_permissions(permissions_str);
953 if (data->permissions <= 0)
956 strncpy(data->path, path, MAX_CONF_VAL_LEN - 1);
962 * @brief Prepare buffer data
963 * @details Extracts data specific for each buffer
964 * @param[in] conf Config database
965 * @param[out] data Buffer init config data
966 * @param[in] buf_id Index of the buffer to work with
967 * @return 0 on success, -errno on failure
969 int prepare_buffer_data(const struct log_config *conf, struct buffer_config_data *data, log_id_t buf_id)
971 char * const buf_name = log_name_by_id(buf_id);
972 char * validity_check_ptr;
973 char conf_key[MAX_CONF_KEY_LEN];
976 r = prepare_socket_data(conf, &data->conn_socket, buf_name, "conn");
980 r = prepare_socket_data(conf, &data->ctl_socket, buf_name, "ctl");
984 r = snprintf(conf_key, MAX_CONF_KEY_LEN, "%s_size", buf_name);
988 const char * const size_str = log_config_get(conf, conf_key);
992 data->size = strtol(size_str, &validity_check_ptr, 10);
993 if (*validity_check_ptr)
1002 * @brief Save logfile line
1003 * @detail Saves logfile config line in user_data list
1004 * @param[in] key Config entry key
1005 * @param[in] value Config entry value
1006 * @param[in] userdata Userdata
1008 void save_logfile_config(char const *key, char const *value, void *userdata)
1011 if (strncmp(key, CONF_PREFIX, sizeof CONF_PREFIX - 1))
1014 struct logger_config_data *data = (struct logger_config_data *)userdata;
1015 void *cmd = (void *)strdup(value);
1017 list_add(&data->logfile_configs, cmd);
1022 * @brief Initialize config data
1023 * @param[out] The data structure to fill with initial values
1025 void initialize_config_data(struct logger_config_data *data)
1027 memset(data, 0, sizeof *data);
1031 * @brief Prepare config data
1032 * @details Extracts relevant config data for logger initialisation
1033 * @param[out] data Parsed configuration
1034 * @return 0 on success, -errno on failure
1036 int prepare_config_data(struct logger_config_data *data)
1040 struct log_config conf;
1041 int ret = log_config_read(&conf);
1045 const dlogutil_sorting_order_e sort_by = get_order_from_config(&conf);
1047 int throttling_default = log_config_get_int(&conf, "logger_dev_throttling", LOGGER_DEVICE_THROTTLING_DEFAULT);
1048 const char *const dynamic_config_dir = log_config_get(&conf, DYNAMIC_CONFIG_CONF_KEY);
1050 const char * const backend = log_config_claim_backend(&conf);
1056 for (int i = 0; i < LOG_ID_MAX; i++) {
1057 char key[MAX_CONF_KEY_LEN];
1058 const int r = snprintf(key, sizeof key, "logger_dev_throttling_%s", log_name_by_id((log_id_t)i));
1062 g_backend.logger_device_throttling[i] = max_int(1, log_config_get_int(&conf, key, throttling_default));
1065 if (dynamic_config_dir && dynamic_config_dir[0] == '/') {
1066 data->dynamic_config_dir = strdup(dynamic_config_dir);
1067 if (!data->dynamic_config_dir) {
1072 data->dynamic_config_dir = NULL; // Technically unnecessary but no reason not to put it
1075 data->epoll_time = log_config_get_int(&conf, "epoll_time_ms", DEFAULT_EPOLL_TIME_MS);
1076 data->lazy_polling_total = log_config_get_int(&conf, "lazy_polling_total_ms", DEFAULT_LAZY_POLLING_TOTAL_MS);
1077 data->lazy_polling_sleep = log_config_get_int(&conf, "lazy_polling_sleep_ms", DEFAULT_LAZY_POLLING_SLEEP_MS);
1079 const char *const qos_file_path = log_config_get(&conf, "qos_file_path");
1080 data->qos_file_path = qos_file_path ? strdup(qos_file_path) : NULL;
1082 data->qos_limit_duration = log_config_get_int(&conf, "qos_refresh_rate_s", DEFAULT_QOS_LIMIT_DURATION_S);
1083 data->qos_max_throughput = log_config_get_int(&conf, "qos_max_throughput_logs", DEFAULT_QOS_THROUGHPUT_LOGS);
1084 data->qos_threshold = log_config_get_int(&conf, "qos_threshold_logs", DEFAULT_QOS_THRESHOLD_LOGS);
1085 data->qos_threshold_reapply = log_config_get_int(&conf, "qos_threshold_reapply_logs", DEFAULT_QOS_THRESHOLD_REAPPLY_LOGS);
1088 void (*func)(struct qos_module *qos, struct metrics_pid_aggr_info *infos, int count);
1090 } const qos_methods[] = {
1091 { qos_distribution_proportional_raw , "proportional_raw" },
1092 { qos_distribution_proportional_talmud, "proportional_talmud" },
1093 { qos_distribution_equal , "equal" },
1094 { qos_distribution_equal_dual , "equal_dual" },
1095 { qos_distribution_equal_multi , "equal_multi" },
1097 qos_distribution_func = qos_distribution_equal_multi; // default
1098 const char *const qos_method = log_config_get(&conf, "qos_method");
1100 for (int i = 0; i < NELEMS(qos_methods); ++i)
1101 if (!strcmp(qos_method, qos_methods[i].name))
1102 qos_distribution_func = qos_methods[i].func;
1104 const char *const first_time_file_path = log_config_get(&conf, "first_time_file_path");
1105 data->first_time_file_path = first_time_file_path ? strdup(first_time_file_path) : NULL;
1107 memset(data->is_buffer_enabled, 0, sizeof(data->is_buffer_enabled));
1108 if (!strcmp(backend, "pipe")) {
1109 data->is_buffer_enabled[LOG_ID_MAIN] =
1110 data->is_buffer_enabled[LOG_ID_RADIO] =
1111 data->is_buffer_enabled[LOG_ID_SYSTEM] =
1112 data->is_buffer_enabled[LOG_ID_APPS] = 1;
1113 g_backend.use_logger_by_default = false;
1114 } else if (!strcmp(backend, "logger")) {
1115 g_backend.use_logger_by_default = true;
1116 for (log_id_t buf_id = 0; buf_id < LOG_ID_MAX; ++buf_id) {
1117 const char *const logger_device = log_config_get(&conf, log_name_by_id(buf_id));
1119 strncpy(g_backend.logger_devices[buf_id], logger_device,
1120 NELEMS(g_backend.logger_devices[buf_id]) - 1);
1126 data->is_buffer_enabled[LOG_ID_KMSG] = log_config_get_boolean(&conf, "handle_kmsg", true);
1127 data->is_buffer_enabled[LOG_ID_SYSLOG] =
1128 dev_log_sock_get() >= 0 || log_config_get_boolean(&conf, "syslog_force", false);
1130 for (log_id_t buf_id = 0; buf_id < LOG_ID_MAX; ++buf_id) {
1131 if (data->is_buffer_enabled[buf_id]) {
1132 ret = prepare_buffer_data(&conf, data->buffers + buf_id, buf_id);
1135 data->buffers[buf_id].sort_by = sort_by;
1138 data->logfile_configs = NULL;
1139 log_config_foreach(&conf, save_logfile_config, data);
1142 log_config_free(&conf);
1146 static bool cond_string_free(void *ptr, void *user_data)
1156 void free_config_data(struct logger_config_data *data)
1158 list_remove_if(&data->logfile_configs, NULL, cond_string_free);
1159 free(data->dynamic_config_dir);
1160 free(data->qos_file_path);
1161 free(data->first_time_file_path);
1165 * @brief Parse logfile line
1166 * @detail Parses a logfile config line
1167 * @param[in] key Config entry key
1168 * @param[in] value Config entry value
1169 * @param[in] userdata Userdata
1171 void parse_logfile_config(void *value, void *userdata)
1176 struct logger *server = (struct logger *) userdata;
1177 char *configline = (char *) value;
1179 __attribute__((cleanup(free_dlogutil_line_params))) struct dlogutil_line_params params;
1180 if (!initialize_dlogutil_line_params(¶ms, server->buf_params))
1183 get_dlogutil_line_params(configline, ¶ms);
1186 if (g_backend.use_logger_by_default && is_core_buffer(params.buf_id)) {
1187 r = create_logger_subreader_from_dlogutil_line(¶ms);
1189 struct reader_pipe *reader = NULL;
1190 r = create_reader_pipe_from_dlogutil_line(¶ms, server, &reader);
1192 add_reader_pipe(server, reader);
1197 printf("Warning: unable to add logutil reader for provided configuration. Ignoring.\n"
1198 " Config line: %s\n"
1199 " Reason given: %m\n",
1207 * @details Prints basic usage tips
1209 static void help(void)
1211 printf("Usage: %s [options]\n"
1212 "\t-h Show this help\n"
1213 "\t-b N Set the size of the log buffer (in bytes)\n"
1214 "\t-t N Set time between writes to file (in seconds)\n",
1215 program_invocation_short_name);
1220 * @details Parses execution parameters of the program
1221 * @param[in] argc Argument count
1222 * @param[in] argv Argument values
1223 * @param[out] b Buffering parameters
1224 * @return 0 or 1 on success, else -errno. Nonzero if the program is to close.
1226 static int parse_args(int argc, char **argv, struct buf_params *b)
1228 b->time = BUF_PARAM_TIME_DEFAULT;
1229 b->bytes = BUF_PARAM_BYTES_DEFAULT;
1232 while ((option = getopt(argc, argv, "hb:t:")) != -1) {
1235 if (!isdigit(optarg[0]))
1237 b->time = clamp_int(atoi(optarg), BUF_PARAM_TIME_MIN, BUF_PARAM_TIME_MAX);
1240 if (!isdigit(optarg[0]))
1242 b->bytes = clamp_int(atoi(optarg), BUF_PARAM_BYTES_MIN, BUF_PARAM_BYTES_MAX);
1255 * @brief Finalize initialisation
1256 * @details Do misc stuff needed at the end of the initialisation
1257 * @param[in] data configuration dat to read logfiles config lines from
1258 * @param[in] server logger instance to configure
1259 * @return 0 on success, -errno on failure
1261 static int finalize_init(struct logger_config_data *data, struct logger *server)
1263 int r = sd_notify(0, "READY=1");
1267 //create files after resetting self privileges
1268 list_foreach(data->logfile_configs, server, parse_logfile_config);
1273 static void precreate_logctl_file(struct logger_config_data *data)
1275 __attribute__((cleanup(free_ptr))) char *logctl_file_path = NULL;
1276 if (asprintf(&logctl_file_path, "%s/%s", data->dynamic_config_dir, DYNAMIC_CONFIG_FILENAME) < 0)
1277 // This is worrying but unimportant
1280 int fd = open(logctl_file_path, O_RDONLY | O_CREAT, 0644);
1282 // Again, no big deal
1288 bool early_termination(const struct logger_config_data *data, const struct logger *logger) {
1289 /* In order to check if the deamon will be doing nothing
1290 * and can quit instantaneously, we do three checks: */
1292 /* 1. We make sure that there are no logger subreaders.
1293 * When the logger backend is being used, the daemon reads the data
1294 * in order to use it internally. The daemon always reads each buffer
1295 * to a separate reader and each concrete usage has its own subreader.
1296 * Therefore, we need to check if no subreaders exist. */
1297 for (list_head l = logger->readers_logger; l != NULL; list_next(&l)) {
1298 struct reader_logger *reader = list_at(l);
1299 if (reader->subs != NULL)
1303 /* 2. We make sure that no pipe-like buffer is enabled.
1304 * When the pipe backend is being used or pipe-like buffers
1305 * (i.e. KMSG, SYSLOG) are handled, the logger allocates space for them.
1306 * In this case, we cannot terminate even if the buffer is enabled
1307 * but unused at the moment, since it might be connected to
1308 * (for instance by dlogutil). */
1309 for (log_id_t id = 0; id < LOG_ID_MAX; id++)
1310 if (data->is_buffer_enabled[id])
1313 /* 3. We make sure that there are no writers.
1314 * In theory, previous checks are sufficient.
1315 * However, we do another check just to be sure
1316 * (since if there are writers, we shouldn't terminate).
1317 * Additionally, this could change in the future,
1318 * so let's hedge against someone forgetting that this function exists. */
1319 return logger->writers == NULL;
1324 * @return 0 on success, nonzero on failure
1325 * @retval 1 Configuration error
1326 * @retval 2 Runtime error
1328 int main(int argc, char **argv)
1332 signal(SIGPIPE, SIG_IGN);
1334 r = reset_self_privileges();
1337 printf("Unable to drop privileges to build-time defaults (%m). Exiting.\n");
1338 return DLOG_EXIT_ERR_RUNTIME;
1341 struct logger_config_data data;
1342 initialize_config_data(&data);
1344 if ((r = parse_args(argc, argv, &data.buf_params)) != 0) {
1348 return DLOG_EXIT_SUCCESS; // --help option
1351 printf("Unable to parse command line args (%m). Exiting.\n");
1352 return DLOG_EXIT_ERR_CONFIG;
1355 if ((r = prepare_config_data(&data)) != 0) {
1357 printf("Unable to prepare config (%m). Exiting.\n");
1358 return DLOG_EXIT_ERR_CONFIG;
1361 precreate_logctl_file(&data);
1363 struct logger server;
1364 if ((r = logger_create(&data, &server)) < 0) {
1366 printf("Unable to initialize logger with provided configuration (%m). Exiting.\n");
1367 ret = DLOG_EXIT_ERR_CONFIG;
1371 if ((r = finalize_init(&data, &server)) < 0) {
1373 printf("Unable to finalize initialisation (%m). Exiting.\n");
1374 ret = DLOG_EXIT_ERR_CONFIG;
1378 if (early_termination(&data, &server)) {
1379 printf("No work to do according to provided configuration. Exiting.\n");
1380 ret = DLOG_EXIT_SUCCESS;
1384 if ((r = do_logger(&server)) < 0) {
1386 printf("Runtime failure (%m). Exiting.\n");
1387 ret = DLOG_EXIT_ERR_RUNTIME;
1391 ret = DLOG_EXIT_SUCCESS;
1394 free_config_data(&data);
1395 logger_free(&server);