src/logger/qos.c \
src/logger/qos_distributions.c \
src/logger/reader_common.c \
+ src/logger/reader_logger.c \
src/logger/reader_pipe.c \
src/shared/backend_androidlogger.c \
src/shared/ptrs_list.c \
static int service_writer_handle_req_pipe(struct logger *server, struct writer *wr, struct dlog_control_msg *msg);
void dispatch_event_writer(struct logger *server, struct epoll_event *event, void *userdata);
void dispatch_event_sock(struct logger *server, struct epoll_event *event, void *userdata);
-static void dispatch_event_reader_logger(struct logger *server, struct epoll_event *event, void *userdata);
-static void reader_logger_free(struct reader_logger *reader);
static void logger_free(struct logger* l);
int socket_initialize(struct sock_data *sock, struct log_buffer *buffer, service_socket_t service_socket, struct socket_config_data *data);
static int initialize_epoll_size(struct epoll_event **events, unsigned *size);
/** global state when logger is not interrupted by any handled signals */
static volatile sig_atomic_t g_logger_run = 1;
-static struct {
- bool use_logger_by_default;
- char logger_devices[LOG_ID_MAX][MAX_CONF_VAL_LEN];
- int logger_device_throttling[LOG_ID_MAX];
- struct reader_logger *logger_readers[LOG_ID_MAX];
-} g_backend = {};
-
static const int DEFAULT_EPOLL_TIME_MS = 1000;
static const int DEFAULT_LAZY_POLLING_TOTAL_MS = 0;
static const int S_TO_MS = 1000;
static const int MS_TO_NS = 1000000;
+struct backend_data g_backend = {};
+
/**
* @brief Parse permissions
* @details Parse a string representation of permissions to the internal integral one
free(w);
}
-static void subreader_logger_metrics_apply_log(const struct subreader_logger *srl, const struct dlogutil_entry *due)
-{
- assert(srl);
- assert(due);
-
- struct subreader_logger_metrics *const srlm = (struct subreader_logger_metrics *) srl->sub_userdata;
- assert(srlm);
-
- qos_add_log(srlm->qos, due);
-}
-
-static void subreader_logger_metrics_free(void *userdata)
-{
- // nothing to do; we're just a wrapper over a weak (shared) pointer
-}
-
-static void subreader_logger_file_apply_log(const struct subreader_logger *srl, const struct dlogutil_entry *due)
-{
- assert(srl);
- assert(due);
-
- struct subreader_logger_file *const srlf = (struct subreader_logger_file *) srl->sub_userdata;
- assert(srlf);
-
- logfile_write_with_rotation(due, &srlf->file, DLOGUTIL_SORT_SENT_REAL);
-}
-
-static void subreader_logger_file_free(void *userdata)
-{
- struct subreader_logger_file *const srlf = (struct subreader_logger_file *) userdata;
- assert(srlf);
-
- logfile_free(&srlf->file);
-}
-
-static void subreader_logger_free(void *sub, void *userdata)
-{
- struct subreader_logger *const srl = (struct subreader_logger *) sub;
- assert(srl);
- assert(userdata == NULL);
-
- srl->sub_destroy(srl->sub_userdata);
- if (srl->filter)
- log_filter_free(srl->filter);
- free(srl->sub_userdata);
-}
-
-static void subreader_logger_apply_log(void *sub, void *userdata)
-{
- struct subreader_logger *const srl = (struct subreader_logger *) sub;
- assert(srl);
-
- const struct dlogutil_entry *const due = (const struct dlogutil_entry *) userdata;
- assert(due);
-
- if (!log_should_print_line(srl->filter, due))
- return;
-
- srl->sub_apply_log(srl, due);
-}
-
-static void reader_logger_free(struct reader_logger *reader)
-{
- if (!reader)
- return;
-
- reader_deinit_common(&reader->common);
- list_clear_custom(&reader->subs, NULL, subreader_logger_free);
- free(reader);
-}
-
-void reader_logger_cleanup(struct reader_logger *const *ptr)
-{
- assert(ptr);
- reader_logger_free(*ptr);
-}
-
-/**
- * @brief Service reader file
- * @details Handles readers reading directly from file
- * @param[in] reader The reader to service
- * @param[in] time Timestamps
- * @return 0 on success, else an errno value
- * @return 1 if the reader is to be removed, 0 if kept, -errno on error
- */
-int service_reader_logger(struct reader_logger* reader, struct now_t time)
-{
- assert(reader);
-
- struct dlogutil_entry_with_msg entry;
- static char buffer[sizeof entry + 1];
- buffer[sizeof buffer - 1] = '\0';
-
- /* The devices for the Android Logger only return one log per read().
- * So using an 'if' here would be wasteful and, more importantly, too slow in the case where other logs come in.
- * However, with an unlimited loop, if there are extreme amounts of logs incoming,
- * the loop handles them slower than they come so the program stays in the loop
- * for a very long time, starving all other log sources. Using a limited loop
- * makes sure that the daemon works efficiently in the usual case while preventing
- * starvation under heavy load. */
- int max_loop_iterations = g_backend.logger_device_throttling[reader->buf_id];
- while (max_loop_iterations--) {
- int r = TEMP_FAILURE_RETRY(read(reader->common.fd_entity_source.fd, buffer, sizeof buffer - 1));
- if (r == 0)
- break;
- else if (r == -1) {
- if (errno == EAGAIN) // no data left in the buffer
- break;
- else
- return -errno;
- } else {
- if (reader->skip_count > 0) {
- reader->skip_count -= r;
- continue;
- }
-
- buffer[r] = '\0';
- parse_androidlogger_message((struct android_logger_entry *) buffer, &entry.header, r);
- add_recv_timestamp(&entry.header, time);
-
- list_foreach(reader->subs, &entry.header, subreader_logger_apply_log);
- }
- }
-
- return 0;
-}
-
void reader_notify_losing_log(const dlogutil_entry_s *le, void *reader_)
{
struct reader_pipe *reader = (struct reader_pipe *) reader_;
return ret;
}
-static struct reader_logger *reader_logger_alloc()
-{
- struct reader_logger *const ret = calloc(1, sizeof *ret);
- if (!ret)
- return NULL;
-
- ret->buf_id = LOG_ID_INVALID;
-
- return ret;
-}
-
-static int reader_logger_add_subreader_file(struct reader_logger *reader, dlogutil_filter_options_s *filter, struct log_file *file)
-{
- assert(reader);
- assert(filter);
-
- struct subreader_logger *const srl = malloc(sizeof *srl);
- struct subreader_logger_file *const srlf = malloc(sizeof *srlf);
- if (!srl || !srlf) {
- free(srl);
- free(srlf);
- return -ENOMEM;
- }
-
- logfile_move(&srlf->file, file);
-
- srl->sub_userdata = srlf;
- srl->sub_destroy = subreader_logger_file_free;
- srl->sub_apply_log = subreader_logger_file_apply_log;
- srl->filter = log_filter_move(filter);
-
- list_add(&reader->subs, srl);
-
- return 0;
-}
-
-static int reader_logger_add_subreader_metrics(struct reader_logger *reader, struct qos_module *qos)
-{
- assert(reader);
- assert(qos);
-
- struct subreader_logger *const srl = malloc(sizeof *srl);
- struct subreader_logger_metrics *const srlm = malloc(sizeof *srlm);
- dlogutil_filter_options_s *const filter = log_filter_new();
- if (!srl || !srlm || !filter || dlogutil_filter_options_set_filterspec(filter, "*:V")) {
- free(srl);
- free(srlm);
- log_filter_free(filter);
- return -ENOMEM;
- }
-
- srlm->qos = qos;
-
- srl->sub_userdata = srlm;
- srl->sub_destroy = subreader_logger_metrics_free;
- srl->sub_apply_log = subreader_logger_metrics_apply_log;
- srl->filter = filter;
-
- list_add(&reader->subs, srl);
-
- return 0;
-}
-
-static int reader_logger_init(struct reader_logger **reader, log_id_t buf_id, struct logger *server, bool skip)
-{
- assert(reader);
- assert(buf_id > LOG_ID_INVALID);
- assert(buf_id < LOG_ID_MAX);
- assert(is_core_buffer(buf_id));
- assert(server);
-
- __attribute__((cleanup(reader_logger_cleanup))) struct reader_logger *ret = reader_logger_alloc();
- if (!ret)
- return -ENOMEM;
-
- assert(buf_id >= 0 && (unsigned) buf_id < NELEMS(g_backend.logger_devices));
- char const *config_list = g_backend.logger_devices[buf_id];
- if (strlen(config_list) == 0)
- return -ENOENT;
- ret->buf_id = buf_id;
-
- int read_fd = -1;
- int r = logger_open_buffer(buf_id, config_list, O_RDONLY | O_NONBLOCK, &read_fd);
- if (r <= 0)
- return r;
-
- ret->skip_count = skip ? logger_get_log_len(read_fd) : 0;
-
- init_fd_entity(&ret->common.fd_entity_sink, dispatch_event_reader_logger, ret);
- init_fd_entity(&ret->common.fd_entity_source, dispatch_event_reader_logger, ret);
- set_read_fd_entity(&ret->common.fd_entity_source, read_fd);
-
- *reader = ret;
- ret = NULL;
- return 0;
-}
-
static int create_fifo_fds(struct logger *server, int fifo_id, int *write_fd, int *read_fd, bool dump)
{
assert(write_fd);
return false;
}
-static void dispatch_event_reader_logger(struct logger *server, struct epoll_event *event, void *userdata)
-{
- struct reader_logger *const rl = (struct reader_logger *) userdata;
- assert(rl);
-
- if (event->events & (EPOLLHUP | EPOLLERR)) {
- remove_reader_fd_entities(server, &rl->common);
- list_remove(&server->readers_logger, rl);
- reader_logger_free(rl);
- return;
- }
-
- int r = service_reader_logger(rl, server->time);
- if (r != 0) {
- /* TODO: There is no reason not to free the reader in full. However, when I do so, some tests start to
- * fail without any reasonable reason. You are welcome to *try* to figure out why does this happen. */
- remove_reader_fd_entities(server, &rl->common);
- }
-}
-
/**
* @brief Service syslog
* @details Read from the syslog socket
#include "qos.h"
#include "fd_entity.h"
#include "reader_common.h"
+#include "reader_logger.h"
#include "reader_pipe.h"
#ifdef __cplusplus
LOGGER_DEVICE_THROTTLING_DEFAULT = 100,
};
+extern struct backend_data {
+ bool use_logger_by_default;
+ char logger_devices[LOG_ID_MAX][MAX_CONF_VAL_LEN];
+ int logger_device_throttling[LOG_ID_MAX];
+ struct reader_logger *logger_readers[LOG_ID_MAX];
+} g_backend;
+
struct logger;
struct writer;
};
#undef LARGEST_STRUCT
-struct subreader_logger_file {
- struct log_file file;
-};
-
-struct subreader_logger_metrics {
- struct qos_module *qos;
-};
-
-struct subreader_logger {
- void (*sub_apply_log)(const struct subreader_logger *srl, const struct dlogutil_entry *due);
- void (*sub_destroy)(void *sub_userdata);
- void *sub_userdata;
- dlogutil_filter_options_s *filter;
-};
-
-struct reader_logger {
- list_head subs;
- log_id_t buf_id;
- int skip_count;
- struct reader common;
-};
-
struct sock_data {
struct fd_entity fd_entity;
struct log_buffer* buf_ptr;
--- /dev/null
+#include "reader_logger.h"
+#include "logger_internal.h"
+
+static void subreader_logger_metrics_apply_log(const struct subreader_logger *srl, const struct dlogutil_entry *due)
+{
+ assert(srl);
+ assert(due);
+
+ struct subreader_logger_metrics *const srlm = (struct subreader_logger_metrics *) srl->sub_userdata;
+ assert(srlm);
+
+ qos_add_log(srlm->qos, due);
+}
+
+static void subreader_logger_metrics_free(void *userdata)
+{
+ // nothing to do; we're just a wrapper over a weak (shared) pointer
+}
+
+static void subreader_logger_file_apply_log(const struct subreader_logger *srl, const struct dlogutil_entry *due)
+{
+ assert(srl);
+ assert(due);
+
+ struct subreader_logger_file *const srlf = (struct subreader_logger_file *) srl->sub_userdata;
+ assert(srlf);
+
+ logfile_write_with_rotation(due, &srlf->file, DLOGUTIL_SORT_SENT_REAL);
+}
+
+static void subreader_logger_file_free(void *userdata)
+{
+ struct subreader_logger_file *const srlf = (struct subreader_logger_file *) userdata;
+ assert(srlf);
+
+ logfile_free(&srlf->file);
+}
+
+static void subreader_logger_free(void *sub, void *userdata)
+{
+ struct subreader_logger *const srl = (struct subreader_logger *) sub;
+ assert(srl);
+ assert(userdata == NULL);
+
+ srl->sub_destroy(srl->sub_userdata);
+ if (srl->filter)
+ log_filter_free(srl->filter);
+ free(srl->sub_userdata);
+}
+
+static void subreader_logger_apply_log(void *sub, void *userdata)
+{
+ struct subreader_logger *const srl = (struct subreader_logger *) sub;
+ assert(srl);
+
+ const struct dlogutil_entry *const due = (const struct dlogutil_entry *) userdata;
+ assert(due);
+
+ if (!log_should_print_line(srl->filter, due))
+ return;
+
+ srl->sub_apply_log(srl, due);
+}
+void reader_logger_free(struct reader_logger *reader)
+{
+ if (!reader)
+ return;
+
+ reader_deinit_common(&reader->common);
+ list_clear_custom(&reader->subs, NULL, subreader_logger_free);
+ free(reader);
+}
+
+void reader_logger_cleanup(struct reader_logger *const *ptr)
+{
+ assert(ptr);
+ reader_logger_free(*ptr);
+}
+
+/**
+ * @brief Service reader file
+ * @details Handles readers reading directly from file
+ * @param[in] reader The reader to service
+ * @param[in] time Timestamps
+ * @return 0 on success, else an errno value
+ * @return 1 if the reader is to be removed, 0 if kept, -errno on error
+ */
+int service_reader_logger(struct reader_logger* reader, struct now_t time)
+{
+ assert(reader);
+
+ struct dlogutil_entry_with_msg entry;
+ static char buffer[sizeof entry + 1];
+ buffer[sizeof buffer - 1] = '\0';
+
+ /* The devices for the Android Logger only return one log per read().
+ * So using an 'if' here would be wasteful and, more importantly, too slow in the case where other logs come in.
+ * However, with an unlimited loop, if there are extreme amounts of logs incoming,
+ * the loop handles them slower than they come so the program stays in the loop
+ * for a very long time, starving all other log sources. Using a limited loop
+ * makes sure that the daemon works efficiently in the usual case while preventing
+ * starvation under heavy load. */
+ int max_loop_iterations = g_backend.logger_device_throttling[reader->buf_id];
+ while (max_loop_iterations--) {
+ int r = TEMP_FAILURE_RETRY(read(reader->common.fd_entity_source.fd, buffer, sizeof buffer - 1));
+ if (r == 0)
+ break;
+ else if (r == -1) {
+ if (errno == EAGAIN) // no data left in the buffer
+ break;
+ else
+ return -errno;
+ } else {
+ if (reader->skip_count > 0) {
+ reader->skip_count -= r;
+ continue;
+ }
+
+ buffer[r] = '\0';
+ parse_androidlogger_message((struct android_logger_entry *) buffer, &entry.header, r);
+ add_recv_timestamp(&entry.header, time);
+
+ list_foreach(reader->subs, &entry.header, subreader_logger_apply_log);
+ }
+ }
+
+ return 0;
+}
+
+static struct reader_logger *reader_logger_alloc()
+{
+ struct reader_logger *const ret = calloc(1, sizeof *ret);
+ if (!ret)
+ return NULL;
+
+ ret->buf_id = LOG_ID_INVALID;
+
+ return ret;
+}
+
+int reader_logger_add_subreader_file(struct reader_logger *reader, dlogutil_filter_options_s *filter, struct log_file *file)
+{
+ assert(reader);
+ assert(filter);
+
+ struct subreader_logger *const srl = malloc(sizeof *srl);
+ struct subreader_logger_file *const srlf = malloc(sizeof *srlf);
+ if (!srl || !srlf) {
+ free(srl);
+ free(srlf);
+ return -ENOMEM;
+ }
+
+ logfile_move(&srlf->file, file);
+
+ srl->sub_userdata = srlf;
+ srl->sub_destroy = subreader_logger_file_free;
+ srl->sub_apply_log = subreader_logger_file_apply_log;
+ srl->filter = log_filter_move(filter);
+
+ list_add(&reader->subs, srl);
+
+ return 0;
+}
+
+int reader_logger_add_subreader_metrics(struct reader_logger *reader, struct qos_module *qos)
+{
+ assert(reader);
+ assert(qos);
+
+ struct subreader_logger *const srl = malloc(sizeof *srl);
+ struct subreader_logger_metrics *const srlm = malloc(sizeof *srlm);
+ dlogutil_filter_options_s *const filter = log_filter_new();
+ if (!srl || !srlm || !filter || dlogutil_filter_options_set_filterspec(filter, "*:V")) {
+ free(srl);
+ free(srlm);
+ log_filter_free(filter);
+ return -ENOMEM;
+ }
+
+ srlm->qos = qos;
+
+ srl->sub_userdata = srlm;
+ srl->sub_destroy = subreader_logger_metrics_free;
+ srl->sub_apply_log = subreader_logger_metrics_apply_log;
+ srl->filter = filter;
+
+ list_add(&reader->subs, srl);
+
+ return 0;
+}
+
+static void dispatch_event_reader_logger(struct logger *server, struct epoll_event *event, void *userdata)
+{
+ struct reader_logger *const rl = (struct reader_logger *) userdata;
+ assert(rl);
+
+ if (event->events & (EPOLLHUP | EPOLLERR)) {
+ remove_reader_fd_entities(server, &rl->common);
+ list_remove(&server->readers_logger, rl);
+ reader_logger_free(rl);
+ return;
+ }
+
+ int r = service_reader_logger(rl, server->time);
+ if (r != 0) {
+ /* TODO: There is no reason not to free the reader in full. However, when I do so, some tests start to
+ * fail without any reasonable reason. You are welcome to *try* to figure out why does this happen. */
+ remove_reader_fd_entities(server, &rl->common);
+ }
+}
+
+int reader_logger_init(struct reader_logger **reader, log_id_t buf_id, struct logger *server, bool skip)
+{
+ assert(reader);
+ assert(buf_id > LOG_ID_INVALID);
+ assert(buf_id < LOG_ID_MAX);
+ assert(is_core_buffer(buf_id));
+ assert(server);
+
+ __attribute__((cleanup(reader_logger_cleanup))) struct reader_logger *ret = reader_logger_alloc();
+ if (!ret)
+ return -ENOMEM;
+
+ assert(buf_id >= 0 && (unsigned) buf_id < NELEMS(g_backend.logger_devices));
+ char const *config_list = g_backend.logger_devices[buf_id];
+ if (strlen(config_list) == 0)
+ return -ENOENT;
+ ret->buf_id = buf_id;
+
+ int read_fd = -1;
+ int r = logger_open_buffer(buf_id, config_list, O_RDONLY | O_NONBLOCK, &read_fd);
+ if (r <= 0)
+ return r;
+
+ ret->skip_count = skip ? logger_get_log_len(read_fd) : 0;
+
+ init_fd_entity(&ret->common.fd_entity_sink, dispatch_event_reader_logger, ret);
+ init_fd_entity(&ret->common.fd_entity_source, dispatch_event_reader_logger, ret);
+ set_read_fd_entity(&ret->common.fd_entity_source, read_fd);
+
+ *reader = ret;
+ ret = NULL;
+ return 0;
+}
+
--- /dev/null
+#pragma once
+
+#include <log_file.h>
+#include <queued_entry_timestamp.h>
+#include "reader_common.h"
+
+struct subreader_logger_file {
+ struct log_file file;
+};
+
+struct subreader_logger_metrics {
+ struct qos_module *qos;
+};
+
+struct subreader_logger {
+ void (*sub_apply_log)(const struct subreader_logger *srl, const struct dlogutil_entry *due);
+ void (*sub_destroy)(void *sub_userdata);
+ void *sub_userdata;
+ dlogutil_filter_options_s *filter;
+};
+
+struct reader_logger {
+ list_head subs;
+ log_id_t buf_id;
+ int skip_count;
+ struct reader common;
+};
+
+int reader_logger_init(struct reader_logger **reader, log_id_t buf_id, struct logger *server, bool skip);
+int service_reader_logger(struct reader_logger* reader, struct now_t time);
+int reader_logger_add_subreader_file(struct reader_logger *reader, dlogutil_filter_options_s *filter, struct log_file *file);
+int reader_logger_add_subreader_metrics(struct reader_logger *reader, struct qos_module *qos);
+void reader_logger_free(struct reader_logger *reader);
+void reader_logger_cleanup(struct reader_logger *const *ptr);