#define _GNU_SOURCE #include #include #include #include #include #include "log.h" #include "getenv.h" static const char *level_str[] = { "panic", "fatal", "error", "warning", "info", "debug", "trace" }; int logfd = -1; static int loglevel = DEBUG; extern char *escape_json_string(char *str); void setup_logpipe(void) { int i; i = getenv_int("_LIBCONTAINER_LOGPIPE"); if (i < 0) { /* We are not runc init, or log pipe was not provided. */ return; } logfd = i; i = getenv_int("_LIBCONTAINER_LOGLEVEL"); if (i < 0) return; loglevel = i; } bool log_enabled_for(int level) { return (logfd >= 0 && level <= loglevel); } /* Defined in nsexec.c */ extern int current_stage; void write_log(int level, const char *format, ...) { char *message = NULL, *stage = NULL, *json = NULL; va_list args; int ret; if (!log_enabled_for(level)) return; va_start(args, format); ret = vasprintf(&message, format, args); va_end(args); if (ret < 0) { message = NULL; goto out; } message = escape_json_string(message); if (current_stage < 0) { stage = strdup("nsexec"); if (stage == NULL) goto out; } else { ret = asprintf(&stage, "nsexec-%d", current_stage); if (ret < 0) { stage = NULL; goto out; } } ret = asprintf(&json, "{\"level\":\"%s\", \"msg\": \"%s[%d]: %s\"}\n", level_str[level], stage, getpid(), message); if (ret < 0) { json = NULL; goto out; } /* This logging is on a best-effort basis. In case of a short or failed * write there is nothing we can do, so just ignore write() errors. */ ssize_t __attribute__((unused)) __res = write(logfd, json, ret); out: free(message); free(stage); free(json); }