mirror of
https://git.proxmox.com/git/mirror_lxc
synced 2025-08-14 13:31:27 +00:00
lxc: introduce log4c style logging
lxc_log_init() should be called in each main() of a command to define the default log priority and log file. Signed-off-by: Cedric Le Goater <legoater@free.fr> Acked-by: Daniel Lezcano <dlezcano@fr.ibm.com> Signed-off-by: Daniel Lezcano <dlezcano@fr.ibm.com>
This commit is contained in:
parent
a57cf79e58
commit
cb8c5720bd
130
src/lxc/log.c
130
src/lxc/log.c
@ -1,9 +1,133 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdarg.h>
|
#include <limits.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define __USE_GNU /* for *_CLOEXEC */
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <lxc/log.h>
|
||||||
|
|
||||||
|
#define LXC_LOG_PREFIX_SIZE 32
|
||||||
|
#define LXC_LOG_BUFFER_SIZE 512
|
||||||
|
|
||||||
|
int lxc_log_fd = 2;
|
||||||
|
|
||||||
|
static char log_prefix[LXC_LOG_PREFIX_SIZE] = "lxc";
|
||||||
|
|
||||||
|
lxc_log_define(lxc_log, lxc);
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static int log_append_logfile(const struct lxc_log_appender *appender,
|
||||||
|
const struct lxc_log_event *event)
|
||||||
|
{
|
||||||
|
char buffer[LXC_LOG_BUFFER_SIZE];
|
||||||
|
int n;
|
||||||
|
|
||||||
|
if (lxc_log_fd == -1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
n = snprintf(buffer, sizeof(buffer),
|
||||||
|
"%15s %10ld.%03ld %-8s %s - ",
|
||||||
|
log_prefix,
|
||||||
|
event->timestamp.tv_sec,
|
||||||
|
event->timestamp.tv_usec / 1000,
|
||||||
|
lxc_log_priority_to_string(event->priority),
|
||||||
|
event->category);
|
||||||
|
|
||||||
|
n += vsnprintf(buffer + n, sizeof(buffer) - n, event->fmt,
|
||||||
|
event->va);
|
||||||
|
|
||||||
|
if (n >= sizeof(buffer) - 1) {
|
||||||
|
WARN("truncated next event from %d to %d bytes", n,
|
||||||
|
sizeof(buffer));
|
||||||
|
n = sizeof(buffer) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[n] = '\n';
|
||||||
|
|
||||||
|
return write(lxc_log_fd, buffer, n + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct lxc_log_appender log_appender_logfile = {
|
||||||
|
.name = "logfile",
|
||||||
|
.append = log_append_logfile,
|
||||||
|
.next = NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct lxc_log_category log_root = {
|
||||||
|
.name = "root",
|
||||||
|
.priority = LXC_LOG_PRIORITY_ERROR,
|
||||||
|
.appender = NULL,
|
||||||
|
.parent = NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct lxc_log_category lxc_log_category_lxc = {
|
||||||
|
.name = "lxc",
|
||||||
|
.priority = LXC_LOG_PRIORITY_ERROR,
|
||||||
|
.appender = &log_appender_logfile,
|
||||||
|
.parent = &log_root
|
||||||
|
};
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
extern void lxc_log_setprefix(const char *prefix)
|
||||||
|
{
|
||||||
|
strncpy(log_prefix, prefix, sizeof(log_prefix));
|
||||||
|
log_prefix[sizeof(log_prefix) - 1] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
static int log_open(const char *name)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
int newfd;
|
||||||
|
|
||||||
|
fd = open(name, O_CREAT | O_WRONLY | O_APPEND | O_CLOEXEC, 0666);
|
||||||
|
if (fd == -1) {
|
||||||
|
ERROR("failed to open log file \"%s\" : %s", name,
|
||||||
|
strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fd > 2)
|
||||||
|
return fd;
|
||||||
|
|
||||||
|
newfd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
|
||||||
|
if (newfd == -1)
|
||||||
|
ERROR("failed to dup log fd %d : %s", fd, strerror(errno));
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
return newfd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
extern int lxc_log_init(const char *file, int priority, const char *prefix)
|
||||||
|
{
|
||||||
|
lxc_log_category_lxc.priority = priority;
|
||||||
|
|
||||||
|
if (prefix)
|
||||||
|
lxc_log_setprefix(prefix);
|
||||||
|
|
||||||
|
if (file) {
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = log_open(file);
|
||||||
|
if (fd == -1) {
|
||||||
|
ERROR("failed to initialize log service");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
lxc_log_fd = fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#include <log.h>
|
|
||||||
|
|
||||||
#define MAXTIMELEN 47;
|
#define MAXTIMELEN 47;
|
||||||
#define ERRNO_FORMAT "%d (%s)"
|
#define ERRNO_FORMAT "%d (%s)"
|
||||||
|
|
||||||
|
244
src/lxc/log.h
244
src/lxc/log.h
@ -1,6 +1,250 @@
|
|||||||
#ifndef _log_h
|
#ifndef _log_h
|
||||||
#define _log_h
|
#define _log_h
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* predefined priorities. */
|
||||||
|
enum {
|
||||||
|
LXC_LOG_PRIORITY_TRACE,
|
||||||
|
LXC_LOG_PRIORITY_DEBUG,
|
||||||
|
LXC_LOG_PRIORITY_INFO,
|
||||||
|
LXC_LOG_PRIORITY_NOTICE,
|
||||||
|
LXC_LOG_PRIORITY_WARN,
|
||||||
|
LXC_LOG_PRIORITY_ERROR,
|
||||||
|
LXC_LOG_PRIORITY_CRIT,
|
||||||
|
LXC_LOG_PRIORITY_ALERT,
|
||||||
|
LXC_LOG_PRIORITY_FATAL,
|
||||||
|
LXC_LOG_PRIORITY_NOTSET,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* location information of the logging event */
|
||||||
|
struct lxc_log_locinfo {
|
||||||
|
const char *file;
|
||||||
|
const char *func;
|
||||||
|
int line;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define LXC_LOG_LOCINFO_INIT \
|
||||||
|
{ .file = __FILE__, .func = __func__, .line = __LINE__ }
|
||||||
|
|
||||||
|
/* brief logging event object */
|
||||||
|
struct lxc_log_event {
|
||||||
|
const char* category;
|
||||||
|
int priority;
|
||||||
|
struct timeval timestamp;
|
||||||
|
struct lxc_log_locinfo *locinfo;
|
||||||
|
const char *fmt;
|
||||||
|
va_list va;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* log appender object */
|
||||||
|
struct lxc_log_appender {
|
||||||
|
const char* name;
|
||||||
|
int (*append)(const struct lxc_log_appender *,
|
||||||
|
const struct lxc_log_event *);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* appenders can be stacked
|
||||||
|
*/
|
||||||
|
struct lxc_log_appender *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* log category object */
|
||||||
|
struct lxc_log_category {
|
||||||
|
const char *name;
|
||||||
|
int priority;
|
||||||
|
struct lxc_log_appender *appender;
|
||||||
|
const struct lxc_log_category *parent;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns true if the chained priority is equal to or higher than
|
||||||
|
* given priority.
|
||||||
|
*/
|
||||||
|
static inline int
|
||||||
|
lxc_log_priority_is_enabled(const struct lxc_log_category* category,
|
||||||
|
int priority)
|
||||||
|
{
|
||||||
|
while (category->priority == LXC_LOG_PRIORITY_NOTSET &&
|
||||||
|
category->parent)
|
||||||
|
category = category->parent;
|
||||||
|
|
||||||
|
return priority >= category->priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* converts a priority to a literal string
|
||||||
|
*/
|
||||||
|
static inline const char* lxc_log_priority_to_string(int priority)
|
||||||
|
{
|
||||||
|
switch (priority) {
|
||||||
|
case LXC_LOG_PRIORITY_TRACE: return "TRACE";
|
||||||
|
case LXC_LOG_PRIORITY_DEBUG: return "DEBUG";
|
||||||
|
case LXC_LOG_PRIORITY_INFO: return "INFO";
|
||||||
|
case LXC_LOG_PRIORITY_NOTICE: return "NOTICE";
|
||||||
|
case LXC_LOG_PRIORITY_WARN: return "WARN";
|
||||||
|
case LXC_LOG_PRIORITY_ERROR: return "ERROR";
|
||||||
|
case LXC_LOG_PRIORITY_CRIT: return "CRIT";
|
||||||
|
case LXC_LOG_PRIORITY_ALERT: return "ALERT";
|
||||||
|
case LXC_LOG_PRIORITY_FATAL: return "FATAL";
|
||||||
|
default:
|
||||||
|
return "NOTSET";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* converts a literal priority to an int
|
||||||
|
*/
|
||||||
|
static inline int lxc_log_priority_to_int(const char* name)
|
||||||
|
{
|
||||||
|
if (!strcasecmp("TRACE", name)) return LXC_LOG_PRIORITY_TRACE;
|
||||||
|
if (!strcasecmp("DEBUG", name)) return LXC_LOG_PRIORITY_DEBUG;
|
||||||
|
if (!strcasecmp("INFO", name)) return LXC_LOG_PRIORITY_INFO;
|
||||||
|
if (!strcasecmp("NOTICE", name)) return LXC_LOG_PRIORITY_NOTICE;
|
||||||
|
if (!strcasecmp("WARN", name)) return LXC_LOG_PRIORITY_WARN;
|
||||||
|
if (!strcasecmp("ERROR", name)) return LXC_LOG_PRIORITY_ERROR;
|
||||||
|
if (!strcasecmp("CRIT", name)) return LXC_LOG_PRIORITY_CRIT;
|
||||||
|
if (!strcasecmp("ALERT", name)) return LXC_LOG_PRIORITY_ALERT;
|
||||||
|
if (!strcasecmp("FATAL", name)) return LXC_LOG_PRIORITY_FATAL;
|
||||||
|
|
||||||
|
return LXC_LOG_PRIORITY_NOTSET;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
__lxc_log_append(const struct lxc_log_appender *appender,
|
||||||
|
const struct lxc_log_event* event)
|
||||||
|
{
|
||||||
|
while (appender) {
|
||||||
|
appender->append(appender, event);
|
||||||
|
appender = appender->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
__lxc_log(const struct lxc_log_category* category,
|
||||||
|
const struct lxc_log_event* event)
|
||||||
|
{
|
||||||
|
while (category) {
|
||||||
|
__lxc_log_append(category->appender, event);
|
||||||
|
category = category->parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Helper macro to define log fonctions.
|
||||||
|
*/
|
||||||
|
#define lxc_log_priority_define(acategory, PRIORITY) \
|
||||||
|
\
|
||||||
|
static inline void LXC_##PRIORITY(struct lxc_log_locinfo *, \
|
||||||
|
const char *, ...) __attribute__ ((format (printf, 2, 3))); \
|
||||||
|
\
|
||||||
|
static inline void LXC_##PRIORITY(struct lxc_log_locinfo* locinfo, \
|
||||||
|
const char* format, ...) \
|
||||||
|
{ \
|
||||||
|
if (lxc_log_priority_is_enabled(acategory, \
|
||||||
|
LXC_LOG_PRIORITY_##PRIORITY)) { \
|
||||||
|
struct lxc_log_event evt = { \
|
||||||
|
.category = (acategory)->name, \
|
||||||
|
.priority = LXC_LOG_PRIORITY_##PRIORITY, \
|
||||||
|
.fmt = format, \
|
||||||
|
.locinfo = locinfo \
|
||||||
|
}; \
|
||||||
|
\
|
||||||
|
gettimeofday(&evt.timestamp, NULL); \
|
||||||
|
\
|
||||||
|
va_start(evt.va, format); \
|
||||||
|
__lxc_log(acategory, &evt); \
|
||||||
|
va_end(evt.va); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Helper macro to define and use static categories.
|
||||||
|
*/
|
||||||
|
#define lxc_log_category_define(name, parent) \
|
||||||
|
extern struct lxc_log_category lxc_log_category_##parent; \
|
||||||
|
struct lxc_log_category lxc_log_category_##name = { \
|
||||||
|
#name, \
|
||||||
|
LXC_LOG_PRIORITY_NOTSET, \
|
||||||
|
NULL, \
|
||||||
|
&lxc_log_category_##parent \
|
||||||
|
};
|
||||||
|
|
||||||
|
#define lxc_log_define(name, parent) \
|
||||||
|
lxc_log_category_define(name, parent) \
|
||||||
|
\
|
||||||
|
lxc_log_priority_define(&lxc_log_category_##name, TRACE) \
|
||||||
|
lxc_log_priority_define(&lxc_log_category_##name, DEBUG) \
|
||||||
|
lxc_log_priority_define(&lxc_log_category_##name, INFO) \
|
||||||
|
lxc_log_priority_define(&lxc_log_category_##name, NOTICE) \
|
||||||
|
lxc_log_priority_define(&lxc_log_category_##name, WARN) \
|
||||||
|
lxc_log_priority_define(&lxc_log_category_##name, ERROR) \
|
||||||
|
lxc_log_priority_define(&lxc_log_category_##name, CRIT) \
|
||||||
|
lxc_log_priority_define(&lxc_log_category_##name, ALERT) \
|
||||||
|
lxc_log_priority_define(&lxc_log_category_##name, FATAL)
|
||||||
|
|
||||||
|
#define lxc_log_category_priority(name) \
|
||||||
|
(lxc_log_priority_to_string(lxc_log_category_##name.priority))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* top categories
|
||||||
|
*/
|
||||||
|
extern struct lxc_log_category lxc_log_category_lxc;
|
||||||
|
|
||||||
|
#define TRACE(format, ...) do { \
|
||||||
|
struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT; \
|
||||||
|
LXC_TRACE(&locinfo, format, ##__VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define DEBUG(format, ...) do { \
|
||||||
|
struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT; \
|
||||||
|
LXC_DEBUG(&locinfo, format, ##__VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define INFO(format, ...) do { \
|
||||||
|
struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT; \
|
||||||
|
LXC_INFO(&locinfo, format, ##__VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define NOTICE(format, ...) do { \
|
||||||
|
struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT; \
|
||||||
|
LXC_NOTICE(&locinfo, format, ##__VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define WARN(format, ...) do { \
|
||||||
|
struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT; \
|
||||||
|
LXC_WARN(&locinfo, format, ##__VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define ERROR(format, ...) do { \
|
||||||
|
struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT; \
|
||||||
|
LXC_ERROR(&locinfo, format, ##__VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define CRIT(format, ...) do { \
|
||||||
|
struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT; \
|
||||||
|
LXC_CRIT(&locinfo, format, ##__VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define ALERT(format, ...) do { \
|
||||||
|
struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT; \
|
||||||
|
LXC_ALERT(&locinfo, format, ##__VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define FATAL(format, ...) do { \
|
||||||
|
struct lxc_log_locinfo locinfo = LXC_LOG_LOCINFO_INIT; \
|
||||||
|
LXC_FATAL(&locinfo, format, ##__VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define SYSERROR(format, ...) do { \
|
||||||
|
ERROR("%s - " format "\n", strerror(errno), ##__VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
#define lxc_log(format, level, ...) do { \
|
#define lxc_log(format, level, ...) do { \
|
||||||
fprintf(stderr, "[%s] \t%s:%d - " format "\n", \
|
fprintf(stderr, "[%s] \t%s:%d - " format "\n", \
|
||||||
level, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
|
level, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
|
||||||
|
Loading…
Reference in New Issue
Block a user