/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set et sw=2 ts=2: */ /*************************************************************************** * debug.c * * Thu Nov 1 13:38:47 CET 2012 * Copyright 2012 Bent Bisballe Nyeng * deva@aasimon.org ****************************************************************************/ /* * This file is part of Debug Module. * * Debug Module is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Debug Module is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Debug Module; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #include "debug.h" #include #include #include #include #include #include #include #include #ifdef WITH_DBG_MUTEX #include #endif #ifdef WITH_DBG_FILTER #include "debug_filter.h" #endif #ifdef WITH_DBG_SYSLOG #include "debug_syslog.h" #endif struct dbg_config_t { unsigned int flags; #ifdef WITH_DBG_MUTEX pthread_mutex_t mutex; #endif int fd; int file_fd; #ifdef WITH_DBG_SYSLOG const char* syslog_host; int syslog_port; #endif };// dbg_config;// = { .flags = DBG_FLAG_DEFAULT, .fd = -1, .file_fd = -1 }; static struct dbg_config_t dbg_config; static void dbg_mutex_init() { #ifdef WITH_DBG_MUTEX if(dbg_config.flags & DBG_FLAG_USE_MUTEX) { pthread_mutex_init(&dbg_config.mutex, NULL); } #endif } static void dbg_mutex_lock() { #ifdef WITH_DBG_MUTEX if(dbg_config.flags & DBG_FLAG_USE_MUTEX) { pthread_mutex_lock(&dbg_config.mutex); } #endif } static void dbg_mutex_unlock() { #ifdef WITH_DBG_MUTEX if(dbg_config.flags & DBG_FLAG_USE_MUTEX) { pthread_mutex_unlock(&dbg_config.mutex); } #endif } static void dbg_mutex_close() { #ifdef WITH_DBG_MUTEX if(dbg_config.flags & DBG_FLAG_USE_MUTEX) { // Make sure we don't destroy the mutex while another thread is using it. dbg_mutex_lock(); dbg_mutex_unlock(); pthread_mutex_destroy(&dbg_config.mutex); } #endif } dbg_status_t dbg_init(unsigned int flags, ...) { dbg_status_t status = DBG_STATUS_OK; dbg_config.flags = flags; dbg_config.flags = DBG_FLAG_DEFAULT; dbg_config.fd = -1; dbg_config.file_fd = -1; int end = 0; va_list vl; va_start(vl, flags); while(!end) { int option = va_arg(vl, int); switch(option) { case DBG_OPTION_END: end = 1; break; case DBG_OPTION_FD: dbg_config.fd = va_arg(vl, int); break; case DBG_OPTION_FILENAME: if(dbg_config.flags & DBG_FLAG_OUTPUT_TO_FILE) { const char *filename = (const char*)va_arg(vl, char*); dbg_config.file_fd = open(filename, O_CREAT | O_RDWR, 0777); } break; #ifdef WITH_DBG_SYSLOG case DBG_OPTION_SYSLOG_PORT: dbg_config.syslog_port = va_arg(vl, int); break; case DBG_OPTION_SYSLOG_HOST: dbg_config.syslog_host = (const char*)va_arg(vl, char*); break; #endif #ifdef WITH_DBG_FILTER case DBG_OPTION_FILTER: dbg_filter_parse((const char*)va_arg(vl, char*)); break; #endif default: status = DBG_STATUS_UNKNOWN_OPTION; printf("option: %x\n", option); goto err; } } dbg_mutex_init(); #ifdef WITH_DBG_SYSLOG if(dbg_config.flags & DBG_FLAG_OUTPUT_TO_SYSLOG) { dbg_syslog_init(dbg_config.syslog_host, dbg_config.syslog_port); } #endif err: va_end(vl); return status; } void dbg_close() { if(dbg_config.flags & DBG_FLAG_OUTPUT_TO_FILE) { if(dbg_config.file_fd != -1) close(dbg_config.file_fd); } #ifdef WITH_DBG_SYSLOG dbg_syslog_close(); #endif dbg_mutex_close(); } const char * const debug_class_str[] = { "fixme", "err", "warn", "info", "debug" }; /* static unsigned int gettid() { return (unsigned int)pthread_self(); } */ static int dbg_create_header(char *hdr, size_t size) { time_t rawtime = time(NULL); struct tm t; localtime_r(&rawtime, &t); return snprintf(hdr, size, "%d-%02d-%02d %02d:%02d:%02d", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec); } static int dbg_output_fd(int fd, const char *msg) { if(fd == -1) return 1; char hdr[32]; dbg_create_header(hdr, sizeof(hdr)); int s = -1; s = write(fd, hdr, strlen(hdr)); s = write(fd, " ", 1); s = write(fd, msg, strlen(msg)); if(msg[strlen(msg) - 1] != '\n') { s = write(fd, "\n", 1); } return 0; } int __debug(const char *func, const int line, const enum __debug_class cl, const char *ch, const char *fmt, ...) { int result = 0; int sz; dbg_mutex_lock(); #ifdef WITH_DBG_FILTER if(!dbg_filter_enabled(cl, ch)) goto done; #endif // // Generate message // char buf[1024]; sz = snprintf(buf, sizeof(buf), "%s:%s:%s:%d ", debug_class_str[(unsigned)cl], ch, func, line); va_list va; va_start(va, fmt); sz += vsnprintf(buf + sz, sizeof(buf) - sz, fmt, va); va_end(va); // // Send message to output // if(dbg_config.flags & DBG_FLAG_OUTPUT_TO_STDOUT) { dbg_output_fd(STDOUT_FILENO, buf); } if(dbg_config.flags & DBG_FLAG_OUTPUT_TO_STDERR) { dbg_output_fd(STDERR_FILENO, buf); } if(dbg_config.flags & DBG_FLAG_OUTPUT_TO_FD) { dbg_output_fd(dbg_config.fd, buf); } if(dbg_config.flags & DBG_FLAG_OUTPUT_TO_FILE) { dbg_output_fd(dbg_config.file_fd, buf); } if(dbg_config.flags & DBG_FLAG_OUTPUT_TO_SYSLOG) { dbg_syslog_output(buf); } // done: dbg_mutex_unlock(); return result; }