From 10f567056986f0178a19e62f3e4859fe86a0a8c8 Mon Sep 17 00:00:00 2001 From: Guillaume Roguez <guillaume.roguez@savoirfairelinux.com> Date: Sat, 15 Aug 2015 00:12:20 -0400 Subject: [PATCH] logger: rewrite - Console mode modified for a nice look: - add timestamp - colored header - reordering - Fix syslog output (openlog on "dring") - Multithread safe (mutex protected) - Make logger a C++ file and code cleanup Issue: #79075 Change-Id: I6c818ec283541ce8e740693ebefbafce3cac5617 --- src/Makefile.am | 2 +- src/{logger.c => logger.cpp} | 131 ++++++++++++++++++++++++++++++++--- src/logger.h | 62 ++++------------- src/winsyslog.c | 5 +- src/winsyslog.h | 4 +- 5 files changed, 138 insertions(+), 66 deletions(-) rename src/{logger.c => logger.cpp} (53%) diff --git a/src/Makefile.am b/src/Makefile.am index 6e20919406..d7cd0e82f8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -112,7 +112,7 @@ libring_la_SOURCES = conference.cpp \ manager.cpp \ call.cpp \ account.cpp \ - logger.c \ + logger.cpp \ fileutils.cpp \ threadloop.cpp \ ip_utils.h \ diff --git a/src/logger.c b/src/logger.cpp similarity index 53% rename from src/logger.c rename to src/logger.cpp index 9200c49d34..f2a669be85 100644 --- a/src/logger.c +++ b/src/logger.cpp @@ -1,6 +1,7 @@ /* * Copyright (C) 2004-2015 Savoir-Faire Linux Inc. * Author: Julien Bonjean <julien.bonjean@savoirfairelinux.com> + * Author: Guillaume Roguez <guillaume.roguez@savoirfairelinux.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -32,17 +33,95 @@ #include <stdarg.h> #include <string.h> #include <errno.h> +#include <time.h> +#include <sys/time.h> + +#include <string> +#include <sstream> +#include <iomanip> +#include <ios> +#include <mutex> +#include <thread> #include "logger.h" -static int consoleLog; -static int debugMode; +#ifdef __linux__ +#include <syslog.h> +#include <unistd.h> +#include <sys/syscall.h> +#endif // __linux__ #ifdef WIN32 #include "winsyslog.h" #endif -void logger(const int level, const char* format, ...) +#define BLACK "\033[22;30m" +#define GREEN "\033[22;32m" +#define BROWN "\033[22;33m" +#define BLUE "\033[22;34m" +#define MAGENTA "\033[22;35m" +#define GREY "\033[22;37m" +#define DARK_GREY "\033[01;30m" +#define LIGHT_RED "\033[01;31m" +#define LIGHT_SCREEN "\033[01;32m" +#define LIGHT_BLUE "\033[01;34m" +#define LIGHT_MAGENTA "\033[01;35m" +#define LIGHT_CYAN "\033[01;36m" +#define WHITE "\033[01;37m" +#define END_COLOR "\033[0m" + +#ifndef _WIN32 +#define RED "\033[22;31m" +#define YELLOW "\033[01;33m" +#define CYAN "\033[22;36m" +#else +#define RED FOREGROUND_RED +#define YELLOW FOREGROUND_RED + FOREGROUND_GREEN +#define CYAN FOREGROUND_BLUE + FOREGROUND_GREEN +#endif + +static int consoleLog; +static int debugMode; +static std::mutex logMutex; + +static std::string +getHeader(const char* ctx) +{ +#ifdef __linux__ + auto tid = syscall(__NR_gettid) & 0xffff; +#else + auto tid = std::this_thread::get_id(); +#endif // __linux__ + + // Timestamp + unsigned int secs, milli; + struct timeval tv; + if (!gettimeofday(&tv, NULL)) { + secs = tv.tv_sec; + milli = tv.tv_usec / 1000; // suppose that milli < 1000 + } else { + secs = time(NULL); + milli = 0; + } + + std::ostringstream out; + const auto prev_fill = out.fill(); + out << '[' << secs + << '.' << std::right << std::setw(3) << std::setfill('0') << milli << std::left + << '|' << std::right << std::setw(5) << std::setfill(' ') << tid << std::left; + out.fill(prev_fill); + + // Context + if (ctx) + out << "|" << std::setw(24) << ctx; + + out << "] "; + + return out.str(); +} + +void +logger(const int level, const char* format, ...) { if (!debugMode && level == LOG_DEBUG) return; @@ -53,8 +132,11 @@ void logger(const int level, const char* format, ...) va_end(ap); } -void vlogger(const int level, const char *format, va_list ap) +void +vlogger(const int level, const char *format, va_list ap) { + std::lock_guard<std::mutex> lk {logMutex}; + #ifdef WIN32 HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); CONSOLE_SCREEN_BUFFER_INFO consoleInfo; @@ -66,8 +148,10 @@ void vlogger(const int level, const char *format, va_list ap) if (consoleLog) { #ifndef _WIN32 - const char *color_prefix = ""; + const char* color_header = CYAN; + const char* color_prefix = ""; #else + WORD color_header = CYAN; WORD color_prefix = FOREGROUND_GREEN; #endif @@ -81,10 +165,23 @@ void vlogger(const int level, const char *format, va_list ap) } #ifndef _WIN32 - fputs(color_prefix, stderr); + fputs(color_header, stderr); #else GetConsoleScreenBufferInfo(hConsole, &consoleInfo); saved_attributes = consoleInfo.wAttributes; + SetConsoleTextAttribute(hConsole, color_header); +#endif + + auto sep = strchr(format, '|'); // must exist, check LOG_FORMAT + std::string ctx(format, sep - format); + format = sep + 2; + fputs(getHeader(ctx.c_str()).c_str(), stderr); + +#ifndef _WIN32 + fputs(END_COLOR, stderr); + fputs(color_prefix, stderr); +#else + SetConsoleTextAttribute(hConsole, saved_attributes); SetConsoleTextAttribute(hConsole, color_prefix); #endif @@ -102,22 +199,36 @@ void vlogger(const int level, const char *format, va_list ap) } } -void setConsoleLog(int c) +void +setConsoleLog(int c) { + if (c) + closelog(); + else { +#ifdef _WIN32 + openlog(LOGFILE, WINLOG_PID, WINLOG_MAIL); +#else + openlog(LOGFILE, LOG_NDELAY, LOG_USER); +#endif /* _WIN32 */ + } + consoleLog = c; } -void setDebugMode(int d) +void +setDebugMode(int d) { debugMode = d; } -int getDebugMode(void) +int +getDebugMode(void) { return debugMode; } -void strErr(void) +void +strErr(void) { #ifdef __GLIBC__ RING_ERR("%m"); diff --git a/src/logger.h b/src/logger.h index cacf358373..05119b8306 100644 --- a/src/logger.h +++ b/src/logger.h @@ -1,6 +1,7 @@ /* * Copyright (C) 2004-2015 Savoir-Faire Linux Inc. * Author: Julien Bonjean <julien.bonjean@savoirfairelinux.com> + * Author: Guillaume Roguez <guillaume.roguez@savoirfairelinux.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,8 +29,7 @@ * as that of the covered work. */ -#ifndef H_LOGGER -#define H_LOGGER +#pragma once #ifdef __cplusplus extern "C" { @@ -37,11 +37,13 @@ extern "C" { #include <stdarg.h> +#define LOGFILE "dring" + /** * Print something, coloring it depending on the level */ -void logger(const int level, const char *format, ...); -void vlogger(const int level, const char *format, va_list); +void logger(const int level, const char* format, ...); +void vlogger(const int level, const char* format, va_list); /** * Allow writing on the console @@ -63,19 +65,11 @@ int getDebugMode(void); */ void strErr(); -#ifdef __linux__ - -#include <unistd.h> -#include <sys/syscall.h> +#define STR(EXP) #EXP +#define XSTR(X) STR(X) -#define LOG_FORMAT(M, ...) "%s:%d:0x%x: " M, FILE_NAME, __LINE__, \ - syscall(__NR_gettid) & 0xffff, \ - ##__VA_ARGS__ -#else - -#define LOG_FORMAT(M, ...) "%s:%d: " M, FILE_NAME , __LINE__, \ - ##__VA_ARGS__ -#endif +// Do not remove the "| " in following without modifying vlogger() code +#define LOG_FORMAT(M, ...) FILE_NAME ":" XSTR(__LINE__) "| " M, ##__VA_ARGS__ #ifdef __ANDROID__ @@ -86,8 +80,7 @@ void strErr(); #endif /* APP_NAME */ // Avoid printing whole path on android -#define FILE_NAME (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 \ - : __FILE__) +#define FILE_NAME (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) // because everyone likes reimplementing the wheel #define LOG_ERR ANDROID_LOG_ERROR @@ -95,8 +88,7 @@ void strErr(); #define LOG_INFO ANDROID_LOG_INFO #define LOG_DEBUG ANDROID_LOG_DEBUG -#define LOGGER(M, LEVEL, ...) __android_log_print(LEVEL, APP_NAME, \ - LOG_FORMAT(M, ##__VA_ARGS__)) +#define LOGGER(M, LEVEL, ...) __android_log_print(LEVEL, APP_NAME, LOG_FORMAT(M, ##__VA_ARGS__)) #elif defined(_WIN32) @@ -122,36 +114,10 @@ void strErr(); #endif /* __ANDROID__ _WIN32 */ #define RING_ERR(M, ...) LOGGER(M, LOG_ERR, ##__VA_ARGS__) -#define RING_WARN(M, ...) LOGGER(M, LOG_WARNING, ##__VA_ARGS__) -#define RING_INFO(M, ...) LOGGER(M, LOG_INFO, ##__VA_ARGS__) +#define RING_WARN(M, ...) LOGGER(M, LOG_WARNING, ##__VA_ARGS__) +#define RING_INFO(M, ...) LOGGER(M, LOG_INFO, ##__VA_ARGS__) #define RING_DBG(M, ...) LOGGER(M, LOG_DEBUG, ##__VA_ARGS__) -#define BLACK "\033[22;30m" -#define GREEN "\033[22;32m" -#define BROWN "\033[22;33m" -#define BLUE "\033[22;34m" -#define MAGENTA "\033[22;35m" -#define CYAN "\033[22;36m" -#define GREY "\033[22;37m" -#define DARK_GREY "\033[01;30m" -#define LIGHT_RED "\033[01;31m" -#define LIGHT_SCREEN "\033[01;32m" -#define LIGHT_BLUE "\033[01;34m" -#define LIGHT_MAGENTA "\033[01;35m" -#define LIGHT_CYAN "\033[01;36m" -#define WHITE "\033[01;37m" -#define END_COLOR "\033[0m" - -#ifndef _WIN32 -#define RED "\033[22;31m" -#define YELLOW "\033[01;33m" -#else -#define RED FOREGROUND_RED -#define YELLOW FOREGROUND_RED + FOREGROUND_GREEN -#endif - #ifdef __cplusplus } #endif - -#endif // H_LOGGER diff --git a/src/winsyslog.c b/src/winsyslog.c index 69f311b449..f737cc28d1 100644 --- a/src/winsyslog.c +++ b/src/winsyslog.c @@ -74,9 +74,6 @@ void closelog(void) CONST CHAR *arr[1]; char tmp[1024]; - if (!loghdl) - openlog(LOGFILE, WINLOG_PID, WINLOG_MAIL); - vsprintf(tmp, format, arglist); arr[0] = tmp; @@ -105,4 +102,4 @@ void closelog(void) loghdl = RegisterEventSource(NULL, ident); sprintf(tmp, (logopt & WINLOG_PID) ? "%s[%d]" : "%s", ident, getpid()); loghdr = _strdup(tmp); /* save header for later */ -} \ No newline at end of file +} diff --git a/src/winsyslog.h b/src/winsyslog.h index 6285732063..514de7dfa5 100644 --- a/src/winsyslog.h +++ b/src/winsyslog.h @@ -40,8 +40,6 @@ #define WINLOG_MASK(pri) (1 << (pri)) #define WINLOG_UPTO(pri) ((1 << ((pri)+1)) - 1) -#define LOGFILE "ringcli" - /* * Option flags for openlog. * @@ -61,4 +59,4 @@ extern void closelog(void); extern void openlog(const char *, int, int); extern void vsyslog(int, const char *, va_list); -#endif \ No newline at end of file +#endif -- GitLab