How to map linux syslog to printf in C

I have a linux application running on my desk and I wanted to redirect syslog () calls to printf () calls.

Note. I don't want to replace calls, just redirect

So, I wrote the code for this:

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

Works great in a single file, where I used it. I moved this to a new file and received an error message:

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

I know that the error is due to the calls in the new file being mixed, some use 2 arguments for syslog, some use 3. I also know that I need to somehow redirect this through variable argument lists, but how exactly do I do it ? I haven't got a job yet ...

As I understand it, syslog () and printf () should be:

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

So I tried:

 #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"); 

but this gives an error:

 error: expected expression before '...' token 

Suggestions on how this macro should look / be used?

+4
source share
3 answers

GCC has an extension in this area, but the most portable way to handle it:

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

Priority is required, but is ignored by the macro extension. The remaining arguments (required format plus optional next arguments) are in __VA_ARGS__ used in the argument list, in printf() . This will be OK whether the format string is a constant (literal) or a variable.


If you want to mark the output as a syslog() surrogate, I would call a function other than printf() to complete the task:

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

or even

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

They will be declared as:

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

or

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

The implementation is the direct use of macros in <stdarg.h> plus the v*printf() function:

 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); } 

You can add timestamps and anything you like; You can also easily organize the output to go to the file instead of the standard output; You can also turn it on or off inside the function. Thus, on average, I would replace syslog() surrogate that allows you to configure your codes to use the tools.

In fact, since you discovered a requirement to change the logging behavior, I would suggest that instead of using syslog() directly in your code, you should use your own function (e.g. syslog_printf() , but possibly under a different name) in your code and have various implementations of this feature available to you. The only drawback to this is that calling a real syslog() now more complicated - there is no vsyslog() AFAIK. That way, the main syslog() call will be made by formatting the line in syslog_printf() with vsnprintf() (or vasprintf() if your available and running out of memory is not a likely problem), and then calling syslog() with a pre-formatted string ( syslog(priority, "%s", buffer); ). Of course, you also want priority to be passed to the surrogate function for relays on syslog() .

+10
source

The fmt string is expected to contain its own formatting specifiers, which are populated with variable arguments. First, you can simply ignore the actual arguments and just print the format string. You need a variable macro:

 #define syslog(level, fmt, ...) printf("SYSLOG: %s\n", fmt) 

Secondly, if you are ready to take a gigantic risk and expect the user to provide the format string as a literal rather than a variable, you can combine your own string:

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

This will work for syslog(1, "Hello"); but not for syslog(1, str); .

+1
source

If you do not want to rely on variable macros (C99 function), you can also do this:

 #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; } 

or similar.

+1
source

All Articles