I'm getting back into C and I wrote this variadic logger as part of a chess application I'm writing. As such I'm looking for feedback about the general approach (I'm going to give it another pass to catch any possible errors, edge cases etc... later on). Mainly I'm concerned with side effects and trade-offs that I may not be aware of by using a solution like this.
The goal is to have a relatively portable, easy to use, and safe (as far as you can go without type checking) logger, that behaves like printf()
but with some extra options.
So with all of that being said, please tell me why this is probably a bad idea in some shape or form.
Is variadic logging in C a sensible thing to do?
log.h
#ifndef CHX_LOG_H
#define CHX_LOG_H
typedef enum
{
CHX_LOG_DEBUG,
CHX_LOG_INFO,
CHX_LOG_WARNING,
CHX_LOG_ERROR,
CHX_LOG_SILENT,
}chx_log_lvl;
typedef enum
{
CHX_TAG_CLI,
CHX_TAG_CORE,
CHX_TAG_ERRORS,
}chx_tag;
#define CHX_LOG_ENABLED
#ifdef CHX_LOG_ENABLED
void chx_log(chx_log_lvl lvl, chx_tag tag, char* msg_tmpl, ...);
#define CHX_LOG(...) chx_log(__VA_ARGS__)
#define CHX_LOG_DEBUG(...) chx_log (CHX_LOG_DEBUG, __VA_ARGS__)
#define CHX_LOG_INFO(...) chx_log (CHX_LOG_INFO, __VA_ARGS__)
#define CHX_LOG_WARNING(...) chx_log (CHX_LOG_WARNING, __VA_ARGS__)
#define CHX_LOG_ERROR(...) chx_log (CHX_LOG_ERROR, __VA_ARGS__)
#else
#define CHX_LOG(...)
#define CHX_LOG_DEBUG(...)
#define CHX_LOG_INFO(...)
#define CHX_LOG_WARNING(...)
#define CHX_LOG_ERROR(...)
#endif
#endif
log.c
#include "log.h"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#ifdef CHX_LOG_ENABLED
void chx_log(chx_log_lvl lvl, chx_tag tag, char* msg_tmpl, ...)
{
va_list msg_args;
va_start(msg_args, msg_tmpl);
char *chx_msg;
if(vasprintf(&chx_msg, msg_tmpl, msg_args) == -1)
{
printf("Error formatting log... %s\n", msg_tmpl);
exit(1);
}
va_end(msg_args);
printf("%s", chx_msg);
free(chx_msg);
}
#endif
Usage:
CHX_LOG_DEBUG(CHX_TAG_CLI, "cli_args:\n --player_side: %d\n --depth: %d\n --fen_path %s\n",
cli_opts.player_side, cli_opts.depth, cli_opts.fen_path);
lvl
andtag
are not used invoid chx_log()
. Why are they in the parameter list? \$\endgroup\$