Last active
October 26, 2022 06:51
-
-
Save rumpelsepp/3229275bbe9e3f41ba5f33a84643fe73 to your computer and use it in GitHub Desktop.
A printf wrapper, with loglevel support and timestamps
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdarg.h> | |
#include <stdlib.h> | |
#include <time.h> | |
#include <libiberty/libiberty.h> | |
#include "log.h" | |
#include "config.h" | |
#define BUFSIZE 1024 | |
#ifdef LOG_TIMESTAMPS | |
#define LOG_FORMAT "%s [%s]: %s\n" // timestamp loglevel: message\n | |
static char *gettimestamp() { | |
int r; | |
time_t t; | |
char *res; | |
struct tm *tmp; | |
// In order to not waste space, the string is reallocated | |
// later on. strftime(3) returns how many bytes have been put | |
// into the buffer. If it does not fit into the buffer, it | |
// errors out. | |
res = xcalloc(1, BUFSIZE); | |
t = time(NULL); | |
tmp = localtime(&t); | |
if (tmp == NULL) { | |
perror("localtime(3)"); | |
exit(EXIT_FAILURE); | |
} | |
r = strftime(res, BUFSIZE, LOG_STRFTIME, tmp); | |
if (r == 0) { | |
fprintf(stderr, "strftime(3) failed\n"); | |
exit(EXIT_FAILURE); | |
} | |
// Reallocate to the actual size of the string. | |
// It is not likely to fail, since we are freeing | |
// memory here. | |
return xrealloc(res, r); | |
} | |
static int __log(const char *level, const char *format, va_list args) { | |
int len; | |
char *timestamp; | |
char *newformat; | |
char *logformat = LOG_FORMAT; | |
timestamp = gettimestamp(); | |
len = snprintf(NULL, 0, logformat, timestamp, level, format); | |
len++; // Trailing null byte. | |
newformat = xmalloc(len); | |
len = snprintf(newformat, len, logformat, timestamp, level, format); | |
if (len < 0) { | |
goto cleanup; | |
} | |
len = vprintf(newformat, args); | |
cleanup: | |
free(timestamp); | |
free(newformat); | |
return len; | |
} | |
#else | |
#define LOG_FORMAT "[%s]: %s\n" // loglevel: message\n | |
static int __log(const char *level, const char *format, va_list args) { | |
int len; | |
char *newformat; | |
char *logformat = LOG_FORMAT; | |
len = snprintf(NULL, 0, logformat, level, format); | |
len++; // Trailing null byte. | |
newformat = xmalloc(len); | |
len = snprintf(newformat, len, logformat, level, format); | |
if (len < 0) { | |
goto cleanup; | |
} | |
len = vprintf(newformat, args); | |
cleanup: | |
free(newformat); | |
return len; | |
} | |
#endif | |
int debug(const char *format, ...) { | |
int r; | |
va_list ap; | |
if (loglevel > DEBUG) { | |
return -1; | |
} | |
va_start(ap, format); | |
r = __log("DEBUG", format, ap); | |
va_end(ap); | |
return r; | |
} | |
int info(const char *format, ...) { | |
int r; | |
va_list ap; | |
if (loglevel > INFO) { | |
return -1; | |
} | |
va_start(ap, format); | |
r = __log("INFO", format, ap); | |
va_end(ap); | |
return r; | |
} | |
int warning(const char *format, ...) { | |
int r; | |
va_list ap; | |
if (loglevel > WARNING) { | |
return -1; | |
} | |
va_start(ap, format); | |
r = __log("WARNING", format, ap); | |
va_end(ap); | |
return r; | |
} | |
int error(const char *format, ...) { | |
int r; | |
va_list ap; | |
if (loglevel > ERROR) { | |
return -1; | |
} | |
va_start(ap, format); | |
r = __log("ERROR", format, ap); | |
va_end(ap); | |
return r; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
enum loglevel_t { DEBUG, INFO, WARNING, ERROR }; | |
extern enum loglevel_t loglevel; | |
int debug(const char *format, ...); | |
int info(const char *format, ...); | |
int warning(const char *format, ...); | |
int error(const char *format, ...); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment