mirror of
https://github.com/kernelkit/infix.git
synced 2026-07-22 01:13:00 +02:00
The only reliable way of getting logs from the container at all times is to let conmon be the logging agent. Unfortunately, the k8s-file format does not handle multiline output very well, which is something we often see on the stdout/stderr of containers. Therefore, add proper syslog support to conmon instead, and make sure that podman knows enough about it to pass the information along to conmon.
197 lines
5.1 KiB
Diff
197 lines
5.1 KiB
Diff
From 075fcae6b463d67149fbf2adc36c6bb423364e24 Mon Sep 17 00:00:00 2001
|
|
From: Tobias Waldekranz <tobias@waldekranz.com>
|
|
Date: Wed, 18 Dec 2024 15:08:57 +0100
|
|
Subject: [PATCH] logging: Add syslog support
|
|
Organization: Addiva Elektronik
|
|
|
|
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
|
|
---
|
|
src/ctr_logging.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++
|
|
1 file changed, 125 insertions(+)
|
|
|
|
diff --git a/src/ctr_logging.c b/src/ctr_logging.c
|
|
index e5f03f3..3bf8fc2 100644
|
|
--- a/src/ctr_logging.c
|
|
+++ b/src/ctr_logging.c
|
|
@@ -26,10 +26,12 @@ static inline int sd_journal_sendv(G_GNUC_UNUSED const struct iovec *iov, G_GNUC
|
|
static gboolean use_journald_logging = FALSE;
|
|
static gboolean use_k8s_logging = FALSE;
|
|
static gboolean use_logging_passthrough = FALSE;
|
|
+static gboolean use_logging_syslog = FALSE;
|
|
|
|
/* Value the user must input for each log driver */
|
|
static const char *const K8S_FILE_STRING = "k8s-file";
|
|
static const char *const JOURNALD_FILE_STRING = "journald";
|
|
+static const char *const SYSLOG_FILE_STRING = "syslog";
|
|
|
|
/* Max log size for any log file types */
|
|
static int64_t log_size_max = -1;
|
|
@@ -41,6 +43,9 @@ static int64_t log_global_size_max = -1;
|
|
static int k8s_log_fd = -1;
|
|
static char *k8s_log_path = NULL;
|
|
|
|
+/* syslog parameters */
|
|
+static int syslog_facility = LOG_LOCAL1;
|
|
+
|
|
/* journald log file parameters */
|
|
// short ID length
|
|
#define TRUNC_ID_LEN 12
|
|
@@ -80,6 +85,7 @@ static void parse_log_path(char *log_config);
|
|
static const char *stdpipe_name(stdpipe_t pipe);
|
|
static int write_journald(int pipe, char *buf, ssize_t num_read);
|
|
static int write_k8s_log(stdpipe_t pipe, const char *buf, ssize_t buflen);
|
|
+static int write_syslog(int pipe, char *buf, ssize_t num_read);
|
|
static bool get_line_len(ptrdiff_t *line_len, const char *buf, ssize_t buflen);
|
|
static ssize_t writev_buffer_append_segment(int fd, writev_buffer_t *buf, const void *data, ssize_t len);
|
|
static ssize_t writev_buffer_append_segment_no_flush(writev_buffer_t *buf, const void *data, ssize_t len);
|
|
@@ -158,6 +164,10 @@ void configure_log_drivers(gchar **log_drivers, int64_t log_size_max_, int64_t l
|
|
syslog_identifier_len = strlen(syslog_identifier);
|
|
}
|
|
}
|
|
+
|
|
+ if (use_logging_syslog) {
|
|
+ openlog(tag ? : (name_ ? : "conmon"), LOG_PID, syslog_facility);
|
|
+ }
|
|
}
|
|
|
|
/*
|
|
@@ -213,6 +223,11 @@ static void parse_log_path(char *log_config)
|
|
return;
|
|
}
|
|
|
|
+ if (!strcmp(driver, SYSLOG_FILE_STRING)) {
|
|
+ use_logging_syslog = TRUE;
|
|
+ return;
|
|
+ }
|
|
+
|
|
// If no : was found, use the entire log-path as a filename to k8s-file.
|
|
if (path == NULL && delim == NULL) {
|
|
use_k8s_logging = TRUE;
|
|
@@ -234,6 +249,10 @@ bool write_to_logs(stdpipe_t pipe, char *buf, ssize_t num_read)
|
|
nwarn("write_journald failed");
|
|
return G_SOURCE_CONTINUE;
|
|
}
|
|
+ if (use_logging_syslog && write_syslog(pipe, buf, num_read) < 0) {
|
|
+ nwarn("write_syslog failed");
|
|
+ return G_SOURCE_CONTINUE;
|
|
+ }
|
|
return true;
|
|
}
|
|
|
|
@@ -436,6 +455,112 @@ static int write_k8s_log(stdpipe_t pipe, const char *buf, ssize_t buflen)
|
|
return 0;
|
|
}
|
|
|
|
+struct log_buf {
|
|
+ char data[STDIO_BUF_SIZE];
|
|
+
|
|
+ FILE *put;
|
|
+ char *get;
|
|
+};
|
|
+
|
|
+static int log_buf_reset(struct log_buf *buf)
|
|
+{
|
|
+ if (buf->put) {
|
|
+ rewind(buf->put);
|
|
+ } else {
|
|
+ buf->put = fmemopen(buf->data, sizeof(buf->data) - 1, "a");
|
|
+ if (!buf->put)
|
|
+ return -1;
|
|
+
|
|
+ setbuf(buf->put, NULL);
|
|
+ }
|
|
+
|
|
+ buf->data[0] = '\0';
|
|
+ buf->get = buf->data;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static const char *log_buf_gets(struct log_buf *buf)
|
|
+{
|
|
+ char *line, *nl;
|
|
+
|
|
+ nl = strchr(buf->get, '\n');
|
|
+ if (!nl)
|
|
+ return NULL;
|
|
+
|
|
+ *nl = '\0';
|
|
+
|
|
+ line = buf->get;
|
|
+ buf->get = nl + 1;
|
|
+ return line;
|
|
+}
|
|
+
|
|
+static const char *log_buf_drain(struct log_buf *buf)
|
|
+{
|
|
+ char *text, *end;
|
|
+
|
|
+ end = buf->data + ftell(buf->put);
|
|
+ *end = '\0';
|
|
+
|
|
+ text = buf->get;
|
|
+ buf->get = end;
|
|
+ return text;
|
|
+}
|
|
+
|
|
+static int log_buf_push(struct log_buf *buf, const char *data, size_t len)
|
|
+{
|
|
+ /* If the last log_buf_gets() completely drained the buffer, we can safely reset. */
|
|
+ if (buf->get != buf->data
|
|
+ && ftell(buf->put) == (buf->data - buf->get)
|
|
+ && log_buf_reset(buf))
|
|
+ return -1;
|
|
+
|
|
+ return (fwrite(data, len, 1, buf->put) == 1) ? 0 : -1;
|
|
+}
|
|
+
|
|
+/* write to syslog(3). If the pipe is stdout, write with notice priority,
|
|
+ * otherwise, write with error priority. Partial lines (that don't end in a newline) are buffered
|
|
+ * between invocations. A 0 buflen argument forces a buffered partial line to be flushed.
|
|
+ */
|
|
+static int write_syslog(int pipe, char *buf, ssize_t buflen)
|
|
+{
|
|
+ static struct log_buf stdout = { 0 }, stderr = { 0 };
|
|
+ struct log_buf *b;
|
|
+ const char *line;
|
|
+ int prio;
|
|
+
|
|
+ switch (pipe) {
|
|
+ case STDOUT_PIPE:
|
|
+ b = &stdout;
|
|
+ prio = LOG_NOTICE;
|
|
+ break;
|
|
+ case STDERR_PIPE:
|
|
+ b = &stderr;
|
|
+ prio = LOG_ERR;
|
|
+ break;
|
|
+ default:
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if (!b->put && log_buf_reset(b))
|
|
+ return -1;
|
|
+
|
|
+ if (!buflen) {
|
|
+ line = log_buf_drain(b);
|
|
+ if (*line) {
|
|
+ syslog(prio, line);
|
|
+ return 0;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (log_buf_push(b, buf, buflen))
|
|
+ return -1;
|
|
+
|
|
+ while ((line = log_buf_gets(b))) {
|
|
+ syslog(prio, line);
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
/* Find the end of the line, or alternatively the end of the buffer.
|
|
* Returns false in the former case (it's a whole line) or true in the latter (it's a partial)
|
|
*/
|
|
--
|
|
2.43.0
|
|
|