diff --git a/docs/conmon.8.md b/docs/conmon.8.md index 2022e85..45762b0 100644 --- a/docs/conmon.8.md +++ b/docs/conmon.8.md @@ -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. diff --git a/src/cli.c b/src/cli.c index cdc57fb..949cf8f 100644 --- a/src/cli.c +++ b/src/cli.c @@ -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); } diff --git a/src/ctr_logging.c b/src/ctr_logging.c index 06266d1..465bf54 100644 --- a/src/ctr_logging.c +++ b/src/ctr_logging.c @@ -2,6 +2,7 @@ #include "ctr_logging.h" #include "cli.h" #include "config.h" +#include #include #include @@ -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) { diff --git a/src/ctr_logging.h b/src/ctr_logging.h index 315dedb..a079868 100644 --- a/src/ctr_logging.h +++ b/src/ctr_logging.h @@ -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);