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"
23 #include "subreader_file.h"
24 #include "subreader_metrics.h"
25 #include "subreader_memory.h"
29 #include <dynamic_config.h>
30 #include <qos_defaults.h>
33 * @addtogroup DLOG_IMPLEMENTATION
35 * @defgroup DLOG_LOGGER Logger
36 * @brief Logger daemon
37 * @details The logger is the core component of the logging framework. It is responsible for collecting, processing and exposing logs.
41 // function prototypes
42 static int initialize_epoll_size(struct epoll_event **events, unsigned *size);
44 /** global state when logger is not interrupted by any handled signals */
45 static volatile sig_atomic_t g_logger_run = 1;
47 static const int DEFAULT_EPOLL_TIME_MS = 1000;
49 static const int DEFAULT_LAZY_POLLING_TOTAL_MS = 0;
50 static const int DEFAULT_LAZY_POLLING_SLEEP_MS = 1000;
52 static const int S_TO_MS = 1000;
53 static const int MS_TO_NS = 1000000;
55 struct backend_data g_backend = {};
57 static bool cond_reader_logger_free(void *ptr, void *user_data)
59 struct reader_logger *reader = (struct reader_logger *)ptr;
60 struct logger *logger = (struct logger *)user_data;
62 // TODO: This is absurd, why isn't this in the reader_logger_free function?
63 if (reader->common.fd_entity_sink.fd >= 0)
64 remove_fd_entity(&logger->epoll_common, &reader->common.fd_entity_sink);
65 if (reader->common.fd_entity_source.fd >= 0)
66 remove_fd_entity(&logger->epoll_common, &reader->common.fd_entity_source);
67 reader_free(&reader->common);
71 // TODO: Consider inlining struct now_t everywhere
72 int get_now(struct now_t *now)
74 if (clock_gettime(CLOCK_MONOTONIC, &now->mono))
76 if (clock_gettime(CLOCK_REALTIME, &now->real))
81 void qos_periodic_check(struct logger *server)
83 struct qos_module *const qos = &server->qos;
84 struct timespec ts_mono;
85 if (clock_gettime(CLOCK_MONOTONIC, &ts_mono))
88 if (ts_mono.tv_sec < qos->cancel_limits_at.tv_sec)
90 if (ts_mono.tv_sec == qos->cancel_limits_at.tv_sec
91 && ts_mono.tv_nsec < qos->cancel_limits_at.tv_nsec)
94 if (metrics_get_total(qos->log_metrics) >= qos->threshold)
95 qos_apply_limits(qos);
97 qos_relax_limits(qos);
99 qos_set_next_update_time(qos, ts_mono);
100 metrics_clear(qos->log_metrics);
104 * @brief FD limit handler
105 * @details Checks whether the FD limit was reached and leaves logs about it if so
106 * @param[in] server The logger server
107 * @param[in] err errno from the call that failed to create an FD
109 void check_if_fd_limit_reached(struct logger *server, int err)
113 if (err != ENFILE && err != EMFILE)
116 printf("ERROR: dlog_logger fd limit reached!\n");
118 /* pick one representative buffer to send the log to;
119 * no point spamming all the buffers, especially since
120 * default dlogutil invocations display 3 buffers so
121 * it would appear multiple times */
122 struct log_buffer *const buf = server->buffers[LOG_ID_MAIN];
126 struct dlogutil_entry_with_msg entry;
127 create_pipe_message(&entry,
128 DLOG_FATAL, /* not really FATAL, but since we're at the FD limit
129 * there are thousands of logging programs so this one
130 * would likely get lost in the flood since developers
131 * tend to overuse ERROR (and FATAL is the one above) */
133 "\x1b[31m DLOG DAEMON FD LIMIT REACHED \x1b[0m" // make it stand out
137 int r = get_now(&now);
140 set_pipe_message_sent_timestamp((struct pipe_logger_entry *) &entry, &now.mono, &now.real);
142 if (buffer_append(&entry.header, buf))
143 printf("ERROR: not enough memory either, please check platform settings as the daemon is seriously resource-starved!\n");
146 void flush_logfile_timely(struct log_file *file, struct timespec ts, int flush_time)
148 if (file->buffer.position > 0) {
149 if (ts.tv_sec - file->buffer.oldest_log.tv_sec +
150 (ts.tv_nsec > file->buffer.oldest_log.tv_nsec ? 1 : 0) >
156 void reader_pipe_notify_losing_log(const dlogutil_entry_s *le, void *reader_)
158 struct reader_pipe *reader = (struct reader_pipe *) reader_;
161 reader_pipe_print_out_single_log(reader, (dlogutil_entry_s *)le);
165 * @brief Add reader to log buffer
166 * @details Adds a reader to the log buffers reader list
167 * @param[in] log_buffer The buffer whither to add the reader
168 * @param[in] reader The reader to add to the buffer
169 * @return 0 on success, -ENOMEM on memory allocation error
171 int add_buffer_reader(struct log_buffer *buffer, struct reader_pipe *reader)
176 reader->log_storage_reader_ptr = log_storage_new_reader(buffer->log_storage_ptr,
177 reader->is_dumping, reader->monitor, reader_pipe_notify_losing_log, reader);
179 if (!reader->log_storage_reader_ptr)
182 return list_add(&buffer->readers_pipe, reader) ? 0 : -ENOMEM;
185 static int add_reader_common(struct logger *server, struct reader_common *reader)
190 if (reader->fd_entity_sink.fd >= 0) {
191 /* Readers who write to file have no sink FD entity (or, strictly
192 * speaking, they do have one but it is not filled) since a file
193 * is not eligible to be added to epoll. However, the entity primarily
194 * serves to handle pipes getting clogged mid-write (which cannot
195 * happen for files) and is not involved in starting a write,
196 * which is handled by the source FD entity, not sink (and which is
197 * also done periodically for all readers anyway regardless
198 * of whether they've been added to epoll or not). The other use
199 * case for epoll - the one where connection FDs leak for unused
200 * buffers - is not a problem here because the daemon is not
201 * supposed to ever stop writing to files. */
203 int r = add_fd_entity(&server->epoll_common, &reader->fd_entity_sink);
211 int add_reader_pipe(struct logger *server, struct reader_pipe *reader)
216 int ret = add_reader_common(server, &reader->common);
220 ret = add_buffer_reader(reader->buf_ptr, reader);
221 if (ret < 0 && reader->common.fd_entity_sink.fd >= 0)
222 remove_fd_entity(&server->epoll_common, &reader->common.fd_entity_sink);
227 int add_reader_memory(struct logger *server, struct reader_memory *reader)
232 int ret = add_reader_common(server, &reader->common);
236 // `readers_logger` actually accepts any readers
237 if (!list_add(&server->readers_logger, reader)) {
238 if (reader->common.fd_entity_sink.fd >= 0)
239 remove_fd_entity(&server->epoll_common, &reader->common.fd_entity_sink);
246 static int add_reader_logger(struct logger *server, struct reader_logger *reader)
251 int ret = add_reader_common(server, &reader->common);
255 assert(reader->common.fd_entity_source.fd >= 0);
256 ret = add_fd_entity(&server->epoll_common, &reader->common.fd_entity_source);
260 if (!list_add(&server->readers_logger, reader)) {
261 remove_fd_entity(&server->epoll_common, &reader->common.fd_entity_source);
269 if (reader->common.fd_entity_sink.fd >= 0)
270 remove_fd_entity(&server->epoll_common, &reader->common.fd_entity_sink);
275 int create_fifo_fds(struct logger *server, int pipe_fd[2], int flags, bool dump)
277 int ret = get_nonblocking_fifo(pipe_fd, flags);
281 /* Speed up dumping dlogutils by increasing their pipe size,
282 * as otherwise this pipe's size becomes a major bottleneck.
284 * Continuous connections don't really care if the initial
285 * burst of "historic" logs is slow and the following flow
286 * of logs is just fine with a small pipe. Meanwhile they
287 * live for a long time during which they would take away
288 * from the valuable total pipe size. */
290 if (fcntl(pipe_fd[1], F_SETPIPE_SZ, DUMPING_READER_PIPE_SIZE) < 0) {
291 /* Ignore; this is just a performance optimisation
292 * and doesn't affect functionality so while errors
293 * are worrisome they not a big deal or something
294 * we can do anything about, at any rate. */
300 static int create_memory_subreader_for_common(struct dlogutil_line_params *params, struct reader_common *reader, struct logger *server)
302 struct log_compressed_storage *storage = log_compressed_storage_create(params->file.rotate_size_kbytes * 1024, params->compression, params->mem_algo);
306 list_add(&server->compressed_memories, storage);
308 return reader_add_subreader_memory(reader, params->filter, storage);
311 static int create_memory_subreader_from_dlogutil_line(struct dlogutil_line_params *params, struct logger *server)
314 assert(params->compression);
316 if (params->file_path) // We're writing to memory, not to file
319 if (params->buf_id == LOG_ID_INVALID)
322 struct reader_logger *const reader = g_backend.logger_readers[params->buf_id];
326 return create_memory_subreader_for_common(params, &reader->common, server);
329 static int create_logger_subreader_from_dlogutil_line(struct dlogutil_line_params *params)
332 assert(!params->compression);
334 if (params->file_path) {
335 int retval = logfile_set_path(¶ms->file, params->file_path);
339 retval = logfile_open(¶ms->file);
344 if (params->buf_id == LOG_ID_INVALID)
347 if (params->file.path == NULL)
350 struct reader_logger *const reader = g_backend.logger_readers[params->buf_id];
354 return reader_add_subreader_file(&reader->common, params->filter, ¶ms->file, DLOGUTIL_SORT_SENT_REAL);
357 static int create_reader_pipe_from_dlogutil_line(struct dlogutil_line_params *params, struct logger *server, struct reader_pipe **rd)
362 __attribute__((cleanup(reader_free_ptr))) struct reader_pipe *reader = NULL;
365 if (params->file_path) {
366 retval = logfile_set_path(¶ms->file, params->file_path);
370 retval = logfile_open(¶ms->file);
375 if (params->buf_id == LOG_ID_INVALID)
378 if ((params->file.path == NULL && !params->compression)
379 || (params->file.path != NULL && params->compression))
382 retval = reader_pipe_init(&reader, params->buf_id, server, params->monitor, params->is_dumping);
386 if (params->file.path == NULL) {
387 assert(params->compression);
388 retval = create_memory_subreader_for_common(params, &reader->common, server);
392 /* FIXME: in theory these could be added independently (1 reader 2 subs),
393 * but so far that has not been needed and it sounds too fragile to do in haste. */
394 assert(!params->compression);
395 retval = reader_add_subreader_file(&reader->common, params->filter, ¶ms->file, server->buffers[params->buf_id]->sort_by);
407 * @brief Service a socket request
408 * @details Handle a socket request
409 * @param[in] server The logger server
410 * @param[in] wr The writer who sent the request
411 * @param[in] event The event containing the request
412 * @return 0 on success, else -errno
414 int service_writer_socket(struct logger *server, struct writer *wr, struct epoll_event *event)
419 struct dlog_control_msg *const msg = (struct dlog_control_msg *) wr->buffer;
422 if (event->events & EPOLLIN)
423 r = read(wr->fd_entity.fd, wr->buffer + wr->readed, sizeof wr->buffer - wr->readed);
425 if ((r == 0 || r == -1) && event->events & EPOLLHUP)
432 /* The socket is SOCK_STREAM (see `listen_fd_create`), so one message
433 * could be split into chunks returned across multiple read() calls. */
434 if (wr->readed < sizeof(msg->length)
435 || wr->readed < msg->length)
436 goto dont_process_yet_and_read_more_data;
438 assert(wr->service_socket);
439 r = wr->service_socket(server, wr, msg);
443 dont_process_yet_and_read_more_data:
444 r = read(wr->fd_entity.fd, wr->buffer + wr->readed, sizeof wr->buffer - wr->readed);
445 } while (r > 0 || ((wr->readed >= sizeof(msg->length) && wr->readed >= msg->length)));
447 return (r >= 0 || errno == EAGAIN) ? 0 : r;
451 * @brief Service /dev/kmsg
452 * @details Read from the /dev/kmsg device
453 * @param[in] server The logger server
454 * @param[in] wr The writer who sent the request
455 * @param[in] event The relevant event
456 * @return 0 on success, else -errno
458 int service_writer_kmsg(struct logger *server, struct writer *wr, struct epoll_event *event)
461 if (event->events & EPOLLHUP)
463 if (!(event->events & EPOLLIN))
466 /* The KMSG device returns just 1 log per read() so it is done in a loop.
467 * In theory this could starve everything else out if logs appeared faster
468 * than the daemon could process them, which would then necessitate some
469 * sort of throttling. In practice, KMSG doesn't really get flooded with
470 * logs the same way Android Logger devices are so the throttling is mostly
471 * there because we get it for free anyway and consistency doesn't hurt. */
473 int max_loop_iterations = g_backend.logger_device_throttling[LOG_ID_KMSG];
474 while (max_loop_iterations--) {
475 int r = read(wr->fd_entity.fd, wr->buffer, sizeof wr->buffer - 1);
477 if (r == -1 && (errno == EAGAIN || errno == EPIPE))
479 else if ((r == 0 || r == -1) && event->events & EPOLLHUP)
486 wr->buffer[r] = '\0';
487 struct dlogutil_entry_with_msg lem;
488 if (parse_kmsg_message(wr->buffer, &lem, r)) {
489 // don't signal an error: KMSG writer is too important to remove; besides, it would not get fixed that way.
497 add_recv_timestamp(&lem.header, now);
499 r = buffer_append(&lem.header, wr->buf_ptr);
507 void remove_reader_fd_entities(struct logger *server, struct reader_common *reader)
511 if (reader->fd_entity_sink.fd >= 0)
512 remove_fd_entity(&server->epoll_common, &reader->fd_entity_sink);
513 if (reader->fd_entity_source.fd >= 0)
514 remove_fd_entity(&server->epoll_common, &reader->fd_entity_source);
517 static bool cond_service_reader_common(void *ptr, void *user_data)
519 struct reader_common *reader = (struct reader_common *)ptr;
520 struct logger *logger = (struct logger *)user_data;
526 int r = get_now(&now);
528 remove_reader_fd_entities(logger, reader);
533 r = reader->service_reader(reader, now);
535 remove_reader_fd_entities(logger, reader);
540 /* `service_reader()` returns -1 if everything was flushed, or 0 if
541 * a mild error happened that can be recovered from simply by waiting,
542 * the prime example being the pipe getting clogged. As soon as the
543 * reader is available again, we'd like to know about it to ensure
544 * logs are flushed as quickly as possible, which is why the EPOLLOUT.
546 * On the other hand, we don't want to remove readers from epoll even
547 * if they successfully flushed and have no logs to wait for. Consider
548 * the case where a buffer is unused (for example through libdlog's
549 * buffer disabling feature). If we relied on receiving an error on
550 * calling `write()` to learn that the connection had been closed,
551 * we would never learn about it because there would be no incoming
552 * logs to trigger the flush and so any FDs representing connections
553 * to such buffer would leak until a log finally arrived (which could
554 * be never). This is why waiting is also done on EPOLLHUP. */
555 if (modify_fd_entity(&logger->epoll_common, &reader->fd_entity_sink, (r == 0) ? EPOLLOUT : EPOLLHUP) < 0) {
556 /* ignore, can't really happen and it's not
557 * like we can do anything about it either */
560 // Ditto, can't do much about it
561 (void) reader_flush(reader, now.mono, logger->buf_params.time);
567 * @brief Service syslog
568 * @details Read from the syslog socket
569 * @param[in] server The logger server
570 * @param[in] wr The writer who sent the request
571 * @param[in] event The relevant event
572 * @return 0 on success, else -errno
574 int service_writer_syslog(struct logger *server, struct writer *wr, struct epoll_event *event)
576 if (event->events & EPOLLHUP)
578 if (!(event->events & EPOLLIN))
581 int r = read(wr->fd_entity.fd, wr->buffer, sizeof wr->buffer - 1);
583 if (r == -1 && (errno == EAGAIN || errno == EPIPE))
585 else if ((r == 0 || r == -1) && event->events & EPOLLHUP)
592 wr->buffer[r] = '\0';
594 struct dlogutil_entry_with_msg lem;
595 if (parse_syslog_datagram(wr->buffer, r + 1, &lem.header)) {
596 /* don't return parse error as writers are removed then */
604 add_recv_timestamp(&lem.header, now);
606 return buffer_append(&lem.header, wr->buf_ptr);
610 * @brief Service all readers
611 * @details Update all readers with latest data
612 * @param[in] server The logger server
613 * @param[in] force_push Whether to force logs to be pushed to the readers
615 static void service_all_readers(struct logger *server)
617 for (int i = 0; i < LOG_ID_MAX; i++) {
618 struct log_buffer *const buffer = server->buffers[i];
622 list_remove_if(&buffer->readers_pipe, server, cond_service_reader_common);
624 list_remove_if(&server->readers_logger, server, cond_service_reader_common);
628 * @brief Add writer to server
629 * @details Adds a writer to the server's witers list and registers its event to epoll loop
630 * @param[in] l The server to add the writer to
631 * @param[in] writer The writer to add to the server and register its working_fd to epoll loop
633 void logger_add_writer(struct logger *l, struct writer *wr)
638 list_add(&l->writers, wr);
639 add_fd_entity(&l->epoll_common, &wr->fd_entity);
642 int epoll_metadata_initialize(struct epoll_metadata *metadata)
644 metadata->fd = epoll_create1(0);
645 if (metadata->fd < 0)
648 int r = initialize_epoll_size(&metadata->events, &metadata->events_size);
659 void epoll_metadata_destroy(struct epoll_metadata *metadata)
661 if (metadata->fd >= 0)
664 free(metadata->events);
668 * @brief Create the logger server
669 * @details Allocate the logger server's auxiliary structures (buffers etc.)
670 * @param[in] data Initialisation data
671 * @param[out] l The logger server
672 * @return 0 on success, -errno on failure
677 int logger_create(struct logger_config_data *data, struct logger *l)
679 memset(l, 0, sizeof *l);
680 l->epoll_socket.fd = -1;
682 int r = epoll_metadata_initialize(&l->epoll_common);
685 r = epoll_metadata_initialize(&l->epoll_socket);
689 l->epolltime = data->epoll_time;
691 l->lazy_polling_total = data->lazy_polling_total;
692 l->lazy_polling_sleep = data->lazy_polling_sleep;
694 l->buf_params = data->buf_params;
696 l->qos.log_metrics = metrics_create();
697 if (!l->qos.log_metrics)
700 l->qos.max_throughput = data->qos_max_throughput;
701 l->qos.threshold = data->qos_threshold;
702 l->qos.threshold_reapply = data->qos_threshold_reapply;
703 l->qos.limit_duration = data->qos_limit_duration;
704 l->qos.file_path = data->qos_file_path;
705 data->qos_file_path = NULL;
707 // Check if the daemon is being launched for the first time since reboot
709 if (data->first_time_file_path) {
710 int fd = open(data->first_time_file_path, O_CREAT | O_EXCL | O_RDONLY, 0644);
721 // If no path, assume first time
724 if (g_backend.use_logger_by_default)
725 for (log_id_t id = 0; id < LOG_ID_MAX; ++id) {
726 if (!is_core_buffer(id))
729 int r = reader_logger_init(g_backend.logger_readers + id, id, l, !first_time);
732 if (!g_backend.logger_readers[id])
735 if (qos_is_enabled(&l->qos)) {
736 r = reader_add_subreader_metrics(&g_backend.logger_readers[id]->common, &l->qos);
741 r = add_reader_logger(l, g_backend.logger_readers[id]);
746 for (log_id_t id = 0; id < LOG_ID_MAX; id++)
747 if (data->is_buffer_enabled[id]) {
748 int r = buffer_create(&l->buffers[id], id, data->buffers + id);
753 for (log_id_t id = 0; id < LOG_ID_MAX; id++)
754 if (l->buffers[id]) {
755 add_fd_entity(&l->epoll_common, &l->buffers[id]->sock_ctl.fd_entity);
756 add_fd_entity(&l->epoll_common, &l->buffers[id]->sock_conn.fd_entity);
758 add_fd_entity(&l->epoll_socket, &l->buffers[id]->sock_ctl.fd_entity);
759 add_fd_entity(&l->epoll_socket, &l->buffers[id]->sock_conn.fd_entity);
762 /* TODO: make writers creation optional/configurable */
763 int (*writers_factories[LOG_ID_MAX])(struct writer **writer, struct log_buffer *log_buf) = {
764 [LOG_ID_KMSG] = create_kmsg_writer,
765 [LOG_ID_SYSLOG] = create_syslog_writer,
767 for (unsigned u = 0; u < NELEMS(writers_factories); ++u)
768 if (writers_factories[u] && data->is_buffer_enabled[u]) {
770 int r = writers_factories[u](&wr, l->buffers[u]);
774 logger_add_writer(l, wr);
780 static bool cond_writer_free(void *ptr, void *user_data)
782 writer_free((struct writer *)ptr, (struct logger *)user_data);
788 * @details Deallocate the logger and its auxiliary structures
789 * @param[in] l The logger server
794 void logger_free(struct logger *l)
798 list_remove_if(&l->writers, l, cond_writer_free);
799 list_remove_if(&l->readers_logger, l, cond_reader_logger_free);
802 for (j = 0; j < LOG_ID_MAX; j++)
804 buffer_free(l->buffers[j], l);
806 epoll_metadata_destroy(&l->epoll_common);
807 epoll_metadata_destroy(&l->epoll_socket);
813 * @brief Handle interrupting/terminating signals
814 * @details Clears global flag to stop main loop
815 * @param[in] signo signal number
817 static void handle_signals(int signo)
823 static void ensure_epoll_size(struct epoll_event **events, unsigned *size, unsigned wanted_size)
828 if (wanted_size <= *size)
831 typeof(*events) temp = realloc(*events, wanted_size * sizeof **events);
839 static int initialize_epoll_size(struct epoll_event **events, unsigned *size)
844 static const size_t default_size = 16U;
845 typeof(*events) ev = malloc(default_size * sizeof *ev);
850 *size = default_size;
854 void dispatch_epoll_event(struct logger *server, struct epoll_event *event)
856 struct fd_entity *const entity = (struct fd_entity *) event->data.ptr;
857 assert(entity->dispatch_event);
858 entity->dispatch_event(server, event, entity->dispatch_data);
861 int handle_epoll_events(struct logger *server, struct epoll_metadata *metadata, int timeout)
863 ensure_epoll_size(&metadata->events, &metadata->events_size, metadata->cnt);
865 int nfds = epoll_wait(metadata->fd, metadata->events, metadata->events_size, timeout);
867 return errno == EINTR ? 0 : -errno;
869 for (int i = 0; i < nfds; i++)
870 dispatch_epoll_event(server, metadata->events + i);
875 int sleep_while_handling_socket(struct logger *server, struct epoll_metadata *metadata, int timeout)
877 struct timespec ts_start;
878 if (clock_gettime(CLOCK_MONOTONIC, &ts_start))
880 struct timespec ts_current;
883 int r = handle_epoll_events(server, metadata, timeout);
886 if (clock_gettime(CLOCK_MONOTONIC, &ts_current))
889 timeout > (ts_current.tv_sec - ts_start.tv_sec ) * S_TO_MS
890 + (ts_current.tv_nsec - ts_start.tv_nsec) / MS_TO_NS
896 void setup_signals(struct logger *server)
898 struct sigaction action = {
899 .sa_handler = handle_signals,
902 sigemptyset(&action.sa_mask);
904 static const int handled_signals[] = { SIGINT, SIGTERM };
905 for (unsigned u = 0; u < NELEMS(handled_signals); ++u)
906 sigaction(handled_signals[u], &action, NULL);
911 * @details The main logging loop
912 * @param[in] server The logger server
913 * @return 0 on success, else -errno
918 int do_logger(struct logger *server)
920 setup_signals(server);
922 bool use_lazy_polling = true;
923 while (g_logger_run) {
924 if (server->lazy_polling_total >= 0) {
925 server->lazy_polling_total -= server->lazy_polling_sleep;
926 use_lazy_polling = (server->lazy_polling_total >= 0);
928 if (use_lazy_polling)
929 sleep_while_handling_socket(server, &server->epoll_socket, server->lazy_polling_sleep);
931 int r = handle_epoll_events(server, &server->epoll_common, server->epolltime * !use_lazy_polling);
935 service_all_readers(server);
936 qos_periodic_check(server);
939 /* ensure all logs are written no matter when the program was interrupted */
941 service_all_readers(server);
947 * @brief Prepare socket data
948 * @details Extracts initialisation data specific to each socket
949 * @param[in] conf Config database
950 * @param[out] data Socket init config data
951 * @param[in] buf_name The name of the buffer the socket belongs to
952 * @param[in] type The name of the buffer type
953 * @return 0 on success, -errno on failure
955 int prepare_socket_data(const struct log_config *conf, struct socket_config_data *data, char *buf_name, const char *type)
957 char conf_key[MAX_CONF_KEY_LEN];
960 r = snprintf(conf_key, MAX_CONF_KEY_LEN, "%s_%s_sock", buf_name, type);
963 const char * const path = log_config_get(conf, conf_key);
965 r = snprintf(conf_key, MAX_CONF_KEY_LEN, "%s_%s_sock_rights", buf_name, type);
968 const char * const permissions_str = log_config_get(conf, conf_key);
970 if (!permissions_str || !path)
973 data->permissions = parse_permissions(permissions_str);
974 if (data->permissions <= 0)
977 strncpy(data->path, path, MAX_CONF_VAL_LEN - 1);
983 * @brief Prepare buffer data
984 * @details Extracts data specific for each buffer
985 * @param[in] conf Config database
986 * @param[out] data Buffer init config data
987 * @param[in] buf_id Index of the buffer to work with
988 * @return 0 on success, -errno on failure
990 int prepare_buffer_data(const struct log_config *conf, struct buffer_config_data *data, log_id_t buf_id)
992 char * const buf_name = log_name_by_id(buf_id);
993 char * validity_check_ptr;
994 char conf_key[MAX_CONF_KEY_LEN];
997 r = prepare_socket_data(conf, &data->conn_socket, buf_name, "conn");
1001 r = prepare_socket_data(conf, &data->ctl_socket, buf_name, "ctl");
1005 r = snprintf(conf_key, MAX_CONF_KEY_LEN, "%s_size", buf_name);
1009 const char * const size_str = log_config_get(conf, conf_key);
1013 data->size = strtol(size_str, &validity_check_ptr, 10);
1014 if (*validity_check_ptr)
1016 if (data->size <= 0)
1023 * @brief Save logfile line
1024 * @detail Saves logfile config line in user_data list
1025 * @param[in] key Config entry key
1026 * @param[in] value Config entry value
1027 * @param[in] userdata Userdata
1029 void save_logfile_config(char const *key, char const *value, void *userdata)
1032 if (strncmp(key, CONF_PREFIX, sizeof CONF_PREFIX - 1))
1035 struct logger_config_data *data = (struct logger_config_data *)userdata;
1036 void *cmd = (void *)strdup(value);
1038 list_add(&data->logfile_configs, cmd);
1043 * @brief Initialize config data
1044 * @param[out] The data structure to fill with initial values
1046 void initialize_config_data(struct logger_config_data *data)
1048 memset(data, 0, sizeof *data);
1052 * @brief Prepare config data
1053 * @details Extracts relevant config data for logger initialisation
1054 * @param[out] data Parsed configuration
1055 * @return 0 on success, -errno on failure
1057 int prepare_config_data(struct logger_config_data *data)
1061 struct log_config conf;
1062 int ret = log_config_read(&conf);
1066 const dlogutil_sorting_order_e sort_by = get_order_from_config(&conf);
1068 int throttling_default = log_config_get_int(&conf, "logger_dev_throttling", LOGGER_DEVICE_THROTTLING_DEFAULT);
1069 const char *const dynamic_config_dir = log_config_get(&conf, DYNAMIC_CONFIG_CONF_KEY);
1071 const char * const backend = log_config_claim_backend(&conf);
1077 for (int i = 0; i < LOG_ID_MAX; i++) {
1078 char key[MAX_CONF_KEY_LEN];
1079 const int r = snprintf(key, sizeof key, "logger_dev_throttling_%s", log_name_by_id((log_id_t)i));
1083 g_backend.logger_device_throttling[i] = max_int(1, log_config_get_int(&conf, key, throttling_default));
1086 if (dynamic_config_dir && dynamic_config_dir[0] == '/') {
1087 data->dynamic_config_dir = strdup(dynamic_config_dir);
1088 if (!data->dynamic_config_dir) {
1093 data->dynamic_config_dir = NULL; // Technically unnecessary but no reason not to put it
1096 data->epoll_time = log_config_get_int(&conf, "epoll_time_ms", DEFAULT_EPOLL_TIME_MS);
1097 data->lazy_polling_total = log_config_get_int(&conf, "lazy_polling_total_ms", DEFAULT_LAZY_POLLING_TOTAL_MS);
1098 data->lazy_polling_sleep = log_config_get_int(&conf, "lazy_polling_sleep_ms", DEFAULT_LAZY_POLLING_SLEEP_MS);
1100 const char *const qos_file_path = log_config_get(&conf, "qos_file_path");
1101 data->qos_file_path = qos_file_path ? strdup(qos_file_path) : NULL;
1103 data->qos_limit_duration = log_config_get_int(&conf, "qos_refresh_rate_s", DEFAULT_QOS_LIMIT_DURATION_S);
1104 data->qos_max_throughput = log_config_get_int(&conf, "qos_max_throughput_logs", DEFAULT_QOS_THROUGHPUT_LOGS);
1105 data->qos_threshold = log_config_get_int(&conf, "qos_threshold_logs", DEFAULT_QOS_THRESHOLD_LOGS);
1106 data->qos_threshold_reapply = log_config_get_int(&conf, "qos_threshold_reapply_logs", DEFAULT_QOS_THRESHOLD_REAPPLY_LOGS);
1109 void (*func)(struct qos_module *qos, struct metrics_pid_aggr_info *infos, int count);
1111 } const qos_methods[] = {
1112 { qos_distribution_proportional_raw , "proportional_raw" },
1113 { qos_distribution_proportional_talmud, "proportional_talmud" },
1114 { qos_distribution_equal , "equal" },
1115 { qos_distribution_equal_dual , "equal_dual" },
1116 { qos_distribution_equal_multi , "equal_multi" },
1118 qos_distribution_func = qos_distribution_equal_multi; // default
1119 const char *const qos_method = log_config_get(&conf, "qos_method");
1121 for (int i = 0; i < NELEMS(qos_methods); ++i)
1122 if (!strcmp(qos_method, qos_methods[i].name))
1123 qos_distribution_func = qos_methods[i].func;
1125 const char *const first_time_file_path = log_config_get(&conf, "first_time_file_path");
1126 data->first_time_file_path = first_time_file_path ? strdup(first_time_file_path) : NULL;
1128 memset(data->is_buffer_enabled, 0, sizeof(data->is_buffer_enabled));
1129 if (!strcmp(backend, "pipe")) {
1130 data->is_buffer_enabled[LOG_ID_MAIN] =
1131 data->is_buffer_enabled[LOG_ID_RADIO] =
1132 data->is_buffer_enabled[LOG_ID_SYSTEM] =
1133 data->is_buffer_enabled[LOG_ID_APPS] = 1;
1134 g_backend.use_logger_by_default = false;
1135 } else if (!strcmp(backend, "logger")) {
1136 g_backend.use_logger_by_default = true;
1137 for (log_id_t buf_id = 0; buf_id < LOG_ID_MAX; ++buf_id) {
1138 const char *const logger_device = log_config_get(&conf, log_name_by_id(buf_id));
1140 strncpy(g_backend.logger_devices[buf_id], logger_device,
1141 NELEMS(g_backend.logger_devices[buf_id]) - 1);
1143 } else if (!strcmp(backend, "zero-copy")) {
1144 /* HACK: This essentially skips reading the most important configuration fields
1145 * (buffer reading and persistent logs) while ensuring the variables are initialized.
1146 * This will result in daemon quitting. Hopefully we will either reenable some of these
1147 * in the future or at least make it exit more gracefully (TODO), but for now this is ok. */
1148 g_backend.use_logger_by_default = false;
1149 data->logfile_configs = NULL;
1155 data->is_buffer_enabled[LOG_ID_KMSG] = log_config_get_boolean(&conf, "handle_kmsg", true);
1156 data->is_buffer_enabled[LOG_ID_SYSLOG] =
1157 dev_log_sock_get() >= 0 || log_config_get_boolean(&conf, "syslog_force", false);
1159 for (log_id_t buf_id = 0; buf_id < LOG_ID_MAX; ++buf_id) {
1160 if (data->is_buffer_enabled[buf_id]) {
1161 ret = prepare_buffer_data(&conf, data->buffers + buf_id, buf_id);
1164 data->buffers[buf_id].sort_by = sort_by;
1167 data->logfile_configs = NULL;
1168 log_config_foreach(&conf, save_logfile_config, data);
1170 data->default_format = get_default_format_from_config(&conf);
1173 log_config_free(&conf);
1177 static bool cond_string_free(void *ptr, void *user_data)
1187 void free_config_data(struct logger_config_data *data)
1189 list_remove_if(&data->logfile_configs, NULL, cond_string_free);
1190 free(data->dynamic_config_dir);
1191 free(data->qos_file_path);
1192 free(data->first_time_file_path);
1195 struct parse_logfile_config_data {
1196 struct logger *server;
1197 struct logger_config_data *data;
1201 * @brief Parse logfile line
1202 * @detail Parses a logfile config line
1203 * @param[in] key Config entry key
1204 * @param[in] value Config entry value
1205 * @param[in] userdata Userdata
1207 void parse_logfile_config(void *value, void *userdata)
1212 struct logger *server = ((struct parse_logfile_config_data *) userdata)->server;
1213 struct logger_config_data *data = ((struct parse_logfile_config_data *) userdata)->data;
1214 char *configline = (char *) value;
1216 __attribute__((cleanup(free_dlogutil_line_params))) struct dlogutil_line_params params;
1217 if (!initialize_dlogutil_line_params(¶ms, server->buf_params))
1220 get_dlogutil_line_params(configline, data->default_format, ¶ms);
1223 if (g_backend.use_logger_by_default && is_core_buffer(params.buf_id)) {
1224 r = params.compression
1225 ? create_memory_subreader_from_dlogutil_line(¶ms, server)
1226 : create_logger_subreader_from_dlogutil_line(¶ms)
1229 struct reader_pipe *reader = NULL;
1230 r = create_reader_pipe_from_dlogutil_line(¶ms, server, &reader);
1232 add_reader_pipe(server, reader);
1237 printf("Warning: unable to add logutil reader for provided configuration. Ignoring.\n"
1238 " Config line: %s\n"
1239 " Reason given: %m\n",
1247 * @details Prints basic usage tips
1249 static void help(void)
1251 printf("Usage: %s [options]\n"
1252 "\t-h Show this help\n"
1253 "\t-b N Set the size of the log buffer (in bytes)\n"
1254 "\t-t N Set time between writes to file (in seconds)\n",
1255 program_invocation_short_name);
1260 * @details Parses execution parameters of the program
1261 * @param[in] argc Argument count
1262 * @param[in] argv Argument values
1263 * @param[out] b Buffering parameters
1264 * @return 0 or 1 on success, else -errno. Nonzero if the program is to close.
1266 static int parse_args(int argc, char **argv, struct buf_params *b)
1268 b->time = BUF_PARAM_TIME_DEFAULT;
1269 b->bytes = BUF_PARAM_BYTES_DEFAULT;
1272 while ((option = getopt(argc, argv, "hb:t:")) != -1) {
1275 if (!isdigit(optarg[0]))
1277 b->time = clamp_int(atoi(optarg), BUF_PARAM_TIME_MIN, BUF_PARAM_TIME_MAX);
1280 if (!isdigit(optarg[0]))
1282 b->bytes = clamp_int(atoi(optarg), BUF_PARAM_BYTES_MIN, BUF_PARAM_BYTES_MAX);
1295 * @brief Finalize initialisation
1296 * @details Do misc stuff needed at the end of the initialisation
1297 * @param[in] data configuration dat to read logfiles config lines from
1298 * @param[in] server logger instance to configure
1299 * @return 0 on success, -errno on failure
1301 static int finalize_init(struct logger_config_data *data, struct logger *server)
1303 int r = sd_notify(0, "READY=1");
1307 //create files after resetting self privileges
1308 list_foreach(data->logfile_configs, &(struct parse_logfile_config_data) {
1311 }, parse_logfile_config);
1316 static void precreate_logctl_file(struct logger_config_data *data)
1318 __attribute__((cleanup(free_ptr))) char *logctl_file_path = NULL;
1319 if (asprintf(&logctl_file_path, "%s/%s", data->dynamic_config_dir, DYNAMIC_CONFIG_FILENAME) < 0)
1320 // This is worrying but unimportant
1323 int fd = open(logctl_file_path, O_RDONLY | O_CREAT, 0644);
1325 // Again, no big deal
1331 bool early_termination(const struct logger_config_data *data, const struct logger *logger) {
1332 /* In order to check if the deamon will be doing nothing
1333 * and can quit instantaneously, we do three checks: */
1335 /* 1. We make sure that there are no logger subreaders.
1336 * When the logger backend is being used, the daemon reads the data
1337 * in order to use it internally. The daemon always reads each buffer
1338 * to a separate reader and each concrete usage has its own subreader.
1339 * Therefore, we need to check if no subreaders exist. */
1340 for (list_head l = logger->readers_logger; l != NULL; list_next(&l)) {
1341 struct reader_logger *reader = list_at(l);
1342 if (reader->common.subs != NULL)
1346 /* 2. We make sure that no pipe-like buffer is enabled.
1347 * When the pipe backend is being used or pipe-like buffers
1348 * (i.e. KMSG, SYSLOG) are handled, the logger allocates space for them.
1349 * In this case, we cannot terminate even if the buffer is enabled
1350 * but unused at the moment, since it might be connected to
1351 * (for instance by dlogutil). */
1352 for (log_id_t id = 0; id < LOG_ID_MAX; id++)
1353 if (data->is_buffer_enabled[id])
1356 /* 3. We make sure that there are no writers.
1357 * In theory, previous checks are sufficient.
1358 * However, we do another check just to be sure
1359 * (since if there are writers, we shouldn't terminate).
1360 * Additionally, this could change in the future,
1361 * so let's hedge against someone forgetting that this function exists. */
1362 return logger->writers == NULL;
1367 * @return 0 on success, nonzero on failure
1368 * @retval 1 Configuration error
1369 * @retval 2 Runtime error
1371 int main(int argc, char **argv)
1375 signal(SIGPIPE, SIG_IGN);
1377 r = reset_self_privileges();
1380 printf("Unable to drop privileges to build-time defaults (%m). Exiting.\n");
1381 return DLOG_EXIT_ERR_RUNTIME;
1384 struct logger_config_data data;
1385 initialize_config_data(&data);
1387 if ((r = parse_args(argc, argv, &data.buf_params)) != 0) {
1391 return DLOG_EXIT_SUCCESS; // --help option
1394 printf("Unable to parse command line args (%m). Exiting.\n");
1395 return DLOG_EXIT_ERR_CONFIG;
1398 if ((r = prepare_config_data(&data)) != 0) {
1400 printf("Unable to prepare config (%m). Exiting.\n");
1401 return DLOG_EXIT_ERR_CONFIG;
1404 precreate_logctl_file(&data);
1406 struct logger server;
1407 if ((r = logger_create(&data, &server)) < 0) {
1409 printf("Unable to initialize logger with provided configuration (%m). Exiting.\n");
1410 ret = DLOG_EXIT_ERR_CONFIG;
1414 if ((r = finalize_init(&data, &server)) < 0) {
1416 printf("Unable to finalize initialisation (%m). Exiting.\n");
1417 ret = DLOG_EXIT_ERR_CONFIG;
1421 if (early_termination(&data, &server)) {
1422 printf("No work to do according to provided configuration. Exiting.\n");
1423 ret = DLOG_EXIT_SUCCESS;
1427 if ((r = do_logger(&server)) < 0) {
1429 printf("Runtime failure (%m). Exiting.\n");
1430 ret = DLOG_EXIT_ERR_RUNTIME;
1434 ret = DLOG_EXIT_SUCCESS;
1437 free_config_data(&data);
1438 logger_free(&server);