src/logger/logger.c \
src/logger/log_storage.c \
src/logger/qos.c \
+ src/logger/reader_pipe.c \
src/shared/backend_androidlogger.c \
src/shared/ptrs_list.c \
src/shared/logcommon.c \
#endif
#include "logger_internal.h"
+#include "reader_pipe.h"
#include <metrics.h>
#include <getopt.h>
#include <dynamic_config.h>
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 dispatch_event_reader_pipe(struct logger *server, struct epoll_event *event, void *userdata);
-void reader_pipe_free(struct reader_pipe *reader);
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);
struct reader_pipe *reader = (struct reader_pipe *)ptr;
struct logger *logger = (struct logger *)user_data;
assert(reader);
+ // TODO: This is absurd, why isn't this in the reader_pipe_free function?
if (reader->common.fd_entity_sink.fd >= 0)
remove_fd_entity(&logger->epoll_common, &reader->common.fd_entity_sink);
if (reader->common.fd_entity_source.fd >= 0)
struct reader_logger *reader = (struct reader_logger *)ptr;
struct logger *logger = (struct logger *)user_data;
assert(reader);
+ // TODO: This is absurd, why isn't this in the reader_logger_free function?
if (reader->common.fd_entity_sink.fd >= 0)
remove_fd_entity(&logger->epoll_common, &reader->common.fd_entity_sink);
if (reader->common.fd_entity_source.fd >= 0)
free(buffer);
}
-uint64_t reader_buffered_space(const struct reader_pipe *reader)
-{
- assert(reader);
- assert(reader->buf_ptr);
- return log_storage_reader_get_ready_bytes(reader->log_storage_reader_ptr);
-}
-
-int reader_is_bufferable(const struct reader_pipe *reader)
-{
- assert(reader);
- return reader->buf_ptr && reader->file.path != NULL;
-}
-
-int reader_ms_since(const struct reader_pipe *reader, struct timespec *ts)
-{
- return (ts->tv_sec - reader->last_read_time.tv_sec) * 1000 + (ts->tv_nsec - reader->last_read_time.tv_nsec) / 1000000;
-}
-
-int reader_should_buffer(struct reader_pipe *reader, const struct buf_params *buf_params, struct timespec now)
-{
- assert(reader);
- assert(buf_params);
-
- if (!reader_is_bufferable(reader))
- return 0;
-
- if (reader_buffered_space(reader) < (uint64_t)buf_params->bytes && reader_ms_since(reader, &now) < (buf_params->time * 1000))
- return 1;
-
- reader->last_read_time = now;
- return 0;
-}
-
bool qos_is_enabled(const struct qos_module *qos)
{
assert(qos);
printf("ERROR: not enough memory either, please check platform settings as the daemon is seriously resource-starved!\n");
}
-static int reader_print_out_single_log(struct reader_pipe *reader, const dlogutil_entry_s *dlogutil_entry)
-{
- assert(reader);
- assert(reader->buf_ptr);
- assert(dlogutil_entry);
-
- if (!log_should_print_line(reader->filter, dlogutil_entry))
- return 0;
-
- if (reader->file.path) {
- logfile_write_with_rotation(dlogutil_entry, &reader->file, reader->buf_ptr->sort_by);
- return 0;
- }
-
- const char *tag = dlogutil_entry->msg + 1;
- if (!strlen(tag))
- return 0;
-
- int r = write(reader->file.path ? reader->file.fd : reader->common.fd_entity_sink.fd, dlogutil_entry, dlogutil_entry->len);
- if (r < 0) {
- if (errno != EAGAIN)
- return 1;
-
- /* The pipe is just clogged, this is not an actual error.
- * We own the entry so it needs to be saved for later. */
- r = 0;
- }
-
- reader->file.size += r;
- if (r < dlogutil_entry->len) {
- reader->partial_log_size = dlogutil_entry->len - r;
- memcpy(reader->partial_log, ((char *)dlogutil_entry) + r, reader->partial_log_size);
- return -1;
- } else if (logfile_rotate_needed(&reader->file) > 0) {
- logfile_do_rotate(&reader->file);
- }
-
- return 0;
-}
-
-/**
- * @brief Print out logs
- * @details Make sure the reader is up to date on printed logs
- * @param[in] reader The reader to read the data
- * @param[in] _time Unused timestamps
- * @return 0 if data remains for the next iteration, 1 if the buffer is to be removed, else -1
- */
-int print_out_logs(struct reader_pipe *reader, struct now_t _time)
-{
- assert(reader);
-
- assert(reader->buf_ptr);
-
- if (reader->partial_log_size) {
- int r = write(reader->common.fd_entity_sink.fd, reader->partial_log, reader->partial_log_size);
- if (r <= 0)
- return r != 0 && errno != EAGAIN;
-
- if (r < reader->partial_log_size) {
- reader->partial_log_size -= r;
- memmove(reader->partial_log, reader->partial_log + r, reader->partial_log_size);
- return 0;
- }
-
- reader->partial_log_size = 0;
- }
-
- while (log_storage_reader_is_new_entry_available(reader->log_storage_reader_ptr)) {
- const dlogutil_entry_s* ple = (const dlogutil_entry_s *)log_storage_reader_get_new_entry(reader->log_storage_reader_ptr);
-
- assert(ple);
-
- switch (reader_print_out_single_log(reader, ple)) {
- case 0: /* nothing more to do, let's do next loop */
- break;
-
- case 1: /* error after which we need to end the reader */
- return 1;
-
- default: /* writing error, bounce out */
- return -1;
- }
- }
-
- return reader->is_dumping ? 1 : -1;
-}
-
/**
* @brief Writer close FD
* @details Close a writer's connections
free(w);
}
-static void reader_deinit_common(struct reader *reader)
+void reader_deinit_common(struct reader *reader)
{
if (reader->fd_entity_sink.fd >= 0)
close(reader->fd_entity_sink.fd);
close(reader->fd_entity_source.fd);
}
-void reader_pipe_free(struct reader_pipe *reader)
-{
- if (!reader)
- return;
-
- reader_deinit_common(&reader->common);
- logfile_free(&reader->file);
- if (reader->log_storage_reader_ptr)
- log_storage_release_reader(reader->log_storage_reader_ptr);
- if (reader->filter)
- log_filter_free(reader->filter);
-
- free(reader);
-}
-
static void subreader_logger_metrics_apply_log(const struct subreader_logger *srl, const struct dlogutil_entry *due)
{
assert(srl);
free(reader);
}
-void reader_pipe_cleanup(struct reader_pipe *const *ptr)
-{
- assert(ptr);
- reader_pipe_free(*ptr);
-}
-
void reader_logger_cleanup(struct reader_logger *const *ptr)
{
assert(ptr);
return ret;
}
-static struct reader_pipe *reader_pipe_alloc(dlogutil_filter_options_s *filter, struct log_file *file, struct timespec ts,
- bool monitor, bool is_dumping)
-{
- struct reader_pipe *ret = calloc(1, sizeof(*ret));
- if (!ret)
- return NULL;
-
- ret->filter = log_filter_move(filter);
- ret->monitor = monitor;
- ret->is_dumping = is_dumping;
- logfile_move(&ret->file, file);
- ret->buf_ptr = NULL;
- ret->log_storage_reader_ptr = NULL;
- ret->last_read_time = ts;
- ret->partial_log_size = 0;
-
- return ret;
-}
-
static struct reader_logger *reader_logger_alloc()
{
struct reader_logger *const ret = calloc(1, sizeof *ret);
return 0;
}
-static int reader_pipe_init(struct reader_pipe **reader, log_id_t buf_id, struct logger *server,
- dlogutil_filter_options_s *filter, struct log_file *file, bool monitor, bool is_dumping)
-{
- assert(reader);
- assert(buf_id > LOG_ID_INVALID);
- assert(buf_id < LOG_ID_MAX);
- assert(server);
- assert(filter);
-
- __attribute__((cleanup(reader_pipe_cleanup))) struct reader_pipe *ret = reader_pipe_alloc(filter, file, server->time.mono, monitor, is_dumping);
- if (!ret)
- return -ENOMEM;
-
- ret->buf_ptr = server->buffers[buf_id];
- if (!ret->buf_ptr)
- return -EINVAL;
-
- init_fd_entity(&ret->common.fd_entity_sink, dispatch_event_reader_pipe, ret);
- init_fd_entity(&ret->common.fd_entity_source, dispatch_event_reader_pipe, ret);
-
- *reader = ret;
- ret = NULL;
- return 0;
-}
-
-static int reader_pipe_init_with_writer(struct reader_pipe **reader, struct writer *writer, struct logger *server,
- dlogutil_filter_options_s *filter, struct log_file *file, bool monitor, bool is_dumping)
-{
- assert(reader);
- assert(writer);
- assert(writer->buf_ptr);
- assert(server);
- assert(filter);
-
- __attribute__((cleanup(reader_pipe_cleanup))) struct reader_pipe *ret = reader_pipe_alloc(filter, file, server->time.mono, monitor, is_dumping);
- if (!ret)
- return -ENOMEM;
-
- ret->buf_ptr = writer->buf_ptr;
-
- init_fd_entity(&ret->common.fd_entity_sink, dispatch_event_reader_pipe, ret);
- init_fd_entity(&ret->common.fd_entity_source, dispatch_event_reader_pipe, ret);
-
- *reader = ret;
- ret = NULL;
- return 0;
-}
-
static int reader_logger_init(struct reader_logger **reader, log_id_t buf_id, struct logger *server, bool skip)
{
assert(reader);
return 0;
}
-static void remove_reader_fd_entities(struct logger *server, struct reader *reader)
+void remove_reader_fd_entities(struct logger *server, struct reader *reader)
{
assert(reader);
}
}
-static void dispatch_event_reader_pipe(struct logger *server, struct epoll_event *event, void *userdata)
-{
- struct reader_pipe *const rp = (struct reader_pipe *) userdata;
- assert(rp);
-
- if (event->events & (EPOLLHUP | EPOLLERR)) {
- remove_reader_fd_entities(server, &rp->common);
- if (rp->buf_ptr)
- list_remove(&rp->buf_ptr->readers_pipe, rp);
- reader_pipe_free(rp);
- return;
- }
-
- int r = print_out_logs(rp, server->time);
- if (r != 0) {
- // see comment above
- remove_reader_fd_entities(server, &rp->common);
- }
-}
-
/**
* @brief Service syslog
* @details Read from the syslog socket
struct fd_entity fd_entity_source;
};
-struct reader_pipe {
- struct log_buffer *buf_ptr;
- log_storage_reader *log_storage_reader_ptr;
- struct timespec last_read_time;
- int partial_log_size;
- char partial_log[sizeof(struct dlogutil_entry_with_msg)];
- struct log_file file;
- bool is_dumping;
- bool monitor;
- dlogutil_filter_options_s *filter;
- struct reader common;
-};
-
struct subreader_logger_file {
struct log_file file;
};
char *first_time_file_path;
};
+void remove_reader_fd_entities(struct logger *server, struct reader *reader);
+void reader_deinit_common(struct reader *reader);
+void init_fd_entity(struct fd_entity *fd_entity, dispatch_event_t dispatch_event, void *user_data);
+
#ifdef __cplusplus
}
#endif
--- /dev/null
+#include "reader_pipe.h"
+
+void reader_pipe_free(struct reader_pipe *reader)
+{
+ if (!reader)
+ return;
+
+ reader_deinit_common(&reader->common);
+ logfile_free(&reader->file);
+ if (reader->log_storage_reader_ptr)
+ log_storage_release_reader(reader->log_storage_reader_ptr);
+ if (reader->filter)
+ log_filter_free(reader->filter);
+
+ free(reader);
+}
+
+void reader_pipe_cleanup(struct reader_pipe *const *ptr)
+{
+ assert(ptr);
+ reader_pipe_free(*ptr);
+}
+
+static void dispatch_event_reader_pipe(struct logger *server, struct epoll_event *event, void *userdata)
+{
+ struct reader_pipe *const rp = (struct reader_pipe *) userdata;
+ assert(rp);
+
+ if (event->events & (EPOLLHUP | EPOLLERR)) {
+ remove_reader_fd_entities(server, &rp->common);
+ if (rp->buf_ptr)
+ list_remove(&rp->buf_ptr->readers_pipe, rp);
+ reader_pipe_free(rp);
+ return;
+ }
+
+ int r = print_out_logs(rp, 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, &rp->common);
+ }
+}
+
+static struct reader_pipe *reader_pipe_alloc(dlogutil_filter_options_s *filter, struct log_file *file, struct timespec ts,
+ bool monitor, bool is_dumping)
+{
+ struct reader_pipe *ret = calloc(1, sizeof(*ret));
+ if (!ret)
+ return NULL;
+
+ ret->filter = log_filter_move(filter);
+ ret->monitor = monitor;
+ ret->is_dumping = is_dumping;
+ logfile_move(&ret->file, file);
+ ret->buf_ptr = NULL;
+ ret->log_storage_reader_ptr = NULL;
+ ret->last_read_time = ts;
+ ret->partial_log_size = 0;
+
+ return ret;
+}
+
+int reader_pipe_init(struct reader_pipe **reader, log_id_t buf_id, struct logger *server,
+ dlogutil_filter_options_s *filter, struct log_file *file, bool monitor, bool is_dumping)
+{
+ assert(reader);
+ assert(buf_id > LOG_ID_INVALID);
+ assert(buf_id < LOG_ID_MAX);
+ assert(server);
+ assert(filter);
+
+ __attribute__((cleanup(reader_pipe_cleanup))) struct reader_pipe *ret = reader_pipe_alloc(filter, file, server->time.mono, monitor, is_dumping);
+ if (!ret)
+ return -ENOMEM;
+
+ ret->buf_ptr = server->buffers[buf_id];
+ if (!ret->buf_ptr)
+ return -EINVAL;
+
+ init_fd_entity(&ret->common.fd_entity_sink, dispatch_event_reader_pipe, ret);
+ init_fd_entity(&ret->common.fd_entity_source, dispatch_event_reader_pipe, ret);
+
+ *reader = ret;
+ ret = NULL;
+ return 0;
+}
+
+int reader_pipe_init_with_writer(struct reader_pipe **reader, struct writer *writer, struct logger *server,
+ dlogutil_filter_options_s *filter, struct log_file *file, bool monitor, bool is_dumping)
+{
+ assert(reader);
+ assert(writer);
+ assert(writer->buf_ptr);
+ assert(server);
+ assert(filter);
+
+ __attribute__((cleanup(reader_pipe_cleanup))) struct reader_pipe *ret = reader_pipe_alloc(filter, file, server->time.mono, monitor, is_dumping);
+ if (!ret)
+ return -ENOMEM;
+
+ ret->buf_ptr = writer->buf_ptr;
+
+ init_fd_entity(&ret->common.fd_entity_sink, dispatch_event_reader_pipe, ret);
+ init_fd_entity(&ret->common.fd_entity_source, dispatch_event_reader_pipe, ret);
+
+ *reader = ret;
+ ret = NULL;
+ return 0;
+}
+
+
+uint64_t reader_buffered_space(const struct reader_pipe *reader)
+{
+ assert(reader);
+ assert(reader->buf_ptr);
+ return log_storage_reader_get_ready_bytes(reader->log_storage_reader_ptr);
+}
+
+int reader_is_bufferable(const struct reader_pipe *reader)
+{
+ assert(reader);
+ return reader->buf_ptr && reader->file.path != NULL;
+}
+
+int reader_ms_since(const struct reader_pipe *reader, struct timespec *ts)
+{
+ return (ts->tv_sec - reader->last_read_time.tv_sec) * 1000 + (ts->tv_nsec - reader->last_read_time.tv_nsec) / 1000000;
+}
+
+int reader_should_buffer(struct reader_pipe *reader, const struct buf_params *buf_params, struct timespec now)
+{
+ assert(reader);
+ assert(buf_params);
+
+ if (!reader_is_bufferable(reader))
+ return 0;
+
+ if (reader_buffered_space(reader) < (uint64_t)buf_params->bytes && reader_ms_since(reader, &now) < (buf_params->time * 1000))
+ return 1;
+
+ reader->last_read_time = now;
+ return 0;
+}
+
+int reader_print_out_single_log(struct reader_pipe *reader, const dlogutil_entry_s *dlogutil_entry)
+{
+ assert(reader);
+ assert(reader->buf_ptr);
+ assert(dlogutil_entry);
+
+ if (!log_should_print_line(reader->filter, dlogutil_entry))
+ return 0;
+
+ if (reader->file.path) {
+ logfile_write_with_rotation(dlogutil_entry, &reader->file, reader->buf_ptr->sort_by);
+ return 0;
+ }
+
+ const char *tag = dlogutil_entry->msg + 1;
+ if (!strlen(tag))
+ return 0;
+
+ int r = write(reader->file.path ? reader->file.fd : reader->common.fd_entity_sink.fd, dlogutil_entry, dlogutil_entry->len);
+ if (r < 0) {
+ if (errno != EAGAIN)
+ return 1;
+
+ /* The pipe is just clogged, this is not an actual error.
+ * We own the entry so it needs to be saved for later. */
+ r = 0;
+ }
+
+ reader->file.size += r;
+ if (r < dlogutil_entry->len) {
+ reader->partial_log_size = dlogutil_entry->len - r;
+ memcpy(reader->partial_log, ((char *)dlogutil_entry) + r, reader->partial_log_size);
+ return -1;
+ } else if (logfile_rotate_needed(&reader->file) > 0) {
+ logfile_do_rotate(&reader->file);
+ }
+
+ return 0;
+}
+
+/**
+ * @brief Print out logs
+ * @details Make sure the reader is up to date on printed logs
+ * @param[in] reader The reader to read the data
+ * @param[in] _time Unused timestamps
+ * @return 0 if data remains for the next iteration, 1 if the buffer is to be removed, else -1
+ */
+int print_out_logs(struct reader_pipe *reader, struct now_t _time)
+{
+ assert(reader);
+
+ assert(reader->buf_ptr);
+
+ if (reader->partial_log_size) {
+ int r = write(reader->common.fd_entity_sink.fd, reader->partial_log, reader->partial_log_size);
+ if (r <= 0)
+ return r != 0 && errno != EAGAIN;
+
+ if (r < reader->partial_log_size) {
+ reader->partial_log_size -= r;
+ memmove(reader->partial_log, reader->partial_log + r, reader->partial_log_size);
+ return 0;
+ }
+
+ reader->partial_log_size = 0;
+ }
+
+ while (log_storage_reader_is_new_entry_available(reader->log_storage_reader_ptr)) {
+ const dlogutil_entry_s* ple = (const dlogutil_entry_s *)log_storage_reader_get_new_entry(reader->log_storage_reader_ptr);
+
+ assert(ple);
+
+ switch (reader_print_out_single_log(reader, ple)) {
+ case 0: /* nothing more to do, let's do next loop */
+ break;
+
+ case 1: /* error after which we need to end the reader */
+ return 1;
+
+ default: /* writing error, bounce out */
+ return -1;
+ }
+ }
+
+ return reader->is_dumping ? 1 : -1;
+}
+
--- /dev/null
+#pragma once
+
+#include "logger_internal.h" // for struct reader
+
+struct reader_pipe {
+ struct log_buffer *buf_ptr;
+ log_storage_reader *log_storage_reader_ptr;
+ struct timespec last_read_time;
+ int partial_log_size;
+ char partial_log[sizeof(struct dlogutil_entry_with_msg)];
+ struct log_file file;
+ bool is_dumping;
+ bool monitor;
+ dlogutil_filter_options_s *filter;
+ struct reader common;
+};
+
+int reader_pipe_init(struct reader_pipe **reader, log_id_t buf_id, struct logger *server,
+ dlogutil_filter_options_s *filter, struct log_file *file, bool monitor, bool is_dumping);
+int reader_pipe_init_with_writer(struct reader_pipe **reader, struct writer *writer, struct logger *server,
+ dlogutil_filter_options_s *filter, struct log_file *file, bool monitor, bool is_dumping);
+int reader_should_buffer(struct reader_pipe *reader, const struct buf_params *buf_params, struct timespec now);
+int reader_print_out_single_log(struct reader_pipe *reader, const dlogutil_entry_s *dlogutil_entry);
+int print_out_logs(struct reader_pipe *reader, struct now_t _time);
+void reader_pipe_free(struct reader_pipe *reader);
+void reader_pipe_cleanup(struct reader_pipe *const *ptr);
+
+#ifdef UNIT_TEST
+uint64_t reader_buffered_space(const struct reader_pipe *reader);
+int reader_is_bufferable(const struct reader_pipe *reader);
+int reader_ms_since(const struct reader_pipe *reader, struct timespec *ts);
+#endif
#include <sd-daemon.h>
#include "../logger/logger_internal.h"
#include "../logger/log_storage.h"
+#include "../logger/reader_pipe.h"
int parse_permissions(const char *str);
int usergr2id(const char *user, const char *group, uid_t *uid, gid_t *gid);
void dispatch_event_sock(struct logger *server, struct epoll_event *event, void *userdata);
void socket_close(struct sock_data *sock);
uint64_t reader_buffered_space(const struct reader_pipe *reader);
-int reader_is_bufferable(const struct reader_pipe *reader);
-int reader_ms_since(const struct reader_pipe *reader, struct timespec *ts);
-int reader_should_buffer(struct reader_pipe *reader, const struct buf_params *buf_params, struct timespec now);
void reader_pipe_free(struct reader_pipe *reader);
int buffer_append(const dlogutil_entry_s *entry, struct log_buffer *b);
int print_out_logs(struct reader_pipe *reader, struct now_t time);