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