From: Michael Tremer Date: Sat, 5 Oct 2024 13:29:42 +0000 (+0000) Subject: logging: Add a simple ring buffer for buffering log lines X-Git-Tag: 0.9.30~1162 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=2da00c93b814e2be31f1d6bb1614a37ce40027fa;p=pakfire.git logging: Add a simple ring buffer for buffering log lines Signed-off-by: Michael Tremer --- diff --git a/Makefile.am b/Makefile.am index 54cd4a97e..4ed9b788f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -234,6 +234,7 @@ libpakfire_la_SOURCES = \ src/libpakfire/job.c \ src/libpakfire/key.c \ src/libpakfire/linter.c \ + src/libpakfire/log_buffer.c \ src/libpakfire/logging.c \ src/libpakfire/mirror.c \ src/libpakfire/mirrorlist.c \ @@ -283,6 +284,7 @@ pkginclude_HEADERS += \ src/libpakfire/include/pakfire/job.h \ src/libpakfire/include/pakfire/key.h \ src/libpakfire/include/pakfire/linter.h \ + src/libpakfire/include/pakfire/log_buffer.h \ src/libpakfire/include/pakfire/logging.h \ src/libpakfire/include/pakfire/mirror.h \ src/libpakfire/include/pakfire/mirrorlist.h \ diff --git a/src/libpakfire/include/pakfire/log_buffer.h b/src/libpakfire/include/pakfire/log_buffer.h new file mode 100644 index 000000000..1480f7bee --- /dev/null +++ b/src/libpakfire/include/pakfire/log_buffer.h @@ -0,0 +1,42 @@ +/*############################################################################# +# # +# Pakfire - The IPFire package management system # +# Copyright (C) 2024 Pakfire development team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +#############################################################################*/ + +#ifndef PAKFIRE_LOG_BUFFER_H +#define PAKFIRE_LOG_BUFFER_H + +#ifdef PAKFIRE_PRIVATE + +#include + +/* + Ring buffer for log messages +*/ + +struct pakfire_log_buffer; + +int pakfire_log_buffer_create(struct pakfire_log_buffer** buffer, struct pakfire_ctx* ctx, size_t size); +struct pakfire_log_buffer* pakfire_log_buffer_ref(struct pakfire_log_buffer* buffer); +struct pakfire_log_buffer* pakfire_log_buffer_unref(struct pakfire_log_buffer* buffer); + +int pakfire_log_buffer_enqueue(struct pakfire_log_buffer* buffer, int priority, const char* line, ssize_t length); +int pakfire_log_buffer_dequeue(struct pakfire_log_buffer* buffer, int* priority, char** line, size_t* length); + +#endif /* PAKFIRE_PRIVATE */ +#endif /* PAKFIRE_LOG_BUFFER_H */ diff --git a/src/libpakfire/log_buffer.c b/src/libpakfire/log_buffer.c new file mode 100644 index 000000000..c525904c1 --- /dev/null +++ b/src/libpakfire/log_buffer.c @@ -0,0 +1,180 @@ +/*############################################################################# +# # +# Pakfire - The IPFire package management system # +# Copyright (C) 2024 Pakfire development team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +#############################################################################*/ + +#include +#include +#include + +#include +#include + +struct pakfire_log_line { + STAILQ_ENTRY(pakfire_log_line) nodes; + + int priority; + char* line; + size_t length; +}; + +struct pakfire_log_buffer { + struct pakfire_ctx* ctx; + int nrefs; + + STAILQ_HEAD(lines, pakfire_log_line) lines; + + size_t max_length; +}; + +static void pakfire_log_line_free(struct pakfire_log_line* line) { + if (line->line) + free(line->line); + free(line); +} + +static void pakfire_log_buffer_free(struct pakfire_log_buffer* buffer) { + if (buffer->ctx) + pakfire_ctx_unref(buffer->ctx); + + free(buffer); +} + +int pakfire_log_buffer_create(struct pakfire_log_buffer** buffer, struct pakfire_ctx* ctx, size_t max_length) { + struct pakfire_log_buffer* b = NULL; + + // Allocate a new object + b = calloc(1, sizeof(*b)); + if (!b) + return -errno; + + // Initialize the reference counter + b->nrefs = 1; + + // Store a reference to the context + b->ctx = pakfire_ctx_ref(ctx); + + // Store the maximum length + b->max_length = max_length; + + // Initialize lines + STAILQ_INIT(&b->lines); + + // Return the pointer + *buffer = b; + + return 0; +} + +struct pakfire_log_buffer* pakfire_log_buffer_ref(struct pakfire_log_buffer* buffer) { + ++buffer->nrefs; + + return buffer; +} + +struct pakfire_log_buffer* pakfire_log_buffer_unref(struct pakfire_log_buffer* buffer) { + if (--buffer->nrefs > 0) + return buffer; + + pakfire_log_buffer_free(buffer); + return NULL; +} + +static size_t pakfire_log_buffer_length(struct pakfire_log_buffer* buffer) { + struct pakfire_log_line* line = NULL; + size_t length = 0; + + STAILQ_FOREACH(line, &buffer->lines, nodes) + length++; + + return length; +} + +int pakfire_log_buffer_enqueue(struct pakfire_log_buffer* buffer, int priority, const char* line, ssize_t length) { + struct pakfire_log_line* l = NULL; + + // Fail if the buffer is full + if (buffer->max_length > 0) { + if (pakfire_log_buffer_length(buffer) >= buffer->max_length) + return -ENOSPC; + } + + // Automatically determine the length + if (length < 0) + length = strlen(line); + + // Allocate a new line + l = calloc(1, sizeof(*l)); + if (!l) + return -errno; + + // Store the priority + l->priority = priority; + + // Store the line + l->line = strndup(line, length); + if (!l->line) + goto ERROR; + + // Store the length + l->length = length; + + // Append to the queue + STAILQ_INSERT_TAIL(&buffer->lines, l, nodes); + + return 0; + +ERROR: + if (l) + pakfire_log_line_free(l); + + return -errno; +} + +int pakfire_log_buffer_dequeue(struct pakfire_log_buffer* buffer, int* priority, char** line, size_t* length) { + struct pakfire_log_line* l = NULL; + + // Priority & Line must be set, length is optional + if (!priority || !line) + return -EINVAL; + + // Fetch the first line + l = STAILQ_FIRST(&buffer->lines); + if (!l) + return 0; + + // Return the priority + *priority = l->priority; + + // Return the line + *line = strndup(l->line, l->length); + if (!*line) + return -errno; + + // Return the length + if (length) + *length = l->length; + + // Remove the line + STAILQ_REMOVE_HEAD(&buffer->lines, nodes); + + // Free the line + pakfire_log_line_free(l); + + return 0; +}