如何将linux系统日志映射到C中的printf



我的桌面上运行着一个linux应用程序,我想将syslog()调用重定向到printf()调用。

注意:我不想替换调用,只是重定向

所以我写了一些代码来做到这一点:

#ifndef EMBED
#define syslog(level, stuff) printf("SYSLOG: %sn", stuff)
#endif

在我使用它的一个文件中效果很好。我把它移到一个新文件中,得到了一个错误:

error: macro "syslog" passed 3 arguments, but takes just 2

我知道这个错误是因为新文件中的调用是混合的,有些对syslog使用了2个参数,有些使用了3个参数。我也知道我需要通过变量参数列表以某种方式重定向,但我到底该怎么做呢?我还没开始工作。。。

据我所知,syslog()和printf()应该是:

void syslog(int priority, const char *format, ...)
int printf(const char *format, ...)

所以我尝试了:

#define ERR 3
#ifndef EMBED         // This is not defined in my env, btw
#define syslog(pri, fmt, ...) printf(fmt, ...)
#endif
...
void main() {
...
syslog(ERR, "test");

但这给出了一个错误:

error: expected expression before ‘...’ token

关于此宏的外观/使用方式的建议?

GCC在这一领域有一个扩展,但最便携的处理方式是:

#define syslog(priority, ...)    printf(__VA_ARGS__)

优先级是强制性的,但被宏扩展忽略。其余参数(强制格式加上可选的后续参数)在printf()的参数列表中使用的__VA_ARGS__中。无论格式字符串是常量(文字)还是变量,都可以。


如果您想将输出标记为syslog()的代理,我会调用printf()以外的函数来完成这项工作:

#define syslog(priority, ...) syslog_print(__VA_ARGS__)

甚至

#define syslog(priority, ...) syslog_print(__FILE__, __LINE__, __func__, __VA_ARGS__)

这些将被宣布为:

extern void syslog_printf(const char *fmt, ...);

或:

extern void syslog_printf(const char *file, int line, const char *func,
                          const char *fmt, ...);

该实现是<stdarg.h>中的宏加上v*printf()函数的直接应用:

void syslog_printf(const char *file, int line, const char *func,
                   const char *fmt, ...)
{
    va_list args;
    printf("SYSLOG:%s:%d:%s: ", file, line, func);
    va_start(args, fmt);
    vprintf(fmt, args);
    va_end(args);
}

你可以添加时间戳和其他你喜欢的东西;您还可以很容易地将输出安排为文件,而不是标准输出;您也可以安排在函数中打开或关闭它。所以,平均来说,我会用一个代理来代替syslog(),它允许您调整代码使用这些工具。

事实上,由于您已经发现了更改日志行为的要求,我建议您不要在代码中直接使用syslog(),而应该在代码中使用自己的函数(例如,syslog_printf(),但可能使用不同的名称),并提供该函数的各种实现。这样做的唯一缺点是调用真正的syslog()现在更难了——没有vsyslog()AFAIK。因此,对syslog()的基本调用将通过使用vsnprintf()格式化syslog_printf()中的字符串(或者vasprintf(),如果这对您来说是可用的,并且内存耗尽不是一个可能的问题),然后使用预格式化的字符串(syslog(priority, "%s", buffer);)调用syslog()来完成。当然,您还希望将优先级传递给代理函数,以便中继到syslog()

fmt字符串应包含其自己的格式说明符,这些说明符由可变参数填充。首先,您可以简单地忽略实际参数,只打印格式化字符串。你需要一个可变宏:

#define syslog(level, fmt, ...) printf("SYSLOG: %sn", fmt)

其次,如果你愿意冒巨大的风险,并期望用户将格式化字符串作为文本而不是变量提供,你可以连接你自己的字符串:

#define syslog(level, fmt, ...) printf("SYSLOG[%d] " fmt, level, ##__VA_ARGS__)

这对syslog(1, "Hello");有效,但对syslog(1, str);无效。

如果你不想依赖可变宏(C99功能),你也可以这样做:

#define syslog my_syslog
static inline int my_syslog(int prio, const char *fmt, ...)
{
    int r;
    va_list ap;
    va_start(ap, fmt);
    r = vprintf(fmt, ap);
    va_end(ap);
    return r;
}

或类似的。

最新更新