fazineroso
fazineroso

Reputation: 7466

Coding a Log Write function (wrapping vfprintf) : how to modify the text string to print?

I am writing a log writer, and for that I am writing a wrapper function over vfprintf so I am able to include some extra information around it.

The log writing macro is defined as this:

#define LOG_WRITE(type, fmt, args...)   write_log(type, __FILE__, __FUNCTION__, __LINE__, fmt, ## args)

And I have my function defined like this:

int write_log(enum LogType_e type, const char* file, const char* function, int line, const char* format, ...) {

    va_list arg;
    int rv;

    va_start(arg, format);
    rv = vfprintf(log_fd, format, arg);
    va_end(arg);

    return rv;
}

That function gets some extra information, like the log level, the file where the log call was ran, function, line of code, and finally the text.

Of course, I want to check that information and format it nicely and add it to 'format'. How can I do that?

Upvotes: 2

Views: 2067

Answers (2)

suspectus
suspectus

Reputation: 17288

Amend the fprintf statement to suit the output you require. Note the example below uses __VA_ARGS__ which is the C pre-processor way to process variadic arguments AFAIK.

#define LOG_WRITE(type, fp, fmt, ...)   write_log(type, fp, __FILE__, __FUNCTION__, __LINE__, fmt,##__VA_ARGS__)

int write_log(enum LogType_e type, FILE *fp, const char *file, const char* function, int line, const char* format, ...) 
{    
    va_list arg;
    int rv;    
    va_start(arg, format);
    fprintf(fp, "file %s:function %s:line %d:", file, function, __LINE__);
    rv = vfprintf(fp, format, arg);
    va_end(arg);    
    return rv;
}

int main()
{
    FILE* fp = fopen("test.log", "w");
    int b = 13, c = 5;
    write_log(LOG_ERROR, fp, "vfprintf.c", "main", 27, "%s %d\n", "value of b=", b);
    LOG_WRITE(LOG_ERROR, fp, "value of c=%d\n", c);
    LOG_WRITE(LOG_ERROR, fp, "help!!\n");
}

Upvotes: 0

M Oehm
M Oehm

Reputation: 29136

The easiest solution is probably not to fiddle with the format string, but to add further calls to fprintf(log_fd, ...):

void write_log(enum LogType_e type, const char* file, const char* function, int line, const char* format, ...) {

    va_list arg;
    int rv;

    switch (type) {
    case TYPE_ERROR:
        fprintf(log_fd, "Error: ");
        break;
    case TYPE_WARN:
        fprintf(log_fd, "Warning: ");
        break;
    }

    if (file) {
        if (function) {
            fprintf(log_fd, "[%s in %s, %d] ", function, file, line);
        } else {
            fprintf(log_fd, "[%s, %d] ", file, line);
        }
    }

    va_start(arg, format);
    rv = vfprintf(log_fd, format, arg);
    va_end(arg);
}

This makes it harder to keep track of the number of characters printed, but you're not going to use that information anyway, so there's no point in calculating and returning it.

(You could also log to a temporary string and then pretty-print that if you need word-wrapping. But that would mean you'd have to keep track of the overall string length again.)

Upvotes: 2

Related Questions