mirror of https://github.com/containers/conmon.git
logging: Add container labels to log entries on journald
At present it's not possible to ship properly labeled logs when using podman and tools like podman-compose. Container labels are lost which makes it much harder to understand where a particular log line originated from. Log processing and analysis is significantly more inconvenient as well, because it's hard to group related logs, e.g. coming from the same compose project. This commit implements the parts necessary to annotate log messages with container labels. Each label and value pair is specified via --log-label LABEL=VALUE arguments. Co-authored-by: OZoneGuy <oalkersh@protonmail.com> Signed-off-by: Povilas Kanapickas <povilas@radix.lt>
This commit is contained in:
parent
de270e6eb9
commit
f37e9e795c
|
|
@ -69,6 +69,10 @@ Maximum size of the log file (in bytes).
|
|||
**--log-tag**
|
||||
Additional tag to use for logging.
|
||||
|
||||
**--log-label**
|
||||
Additional label to use for logging. The accepted format is LABEL=VALUE. Can be specified multiple times.
|
||||
Note that LABEL must contain only uppercase letters, numbers and underscore character.
|
||||
|
||||
**-n**, **--name**
|
||||
Container name.
|
||||
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ int opt_exit_delay = 0;
|
|||
gboolean opt_replace_listen_pid = FALSE;
|
||||
char *opt_log_level = NULL;
|
||||
char *opt_log_tag = NULL;
|
||||
gchar **opt_log_labels = NULL;
|
||||
gboolean opt_sync = FALSE;
|
||||
gboolean opt_no_sync_log = FALSE;
|
||||
char *opt_sdnotify_socket = NULL;
|
||||
|
|
@ -78,6 +79,8 @@ GOptionEntry opt_entries[] = {
|
|||
{"log-size-max", 0, 0, G_OPTION_ARG_INT64, &opt_log_size_max, "Maximum size of log file", NULL},
|
||||
{"log-global-size-max", 0, 0, G_OPTION_ARG_INT64, &opt_log_global_size_max, "Maximum size of all log files", NULL},
|
||||
{"log-tag", 0, 0, G_OPTION_ARG_STRING, &opt_log_tag, "Additional tag to use for logging", NULL},
|
||||
{"log-label", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_log_labels,
|
||||
"Additional label to include in logs. Can be specified multiple times", NULL},
|
||||
{"name", 'n', 0, G_OPTION_ARG_STRING, &opt_name, "Container name", NULL},
|
||||
{"no-new-keyring", 0, 0, G_OPTION_ARG_NONE, &opt_no_new_keyring, "Do not create a new session keyring for the container", NULL},
|
||||
{"no-pivot", 0, 0, G_OPTION_ARG_NONE, &opt_no_pivot, "Do not use pivot_root", NULL},
|
||||
|
|
@ -194,5 +197,5 @@ void process_cli()
|
|||
if (opt_container_pid_file == NULL)
|
||||
opt_container_pid_file = g_strdup_printf("%s/pidfile-%s", cwd, opt_cid);
|
||||
|
||||
configure_log_drivers(opt_log_path, opt_log_size_max, opt_log_global_size_max, opt_cid, opt_name, opt_log_tag);
|
||||
configure_log_drivers(opt_log_path, opt_log_size_max, opt_log_global_size_max, opt_cid, opt_name, opt_log_tag, opt_log_labels);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#include "ctr_logging.h"
|
||||
#include "cli.h"
|
||||
#include "config.h"
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
|
|
@ -70,6 +71,7 @@ static char *container_id_full = NULL;
|
|||
static char *container_id = NULL;
|
||||
static char *container_name = NULL;
|
||||
static char *container_tag = NULL;
|
||||
static gchar **container_labels = NULL;
|
||||
static size_t container_tag_len;
|
||||
static char *syslog_identifier = NULL;
|
||||
static size_t syslog_identifier_len;
|
||||
|
|
@ -96,13 +98,43 @@ gboolean logging_is_passthrough(void)
|
|||
return use_logging_passthrough;
|
||||
}
|
||||
|
||||
static int count_chars_in_string(const char *str, char ch)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
while (str) {
|
||||
str = strchr(str, ch);
|
||||
if (str == NULL)
|
||||
break;
|
||||
count++;
|
||||
str++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int is_valid_label_name(const char *str)
|
||||
{
|
||||
while (*str) {
|
||||
if (*str == '=') {
|
||||
return 1;
|
||||
}
|
||||
if (!isupper(*str) && !isdigit(*str) && *str != '_') {
|
||||
return 0;
|
||||
}
|
||||
str++;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* configures container log specific information, such as the drivers the user
|
||||
* called with and the max log size for log file types. For the log file types
|
||||
* (currently just k8s log file), it will also open the log_fd for that specific
|
||||
* log file.
|
||||
*/
|
||||
void configure_log_drivers(gchar **log_drivers, int64_t log_size_max_, int64_t log_global_size_max_, char *cuuid_, char *name_, char *tag)
|
||||
void configure_log_drivers(gchar **log_drivers, int64_t log_size_max_, int64_t log_global_size_max_, char *cuuid_, char *name_, char *tag,
|
||||
gchar **log_labels)
|
||||
{
|
||||
log_size_max = log_size_max_;
|
||||
log_global_size_max = log_global_size_max_;
|
||||
|
|
@ -126,8 +158,14 @@ void configure_log_drivers(gchar **log_drivers, int64_t log_size_max_, int64_t l
|
|||
}
|
||||
k8s_total_bytes_written = k8s_bytes_written;
|
||||
|
||||
if (!use_journald_logging && tag)
|
||||
nexit("k8s-file doesn't support --log-tag");
|
||||
if (!use_journald_logging) {
|
||||
if (!tag) {
|
||||
nexit("k8s-file doesn't support --log-tag");
|
||||
}
|
||||
if (!log_labels) {
|
||||
nexit("k8s-file doesn't support --log-label");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (use_journald_logging) {
|
||||
|
|
@ -169,6 +207,24 @@ void configure_log_drivers(gchar **log_drivers, int64_t log_size_max_, int64_t l
|
|||
syslog_identifier = g_strdup_printf("SYSLOG_IDENTIFIER=%s", tag);
|
||||
syslog_identifier_len = strlen(syslog_identifier);
|
||||
}
|
||||
if (log_labels) {
|
||||
container_labels = log_labels;
|
||||
|
||||
/* Ensure that valid LABEL=VALUE pairs have been passed */
|
||||
for (char **ptr = log_labels; *ptr; ptr++) {
|
||||
if (**ptr == '=') {
|
||||
nexitf("Container labels must be in format LABEL=VALUE (no LABEL present in '%s')", *ptr);
|
||||
}
|
||||
if (count_chars_in_string(*ptr, '=') != 1) {
|
||||
nexitf("Container labels must be in format LABEL=VALUE (none or more than one '=' present in '%s')",
|
||||
*ptr);
|
||||
}
|
||||
if (!is_valid_label_name(*ptr)) {
|
||||
nexitf("Container label names must contain only uppercase letters, numbers and underscore (in '%s')",
|
||||
*ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -325,6 +381,12 @@ static int write_journald(int pipe, char *buf, ssize_t buflen)
|
|||
/* per docker journald logging format, CONTAINER_PARTIAL_MESSAGE is set to true if it's partial, but otherwise not set. */
|
||||
if (partial && writev_buffer_append_segment_no_flush(&bufv, "CONTAINER_PARTIAL_MESSAGE=true", PARTIAL_MESSAGE_EQ_LEN) < 0)
|
||||
return -1;
|
||||
if (container_labels) {
|
||||
for (gchar **label = container_labels; *label; ++label) {
|
||||
if (writev_buffer_append_segment_no_flush(&bufv, *label, strlen(*label)) < 0)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int err = sd_journal_sendv(bufv.iov, bufv.iovcnt);
|
||||
if (err < 0) {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@
|
|||
|
||||
void reopen_log_files(void);
|
||||
bool write_to_logs(stdpipe_t pipe, char *buf, ssize_t num_read);
|
||||
void configure_log_drivers(gchar **log_drivers, int64_t log_size_max_, int64_t log_global_size_max_, char *cuuid_, char *name_, char *tag);
|
||||
void configure_log_drivers(gchar **log_drivers, int64_t log_size_max_, int64_t log_global_size_max_, char *cuuid_, char *name_, char *tag,
|
||||
gchar **labels);
|
||||
void sync_logs(void);
|
||||
gboolean logging_is_passthrough(void);
|
||||
void close_logging_fds(void);
|
||||
|
|
|
|||
Loading…
Reference in New Issue