328 lines
5.2 KiB
C
328 lines
5.2 KiB
C
/**
|
|
* @file dbg.c Debug printing
|
|
*
|
|
* Copyright (C) 2010 Creytiv.com
|
|
*/
|
|
#include <stdio.h>
|
|
#ifdef HAVE_UNISTD_H
|
|
#include <unistd.h>
|
|
#endif
|
|
#ifdef HAVE_PTHREAD
|
|
#include <stdlib.h>
|
|
#include <pthread.h>
|
|
#endif
|
|
#include <time.h>
|
|
#include <re_types.h>
|
|
#include <re_fmt.h>
|
|
#include <re_list.h>
|
|
#include <re_tmr.h>
|
|
|
|
|
|
#define DEBUG_MODULE "dbg"
|
|
#define DEBUG_LEVEL 0
|
|
#include <re_dbg.h>
|
|
|
|
|
|
/** Debug configuration */
|
|
static struct {
|
|
uint64_t tick; /**< Init ticks */
|
|
int level; /**< Current debug level */
|
|
enum dbg_flags flags; /**< Debug flags */
|
|
dbg_print_h *ph; /**< Optional print handler */
|
|
void *arg; /**< Handler argument */
|
|
FILE *f; /**< Logfile */
|
|
#ifdef HAVE_PTHREAD
|
|
pthread_mutex_t mutex; /**< Thread locking */
|
|
#endif
|
|
} dbg = {
|
|
0,
|
|
DBG_INFO,
|
|
DBG_ANSI,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
#ifdef HAVE_PTHREAD
|
|
PTHREAD_MUTEX_INITIALIZER,
|
|
#endif
|
|
};
|
|
|
|
|
|
#ifdef HAVE_PTHREAD
|
|
static inline void dbg_lock(void)
|
|
{
|
|
pthread_mutex_lock(&dbg.mutex);
|
|
}
|
|
|
|
|
|
static inline void dbg_unlock(void)
|
|
{
|
|
pthread_mutex_unlock(&dbg.mutex);
|
|
}
|
|
#else
|
|
#define dbg_lock() /**< Stub */
|
|
#define dbg_unlock() /**< Stub */
|
|
#endif
|
|
|
|
|
|
/**
|
|
* Initialise debug printing
|
|
*
|
|
* @param level Debug level
|
|
* @param flags Debug flags
|
|
*/
|
|
void dbg_init(int level, enum dbg_flags flags)
|
|
{
|
|
dbg.tick = tmr_jiffies();
|
|
dbg.level = level;
|
|
dbg.flags = flags;
|
|
}
|
|
|
|
|
|
/**
|
|
* Close debugging
|
|
*/
|
|
void dbg_close(void)
|
|
{
|
|
if (dbg.f) {
|
|
(void)fclose(dbg.f);
|
|
dbg.f = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Set debug logfile
|
|
*
|
|
* @param name Name of the logfile, NULL to close
|
|
*
|
|
* @return 0 if success, otherwise errorcode
|
|
*/
|
|
int dbg_logfile_set(const char *name)
|
|
{
|
|
time_t t;
|
|
|
|
dbg_close();
|
|
|
|
if (!name)
|
|
return 0;
|
|
|
|
dbg.f = fopen(name, "a+");
|
|
if (!dbg.f)
|
|
return errno;
|
|
|
|
(void)time(&t);
|
|
(void)re_fprintf(dbg.f, "\n===== Log Started: %s", ctime(&t));
|
|
(void)fflush(dbg.f);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**
|
|
* Set optional debug print handler
|
|
*
|
|
* @param ph Print handler
|
|
* @param arg Handler argument
|
|
*/
|
|
void dbg_handler_set(dbg_print_h *ph, void *arg)
|
|
{
|
|
dbg.ph = ph;
|
|
dbg.arg = arg;
|
|
}
|
|
|
|
|
|
/* NOTE: This function should not allocate memory */
|
|
static void dbg_vprintf(int level, const char *fmt, va_list ap)
|
|
{
|
|
if (level > dbg.level)
|
|
return;
|
|
|
|
/* Print handler? */
|
|
if (dbg.ph)
|
|
return;
|
|
|
|
dbg_lock();
|
|
|
|
if (dbg.flags & DBG_ANSI) {
|
|
|
|
switch (level) {
|
|
|
|
case DBG_WARNING:
|
|
(void)re_fprintf(stderr, "\x1b[31m"); /* Red */
|
|
break;
|
|
|
|
case DBG_NOTICE:
|
|
(void)re_fprintf(stderr, "\x1b[33m"); /* Yellow */
|
|
break;
|
|
|
|
case DBG_INFO:
|
|
(void)re_fprintf(stderr, "\x1b[32m"); /* Green */
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (dbg.flags & DBG_TIME) {
|
|
const uint64_t ticks = tmr_jiffies();
|
|
|
|
if (0 == dbg.tick)
|
|
dbg.tick = tmr_jiffies();
|
|
|
|
(void)re_fprintf(stderr, "[%09llu] ", ticks - dbg.tick);
|
|
}
|
|
|
|
(void)re_vfprintf(stderr, fmt, ap);
|
|
|
|
if (dbg.flags & DBG_ANSI && level < DBG_DEBUG)
|
|
(void)re_fprintf(stderr, "\x1b[;m");
|
|
|
|
dbg_unlock();
|
|
}
|
|
|
|
|
|
/* Formatted output to print handler and/or logfile */
|
|
static void dbg_fmt_vprintf(int level, const char *fmt, va_list ap)
|
|
{
|
|
char buf[256];
|
|
int len;
|
|
|
|
if (level > dbg.level)
|
|
return;
|
|
|
|
if (!dbg.ph && !dbg.f)
|
|
return;
|
|
|
|
dbg_lock();
|
|
|
|
len = re_vsnprintf(buf, sizeof(buf), fmt, ap);
|
|
if (len <= 0)
|
|
goto out;
|
|
|
|
/* Print handler? */
|
|
if (dbg.ph) {
|
|
dbg.ph(level, buf, len, dbg.arg);
|
|
}
|
|
|
|
/* Output to file */
|
|
if (dbg.f) {
|
|
if (fwrite(buf, 1, len, dbg.f) > 0)
|
|
(void)fflush(dbg.f);
|
|
}
|
|
|
|
out:
|
|
dbg_unlock();
|
|
}
|
|
|
|
|
|
/**
|
|
* Print a formatted debug message
|
|
*
|
|
* @param level Debug level
|
|
* @param fmt Formatted string
|
|
*/
|
|
void dbg_printf(int level, const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
|
dbg_vprintf(level, fmt, ap);
|
|
va_end(ap);
|
|
|
|
va_start(ap, fmt);
|
|
dbg_fmt_vprintf(level, fmt, ap);
|
|
va_end(ap);
|
|
}
|
|
|
|
|
|
/**
|
|
* Print a formatted debug message to /dev/null
|
|
*
|
|
* @param fmt Formatted string
|
|
*/
|
|
void dbg_noprintf(const char *fmt, ...)
|
|
{
|
|
(void)fmt;
|
|
}
|
|
|
|
|
|
/**
|
|
* Print a formatted warning message
|
|
*
|
|
* @param fmt Formatted string
|
|
*/
|
|
void dbg_warning(const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
|
dbg_vprintf(DBG_WARNING, fmt, ap);
|
|
va_end(ap);
|
|
|
|
va_start(ap, fmt);
|
|
dbg_fmt_vprintf(DBG_WARNING, fmt, ap);
|
|
va_end(ap);
|
|
}
|
|
|
|
|
|
/**
|
|
* Print a formatted notice message
|
|
*
|
|
* @param fmt Formatted string
|
|
*/
|
|
void dbg_notice(const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
|
dbg_vprintf(DBG_NOTICE, fmt, ap);
|
|
va_end(ap);
|
|
|
|
va_start(ap, fmt);
|
|
dbg_fmt_vprintf(DBG_NOTICE, fmt, ap);
|
|
va_end(ap);
|
|
}
|
|
|
|
|
|
/**
|
|
* Print a formatted info message
|
|
*
|
|
* @param fmt Formatted string
|
|
*/
|
|
void dbg_info(const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
|
dbg_vprintf(DBG_INFO, fmt, ap);
|
|
va_end(ap);
|
|
|
|
va_start(ap, fmt);
|
|
dbg_fmt_vprintf(DBG_INFO, fmt, ap);
|
|
va_end(ap);
|
|
}
|
|
|
|
|
|
/**
|
|
* Get the name of the debug level
|
|
*
|
|
* @param level Debug level
|
|
*
|
|
* @return String with debug level name
|
|
*/
|
|
const char *dbg_level_str(int level)
|
|
{
|
|
switch (level) {
|
|
|
|
case DBG_EMERG: return "EMERGENCY";
|
|
case DBG_ALERT: return "ALERT";
|
|
case DBG_CRIT: return "CRITICAL";
|
|
case DBG_ERR: return "ERROR";
|
|
case DBG_WARNING: return "WARNING";
|
|
case DBG_NOTICE: return "NOTICE";
|
|
case DBG_INFO: return "INFO";
|
|
case DBG_DEBUG: return "DEBUG";
|
|
default: return "???";
|
|
}
|
|
}
|