From 5a4b67605c107bdeb10c525b52d0e5ff4eee9df5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Verstraeten?= Date: Thu, 3 May 2018 16:16:41 +0200 Subject: [PATCH 01/35] add live streaming support to cloud --- include/kerberos/Globals.h | 2 +- include/kerberos/cloud/Cloud.h | 12 +++++ include/kerberos/cloud/ForwardStream.h | 67 +++++++++++++++++++++++++ src/kerberos/CMakeLists.txt | 1 + src/kerberos/Kerberos.cpp | 3 ++ src/kerberos/cloud/Cloud.cpp | 64 ++++++++++++++++++++++++ src/kerberos/cloud/ForwardStream.cpp | 68 ++++++++++++++++++++++++++ 7 files changed, 216 insertions(+), 1 deletion(-) create mode 100644 include/kerberos/cloud/ForwardStream.h create mode 100644 src/kerberos/cloud/ForwardStream.cpp diff --git a/include/kerberos/Globals.h b/include/kerberos/Globals.h index b3b625d..a282d2a 100755 --- a/include/kerberos/Globals.h +++ b/include/kerberos/Globals.h @@ -17,7 +17,7 @@ #ifndef __Version_H_INCLUDED__ // if Version.h hasn't been included yet... #define __Version_H_INCLUDED__ // #define this so the compiler knows it has been included - #define VERSION "2.5.1" + #define VERSION "2.6.0" #define HADES "https://hades.kerberos.io" #define CLOUD "https://cloud.kerberos.io" #define SYMBOL_DIRECTORY "/etc/opt/kerberosio/symbols/" diff --git a/include/kerberos/cloud/Cloud.h b/include/kerberos/cloud/Cloud.h index 33484f6..b30a949 100755 --- a/include/kerberos/cloud/Cloud.h +++ b/include/kerberos/cloud/Cloud.h @@ -26,6 +26,8 @@ #include "restclient-cpp/restclient.h" #include #include +#include "capture/Capture.h" +#include "cloud/ForwardStream.h" namespace kerberos { @@ -49,6 +51,10 @@ namespace kerberos pthread_t m_healthThread; bool m_healthThread_running; + pthread_t m_livestreamThread; + pthread_mutex_t m_capture_lock; + bool m_livestreamThread_running; + std::string m_keyFile; std::string m_productKey; std::string m_name; @@ -62,6 +68,8 @@ namespace kerberos StringMap m_parameters; RestClient::Connection * cloudConnection; RestClient::Connection * pollConnection; + Capture * m_capturedevice; + ForwardStream fstream; Cloud(){}; virtual ~Cloud(){}; @@ -69,12 +77,16 @@ namespace kerberos virtual bool upload(std::string pathToImage) = 0; virtual bool doesExist(std::string pathToImage) = 0; + void setCapture(Capture * capture){m_capturedevice = capture;}; + void disableCapture(); void startUploadThread(); void stopUploadThread(); void startPollThread(); void stopPollThread(); void startHealthThread(); void stopHealthThread(); + void startLivestreamThread(); + void stopLivestreamThread(); void scan(); void generateHash(kerberos::StringMap & settings); diff --git a/include/kerberos/cloud/ForwardStream.h b/include/kerberos/cloud/ForwardStream.h new file mode 100644 index 0000000..643a362 --- /dev/null +++ b/include/kerberos/cloud/ForwardStream.h @@ -0,0 +1,67 @@ +// +// Class: ForwardStream +// Description: ForwardStream +// +// Created: 16/04/2018 +// Author: Cédric Verstraeten +// Mail: cedric@verstraeten.io +// Website: www.verstraeten.io +// +// The copyright to the computer program(s) herein +// is the property of Verstraeten.io, Belgium. +// The program(s) may be used and/or copied under +// the CC-NC-ND license model. +// +// https://doc.kerberos.io/license +// +///////////////////////////////////////////////////// + +#ifndef __ForwardStream_H_INCLUDED__ // if ForwardStream.h hasn't been included yet... +#define __ForwardStream_H_INCLUDED__ // #define this so the compiler knows it has been included + +#include "Exception.hpp" +#include "capture/Image.h" +#include "mosquittopp.h" +#include "writer.h" +#include "base64.h" +#include "Helper.h" + +namespace kerberos +{ + class ForwardStream : public mosqpp::mosquittopp + { + private: + std::string m_server_ip; + unsigned short m_port; + std::string m_topic; + std::vector m_encode_params; + + public: + ForwardStream(){}; + virtual ~ForwardStream() + { + disconnect(); + loop_stop(); + mosqpp::lib_cleanup(); + }; + + std::string m_publicKey; + std::string m_deviceKey; + int m_lastReceived; + + void setup(std::string publickey, std::string deviceKey); + void setIp(const std::string server_ip){m_server_ip=server_ip;}; + const char * getIp(){return m_server_ip.c_str();}; + void setPort(const unsigned short port){m_port=port;}; + unsigned short getPort(){return m_port;}; + void setTopic(std::string topic){m_topic=topic;}; + const char * getTopic(){return m_topic.c_str();}; + bool forward(Image & cleanImage); + bool isRequestingLiveStream(); + + void on_connect(int rc); + void on_message(const struct mosquitto_message *message); + void on_subscribe(int mid, int qos_count, const int *granted_qos); + }; +} +#endif diff --git a/src/kerberos/CMakeLists.txt b/src/kerberos/CMakeLists.txt index f8b4e39..37d29ca 100755 --- a/src/kerberos/CMakeLists.txt +++ b/src/kerberos/CMakeLists.txt @@ -5,6 +5,7 @@ set(KERBEROS_SRC cloud/Cloud.cpp + cloud/ForwardStream.cpp capture/Capture.cpp capture/Stream.cpp capture/Image.cpp diff --git a/src/kerberos/Kerberos.cpp b/src/kerberos/Kerberos.cpp index acd1554..3f2ff88 100755 --- a/src/kerberos/Kerberos.cpp +++ b/src/kerberos/Kerberos.cpp @@ -227,6 +227,8 @@ namespace kerberos if(capture->isOpened()) { machinery->disableCapture(); + cloud->disableCapture(); + cloud->stopLivestreamThread(); capture->stopGrabThread(); capture->stopHealthThread(); capture->close(); @@ -272,6 +274,7 @@ namespace kerberos LINFO << "Starting cloud service: " + settings.at("cloud"); cloud = Factory::getInstance()->create(settings.at("cloud")); + cloud->setCapture(capture); cloud->setup(settings); } diff --git a/src/kerberos/cloud/Cloud.cpp b/src/kerberos/cloud/Cloud.cpp index 29467f4..3163134 100755 --- a/src/kerberos/cloud/Cloud.cpp +++ b/src/kerberos/cloud/Cloud.cpp @@ -5,6 +5,8 @@ namespace kerberos { void Cloud::setup(kerberos::StringMap & settings) { + pthread_mutex_init(&m_capture_lock, NULL); + // ------------------------------- // Upload interval [1.5sec;4.2min] @@ -61,6 +63,19 @@ namespace kerberos std::string privateKey = settings.at("clouds.S3.privateKey"); setCloudCredentials(user, publicKey, privateKey); startHealthThread(); + + // ------------------- + // Start livestreaming + + fstream.setup(m_publicKey, m_productKey); + startLivestreamThread(); + } + + void Cloud::disableCapture() + { + pthread_mutex_lock(&m_capture_lock); + m_capturedevice = 0; + pthread_mutex_unlock(&m_capture_lock); } void Cloud::scan() @@ -223,6 +238,13 @@ namespace kerberos BINFO << "Cloud: reset product key (" << key << ")"; } + // -------------------------------------------- + // Start livestreaming + /*std::cout << cloud->m_publicKey << std::endl; + std::cout << cloud->m_productKey << std::endl; + cloud->fstream.setup(cloud->m_publicKey, cloud->m_productKey); + cloud->startLivestreamThread();*/ + // -------------------------------------------- // Generate fixed JSON data which will be send, // over and over again. @@ -306,4 +328,46 @@ namespace kerberos pthread_join(m_healthThread, NULL); delete cloudConnection; } + + // ------------------------------------ + // Send live stream to cloud, if + // subscribed to our cloud plan. + + void * livestream (void * clo) + { + Cloud * cloud = (Cloud *) clo; + + while(cloud->m_livestreamThread_running) + { + pthread_mutex_lock(&cloud->m_capture_lock); + + if(cloud->m_capturedevice != 0) + { + while(cloud->fstream.isRequestingLiveStream()) + { + Image image = cloud->m_capturedevice->retrieve(); + cloud->fstream.forward(image); + usleep(200 * 1000); // 5 fps + //printf("Sending livestream.\n"); + } + + usleep(3000 * 1000); + } + + pthread_mutex_unlock(&cloud->m_capture_lock); + } + } + + void Cloud::startLivestreamThread() + { + m_livestreamThread_running = true; + pthread_create(&m_livestreamThread, NULL, livestream, this); + } + + void Cloud::stopLivestreamThread() + { + m_livestreamThread_running = false; + pthread_cancel(m_livestreamThread); + pthread_join(m_livestreamThread, NULL); + } } diff --git a/src/kerberos/cloud/ForwardStream.cpp b/src/kerberos/cloud/ForwardStream.cpp new file mode 100644 index 0000000..0ad75fc --- /dev/null +++ b/src/kerberos/cloud/ForwardStream.cpp @@ -0,0 +1,68 @@ +#include "cloud/ForwardStream.h" + +namespace kerberos +{ + void ForwardStream::setup(std::string publicKey, std::string deviceKey) + { + std::string ip = "37.139.29.235"; + int port = 1883; + m_publicKey = publicKey; + m_deviceKey = deviceKey; + setTopic("kerberos/" + m_publicKey + "/device/" + m_deviceKey + "/live"); + reinitialise(m_publicKey.c_str(), true); + mosqpp::lib_init(); + username_pw_set(publicKey.c_str(),nullptr); + connect_async(ip.c_str(), port); + loop_start(); + + std::string timestamp = kerberos::helper::getTimestamp(); + m_lastReceived = std::stoi(timestamp) - 10; + + m_encode_params.push_back(cv::IMWRITE_JPEG_QUALITY); + m_encode_params.push_back(20); + } + + bool ForwardStream::forward(Image & cleanImage) + { + cv::Mat img = cleanImage.getImage(); + + std::vector buf; + cv::imencode(".jpg", img, buf, m_encode_params); + uchar *enc_msg = new uchar[buf.size()]; + for(int i=0; i < buf.size(); i++) enc_msg[i] = buf[i]; + std::string encoded = base64_encode(enc_msg, buf.size()); + + int ret = publish(NULL, getTopic(), encoded.size(), encoded.c_str(), 0 ,true); + return (ret == MOSQ_ERR_SUCCESS); + } + + bool ForwardStream::isRequestingLiveStream() + { + std::string t = kerberos::helper::getTimestamp(); + int timestamp = std::stoi(t); + return timestamp - m_lastReceived < 10; + } + + void ForwardStream::on_connect(int rc) + { + //printf("Connected with code %d.\n", rc); + if(rc == 0) + { + std::string topic = "kerberos/" + m_publicKey + "/device/" + m_deviceKey + "/request-live"; + subscribe(NULL, topic.c_str()); + } + } + + void ForwardStream::on_message(const struct mosquitto_message *message) + { + //printf("Receive succeeded %s.\n", message->topic); + std::string timestamp = kerberos::helper::getTimestamp(); + m_lastReceived = std::stoi(timestamp); + } + + void ForwardStream::on_subscribe(int mid, int qos_count, const int *granted_qos) + { + //printf("Subscription succeeded.\n"); + } + +} From 6312613aedf73b5dde4e65895d87864b3bcaa827 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Verstraeten?= Date: Thu, 3 May 2018 19:18:31 +0200 Subject: [PATCH 02/35] max size + fix for locking --- include/kerberos/cloud/ForwardStream.h | 1 + src/kerberos/cloud/Cloud.cpp | 8 +++--- src/kerberos/cloud/ForwardStream.cpp | 34 ++++++++++++++++++++++++-- 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/include/kerberos/cloud/ForwardStream.h b/include/kerberos/cloud/ForwardStream.h index 643a362..43f7d7a 100644 --- a/include/kerberos/cloud/ForwardStream.h +++ b/include/kerberos/cloud/ForwardStream.h @@ -56,6 +56,7 @@ namespace kerberos unsigned short getPort(){return m_port;}; void setTopic(std::string topic){m_topic=topic;}; const char * getTopic(){return m_topic.c_str();}; + cv::Mat GetSquareImage(const cv::Mat& img, int target_width = 500); bool forward(Image & cleanImage); bool isRequestingLiveStream(); diff --git a/src/kerberos/cloud/Cloud.cpp b/src/kerberos/cloud/Cloud.cpp index 3163134..09ba190 100755 --- a/src/kerberos/cloud/Cloud.cpp +++ b/src/kerberos/cloud/Cloud.cpp @@ -341,20 +341,20 @@ namespace kerberos { pthread_mutex_lock(&cloud->m_capture_lock); - if(cloud->m_capturedevice != 0) + while(cloud->fstream.isRequestingLiveStream()) { - while(cloud->fstream.isRequestingLiveStream()) + if(cloud->m_capturedevice != 0) { Image image = cloud->m_capturedevice->retrieve(); cloud->fstream.forward(image); usleep(200 * 1000); // 5 fps //printf("Sending livestream.\n"); } - - usleep(3000 * 1000); } pthread_mutex_unlock(&cloud->m_capture_lock); + + usleep(3000 * 1000); } } diff --git a/src/kerberos/cloud/ForwardStream.cpp b/src/kerberos/cloud/ForwardStream.cpp index 0ad75fc..f7a5bed 100644 --- a/src/kerberos/cloud/ForwardStream.cpp +++ b/src/kerberos/cloud/ForwardStream.cpp @@ -19,12 +19,42 @@ namespace kerberos m_lastReceived = std::stoi(timestamp) - 10; m_encode_params.push_back(cv::IMWRITE_JPEG_QUALITY); - m_encode_params.push_back(20); + m_encode_params.push_back(50); + } + + cv::Mat ForwardStream::GetSquareImage(const cv::Mat& img, int target_width) + { + int width = img.cols, + height = img.rows; + + cv::Mat square = cv::Mat::zeros( target_width, target_width, img.type() ); + + int max_dim = ( width >= height ) ? width : height; + float scale = ( ( float ) target_width ) / max_dim; + cv::Rect roi; + if ( width >= height ) + { + roi.width = target_width; + roi.x = 0; + roi.height = height * scale; + roi.y = ( target_width - roi.height ) / 2; + } + else + { + roi.y = 0; + roi.height = target_width; + roi.width = width * scale; + roi.x = ( target_width - roi.width ) / 2; + } + + cv::resize( img, square( roi ), roi.size() ); + + return square; } bool ForwardStream::forward(Image & cleanImage) { - cv::Mat img = cleanImage.getImage(); + cv::Mat img = GetSquareImage(cleanImage.getImage(), 250); std::vector buf; cv::imencode(".jpg", img, buf, m_encode_params); From d833b04ce699e15ad4009251b2e9d800be62f89b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Verstraeten?= Date: Thu, 3 May 2018 20:47:42 +0200 Subject: [PATCH 03/35] 1 fps --- src/kerberos/cloud/Cloud.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/kerberos/cloud/Cloud.cpp b/src/kerberos/cloud/Cloud.cpp index 09ba190..382ef17 100755 --- a/src/kerberos/cloud/Cloud.cpp +++ b/src/kerberos/cloud/Cloud.cpp @@ -347,13 +347,13 @@ namespace kerberos { Image image = cloud->m_capturedevice->retrieve(); cloud->fstream.forward(image); - usleep(200 * 1000); // 5 fps + usleep(1000 * 1000); // 1 fps //printf("Sending livestream.\n"); } } pthread_mutex_unlock(&cloud->m_capture_lock); - + usleep(3000 * 1000); } } From e0eb5977522cc87c2ec539ac9b5e6c7821c8e1c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Verstraeten?= Date: Thu, 3 May 2018 21:19:16 +0200 Subject: [PATCH 04/35] replace save key --- src/kerberos/cloud/Cloud.cpp | 50 ++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/kerberos/cloud/Cloud.cpp b/src/kerberos/cloud/Cloud.cpp index 382ef17..d2a98b1 100755 --- a/src/kerberos/cloud/Cloud.cpp +++ b/src/kerberos/cloud/Cloud.cpp @@ -52,6 +52,31 @@ namespace kerberos setProductKey(""); } + // ----------------------------------- + // Check if we need to generate a + // new product key (first time running) + + if(m_productKey == "") + { + // Generate random key + std::string key = helper::random_string(26); + + // Create product key file + std::string command = "touch " + m_keyFile; + std::string createProductKeyFile = helper::GetStdoutFromCommand(command); + BINFO << "Cloud: create key file"; + + // Write product key + command = "echo " + key + " > " + m_keyFile; + std::string writeProductKey = helper::GetStdoutFromCommand(command); + BINFO << "Cloud: write key"; + + // Reset key + setProductKey(key); + + BINFO << "Cloud: reset product key (" << key << ")"; + } + startPollThread(); startUploadThread(); @@ -213,31 +238,6 @@ namespace kerberos headers["Content-Type"] = "application/json"; conn->SetHeaders(headers); - // ----------------------------------- - // Check if we need to generate a - // new product key (first time running) - - if(cloud->m_productKey == "") - { - // Generate random key - std::string key = helper::random_string(26); - - // Create product key file - std::string command = "touch " + cloud->m_keyFile; - std::string createProductKeyFile = helper::GetStdoutFromCommand(command); - BINFO << "Cloud: create key file"; - - // Write product key - command = "echo " + key + " > " + cloud->m_keyFile; - std::string writeProductKey = helper::GetStdoutFromCommand(command); - BINFO << "Cloud: write key"; - - // Reset key - cloud->setProductKey(key); - - BINFO << "Cloud: reset product key (" << key << ")"; - } - // -------------------------------------------- // Start livestreaming /*std::cout << cloud->m_publicKey << std::endl; From 0610125c7ae234ccc1c39ecc44a36b874ea75aeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Verstraeten?= Date: Fri, 4 May 2018 13:44:51 +0200 Subject: [PATCH 05/35] Update ForwardStream.cpp --- src/kerberos/cloud/ForwardStream.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kerberos/cloud/ForwardStream.cpp b/src/kerberos/cloud/ForwardStream.cpp index f7a5bed..e3d5711 100644 --- a/src/kerberos/cloud/ForwardStream.cpp +++ b/src/kerberos/cloud/ForwardStream.cpp @@ -4,7 +4,7 @@ namespace kerberos { void ForwardStream::setup(std::string publicKey, std::string deviceKey) { - std::string ip = "37.139.29.235"; + std::string ip = "159.65.233.50"; int port = 1883; m_publicKey = publicKey; m_deviceKey = deviceKey; From 4b7018ff10992d11c9580ae9f17cff1a4235cb0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Verstraeten?= Date: Fri, 4 May 2018 21:05:11 +0200 Subject: [PATCH 06/35] fix --- src/kerberos/cloud/Cloud.cpp | 7 ++++--- src/kerberos/cloud/ForwardStream.cpp | 10 ++++++---- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/kerberos/cloud/Cloud.cpp b/src/kerberos/cloud/Cloud.cpp index d2a98b1..dc2631a 100755 --- a/src/kerberos/cloud/Cloud.cpp +++ b/src/kerberos/cloud/Cloud.cpp @@ -347,14 +347,15 @@ namespace kerberos { Image image = cloud->m_capturedevice->retrieve(); cloud->fstream.forward(image); - usleep(1000 * 1000); // 1 fps - //printf("Sending livestream.\n"); + printf("Sending livestream.\n"); } + + usleep(300 * 1000); // 3 fps } pthread_mutex_unlock(&cloud->m_capture_lock); - usleep(3000 * 1000); + usleep(1000 * 1000); } } diff --git a/src/kerberos/cloud/ForwardStream.cpp b/src/kerberos/cloud/ForwardStream.cpp index e3d5711..4920d54 100644 --- a/src/kerberos/cloud/ForwardStream.cpp +++ b/src/kerberos/cloud/ForwardStream.cpp @@ -9,9 +9,11 @@ namespace kerberos m_publicKey = publicKey; m_deviceKey = deviceKey; setTopic("kerberos/" + m_publicKey + "/device/" + m_deviceKey + "/live"); - reinitialise(m_publicKey.c_str(), true); + + std::string clientId = publicKey + "-" + kerberos::helper::getTimestamp() + "-" + kerberos::helper::getMicroseconds(); mosqpp::lib_init(); - username_pw_set(publicKey.c_str(),nullptr); + reinitialise(clientId.c_str(), true); + username_pw_set(clientId.c_str(),nullptr); connect_async(ip.c_str(), port); loop_start(); @@ -19,7 +21,7 @@ namespace kerberos m_lastReceived = std::stoi(timestamp) - 10; m_encode_params.push_back(cv::IMWRITE_JPEG_QUALITY); - m_encode_params.push_back(50); + m_encode_params.push_back(70); } cv::Mat ForwardStream::GetSquareImage(const cv::Mat& img, int target_width) @@ -62,7 +64,7 @@ namespace kerberos for(int i=0; i < buf.size(); i++) enc_msg[i] = buf[i]; std::string encoded = base64_encode(enc_msg, buf.size()); - int ret = publish(NULL, getTopic(), encoded.size(), encoded.c_str(), 0 ,true); + int ret = publish(NULL, getTopic(), encoded.size(), encoded.c_str(), 2 ,false); return (ret == MOSQ_ERR_SUCCESS); } From 3344b6d913874907aa5ad0745134499ad15a116f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Verstraeten?= Date: Mon, 7 May 2018 15:11:29 +0200 Subject: [PATCH 07/35] change ip + hardware encoding if possible --- include/kerberos/cloud/ForwardStream.h | 1 + src/kerberos/cloud/Cloud.cpp | 18 ++++++++++++++---- src/kerberos/cloud/ForwardStream.cpp | 13 ++++++++++--- 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/include/kerberos/cloud/ForwardStream.h b/include/kerberos/cloud/ForwardStream.h index 43f7d7a..4922441 100644 --- a/include/kerberos/cloud/ForwardStream.h +++ b/include/kerberos/cloud/ForwardStream.h @@ -58,6 +58,7 @@ namespace kerberos const char * getTopic(){return m_topic.c_str();}; cv::Mat GetSquareImage(const cv::Mat& img, int target_width = 500); bool forward(Image & cleanImage); + bool forwardRAW(uint8_t * data, int32_t length); bool isRequestingLiveStream(); void on_connect(int rc); diff --git a/src/kerberos/cloud/Cloud.cpp b/src/kerberos/cloud/Cloud.cpp index dc2631a..e6ce0ec 100755 --- a/src/kerberos/cloud/Cloud.cpp +++ b/src/kerberos/cloud/Cloud.cpp @@ -337,6 +337,9 @@ namespace kerberos { Cloud * cloud = (Cloud *) clo; + uint8_t * data = new uint8_t[(int)(1280*960*1.5)]; + int32_t length = cloud->m_capturedevice->retrieveRAW(data); + while(cloud->m_livestreamThread_running) { pthread_mutex_lock(&cloud->m_capture_lock); @@ -345,12 +348,19 @@ namespace kerberos { if(cloud->m_capturedevice != 0) { - Image image = cloud->m_capturedevice->retrieve(); - cloud->fstream.forward(image); - printf("Sending livestream.\n"); + if(cloud->m_capturedevice->m_hardwareMJPEGEncoding) + { + length = cloud->m_capturedevice->retrieveRAW(data); + cloud->fstream.forwardRAW(data, length); + } + else + { + Image image = cloud->m_capturedevice->retrieve(); + cloud->fstream.forward(image); + } } - usleep(300 * 1000); // 3 fps + usleep(100 * 1000); // 10 fps } pthread_mutex_unlock(&cloud->m_capture_lock); diff --git a/src/kerberos/cloud/ForwardStream.cpp b/src/kerberos/cloud/ForwardStream.cpp index 4920d54..edd7c3d 100644 --- a/src/kerberos/cloud/ForwardStream.cpp +++ b/src/kerberos/cloud/ForwardStream.cpp @@ -4,7 +4,7 @@ namespace kerberos { void ForwardStream::setup(std::string publicKey, std::string deviceKey) { - std::string ip = "159.65.233.50"; + std::string ip = "174.138.111.149"; int port = 1883; m_publicKey = publicKey; m_deviceKey = deviceKey; @@ -21,7 +21,7 @@ namespace kerberos m_lastReceived = std::stoi(timestamp) - 10; m_encode_params.push_back(cv::IMWRITE_JPEG_QUALITY); - m_encode_params.push_back(70); + m_encode_params.push_back(85); } cv::Mat ForwardStream::GetSquareImage(const cv::Mat& img, int target_width) @@ -56,7 +56,7 @@ namespace kerberos bool ForwardStream::forward(Image & cleanImage) { - cv::Mat img = GetSquareImage(cleanImage.getImage(), 250); + cv::Mat img = GetSquareImage(cleanImage.getImage(), 400); std::vector buf; cv::imencode(".jpg", img, buf, m_encode_params); @@ -68,6 +68,13 @@ namespace kerberos return (ret == MOSQ_ERR_SUCCESS); } + bool ForwardStream::forwardRAW(uint8_t * data, int32_t length) + { + std::string encoded = base64_encode((uchar *) data, length); + int ret = publish(NULL, getTopic(), encoded.size(), encoded.c_str(), 2 ,false); + return (ret == MOSQ_ERR_SUCCESS); + } + bool ForwardStream::isRequestingLiveStream() { std::string t = kerberos::helper::getTimestamp(); From a5d916787d91b277d6ca25a18ddede50f2e8e7da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Verstraeten?= Date: Mon, 7 May 2018 17:03:46 +0200 Subject: [PATCH 08/35] lower fps --- src/kerberos/cloud/Cloud.cpp | 2 +- src/kerberos/cloud/ForwardStream.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/kerberos/cloud/Cloud.cpp b/src/kerberos/cloud/Cloud.cpp index e6ce0ec..72a3547 100755 --- a/src/kerberos/cloud/Cloud.cpp +++ b/src/kerberos/cloud/Cloud.cpp @@ -360,7 +360,7 @@ namespace kerberos } } - usleep(100 * 1000); // 10 fps + usleep(300 * 1000); // 3 fps } pthread_mutex_unlock(&cloud->m_capture_lock); diff --git a/src/kerberos/cloud/ForwardStream.cpp b/src/kerberos/cloud/ForwardStream.cpp index edd7c3d..49307d1 100644 --- a/src/kerberos/cloud/ForwardStream.cpp +++ b/src/kerberos/cloud/ForwardStream.cpp @@ -21,7 +21,7 @@ namespace kerberos m_lastReceived = std::stoi(timestamp) - 10; m_encode_params.push_back(cv::IMWRITE_JPEG_QUALITY); - m_encode_params.push_back(85); + m_encode_params.push_back(75); } cv::Mat ForwardStream::GetSquareImage(const cv::Mat& img, int target_width) From a062bf0e393856fb9362acb3f79521b46d72c350 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Verstraeten?= Date: Mon, 7 May 2018 18:50:16 +0200 Subject: [PATCH 09/35] revert --- src/kerberos/cloud/Cloud.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/kerberos/cloud/Cloud.cpp b/src/kerberos/cloud/Cloud.cpp index 72a3547..61fbcb1 100755 --- a/src/kerberos/cloud/Cloud.cpp +++ b/src/kerberos/cloud/Cloud.cpp @@ -348,19 +348,19 @@ namespace kerberos { if(cloud->m_capturedevice != 0) { - if(cloud->m_capturedevice->m_hardwareMJPEGEncoding) - { - length = cloud->m_capturedevice->retrieveRAW(data); - cloud->fstream.forwardRAW(data, length); - } - else - { + //if(cloud->m_capturedevice->m_hardwareMJPEGEncoding) + //{ + // length = cloud->m_capturedevice->retrieveRAW(data); + // cloud->fstream.forwardRAW(data, length); + //} + //else + //{ Image image = cloud->m_capturedevice->retrieve(); cloud->fstream.forward(image); - } + //} } - usleep(300 * 1000); // 3 fps + usleep(333 * 1000); // 3 fps } pthread_mutex_unlock(&cloud->m_capture_lock); From 1ac88f9e6b8ed7c1b5e522e91de7336a572ceea8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Verstraeten?= Date: Mon, 7 May 2018 21:36:58 +0200 Subject: [PATCH 10/35] decrease --- src/kerberos/cloud/ForwardStream.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kerberos/cloud/ForwardStream.cpp b/src/kerberos/cloud/ForwardStream.cpp index 49307d1..5525f4b 100644 --- a/src/kerberos/cloud/ForwardStream.cpp +++ b/src/kerberos/cloud/ForwardStream.cpp @@ -56,7 +56,7 @@ namespace kerberos bool ForwardStream::forward(Image & cleanImage) { - cv::Mat img = GetSquareImage(cleanImage.getImage(), 400); + cv::Mat img = GetSquareImage(cleanImage.getImage(), 300); std::vector buf; cv::imencode(".jpg", img, buf, m_encode_params); From 02b45201502b8a714bce83df84afda30adfd1113 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Verstraeten?= Date: Wed, 9 May 2018 13:36:45 +0200 Subject: [PATCH 11/35] increase quality, lower FPS --- src/kerberos/cloud/Cloud.cpp | 2 +- src/kerberos/cloud/ForwardStream.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/kerberos/cloud/Cloud.cpp b/src/kerberos/cloud/Cloud.cpp index 61fbcb1..d5a5ef7 100755 --- a/src/kerberos/cloud/Cloud.cpp +++ b/src/kerberos/cloud/Cloud.cpp @@ -360,7 +360,7 @@ namespace kerberos //} } - usleep(333 * 1000); // 3 fps + usleep(1000 * 1000); // 1 fps } pthread_mutex_unlock(&cloud->m_capture_lock); diff --git a/src/kerberos/cloud/ForwardStream.cpp b/src/kerberos/cloud/ForwardStream.cpp index 5525f4b..ef51526 100644 --- a/src/kerberos/cloud/ForwardStream.cpp +++ b/src/kerberos/cloud/ForwardStream.cpp @@ -21,7 +21,7 @@ namespace kerberos m_lastReceived = std::stoi(timestamp) - 10; m_encode_params.push_back(cv::IMWRITE_JPEG_QUALITY); - m_encode_params.push_back(75); + m_encode_params.push_back(90); } cv::Mat ForwardStream::GetSquareImage(const cv::Mat& img, int target_width) @@ -56,7 +56,7 @@ namespace kerberos bool ForwardStream::forward(Image & cleanImage) { - cv::Mat img = GetSquareImage(cleanImage.getImage(), 300); + cv::Mat img = GetSquareImage(cleanImage.getImage(), 500); std::vector buf; cv::imencode(".jpg", img, buf, m_encode_params); From 267b8bb772d99ad81d1dfd1f6de8c8e65dccd64c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Verstraeten?= Date: Mon, 14 May 2018 21:52:45 +0200 Subject: [PATCH 12/35] decrease resolution --- src/kerberos/cloud/ForwardStream.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/kerberos/cloud/ForwardStream.cpp b/src/kerberos/cloud/ForwardStream.cpp index ef51526..8d44831 100644 --- a/src/kerberos/cloud/ForwardStream.cpp +++ b/src/kerberos/cloud/ForwardStream.cpp @@ -18,10 +18,14 @@ namespace kerberos loop_start(); std::string timestamp = kerberos::helper::getTimestamp(); - m_lastReceived = std::stoi(timestamp) - 10; + m_lastReceived = std::stoi(timestamp) - 5; m_encode_params.push_back(cv::IMWRITE_JPEG_QUALITY); +<<<<<<< Updated upstream m_encode_params.push_back(90); +======= + m_encode_params.push_back(65); +>>>>>>> Stashed changes } cv::Mat ForwardStream::GetSquareImage(const cv::Mat& img, int target_width) @@ -56,7 +60,11 @@ namespace kerberos bool ForwardStream::forward(Image & cleanImage) { +<<<<<<< Updated upstream cv::Mat img = GetSquareImage(cleanImage.getImage(), 500); +======= + cv::Mat img = GetSquareImage(cleanImage.getImage(), 200); +>>>>>>> Stashed changes std::vector buf; cv::imencode(".jpg", img, buf, m_encode_params); From c52e3b22108a6bfbb81a8262c047a1981b428577 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Verstraeten?= Date: Mon, 14 May 2018 22:28:12 +0200 Subject: [PATCH 13/35] fix --- src/kerberos/cloud/ForwardStream.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/kerberos/cloud/ForwardStream.cpp b/src/kerberos/cloud/ForwardStream.cpp index 8d44831..0a2629c 100644 --- a/src/kerberos/cloud/ForwardStream.cpp +++ b/src/kerberos/cloud/ForwardStream.cpp @@ -21,11 +21,7 @@ namespace kerberos m_lastReceived = std::stoi(timestamp) - 5; m_encode_params.push_back(cv::IMWRITE_JPEG_QUALITY); -<<<<<<< Updated upstream - m_encode_params.push_back(90); -======= m_encode_params.push_back(65); ->>>>>>> Stashed changes } cv::Mat ForwardStream::GetSquareImage(const cv::Mat& img, int target_width) @@ -60,11 +56,7 @@ namespace kerberos bool ForwardStream::forward(Image & cleanImage) { -<<<<<<< Updated upstream - cv::Mat img = GetSquareImage(cleanImage.getImage(), 500); -======= cv::Mat img = GetSquareImage(cleanImage.getImage(), 200); ->>>>>>> Stashed changes std::vector buf; cv::imencode(".jpg", img, buf, m_encode_params); From 01a43bcff65965c012ff0d09c6a26cec7dc10562 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Verstraeten?= Date: Wed, 16 May 2018 15:10:33 +0200 Subject: [PATCH 14/35] convert to gray --- src/kerberos/cloud/ForwardStream.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/kerberos/cloud/ForwardStream.cpp b/src/kerberos/cloud/ForwardStream.cpp index 0a2629c..cc66fad 100644 --- a/src/kerberos/cloud/ForwardStream.cpp +++ b/src/kerberos/cloud/ForwardStream.cpp @@ -21,7 +21,7 @@ namespace kerberos m_lastReceived = std::stoi(timestamp) - 5; m_encode_params.push_back(cv::IMWRITE_JPEG_QUALITY); - m_encode_params.push_back(65); + m_encode_params.push_back(75); } cv::Mat ForwardStream::GetSquareImage(const cv::Mat& img, int target_width) @@ -56,7 +56,8 @@ namespace kerberos bool ForwardStream::forward(Image & cleanImage) { - cv::Mat img = GetSquareImage(cleanImage.getImage(), 200); + cv::Mat img = GetSquareImage(cleanImage.getImage(), 300); + cvtColor(img, img, CV_RGB2GRAY); std::vector buf; cv::imencode(".jpg", img, buf, m_encode_params); @@ -79,7 +80,7 @@ namespace kerberos { std::string t = kerberos::helper::getTimestamp(); int timestamp = std::stoi(t); - return timestamp - m_lastReceived < 10; + return timestamp - m_lastReceived < 5; } void ForwardStream::on_connect(int rc) From 520c1316be42321a9e4e5926ee7841aec284fe83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Verstraeten?= Date: Wed, 16 May 2018 20:41:50 +0200 Subject: [PATCH 15/35] resize --- src/kerberos/cloud/ForwardStream.cpp | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/kerberos/cloud/ForwardStream.cpp b/src/kerberos/cloud/ForwardStream.cpp index cc66fad..8f7deb9 100644 --- a/src/kerberos/cloud/ForwardStream.cpp +++ b/src/kerberos/cloud/ForwardStream.cpp @@ -21,7 +21,7 @@ namespace kerberos m_lastReceived = std::stoi(timestamp) - 5; m_encode_params.push_back(cv::IMWRITE_JPEG_QUALITY); - m_encode_params.push_back(75); + m_encode_params.push_back(55); } cv::Mat ForwardStream::GetSquareImage(const cv::Mat& img, int target_width) @@ -56,11 +56,24 @@ namespace kerberos bool ForwardStream::forward(Image & cleanImage) { - cv::Mat img = GetSquareImage(cleanImage.getImage(), 300); - cvtColor(img, img, CV_RGB2GRAY); + cv::Mat & img = cleanImage.getImage(); + + int maxWidth = 300; + int newWidth = img.cols; + int newHeight = img.rows; + + if(newWidth > maxWidth) { + double ratio = newWidth / maxWidth; + newWidth = newWidth / ratio; + newHeight = newHeight / ratio; + } + + cv::resize(img, img, cv::Size(newWidth,newHeight)); + cv::Mat grayImg(img.cols, img.rows, CV_8UC1); + cvtColor(img, grayImg, cv::COLOR_RGB2GRAY); std::vector buf; - cv::imencode(".jpg", img, buf, m_encode_params); + cv::imencode(".jpg", grayImg, buf, m_encode_params); uchar *enc_msg = new uchar[buf.size()]; for(int i=0; i < buf.size(); i++) enc_msg[i] = buf[i]; std::string encoded = base64_encode(enc_msg, buf.size()); From 03d4004767c07c8f007ec49108e2f36f74cfcf29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Verstraeten?= Date: Wed, 16 May 2018 22:25:54 +0200 Subject: [PATCH 16/35] change ip --- src/kerberos/cloud/ForwardStream.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kerberos/cloud/ForwardStream.cpp b/src/kerberos/cloud/ForwardStream.cpp index 8f7deb9..235db04 100644 --- a/src/kerberos/cloud/ForwardStream.cpp +++ b/src/kerberos/cloud/ForwardStream.cpp @@ -4,7 +4,7 @@ namespace kerberos { void ForwardStream::setup(std::string publicKey, std::string deviceKey) { - std::string ip = "174.138.111.149"; + std::string ip = "178.62.38.102"; int port = 1883; m_publicKey = publicKey; m_deviceKey = deviceKey; From f5cea60901e676f322c56a8ea5e264f8f7a578f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Verstraeten?= Date: Thu, 17 May 2018 22:46:23 +0200 Subject: [PATCH 17/35] send a motion trigger if set a public key --- include/kerberos/cloud/ForwardStream.h | 4 ++++ src/kerberos/Kerberos.cpp | 9 +++++++++ src/kerberos/cloud/ForwardStream.cpp | 8 ++++++++ 3 files changed, 21 insertions(+) diff --git a/include/kerberos/cloud/ForwardStream.h b/include/kerberos/cloud/ForwardStream.h index 4922441..09a7d36 100644 --- a/include/kerberos/cloud/ForwardStream.h +++ b/include/kerberos/cloud/ForwardStream.h @@ -34,6 +34,7 @@ namespace kerberos std::string m_server_ip; unsigned short m_port; std::string m_topic; + std::string m_motion_topic; std::vector m_encode_params; public: @@ -56,9 +57,12 @@ namespace kerberos unsigned short getPort(){return m_port;}; void setTopic(std::string topic){m_topic=topic;}; const char * getTopic(){return m_topic.c_str();}; + void setMotionTopic(std::string motion_topic){m_motion_topic=motion_topic;}; + const char * getMotionTopic(){return m_motion_topic.c_str();}; cv::Mat GetSquareImage(const cv::Mat& img, int target_width = 500); bool forward(Image & cleanImage); bool forwardRAW(uint8_t * data, int32_t length); + bool triggerMotion(); bool isRequestingLiveStream(); void on_connect(int rc); diff --git a/src/kerberos/Kerberos.cpp b/src/kerberos/Kerberos.cpp index 3f2ff88..7e76c92 100755 --- a/src/kerberos/Kerberos.cpp +++ b/src/kerberos/Kerberos.cpp @@ -78,6 +78,15 @@ namespace kerberos Detection detection(toJSON(data), cleanImage); m_detections.push_back(detection); + // ----------------------------------------------- + // If we have a cloud account, send a notification + // to the cloud app. + + if(cloud && cloud->m_publicKey != "") + { + cloud->fstream.triggerMotion(); + } + pthread_mutex_unlock(&m_ioLock); } diff --git a/src/kerberos/cloud/ForwardStream.cpp b/src/kerberos/cloud/ForwardStream.cpp index 235db04..b090bf8 100644 --- a/src/kerberos/cloud/ForwardStream.cpp +++ b/src/kerberos/cloud/ForwardStream.cpp @@ -9,6 +9,7 @@ namespace kerberos m_publicKey = publicKey; m_deviceKey = deviceKey; setTopic("kerberos/" + m_publicKey + "/device/" + m_deviceKey + "/live"); + setMotionTopic("kerberos/" + m_publicKey + "/device/" + m_deviceKey + "/motion"); std::string clientId = publicKey + "-" + kerberos::helper::getTimestamp() + "-" + kerberos::helper::getMicroseconds(); mosqpp::lib_init(); @@ -113,6 +114,13 @@ namespace kerberos m_lastReceived = std::stoi(timestamp); } + bool ForwardStream::triggerMotion() + { + std::string motion = "motion"; + int ret = publish(NULL, getMotionTopic(), motion.size(), motion.c_str(), 2 ,false); + return (ret == MOSQ_ERR_SUCCESS); + } + void ForwardStream::on_subscribe(int mid, int qos_count, const int *granted_qos) { //printf("Subscription succeeded.\n"); From cd36a10f1ecc5b8839e6f07539ede74c981a9105 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Verstraeten?= Date: Thu, 17 May 2018 23:10:42 +0200 Subject: [PATCH 18/35] add throttler --- include/kerberos/cloud/ForwardStream.h | 2 ++ src/kerberos/cloud/ForwardStream.cpp | 12 +++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/include/kerberos/cloud/ForwardStream.h b/include/kerberos/cloud/ForwardStream.h index 09a7d36..f76436f 100644 --- a/include/kerberos/cloud/ForwardStream.h +++ b/include/kerberos/cloud/ForwardStream.h @@ -25,6 +25,7 @@ #include "writer.h" #include "base64.h" #include "Helper.h" +#include "machinery/io/Throttler.h" namespace kerberos { @@ -49,6 +50,7 @@ namespace kerberos std::string m_publicKey; std::string m_deviceKey; int m_lastReceived; + Throttler throttle; void setup(std::string publickey, std::string deviceKey); void setIp(const std::string server_ip){m_server_ip=server_ip;}; diff --git a/src/kerberos/cloud/ForwardStream.cpp b/src/kerberos/cloud/ForwardStream.cpp index b090bf8..4ac2e39 100644 --- a/src/kerberos/cloud/ForwardStream.cpp +++ b/src/kerberos/cloud/ForwardStream.cpp @@ -8,6 +8,7 @@ namespace kerberos int port = 1883; m_publicKey = publicKey; m_deviceKey = deviceKey; + throttle.setRate(10); setTopic("kerberos/" + m_publicKey + "/device/" + m_deviceKey + "/live"); setMotionTopic("kerberos/" + m_publicKey + "/device/" + m_deviceKey + "/motion"); @@ -116,9 +117,14 @@ namespace kerberos bool ForwardStream::triggerMotion() { - std::string motion = "motion"; - int ret = publish(NULL, getMotionTopic(), motion.size(), motion.c_str(), 2 ,false); - return (ret == MOSQ_ERR_SUCCESS); + if(throttle.canExecute()) + { + std::string motion = "motion"; + int ret = publish(NULL, getMotionTopic(), motion.size(), motion.c_str(), 2 ,false); + return (ret == MOSQ_ERR_SUCCESS); + } + + return false; } void ForwardStream::on_subscribe(int mid, int qos_count, const int *granted_qos) From 2e568239d173c9ddc970dbd9634c315d5c2a9138 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Verstraeten?= Date: Fri, 18 May 2018 20:03:58 +0200 Subject: [PATCH 19/35] increase quality disable gray image --- src/kerberos/Kerberos.cpp | 1 - src/kerberos/cloud/ForwardStream.cpp | 8 ++++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/kerberos/Kerberos.cpp b/src/kerberos/Kerberos.cpp index 7e76c92..95f2ec1 100755 --- a/src/kerberos/Kerberos.cpp +++ b/src/kerberos/Kerberos.cpp @@ -29,7 +29,6 @@ namespace kerberos std::string file = configuration.substr(configuration.rfind('/')+1); guard = new FW::Guard(); guard->listenTo(directory, file); - guard->onChange(&Kerberos::reconfigure); guard->start(); diff --git a/src/kerberos/cloud/ForwardStream.cpp b/src/kerberos/cloud/ForwardStream.cpp index 4ac2e39..f63d804 100644 --- a/src/kerberos/cloud/ForwardStream.cpp +++ b/src/kerberos/cloud/ForwardStream.cpp @@ -23,7 +23,7 @@ namespace kerberos m_lastReceived = std::stoi(timestamp) - 5; m_encode_params.push_back(cv::IMWRITE_JPEG_QUALITY); - m_encode_params.push_back(55); + m_encode_params.push_back(75); } cv::Mat ForwardStream::GetSquareImage(const cv::Mat& img, int target_width) @@ -71,11 +71,11 @@ namespace kerberos } cv::resize(img, img, cv::Size(newWidth,newHeight)); - cv::Mat grayImg(img.cols, img.rows, CV_8UC1); - cvtColor(img, grayImg, cv::COLOR_RGB2GRAY); + //cv::Mat grayImg(img.cols, img.rows, CV_8UC1); + //cvtColor(img, grayImg, cv::COLOR_RGB2GRAY); std::vector buf; - cv::imencode(".jpg", grayImg, buf, m_encode_params); + cv::imencode(".jpg", img, buf, m_encode_params); uchar *enc_msg = new uchar[buf.size()]; for(int i=0; i < buf.size(); i++) enc_msg[i] = buf[i]; std::string encoded = base64_encode(enc_msg, buf.size()); From 011c3cbbb6f6519fa468fd28ee97a218aeb5cb7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Verstraeten?= Date: Mon, 21 May 2018 09:58:07 +0200 Subject: [PATCH 20/35] smallbug --- src/kerberos/cloud/ForwardStream.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kerberos/cloud/ForwardStream.cpp b/src/kerberos/cloud/ForwardStream.cpp index f63d804..a1b973a 100644 --- a/src/kerberos/cloud/ForwardStream.cpp +++ b/src/kerberos/cloud/ForwardStream.cpp @@ -15,7 +15,7 @@ namespace kerberos std::string clientId = publicKey + "-" + kerberos::helper::getTimestamp() + "-" + kerberos::helper::getMicroseconds(); mosqpp::lib_init(); reinitialise(clientId.c_str(), true); - username_pw_set(clientId.c_str(),nullptr); + username_pw_set(publicKey.c_str(),nullptr); connect_async(ip.c_str(), port); loop_start(); From 1bf01bea644ec4ae2aca00a79a284d2c16e83c44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Verstraeten?= Date: Mon, 21 May 2018 10:45:52 +0200 Subject: [PATCH 21/35] add more logging to cloud uploading --- src/kerberos/cloud/S3.cpp | 25 ++++++++++++++++++++++--- src/main.cpp | 2 +- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/kerberos/cloud/S3.cpp b/src/kerberos/cloud/S3.cpp index ae6656f..ab28d1d 100755 --- a/src/kerberos/cloud/S3.cpp +++ b/src/kerberos/cloud/S3.cpp @@ -114,11 +114,13 @@ namespace kerberos // ---------------------------------------------- // Before send the headers, we need to sort them! + BINFO << "S3: Sending new file to cloud."; + std::sort(canonicalizedAmzHeaders.begin(), canonicalizedAmzHeaders.end()); for(int i = 0; i < canonicalizedAmzHeaders.size(); i++) { - LINFO << canonicalizedAmzHeaders[i]; + BINFO << "S3 - File info: " << canonicalizedAmzHeaders[i]; } return canonicalizedAmzHeaders; @@ -252,6 +254,8 @@ namespace kerberos // Check if file really was uploaded. // We'll query the S3 bucket and check if it's there. + BINFO << "S3: file succesfully uploaded."; + return doesExist(pathToImage); } @@ -260,9 +264,17 @@ namespace kerberos // User is not allowed to push with these credentials. // We remove the symbol. + BINFO << "S3: permission denied, your file wasn't uploaded."; + return true; } + + else { + + BINFO << "S3: file was not uploaded, something went wrong. Please check if you internet connectivity works."; + + } } return false; @@ -337,7 +349,7 @@ namespace kerberos curl_easy_setopt(curlHandle, CURLOPT_WRITEFUNCTION, write); curl_easy_setopt(curlHandle, CURLOPT_WRITEDATA, &output); - BINFO << "S3: checking is exists in bucket."; + BINFO << "S3: checking if file exists in bucket."; result = curl_easy_perform(curlHandle); //Perform long http_code = 0; @@ -345,7 +357,14 @@ namespace kerberos curl_easy_cleanup(curlHandle); curl_slist_free_all(httpHeaders); - return (http_code == 200 && result != CURLE_ABORTED_BY_CALLBACK); + if(http_code == 200 && result != CURLE_ABORTED_BY_CALLBACK) + { + BINFO << "S3: file exists in bucket, succesfully uploaded."; + return true; + } + + BINFO << "S3: file wasn't uploaded, something went wrong."; + return false; } return false; diff --git a/src/main.cpp b/src/main.cpp index 9fc3ba7..02fa2e4 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -60,7 +60,7 @@ int main(int argc, char** argv) config.setAll(easyloggingpp::ConfigurationType::ToFile, "true"); std::string logFile = (helper::getValueByKey(parameters, "log")) ?: LOG_PATH; config.setAll(easyloggingpp::ConfigurationType::Filename, logFile); - config.setAll(easyloggingpp::ConfigurationType::RollOutSize, "100000"); // 100MB + config.setAll(easyloggingpp::ConfigurationType::RollOutSize, "2048"); // 2KB easyloggingpp::Loggers::reconfigureAllLoggers(config); LINFO << "Logging is written to: " + logFile; From 4857b75cb4cc8e91f68bce399d32dce7493199ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Verstraeten?= Date: Mon, 21 May 2018 21:53:09 +0200 Subject: [PATCH 22/35] add new way of logging --- include/easylogging/easylogging++.h | 8190 +++++++++-------- include/kerberos/Kerberos.h | 2 +- src/CMakeLists.txt | 1 + src/easylogging/CMakeLists.txt | 7 + src/easylogging/easylogging++.cpp | 3104 +++++++ src/kerberos/Kerberos.cpp | 32 +- src/kerberos/capture/Capture.cpp | 7 +- src/kerberos/capture/IPCamera.cpp | 6 +- src/kerberos/capture/RaspiCamera.cpp | 16 +- src/kerberos/capture/Stream.cpp | 36 +- src/kerberos/capture/USBCamera.cpp | 6 +- src/kerberos/cloud/Cloud.cpp | 13 +- src/kerberos/cloud/S3.cpp | 18 +- src/kerberos/machinery/Machinery.cpp | 10 +- src/kerberos/machinery/condition/Enabled.cpp | 8 +- src/kerberos/machinery/condition/Time.cpp | 18 +- .../machinery/expositor/HullExpositor.cpp | 2 +- .../expositor/RectangleExpositor.cpp | 18 +- src/kerberos/machinery/heuristic/Counter.cpp | 62 +- src/kerberos/machinery/heuristic/Sequence.cpp | 6 +- src/kerberos/machinery/io/IoDisk.cpp | 2 +- src/kerberos/machinery/io/IoGPIO.cpp | 2 +- src/kerberos/machinery/io/IoMQTT.cpp | 2 +- src/kerberos/machinery/io/IoPushbullet.cpp | 30 +- src/kerberos/machinery/io/IoScript.cpp | 2 +- src/kerberos/machinery/io/IoTCP.cpp | 2 +- src/kerberos/machinery/io/IoVideo.cpp | 58 +- src/kerberos/machinery/io/IoWebhook.cpp | 2 +- src/main.cpp | 23 +- test/test_main.cpp | 17 +- 30 files changed, 7689 insertions(+), 4013 deletions(-) create mode 100644 src/easylogging/CMakeLists.txt create mode 100644 src/easylogging/easylogging++.cpp diff --git a/include/easylogging/easylogging++.h b/include/easylogging/easylogging++.h index 0a252f8..c425a44 100755 --- a/include/easylogging/easylogging++.h +++ b/include/easylogging/easylogging++.h @@ -1,296 +1,431 @@ -/////////////////////////////////////////////////////////////////////////////////// -// // -// easylogging++.h - Core of EasyLogging++ // -// // -// EasyLogging++ v8.91 // -// Cross platform logging made easy for C++ applications // -// Author Majid Khan // -// http://www.icplusplus.com/tools/easylogging // -// https://github.com/mkhan3189/EasyLoggingPP // -// // -// Copyright (c) 2012-2013 Majid Khan // -// // -// This software is provided 'as-is', without any express or implied // -// warranty. In no event will the authors be held liable for any damages // -// arising from the use of this software. // -// // -// Permission is granted to anyone to use this software for any purpose, // -// including commercial applications, and to alter it and redistribute // -// it freely, subject to the following restrictions: // -// // -// 1. The origin of this software must not be misrepresented; you must // -// not claim that you wrote the original software. If you use this // -// software in a product, an acknowledgment in the product documentation // -// would be appreciated but is not required. // -// // -// 2. Altered source versions must be plainly marked as such, and must // -// not be misrepresented as being the original software. // -// // -// 3. This notice may not be removed or altered from any source // -// distribution // -// // -// PLEASE NOTE: THIS FILE MAY BE CHANGED. TO GET ORIGINAL VERSION // -// EITHER DOWNLOAD IT FROM http://www.icplusplus.com/tools/easylogging/ // -// OR PULL IT FROM https://github.com/mkhan3189/EasyLoggingPP (master branch) // -// // -/////////////////////////////////////////////////////////////////////////////////// - -#ifndef EASYLOGGINGPP_H -#define EASYLOGGINGPP_H // -// Log location macros +// Bismillah ar-Rahmaan ar-Raheem // -#if !defined(__FILE__) -# define __FILE__ "" -#endif // !defined(__FILE__) -#if !defined(__LINE__) -# define __LINE__ 0 -#endif // !defined(__LINE__) -// Appropriate function macro -#if defined(__func__) -# undef __func__ -#endif // defined(__func__) -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# define __func__ __FUNCSIG__ -#elif defined(__GNUC__) && (__GNUC__ >= 2) -# define __func__ __PRETTY_FUNCTION__ -#elif defined(__clang__) && (__clang__ == 1) -# define __func__ __PRETTY_FUNCTION__ -#else -# define __func__ "" -#endif // defined(_MSC_VER) && (_MSC_VER >= 1020) +// Easylogging++ v9.96.4 +// Single-header only, cross-platform logging library for C++ applications // -// Compiler evaluation -// http://isocpp.org/blog/2013/05/gcc-4.8.1-released-c11-feature-complete -// http://msdn.microsoft.com/en-us/library/vstudio/hh567368.aspx +// Copyright (c) 2012-2018 Muflihun Labs +// Copyright (c) 2012-2018 @abumusamq // -// GNU -#if defined(__GNUC__) -# define _ELPP_GCC_VERSION (__GNUC__ * 10000 \ - + __GNUC_MINOR__ * 100 \ - + __GNUC_PATCHLEVEL__) -# if defined(__GXX_EXPERIMENTAL_CXX0X__) -# define _ELPP_CXX0X 1 -# elif (_ELPP_GCC_VERSION >= 40801) -# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) -#endif // defined(__GNUC__) -// VC++ -#if defined(_MSC_VER) -# if (_MSC_VER >= 1400) // VC++ 8.0 -# define _ELPP_CRT_DBG_WARNINGS 1 -# else -# define _ELPP_CRT_DBG_WARNINGS 0 -# endif // (_MSC_VER >= 1400) -# if (_MSC_VER == 1600) -# define _ELPP_CXX0X 1 -# elif (_MSC_VER == 1700) -# define _ELPP_CXX11 1 -# endif // (_MSC_VER == 1600) -#else -# define _ELPP_CRT_DBG_WARNINGS 0 -#endif // defined(_MSC_VER) -// Clang -#if defined(__clang__) && (__clang__ == 1) -# define _ELPP_CLANG_VERSION (__clang_major__ * 10000 \ - + __clang_minor__ * 100 \ - + __clang_patchlevel__) -# if (_ELPP_CLANG_VERSION >= 30300) -# define _ELPP_CXX11 1 -# endif // (_ELPP_CLANG_VERSION >= 30300) -#endif // defined(__clang__) && (__clang__ == 1) -// MinGW -#if defined(__MINGW32__) || defined(__MINGW64__) -# define _ELPP_MINGW 1 -#else -# define _ELPP_MINGW 0 -#endif // defined(__MINGW32__) || defined(__MINGW64__) -#if defined(__ANDROID__) -# define _ELPP_NDK 1 -#else -# define _ELPP_NDK 0 -#endif // defined(__ANDROID__) -// Some special functions that are special for VC++ -// This is to prevent CRT security warnings and to override deprecated methods but at the same time -// MinGW does not support some functions, so we need to make sure that proper function is used. -#if _ELPP_CRT_DBG_WARNINGS -# define SPRINTF sprintf_s -# define STRTOK(a,b,c) strtok_s(a,b,c) -#else -# define SPRINTF sprintf -# define STRTOK(a,b,c) strtok(a,b) -#endif -// std::thread availablity -#if defined(__GNUC__) && (!_ELPP_NDK) && (_ELPP_CXX0X || _ELPP_CXX11) -# define _ELPP_STD_THREAD_AVAILABLE 1 -#elif defined(_MSC_VER) && (!_ELPP_NDK) && (_ELPP_CXX11) -# define _ELPP_STD_THREAD_AVAILABLE 1 -#elif defined(__clang__) && (!_ELPP_NDK) && (__clang__ == 1) && (_ELPP_CXX11) -# define _ELPP_STD_THREAD_AVAILABLE 1 -#else -# define _ELPP_STD_THREAD_AVAILABLE 0 -#endif // defined(__GNUC__) && (_ELPP_CXX0X || _ELPP_CXX11) -// Qt -#if defined(QT_CORE_LIB) -# if (defined(QT_VERSION) && QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) -# define _ELPP_QT_5 1 -# else -# define _ELPP_QT_5 0 -# endif // (defined(QT_VERSION) && QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) -#endif // defined(QT_CORE_LIB) +// This library is released under the MIT Licence. +// https://github.com/muflihun/easyloggingpp/blob/master/LICENSE // -// High-level log evaluation +// https://github.com/muflihun/easyloggingpp +// https://muflihun.github.io/easyloggingpp +// http://muflihun.com // -#if (defined(_DISABLE_LOGS)) -# define _ENABLE_EASYLOGGING 0 + +#ifndef EASYLOGGINGPP_H +#define EASYLOGGINGPP_H +// Compilers and C++0x/C++11 Evaluation +#if __cplusplus >= 201103L +# define ELPP_CXX11 1 +#endif // __cplusplus >= 201103L +#if (defined(__GNUC__)) +# define ELPP_COMPILER_GCC 1 #else -# define _ENABLE_EASYLOGGING 1 -#endif // (!defined(_DISABLE_LOGS)) -// -// OS evaluation -// +# define ELPP_COMPILER_GCC 0 +#endif +#if ELPP_COMPILER_GCC +# define ELPP_GCC_VERSION (__GNUC__ * 10000 \ ++ __GNUC_MINOR__ * 100 \ ++ __GNUC_PATCHLEVEL__) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define ELPP_CXX0X 1 +# endif +#endif +// Visual C++ +#if defined(_MSC_VER) +# define ELPP_COMPILER_MSVC 1 +#else +# define ELPP_COMPILER_MSVC 0 +#endif +#define ELPP_CRT_DBG_WARNINGS ELPP_COMPILER_MSVC +#if ELPP_COMPILER_MSVC +# if (_MSC_VER == 1600) +# define ELPP_CXX0X 1 +# elif(_MSC_VER >= 1700) +# define ELPP_CXX11 1 +# endif +#endif +// Clang++ +#if (defined(__clang__) && (__clang__ == 1)) +# define ELPP_COMPILER_CLANG 1 +#else +# define ELPP_COMPILER_CLANG 0 +#endif +#if ELPP_COMPILER_CLANG +# if __has_include() +# include // Make __GLIBCXX__ defined when using libstdc++ +# if !defined(__GLIBCXX__) || __GLIBCXX__ >= 20150426 +# define ELPP_CLANG_SUPPORTS_THREAD +# endif // !defined(__GLIBCXX__) || __GLIBCXX__ >= 20150426 +# endif // __has_include() +#endif +#if (defined(__MINGW32__) || defined(__MINGW64__)) +# define ELPP_MINGW 1 +#else +# define ELPP_MINGW 0 +#endif +#if (defined(__CYGWIN__) && (__CYGWIN__ == 1)) +# define ELPP_CYGWIN 1 +#else +# define ELPP_CYGWIN 0 +#endif +#if (defined(__INTEL_COMPILER)) +# define ELPP_COMPILER_INTEL 1 +#else +# define ELPP_COMPILER_INTEL 0 +#endif +// Operating System Evaluation // Windows -#if defined(_WIN32) || defined(_WIN64) -# define _ELPP_OS_WINDOWS 1 +#if (defined(_WIN32) || defined(_WIN64)) +# define ELPP_OS_WINDOWS 1 #else -# define _ELPP_OS_WINDOWS 0 -#endif // defined(_WIN32) || defined(_WIN64) +# define ELPP_OS_WINDOWS 0 +#endif // Linux #if (defined(__linux) || defined(__linux__)) -# define _ELPP_OS_LINUX 1 +# define ELPP_OS_LINUX 1 +#else +# define ELPP_OS_LINUX 0 +#endif +#if (defined(__APPLE__)) +# define ELPP_OS_MAC 1 +#else +# define ELPP_OS_MAC 0 +#endif +#if (defined(__FreeBSD__) || defined(__FreeBSD_kernel__)) +# define ELPP_OS_FREEBSD 1 #else -# define _ELPP_OS_LINUX 0 -#endif // (defined(__linux) || defined(__linux__)) -// Mac -#if defined(__APPLE__) -# define _ELPP_OS_MAC 1 +# define ELPP_OS_FREEBSD 0 +#endif +#if (defined(__sun)) +# define ELPP_OS_SOLARIS 1 +#else +# define ELPP_OS_SOLARIS 0 +#endif +#if (defined(_AIX)) +# define ELPP_OS_AIX 1 #else -# define _ELPP_OS_MAC 0 -#endif // defined(__APPLE__) +# define ELPP_OS_AIX 0 +#endif +#if (defined(__NetBSD__)) +# define ELPP_OS_NETBSD 1 +#else +# define ELPP_OS_NETBSD 0 +#endif // Unix -#define _ELPP_OS_UNIX ((_ELPP_OS_LINUX || _ELPP_OS_MAC) && (!_ELPP_OS_WINDOWS)) -// Assembly -#if (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))) || \ - (defined(_MSC_VER) && (defined(_M_IX86))) -# define _ELPP_ASSEMBLY_SUPPORTED 1 +#if ((ELPP_OS_LINUX || ELPP_OS_MAC || ELPP_OS_FREEBSD || ELPP_OS_NETBSD || ELPP_OS_SOLARIS || ELPP_OS_AIX) && (!ELPP_OS_WINDOWS)) +# define ELPP_OS_UNIX 1 #else -# define _ELPP_ASSEMBLY_SUPPORTED 0 +# define ELPP_OS_UNIX 0 #endif -#if (!defined(_DISABLE_ELPP_ASSERT)) -# if (defined(_STOP_ON_FIRST_ELPP_ASSERTION)) -# define __EASYLOGGINGPP_ASSERT(expr, msg) if (!(expr)) { std::cerr << "EASYLOGGING++ ASSERTION FAILED (LINE: " << __LINE__ << ") [" #expr << "] with message \"" << msg << "\"" << std::endl; exit(1); } -# else -# define __EASYLOGGINGPP_ASSERT(expr, msg) if (!(expr)) { std::cerr << "EASYLOGGING++ ASSERTION FAILED (LINE: " << __LINE__ << ") [" #expr << "] with message \"" << msg << "\"" << std::endl; } -# endif // (defined(_STOP_ON_FIRST_ELPP_ASSERTION)) -#else -# define __EASYLOGGINGPP_ASSERT(x, y) -#endif // (!defined(_DISABLE_ELPP_ASSERT)) -#define __EASYLOGGINGPP_SUPPRESS_UNSED(x) (void)x; -#if _ELPP_OS_UNIX +#if (defined(__ANDROID__)) +# define ELPP_OS_ANDROID 1 +#else +# define ELPP_OS_ANDROID 0 +#endif +// Evaluating Cygwin as *nix OS +#if !ELPP_OS_UNIX && !ELPP_OS_WINDOWS && ELPP_CYGWIN +# undef ELPP_OS_UNIX +# undef ELPP_OS_LINUX +# define ELPP_OS_UNIX 1 +# define ELPP_OS_LINUX 1 +#endif // !ELPP_OS_UNIX && !ELPP_OS_WINDOWS && ELPP_CYGWIN +#if !defined(ELPP_INTERNAL_DEBUGGING_OUT_INFO) +# define ELPP_INTERNAL_DEBUGGING_OUT_INFO std::cout +#endif // !defined(ELPP_INTERNAL_DEBUGGING_OUT) +#if !defined(ELPP_INTERNAL_DEBUGGING_OUT_ERROR) +# define ELPP_INTERNAL_DEBUGGING_OUT_ERROR std::cerr +#endif // !defined(ELPP_INTERNAL_DEBUGGING_OUT) +#if !defined(ELPP_INTERNAL_DEBUGGING_ENDL) +# define ELPP_INTERNAL_DEBUGGING_ENDL std::endl +#endif // !defined(ELPP_INTERNAL_DEBUGGING_OUT) +#if !defined(ELPP_INTERNAL_DEBUGGING_MSG) +# define ELPP_INTERNAL_DEBUGGING_MSG(msg) msg +#endif // !defined(ELPP_INTERNAL_DEBUGGING_OUT) +// Internal Assertions and errors +#if !defined(ELPP_DISABLE_ASSERT) +# if (defined(ELPP_DEBUG_ASSERT_FAILURE)) +# define ELPP_ASSERT(expr, msg) if (!(expr)) { \ +std::stringstream internalInfoStream; internalInfoStream << msg; \ +ELPP_INTERNAL_DEBUGGING_OUT_ERROR \ +<< "EASYLOGGING++ ASSERTION FAILED (LINE: " << __LINE__ << ") [" #expr << "] WITH MESSAGE \"" \ +<< ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStream.str()) << "\"" << ELPP_INTERNAL_DEBUGGING_ENDL; base::utils::abort(1, \ +"ELPP Assertion failure, please define ELPP_DEBUG_ASSERT_FAILURE"); } +# else +# define ELPP_ASSERT(expr, msg) if (!(expr)) { \ +std::stringstream internalInfoStream; internalInfoStream << msg; \ +ELPP_INTERNAL_DEBUGGING_OUT_ERROR\ +<< "ASSERTION FAILURE FROM EASYLOGGING++ (LINE: " \ +<< __LINE__ << ") [" #expr << "] WITH MESSAGE \"" << ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStream.str()) << "\"" \ +<< ELPP_INTERNAL_DEBUGGING_ENDL; } +# endif // (defined(ELPP_DEBUG_ASSERT_FAILURE)) +#else +# define ELPP_ASSERT(x, y) +#endif //(!defined(ELPP_DISABLE_ASSERT) +#if ELPP_COMPILER_MSVC +# define ELPP_INTERNAL_DEBUGGING_WRITE_PERROR \ +{ char buff[256]; strerror_s(buff, 256, errno); \ +ELPP_INTERNAL_DEBUGGING_OUT_ERROR << ": " << buff << " [" << errno << "]";} (void)0 +#else +# define ELPP_INTERNAL_DEBUGGING_WRITE_PERROR \ +ELPP_INTERNAL_DEBUGGING_OUT_ERROR << ": " << strerror(errno) << " [" << errno << "]"; (void)0 +#endif // ELPP_COMPILER_MSVC +#if defined(ELPP_DEBUG_ERRORS) +# if !defined(ELPP_INTERNAL_ERROR) +# define ELPP_INTERNAL_ERROR(msg, pe) { \ +std::stringstream internalInfoStream; internalInfoStream << " " << msg; \ +ELPP_INTERNAL_DEBUGGING_OUT_ERROR \ +<< "ERROR FROM EASYLOGGING++ (LINE: " << __LINE__ << ") " \ +<< ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStream.str()) << ELPP_INTERNAL_DEBUGGING_ENDL; \ +if (pe) { ELPP_INTERNAL_DEBUGGING_OUT_ERROR << " "; ELPP_INTERNAL_DEBUGGING_WRITE_PERROR; }} (void)0 +# endif +#else +# undef ELPP_INTERNAL_INFO +# define ELPP_INTERNAL_ERROR(msg, pe) +#endif // defined(ELPP_DEBUG_ERRORS) +#if (defined(ELPP_DEBUG_INFO)) +# if !(defined(ELPP_INTERNAL_INFO_LEVEL)) +# define ELPP_INTERNAL_INFO_LEVEL 9 +# endif // !(defined(ELPP_INTERNAL_INFO_LEVEL)) +# if !defined(ELPP_INTERNAL_INFO) +# define ELPP_INTERNAL_INFO(lvl, msg) { if (lvl <= ELPP_INTERNAL_INFO_LEVEL) { \ +std::stringstream internalInfoStream; internalInfoStream << " " << msg; \ +ELPP_INTERNAL_DEBUGGING_OUT_INFO << ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStream.str()) \ +<< ELPP_INTERNAL_DEBUGGING_ENDL; }} +# endif +#else +# undef ELPP_INTERNAL_INFO +# define ELPP_INTERNAL_INFO(lvl, msg) +#endif // (defined(ELPP_DEBUG_INFO)) +#if (defined(ELPP_FEATURE_ALL)) || (defined(ELPP_FEATURE_CRASH_LOG)) +# if (ELPP_COMPILER_GCC && !ELPP_MINGW && !ELPP_OS_ANDROID) +# define ELPP_STACKTRACE 1 +# else +# if ELPP_COMPILER_MSVC +# pragma message("Stack trace not available for this compiler") +# else +# warning "Stack trace not available for this compiler"; +# endif // ELPP_COMPILER_MSVC +# define ELPP_STACKTRACE 0 +# endif // ELPP_COMPILER_GCC +#else +# define ELPP_STACKTRACE 0 +#endif // (defined(ELPP_FEATURE_ALL)) || (defined(ELPP_FEATURE_CRASH_LOG)) +// Miscellaneous macros +#define ELPP_UNUSED(x) (void)x +#if ELPP_OS_UNIX // Log file permissions for unix-based systems -# define _LOG_PERMS S_IRUSR | S_IWUSR | S_IXUSR | S_IWGRP | S_IRGRP | S_IXGRP | S_IWOTH | S_IXOTH -#endif // _ELPP_OS_UNIX -#if (!defined(_DISABLE_MUTEX) && (_ENABLE_EASYLOGGING)) -# define _ELPP_ENABLE_MUTEX 1 -#else -# define _ELPP_ENABLE_MUTEX 0 -#endif // (!defined(_DISABLE_MUTEX) && (_ENABLE_EASYLOGGING)) -#if (!defined(_DISABLE_DEBUG_LOGS) && (_ENABLE_EASYLOGGING) && ((defined(_DEBUG)) || (!defined(NDEBUG)))) -# define _ELPP_DEBUG_LOG 1 -#else -# define _ELPP_DEBUG_LOG 0 -#endif // (!defined(_DISABLE_DEBUG_LOGS) && (_ENABLE_EASYLOGGING) && ((defined(_DEBUG)) || (!defined(NDEBUG)))) -#if (!defined(_DISABLE_INFO_LOGS) && (_ENABLE_EASYLOGGING)) -# define _ELPP_INFO_LOG 1 -#else -# define _ELPP_INFO_LOG 0 -#endif // (!defined(_DISABLE_INFO_LOGS) && (_ENABLE_EASYLOGGING)) -#if (!defined(_DISABLE_WARNING_LOGS) && (_ENABLE_EASYLOGGING)) -# define _ELPP_WARNING_LOG 1 -#else -# define _ELPP_WARNING_LOG 0 -#endif // (!defined(_DISABLE_WARNING_LOGS) && (_ENABLE_EASYLOGGING)) -#if (!defined(_DISABLE_ERROR_LOGS) && (_ENABLE_EASYLOGGING)) -# define _ELPP_ERROR_LOG 1 -#else -# define _ELPP_ERROR_LOG 0 -#endif // (!defined(_DISABLE_ERROR_LOGS) && (_ENABLE_EASYLOGGING)) -#if (!defined(_DISABLE_FATAL_LOGS) && (_ENABLE_EASYLOGGING)) -# define _ELPP_FATAL_LOG 1 -#else -# define _ELPP_FATAL_LOG 0 -#endif // (!defined(_DISABLE_FATAL_LOGS) && (_ENABLE_EASYLOGGING)) -#if (defined(_QUALITY_ASSURANCE) && (_ENABLE_EASYLOGGING)) -# define _ELPP_QA_LOG 1 -#else -# define _ELPP_QA_LOG 0 -#endif // (defined(_QUALITY_ASSURANCE) && (_ENABLE_EASYLOGGING)) -#if (!defined(_DISABLE_TRACE_LOGS) && (_ENABLE_EASYLOGGING)) -# define _ELPP_TRACE_LOG 1 -#else -# define _ELPP_TRACE_LOG 0 -#endif // (!defined(_DISABLE_TRACE_LOGS) && (_ENABLE_EASYLOGGING)) -#if (!defined(_DISABLE_VERBOSE_LOGS) && (_ENABLE_EASYLOGGING)) -# define _ELPP_VERBOSE_LOG 1 -#else -# define _ELPP_VERBOSE_LOG 0 -#endif // (!defined(_DISABLE_VERBOSE_LOGS) && (_ENABLE_EASYLOGGING)) -#define ELPP_FOR_EACH(variableName, initialValue, operation, limit) unsigned int variableName = initialValue; \ - do { \ - operation \ - variableName = variableName << 1; \ - if (variableName == 0) { ++variableName; } \ - } while (variableName <= limit) -#define ELPP_FOR_EACH_LEVEL(variableName, initialValue, operation) \ - ELPP_FOR_EACH(variableName, initialValue, operation, easyloggingpp::Level::kMaxValid) -#define ELPP_FOR_EACH_CONFIGURATION(variableName, initialValue, operation) \ - ELPP_FOR_EACH(variableName, initialValue, operation, easyloggingpp::ConfigurationType::kMaxValid) -// Includes +# define ELPP_LOG_PERMS S_IRUSR | S_IWUSR | S_IXUSR | S_IWGRP | S_IRGRP | S_IXGRP | S_IWOTH | S_IXOTH +#endif // ELPP_OS_UNIX +#if defined(ELPP_AS_DLL) && ELPP_COMPILER_MSVC +# if defined(ELPP_EXPORT_SYMBOLS) +# define ELPP_EXPORT __declspec(dllexport) +# else +# define ELPP_EXPORT __declspec(dllimport) +# endif // defined(ELPP_EXPORT_SYMBOLS) +#else +# define ELPP_EXPORT +#endif // defined(ELPP_AS_DLL) && ELPP_COMPILER_MSVC +// Some special functions that are VC++ specific +#undef STRTOK +#undef STRERROR +#undef STRCAT +#undef STRCPY +#if ELPP_CRT_DBG_WARNINGS +# define STRTOK(a, b, c) strtok_s(a, b, c) +# define STRERROR(a, b, c) strerror_s(a, b, c) +# define STRCAT(a, b, len) strcat_s(a, len, b) +# define STRCPY(a, b, len) strcpy_s(a, len, b) +#else +# define STRTOK(a, b, c) strtok(a, b) +# define STRERROR(a, b, c) strerror(c) +# define STRCAT(a, b, len) strcat(a, b) +# define STRCPY(a, b, len) strcpy(a, b) +#endif +// Compiler specific support evaluations +#if (ELPP_MINGW && !defined(ELPP_FORCE_USE_STD_THREAD)) +# define ELPP_USE_STD_THREADING 0 +#else +# if ((ELPP_COMPILER_CLANG && defined(ELPP_CLANG_SUPPORTS_THREAD)) || \ + (!ELPP_COMPILER_CLANG && defined(ELPP_CXX11)) || \ + defined(ELPP_FORCE_USE_STD_THREAD)) +# define ELPP_USE_STD_THREADING 1 +# else +# define ELPP_USE_STD_THREADING 0 +# endif +#endif +#undef ELPP_FINAL +#if ELPP_COMPILER_INTEL || (ELPP_GCC_VERSION < 40702) +# define ELPP_FINAL +#else +# define ELPP_FINAL final +#endif // ELPP_COMPILER_INTEL || (ELPP_GCC_VERSION < 40702) +#if defined(ELPP_EXPERIMENTAL_ASYNC) +# define ELPP_ASYNC_LOGGING 1 +#else +# define ELPP_ASYNC_LOGGING 0 +#endif // defined(ELPP_EXPERIMENTAL_ASYNC) +#if defined(ELPP_THREAD_SAFE) || ELPP_ASYNC_LOGGING +# define ELPP_THREADING_ENABLED 1 +#else +# define ELPP_THREADING_ENABLED 0 +#endif // defined(ELPP_THREAD_SAFE) || ELPP_ASYNC_LOGGING +// Function macro ELPP_FUNC +#undef ELPP_FUNC +#if ELPP_COMPILER_MSVC // Visual C++ +# define ELPP_FUNC __FUNCSIG__ +#elif ELPP_COMPILER_GCC // GCC +# define ELPP_FUNC __PRETTY_FUNCTION__ +#elif ELPP_COMPILER_INTEL // Intel C++ +# define ELPP_FUNC __PRETTY_FUNCTION__ +#elif ELPP_COMPILER_CLANG // Clang++ +# define ELPP_FUNC __PRETTY_FUNCTION__ +#else +# if defined(__func__) +# define ELPP_FUNC __func__ +# else +# define ELPP_FUNC "" +# endif // defined(__func__) +#endif // defined(_MSC_VER) +#undef ELPP_VARIADIC_TEMPLATES_SUPPORTED +// Keep following line commented until features are fixed +#define ELPP_VARIADIC_TEMPLATES_SUPPORTED \ +(ELPP_COMPILER_GCC || ELPP_COMPILER_CLANG || ELPP_COMPILER_INTEL || (ELPP_COMPILER_MSVC && _MSC_VER >= 1800)) +// Logging Enable/Disable macros +#if defined(ELPP_DISABLE_LOGS) +#define ELPP_LOGGING_ENABLED 0 +#else +#define ELPP_LOGGING_ENABLED 1 +#endif +#if (!defined(ELPP_DISABLE_DEBUG_LOGS) && (ELPP_LOGGING_ENABLED)) +# define ELPP_DEBUG_LOG 1 +#else +# define ELPP_DEBUG_LOG 0 +#endif // (!defined(ELPP_DISABLE_DEBUG_LOGS) && (ELPP_LOGGING_ENABLED)) +#if (!defined(ELPP_DISABLE_INFO_LOGS) && (ELPP_LOGGING_ENABLED)) +# define ELPP_INFO_LOG 1 +#else +# define ELPP_INFO_LOG 0 +#endif // (!defined(ELPP_DISABLE_INFO_LOGS) && (ELPP_LOGGING_ENABLED)) +#if (!defined(ELPP_DISABLE_WARNING_LOGS) && (ELPP_LOGGING_ENABLED)) +# define ELPP_WARNING_LOG 1 +#else +# define ELPP_WARNING_LOG 0 +#endif // (!defined(ELPP_DISABLE_WARNING_LOGS) && (ELPP_LOGGING_ENABLED)) +#if (!defined(ELPP_DISABLE_ERROR_LOGS) && (ELPP_LOGGING_ENABLED)) +# define ELPP_ERROR_LOG 1 +#else +# define ELPP_ERROR_LOG 0 +#endif // (!defined(ELPP_DISABLE_ERROR_LOGS) && (ELPP_LOGGING_ENABLED)) +#if (!defined(ELPP_DISABLE_FATAL_LOGS) && (ELPP_LOGGING_ENABLED)) +# define ELPP_FATAL_LOG 1 +#else +# define ELPP_FATAL_LOG 0 +#endif // (!defined(ELPP_DISABLE_FATAL_LOGS) && (ELPP_LOGGING_ENABLED)) +#if (!defined(ELPP_DISABLE_TRACE_LOGS) && (ELPP_LOGGING_ENABLED)) +# define ELPP_TRACE_LOG 1 +#else +# define ELPP_TRACE_LOG 0 +#endif // (!defined(ELPP_DISABLE_TRACE_LOGS) && (ELPP_LOGGING_ENABLED)) +#if (!defined(ELPP_DISABLE_VERBOSE_LOGS) && (ELPP_LOGGING_ENABLED)) +# define ELPP_VERBOSE_LOG 1 +#else +# define ELPP_VERBOSE_LOG 0 +#endif // (!defined(ELPP_DISABLE_VERBOSE_LOGS) && (ELPP_LOGGING_ENABLED)) +#if (!(ELPP_CXX0X || ELPP_CXX11)) +# error "C++0x (or higher) support not detected! (Is `-std=c++11' missing?)" +#endif // (!(ELPP_CXX0X || ELPP_CXX11)) +// Headers +#if defined(ELPP_SYSLOG) +# include +#endif // defined(ELPP_SYSLOG) #include #include #include #include #include -#if _ELPP_NDK +#include +#include +#include +#if defined(ELPP_UNICODE) +# include +# if ELPP_OS_WINDOWS +# include +# endif // ELPP_OS_WINDOWS +#endif // defined(ELPP_UNICODE) +#if ELPP_STACKTRACE +# include +# include +#endif // ELPP_STACKTRACE +#if ELPP_OS_ANDROID # include -#endif // _ELPP_NDK -#if _ELPP_OS_UNIX +#endif // ELPP_OS_ANDROID +#if ELPP_OS_UNIX # include # include -# if (_ELPP_ENABLE_MUTEX) -# if (_ELPP_ASSEMBLY_SUPPORTED) -# include -# else -# include -# endif // (_ELPP_ASSEMBLY_SUPPORTED) -# endif // (_ELPP_ENABLE_MUTEX) -#elif _ELPP_OS_WINDOWS +#elif ELPP_OS_WINDOWS # include -# include -#endif // _ELPP_OS_UNIX +# include +# if defined(WIN32_LEAN_AND_MEAN) +# if defined(ELPP_WINSOCK2) +# include +# else +# include +# endif // defined(ELPP_WINSOCK2) +# endif // defined(WIN32_LEAN_AND_MEAN) +#endif // ELPP_OS_UNIX #include #include #include +#include +#include #include #include #include #include #include -#if (_ELPP_STD_THREAD_AVAILABLE) +#include +#include +#if ELPP_THREADING_ENABLED +# if ELPP_USE_STD_THREADING +# include +# include +# else +# if ELPP_OS_UNIX +# include +# endif // ELPP_OS_UNIX +# endif // ELPP_USE_STD_THREADING +#endif // ELPP_THREADING_ENABLED +#if ELPP_ASYNC_LOGGING +# if defined(ELPP_NO_SLEEP_FOR) +# include +# endif // defined(ELPP_NO_SLEEP_FOR) # include -#endif // _ELPP_STD_THREAD_AVAILABLE -#if defined(_ELPP_STL_LOGGING) +# include +# include +#endif // ELPP_ASYNC_LOGGING +#if defined(ELPP_STL_LOGGING) // For logging STL based templates # include -# include # include # include # include # include # include -#endif // defined(_ELPP_STL_LOGGING) -#if defined(QT_CORE_LIB) && defined(_ELPP_QT_LOGGING) +# if defined(ELPP_LOG_STD_ARRAY) +# include +# endif // defined(ELPP_LOG_STD_ARRAY) +# if defined(ELPP_LOG_UNORDERED_SET) +# include +# endif // defined(ELPP_UNORDERED_SET) +#endif // defined(ELPP_STL_LOGGING) +#if defined(ELPP_QT_LOGGING) // For logging Qt based classes & templates # include +# include # include # include # include @@ -301,3256 +436,3516 @@ # include # include # include -#endif // defined(QT_CORE_LIB) && defined(_ELPP_QT_LOGGING) -namespace easyloggingpp { - namespace internal { - - class NoCopy { - protected: - NoCopy(void) {} - private: - NoCopy(const NoCopy&); - NoCopy& operator=(const NoCopy&); - }; - - class StaticClass { - private: - StaticClass(void); - StaticClass(const StaticClass&); - StaticClass& operator=(const StaticClass&); - }; - } // namespace internal - - struct Level : private internal::StaticClass { - public: - enum { - All = 0, Debug = 1, Info = 2, Warning = 4, Error = 8, - Fatal = 16, Verbose = 32, QA = 64, Trace = 128, Unknown = 1010 - }; - - static const unsigned int kMinValid = All; - static const unsigned int kMaxValid = Trace; - - static std::string convertToString(unsigned int level_) { - switch (level_) { - case All: - return std::string("ALL"); - case Debug: - return std::string("DEBUG"); - case Info: - return std::string("INFO"); - case Warning: - return std::string("WARNING"); - case Error: - return std::string("ERROR"); - case Fatal: - return std::string("FATAL"); - case QA: - return std::string("QA"); - case Verbose: - return std::string("VERBOSE"); - case Trace: - return std::string("TRACE"); - default: - return std::string("UNKNOWN"); - } - } +#endif // defined(ELPP_QT_LOGGING) +#if defined(ELPP_BOOST_LOGGING) +// For logging boost based classes & templates +# include +# include +# include +# include +# include +# include +# include +# include +#endif // defined(ELPP_BOOST_LOGGING) +#if defined(ELPP_WXWIDGETS_LOGGING) +// For logging wxWidgets based classes & templates +# include +#endif // defined(ELPP_WXWIDGETS_LOGGING) +#if defined(ELPP_UTC_DATETIME) +# define elpptime_r gmtime_r +# define elpptime_s gmtime_s +# define elpptime gmtime +#else +# define elpptime_r localtime_r +# define elpptime_s localtime_s +# define elpptime localtime +#endif // defined(ELPP_UTC_DATETIME) +// Forward declarations +namespace el { +class Logger; +class LogMessage; +class PerformanceTrackingData; +class Loggers; +class Helpers; +template class Callback; +class LogDispatchCallback; +class PerformanceTrackingCallback; +class LoggerRegistrationCallback; +class LogDispatchData; +namespace base { +class Storage; +class RegisteredLoggers; +class PerformanceTracker; +class MessageBuilder; +class Writer; +class PErrorWriter; +class LogDispatcher; +class DefaultLogBuilder; +class DefaultLogDispatchCallback; +#if ELPP_ASYNC_LOGGING +class AsyncLogDispatchCallback; +class AsyncDispatchWorker; +#endif // ELPP_ASYNC_LOGGING +class DefaultPerformanceTrackingCallback; +} // namespace base +} // namespace el +/// @brief Easylogging++ entry namespace +namespace el { +/// @brief Namespace containing base/internal functionality used by Easylogging++ +namespace base { +/// @brief Data types used by Easylogging++ +namespace type { +#undef ELPP_LITERAL +#undef ELPP_STRLEN +#undef ELPP_COUT +#if defined(ELPP_UNICODE) +# define ELPP_LITERAL(txt) L##txt +# define ELPP_STRLEN wcslen +# if defined ELPP_CUSTOM_COUT +# define ELPP_COUT ELPP_CUSTOM_COUT +# else +# define ELPP_COUT std::wcout +# endif // defined ELPP_CUSTOM_COUT +typedef wchar_t char_t; +typedef std::wstring string_t; +typedef std::wstringstream stringstream_t; +typedef std::wfstream fstream_t; +typedef std::wostream ostream_t; +#else +# define ELPP_LITERAL(txt) txt +# define ELPP_STRLEN strlen +# if defined ELPP_CUSTOM_COUT +# define ELPP_COUT ELPP_CUSTOM_COUT +# else +# define ELPP_COUT std::cout +# endif // defined ELPP_CUSTOM_COUT +typedef char char_t; +typedef std::string string_t; +typedef std::stringstream stringstream_t; +typedef std::fstream fstream_t; +typedef std::ostream ostream_t; +#endif // defined(ELPP_UNICODE) +#if defined(ELPP_CUSTOM_COUT_LINE) +# define ELPP_COUT_LINE(logLine) ELPP_CUSTOM_COUT_LINE(logLine) +#else +# define ELPP_COUT_LINE(logLine) logLine << std::flush +#endif // defined(ELPP_CUSTOM_COUT_LINE) +typedef unsigned int EnumType; +typedef unsigned short VerboseLevel; +typedef unsigned long int LineNumber; +typedef std::shared_ptr StoragePointer; +typedef std::shared_ptr LogDispatchCallbackPtr; +typedef std::shared_ptr PerformanceTrackingCallbackPtr; +typedef std::shared_ptr LoggerRegistrationCallbackPtr; +typedef std::unique_ptr PerformanceTrackerPtr; +} // namespace type +/// @brief Internal helper class that prevent copy constructor for class +/// +/// @detail When using this class simply inherit it privately +class NoCopy { + protected: + NoCopy(void) {} + private: + NoCopy(const NoCopy&); + NoCopy& operator=(const NoCopy&); +}; +/// @brief Internal helper class that makes all default constructors private. +/// +/// @detail This prevents initializing class making it static unless an explicit constructor is declared. +/// When using this class simply inherit it privately +class StaticClass { + private: + StaticClass(void); + StaticClass(const StaticClass&); + StaticClass& operator=(const StaticClass&); +}; +} // namespace base +/// @brief Represents enumeration for severity level used to determine level of logging +/// +/// @detail With Easylogging++, developers may disable or enable any level regardless of +/// what the severity is. Or they can choose to log using hierarchical logging flag +enum class Level : base::type::EnumType { + /// @brief Generic level that represents all the levels. Useful when setting global configuration for all levels + Global = 1, + /// @brief Information that can be useful to back-trace certain events - mostly useful than debug logs. + Trace = 2, + /// @brief Informational events most useful for developers to debug application + Debug = 4, + /// @brief Severe error information that will presumably abort application + Fatal = 8, + /// @brief Information representing errors in application but application will keep running + Error = 16, + /// @brief Useful when application has potentially harmful situtaions + Warning = 32, + /// @brief Information that can be highly useful and vary with verbose logging level. + Verbose = 64, + /// @brief Mainly useful to represent current progress of application + Info = 128, + /// @brief Represents unknown level + Unknown = 1010 +}; +} // namespace el +namespace std { +template<> struct hash { + public: + std::size_t operator()(const el::Level& l) const { + return hash {}(static_cast(l)); + } +}; +} +namespace el { +/// @brief Static class that contains helper functions for el::Level +class LevelHelper : base::StaticClass { + public: + /// @brief Represents minimum valid level. Useful when iterating through enum. + static const base::type::EnumType kMinValid = static_cast(Level::Trace); + /// @brief Represents maximum valid level. This is used internally and you should not need it. + static const base::type::EnumType kMaxValid = static_cast(Level::Info); + /// @brief Casts level to int, useful for iterating through enum. + static base::type::EnumType castToInt(Level level) { + return static_cast(level); + } + /// @brief Casts int(ushort) to level, useful for iterating through enum. + static Level castFromInt(base::type::EnumType l) { + return static_cast(l); + } + /// @brief Converts level to associated const char* + /// @return Upper case string based level. + static const char* convertToString(Level level); + /// @brief Converts from levelStr to Level + /// @param levelStr Upper case string based level. + /// Lower case is also valid but providing upper case is recommended. + static Level convertFromString(const char* levelStr); + /// @brief Applies specified function to each level starting from startIndex + /// @param startIndex initial value to start the iteration from. This is passed as pointer and + /// is left-shifted so this can be used inside function (fn) to represent current level. + /// @param fn function to apply with each level. This bool represent whether or not to stop iterating through levels. + static void forEachLevel(base::type::EnumType* startIndex, const std::function& fn); +}; +/// @brief Represents enumeration of ConfigurationType used to configure or access certain aspect +/// of logging +enum class ConfigurationType : base::type::EnumType { + /// @brief Determines whether or not corresponding level and logger of logging is enabled + /// You may disable all logs by using el::Level::Global + Enabled = 1, + /// @brief Whether or not to write corresponding log to log file + ToFile = 2, + /// @brief Whether or not to write corresponding level and logger log to standard output. + /// By standard output meaning termnal, command prompt etc + ToStandardOutput = 4, + /// @brief Determines format of logging corresponding level and logger. + Format = 8, + /// @brief Determines log file (full path) to write logs to for correponding level and logger + Filename = 16, + /// @brief Specifies precision of the subsecond part. It should be within range (1-6). + SubsecondPrecision = 32, + /// @brief Alias of SubsecondPrecision (for backward compatibility) + MillisecondsWidth = SubsecondPrecision, + /// @brief Determines whether or not performance tracking is enabled. + /// + /// @detail This does not depend on logger or level. Performance tracking always uses 'performance' logger + PerformanceTracking = 64, + /// @brief Specifies log file max size. + /// + /// @detail If file size of corresponding log file (for corresponding level) is >= specified size, log file will + /// be truncated and re-initiated. + MaxLogFileSize = 128, + /// @brief Specifies number of log entries to hold until we flush pending log data + LogFlushThreshold = 256, + /// @brief Represents unknown configuration + Unknown = 1010 +}; +/// @brief Static class that contains helper functions for el::ConfigurationType +class ConfigurationTypeHelper : base::StaticClass { + public: + /// @brief Represents minimum valid configuration type. Useful when iterating through enum. + static const base::type::EnumType kMinValid = static_cast(ConfigurationType::Enabled); + /// @brief Represents maximum valid configuration type. This is used internally and you should not need it. + static const base::type::EnumType kMaxValid = static_cast(ConfigurationType::MaxLogFileSize); + /// @brief Casts configuration type to int, useful for iterating through enum. + static base::type::EnumType castToInt(ConfigurationType configurationType) { + return static_cast(configurationType); + } + /// @brief Casts int(ushort) to configurationt type, useful for iterating through enum. + static ConfigurationType castFromInt(base::type::EnumType c) { + return static_cast(c); + } + /// @brief Converts configuration type to associated const char* + /// @returns Upper case string based configuration type. + static const char* convertToString(ConfigurationType configurationType); + /// @brief Converts from configStr to ConfigurationType + /// @param configStr Upper case string based configuration type. + /// Lower case is also valid but providing upper case is recommended. + static ConfigurationType convertFromString(const char* configStr); + /// @brief Applies specified function to each configuration type starting from startIndex + /// @param startIndex initial value to start the iteration from. This is passed by pointer and is left-shifted + /// so this can be used inside function (fn) to represent current configuration type. + /// @param fn function to apply with each configuration type. + /// This bool represent whether or not to stop iterating through configurations. + static inline void forEachConfigType(base::type::EnumType* startIndex, const std::function& fn); +}; +/// @brief Flags used while writing logs. This flags are set by user +enum class LoggingFlag : base::type::EnumType { + /// @brief Makes sure we have new line for each container log entry + NewLineForContainer = 1, + /// @brief Makes sure if -vmodule is used and does not specifies a module, then verbose + /// logging is allowed via that module. + AllowVerboseIfModuleNotSpecified = 2, + /// @brief When handling crashes by default, detailed crash reason will be logged as well + LogDetailedCrashReason = 4, + /// @brief Allows to disable application abortion when logged using FATAL level + DisableApplicationAbortOnFatalLog = 8, + /// @brief Flushes log with every log-entry (performance sensative) - Disabled by default + ImmediateFlush = 16, + /// @brief Enables strict file rolling + StrictLogFileSizeCheck = 32, + /// @brief Make terminal output colorful for supported terminals + ColoredTerminalOutput = 64, + /// @brief Supports use of multiple logging in same macro, e.g, CLOG(INFO, "default", "network") + MultiLoggerSupport = 128, + /// @brief Disables comparing performance tracker's checkpoints + DisablePerformanceTrackingCheckpointComparison = 256, + /// @brief Disable VModules + DisableVModules = 512, + /// @brief Disable VModules extensions + DisableVModulesExtensions = 1024, + /// @brief Enables hierarchical logging + HierarchicalLogging = 2048, + /// @brief Creates logger automatically when not available + CreateLoggerAutomatically = 4096, + /// @brief Adds spaces b/w logs that separated by left-shift operator + AutoSpacing = 8192, + /// @brief Preserves time format and does not convert it to sec, hour etc (performance tracking only) + FixedTimeFormat = 16384 +}; +namespace base { +/// @brief Namespace containing constants used internally. +namespace consts { +static const char kFormatSpecifierCharValue = 'v'; +static const char kFormatSpecifierChar = '%'; +static const unsigned int kMaxLogPerCounter = 100000; +static const unsigned int kMaxLogPerContainer = 100; +static const unsigned int kDefaultSubsecondPrecision = 3; + +#ifdef ELPP_DEFAULT_LOGGER +static const char* kDefaultLoggerId = ELPP_DEFAULT_LOGGER; +#else +static const char* kDefaultLoggerId = "default"; +#endif - static unsigned int convertFromString(const std::string& levelStr) { - if (levelStr == "all" || levelStr == "ALL") return Level::All; - if (levelStr == "debug" || levelStr == "DEBUG") return Level::Debug; - if (levelStr == "info" || levelStr == "INFO") return Level::Info; - if (levelStr == "warning" || levelStr == "WARNING") return Level::Warning; - if (levelStr == "error" || levelStr == "ERROR") return Level::Error; - if (levelStr == "fatal" || levelStr == "FATAL") return Level::Fatal; - if (levelStr == "qa" || levelStr == "QA") return Level::QA; - if (levelStr == "verbose" || levelStr == "VERBOSE") return Level::Verbose; - if (levelStr == "trace" || levelStr == "TRACE") return Level::Trace; - return Level::Unknown; - } - }; - - struct ConfigurationType : private internal::StaticClass { - public: - enum { - Enabled = 0, ToFile = 1, ToStandardOutput = 2, Format = 4, Filename = 8, - MillisecondsWidth = 16, PerformanceTracking = 32, RollOutSize = 64, Unknown = 1010 - }; - - static const unsigned int kMinValid = Enabled; - static const unsigned int kMaxValid = RollOutSize; - - static std::string convertToString(unsigned int configurationType_) { - switch (configurationType_) { - case Enabled: - return std::string("ENABLED"); - case Filename: - return std::string("FILENAME"); - case Format: - return std::string("FORMAT"); - case ToFile: - return std::string("TO_FILE"); - case ToStandardOutput: - return std::string("TO_STANDARD_OUTPUT"); - case MillisecondsWidth: - return std::string("MILLISECONDS_WIDTH"); - case PerformanceTracking: - return std::string("PERFORMANCE_TRACKING"); - case RollOutSize: - return std::string("ROLL_OUT_SIZE"); - default: return std::string("UNKNOWN"); - } - } +#ifdef ELPP_DEFAULT_PERFORMANCE_LOGGER +static const char* kPerformanceLoggerId = ELPP_DEFAULT_PERFORMANCE_LOGGER; +#else +static const char* kPerformanceLoggerId = "performance"; +#endif - static unsigned int convertFromString(const std::string& configStr) { - if (configStr == "enabled" || configStr == "ENABLED") return ConfigurationType::Enabled; - if (configStr == "to_file" || configStr == "TO_FILE") return ConfigurationType::ToFile; - if (configStr == "to_standard_output" || configStr == "TO_STANDARD_OUTPUT") return ConfigurationType::ToStandardOutput; - if (configStr == "format" || configStr == "FORMAT") return ConfigurationType::Format; - if (configStr == "filename" || configStr == "FILENAME") return ConfigurationType::Filename; - if (configStr == "milliseconds_width" || configStr == "MILLISECONDS_WIDTH") return ConfigurationType::MillisecondsWidth; - if (configStr == "performance_tracking" || configStr == "PERFORMANCE_TRACKING") return ConfigurationType::PerformanceTracking; - if (configStr == "roll_out_size" || configStr == "ROLL_OUT_SIZE") return ConfigurationType::RollOutSize; - return ConfigurationType::Unknown; - } - }; - - namespace internal { - struct Aspect : private internal::StaticClass { - public: - enum { - Normal = 0, Conditional = 1, Interval = 2 - }; - }; - -//! -//! Used internally. You should not need this class. -//! - class Constants : private internal::NoCopy { - public: - Constants (void) : - // - // Log level name outputs - // - LOG_INFO_LEVEL_VALUE ("INFO") , - LOG_DEBUG_LEVEL_VALUE ("DEBUG"), - LOG_WARNING_LEVEL_VALUE("WARN"), - LOG_ERROR_LEVEL_VALUE ("ERROR"), - LOG_FATAL_LEVEL_VALUE ("FATAL"), - LOG_VERBOSE_LEVEL_VALUE("VER"), - LOG_QA_LEVEL_VALUE ("QA"), - LOG_TRACE_LEVEL_VALUE ("TRACE"), - // - // Format specifiers - // - APP_NAME_FORMAT_SPECIFIER ("%app"), - LOGGER_ID_FORMAT_SPECIFIER ("%logger"), - THREAD_ID_FORMAT_SPECIFIER ("%thread"), - LEVEL_FORMAT_SPECIFIER ("%level"), - DATE_ONLY_FORMAT_SPECIFIER ("%date"), - TIME_ONLY_FORMAT_SPECIFIER ("%time"), - DATE_TIME_FORMAT_SPECIFIER ("%datetime"), - LOCATION_FORMAT_SPECIFIER ("%loc"), - FUNCTION_FORMAT_SPECIFIER ("%func"), - USER_FORMAT_SPECIFIER ("%user"), - HOST_FORMAT_SPECIFIER ("%host"), - LOG_MESSAGE_FORMAT_SPECIFIER ("%log"), - VERBOSE_LEVEL_FORMAT_SPECIFIER ("%vlevel"), - // - // Others - // - NULL_POINTER ("nullptr"), - FORMAT_SPECIFIER_ESCAPE_CHAR ('E'), - MAX_LOG_PER_CONTAINER (100), - MAX_LOG_PER_COUNTER (100000), - DEFAULT_MILLISECOND_OFFSET (1000), - MAX_VERBOSE_LEVEL (9), - CURRENT_VERBOSE_LEVEL (0), // Set dynamically from registeredLoggers -#if _ELPP_OS_UNIX - PATH_SLASH ("/"), -#elif _ELPP_OS_WINDOWS - PATH_SLASH ("\\"), -#endif // _ELPP_OS_UNIX, - DEFAULT_LOG_FILENAME ("myeasylog.log") - { - // Trivial logger configuration - only to set format (difference: not using %logger) - std::stringstream ss; - ss << " * ALL:\n"; - ss << " FORMAT = %datetime %level %log\n"; - ss << "* DEBUG:\n"; - ss << " FORMAT = %datetime %level [%user@%host] [%func] [%loc] %log\n"; - // INFO and WARNING uses is defined by ALL - ss << "* ERROR:\n"; - ss << " FORMAT = %datetime %level %log\n"; - ss << "* FATAL:\n"; - ss << " FORMAT = %datetime %level %log\n"; - ss << "* QA:\n"; - ss << " FORMAT = %datetime %level %log\n"; - ss << "* VERBOSE:\n"; - ss << " FORMAT = %datetime %level-%vlevel %log\n"; - ss << "* TRACE:\n"; - ss << " FORMAT = %datetime %level [%func] [%loc] %log\n"; - DEFAULT_LOGGER_CONFIGURATION = ss.str(); - } // C'tor - // - // Log level name outputs - // - const std::string LOG_INFO_LEVEL_VALUE; - const std::string LOG_DEBUG_LEVEL_VALUE; - const std::string LOG_WARNING_LEVEL_VALUE; - const std::string LOG_ERROR_LEVEL_VALUE; - const std::string LOG_FATAL_LEVEL_VALUE; - const std::string LOG_VERBOSE_LEVEL_VALUE; - const std::string LOG_QA_LEVEL_VALUE; - const std::string LOG_TRACE_LEVEL_VALUE; - // - // Format specifiers - // - const std::string APP_NAME_FORMAT_SPECIFIER; - const std::string LOGGER_ID_FORMAT_SPECIFIER; - const std::string THREAD_ID_FORMAT_SPECIFIER; - const std::string LEVEL_FORMAT_SPECIFIER; - const std::string DATE_ONLY_FORMAT_SPECIFIER; - const std::string TIME_ONLY_FORMAT_SPECIFIER; - const std::string DATE_TIME_FORMAT_SPECIFIER; - const std::string LOCATION_FORMAT_SPECIFIER; - const std::string FUNCTION_FORMAT_SPECIFIER; - const std::string USER_FORMAT_SPECIFIER; - const std::string HOST_FORMAT_SPECIFIER; - const std::string LOG_MESSAGE_FORMAT_SPECIFIER; - const std::string VERBOSE_LEVEL_FORMAT_SPECIFIER; - // - // Others - // - const std::string NULL_POINTER; - const char FORMAT_SPECIFIER_ESCAPE_CHAR; - const unsigned int MAX_LOG_PER_CONTAINER; - const unsigned int MAX_LOG_PER_COUNTER; - const unsigned int DEFAULT_MILLISECOND_OFFSET; - const int MAX_VERBOSE_LEVEL; - int CURRENT_VERBOSE_LEVEL; - const std::string PATH_SLASH; - const std::string DEFAULT_LOG_FILENAME; - std::string DEFAULT_LOGGER_CONFIGURATION; - - enum kFormatFlags { - kDateOnly = 2, - kTimeOnly = 4, - kDateTime = 8, - kLoggerId = 16, - kLocation = 32, - kFunction = 64, - kUser = 128, - kHost = 256, - kLogMessage = 512, - kVerboseLevel = 1024, - kAppName = 2048, - kThreadId = 4096 - }; - }; // class Constants - namespace threading { - -//! -//! To take care of shared resources in multi-threaded application. Used internally, you should not need it. -//! - class Mutex { - public: -#if _ELPP_ASSEMBLY_SUPPORTED -# if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) -# define _ELPP_MUTEX_LOCK_GNU_ASM(lf_, old_) "movl $1,%%eax\n" \ - "\txchg %%eax,%0\n" \ - "\tmovl %%eax,%1\n" \ - "\t" : "=m" (lf_), "=m" (old_) : : "%eax", "memory" -# define _ELPP_MUTEX_UNLOCK_GNU_ASM(lf_) "movl $0,%%eax\n" \ - "\txchg %%eax,%0\n" \ - "\t" : "=m" (lf_) : : "%eax", "memory" -# endif // defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) - Mutex(void) : lockerFlag_(0) { - } +#if defined(ELPP_SYSLOG) +static const char* kSysLogLoggerId = "syslog"; +#endif // defined(ELPP_SYSLOG) + +#if ELPP_OS_WINDOWS +static const char* kFilePathSeperator = "\\"; #else - Mutex(void) { -# if _ELPP_OS_UNIX - pthread_mutex_init(&underlyingMutex_, NULL); -# elif _ELPP_OS_WINDOWS - InitializeCriticalSection(&underlyingMutex_); -# endif // _ELPP_OS_UNIX - } - - virtual ~Mutex(void) { -# if _ELPP_OS_UNIX - pthread_mutex_destroy(&underlyingMutex_); -# elif _ELPP_OS_WINDOWS - DeleteCriticalSection(&underlyingMutex_); -# endif // _ELPP_OS_UNIX - } -#endif // _ELPP_ASSEMBLY_SUPPORTED - - inline void lock(void) { -#if _ELPP_ASSEMBLY_SUPPORTED - bool locked = false; - while (!locked) { - locked = tryLock(); - if (!locked) { -# if _ELPP_OS_UNIX - sched_yield(); -# elif _ELPP_OS_WINDOWS - Sleep(0); -# endif - } - } +static const char* kFilePathSeperator = "/"; +#endif // ELPP_OS_WINDOWS + +static const std::size_t kSourceFilenameMaxLength = 100; +static const std::size_t kSourceLineMaxLength = 10; +static const Level kPerformanceTrackerDefaultLevel = Level::Info; +const struct { + double value; + const base::type::char_t* unit; +} kTimeFormats[] = { + { 1000.0f, ELPP_LITERAL("us") }, + { 1000.0f, ELPP_LITERAL("ms") }, + { 60.0f, ELPP_LITERAL("seconds") }, + { 60.0f, ELPP_LITERAL("minutes") }, + { 24.0f, ELPP_LITERAL("hours") }, + { 7.0f, ELPP_LITERAL("days") } +}; +static const int kTimeFormatsCount = sizeof(kTimeFormats) / sizeof(kTimeFormats[0]); +const struct { + int numb; + const char* name; + const char* brief; + const char* detail; +} kCrashSignals[] = { + // NOTE: Do not re-order, if you do please check CrashHandler(bool) constructor and CrashHandler::setHandler(..) + { + SIGABRT, "SIGABRT", "Abnormal termination", + "Program was abnormally terminated." + }, + { + SIGFPE, "SIGFPE", "Erroneous arithmetic operation", + "Arithemetic operation issue such as division by zero or operation resulting in overflow." + }, + { + SIGILL, "SIGILL", "Illegal instruction", + "Generally due to a corruption in the code or to an attempt to execute data." + }, + { + SIGSEGV, "SIGSEGV", "Invalid access to memory", + "Program is trying to read an invalid (unallocated, deleted or corrupted) or inaccessible memory." + }, + { + SIGINT, "SIGINT", "Interactive attention signal", + "Interruption generated (generally) by user or operating system." + }, +}; +static const int kCrashSignalsCount = sizeof(kCrashSignals) / sizeof(kCrashSignals[0]); +} // namespace consts +} // namespace base +typedef std::function PreRollOutCallback; +namespace base { +static inline void defaultPreRollOutCallback(const char*, std::size_t) {} +/// @brief Enum to represent timestamp unit +enum class TimestampUnit : base::type::EnumType { + Microsecond = 0, Millisecond = 1, Second = 2, Minute = 3, Hour = 4, Day = 5 +}; +/// @brief Format flags used to determine specifiers that are active for performance improvements. +enum class FormatFlags : base::type::EnumType { + DateTime = 1 << 1, + LoggerId = 1 << 2, + File = 1 << 3, + Line = 1 << 4, + Location = 1 << 5, + Function = 1 << 6, + User = 1 << 7, + Host = 1 << 8, + LogMessage = 1 << 9, + VerboseLevel = 1 << 10, + AppName = 1 << 11, + ThreadId = 1 << 12, + Level = 1 << 13, + FileBase = 1 << 14, + LevelShort = 1 << 15 +}; +/// @brief A subsecond precision class containing actual width and offset of the subsecond part +class SubsecondPrecision { + public: + SubsecondPrecision(void) { + init(base::consts::kDefaultSubsecondPrecision); + } + explicit SubsecondPrecision(int width) { + init(width); + } + bool operator==(const SubsecondPrecision& ssPrec) { + return m_width == ssPrec.m_width && m_offset == ssPrec.m_offset; + } + int m_width; + unsigned int m_offset; + private: + void init(int width); +}; +/// @brief Type alias of SubsecondPrecision +typedef SubsecondPrecision MillisecondsWidth; +/// @brief Namespace containing utility functions/static classes used internally +namespace utils { +/// @brief Deletes memory safely and points to null +template +static +typename std::enable_if::value, void>::type +safeDelete(T*& pointer) { + if (pointer == nullptr) + return; + delete pointer; + pointer = nullptr; +} +/// @brief Bitwise operations for C++11 strong enum class. This casts e into Flag_T and returns value after bitwise operation +/// Use these function as
flag = bitwise::Or(MyEnum::val1, flag);
+namespace bitwise { +template +static inline base::type::EnumType And(Enum e, base::type::EnumType flag) { + return static_cast(flag) & static_cast(e); +} +template +static inline base::type::EnumType Not(Enum e, base::type::EnumType flag) { + return static_cast(flag) & ~(static_cast(e)); +} +template +static inline base::type::EnumType Or(Enum e, base::type::EnumType flag) { + return static_cast(flag) | static_cast(e); +} +} // namespace bitwise +template +static inline void addFlag(Enum e, base::type::EnumType* flag) { + *flag = base::utils::bitwise::Or(e, *flag); +} +template +static inline void removeFlag(Enum e, base::type::EnumType* flag) { + *flag = base::utils::bitwise::Not(e, *flag); +} +template +static inline bool hasFlag(Enum e, base::type::EnumType flag) { + return base::utils::bitwise::And(e, flag) > 0x0; +} +} // namespace utils +namespace threading { +#if ELPP_THREADING_ENABLED +# if !ELPP_USE_STD_THREADING +namespace internal { +/// @brief A mutex wrapper for compiler that dont yet support std::recursive_mutex +class Mutex : base::NoCopy { + public: + Mutex(void) { +# if ELPP_OS_UNIX + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&m_underlyingMutex, &attr); + pthread_mutexattr_destroy(&attr); +# elif ELPP_OS_WINDOWS + InitializeCriticalSection(&m_underlyingMutex); +# endif // ELPP_OS_UNIX + } + + virtual ~Mutex(void) { +# if ELPP_OS_UNIX + pthread_mutex_destroy(&m_underlyingMutex); +# elif ELPP_OS_WINDOWS + DeleteCriticalSection(&m_underlyingMutex); +# endif // ELPP_OS_UNIX + } + + inline void lock(void) { +# if ELPP_OS_UNIX + pthread_mutex_lock(&m_underlyingMutex); +# elif ELPP_OS_WINDOWS + EnterCriticalSection(&m_underlyingMutex); +# endif // ELPP_OS_UNIX + } + + inline bool try_lock(void) { +# if ELPP_OS_UNIX + return (pthread_mutex_trylock(&m_underlyingMutex) == 0); +# elif ELPP_OS_WINDOWS + return TryEnterCriticalSection(&m_underlyingMutex); +# endif // ELPP_OS_UNIX + } + + inline void unlock(void) { +# if ELPP_OS_UNIX + pthread_mutex_unlock(&m_underlyingMutex); +# elif ELPP_OS_WINDOWS + LeaveCriticalSection(&m_underlyingMutex); +# endif // ELPP_OS_UNIX + } + + private: +# if ELPP_OS_UNIX + pthread_mutex_t m_underlyingMutex; +# elif ELPP_OS_WINDOWS + CRITICAL_SECTION m_underlyingMutex; +# endif // ELPP_OS_UNIX +}; +/// @brief Scoped lock for compiler that dont yet support std::lock_guard +template +class ScopedLock : base::NoCopy { + public: + explicit ScopedLock(M& mutex) { + m_mutex = &mutex; + m_mutex->lock(); + } + + virtual ~ScopedLock(void) { + m_mutex->unlock(); + } + private: + M* m_mutex; + ScopedLock(void); +}; +} // namespace internal +typedef base::threading::internal::Mutex Mutex; +typedef base::threading::internal::ScopedLock ScopedLock; +# else +typedef std::recursive_mutex Mutex; +typedef std::lock_guard ScopedLock; +# endif // !ELPP_USE_STD_THREADING #else -# if _ELPP_OS_UNIX - pthread_mutex_lock(&underlyingMutex_); -# elif _ELPP_OS_WINDOWS - EnterCriticalSection(&underlyingMutex_); -# endif // _ELPP_OS_UNIX -#endif // _ELPP_ASSEMBLY_SUPPORTED - } - - inline bool tryLock(void) { -#if _ELPP_ASSEMBLY_SUPPORTED - int oldLock_; -# if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) - asm volatile (_ELPP_MUTEX_LOCK_GNU_ASM(lockerFlag_, oldLock_)); -# elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)) - int *ptrLock = &lockerFlag_; - __asm { - mov eax,1 - mov ecx,ptrLock - xchg eax,[ecx] - mov oldLock_,eax - } -# endif // defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) - return (oldLock_ == 0); -#else -# if _ELPP_OS_UNIX - return (pthread_mutex_trylock(&underlyingMutex_) == 0) ? true : false; -# elif _ELPP_OS_WINDOWS - return TryEnterCriticalSection(&underlyingMutex_) ? true : false; -# endif // _ELPP_OS_UNIX -#endif // _ELPP_ASSEMBLY_SUPPORTED - } - - inline void unlock(void) { -#if _ELPP_ASSEMBLY_SUPPORTED -# if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) - asm volatile (_ELPP_MUTEX_UNLOCK_GNU_ASM(lockerFlag_)); -# elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)) - int *ptrLock = &lockerFlag_; - __asm { - mov eax,0 - mov ecx,ptrLock - xchg eax,[ecx] - } -# endif // defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) -#else -# if _ELPP_OS_UNIX - pthread_mutex_unlock(&underlyingMutex_); -# elif _ELPP_OS_WINDOWS - LeaveCriticalSection(&underlyingMutex_); -# endif // _ELPP_OS_UNIX -#endif // _ELPP_ASSEMBLY_SUPPORTED - } - private: -#if _ELPP_ASSEMBLY_SUPPORTED - int lockerFlag_; -#else -# if _ELPP_OS_UNIX - pthread_mutex_t underlyingMutex_; -# elif _ELPP_OS_WINDOWS - CRITICAL_SECTION underlyingMutex_; -# endif // _ELPP_OS_UNIX -#endif // _ELPP_ASSEMBLY_SUPPORTED - }; // class Mutex -//! -//! Scoped mutex that works same as C++11 std::lock_guard. Used internally, you should not use it. -//! - class ScopedLock : private internal::NoCopy { - public: - explicit ScopedLock(Mutex& m_) { - mutex_ = &m_; - mutex_->lock(); - } - - virtual ~ScopedLock(void) { - mutex_->unlock(); - } - private: - Mutex* mutex_; - ScopedLock(void); - }; // class ScopedLock - -//! -//! \return ID of current thread. If std::thread is available it uses get_id() otherwise if on windows it uses -//! GetCurrentThreadId() otherwise empty string. Used internally, you should not use it. -//! - inline std::string getCurrentThreadId(void) { - std::stringstream ss; -#if (_ELPP_STD_THREAD_AVAILABLE) - ss << std::this_thread::get_id(); -#else -# if (_ELPP_OS_WINDOWS) - ss << GetCurrentThreadId(); -# endif // (_ELPP_OS_WINDOWS) -#endif - return ss.str(); - } - - } // namespace threading - namespace utilities { - - template - inline void safeDelete(T*& pointer, bool checkNullity = true) { - if (checkNullity && pointer == NULL) return; - delete pointer; - pointer = NULL; - } - -//! -//! String utilities class used internally. You should not use it. -//! - class StringUtils : private internal::StaticClass { - public: - static inline std::string trim(const std::string &str) { - std::size_t s = str.find_first_not_of(" \n\r\t"); - std::size_t e = str.find_last_not_of(" \n\r\t"); - if ((s == std::string::npos) || (e == std::string::npos)) { - return ""; - } - else { - return str.substr(s, e - s + 1); - } - } - - static inline bool startsWith(const std::string& str, const std::string& start) { - return (str.length() >= start.length()) && (str.compare(0, start.length(), start) == 0); - } - - static inline bool endsWith(const std::string& str, const std::string& end) { - return (str.length() >= end.length()) && (str.compare(str.length() - end.length(), end.length(), end) == 0); - } - - static inline std::vector& split(const std::string& s, char delim, std::vector& elems) { - std::stringstream ss(s); - std::string item; - while (std::getline(ss, item, delim)) { - elems.push_back(item); - } - return elems; - } - - static inline std::string replaceAll(const std::string& str, const std::string& replaceWhat, const std::string& replaceWith) { - if (replaceWhat == replaceWith) - return str; - std::string result = str; - std::size_t foundAt = std::string::npos; - while ((foundAt = result.find(replaceWhat)) != std::string::npos) { - result.replace(foundAt, replaceWhat.length(), replaceWith); - } - return result; - } - - static inline std::string stripAllWhiteSpaces(const std::string& str) { - std::string result = replaceAll(str, " ", ""); - result = replaceAll(result, "\n", ""); - result = replaceAll(result, "\r", ""); - result = replaceAll(result, "\t", ""); - return result; - } - - static inline void tolower(std::string& str) { - std::transform(str.begin(), str.end(), str.begin(), ::tolower); - } - }; - -//! -//! Operating System utilities class used internally. You should not use it. -//! - class OSUtils : private internal::StaticClass { - public: -#if _ELPP_OS_WINDOWS - static const char* getWindowsEnvironmentVariable(const char* variableName) { - const DWORD bufferLen = 50; - static char buffer[bufferLen]; - if (GetEnvironmentVariableA(variableName, buffer, bufferLen)) { - return buffer; - } - return NULL; - } -#endif // _ELPP_OS_WINDOWS -#if _ELPP_NDK - static std::string getProperty(const char* prop) { - char propVal[PROP_VALUE_MAX + 1]; - __system_property_get(prop, propVal); - return std::string(propVal); +namespace internal { +/// @brief Mutex wrapper used when multi-threading is disabled. +class NoMutex : base::NoCopy { + public: + NoMutex(void) {} + inline void lock(void) {} + inline bool try_lock(void) { + return true; + } + inline void unlock(void) {} +}; +/// @brief Lock guard wrapper used when multi-threading is disabled. +template +class NoScopedLock : base::NoCopy { + public: + explicit NoScopedLock(Mutex&) { + } + virtual ~NoScopedLock(void) { + } + private: + NoScopedLock(void); +}; +} // namespace internal +typedef base::threading::internal::NoMutex Mutex; +typedef base::threading::internal::NoScopedLock ScopedLock; +#endif // ELPP_THREADING_ENABLED +/// @brief Base of thread safe class, this class is inheritable-only +class ThreadSafe { + public: + virtual inline void acquireLock(void) ELPP_FINAL { m_mutex.lock(); } + virtual inline void releaseLock(void) ELPP_FINAL { m_mutex.unlock(); } + virtual inline base::threading::Mutex& lock(void) ELPP_FINAL { return m_mutex; } + protected: + ThreadSafe(void) {} + virtual ~ThreadSafe(void) {} + private: + base::threading::Mutex m_mutex; +}; + +#if ELPP_THREADING_ENABLED +# if !ELPP_USE_STD_THREADING +/// @brief Gets ID of currently running threading in windows systems. On unix, nothing is returned. +static std::string getCurrentThreadId(void) { + std::stringstream ss; +# if (ELPP_OS_WINDOWS) + ss << GetCurrentThreadId(); +# endif // (ELPP_OS_WINDOWS) + return ss.str(); +} +# else +/// @brief Gets ID of currently running threading using std::this_thread::get_id() +static std::string getCurrentThreadId(void) { + std::stringstream ss; + ss << std::this_thread::get_id(); + return ss.str(); +} +# endif // !ELPP_USE_STD_THREADING +#else +static inline std::string getCurrentThreadId(void) { + return std::string(); +} +#endif // ELPP_THREADING_ENABLED +} // namespace threading +namespace utils { +class File : base::StaticClass { + public: + /// @brief Creates new out file stream for specified filename. + /// @return Pointer to newly created fstream or nullptr + static base::type::fstream_t* newFileStream(const std::string& filename); + + /// @brief Gets size of file provided in stream + static std::size_t getSizeOfFile(base::type::fstream_t* fs); + + /// @brief Determines whether or not provided path exist in current file system + static bool pathExists(const char* path, bool considerFile = false); + + /// @brief Creates specified path on file system + /// @param path Path to create. + static bool createPath(const std::string& path); + /// @brief Extracts path of filename with leading slash + static std::string extractPathFromFilename(const std::string& fullPath, + const char* seperator = base::consts::kFilePathSeperator); + /// @brief builds stripped filename and puts it in buff + static void buildStrippedFilename(const char* filename, char buff[], + std::size_t limit = base::consts::kSourceFilenameMaxLength); + /// @brief builds base filename and puts it in buff + static void buildBaseFilename(const std::string& fullPath, char buff[], + std::size_t limit = base::consts::kSourceFilenameMaxLength, + const char* seperator = base::consts::kFilePathSeperator); +}; +/// @brief String utilities helper class used internally. You should not use it. +class Str : base::StaticClass { + public: + /// @brief Checks if character is digit. Dont use libc implementation of it to prevent locale issues. + static inline bool isDigit(char c) { + return c >= '0' && c <= '9'; + } + + /// @brief Matches wildcards, '*' and '?' only supported. + static bool wildCardMatch(const char* str, const char* pattern); + + static std::string& ltrim(std::string& str); + static std::string& rtrim(std::string& str); + static std::string& trim(std::string& str); + + /// @brief Determines whether or not str starts with specified string + /// @param str String to check + /// @param start String to check against + /// @return Returns true if starts with specified string, false otherwise + static bool startsWith(const std::string& str, const std::string& start); + + /// @brief Determines whether or not str ends with specified string + /// @param str String to check + /// @param end String to check against + /// @return Returns true if ends with specified string, false otherwise + static bool endsWith(const std::string& str, const std::string& end); + + /// @brief Replaces all instances of replaceWhat with 'replaceWith'. Original variable is changed for performance. + /// @param [in,out] str String to replace from + /// @param replaceWhat Character to replace + /// @param replaceWith Character to replace with + /// @return Modified version of str + static std::string& replaceAll(std::string& str, char replaceWhat, char replaceWith); + + /// @brief Replaces all instances of 'replaceWhat' with 'replaceWith'. (String version) Replaces in place + /// @param str String to replace from + /// @param replaceWhat Character to replace + /// @param replaceWith Character to replace with + /// @return Modified (original) str + static std::string& replaceAll(std::string& str, const std::string& replaceWhat, + const std::string& replaceWith); + + static void replaceFirstWithEscape(base::type::string_t& str, const base::type::string_t& replaceWhat, + const base::type::string_t& replaceWith); +#if defined(ELPP_UNICODE) + static void replaceFirstWithEscape(base::type::string_t& str, const base::type::string_t& replaceWhat, + const std::string& replaceWith); +#endif // defined(ELPP_UNICODE) + /// @brief Converts string to uppercase + /// @param str String to convert + /// @return Uppercase string + static std::string& toUpper(std::string& str); + + /// @brief Compares cstring equality - uses strcmp + static bool cStringEq(const char* s1, const char* s2); + + /// @brief Compares cstring equality (case-insensitive) - uses toupper(char) + /// Dont use strcasecmp because of CRT (VC++) + static bool cStringCaseEq(const char* s1, const char* s2); + + /// @brief Returns true if c exist in str + static bool contains(const char* str, char c); + + static char* convertAndAddToBuff(std::size_t n, int len, char* buf, const char* bufLim, bool zeroPadded = true); + static char* addToBuff(const char* str, char* buf, const char* bufLim); + static char* clearBuff(char buff[], std::size_t lim); + + /// @brief Converst wchar* to char* + /// NOTE: Need to free return value after use! + static char* wcharPtrToCharPtr(const wchar_t* line); +}; +/// @brief Operating System helper static class used internally. You should not use it. +class OS : base::StaticClass { + public: +#if ELPP_OS_WINDOWS + /// @brief Gets environment variables for Windows based OS. + /// We are not using getenv(const char*) because of CRT deprecation + /// @param varname Variable name to get environment variable value for + /// @return If variable exist the value of it otherwise nullptr + static const char* getWindowsEnvironmentVariable(const char* varname); +#endif // ELPP_OS_WINDOWS +#if ELPP_OS_ANDROID + /// @brief Reads android property value + static std::string getProperty(const char* prop); + + /// @brief Reads android device name + static std::string getDeviceName(void); +#endif // ELPP_OS_ANDROID + + /// @brief Runs command on terminal and returns the output. + /// + /// @detail This is applicable only on unix based systems, for all other OS, an empty string is returned. + /// @param command Bash command + /// @return Result of bash output or empty string if no result found. + static const std::string getBashOutput(const char* command); + + /// @brief Gets environment variable. This is cross-platform and CRT safe (for VC++) + /// @param variableName Environment variable name + /// @param defaultVal If no environment variable or value found the value to return by default + /// @param alternativeBashCommand If environment variable not found what would be alternative bash command + /// in order to look for value user is looking for. E.g, for 'user' alternative command will 'whoami' + static std::string getEnvironmentVariable(const char* variableName, const char* defaultVal, + const char* alternativeBashCommand = nullptr); + /// @brief Gets current username. + static std::string currentUser(void); + + /// @brief Gets current host name or computer name. + /// + /// @detail For android systems this is device name with its manufacturer and model seperated by hyphen + static std::string currentHost(void); + /// @brief Whether or not terminal supports colors + static bool termSupportsColor(void); +}; +/// @brief Contains utilities for cross-platform date/time. This class make use of el::base::utils::Str +class DateTime : base::StaticClass { + public: + /// @brief Cross platform gettimeofday for Windows and unix platform. This can be used to determine current microsecond. + /// + /// @detail For unix system it uses gettimeofday(timeval*, timezone*) and for Windows, a seperate implementation is provided + /// @param [in,out] tv Pointer that gets updated + static void gettimeofday(struct timeval* tv); + + /// @brief Gets current date and time with a subsecond part. + /// @param format User provided date/time format + /// @param ssPrec A pointer to base::SubsecondPrecision from configuration (non-null) + /// @returns string based date time in specified format. + static std::string getDateTime(const char* format, const base::SubsecondPrecision* ssPrec); + + /// @brief Converts timeval (struct from ctime) to string using specified format and subsecond precision + static std::string timevalToString(struct timeval tval, const char* format, + const el::base::SubsecondPrecision* ssPrec); + + /// @brief Formats time to get unit accordingly, units like second if > 1000 or minutes if > 60000 etc + static base::type::string_t formatTime(unsigned long long time, base::TimestampUnit timestampUnit); + + /// @brief Gets time difference in milli/micro second depending on timestampUnit + static unsigned long long getTimeDifference(const struct timeval& endTime, const struct timeval& startTime, + base::TimestampUnit timestampUnit); + + + static struct ::tm* buildTimeInfo(struct timeval* currTime, struct ::tm* timeInfo); + private: + static char* parseFormat(char* buf, std::size_t bufSz, const char* format, const struct tm* tInfo, + std::size_t msec, const base::SubsecondPrecision* ssPrec); +}; +/// @brief Command line arguments for application if specified using el::Helpers::setArgs(..) or START_EASYLOGGINGPP(..) +class CommandLineArgs { + public: + CommandLineArgs(void) { + setArgs(0, static_cast(nullptr)); + } + CommandLineArgs(int argc, const char** argv) { + setArgs(argc, argv); + } + CommandLineArgs(int argc, char** argv) { + setArgs(argc, argv); + } + virtual ~CommandLineArgs(void) {} + /// @brief Sets arguments and parses them + inline void setArgs(int argc, const char** argv) { + setArgs(argc, const_cast(argv)); + } + /// @brief Sets arguments and parses them + void setArgs(int argc, char** argv); + /// @brief Returns true if arguments contain paramKey with a value (seperated by '=') + bool hasParamWithValue(const char* paramKey) const; + /// @brief Returns value of arguments + /// @see hasParamWithValue(const char*) + const char* getParamValue(const char* paramKey) const; + /// @brief Return true if arguments has a param (not having a value) i,e without '=' + bool hasParam(const char* paramKey) const; + /// @brief Returns true if no params available. This exclude argv[0] + bool empty(void) const; + /// @brief Returns total number of arguments. This exclude argv[0] + std::size_t size(void) const; + friend base::type::ostream_t& operator<<(base::type::ostream_t& os, const CommandLineArgs& c); + + private: + int m_argc; + char** m_argv; + std::unordered_map m_paramsWithValue; + std::vector m_params; +}; +/// @brief Abstract registry (aka repository) that provides basic interface for pointer repository specified by T_Ptr type. +/// +/// @detail Most of the functions are virtual final methods but anything implementing this abstract class should implement +/// unregisterAll() and deepCopy(const AbstractRegistry&) and write registerNew() method according to container +/// and few more methods; get() to find element, unregister() to unregister single entry. +/// Please note that this is thread-unsafe and should also implement thread-safety mechanisms in implementation. +template +class AbstractRegistry : public base::threading::ThreadSafe { + public: + typedef typename Container::iterator iterator; + typedef typename Container::const_iterator const_iterator; + + /// @brief Default constructor + AbstractRegistry(void) {} + + /// @brief Move constructor that is useful for base classes + AbstractRegistry(AbstractRegistry&& sr) { + if (this == &sr) { + return; } + unregisterAll(); + m_list = std::move(sr.m_list); + } - static std::string getDeviceName(void) { - std::stringstream ss; - std::string manufacturer = getProperty("ro.product.manufacturer"); - std::string model = getProperty("ro.product.model"); - if (manufacturer.empty() && model.empty()) { - return std::string(); - } - ss << manufacturer << " " << model; - return ss.str(); + bool operator==(const AbstractRegistry& other) { + if (size() != other.size()) { + return false; } -#endif // _ELPP_NDK - // Runs command on terminal and returns the output. - // This is applicable only on linux and mac, for all other OS, an empty string is returned. - static const std::string getBashOutput(const char* command_) { - if (command_ == NULL) { - return std::string(); - } -#if _ELPP_OS_UNIX && !_ELPP_NDK - FILE* proc = NULL; - if ((proc = popen(command_, "r")) == NULL) { - std::cerr << "\nUnable to run command [" << command_ << "]" << std::endl; - return std::string(); - } - char hBuff[4096]; - if (fgets(hBuff, sizeof(hBuff), proc) != NULL) { - pclose(proc); - if (hBuff[strlen(hBuff) - 1] == '\n') { - hBuff[strlen(hBuff) - 1] = '\0'; - } - return std::string(hBuff); - } - return std::string(); -#else - return std::string(); -#endif // _ELPP_OS_UNIX - } - - static std::string getEnvironmentVariable(const char* variableName, const char* defaultVal, const char* alternativeBashCommand = NULL) { -#if _ELPP_OS_UNIX - const char* val = getenv(variableName); -#elif _ELPP_OS_WINDOWS - const char* val = getWindowsEnvironmentVariable(variableName); -#endif // _ELPP_OS_UNIX - if ((val == NULL) || ((strcmp(val, "") == 0))) { -#if _ELPP_OS_UNIX - // Try harder on unix-based systems - std::string valBash = internal::utilities::OSUtils::getBashOutput(alternativeBashCommand); - if (valBash.empty()) { - return std::string(defaultVal); - } else { - return valBash; - } -#elif _ELPP_OS_WINDOWS - return std::string(defaultVal); -#endif // _ELPP_OS_WINDOWS - } - return std::string(val); - } - - // Gets current username. - static const std::string currentUser(void) { -#if _ELPP_OS_UNIX && !_ELPP_NDK - return getEnvironmentVariable("USER", "user", "whoami"); -#elif _ELPP_OS_WINDOWS - return getEnvironmentVariable("USERNAME", "user"); -#elif _ELPP_NDK - return std::string("android"); -#else - return std::string(); -#endif // _ELPP_OS_UNIX - } - - // Gets current host name or computer name. - static const std::string currentHost(void) { -#if _ELPP_OS_UNIX && !_ELPP_NDK - return getEnvironmentVariable("HOSTNAME", "unknown-host", "hostname"); -#elif _ELPP_OS_WINDOWS - return getEnvironmentVariable("COMPUTERNAME", "unknown-host"); -#elif _ELPP_NDK - return getDeviceName(); -#else - return std::string(); -#endif // _ELPP_OS_UNIX - } - - // Determines whether or not provided path_ exist in current file system - static inline bool pathExists(const char* path_) { - if (path_ == NULL) { - return false; - } -#if _ELPP_OS_UNIX - struct stat st; - return (stat(path_, &st) == 0); -#elif _ELPP_OS_WINDOWS - DWORD fileType = GetFileAttributesA(path_); - if (fileType == INVALID_FILE_ATTRIBUTES) { - return false; - } - return (fileType & FILE_ATTRIBUTE_DIRECTORY) == 0 ? false : true; -#endif // _ELPP_OS_UNIX - } - - // Creates path as specified - static bool createPath(const std::string& path_) { - if (path_.empty()) { - return false; - } - if (internal::utilities::OSUtils::pathExists(path_.c_str())) { - return true; - } -#if _ELPP_OS_UNIX - const char* pathDelim_ = "/"; -#elif _ELPP_OS_WINDOWS - char pathDelim_[] = "\\"; -#endif // _ELPP_OS_UNIX - int status = -1; - - char* currPath_ = const_cast(path_.c_str()); - std::string buildingPath_ = std::string(); -#if _ELPP_OS_UNIX - if (path_[0] == '/') { - buildingPath_ = "/"; - } - currPath_ = STRTOK(currPath_, pathDelim_, 0); -#elif _ELPP_OS_WINDOWS - // Use secure functions API - char* nextTok_; - currPath_ = STRTOK(currPath_, pathDelim_, &nextTok_); -#endif // _ELPP_OS_UNIX - while (currPath_ != NULL) { - buildingPath_.append(currPath_); - buildingPath_.append(pathDelim_); -#if _ELPP_OS_UNIX - status = mkdir(buildingPath_.c_str(), _LOG_PERMS); - currPath_ = STRTOK(NULL, pathDelim_, 0); -#elif _ELPP_OS_WINDOWS - status = _mkdir(buildingPath_.c_str()); - currPath_ = STRTOK(NULL, pathDelim_, &nextTok_); -#endif // _ELPP_OS_UNIX - } - if (status == -1) { - return false; - } - return true; - } - - static std::string getPathFromFilename(const std::string& fullPath_, internal::Constants* constants_) { - if (fullPath_ == "" || fullPath_.find(constants_->PATH_SLASH) == std::string::npos) { - return fullPath_; - } - std::size_t lastSlashAt = fullPath_.find_last_of(constants_->PATH_SLASH); - if (lastSlashAt == 0) { - return constants_->PATH_SLASH; - } - return fullPath_.substr(0, lastSlashAt + 1); - } - }; // class OSUtils - -//! -//! Contains static functions related to log manipulation used internally. You should not use it. -//! - class LogManipulator : private internal::StaticClass { - public: - // Updates the formatSpecifier_ for currentFormat_ to value_ provided - static void updateFormatValue(const std::string& formatSpecifier_, - const std::string& value_, std::string& currentFormat_, - internal::Constants* constants_) { - std::size_t foundAt = std::string::npos; - while ((foundAt = currentFormat_.find(formatSpecifier_, foundAt + 1)) != std::string::npos){ - if (currentFormat_[foundAt > 0 ? foundAt - 1 : 0] == constants_->FORMAT_SPECIFIER_ESCAPE_CHAR) { - currentFormat_.erase(foundAt > 0 ? foundAt - 1 : 0, 1); - ++foundAt; - } else { - currentFormat_ = currentFormat_.replace(foundAt, formatSpecifier_.size(), value_); - return; - } - } - } - }; // class LogManipulator - -//! -//! Contains utility functions related to date/time used internally. You should not use it. -//! - class DateUtils : private internal::StaticClass { - public: -#if _ELPP_OS_WINDOWS - static void gettimeofday(struct timeval *tv) { - if (tv != NULL) { -# if defined(_MSC_EXTENSIONS) - const unsigned __int64 delta_ = 11644473600000000Ui64; -# else - const unsigned __int64 delta_ = 11644473600000000ULL; -# endif // defined(_MSC_EXTENSIONS) - const double secOffSet = 0.000001; - const unsigned long usecOffSet = 1000000; - FILETIME fileTime_; - GetSystemTimeAsFileTime(&fileTime_); - unsigned __int64 present_ = 0; - present_ |= fileTime_.dwHighDateTime; - present_ = present_ << 32; - present_ |= fileTime_.dwLowDateTime; - present_ /= 10; // mic-sec - // Subtract the difference - present_ -= delta_; - tv->tv_sec = static_cast(present_ * secOffSet); - tv->tv_usec = static_cast(present_ % usecOffSet); - } + for (std::size_t i = 0; i < m_list.size(); ++i) { + if (m_list.at(i) != other.m_list.at(i)) { + return false; + } } -#endif // _ELPP_OS_WINDOWS - - // Gets current date and time with milliseconds. - static std::string getDateTime(const std::string& bufferFormat_, unsigned int type_, internal::Constants* constants_, std::size_t milliSecondOffset_ = 1000) { - long milliSeconds = 0; - const int kDateBuffSize_ = 30; - char dateBuffer_[kDateBuffSize_] = ""; - char dateBufferOut_[kDateBuffSize_] = ""; -#if _ELPP_OS_UNIX - bool hasTime_ = ((type_ & constants_->kDateTime) || (type_ & constants_->kTimeOnly)); - timeval currTime; - gettimeofday(&currTime, NULL); - if (hasTime_) { - milliSeconds = currTime.tv_usec / milliSecondOffset_ ; - } - struct tm * timeInfo = localtime(&currTime.tv_sec); - strftime(dateBuffer_, sizeof(dateBuffer_), bufferFormat_.c_str(), timeInfo); - if (hasTime_) { - SPRINTF(dateBufferOut_, "%s.%03ld", dateBuffer_, milliSeconds); - } else { - SPRINTF(dateBufferOut_, "%s", dateBuffer_); - } -#elif _ELPP_OS_WINDOWS - const char* kTimeFormatLocal_ = "HH':'mm':'ss"; - const char* kDateFormatLocal_ = "dd/MM/yyyy"; - if ((type_ & constants_->kDateTime) || (type_ & constants_->kDateOnly)) { - if (GetDateFormatA(LOCALE_USER_DEFAULT, 0, 0, kDateFormatLocal_, dateBuffer_, kDateBuffSize_) != 0) { - SPRINTF(dateBufferOut_, "%s", dateBuffer_); - } - } - if ((type_ & constants_->kDateTime) || (type_ & constants_->kTimeOnly)) { - if (GetTimeFormatA(LOCALE_USER_DEFAULT, 0, 0, kTimeFormatLocal_, dateBuffer_, kDateBuffSize_) != 0) { - milliSeconds = static_cast(GetTickCount()) % milliSecondOffset_; - if (type_ & constants_->kDateTime) { - SPRINTF(dateBufferOut_, "%s %s.%03ld", dateBufferOut_, dateBuffer_, milliSeconds); - } else { - SPRINTF(dateBufferOut_, "%s.%03ld", dateBuffer_, milliSeconds); - } - } - } -#endif // _ELPP_OS_UNIX - return std::string(dateBufferOut_); - } - - static std::string formatMilliSeconds(double milliSeconds_) { - double result = milliSeconds_; - std::string unit = "ms"; - std::stringstream stream_; - if (result > 1000.0f) { - result /= 1000; unit = "seconds"; - if (result > 60.0f) { - result /= 60; unit = "minutes"; - if (result > 60.0f) { - result /= 60; unit = "hours"; - if (result > 24.0f) { - result /= 24; unit = "days"; - } - } - } - } - stream_ << result << " " << unit; - return stream_.str(); - } - - static inline double getTimeDifference(const timeval& endTime_, const timeval& startTime_) { - return static_cast((((endTime_.tv_sec - startTime_.tv_sec) * 1000000) + (endTime_.tv_usec - startTime_.tv_usec)) / 1000); - } - }; // class DateUtils - } // namespace utilities - -//! -//! Internal repository base to manage memory on heap. Used internally, you should not use it. -//! - template - class Registry { - public: - Registry(void) { - } - - virtual ~Registry(void) { - unregisterAll(); - } - - Registry(const Registry& other_) { - if (this != &other_) { - unregisterAll(); - for (std::size_t i = 0; i < other_.list_.size(); ++i) { - Class* curr_ = other_.list_.at(i); - if (curr_) { - list_.push_back(new Class(*curr_)); - } - } - } - } - - Registry& operator=(const Registry& other_) { - if (this == &other_) { - return *this; - } - unregisterAll(); - for (std::size_t i = 0; i < other_.list_.size(); ++i) { - Class* curr_ = other_.list_.at(i); - if (curr_) { - list_.push_back(new Class(*curr_)); - } - } - return *this; - } - - inline void registerNew(Class* c_) { - list_.push_back(c_); - } - - bool operator!=(const Registry& other_) { - if (list_.size() != other_.list_.size()) { - return true; - } - for (std::size_t i = 0; i < list_.size(); ++i) { - if (list_.at(i) != other_.list_.at(i)) { - return true; - } - } - return false; - } - - bool operator==(const Registry& other_) { - if (list_.size() != other_.list_.size()) { - return false; - } - for (std::size_t i = 0; i < list_.size(); ++i) { - if (list_.at(i) != other_.list_.at(i)) { - return false; - } - } - return true; - } - - template - Class* get(const T& t_) { - Iterator iter = std::find_if(list_.begin(), list_.end(), Predicate(t_)); - if (iter != list_.end() && *iter != NULL) { - return *iter; - } - return NULL; - } - - template - Class* get(const T& t_, const T2& t2_) { - Iterator iter = std::find_if(list_.begin(), list_.end(), Predicate(t_, t2_)); - if (iter != list_.end() && *iter != NULL) { - return *iter; - } - return NULL; - } - - template - inline bool exist(const T& t_) { - return (get(t_) != NULL); - } - - inline std::size_t count(void) const { - return list_.size(); - } - - inline bool empty(void) const { - return list_.empty(); - } - - Class* at(std::size_t i) const { - return list_.at(i); - } - - protected: - typedef typename std::vector::iterator Iterator; - - inline void unregisterAll(void) { - if (!empty()) { - std::for_each(list_.begin(), list_.end(), std::bind1st(std::mem_fun(&Registry::release), this)); - list_.clear(); - } - } - - inline void unregister(Class*& c_) { - if (c_) { - Iterator iter = list_.begin(); - for (; iter != list_.end(); ++iter) { - if (c_ == *iter) { - break; - } - } - if (iter != list_.end() && *iter != NULL) { - list_.erase(iter); - internal::utilities::safeDelete(c_); - } - } - } - - inline std::vector& list(void) { - return list_; - } - private: - std::vector list_; - - inline void release(Class* c_) { - internal::utilities::safeDelete(c_); - } - }; // class Registry - -//! -//! Scoped pointer used internally. You should not use it. -//! - template - class ScopedPointer { - public: - explicit ScopedPointer(T* ptr_ = 0) : - ptr_(ptr_), referenceCounter_(0) { - referenceCounter_ = new ReferenceCounter(); - referenceCounter_->increment(); - } - - ScopedPointer(const ScopedPointer& scopedPointer_) : - ptr_(scopedPointer_.ptr_), referenceCounter_(scopedPointer_.referenceCounter_) { - referenceCounter_->increment(); - } - - ScopedPointer& operator=(const ScopedPointer& other_) { - if (this != &other_) - { - validate(); - ptr_ = other_.ptr_; - referenceCounter_ = other_.referenceCounter_; - referenceCounter_->increment(); - } - return *this; - } - - virtual ~ScopedPointer(void) { - validate(); - } - - T& operator*(void) { - return *ptr_; - } - - T* operator->(void) { - return ptr_; - } - - T* pointer(void) { - return ptr_; - } - - class ReferenceCounter { - public: - ReferenceCounter(void) : count_(0) { - } - - ReferenceCounter& operator=(const ReferenceCounter& other_) { - if (this != &other_) { - count_ = other_.count_; - } - return *this; - } - - void increment(void) { - ++count_; - } - - int decrement(void) { - return this == NULL ? 0 : --count_; - } - - private: - int count_; - }; - private: - T* ptr_; - ReferenceCounter* referenceCounter_; - - void validate(void) { - if(referenceCounter_->decrement() == 0) { - internal::utilities::safeDelete(ptr_, false); - internal::utilities::safeDelete(referenceCounter_, false); - } - } - }; - -//! -//! Class that represents single configuration. -//! -//! Single configuration has a level (easyloggingpp::Level), type (easyloggingpp::ConfigurationType) -//! and std::string based value. This value is later parsed into more appropriate data type depending on -//! type -//! - class Configuration { - public: - //! - //! Full constructor used to set initial value of configuration - //! \param level_ - //! \param type_ - //! \param value_ - //! - Configuration(unsigned int level_, unsigned int type_, const std::string& value_) : - level_(level_), - type_(type_), - value_(value_) { - } - - //! - //! \return Level of current configuration - //! - unsigned int level(void) const { - return level_; - } - - //! - //! \return Configuration type of current configuration - //! - unsigned int type(void) const { - return type_; - } - - //! - //! \return String based configuration value - //! - std::string value(void) const { - return value_; - } - - //! - //! Set string based configuration value - //! \param value_ Value to set. Values have to be std::string; For boolean values use "true", "false", for any integral values - //! use them in quotes. They will be parsed when configuring - //! - void setValue(const std::string& value_) { - this->value_ = value_; - } - - //! - //! Predicate used to find configuration from configuration repository. This is used internally. - //! - class Predicate { - public: - Predicate(unsigned int level_, unsigned int type_) : - level_(level_), - type_(type_) { - } - - bool operator()(const Configuration* conf_) { - return ((conf_ != NULL) && (conf_->level() == level_) && (conf_->type() == type_)); - } - - private: - unsigned int level_; - unsigned int type_; - }; - private: - unsigned int level_; - unsigned int type_; - std::string value_; - }; - - } // namespace internal - -//! -//! Configuration repository that represents configuration for single logger -//! - class Configurations : public internal::Registry { - public: - //! - //! Default constructor - //! - Configurations(void) : - isFromFile_(false) { - } - - //! - //! Constructor used to set configurations via configuration file - //! \param configurationFile_ Full path to configuration file - //! \param base_ Configurations to base new configuration repository off. This value is used when you want to use - //! existing Configurations to base all the values and then set rest of configuration via configuration file. - //! - Configurations(const std::string& configurationFile_, Configurations* base_ = NULL) : - configurationFile_(configurationFile_), - isFromFile_(false) { - parseFromFile(configurationFile_, base_); - } + return true; + } - //! - //! Set configurations based on other configurations - //! \param base_ Pointer to existing configurations. - //! - inline void setFromBase(Configurations* base_) { - if (base_ == NULL || base_ == this) return; - std::for_each(base_->list().begin(), base_->list().end(), std::bind1st(std::mem_fun(&Configurations::set), this)); - } - - //! - //! Checks to see whether specified configuration type exist in this repository - //! \param configurationType_ Configuration type to check against. Use easyloggingpp::ConfigurationType to prevent confusions - //! \return True if exist, false otherwise - //! - inline bool contains(unsigned int configurationType_) { - ELPP_FOR_EACH_CONFIGURATION(i, ConfigurationType::kMinValid, - if (get(i, configurationType_) != NULL) { - return true; - } - ); - return false; - } + bool operator!=(const AbstractRegistry& other) { + if (size() != other.size()) { + return true; + } + for (std::size_t i = 0; i < m_list.size(); ++i) { + if (m_list.at(i) != other.m_list.at(i)) { + return true; + } + } + return false; + } - //! - //! Sets configuration for specified level_ and configurationType_. If configuration already exists for specified - //! level and configuration type, value just gets updated. - //! Remember, it is not recommended to set skip_ELPPALL_Check to false unless you know exactly what you are doing - //! \param level_ Level to set configuration for. Use easyloggingpp::Level to prevent confusion - //! \param configurationType_ Configuration type to set configuration against. Use easyloggingpp::ConfigurationType to prevent confusion - //! \param value_ String based configuration value - //! \param skipLEVEL_ALL Determines whether to skip 'easyloggingpp::Level::All'. This is skipped by default because setting - //! 'All' may override configuration. Be careful with this. - //! - void set(unsigned int level_, unsigned int configurationType_, const std::string& value_, bool skipLEVEL_ALL = false) { - if (value_ == "") return; // ignore empty values - if ((configurationType_ == ConfigurationType::PerformanceTracking && level_ != Level::All) || - (configurationType_ == ConfigurationType::MillisecondsWidth && level_ != Level::All)) { - // configurationType_ not applicable for this level_ - return; - } - internal::Configuration* conf_ = get(level_, configurationType_); - if (conf_ == NULL) { - registerNew(new internal::Configuration(level_, configurationType_, value_)); - } else { - // Configuration already there, just update the value! - conf_->setValue(value_); - } - if (!skipLEVEL_ALL && level_ == Level::All) { - setAll(configurationType_, value_, true); - } - } + /// @brief Assignment move operator + AbstractRegistry& operator=(AbstractRegistry&& sr) { + if (this == &sr) { + return *this; + } + unregisterAll(); + m_list = std::move(sr.m_list); + return *this; + } + + virtual ~AbstractRegistry(void) { + } + + /// @return Iterator pointer from start of repository + virtual inline iterator begin(void) ELPP_FINAL { + return m_list.begin(); + } + + /// @return Iterator pointer from end of repository + virtual inline iterator end(void) ELPP_FINAL { + return m_list.end(); + } + + + /// @return Constant iterator pointer from start of repository + virtual inline const_iterator cbegin(void) const ELPP_FINAL { + return m_list.cbegin(); + } + + /// @return End of repository + virtual inline const_iterator cend(void) const ELPP_FINAL { + return m_list.cend(); + } + + /// @return Whether or not repository is empty + virtual inline bool empty(void) const ELPP_FINAL { + return m_list.empty(); + } + + /// @return Size of repository + virtual inline std::size_t size(void) const ELPP_FINAL { + return m_list.size(); + } + + /// @brief Returns underlying container by reference + virtual inline Container& list(void) ELPP_FINAL { + return m_list; + } + + /// @brief Returns underlying container by constant reference. + virtual inline const Container& list(void) const ELPP_FINAL { + return m_list; + } + + /// @brief Unregisters all the pointers from current repository. + virtual void unregisterAll(void) = 0; + + protected: + virtual void deepCopy(const AbstractRegistry&) = 0; + void reinitDeepCopy(const AbstractRegistry& sr) { + unregisterAll(); + deepCopy(sr); + } + + private: + Container m_list; +}; - //! - //! Parse configuration from file. - //! \param configurationFile_ - //! \param base_Configurations to base new configuration repository off. This value is used when you want to use - //! existing Configurations to base all the values and then set rest of configuration via configuration file. - //! \return True if successfully parsed, false otherwise. You may define '_STOP_ON_FIRST_ELPP_ASSERTION' to make sure you - //! do not proceed without successful parse. - //! - bool parseFromFile(const std::string& configurationFile_, Configurations* base_ = NULL) { - setFromBase(base_); - std::ifstream fileStream_(configurationFile_.c_str(), std::ifstream::in); - __EASYLOGGINGPP_ASSERT(fileStream_.is_open(), "Unable to open configuration file [" << configurationFile_ << "] for parsing."); - bool parsedSuccessfully_ = false; - std::string line = std::string(); - unsigned int currLevel = 0; - while (fileStream_.good()) { - std::getline(fileStream_, line); - parsedSuccessfully_ = Parser::parseLine(line, currLevel, this); - __EASYLOGGINGPP_ASSERT(parsedSuccessfully_, "Unable to parse configuration line: " << line); - } - isFromFile_ = true; - return parsedSuccessfully_; - } +/// @brief A pointer registry mechanism to manage memory and provide search functionalities. (non-predicate version) +/// +/// @detail NOTE: This is thread-unsafe implementation (although it contains lock function, it does not use these functions) +/// of AbstractRegistry. Any implementation of this class should be +/// explicitly (by using lock functions) +template +class Registry : public AbstractRegistry> { + public: + typedef typename Registry::iterator iterator; + typedef typename Registry::const_iterator const_iterator; + + Registry(void) {} + + /// @brief Copy constructor that is useful for base classes. Try to avoid this constructor, use move constructor. + Registry(const Registry& sr) : AbstractRegistry>() { + if (this == &sr) { + return; + } + this->reinitDeepCopy(sr); + } + + /// @brief Assignment operator that unregisters all the existing registeries and deeply copies each of repo element + /// @see unregisterAll() + /// @see deepCopy(const AbstractRegistry&) + Registry& operator=(const Registry& sr) { + if (this == &sr) { + return *this; + } + this->reinitDeepCopy(sr); + return *this; + } + + virtual ~Registry(void) { + unregisterAll(); + } + + protected: + virtual void unregisterAll(void) ELPP_FINAL { + if (!this->empty()) { + for (auto&& curr : this->list()) { + base::utils::safeDelete(curr.second); + } + this->list().clear(); + } + } + +/// @brief Registers new registry to repository. + virtual void registerNew(const T_Key& uniqKey, T_Ptr* ptr) ELPP_FINAL { + unregister(uniqKey); + this->list().insert(std::make_pair(uniqKey, ptr)); + } + +/// @brief Unregisters single entry mapped to specified unique key + void unregister(const T_Key& uniqKey) { + T_Ptr* existing = get(uniqKey); + if (existing != nullptr) { + this->list().erase(uniqKey); + base::utils::safeDelete(existing); + } + } + +/// @brief Gets pointer from repository. If none found, nullptr is returned. + T_Ptr* get(const T_Key& uniqKey) { + iterator it = this->list().find(uniqKey); + return it == this->list().end() + ? nullptr + : it->second; + } + + private: + virtual void deepCopy(const AbstractRegistry>& sr) ELPP_FINAL { + for (const_iterator it = sr.cbegin(); it != sr.cend(); ++it) { + registerNew(it->first, new T_Ptr(*it->second)); + } + } +}; - //! - //! Parse configurations from configuration string. This configuration string has same syntax as configuration file contents. Make - //! sure all the necessary new line characters are provided. - //! \param configurationsString - //! \return True if successfully parsed, false otherwise. You may define '_STOP_ON_FIRST_ELPP_ASSERTION' to make sure you - //! do not proceed without successful parse. - //! - bool parseFromText(const std::string& configurationsString) { - bool parsedSuccessfully_ = false; - std::string line = std::string(); - unsigned int currLevel = 0; - std::vector lines; - internal::utilities::StringUtils::split(configurationsString, '\n', lines); - for (std::size_t i = 0; i < lines.size(); ++i) { - line = lines.at(i); - parsedSuccessfully_ = Parser::parseLine(line, currLevel, this); - __EASYLOGGINGPP_ASSERT(parsedSuccessfully_, "Unable to parse configuration line: " << line); - } - isFromFile_ = false; - return parsedSuccessfully_; - } +/// @brief A pointer registry mechanism to manage memory and provide search functionalities. (predicate version) +/// +/// @detail NOTE: This is thread-unsafe implementation of AbstractRegistry. Any implementation of this class +/// should be made thread-safe explicitly +template +class RegistryWithPred : public AbstractRegistry> { + public: + typedef typename RegistryWithPred::iterator iterator; + typedef typename RegistryWithPred::const_iterator const_iterator; + + RegistryWithPred(void) { + } + + virtual ~RegistryWithPred(void) { + unregisterAll(); + } + + /// @brief Copy constructor that is useful for base classes. Try to avoid this constructor, use move constructor. + RegistryWithPred(const RegistryWithPred& sr) : AbstractRegistry>() { + if (this == &sr) { + return; + } + this->reinitDeepCopy(sr); + } + + /// @brief Assignment operator that unregisters all the existing registeries and deeply copies each of repo element + /// @see unregisterAll() + /// @see deepCopy(const AbstractRegistry&) + RegistryWithPred& operator=(const RegistryWithPred& sr) { + if (this == &sr) { + return *this; + } + this->reinitDeepCopy(sr); + return *this; + } - //! - //! Sets configurations to default configurations set by easylogging++. - //! NOTE: This has nothing to do with Loggers::setDefaultConfigurations - thats completely different thing. This is - //! library's own default format. - //! - void setToDefault(void) { - setAll(ConfigurationType::Enabled, "true"); -#if _ELPP_OS_UNIX -# if _ELPP_NDK - setAll(ConfigurationType::Filename, "/data/local/tmp/myeasylog.txt"); -# else - setAll(ConfigurationType::Filename, "/tmp/logs/myeasylog.log"); -# endif // _ELPP_NDK -#elif _ELPP_OS_WINDOWS - setAll(ConfigurationType::Filename, "logs\\myeasylog.log"); -#endif // _ELPP_OS_UNIX - setAll(ConfigurationType::ToFile, "true"); - setAll(ConfigurationType::ToStandardOutput, "true"); - setAll(ConfigurationType::MillisecondsWidth, "3"); - setAll(ConfigurationType::PerformanceTracking, "false"); - setAll(easyloggingpp::ConfigurationType::RollOutSize, "0"); - setAll(ConfigurationType::Format, "%datetime %level [%logger] %log"); - set(Level::Debug, ConfigurationType::Format, "%datetime %level [%logger] [%user@%host] [%func] [%loc] %log"); - // INFO and WARNING are set to default by Level::ALL - set(Level::Error, ConfigurationType::Format, "%datetime %level [%logger] %log"); - set(Level::Fatal, ConfigurationType::Format, "%datetime %level [%logger] %log"); - set(Level::Verbose, ConfigurationType::Format, "%datetime %level-%vlevel [%logger] %log"); - set(Level::QA, ConfigurationType::Format, "%datetime %level [%logger] %log"); - set(Level::Trace, ConfigurationType::Format, "%datetime %level [%logger] [%func] [%loc] %log"); + friend base::type::ostream_t& operator<<(base::type::ostream_t& os, const RegistryWithPred& sr) { + for (const_iterator it = sr.list().begin(); it != sr.list().end(); ++it) { + os << ELPP_LITERAL(" ") << **it << ELPP_LITERAL("\n"); + } + return os; + } + + protected: + virtual void unregisterAll(void) ELPP_FINAL { + if (!this->empty()) { + for (auto&& curr : this->list()) { + base::utils::safeDelete(curr); + } + this->list().clear(); + } + } + + virtual void unregister(T_Ptr*& ptr) ELPP_FINAL { + if (ptr) { + iterator iter = this->begin(); + for (; iter != this->end(); ++iter) { + if (ptr == *iter) { + break; } + } + if (iter != this->end() && *iter != nullptr) { + this->list().erase(iter); + base::utils::safeDelete(*iter); + } + } + } + + virtual inline void registerNew(T_Ptr* ptr) ELPP_FINAL { + this->list().push_back(ptr); + } + +/// @brief Gets pointer from repository with speicifed arguments. Arguments are passed to predicate +/// in order to validate pointer. + template + T_Ptr* get(const T& arg1, const T2 arg2) { + iterator iter = std::find_if(this->list().begin(), this->list().end(), Pred(arg1, arg2)); + if (iter != this->list().end() && *iter != nullptr) { + return *iter; + } + return nullptr; + } - //! - //! Sets configuration for all levels. - //! Remember, it is not recommended to set skip_ELPPALL_Check to false unless you know exactly what you are doing - //! \param configurationType_ - //! \param value_ - //! \param skipLEVEL_ALL Determines whether to skip 'easyloggingpp::Level::All'. This is skipped by default because setting - //! 'All' may override configuration. Be careful with this. - //! - inline void setAll(unsigned int configurationType_, const std::string& value_, bool skipLEVEL_ALL = false) { - if (!skipLEVEL_ALL) { - set(Level::All, configurationType_, value_); - } - ELPP_FOR_EACH_LEVEL(i, Level::Debug, - set(i, configurationType_, value_); - ); - } + private: + virtual void deepCopy(const AbstractRegistry>& sr) { + for (const_iterator it = sr.list().begin(); it != sr.list().end(); ++it) { + registerNew(new T_Ptr(**it)); + } + } +}; +class Utils { + public: + template + static bool installCallback(const std::string& id, std::unordered_map* mapT) { + if (mapT->find(id) == mapT->end()) { + mapT->insert(std::make_pair(id, TPtr(new T()))); + return true; + } + return false; + } - //! - //! Clears the repository. - //! All the configurations are maintained on heap for faster access so if you are sure you will not use this - //! repository and you have configured all the loggers against this or you have used this configuration for all the - //! purposes you need it for, you may retain memory by using this method. If you do not do this, internal memory management - //! does it itself at the end of application execution. - //! - inline void clear(void) { - unregisterAll(); - } + template + static void uninstallCallback(const std::string& id, std::unordered_map* mapT) { + if (mapT->find(id) != mapT->end()) { + mapT->erase(id); + } + } - //! - //! \return Returns configuration file used in parsing this configurations. If this repository was set manually or by text - //! this returns empty string. - //! - std::string configurationFile(void) const { - return configurationFile_; - } + template + static T* callback(const std::string& id, std::unordered_map* mapT) { + typename std::unordered_map::iterator iter = mapT->find(id); + if (iter != mapT->end()) { + return static_cast(iter->second.get()); + } + return nullptr; + } +}; +} // namespace utils +} // namespace base +/// @brief Base of Easylogging++ friendly class +/// +/// @detail After inheriting this class publicly, implement pure-virtual function `void log(std::ostream&) const` +class Loggable { + public: + virtual ~Loggable(void) {} + virtual void log(el::base::type::ostream_t&) const = 0; + private: + friend inline el::base::type::ostream_t& operator<<(el::base::type::ostream_t& os, const Loggable& loggable) { + loggable.log(os); + return os; + } +}; +namespace base { +/// @brief Represents log format containing flags and date format. This is used internally to start initial log +class LogFormat : public Loggable { + public: + LogFormat(void); + LogFormat(Level level, const base::type::string_t& format); + LogFormat(const LogFormat& logFormat); + LogFormat(LogFormat&& logFormat); + LogFormat& operator=(const LogFormat& logFormat); + virtual ~LogFormat(void) {} + bool operator==(const LogFormat& other); + + /// @brief Updates format to be used while logging. + /// @param userFormat User provided format + void parseFromFormat(const base::type::string_t& userFormat); + + inline Level level(void) const { + return m_level; + } + + inline const base::type::string_t& userFormat(void) const { + return m_userFormat; + } + + inline const base::type::string_t& format(void) const { + return m_format; + } + + inline const std::string& dateTimeFormat(void) const { + return m_dateTimeFormat; + } + + inline base::type::EnumType flags(void) const { + return m_flags; + } + + inline bool hasFlag(base::FormatFlags flag) const { + return base::utils::hasFlag(flag, m_flags); + } + + virtual void log(el::base::type::ostream_t& os) const { + os << m_format; + } + + protected: + /// @brief Updates date time format if available in currFormat. + /// @param index Index where %datetime, %date or %time was found + /// @param [in,out] currFormat current format that is being used to format + virtual void updateDateFormat(std::size_t index, base::type::string_t& currFormat) ELPP_FINAL; + + /// @brief Updates %level from format. This is so that we dont have to do it at log-writing-time. It uses m_format and m_level + virtual void updateFormatSpec(void) ELPP_FINAL; + + inline void addFlag(base::FormatFlags flag) { + base::utils::addFlag(flag, &m_flags); + } + + private: + Level m_level; + base::type::string_t m_userFormat; + base::type::string_t m_format; + std::string m_dateTimeFormat; + base::type::EnumType m_flags; + std::string m_currentUser; + std::string m_currentHost; + friend class el::Logger; // To resolve loggerId format specifier easily +}; +} // namespace base +/// @brief Resolving function for format specifier +typedef std::function FormatSpecifierValueResolver; +/// @brief User-provided custom format specifier +/// @see el::Helpers::installCustomFormatSpecifier +/// @see FormatSpecifierValueResolver +class CustomFormatSpecifier { + public: + CustomFormatSpecifier(const char* formatSpecifier, const FormatSpecifierValueResolver& resolver) : + m_formatSpecifier(formatSpecifier), m_resolver(resolver) {} + inline const char* formatSpecifier(void) const { + return m_formatSpecifier; + } + inline const FormatSpecifierValueResolver& resolver(void) const { + return m_resolver; + } + inline bool operator==(const char* formatSpecifier) { + return strcmp(m_formatSpecifier, formatSpecifier) == 0; + } + + private: + const char* m_formatSpecifier; + FormatSpecifierValueResolver m_resolver; +}; +/// @brief Represents single configuration that has representing level, configuration type and a string based value. +/// +/// @detail String based value means any value either its boolean, integer or string itself, it will be embedded inside quotes +/// and will be parsed later. +/// +/// Consider some examples below: +/// * el::Configuration confEnabledInfo(el::Level::Info, el::ConfigurationType::Enabled, "true"); +/// * el::Configuration confMaxLogFileSizeInfo(el::Level::Info, el::ConfigurationType::MaxLogFileSize, "2048"); +/// * el::Configuration confFilenameInfo(el::Level::Info, el::ConfigurationType::Filename, "/var/log/my.log"); +class Configuration : public Loggable { + public: + Configuration(const Configuration& c); + Configuration& operator=(const Configuration& c); + + virtual ~Configuration(void) { + } + + /// @brief Full constructor used to sets value of configuration + Configuration(Level level, ConfigurationType configurationType, const std::string& value); + + /// @brief Gets level of current configuration + inline Level level(void) const { + return m_level; + } + + /// @brief Gets configuration type of current configuration + inline ConfigurationType configurationType(void) const { + return m_configurationType; + } + + /// @brief Gets string based configuration value + inline const std::string& value(void) const { + return m_value; + } + + /// @brief Set string based configuration value + /// @param value Value to set. Values have to be std::string; For boolean values use "true", "false", for any integral values + /// use them in quotes. They will be parsed when configuring + inline void setValue(const std::string& value) { + m_value = value; + } + + virtual void log(el::base::type::ostream_t& os) const; + + /// @brief Used to find configuration from configuration (pointers) repository. Avoid using it. + class Predicate { + public: + Predicate(Level level, ConfigurationType configurationType); + + bool operator()(const Configuration* conf) const; + + private: + Level m_level; + ConfigurationType m_configurationType; + }; + + private: + Level m_level; + ConfigurationType m_configurationType; + std::string m_value; +}; - //! - //! Parser used internally to parse configurations from file or text. You should not need this unless you are working on - //! some tool for EasyLogging++ - //! - class Parser : private internal::StaticClass { - public: - static void ignoreComments(std::string& line) { - std::size_t foundAt = 0; - std::size_t quotesStart = line.find("\""); - std::size_t quotesEnd = std::string::npos; - if (quotesStart != std::string::npos) { - quotesEnd = line.find("\"", quotesStart + 1); - } - if ((foundAt = line.find("//")) != std::string::npos) { - if (foundAt < quotesEnd) { - foundAt = line.find("//", quotesEnd + 1); - } - line = line.substr(0, foundAt); - } - } - - static inline bool isLevel(const std::string& line) { - return internal::utilities::StringUtils::startsWith(line, "*"); - } - - static inline bool isConfig(const std::string& line) { - std::size_t assignment = line.find('='); - return line != "" && - (line[0] >= 65 || line[0] <= 90 || line[0] >= 97 || line[0] <= 122) && - (assignment != std::string::npos) && - (line.size() > assignment); - } - - static inline bool isComment(const std::string& line) { - return internal::utilities::StringUtils::startsWith(line, "//"); - } - - static bool parseLine(std::string& line, unsigned int& currLevel, Configurations* conf) { - std::string currLevelStr = std::string(); - unsigned int currConfig = 0; - std::string currConfigStr = std::string(); - std::string currValue = std::string(); - line = internal::utilities::StringUtils::trim(line); - if (isComment(line)) return true; - ignoreComments(line); - if (line == "") { - // Comment ignored - return true; - } - if (isLevel(line)) { - currLevelStr = internal::utilities::StringUtils::stripAllWhiteSpaces(line); - if (currLevelStr.size() <= 2) { - return true; - } - currLevelStr = currLevelStr.substr(1, currLevelStr.size() - 2); - internal::utilities::StringUtils::tolower(currLevelStr); - currLevel = Level::convertFromString(currLevelStr); - return true; - } - if (isConfig(line)) { - std::size_t assignment = line.find('='); - currConfigStr = line.substr(0, assignment); - currConfigStr = internal::utilities::StringUtils::stripAllWhiteSpaces(currConfigStr); - internal::utilities::StringUtils::tolower(currConfigStr); - currConfig = ConfigurationType::convertFromString(currConfigStr); - currValue = line.substr(assignment + 1); - currValue = internal::utilities::StringUtils::trim(currValue); - std::size_t quotesStart = currValue.find("\"", 0); - std::size_t quotesEnd = std::string::npos; - if (quotesStart != std::string::npos) { - quotesEnd = currValue.find("\"", quotesStart + 1); - } - if (quotesStart != std::string::npos && quotesEnd != std::string::npos) { - // Quote provided - check and strip if valid - __EASYLOGGINGPP_ASSERT((quotesStart < quotesEnd), "Configuration error - No ending quote found in [" << currConfigStr << "]"); - __EASYLOGGINGPP_ASSERT((quotesStart + 1 != quotesEnd), "Empty configuration value for [" << currConfigStr << "]"); - if ((quotesStart != quotesEnd) && (quotesStart + 1 != quotesEnd)) { - // Explicit check in case if assertion is disabled - currValue = currValue.substr(quotesStart + 1, quotesEnd - 1); - } - } - } - __EASYLOGGINGPP_ASSERT(currLevel != Level::Unknown, "Unrecognized severity level [" << currLevelStr << "]"); - __EASYLOGGINGPP_ASSERT(currConfig != ConfigurationType::Unknown, "Unrecognized configuration [" << currConfigStr << "]"); - if (currLevel == Level::Unknown || currConfig == ConfigurationType::Unknown) { - return false; // unrecognizable level or config - } - conf->set(currLevel, currConfig, currValue); - return true; - } - }; // class Parser - private: - std::string configurationFile_; - bool isFromFile_; - internal::threading::Mutex mutex_; - - inline void set(internal::Configuration* conf_) { - if (conf_ == NULL) return; - set(conf_->level(), conf_->type(), conf_->value()); - } - }; // class Configurations - - class Loggers; // fwd declaration - - namespace internal { - - class RegisteredLoggers; // fwd declaration - class Writer; // fwd declaration - -//! -//! Configuration map used internally for faster access of configuration while executing. -//! - template - class ConfigurationMap { - public: - typedef typename std::pair Entry; - - ConfigurationMap(void) { - table = new Entry*[Level::kMaxValid + 1]; - for (unsigned int i = 0; i < (Level::kMaxValid + 1); ++i) { - table[i] = NULL; - } - count = 0; - } - - const T& get(unsigned int level_, bool forceGetLevel = false) { - if (forceGetLevel || table[level_] != NULL) { - if (table[level_] == NULL) { - return default_; - } - return table[level_]->second; - } else if (table[Level::All] != NULL) { - return table[Level::All]->second; - } - return default_; - } - - void set(unsigned int level_, const T& value) { - // Unset any existing value for this level - unset(level_); - table[level_] = new Entry(level_, value); - ++count; - } - - void unset(unsigned int level_) { - if (table[level_] != NULL) { - internal::utilities::safeDelete(table[level_]); - if (count > 0) - --count; - } - } - - inline bool exist(unsigned int level_) const { - return table[level_] != NULL; - } - - inline bool exist(unsigned int level_, const T& value) { - return get(level_, true) == value; - } - - void clear(void) { - for (unsigned int i = 0; i < (Level::kMaxValid + 1); ++i) { - internal::utilities::safeDelete(table[i]); - } - delete[] table; - count = 0; - } - - virtual ~ConfigurationMap(void) { - clear(); - } - - inline void setDefault(const T& default_) { - this->default_ = default_; - } - - inline std::size_t size(void) const { - return count; - } - private: - Entry** table; - std::size_t count; - T default_; - }; - -//! -//! Configurations used internally that defines data type of each configuration from easyloggingpp::ConfigurationType -//! - class TypedConfigurations { - public: - TypedConfigurations(const Configurations& configurations, internal::Constants* constants_) { - this->constants_ = constants_; - this->configurations_ = configurations; - enabledMap_.setDefault(false); - toFileMap_.setDefault(false); - toStandardOutputMap_.setDefault(false); - filenameMap_.setDefault(""); - logFormatMap_.setDefault(""); - dateFormatMap_.setDefault(""); - dateFormatSpecifierMap_.setDefault(""); - millisecondsWidthMap_.setDefault(3); - performanceTrackingMap_.setDefault(false); - fileStreamMap_.setDefault(NULL); - formatFlagMap_.setDefault(0x0); - rollOutSizeMap_.setDefault(0); - parse(configurations); - } - - virtual ~TypedConfigurations(void) { - deleteFileStreams(); - } - - const Configurations& configurations(void) const { - return configurations_; - } - private: - internal::ConfigurationMap enabledMap_; - internal::ConfigurationMap toFileMap_; - internal::ConfigurationMap filenameMap_; - internal::ConfigurationMap toStandardOutputMap_; - internal::ConfigurationMap logFormatMap_; - internal::ConfigurationMap dateFormatMap_; - internal::ConfigurationMap dateFormatSpecifierMap_; - internal::ConfigurationMap millisecondsWidthMap_; - internal::ConfigurationMap performanceTrackingMap_; - internal::ConfigurationMap fileStreamMap_; - internal::ConfigurationMap formatFlagMap_; - internal::ConfigurationMap rollOutSizeMap_; - internal::Constants* constants_; - Configurations configurations_; - - friend class Writer; - friend class easyloggingpp::Loggers; - - inline bool enabled(unsigned int level_) { - return enabledMap_.get(level_); - } - - inline bool toFile(unsigned int level_) { - return toFileMap_.get(level_); - } - - inline const std::string& filename(unsigned int level_) { - return filenameMap_.get(level_); - } - - inline bool toStandardOutput(unsigned int level_) { - return toStandardOutputMap_.get(level_); - } - - inline const std::string& logFormat(unsigned int level_) { - return logFormatMap_.get(level_); - } - - inline const std::string& dateFormat(unsigned int level_) { - return dateFormatMap_.get(level_); - } - - inline const std::string& dateFormatSpecifier(unsigned int level_) { - return dateFormatSpecifierMap_.get(level_); - } - - inline int millisecondsWidth(unsigned int level_ = Level::All) { - return millisecondsWidthMap_.get(level_); - } - - inline bool performanceTracking(unsigned int level_ = Level::All) { - return performanceTrackingMap_.get(level_); - } - - inline std::fstream* fileStream(unsigned int level_) { - return fileStreamMap_.get(level_); - } - - inline std::size_t rollOutSize(unsigned int level_) { - return rollOutSizeMap_.get(level_); - } - - inline int formatFlag(unsigned int level_) { - return formatFlagMap_.get(level_); - } - - void parse(const Configurations& configurations_) { - for (std::size_t i = 0; i < configurations_.count(); ++i) { - Configuration* conf = configurations_.at(i); - switch (conf->type()) { - case ConfigurationType::Enabled: - setValue(conf->level(), getBool(conf->value()), enabledMap_); - break; - case ConfigurationType::ToFile: - setValue(conf->level(), getBool(conf->value()), toFileMap_); - break; - case ConfigurationType::Filename: - insertFilename(conf->level(), conf->value()); - break; - case ConfigurationType::ToStandardOutput: - setValue(conf->level(), getBool(conf->value()), toStandardOutputMap_); - break; - case ConfigurationType::Format: - determineFormats(conf->level(), conf->value()); - break; - case ConfigurationType::MillisecondsWidth: - if (conf->level() == Level::All) { - int origVal = getInt(conf->value()); - int msl_; -#if _ELPP_OS_UNIX - switch (origVal) { - case 3: - msl_ = 1000; - break; - case 4: - msl_ = 100; - break; - case 5: - msl_ = 10; - break; - case 6: - msl_ = 1; - break; - default: - msl_ = constants_->DEFAULT_MILLISECOND_OFFSET; - } -#elif _ELPP_OS_WINDOWS - msl_ = 1000; - __EASYLOGGINGPP_SUPPRESS_UNSED(origVal); -#endif // _ELPP_OS_UNIX - setValue(conf->level(), msl_, millisecondsWidthMap_); - } - break; - case ConfigurationType::PerformanceTracking: - if (conf->level() == Level::All) { - setValue(conf->level(), getBool(conf->value()), performanceTrackingMap_); - } - break; - case ConfigurationType::RollOutSize: - setValue(conf->level(), static_cast(getULong(conf->value())), rollOutSizeMap_); - unsigned int validLevel_ = 0; - std::string rolloutFilename_ = std::string(); - checkRollOuts(conf->level(), validLevel_, rolloutFilename_); - break; - } - } - } - - void determineFormats(unsigned int level_, const std::string& originalFormat) { - unsigned int formatSpec = 0x0; - if (originalFormat.find(constants_->APP_NAME_FORMAT_SPECIFIER) != std::string::npos) { - formatSpec |= constants_->kAppName; - } - if (originalFormat.find(constants_->LOGGER_ID_FORMAT_SPECIFIER) != std::string::npos) { - formatSpec |= constants_->kLoggerId; - } - if (originalFormat.find(constants_->THREAD_ID_FORMAT_SPECIFIER) != std::string::npos) { - formatSpec |= constants_->kThreadId; - } - if (originalFormat.find(constants_->LOCATION_FORMAT_SPECIFIER) != std::string::npos) { - formatSpec |= constants_->kLocation; - } - if (originalFormat.find(constants_->FUNCTION_FORMAT_SPECIFIER) != std::string::npos) { - formatSpec |= constants_->kFunction; - } - if (originalFormat.find(constants_->USER_FORMAT_SPECIFIER) != std::string::npos) { - formatSpec |= constants_->kUser; - } - if (originalFormat.find(constants_->HOST_FORMAT_SPECIFIER) != std::string::npos) { - formatSpec |= constants_->kHost; - } - if (originalFormat.find(constants_->LOG_MESSAGE_FORMAT_SPECIFIER) != std::string::npos) { - formatSpec |= constants_->kLogMessage; - } - if (originalFormat.find(constants_->VERBOSE_LEVEL_FORMAT_SPECIFIER) != std::string::npos) { - formatSpec |= constants_->kVerboseLevel; - } - if (originalFormat.find(constants_->DATE_TIME_FORMAT_SPECIFIER) != std::string::npos) { - formatSpec |= constants_->kDateTime; - setValue(level_, constants_->DATE_TIME_FORMAT_SPECIFIER, dateFormatSpecifierMap_); - } else if (originalFormat.find(constants_->DATE_ONLY_FORMAT_SPECIFIER) != std::string::npos) { - formatSpec |= constants_->kDateOnly; - setValue(level_, constants_->DATE_ONLY_FORMAT_SPECIFIER, dateFormatSpecifierMap_); - } else if (originalFormat.find(constants_->TIME_ONLY_FORMAT_SPECIFIER) != std::string::npos) { - formatSpec |= constants_->kTimeOnly; - setValue(level_, constants_->TIME_ONLY_FORMAT_SPECIFIER, dateFormatSpecifierMap_); - } -#if _ELPP_OS_UNIX - const std::string kTimeFormatLocal_ = "%H:%M:%S"; - const std::string kDateFormatLocal_ = "%d/%m/%Y"; - std::string dateFormat; - - if (formatSpec & constants_->kDateOnly) { - dateFormat = kDateFormatLocal_; - } else if (formatSpec & constants_->kTimeOnly) { - dateFormat = kTimeFormatLocal_; - } else { - std::stringstream ss; - ss << kDateFormatLocal_ << " " << kTimeFormatLocal_; - dateFormat = ss.str(); - } - setValue(level_, dateFormat, dateFormatMap_); -#endif // _ELPP_OS_UNIX - setValue(level_, formatSpec, formatFlagMap_); - // Update %level - std::string origFormatCopy = originalFormat; - switch (level_) { - case Level::Debug: - internal::utilities::LogManipulator::updateFormatValue(constants_->LEVEL_FORMAT_SPECIFIER, - constants_->LOG_DEBUG_LEVEL_VALUE, origFormatCopy, constants_); - break; - case Level::Info: - internal::utilities::LogManipulator::updateFormatValue(constants_->LEVEL_FORMAT_SPECIFIER, - constants_->LOG_INFO_LEVEL_VALUE, origFormatCopy, constants_); - break; - case Level::Warning: - internal::utilities::LogManipulator::updateFormatValue(constants_->LEVEL_FORMAT_SPECIFIER, - constants_->LOG_WARNING_LEVEL_VALUE, origFormatCopy, constants_); - break; - case Level::Error: - internal::utilities::LogManipulator::updateFormatValue(constants_->LEVEL_FORMAT_SPECIFIER, - constants_->LOG_ERROR_LEVEL_VALUE, origFormatCopy, constants_); - break; - case Level::Fatal: - internal::utilities::LogManipulator::updateFormatValue(constants_->LEVEL_FORMAT_SPECIFIER, - constants_->LOG_FATAL_LEVEL_VALUE, origFormatCopy, constants_); - break; - case Level::Verbose: - internal::utilities::LogManipulator::updateFormatValue(constants_->LEVEL_FORMAT_SPECIFIER, - constants_->LOG_VERBOSE_LEVEL_VALUE, origFormatCopy, constants_); - break; - case Level::QA: - internal::utilities::LogManipulator::updateFormatValue(constants_->LEVEL_FORMAT_SPECIFIER, - constants_->LOG_QA_LEVEL_VALUE, origFormatCopy, constants_); - break; - case Level::Trace: - internal::utilities::LogManipulator::updateFormatValue(constants_->LEVEL_FORMAT_SPECIFIER, - constants_->LOG_TRACE_LEVEL_VALUE, origFormatCopy, constants_); - break; - } - setValue(level_, origFormatCopy + "\n", logFormatMap_); - } - - void deleteFileStreams(void) { - ELPP_FOR_EACH_LEVEL(i, Level::kMinValid, - removeFile(i); - ); - } - - // This is different since we need unique values - void insertFilename(unsigned int level_, const std::string& fname_, bool forceNew = false) { - std::string fnameFull = fname_; - if (internal::utilities::StringUtils::endsWith(fnameFull, constants_->PATH_SLASH)) { - fnameFull.append(constants_->DEFAULT_LOG_FILENAME); - } - std::string path_ = internal::utilities::OSUtils::getPathFromFilename(fnameFull, constants_); - if (path_.size() < fnameFull.size()) { - // Contains path - create it if it does not already exist - internal::utilities::OSUtils::createPath(path_); - } - if (filenameMap_.size() == 0) { - filenameMap_.set(Level::All, fnameFull); - std::fstream *fsAll = newFileStream(fnameFull, forceNew); - if (fsAll != NULL) { - fileStreamMap_.set(Level::All, fsAll); - } - return; - } - ELPP_FOR_EACH_LEVEL(i, Level::kMinValid, - if (filenameMap_.exist(i, fnameFull)) { - return; - } - ); - filenameMap_.set(level_, fnameFull); - // Just before we proceed and create new file stream we check for existing one on same level, - // if we have existing one, we first delete it to prevent memory leak. - std::fstream *fs = fileStreamMap_.get(level_, true); - internal::utilities::safeDelete(fs); - fileStreamMap_.unset(level_); - fs = newFileStream(fnameFull, forceNew); - if (fs != NULL) { - fileStreamMap_.set(level_, fs); - } - } - - template - void setValue(unsigned int level_, const T& value_, internal::ConfigurationMap& map_, bool skipLEVEL_ALL = false) { - if (map_.size() == 0 && !skipLEVEL_ALL) { - map_.set(Level::All, value_); - return; - } - if (map_.exist(static_cast(Level::All), value_)) { - return; - } - map_.set(level_, value_); - } - - std::fstream* newFileStream(const std::string& filename, bool forceNew = false) { - std::fstream *fs = NULL; - if (forceNew) { - fs = new std::fstream(filename.c_str(), std::fstream::out); - } else { - fs = new std::fstream(filename.c_str(), std::fstream::out | std::fstream::app); - } - if (fs->is_open()) { - fs->flush(); - } else { - internal::utilities::safeDelete(fs, false); - std::cerr << "Bad file [" << filename << "]" << std::endl; - return NULL; - } - return fs; - } - - void removeFile(unsigned int level_) { - std::fstream* fs = fileStream(level_); - if (!fs) { - return; - } - if (fs->is_open()) { - fs->close(); - } - internal::utilities::safeDelete(fs, false); - fileStreamMap_.unset(level_); - filenameMap_.unset(level_); - } - - unsigned long getULong(const std::string& confValue_) { - bool valid = true; - std::string trimmedVal = internal::utilities::StringUtils::trim(confValue_); - if (trimmedVal.size() == 0) { - valid = false; - __EASYLOGGINGPP_SUPPRESS_UNSED(valid); - __EASYLOGGINGPP_ASSERT(valid, "Configuration value not a valid integer " << trimmedVal); - } - for (std::size_t i = 0; i < trimmedVal.size(); ++i) { - if (trimmedVal[i] < 48 || trimmedVal[i] > 57) { - valid = false; - break; - } - } - __EASYLOGGINGPP_SUPPRESS_UNSED(valid); - __EASYLOGGINGPP_ASSERT(valid, "Configuration value not a valid integer " << trimmedVal); - return atol(confValue_.c_str()); - } - - inline int getInt(const std::string& confValue_) { - return static_cast(getULong(confValue_)); - } - - inline bool getBool(const std::string& confValue_) { - std::string trimmedVal = internal::utilities::StringUtils::trim(confValue_); - return (trimmedVal == "1" || trimmedVal == "true" || trimmedVal == "TRUE"); - } - - std::size_t getSizeOfFile(std::fstream *fs) { - if (!fs) { - return 0; - } - std::streampos currPos = fs->tellg(); - fs->seekg (0, fs->end); - std::size_t size = static_cast(fs->tellg()); - fs->seekg (currPos); - return size; - } - - bool checkRollOuts(unsigned int level_, unsigned int& validLevel_, std::string& fname_) { - std::fstream* fs = fileStream(level_); - std::size_t rollOutSize_ = rollOutSize(level_); - if (rollOutSize_ != 0 && getSizeOfFile(fs) >= rollOutSize_) { - fname_ = filename(level_); -#if defined(_ELPP_INTERNAL_INFO) - std::cout << "Cleaning log file [" << fname_ << "]\n"; -#endif // defined(_ELPP_INTERNAL_INFO) - // Find and reset correct level. By correct level we mean the current - // available level in fileStream because this level_ could actually be using - // configurations from Level::All and you do not want to create a brand new - // stream just because we are rolling log away - validLevel_ = findValidLevel(fileStreamMap_, level_); - forceReinitiateFile(validLevel_, fname_); - return true; - } - return false; - } - - template - inline unsigned int findValidLevel(internal::ConfigurationMap& map_, unsigned int refLevel_) { - return map_.exist(refLevel_) ? refLevel_ : static_cast(Level::All); - } - - inline void forceReinitiateFile(unsigned int level_, const std::string& filename_) { - removeFile(level_); - insertFilename(level_, filename_, true); - } - }; - } // namespace internal - -//! -//! Represents single logger used to write log. -//! - class Logger { - public: - //! - //! Minimal constructor to set logger ID and constants. You should not use this constructor manually, instead use - //! easyloggingpp::Loggers::getLogger - //! \param uniqueIdentifier_ Logger ID that you will require to get logger from logger repository - //! \param constants_ Use easyloggingpp::internal::registeredLoggers->constants() - //! - Logger(const std::string& uniqueIdentifier_, internal::Constants* constants_) : - id_(uniqueIdentifier_), - constants_(constants_), - typedConfigurations_(NULL), - stream_(new std::stringstream()) { - Configurations defaultConfs; - defaultConfs.setToDefault(); - configure(defaultConfs); - userConfigurations_ = defaultConfs; - defaultConfs.clear(); - } +/// @brief Thread-safe Configuration repository +/// +/// @detail This repository represents configurations for all the levels and configuration type mapped to a value. +class Configurations : public base::utils::RegistryWithPred { + public: + /// @brief Default constructor with empty repository + Configurations(void); + + /// @brief Constructor used to set configurations using configuration file. + /// @param configurationFile Full path to configuration file + /// @param useDefaultsForRemaining Lets you set the remaining configurations to default. + /// @param base If provided, this configuration will be based off existing repository that this argument is pointing to. + /// @see parseFromFile(const std::string&, Configurations* base) + /// @see setRemainingToDefault() + Configurations(const std::string& configurationFile, bool useDefaultsForRemaining = true, + Configurations* base = nullptr); + + virtual ~Configurations(void) { + } + + /// @brief Parses configuration from file. + /// @param configurationFile Full path to configuration file + /// @param base Configurations to base new configuration repository off. This value is used when you want to use + /// existing Configurations to base all the values and then set rest of configuration via configuration file. + /// @return True if successfully parsed, false otherwise. You may define 'ELPP_DEBUG_ASSERT_FAILURE' to make sure you + /// do not proceed without successful parse. + bool parseFromFile(const std::string& configurationFile, Configurations* base = nullptr); + + /// @brief Parse configurations from configuration string. + /// + /// @detail This configuration string has same syntax as configuration file contents. Make sure all the necessary + /// new line characters are provided. + /// @param base Configurations to base new configuration repository off. This value is used when you want to use + /// existing Configurations to base all the values and then set rest of configuration via configuration text. + /// @return True if successfully parsed, false otherwise. You may define 'ELPP_DEBUG_ASSERT_FAILURE' to make sure you + /// do not proceed without successful parse. + bool parseFromText(const std::string& configurationsString, Configurations* base = nullptr); + + /// @brief Sets configuration based-off an existing configurations. + /// @param base Pointer to existing configurations. + void setFromBase(Configurations* base); + + /// @brief Determines whether or not specified configuration type exists in the repository. + /// + /// @detail Returns as soon as first level is found. + /// @param configurationType Type of configuration to check existence for. + bool hasConfiguration(ConfigurationType configurationType); + + /// @brief Determines whether or not specified configuration type exists for specified level + /// @param level Level to check + /// @param configurationType Type of configuration to check existence for. + bool hasConfiguration(Level level, ConfigurationType configurationType); + + /// @brief Sets value of configuration for specified level. + /// + /// @detail Any existing configuration for specified level will be replaced. Also note that configuration types + /// ConfigurationType::SubsecondPrecision and ConfigurationType::PerformanceTracking will be ignored if not set for + /// Level::Global because these configurations are not dependant on level. + /// @param level Level to set configuration for (el::Level). + /// @param configurationType Type of configuration (el::ConfigurationType) + /// @param value A string based value. Regardless of what the data type of configuration is, it will always be string + /// from users' point of view. This is then parsed later to be used internally. + /// @see Configuration::setValue(const std::string& value) + /// @see el::Level + /// @see el::ConfigurationType + void set(Level level, ConfigurationType configurationType, const std::string& value); + + /// @brief Sets single configuration based on other single configuration. + /// @see set(Level level, ConfigurationType configurationType, const std::string& value) + void set(Configuration* conf); + + inline Configuration* get(Level level, ConfigurationType configurationType) { + base::threading::ScopedLock scopedLock(lock()); + return RegistryWithPred::get(level, configurationType); + } + + /// @brief Sets configuration for all levels. + /// @param configurationType Type of configuration + /// @param value String based value + /// @see Configurations::set(Level level, ConfigurationType configurationType, const std::string& value) + inline void setGlobally(ConfigurationType configurationType, const std::string& value) { + setGlobally(configurationType, value, false); + } + + /// @brief Clears repository so that all the configurations are unset + inline void clear(void) { + base::threading::ScopedLock scopedLock(lock()); + unregisterAll(); + } + + /// @brief Gets configuration file used in parsing this configurations. + /// + /// @detail If this repository was set manually or by text this returns empty string. + inline const std::string& configurationFile(void) const { + return m_configurationFile; + } + + /// @brief Sets configurations to "factory based" configurations. + void setToDefault(void); + + /// @brief Lets you set the remaining configurations to default. + /// + /// @detail By remaining, it means that the level/type a configuration does not exist for. + /// This function is useful when you want to minimize chances of failures, e.g, if you have a configuration file that sets + /// configuration for all the configurations except for Enabled or not, we use this so that ENABLED is set to default i.e, + /// true. If you dont do this explicitly (either by calling this function or by using second param in Constructor + /// and try to access a value, an error is thrown + void setRemainingToDefault(void); + + /// @brief Parser used internally to parse configurations from file or text. + /// + /// @detail This class makes use of base::utils::Str. + /// You should not need this unless you are working on some tool for Easylogging++ + class Parser : base::StaticClass { + public: + /// @brief Parses configuration from file. + /// @param configurationFile Full path to configuration file + /// @param sender Sender configurations pointer. Usually 'this' is used from calling class + /// @param base Configurations to base new configuration repository off. This value is used when you want to use + /// existing Configurations to base all the values and then set rest of configuration via configuration file. + /// @return True if successfully parsed, false otherwise. You may define '_STOP_ON_FIRSTELPP_ASSERTION' to make sure you + /// do not proceed without successful parse. + static bool parseFromFile(const std::string& configurationFile, Configurations* sender, + Configurations* base = nullptr); + + /// @brief Parse configurations from configuration string. + /// + /// @detail This configuration string has same syntax as configuration file contents. Make sure all the necessary + /// new line characters are provided. You may define '_STOP_ON_FIRSTELPP_ASSERTION' to make sure you + /// do not proceed without successful parse (This is recommended) + /// @param configurationsString the configuration in plain text format + /// @param sender Sender configurations pointer. Usually 'this' is used from calling class + /// @param base Configurations to base new configuration repository off. This value is used when you want to use + /// existing Configurations to base all the values and then set rest of configuration via configuration text. + /// @return True if successfully parsed, false otherwise. + static bool parseFromText(const std::string& configurationsString, Configurations* sender, + Configurations* base = nullptr); + + private: + friend class el::Loggers; + static void ignoreComments(std::string* line); + static bool isLevel(const std::string& line); + static bool isComment(const std::string& line); + static inline bool isConfig(const std::string& line); + static bool parseLine(std::string* line, std::string* currConfigStr, std::string* currLevelStr, Level* currLevel, + Configurations* conf); + }; + + private: + std::string m_configurationFile; + bool m_isFromFile; + friend class el::Loggers; + + /// @brief Unsafely sets configuration if does not already exist + void unsafeSetIfNotExist(Level level, ConfigurationType configurationType, const std::string& value); + + /// @brief Thread unsafe set + void unsafeSet(Level level, ConfigurationType configurationType, const std::string& value); + + /// @brief Sets configurations for all levels including Level::Global if includeGlobalLevel is true + /// @see Configurations::setGlobally(ConfigurationType configurationType, const std::string& value) + void setGlobally(ConfigurationType configurationType, const std::string& value, bool includeGlobalLevel); + + /// @brief Sets configurations (Unsafely) for all levels including Level::Global if includeGlobalLevel is true + /// @see Configurations::setGlobally(ConfigurationType configurationType, const std::string& value) + void unsafeSetGlobally(ConfigurationType configurationType, const std::string& value, bool includeGlobalLevel); +}; - //! - //! Full constructor to set logger ID, constants and configuration. - //! \param uniqueIdentifier_ Logger ID that you will require to get logger from logger repository - //! \param constants_ Use easyloggingpp::internal::registeredLoggers->constants() - //! \param configurations Configurations to set logger against - //! - Logger(const std::string& uniqueIdentifier_, internal::Constants* constants_, const Configurations& configurations) : - id_(uniqueIdentifier_), - constants_(constants_), - typedConfigurations_(NULL), - stream_(new std::stringstream()) { - configure(configurations); - } +namespace base { +typedef std::shared_ptr FileStreamPtr; +typedef std::unordered_map LogStreamsReferenceMap; +/// @brief Configurations with data types. +/// +/// @detail el::Configurations have string based values. This is whats used internally in order to read correct configurations. +/// This is to perform faster while writing logs using correct configurations. +/// +/// This is thread safe and final class containing non-virtual destructor (means nothing should inherit this class) +class TypedConfigurations : public base::threading::ThreadSafe { + public: + /// @brief Constructor to initialize (construct) the object off el::Configurations + /// @param configurations Configurations pointer/reference to base this typed configurations off. + /// @param logStreamsReference Use ELPP->registeredLoggers()->logStreamsReference() + TypedConfigurations(Configurations* configurations, base::LogStreamsReferenceMap* logStreamsReference); + + TypedConfigurations(const TypedConfigurations& other); + + virtual ~TypedConfigurations(void) { + } + + const Configurations* configurations(void) const { + return m_configurations; + } + + bool enabled(Level level); + bool toFile(Level level); + const std::string& filename(Level level); + bool toStandardOutput(Level level); + const base::LogFormat& logFormat(Level level); + const base::SubsecondPrecision& subsecondPrecision(Level level = Level::Global); + const base::MillisecondsWidth& millisecondsWidth(Level level = Level::Global); + bool performanceTracking(Level level = Level::Global); + base::type::fstream_t* fileStream(Level level); + std::size_t maxLogFileSize(Level level); + std::size_t logFlushThreshold(Level level); + + private: + Configurations* m_configurations; + std::unordered_map m_enabledMap; + std::unordered_map m_toFileMap; + std::unordered_map m_filenameMap; + std::unordered_map m_toStandardOutputMap; + std::unordered_map m_logFormatMap; + std::unordered_map m_subsecondPrecisionMap; + std::unordered_map m_performanceTrackingMap; + std::unordered_map m_fileStreamMap; + std::unordered_map m_maxLogFileSizeMap; + std::unordered_map m_logFlushThresholdMap; + base::LogStreamsReferenceMap* m_logStreamsReference; + + friend class el::Helpers; + friend class el::base::MessageBuilder; + friend class el::base::Writer; + friend class el::base::DefaultLogDispatchCallback; + friend class el::base::LogDispatcher; + + template + inline Conf_T getConfigByVal(Level level, const std::unordered_map* confMap, const char* confName) { + base::threading::ScopedLock scopedLock(lock()); + return unsafeGetConfigByVal(level, confMap, confName); // This is not unsafe anymore - mutex locked in scope + } + + template + inline Conf_T& getConfigByRef(Level level, std::unordered_map* confMap, const char* confName) { + base::threading::ScopedLock scopedLock(lock()); + return unsafeGetConfigByRef(level, confMap, confName); // This is not unsafe anymore - mutex locked in scope + } + + template + Conf_T unsafeGetConfigByVal(Level level, const std::unordered_map* confMap, const char* confName) { + ELPP_UNUSED(confName); + typename std::unordered_map::const_iterator it = confMap->find(level); + if (it == confMap->end()) { + try { + return confMap->at(Level::Global); + } catch (...) { + ELPP_INTERNAL_ERROR("Unable to get configuration [" << confName << "] for level [" + << LevelHelper::convertToString(level) << "]" + << std::endl << "Please ensure you have properly configured logger.", false); + return Conf_T(); + } + } + return it->second; + } + + template + Conf_T& unsafeGetConfigByRef(Level level, std::unordered_map* confMap, const char* confName) { + ELPP_UNUSED(confName); + typename std::unordered_map::iterator it = confMap->find(level); + if (it == confMap->end()) { + try { + return confMap->at(Level::Global); + } catch (...) { + ELPP_INTERNAL_ERROR("Unable to get configuration [" << confName << "] for level [" + << LevelHelper::convertToString(level) << "]" + << std::endl << "Please ensure you have properly configured logger.", false); + } + } + return it->second; + } + + template + void setValue(Level level, const Conf_T& value, std::unordered_map* confMap, + bool includeGlobalLevel = true) { + // If map is empty and we are allowed to add into generic level (Level::Global), do it! + if (confMap->empty() && includeGlobalLevel) { + confMap->insert(std::make_pair(Level::Global, value)); + return; + } + // If same value exist in generic level already, dont add it to explicit level + typename std::unordered_map::iterator it = confMap->find(Level::Global); + if (it != confMap->end() && it->second == value) { + return; + } + // Now make sure we dont double up values if we really need to add it to explicit level + it = confMap->find(level); + if (it == confMap->end()) { + // Value not found for level, add new + confMap->insert(std::make_pair(level, value)); + } else { + // Value found, just update value + confMap->at(level) = value; + } + } + + void build(Configurations* configurations); + unsigned long getULong(std::string confVal); + std::string resolveFilename(const std::string& filename); + void insertFile(Level level, const std::string& fullFilename); + bool unsafeValidateFileRolling(Level level, const PreRollOutCallback& preRollOutCallback); + + inline bool validateFileRolling(Level level, const PreRollOutCallback& preRollOutCallback) { + base::threading::ScopedLock scopedLock(lock()); + return unsafeValidateFileRolling(level, preRollOutCallback); + } +}; +/// @brief Class that keeps record of current line hit for occasional logging +class HitCounter { + public: + HitCounter(void) : + m_filename(""), + m_lineNumber(0), + m_hitCounts(0) { + } + + HitCounter(const char* filename, base::type::LineNumber lineNumber) : + m_filename(filename), + m_lineNumber(lineNumber), + m_hitCounts(0) { + } + + HitCounter(const HitCounter& hitCounter) : + m_filename(hitCounter.m_filename), + m_lineNumber(hitCounter.m_lineNumber), + m_hitCounts(hitCounter.m_hitCounts) { + } + + HitCounter& operator=(const HitCounter& hitCounter) { + if (&hitCounter != this) { + m_filename = hitCounter.m_filename; + m_lineNumber = hitCounter.m_lineNumber; + m_hitCounts = hitCounter.m_hitCounts; + } + return *this; + } + + virtual ~HitCounter(void) { + } + + /// @brief Resets location of current hit counter + inline void resetLocation(const char* filename, base::type::LineNumber lineNumber) { + m_filename = filename; + m_lineNumber = lineNumber; + } + + /// @brief Validates hit counts and resets it if necessary + inline void validateHitCounts(std::size_t n) { + if (m_hitCounts >= base::consts::kMaxLogPerCounter) { + m_hitCounts = (n >= 1 ? base::consts::kMaxLogPerCounter % n : 0); + } + ++m_hitCounts; + } + + inline const char* filename(void) const { + return m_filename; + } + + inline base::type::LineNumber lineNumber(void) const { + return m_lineNumber; + } + + inline std::size_t hitCounts(void) const { + return m_hitCounts; + } + + inline void increment(void) { + ++m_hitCounts; + } + + class Predicate { + public: + Predicate(const char* filename, base::type::LineNumber lineNumber) + : m_filename(filename), + m_lineNumber(lineNumber) { + } + inline bool operator()(const HitCounter* counter) { + return ((counter != nullptr) && + (strcmp(counter->m_filename, m_filename) == 0) && + (counter->m_lineNumber == m_lineNumber)); + } - virtual ~Logger(void) { - internal::utilities::safeDelete(typedConfigurations_); - internal::utilities::safeDelete(stream_); - } + private: + const char* m_filename; + base::type::LineNumber m_lineNumber; + }; - //! - //! \return Logger ID - //! - inline std::string id(void) const { - return id_; - } + private: + const char* m_filename; + base::type::LineNumber m_lineNumber; + std::size_t m_hitCounts; +}; +/// @brief Repository for hit counters used across the application +class RegisteredHitCounters : public base::utils::RegistryWithPred { + public: + /// @brief Validates counter for every N, i.e, registers new if does not exist otherwise updates original one + /// @return True if validation resulted in triggering hit. Meaning logs should be written everytime true is returned + bool validateEveryN(const char* filename, base::type::LineNumber lineNumber, std::size_t n); + + /// @brief Validates counter for hits >= N, i.e, registers new if does not exist otherwise updates original one + /// @return True if validation resulted in triggering hit. Meaning logs should be written everytime true is returned + bool validateAfterN(const char* filename, base::type::LineNumber lineNumber, std::size_t n); + + /// @brief Validates counter for hits are <= n, i.e, registers new if does not exist otherwise updates original one + /// @return True if validation resulted in triggering hit. Meaning logs should be written everytime true is returned + bool validateNTimes(const char* filename, base::type::LineNumber lineNumber, std::size_t n); + + /// @brief Gets hit counter registered at specified position + inline const base::HitCounter* getCounter(const char* filename, base::type::LineNumber lineNumber) { + base::threading::ScopedLock scopedLock(lock()); + return get(filename, lineNumber); + } +}; +/// @brief Action to be taken for dispatching +enum class DispatchAction : base::type::EnumType { + None = 1, NormalLog = 2, SysLog = 4 +}; +} // namespace base +template +class Callback : protected base::threading::ThreadSafe { + public: + Callback(void) : m_enabled(true) {} + inline bool enabled(void) const { + return m_enabled; + } + inline void setEnabled(bool enabled) { + base::threading::ScopedLock scopedLock(lock()); + m_enabled = enabled; + } + protected: + virtual void handle(const T* handlePtr) = 0; + private: + bool m_enabled; +}; +class LogDispatchData { + public: + LogDispatchData() : m_logMessage(nullptr), m_dispatchAction(base::DispatchAction::None) {} + inline const LogMessage* logMessage(void) const { + return m_logMessage; + } + inline base::DispatchAction dispatchAction(void) const { + return m_dispatchAction; + } + inline void setLogMessage(LogMessage* logMessage) { + m_logMessage = logMessage; + } + inline void setDispatchAction(base::DispatchAction dispatchAction) { + m_dispatchAction = dispatchAction; + } + private: + LogMessage* m_logMessage; + base::DispatchAction m_dispatchAction; + friend class base::LogDispatcher; - //! - //! Configures logger against specified configurations - //! \param configurations_ - //! - void configure(const Configurations& configurations_) { -#if _ELPP_ENABLE_MUTEX - internal::threading::ScopedLock slock_(mutex_); - __EASYLOGGINGPP_SUPPRESS_UNSED(slock_); -#endif // _ELPP_ENABLE_MUTEX - // Configuring uses existing configuration as starting point - // and then sets configurations_ as base to prevent losing any - // previous configurations - Configurations base_ = userConfigurations_; - if (userConfigurations_ != configurations_) { - userConfigurations_ = configurations_; - base_.setFromBase(const_cast(&configurations_)); - } - internal::utilities::safeDelete(typedConfigurations_); - typedConfigurations_ = new internal::TypedConfigurations(base_, constants_); - configured_ = true; - } +}; +class LogDispatchCallback : public Callback { + protected: + virtual void handle(const LogDispatchData* data); + base::threading::Mutex& fileHandle(const LogDispatchData* data); + private: + friend class base::LogDispatcher; + std::unordered_map> m_fileLocks; + base::threading::Mutex m_fileLocksMapLock; +}; +class PerformanceTrackingCallback : public Callback { + private: + friend class base::PerformanceTracker; +}; +class LoggerRegistrationCallback : public Callback { + private: + friend class base::RegisteredLoggers; +}; +class LogBuilder : base::NoCopy { + public: + LogBuilder() : m_termSupportsColor(base::utils::OS::termSupportsColor()) {} + virtual ~LogBuilder(void) { + ELPP_INTERNAL_INFO(3, "Destroying log builder...") + } + virtual base::type::string_t build(const LogMessage* logMessage, bool appendNewLine) const = 0; + void convertToColoredOutput(base::type::string_t* logLine, Level level); + private: + bool m_termSupportsColor; + friend class el::base::DefaultLogDispatchCallback; +}; +typedef std::shared_ptr LogBuilderPtr; +/// @brief Represents a logger holding ID and configurations we need to write logs +/// +/// @detail This class does not write logs itself instead its used by writer to read configuations from. +class Logger : public base::threading::ThreadSafe, public Loggable { + public: + Logger(const std::string& id, base::LogStreamsReferenceMap* logStreamsReference); + Logger(const std::string& id, const Configurations& configurations, base::LogStreamsReferenceMap* logStreamsReference); + Logger(const Logger& logger); + Logger& operator=(const Logger& logger); + + virtual ~Logger(void) { + base::utils::safeDelete(m_typedConfigurations); + } + + virtual inline void log(el::base::type::ostream_t& os) const { + os << m_id.c_str(); + } + + /// @brief Configures the logger using specified configurations. + void configure(const Configurations& configurations); + + /// @brief Reconfigures logger using existing configurations + void reconfigure(void); + + inline const std::string& id(void) const { + return m_id; + } + + inline const std::string& parentApplicationName(void) const { + return m_parentApplicationName; + } + + inline void setParentApplicationName(const std::string& parentApplicationName) { + m_parentApplicationName = parentApplicationName; + } + + inline Configurations* configurations(void) { + return &m_configurations; + } + + inline base::TypedConfigurations* typedConfigurations(void) { + return m_typedConfigurations; + } + + static bool isValidId(const std::string& id); + + /// @brief Flushes logger to sync all log files for all levels + void flush(void); + + void flush(Level level, base::type::fstream_t* fs); + + inline bool isFlushNeeded(Level level) { + return ++m_unflushedCount.find(level)->second >= m_typedConfigurations->logFlushThreshold(level); + } + + inline LogBuilder* logBuilder(void) const { + return m_logBuilder.get(); + } + + inline void setLogBuilder(const LogBuilderPtr& logBuilder) { + m_logBuilder = logBuilder; + } + + inline bool enabled(Level level) const { + return m_typedConfigurations->enabled(level); + } + +#if ELPP_VARIADIC_TEMPLATES_SUPPORTED +# define LOGGER_LEVEL_WRITERS_SIGNATURES(FUNCTION_NAME)\ +template \ +inline void FUNCTION_NAME(const char*, const T&, const Args&...);\ +template \ +inline void FUNCTION_NAME(const T&); + + template + inline void verbose(int, const char*, const T&, const Args&...); + + template + inline void verbose(int, const T&); + + LOGGER_LEVEL_WRITERS_SIGNATURES(info) + LOGGER_LEVEL_WRITERS_SIGNATURES(debug) + LOGGER_LEVEL_WRITERS_SIGNATURES(warn) + LOGGER_LEVEL_WRITERS_SIGNATURES(error) + LOGGER_LEVEL_WRITERS_SIGNATURES(fatal) + LOGGER_LEVEL_WRITERS_SIGNATURES(trace) +# undef LOGGER_LEVEL_WRITERS_SIGNATURES +#endif // ELPP_VARIADIC_TEMPLATES_SUPPORTED + private: + std::string m_id; + base::TypedConfigurations* m_typedConfigurations; + base::type::stringstream_t m_stream; + std::string m_parentApplicationName; + bool m_isConfigured; + Configurations m_configurations; + std::unordered_map m_unflushedCount; + base::LogStreamsReferenceMap* m_logStreamsReference; + LogBuilderPtr m_logBuilder; + + friend class el::LogMessage; + friend class el::Loggers; + friend class el::Helpers; + friend class el::base::RegisteredLoggers; + friend class el::base::DefaultLogDispatchCallback; + friend class el::base::MessageBuilder; + friend class el::base::Writer; + friend class el::base::PErrorWriter; + friend class el::base::Storage; + friend class el::base::PerformanceTracker; + friend class el::base::LogDispatcher; + + Logger(void); + +#if ELPP_VARIADIC_TEMPLATES_SUPPORTED + template + void log_(Level, int, const char*, const T&, const Args&...); + + template + inline void log_(Level, int, const T&); + + template + void log(Level, const char*, const T&, const Args&...); + + template + inline void log(Level, const T&); +#endif // ELPP_VARIADIC_TEMPLATES_SUPPORTED + + void initUnflushedCount(void); + + inline base::type::stringstream_t& stream(void) { + return m_stream; + } + + void resolveLoggerFormatSpec(void) const; +}; +namespace base { +/// @brief Loggers repository +class RegisteredLoggers : public base::utils::Registry { + public: + explicit RegisteredLoggers(const LogBuilderPtr& defaultLogBuilder); + + virtual ~RegisteredLoggers(void) { + unsafeFlushAll(); + } + + inline void setDefaultConfigurations(const Configurations& configurations) { + base::threading::ScopedLock scopedLock(lock()); + m_defaultConfigurations.setFromBase(const_cast(&configurations)); + } + + inline Configurations* defaultConfigurations(void) { + return &m_defaultConfigurations; + } + + Logger* get(const std::string& id, bool forceCreation = true); + + template + inline bool installLoggerRegistrationCallback(const std::string& id) { + return base::utils::Utils::installCallback(id, + &m_loggerRegistrationCallbacks); + } + + template + inline void uninstallLoggerRegistrationCallback(const std::string& id) { + base::utils::Utils::uninstallCallback(id, &m_loggerRegistrationCallbacks); + } + + template + inline T* loggerRegistrationCallback(const std::string& id) { + return base::utils::Utils::callback(id, &m_loggerRegistrationCallbacks); + } + + bool remove(const std::string& id); + + inline bool has(const std::string& id) { + return get(id, false) != nullptr; + } + + inline void unregister(Logger*& logger) { + base::threading::ScopedLock scopedLock(lock()); + base::utils::Registry::unregister(logger->id()); + } + + inline base::LogStreamsReferenceMap* logStreamsReference(void) { + return &m_logStreamsReference; + } + + inline void flushAll(void) { + base::threading::ScopedLock scopedLock(lock()); + unsafeFlushAll(); + } + + inline void setDefaultLogBuilder(LogBuilderPtr& logBuilderPtr) { + base::threading::ScopedLock scopedLock(lock()); + m_defaultLogBuilder = logBuilderPtr; + } + + private: + LogBuilderPtr m_defaultLogBuilder; + Configurations m_defaultConfigurations; + base::LogStreamsReferenceMap m_logStreamsReference; + std::unordered_map m_loggerRegistrationCallbacks; + friend class el::base::Storage; + + void unsafeFlushAll(void); +}; +/// @brief Represents registries for verbose logging +class VRegistry : base::NoCopy, public base::threading::ThreadSafe { + public: + explicit VRegistry(base::type::VerboseLevel level, base::type::EnumType* pFlags); - //! - //! Reconfigures logger - //! - inline void reconfigure(void) { - configure(this->userConfigurations_); - } + /// @brief Sets verbose level. Accepted range is 0-9 + void setLevel(base::type::VerboseLevel level); - //! - //! \return Application name for this logger - //! - inline std::string applicationName(void) const { - return applicationName_; - } + inline base::type::VerboseLevel level(void) const { + return m_level; + } + inline void clearModules(void) { + base::threading::ScopedLock scopedLock(lock()); + m_modules.clear(); + } - //! - //! Application name can vary from logger to logger. For example for a library application name may be different. - //! This is whats used later when you use '%app' in log format - //! - inline void setApplicationName(const std::string& applicationName_) { - this->applicationName_ = applicationName_; - } + void setModules(const char* modules); - //! - //! \return Configurations that this logger is set against - //! - inline Configurations& configurations(void) { - return userConfigurations_; - } + bool allowed(base::type::VerboseLevel vlevel, const char* file); - //! - //! \return Whether or not logger is configured. - //! - inline bool configured(void) const { - return configured_; - } + inline const std::unordered_map& modules(void) const { + return m_modules; + } - //! - //! Predicate used in logger repository to find logger. This is used internally. You should not use it. - //! - class Predicate { - public: - explicit Predicate(const std::string& id_) : - id_(id_) { - } - inline bool operator()(const Logger* logger_) { - return ((logger_ != NULL) && (logger_->id() == id_)); - } - private: - std::string id_; - }; - private: - std::string id_; - internal::Constants* constants_; - Configurations userConfigurations_; - internal::TypedConfigurations* typedConfigurations_; - std::stringstream* stream_; - std::string applicationName_; - bool configured_; - internal::threading::Mutex mutex_; - friend class internal::Writer; - friend class Loggers; - friend class internal::RegisteredLoggers; - - Logger(void); - - std::stringstream* stream(void) { - return stream_; - } + void setFromArgs(const base::utils::CommandLineArgs* commandLineArgs); - inline void acquireLock(void) { - mutex_.lock(); - } + /// @brief Whether or not vModules enabled + inline bool vModulesEnabled(void) { + return !base::utils::hasFlag(LoggingFlag::DisableVModules, *m_pFlags); + } - inline void releaseLock(void) { - mutex_.unlock(); - } - }; - - namespace internal { -//! -//! Internal log counter used for interval logging -//! - class LogCounter : private internal::NoCopy { - public: - explicit LogCounter(internal::Constants* constants_) : - file_(""), - line_(0), - position_(1), - constants_(constants_) { - } - - LogCounter(const char* file_, - unsigned long int line_, - internal::Constants* constants_) : - file_(file_), - line_(line_), - position_(1), - constants_(constants_) { - } - - virtual ~LogCounter(void) { - } - - inline void resetLocation(const char* file_, - unsigned long int line_) { - this->file_ = file_; - this->line_ = line_; - } - - inline void reset(std::size_t n_) { - if (position_ >= constants_->MAX_LOG_PER_COUNTER) { - position_ = (n_ >= 1 ? constants_->MAX_LOG_PER_COUNTER % n_ : 0); - } - ++position_; - } - - inline const char* file(void) const { - return file_; - } - - inline unsigned long int line(void) const { - return line_; - } - - inline std::size_t position(void) const { - return position_; - } - - class Predicate { - public: - Predicate(const char* file_, unsigned long int line_) - : file_(file_), - line_(line_) { - } - inline bool operator()(const LogCounter* counter_) { - return ((counter_ != NULL) && - (counter_->file_ == file_) && - (counter_->line_ == line_)); - } - - private: - const char* file_; - unsigned long int line_; - }; - private: - const char* file_; - unsigned long int line_; - std::size_t position_; - internal::Constants* constants_; - }; // class LogCounter - -//! -//! Internal LogCounter repository -//! - class RegisteredCounters : public Registry { - public: - bool validate(const char* file_, unsigned long int line_, std::size_t n_, internal::Constants* constants_) { -#if _ELPP_ENABLE_MUTEX - internal::threading::ScopedLock slock_(mutex_); - __EASYLOGGINGPP_SUPPRESS_UNSED(slock_); -#endif // _ELPP_ENABLE_MUTEX - bool result_ = false; - internal::LogCounter* counter_ = get(file_, line_); - if (counter_ == NULL) { - registerNew(counter_ = new internal::LogCounter(file_, line_, constants_)); - } - if (n_ >= 1 && counter_->position() != 0 && counter_->position() % n_ == 0) { - result_ = true; - } - counter_->reset(n_); - return result_; - } - private: - internal::threading::Mutex mutex_; - }; // class RegisteredCounters - -//! -//! Internal logger repository. You should not access functionalities directly, you should use easyloggingpp::Loggers instead -//! - class RegisteredLoggers : public internal::Registry { - public: - RegisteredLoggers(void) : - constants_(new internal::Constants()), - username_(internal::utilities::OSUtils::currentUser()), - hostname_(internal::utilities::OSUtils::currentHost()), - counters_(new internal::RegisteredCounters()) { - defaultConfigurations_.setToDefault(); - Configurations conf; - conf.setToDefault(); - conf.parseFromText(constants_->DEFAULT_LOGGER_CONFIGURATION); - registerNew(new Logger("trivial", constants_, conf)); - registerNew(new Logger("business", constants_)); - registerNew(new Logger("security", constants_)); - Configurations confPerformance; - confPerformance.setToDefault(); - confPerformance.setAll(ConfigurationType::PerformanceTracking, "true"); - registerNew(new Logger("performance", constants_, confPerformance)); - } - - virtual ~RegisteredLoggers(void) { - internal::utilities::safeDelete(constants_); - internal::utilities::safeDelete(counters_); - } - - inline internal::Constants* constants(void) const { - return constants_; - } - - inline RegisteredCounters* counters(void) { - return counters_; - } - - inline bool validateCounter(const char* file_, unsigned long int line_, std::size_t n_) { - return counters_->validate(file_, line_, n_, constants_); - } - private: - internal::Constants* constants_; - std::string username_; - std::string hostname_; - internal::threading::Mutex mutex_; - internal::RegisteredCounters* counters_; - Configurations defaultConfigurations_; - - friend class Writer; - friend class easyloggingpp::Loggers; - - inline const std::string& username(void) { - return username_; - } - - inline const std::string& hostname(void) { - return hostname_; - } - - inline void setDefaultConfigurations(const Configurations& configurations) { - defaultConfigurations_.setFromBase(const_cast(&configurations)); - } - - Logger* get(const std::string& id_, bool forceCreation_ = true) { -#if _ELPP_ENABLE_MUTEX - internal::threading::ScopedLock slock_(mutex_); - __EASYLOGGINGPP_SUPPRESS_UNSED(slock_); -#endif // _ELPP_ENABLE_MUTEX - Logger* logger_ = internal::Registry::get(id_); - if (logger_ == NULL && forceCreation_) { - logger_ = new Logger(id_, constants_, defaultConfigurations_); - registerNew(logger_); - } - return logger_; - } - - inline void unregister(Logger*& logger_) { -#if _ELPP_ENABLE_MUTEX - internal::threading::ScopedLock slock_(mutex_); -#endif // _ELPP_ENABLE_MUTEX - internal::Registry::unregister(logger_); - } - - inline void acquireLock(void) { - mutex_.lock(); - } - - inline void releaseLock(void) { - mutex_.unlock(); - } - - void setApplicationArguments(int argc, char** argv) { - while (argc-- > 0) { - // Look for --v=X argument - if ((strlen(argv[argc]) >= 5) && (argv[argc][0] == '-') && (argv[argc][1] == '-') && - (argv[argc][2] == 'v') && (argv[argc][3] == '=') && (isdigit(argv[argc][4]))) { - // Current argument is --v=X - // where X is a digit between 0-9 - constants_->CURRENT_VERBOSE_LEVEL = atoi(argv[argc] + 4); - } - // Look for -v argument - else if ((strlen(argv[argc]) == 2) && (argv[argc][0] == '-') && (argv[argc][1] == 'v')) { - constants_->CURRENT_VERBOSE_LEVEL = constants_->MAX_VERBOSE_LEVEL; - } - // Look for --verbose argument - else if ((strlen(argv[argc]) == 9) && (argv[argc][0] == '-') && (argv[argc][1] == '-') && - (argv[argc][2] == 'v') && (argv[argc][3] == 'e') && (argv[argc][4] == 'r') && - (argv[argc][5] == 'b') && (argv[argc][6] == 'o') && (argv[argc][7] == 's') && - (argv[argc][8] == 'e')) { - constants_->CURRENT_VERBOSE_LEVEL = constants_->MAX_VERBOSE_LEVEL; - } - } - } - - inline void setApplicationArguments(int argc, const char** argv) { - setApplicationArguments(argc, const_cast(argv)); - } - }; - - extern internal::ScopedPointer registeredLoggers; -#if defined(_ELPP_STL_LOGGING) + private: + base::type::VerboseLevel m_level; + base::type::EnumType* m_pFlags; + std::unordered_map m_modules; +}; +} // namespace base +class LogMessage { + public: + LogMessage(Level level, const std::string& file, base::type::LineNumber line, const std::string& func, + base::type::VerboseLevel verboseLevel, Logger* logger) : + m_level(level), m_file(file), m_line(line), m_func(func), + m_verboseLevel(verboseLevel), m_logger(logger), m_message(logger->stream().str()) { + } + inline Level level(void) const { + return m_level; + } + inline const std::string& file(void) const { + return m_file; + } + inline base::type::LineNumber line(void) const { + return m_line; + } + inline const std::string& func(void) const { + return m_func; + } + inline base::type::VerboseLevel verboseLevel(void) const { + return m_verboseLevel; + } + inline Logger* logger(void) const { + return m_logger; + } + inline const base::type::string_t& message(void) const { + return m_message; + } + private: + Level m_level; + std::string m_file; + base::type::LineNumber m_line; + std::string m_func; + base::type::VerboseLevel m_verboseLevel; + Logger* m_logger; + base::type::string_t m_message; +}; +namespace base { +#if ELPP_ASYNC_LOGGING +class AsyncLogItem { + public: + explicit AsyncLogItem(const LogMessage& logMessage, const LogDispatchData& data, const base::type::string_t& logLine) + : m_logMessage(logMessage), m_dispatchData(data), m_logLine(logLine) {} + virtual ~AsyncLogItem() {} + inline LogMessage* logMessage(void) { + return &m_logMessage; + } + inline LogDispatchData* data(void) { + return &m_dispatchData; + } + inline base::type::string_t logLine(void) { + return m_logLine; + } + private: + LogMessage m_logMessage; + LogDispatchData m_dispatchData; + base::type::string_t m_logLine; +}; +class AsyncLogQueue : public base::threading::ThreadSafe { + public: + virtual ~AsyncLogQueue() { + ELPP_INTERNAL_INFO(6, "~AsyncLogQueue"); + } + + inline AsyncLogItem next(void) { + base::threading::ScopedLock scopedLock(lock()); + AsyncLogItem result = m_queue.front(); + m_queue.pop(); + return result; + } + + inline void push(const AsyncLogItem& item) { + base::threading::ScopedLock scopedLock(lock()); + m_queue.push(item); + } + inline void pop(void) { + base::threading::ScopedLock scopedLock(lock()); + m_queue.pop(); + } + inline AsyncLogItem front(void) { + base::threading::ScopedLock scopedLock(lock()); + return m_queue.front(); + } + inline bool empty(void) { + base::threading::ScopedLock scopedLock(lock()); + return m_queue.empty(); + } + private: + std::queue m_queue; +}; +class IWorker { + public: + virtual ~IWorker() {} + virtual void start() = 0; +}; +#endif // ELPP_ASYNC_LOGGING +/// @brief Easylogging++ management storage +class Storage : base::NoCopy, public base::threading::ThreadSafe { + public: +#if ELPP_ASYNC_LOGGING + Storage(const LogBuilderPtr& defaultLogBuilder, base::IWorker* asyncDispatchWorker); +#else + explicit Storage(const LogBuilderPtr& defaultLogBuilder); +#endif // ELPP_ASYNC_LOGGING + + virtual ~Storage(void); + + inline bool validateEveryNCounter(const char* filename, base::type::LineNumber lineNumber, std::size_t occasion) { + return hitCounters()->validateEveryN(filename, lineNumber, occasion); + } + + inline bool validateAfterNCounter(const char* filename, base::type::LineNumber lineNumber, std::size_t n) { + return hitCounters()->validateAfterN(filename, lineNumber, n); + } + + inline bool validateNTimesCounter(const char* filename, base::type::LineNumber lineNumber, std::size_t n) { + return hitCounters()->validateNTimes(filename, lineNumber, n); + } + + inline base::RegisteredHitCounters* hitCounters(void) const { + return m_registeredHitCounters; + } + + inline base::RegisteredLoggers* registeredLoggers(void) const { + return m_registeredLoggers; + } + + inline base::VRegistry* vRegistry(void) const { + return m_vRegistry; + } + +#if ELPP_ASYNC_LOGGING + inline base::AsyncLogQueue* asyncLogQueue(void) const { + return m_asyncLogQueue; + } +#endif // ELPP_ASYNC_LOGGING + + inline const base::utils::CommandLineArgs* commandLineArgs(void) const { + return &m_commandLineArgs; + } + + inline void addFlag(LoggingFlag flag) { + base::utils::addFlag(flag, &m_flags); + } + + inline void removeFlag(LoggingFlag flag) { + base::utils::removeFlag(flag, &m_flags); + } + + inline bool hasFlag(LoggingFlag flag) const { + return base::utils::hasFlag(flag, m_flags); + } + + inline base::type::EnumType flags(void) const { + return m_flags; + } + + inline void setFlags(base::type::EnumType flags) { + m_flags = flags; + } + + inline void setPreRollOutCallback(const PreRollOutCallback& callback) { + m_preRollOutCallback = callback; + } + + inline void unsetPreRollOutCallback(void) { + m_preRollOutCallback = base::defaultPreRollOutCallback; + } + + inline PreRollOutCallback& preRollOutCallback(void) { + return m_preRollOutCallback; + } + + bool hasCustomFormatSpecifier(const char* formatSpecifier); + void installCustomFormatSpecifier(const CustomFormatSpecifier& customFormatSpecifier); + bool uninstallCustomFormatSpecifier(const char* formatSpecifier); + + const std::vector* customFormatSpecifiers(void) const { + return &m_customFormatSpecifiers; + } + + base::threading::Mutex& customFormatSpecifiersLock() { + return m_customFormatSpecifiersLock; + } + + inline void setLoggingLevel(Level level) { + m_loggingLevel = level; + } + + template + inline bool installLogDispatchCallback(const std::string& id) { + return base::utils::Utils::installCallback(id, &m_logDispatchCallbacks); + } + + template + inline void uninstallLogDispatchCallback(const std::string& id) { + base::utils::Utils::uninstallCallback(id, &m_logDispatchCallbacks); + } + template + inline T* logDispatchCallback(const std::string& id) { + return base::utils::Utils::callback(id, &m_logDispatchCallbacks); + } + +#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING) + template + inline bool installPerformanceTrackingCallback(const std::string& id) { + return base::utils::Utils::installCallback(id, + &m_performanceTrackingCallbacks); + } + + template + inline void uninstallPerformanceTrackingCallback(const std::string& id) { + base::utils::Utils::uninstallCallback(id, + &m_performanceTrackingCallbacks); + } + + template + inline T* performanceTrackingCallback(const std::string& id) { + return base::utils::Utils::callback(id, &m_performanceTrackingCallbacks); + } +#endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING) + + /// @brief Sets thread name for current thread. Requires std::thread + inline void setThreadName(const std::string& name) { + if (name.empty()) return; + base::threading::ScopedLock scopedLock(m_threadNamesLock); + m_threadNames[base::threading::getCurrentThreadId()] = name; + } + + inline std::string getThreadName(const std::string& threadId) { + base::threading::ScopedLock scopedLock(m_threadNamesLock); + std::unordered_map::const_iterator it = m_threadNames.find(threadId); + if (it == m_threadNames.end()) { + return threadId; + } + return it->second; + } + private: + base::RegisteredHitCounters* m_registeredHitCounters; + base::RegisteredLoggers* m_registeredLoggers; + base::type::EnumType m_flags; + base::VRegistry* m_vRegistry; +#if ELPP_ASYNC_LOGGING + base::AsyncLogQueue* m_asyncLogQueue; + base::IWorker* m_asyncDispatchWorker; +#endif // ELPP_ASYNC_LOGGING + base::utils::CommandLineArgs m_commandLineArgs; + PreRollOutCallback m_preRollOutCallback; + std::unordered_map m_logDispatchCallbacks; + std::unordered_map m_performanceTrackingCallbacks; + std::unordered_map m_threadNames; + std::vector m_customFormatSpecifiers; + base::threading::Mutex m_customFormatSpecifiersLock; + base::threading::Mutex m_threadNamesLock; + Level m_loggingLevel; + + friend class el::Helpers; + friend class el::base::DefaultLogDispatchCallback; + friend class el::LogBuilder; + friend class el::base::MessageBuilder; + friend class el::base::Writer; + friend class el::base::PerformanceTracker; + friend class el::base::LogDispatcher; + + void setApplicationArguments(int argc, char** argv); + + inline void setApplicationArguments(int argc, const char** argv) { + setApplicationArguments(argc, const_cast(argv)); + } +}; +extern ELPP_EXPORT base::type::StoragePointer elStorage; +#define ELPP el::base::elStorage +class DefaultLogDispatchCallback : public LogDispatchCallback { + protected: + void handle(const LogDispatchData* data); + private: + const LogDispatchData* m_data; + void dispatch(base::type::string_t&& logLine); +}; +#if ELPP_ASYNC_LOGGING +class AsyncLogDispatchCallback : public LogDispatchCallback { + protected: + void handle(const LogDispatchData* data); +}; +class AsyncDispatchWorker : public base::IWorker, public base::threading::ThreadSafe { + public: + AsyncDispatchWorker(); + virtual ~AsyncDispatchWorker(); + + bool clean(void); + void emptyQueue(void); + virtual void start(void); + void handle(AsyncLogItem* logItem); + void run(void); + + void setContinueRunning(bool value) { + base::threading::ScopedLock scopedLock(m_continueRunningLock); + m_continueRunning = value; + } + + bool continueRunning(void) const { + return m_continueRunning; + } + private: + std::condition_variable cv; + bool m_continueRunning; + base::threading::Mutex m_continueRunningLock; +}; +#endif // ELPP_ASYNC_LOGGING +} // namespace base +namespace base { +class DefaultLogBuilder : public LogBuilder { + public: + base::type::string_t build(const LogMessage* logMessage, bool appendNewLine) const; +}; +/// @brief Dispatches log messages +class LogDispatcher : base::NoCopy { + public: + LogDispatcher(bool proceed, LogMessage* logMessage, base::DispatchAction dispatchAction) : + m_proceed(proceed), + m_logMessage(logMessage), + m_dispatchAction(std::move(dispatchAction)) { + } + + void dispatch(void); + + private: + bool m_proceed; + LogMessage* m_logMessage; + base::DispatchAction m_dispatchAction; +}; +#if defined(ELPP_STL_LOGGING) +/// @brief Workarounds to write some STL logs +/// +/// @detail There is workaround needed to loop through some stl containers. In order to do that, we need iterable containers +/// of same type and provide iterator interface and pass it on to writeIterator(). +/// Remember, this is passed by value in constructor so that we dont change original containers. +/// This operation is as expensive as Big-O(std::min(class_.size(), base::consts::kMaxLogPerContainer)) namespace workarounds { -// There is workaround needed to loop through some stl containers. In order to do that, we need iterable containers -// of same type and provide iterator interface and pass it on to writeIterator(). -// Remember, this is passed by value in constructor so that we dont change original containers. -// This operation is as expensive as O(class_.size()) or O(constants->MAX_LOG_PER_COUNTER) which ever is smaller. - -// -// Abstract IterableContainer template that provides interface for iterable classes of type T -// +/// @brief Abstract IterableContainer template that provides interface for iterable classes of type T template class IterableContainer { -public: - typedef typename Container::iterator iterator; - typedef typename Container::const_iterator const_iterator; - IterableContainer(void){} - virtual ~IterableContainer(void) {} - iterator begin(void) { return getContainer().begin(); } - iterator end(void) { return getContainer().end(); } - const_iterator begin(void) const { return getContainer().begin(); } - const_iterator end(void) const { return getContainer().end(); } -private: - virtual Container& getContainer(void) = 0; + public: + typedef typename Container::iterator iterator; + typedef typename Container::const_iterator const_iterator; + IterableContainer(void) {} + virtual ~IterableContainer(void) {} + iterator begin(void) { + return getContainer().begin(); + } + iterator end(void) { + return getContainer().end(); + } + private: + virtual Container& getContainer(void) = 0; }; - -// -// Implements IterableContainer and provides iterable std::priority_queue class -// -template, typename Comparator = std::less > -class IterablePriorityQueue : public IterableContainer, public std::priority_queue { -public: - IterablePriorityQueue(std::priority_queue queue_) { - std::size_t count_ = 0; - while (++count_ < registeredLoggers->constants()->MAX_LOG_PER_CONTAINER && !queue_.empty()) { - this->push(queue_.top()); - queue_.pop(); - } - } -private: - inline Container& getContainer(void) { - return this->c; +/// @brief Implements IterableContainer and provides iterable std::priority_queue class +template, typename Comparator = std::less> +class IterablePriorityQueue : public IterableContainer, + public std::priority_queue { + public: + IterablePriorityQueue(std::priority_queue queue_) { + std::size_t count_ = 0; + while (++count_ < base::consts::kMaxLogPerContainer && !queue_.empty()) { + this->push(queue_.top()); + queue_.pop(); } + } + private: + inline Container& getContainer(void) { + return this->c; + } }; - -// -// Implements IterableContainer and provides iterable std::queue class -// -template > +/// @brief Implements IterableContainer and provides iterable std::queue class +template> class IterableQueue : public IterableContainer, public std::queue { -public: - IterableQueue(std::queue queue_) { - std::size_t count_ = 0; - while (++count_ < registeredLoggers->constants()->MAX_LOG_PER_CONTAINER && !queue_.empty()) { - this->push(queue_.front()); - queue_.pop(); - } - } -private: - inline Container& getContainer(void) { - return this->c; + public: + IterableQueue(std::queue queue_) { + std::size_t count_ = 0; + while (++count_ < base::consts::kMaxLogPerContainer && !queue_.empty()) { + this->push(queue_.front()); + queue_.pop(); } + } + private: + inline Container& getContainer(void) { + return this->c; + } }; - -// -// Implements IterableContainer and provides iterable std::stack class -// -template > +/// @brief Implements IterableContainer and provides iterable std::stack class +template> class IterableStack : public IterableContainer, public std::stack { -public: - IterableStack(std::stack stack_) { - std::size_t count_ = 0; - while (++count_ < registeredLoggers->constants()->MAX_LOG_PER_CONTAINER && !stack_.empty()) { - this->push(stack_.top()); - stack_.pop(); - } - } -private: - inline Container& getContainer(void) { - return this->c; + public: + IterableStack(std::stack stack_) { + std::size_t count_ = 0; + while (++count_ < base::consts::kMaxLogPerContainer && !stack_.empty()) { + this->push(stack_.top()); + stack_.pop(); } + } + private: + inline Container& getContainer(void) { + return this->c; + } }; -} // namespace workarounds -#endif //defined(_ELPP_STL_LOGGING) - -#define _ELPP_STREAM(l) (*(l->stream())) - - class NullWriter : private internal::NoCopy { - public: - NullWriter(void) {} - - template - inline NullWriter& operator<<(const T&) { - return *this; - } - }; - - class Writer : private internal::NoCopy { - public: - Writer(const std::string& loggerId_, - unsigned int aspect_, - unsigned int severity_, - const char* func_, - const char* file_, - const unsigned long int line_, - bool condition_ = true, - int verboseLevel_ = 0, - int counter_ = 0) : - aspect_(aspect_), - severity_(severity_), - func_(func_), - file_(file_), - line_(line_), - condition_(condition_), - verboseLevel_(verboseLevel_), - counter_(counter_), - proceed_(true) { - constants_ = registeredLoggers->constants(); - logger_ = registeredLoggers->get(loggerId_, false); - if (logger_ == NULL) { - __EASYLOGGINGPP_ASSERT(logger_ != NULL, "Logger [" << loggerId_ << "] not registered or configured yet!"); - proceed_ = false; - } -#if _ELPP_ENABLE_MUTEX - registeredLoggers->acquireLock(); - mutex_.lock(); -#endif // _ELPP_ENABLE_MUTEX - - if (proceed_) { - proceed_ = logger_->typedConfigurations_->enabled(severity_); - } - if (proceed_) { -#if (defined(_ELPP_STRICT_ROLLOUT)) - checkRollOuts(severity_, logger_); -#endif // (defined(_ELPP_STRICT_ROLLOUT)) - } - if (proceed_ && (severity_ == Level::Verbose)) { - proceed_ = (verboseLevel_ <= constants_->CURRENT_VERBOSE_LEVEL); - } - if (proceed_ && (aspect_ == Aspect::Conditional)) { - proceed_ = condition_; - } - } - - virtual ~Writer(void) { - if (proceed_) { - buildAndWriteLine(); - } -#if _ELPP_ENABLE_MUTEX - registeredLoggers->releaseLock(); - mutex_.unlock(); -#endif // _ELPP_ENABLE_MUTEX - } - - inline Writer& operator<<(const std::string& log_) { - if (!proceed_) { return *this; } - _ELPP_STREAM(logger_) << log_; - return *this; - } - inline Writer& operator<<(char log_) { - if (!proceed_) { return *this; } - _ELPP_STREAM(logger_) << log_; - return *this; - } - inline Writer& operator<<(bool log_) { - if (!proceed_) { return *this; } - _ELPP_STREAM(logger_) << log_; - return *this; - } - inline Writer& operator<<(signed short log_) { - if (!proceed_) { return *this; } - _ELPP_STREAM(logger_) << log_; - return *this; - } - inline Writer& operator<<(unsigned short log_) { - if (!proceed_) { return *this; } - _ELPP_STREAM(logger_) << log_; - return *this; - } - inline Writer& operator<<(signed int log_) { - if (!proceed_) { return *this; } - _ELPP_STREAM(logger_) << log_; - return *this; - } - inline Writer& operator<<(unsigned int log_) { - if (!proceed_) { return *this; } - _ELPP_STREAM(logger_) << log_; - return *this; - } - inline Writer& operator<<(signed long log_) { - if (!proceed_) { return *this; } - _ELPP_STREAM(logger_) << log_; - return *this; - } - inline Writer& operator<<(unsigned long log_) { - if (!proceed_) { return *this; } - _ELPP_STREAM(logger_) << log_; - return *this; - } - inline Writer& operator<<(float log_) { - if (!proceed_) { return *this; } - _ELPP_STREAM(logger_) << log_; - return *this; - } - inline Writer& operator<<(double log_) { - if (!proceed_) { return *this; } - _ELPP_STREAM(logger_) << log_; - return *this; - } - inline Writer& operator<<(char* log_) { - if (!proceed_) { return *this; } - _ELPP_STREAM(logger_) << log_; - return *this; - } - inline Writer& operator<<(const char* log_) { - if (!proceed_) { return *this; } - _ELPP_STREAM(logger_) << log_; - return *this; - } - inline Writer& operator<<(const void* log_) { - if (!proceed_) { return *this; } - _ELPP_STREAM(logger_) << log_; - return *this; - } - inline Writer& operator<<(long double log_) { - if (!proceed_) { return *this; } - _ELPP_STREAM(logger_) << log_; - return *this; - } - inline Writer& operator<<(const std::wstring& log_) { - if (!proceed_) { return *this; } - return operator<<(log_.c_str()); - } - inline Writer& operator<<(const wchar_t* log_) { - if (!proceed_) { return *this; } - if (log_ == NULL) { - _ELPP_STREAM(logger_) << constants_->NULL_POINTER; - return *this; - } - std::size_t len_ = wcslen(log_) + 1; - char* buff_ = (char*)malloc(len_ + 1); -# if _ELPP_OS_UNIX || (_ELPP_OS_WINDOWS && !_ELPP_CRT_DBG_WARNINGS) - std::wcstombs(buff_, log_, len_); -# elif _ELPP_OS_WINDOWS - std::size_t convCount_ = 0; - mbstate_t mbState_; - ::memset((void*)&mbState_, 0, sizeof(mbState_)); - wcsrtombs_s(&convCount_, buff_, len_, &log_, len_, &mbState_); -# endif // _ELPP_OS_UNIX - _ELPP_STREAM(logger_) << buff_; - free(buff_); - return *this; - } -#if defined(_ELPP_STL_LOGGING) - template - inline Writer& operator<<(const std::vector& vec_) { - if (!proceed_) { return *this; } - return writeIterator(vec_.begin(), vec_.end(), vec_.size()); - } - template - inline Writer& operator<<(const std::list& list_) { - if (!proceed_) { return *this; } - return writeIterator(list_.begin(), list_.end(), list_.size()); - } - template - inline Writer& operator<<(const std::deque& deque_) { - if (!proceed_) { return *this; } - return writeIterator(deque_.begin(), deque_.end(), deque_.size()); - } - template - inline Writer& operator<<(const std::queue& queue_) { - if (!proceed_) { return *this; } - internal::workarounds::IterableQueue iterableQueue_ = - static_cast >(queue_); - return writeIterator(iterableQueue_.begin(), iterableQueue_.end(), iterableQueue_.size()); +} // namespace workarounds +#endif // defined(ELPP_STL_LOGGING) +// Log message builder +class MessageBuilder { + public: + MessageBuilder(void) : m_logger(nullptr), m_containerLogSeperator(ELPP_LITERAL("")) {} + void initialize(Logger* logger); + +# define ELPP_SIMPLE_LOG(LOG_TYPE)\ +MessageBuilder& operator<<(LOG_TYPE msg) {\ +m_logger->stream() << msg;\ +if (ELPP->hasFlag(LoggingFlag::AutoSpacing)) {\ +m_logger->stream() << " ";\ +}\ +return *this;\ +} + + inline MessageBuilder& operator<<(const std::string& msg) { + return operator<<(msg.c_str()); + } + ELPP_SIMPLE_LOG(char) + ELPP_SIMPLE_LOG(bool) + ELPP_SIMPLE_LOG(signed short) + ELPP_SIMPLE_LOG(unsigned short) + ELPP_SIMPLE_LOG(signed int) + ELPP_SIMPLE_LOG(unsigned int) + ELPP_SIMPLE_LOG(signed long) + ELPP_SIMPLE_LOG(unsigned long) + ELPP_SIMPLE_LOG(float) + ELPP_SIMPLE_LOG(double) + ELPP_SIMPLE_LOG(char*) + ELPP_SIMPLE_LOG(const char*) + ELPP_SIMPLE_LOG(const void*) + ELPP_SIMPLE_LOG(long double) + inline MessageBuilder& operator<<(const std::wstring& msg) { + return operator<<(msg.c_str()); + } + MessageBuilder& operator<<(const wchar_t* msg); + // ostream manipulators + inline MessageBuilder& operator<<(std::ostream& (*OStreamMani)(std::ostream&)) { + m_logger->stream() << OStreamMani; + return *this; + } +#define ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(temp) \ +template \ +inline MessageBuilder& operator<<(const temp& template_inst) { \ +return writeIterator(template_inst.begin(), template_inst.end(), template_inst.size()); \ +} +#define ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(temp) \ +template \ +inline MessageBuilder& operator<<(const temp& template_inst) { \ +return writeIterator(template_inst.begin(), template_inst.end(), template_inst.size()); \ +} +#define ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG(temp) \ +template \ +inline MessageBuilder& operator<<(const temp& template_inst) { \ +return writeIterator(template_inst.begin(), template_inst.end(), template_inst.size()); \ +} +#define ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(temp) \ +template \ +inline MessageBuilder& operator<<(const temp& template_inst) { \ +return writeIterator(template_inst.begin(), template_inst.end(), template_inst.size()); \ +} +#define ELPP_ITERATOR_CONTAINER_LOG_FIVE_ARG(temp) \ +template \ +inline MessageBuilder& operator<<(const temp& template_inst) { \ +return writeIterator(template_inst.begin(), template_inst.end(), template_inst.size()); \ +} + +#if defined(ELPP_STL_LOGGING) + ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(std::vector) + ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(std::list) + ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(std::deque) + ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG(std::set) + ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG(std::multiset) + ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(std::map) + ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(std::multimap) + template + inline MessageBuilder& operator<<(const std::queue& queue_) { + base::workarounds::IterableQueue iterableQueue_ = + static_cast >(queue_); + return writeIterator(iterableQueue_.begin(), iterableQueue_.end(), iterableQueue_.size()); + } + template + inline MessageBuilder& operator<<(const std::stack& stack_) { + base::workarounds::IterableStack iterableStack_ = + static_cast >(stack_); + return writeIterator(iterableStack_.begin(), iterableStack_.end(), iterableStack_.size()); + } + template + inline MessageBuilder& operator<<(const std::priority_queue& priorityQueue_) { + base::workarounds::IterablePriorityQueue iterablePriorityQueue_ = + static_cast >(priorityQueue_); + return writeIterator(iterablePriorityQueue_.begin(), iterablePriorityQueue_.end(), iterablePriorityQueue_.size()); + } + template + MessageBuilder& operator<<(const std::pair& pair_) { + m_logger->stream() << ELPP_LITERAL("("); + operator << (static_cast(pair_.first)); + m_logger->stream() << ELPP_LITERAL(", "); + operator << (static_cast(pair_.second)); + m_logger->stream() << ELPP_LITERAL(")"); + return *this; + } + template + MessageBuilder& operator<<(const std::bitset& bitset_) { + m_logger->stream() << ELPP_LITERAL("["); + operator << (bitset_.to_string()); + m_logger->stream() << ELPP_LITERAL("]"); + return *this; + } +# if defined(ELPP_LOG_STD_ARRAY) + template + inline MessageBuilder& operator<<(const std::array& array) { + return writeIterator(array.begin(), array.end(), array.size()); + } +# endif // defined(ELPP_LOG_STD_ARRAY) +# if defined(ELPP_LOG_UNORDERED_MAP) + ELPP_ITERATOR_CONTAINER_LOG_FIVE_ARG(std::unordered_map) + ELPP_ITERATOR_CONTAINER_LOG_FIVE_ARG(std::unordered_multimap) +# endif // defined(ELPP_LOG_UNORDERED_MAP) +# if defined(ELPP_LOG_UNORDERED_SET) + ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(std::unordered_set) + ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(std::unordered_multiset) +# endif // defined(ELPP_LOG_UNORDERED_SET) +#endif // defined(ELPP_STL_LOGGING) +#if defined(ELPP_QT_LOGGING) + inline MessageBuilder& operator<<(const QString& msg) { +# if defined(ELPP_UNICODE) + m_logger->stream() << msg.toStdWString(); +# else + m_logger->stream() << msg.toStdString(); +# endif // defined(ELPP_UNICODE) + return *this; + } + inline MessageBuilder& operator<<(const QByteArray& msg) { + return operator << (QString(msg)); + } + inline MessageBuilder& operator<<(const QStringRef& msg) { + return operator<<(msg.toString()); + } + inline MessageBuilder& operator<<(qint64 msg) { +# if defined(ELPP_UNICODE) + m_logger->stream() << QString::number(msg).toStdWString(); +# else + m_logger->stream() << QString::number(msg).toStdString(); +# endif // defined(ELPP_UNICODE) + return *this; + } + inline MessageBuilder& operator<<(quint64 msg) { +# if defined(ELPP_UNICODE) + m_logger->stream() << QString::number(msg).toStdWString(); +# else + m_logger->stream() << QString::number(msg).toStdString(); +# endif // defined(ELPP_UNICODE) + return *this; + } + inline MessageBuilder& operator<<(QChar msg) { + m_logger->stream() << msg.toLatin1(); + return *this; + } + inline MessageBuilder& operator<<(const QLatin1String& msg) { + m_logger->stream() << msg.latin1(); + return *this; + } + ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QList) + ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QVector) + ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QQueue) + ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QSet) + ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QLinkedList) + ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QStack) + template + MessageBuilder& operator<<(const QPair& pair_) { + m_logger->stream() << ELPP_LITERAL("("); + operator << (static_cast(pair_.first)); + m_logger->stream() << ELPP_LITERAL(", "); + operator << (static_cast(pair_.second)); + m_logger->stream() << ELPP_LITERAL(")"); + return *this; + } + template + MessageBuilder& operator<<(const QMap& map_) { + m_logger->stream() << ELPP_LITERAL("["); + QList keys = map_.keys(); + typename QList::const_iterator begin = keys.begin(); + typename QList::const_iterator end = keys.end(); + int max_ = static_cast(base::consts::kMaxLogPerContainer); // to prevent warning + for (int index_ = 0; begin != end && index_ < max_; ++index_, ++begin) { + m_logger->stream() << ELPP_LITERAL("("); + operator << (static_cast(*begin)); + m_logger->stream() << ELPP_LITERAL(", "); + operator << (static_cast(map_.value(*begin))); + m_logger->stream() << ELPP_LITERAL(")"); + m_logger->stream() << ((index_ < keys.size() -1) ? m_containerLogSeperator : ELPP_LITERAL("")); } - template - inline Writer& operator<<(const std::stack& stack_) { - if (!proceed_) { return *this; } - internal::workarounds::IterableStack iterableStack_ = - static_cast >(stack_); - return writeIterator(iterableStack_.begin(), iterableStack_.end(), iterableStack_.size()); + if (begin != end) { + m_logger->stream() << ELPP_LITERAL("..."); } - template - inline Writer& operator<<(const std::priority_queue& priorityQueue_) { - if (!proceed_) { return *this; } - internal::workarounds::IterablePriorityQueue iterablePriorityQueue_ = - static_cast >(priorityQueue_); - return writeIterator(iterablePriorityQueue_.begin(), iterablePriorityQueue_.end(), iterablePriorityQueue_.size()); + m_logger->stream() << ELPP_LITERAL("]"); + return *this; + } + template + inline MessageBuilder& operator<<(const QMultiMap& map_) { + operator << (static_cast>(map_)); + return *this; + } + template + MessageBuilder& operator<<(const QHash& hash_) { + m_logger->stream() << ELPP_LITERAL("["); + QList keys = hash_.keys(); + typename QList::const_iterator begin = keys.begin(); + typename QList::const_iterator end = keys.end(); + int max_ = static_cast(base::consts::kMaxLogPerContainer); // prevent type warning + for (int index_ = 0; begin != end && index_ < max_; ++index_, ++begin) { + m_logger->stream() << ELPP_LITERAL("("); + operator << (static_cast(*begin)); + m_logger->stream() << ELPP_LITERAL(", "); + operator << (static_cast(hash_.value(*begin))); + m_logger->stream() << ELPP_LITERAL(")"); + m_logger->stream() << ((index_ < keys.size() -1) ? m_containerLogSeperator : ELPP_LITERAL("")); } - template - inline Writer& operator<<(const std::set& set_) { - if (!proceed_) { return *this; } - return writeIterator(set_.begin(), set_.end(), set_.size()); + if (begin != end) { + m_logger->stream() << ELPP_LITERAL("..."); } - template - inline Writer& operator<<(const std::multiset& set_) { - if (!proceed_) { return *this; } - return writeIterator(set_.begin(), set_.end(), set_.size()); - } - template - inline Writer& operator<<(const std::pair& pair_) { - if (!proceed_) { return *this; } - _ELPP_STREAM(logger_) << "("; - operator << (static_cast(pair_.first)); - _ELPP_STREAM(logger_) << ", "; - operator << (static_cast(pair_.second)); - _ELPP_STREAM(logger_) << ")"; - return *this; - } - template - inline Writer& operator<<(const std::bitset& bitset_) { - if (!proceed_) { return *this; } - _ELPP_STREAM(logger_) << "["; - _ELPP_STREAM(logger_) << bitset_.to_string(); - _ELPP_STREAM(logger_) << "]"; - return *this; - } - template - inline Writer& operator<<(const std::map& map_) { - if (!proceed_) { return *this; } - return writeIterator(map_.begin(), map_.end(), map_.size()); - } - template - inline Writer& operator<<(const std::multimap& map_) { - if (!proceed_) { return *this; } - return writeIterator(map_.begin(), map_.end(), map_.size()); - } -#endif // defined(_ELPP_STL_LOGGING) -#if defined(QT_CORE_LIB) && defined(_ELPP_QT_LOGGING) - inline Writer& operator<<(const QString& log_) { - if (!proceed_) { return *this; } - _ELPP_STREAM(logger_) << log_.toStdString(); - return *this; - } - inline Writer& operator<<(const QStringRef& log_) { - if (!proceed_) { return *this; } - return operator<<(log_.toString()); - } - inline Writer& operator<<(qint64 log_) { - if (!proceed_) { return *this; } - _ELPP_STREAM(logger_) << QString::number(log_).toStdString(); - return *this; - } - inline Writer& operator<<(quint64 log_) { - if (!proceed_) { return *this; } - _ELPP_STREAM(logger_) << QString::number(log_).toStdString(); - return *this; - } - inline Writer& operator<<(QChar log_) { - if (!proceed_) { return *this; } - _ELPP_STREAM(logger_) << log_.toLatin1(); - return *this; - } -# if (!_ELPP_QT_5) - inline Writer& operator<<(QBool log_) { - if (!proceed_) { return *this; } - _ELPP_STREAM(logger_) << (bool(log_ != 0) ? "true" : "false"); - return *this; - } -# endif // (!_ELPP_QT_5) - inline Writer& operator<<(const QLatin1String& log_) { - if (!proceed_) { return *this; } - _ELPP_STREAM(logger_) << log_.latin1(); - return *this; - } - template - inline Writer& operator<<(const QList& list_) { - if (!proceed_) { return *this; } - return writeIterator(list_.begin(), list_.end(), list_.size()); + m_logger->stream() << ELPP_LITERAL("]"); + return *this; + } + template + inline MessageBuilder& operator<<(const QMultiHash& multiHash_) { + operator << (static_cast>(multiHash_)); + return *this; + } +#endif // defined(ELPP_QT_LOGGING) +#if defined(ELPP_BOOST_LOGGING) + ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(boost::container::vector) + ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(boost::container::stable_vector) + ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(boost::container::list) + ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(boost::container::deque) + ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(boost::container::map) + ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(boost::container::flat_map) + ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG(boost::container::set) + ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG(boost::container::flat_set) +#endif // defined(ELPP_BOOST_LOGGING) + + /// @brief Macro used internally that can be used externally to make containers easylogging++ friendly + /// + /// @detail This macro expands to write an ostream& operator<< for container. This container is expected to + /// have begin() and end() methods that return respective iterators + /// @param ContainerType Type of container e.g, MyList from WX_DECLARE_LIST(int, MyList); in wxwidgets + /// @param SizeMethod Method used to get size of container. + /// @param ElementInstance Instance of element to be fed out. Insance name is "elem". See WXELPP_ENABLED macro + /// for an example usage +#define MAKE_CONTAINERELPP_FRIENDLY(ContainerType, SizeMethod, ElementInstance) \ +el::base::type::ostream_t& operator<<(el::base::type::ostream_t& ss, const ContainerType& container) {\ +const el::base::type::char_t* sep = ELPP->hasFlag(el::LoggingFlag::NewLineForContainer) ? \ +ELPP_LITERAL("\n ") : ELPP_LITERAL(", ");\ +ContainerType::const_iterator elem = container.begin();\ +ContainerType::const_iterator endElem = container.end();\ +std::size_t size_ = container.SizeMethod; \ +ss << ELPP_LITERAL("[");\ +for (std::size_t i = 0; elem != endElem && i < el::base::consts::kMaxLogPerContainer; ++i, ++elem) { \ +ss << ElementInstance;\ +ss << ((i < size_ - 1) ? sep : ELPP_LITERAL(""));\ +}\ +if (elem != endElem) {\ +ss << ELPP_LITERAL("...");\ +}\ +ss << ELPP_LITERAL("]");\ +return ss;\ +} +#if defined(ELPP_WXWIDGETS_LOGGING) + ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(wxVector) +# define ELPP_WX_PTR_ENABLED(ContainerType) MAKE_CONTAINERELPP_FRIENDLY(ContainerType, size(), *(*elem)) +# define ELPP_WX_ENABLED(ContainerType) MAKE_CONTAINERELPP_FRIENDLY(ContainerType, size(), (*elem)) +# define ELPP_WX_HASH_MAP_ENABLED(ContainerType) MAKE_CONTAINERELPP_FRIENDLY(ContainerType, size(), \ +ELPP_LITERAL("(") << elem->first << ELPP_LITERAL(", ") << elem->second << ELPP_LITERAL(")") +#else +# define ELPP_WX_PTR_ENABLED(ContainerType) +# define ELPP_WX_ENABLED(ContainerType) +# define ELPP_WX_HASH_MAP_ENABLED(ContainerType) +#endif // defined(ELPP_WXWIDGETS_LOGGING) + // Other classes + template + ELPP_SIMPLE_LOG(const Class&) +#undef ELPP_SIMPLE_LOG +#undef ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG +#undef ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG +#undef ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG +#undef ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG +#undef ELPP_ITERATOR_CONTAINER_LOG_FIVE_ARG + private: + Logger* m_logger; + const base::type::char_t* m_containerLogSeperator; + + template + MessageBuilder& writeIterator(Iterator begin_, Iterator end_, std::size_t size_) { + m_logger->stream() << ELPP_LITERAL("["); + for (std::size_t i = 0; begin_ != end_ && i < base::consts::kMaxLogPerContainer; ++i, ++begin_) { + operator << (*begin_); + m_logger->stream() << ((i < size_ - 1) ? m_containerLogSeperator : ELPP_LITERAL("")); } - template - inline Writer& operator<<(const QVector& vec_) { - if (!proceed_) { return *this; } - return writeIterator(vec_.begin(), vec_.end(), vec_.size()); + if (begin_ != end_) { + m_logger->stream() << ELPP_LITERAL("..."); } - template - inline Writer& operator<<(const QQueue& queue_) { - if (!proceed_) { return *this; } - return writeIterator(queue_.begin(), queue_.end(), queue_.size()); + m_logger->stream() << ELPP_LITERAL("]"); + if (ELPP->hasFlag(LoggingFlag::AutoSpacing)) { + m_logger->stream() << " "; } - template - inline Writer& operator<<(const QSet& set_) { - if (!proceed_) { return *this; } - return writeIterator(set_.begin(), set_.end(), set_.size()); + return *this; + } +}; +/// @brief Writes nothing - Used when certain log is disabled +class NullWriter : base::NoCopy { + public: + NullWriter(void) {} + + // Null manipulator + inline NullWriter& operator<<(std::ostream& (*)(std::ostream&)) { + return *this; + } + + template + inline NullWriter& operator<<(const T&) { + return *this; + } + + inline operator bool() { + return true; + } +}; +/// @brief Main entry point of each logging +class Writer : base::NoCopy { + public: + Writer(Level level, const char* file, base::type::LineNumber line, + const char* func, base::DispatchAction dispatchAction = base::DispatchAction::NormalLog, + base::type::VerboseLevel verboseLevel = 0) : + m_msg(nullptr), m_level(level), m_file(file), m_line(line), m_func(func), m_verboseLevel(verboseLevel), + m_logger(nullptr), m_proceed(false), m_dispatchAction(dispatchAction) { + } + + Writer(LogMessage* msg, base::DispatchAction dispatchAction = base::DispatchAction::NormalLog) : + m_msg(msg), m_line(0), m_logger(nullptr), m_proceed(false), m_dispatchAction(dispatchAction) { + } + + virtual ~Writer(void) { + processDispatch(); + } + + template + inline Writer& operator<<(const T& log) { +#if ELPP_LOGGING_ENABLED + if (m_proceed) { + m_messageBuilder << log; } - template - inline Writer& operator<<(const QPair& pair_) { - if (!proceed_) { return *this; } - _ELPP_STREAM(logger_) << "("; - operator << (static_cast(pair_.first)); - _ELPP_STREAM(logger_) << ", "; - operator << (static_cast(pair_.second)); - _ELPP_STREAM(logger_) << ")"; - return *this; +#endif // ELPP_LOGGING_ENABLED + return *this; + } + + inline Writer& operator<<(std::ostream& (*log)(std::ostream&)) { +#if ELPP_LOGGING_ENABLED + if (m_proceed) { + m_messageBuilder << log; } - template - inline Writer& operator<<(const QMap& map_) { - if (!proceed_) { return *this; } - _ELPP_STREAM(logger_) << "["; - QList keys = map_.keys(); - typename QList::const_iterator begin = keys.begin(); - typename QList::const_iterator end = keys.end(); - int max_ = static_cast(constants_->MAX_LOG_PER_CONTAINER); // to prevent warning - for (int index_ = 0; begin != end && index_ < max_; ++index_, ++begin) { - _ELPP_STREAM(logger_) << "("; - operator << (static_cast(*begin)); - _ELPP_STREAM(logger_) << ", "; - operator << (static_cast(map_.value(*begin))); - _ELPP_STREAM(logger_) << ")"; - _ELPP_STREAM(logger_) << ((index_ < keys.size() -1) ? ", " : ""); - } - if (begin != end) { - _ELPP_STREAM(logger_) << " ..."; +#endif // ELPP_LOGGING_ENABLED + return *this; + } + + inline operator bool() { + return true; + } + + Writer& construct(Logger* logger, bool needLock = true); + Writer& construct(int count, const char* loggerIds, ...); + protected: + LogMessage* m_msg; + Level m_level; + const char* m_file; + const base::type::LineNumber m_line; + const char* m_func; + base::type::VerboseLevel m_verboseLevel; + Logger* m_logger; + bool m_proceed; + base::MessageBuilder m_messageBuilder; + base::DispatchAction m_dispatchAction; + std::vector m_loggerIds; + friend class el::Helpers; + + void initializeLogger(const std::string& loggerId, bool lookup = true, bool needLock = true); + void processDispatch(); + void triggerDispatch(void); +}; +class PErrorWriter : public base::Writer { + public: + PErrorWriter(Level level, const char* file, base::type::LineNumber line, + const char* func, base::DispatchAction dispatchAction = base::DispatchAction::NormalLog, + base::type::VerboseLevel verboseLevel = 0) : + base::Writer(level, file, line, func, dispatchAction, verboseLevel) { + } + + virtual ~PErrorWriter(void); +}; +} // namespace base +// Logging from Logger class. Why this is here? Because we have Storage and Writer class available +#if ELPP_VARIADIC_TEMPLATES_SUPPORTED +template +void Logger::log_(Level level, int vlevel, const char* s, const T& value, const Args&... args) { + base::MessageBuilder b; + b.initialize(this); + while (*s) { + if (*s == base::consts::kFormatSpecifierChar) { + if (*(s + 1) == base::consts::kFormatSpecifierChar) { + ++s; + } else { + if (*(s + 1) == base::consts::kFormatSpecifierCharValue) { + ++s; + b << value; + log_(level, vlevel, ++s, args...); + return; } - _ELPP_STREAM(logger_) << "]"; - return *this; + } } - template - inline Writer& operator<<(const QMultiMap& map_) { - if (!proceed_) { return *this; } - operator << (static_cast >(map_)); - return *this; + b << *s++; + } + ELPP_INTERNAL_ERROR("Too many arguments provided. Unable to handle. Please provide more format specifiers", false); +} +template +void Logger::log_(Level level, int vlevel, const T& log) { + if (level == Level::Verbose) { + if (ELPP->vRegistry()->allowed(vlevel, __FILE__)) { + base::Writer(Level::Verbose, "FILE", 0, "FUNCTION", + base::DispatchAction::NormalLog, vlevel).construct(this, false) << log; + } else { + stream().str(ELPP_LITERAL("")); + releaseLock(); } - template - inline Writer& operator<<(const QHash& hash_) { - if (!proceed_) { return *this; } - _ELPP_STREAM(logger_) << "["; - QList keys = hash_.keys(); - typename QList::const_iterator begin = keys.begin(); - typename QList::const_iterator end = keys.end(); - int max_ = static_cast(constants_->MAX_LOG_PER_CONTAINER); // prevent type warning - for (int index_ = 0; begin != end && index_ < max_; ++index_, ++begin) { - _ELPP_STREAM(logger_) << "("; - operator << (static_cast(*begin)); - _ELPP_STREAM(logger_) << ", "; - operator << (static_cast(hash_.value(*begin))); - _ELPP_STREAM(logger_) << ")"; - _ELPP_STREAM(logger_) << ((index_ < keys.size() -1) ? ", " : ""); - } - if (begin != end) { - _ELPP_STREAM(logger_) << " ..."; + } else { + base::Writer(level, "FILE", 0, "FUNCTION").construct(this, false) << log; + } +} +template +inline void Logger::log(Level level, const char* s, const T& value, const Args&... args) { + acquireLock(); // released in Writer! + log_(level, 0, s, value, args...); +} +template +inline void Logger::log(Level level, const T& log) { + acquireLock(); // released in Writer! + log_(level, 0, log); +} +# if ELPP_VERBOSE_LOG +template +inline void Logger::verbose(int vlevel, const char* s, const T& value, const Args&... args) { + acquireLock(); // released in Writer! + log_(el::Level::Verbose, vlevel, s, value, args...); +} +template +inline void Logger::verbose(int vlevel, const T& log) { + acquireLock(); // released in Writer! + log_(el::Level::Verbose, vlevel, log); +} +# else +template +inline void Logger::verbose(int, const char*, const T&, const Args&...) { + return; +} +template +inline void Logger::verbose(int, const T&) { + return; +} +# endif // ELPP_VERBOSE_LOG +# define LOGGER_LEVEL_WRITERS(FUNCTION_NAME, LOG_LEVEL)\ +template \ +inline void Logger::FUNCTION_NAME(const char* s, const T& value, const Args&... args) {\ +log(LOG_LEVEL, s, value, args...);\ +}\ +template \ +inline void Logger::FUNCTION_NAME(const T& value) {\ +log(LOG_LEVEL, value);\ +} +# define LOGGER_LEVEL_WRITERS_DISABLED(FUNCTION_NAME, LOG_LEVEL)\ +template \ +inline void Logger::FUNCTION_NAME(const char*, const T&, const Args&...) {\ +return;\ +}\ +template \ +inline void Logger::FUNCTION_NAME(const T&) {\ +return;\ +} + +# if ELPP_INFO_LOG +LOGGER_LEVEL_WRITERS(info, Level::Info) +# else +LOGGER_LEVEL_WRITERS_DISABLED(info, Level::Info) +# endif // ELPP_INFO_LOG +# if ELPP_DEBUG_LOG +LOGGER_LEVEL_WRITERS(debug, Level::Debug) +# else +LOGGER_LEVEL_WRITERS_DISABLED(debug, Level::Debug) +# endif // ELPP_DEBUG_LOG +# if ELPP_WARNING_LOG +LOGGER_LEVEL_WRITERS(warn, Level::Warning) +# else +LOGGER_LEVEL_WRITERS_DISABLED(warn, Level::Warning) +# endif // ELPP_WARNING_LOG +# if ELPP_ERROR_LOG +LOGGER_LEVEL_WRITERS(error, Level::Error) +# else +LOGGER_LEVEL_WRITERS_DISABLED(error, Level::Error) +# endif // ELPP_ERROR_LOG +# if ELPP_FATAL_LOG +LOGGER_LEVEL_WRITERS(fatal, Level::Fatal) +# else +LOGGER_LEVEL_WRITERS_DISABLED(fatal, Level::Fatal) +# endif // ELPP_FATAL_LOG +# if ELPP_TRACE_LOG +LOGGER_LEVEL_WRITERS(trace, Level::Trace) +# else +LOGGER_LEVEL_WRITERS_DISABLED(trace, Level::Trace) +# endif // ELPP_TRACE_LOG +# undef LOGGER_LEVEL_WRITERS +# undef LOGGER_LEVEL_WRITERS_DISABLED +#endif // ELPP_VARIADIC_TEMPLATES_SUPPORTED +#if ELPP_COMPILER_MSVC +# define ELPP_VARIADIC_FUNC_MSVC(variadicFunction, variadicArgs) variadicFunction variadicArgs +# define ELPP_VARIADIC_FUNC_MSVC_RUN(variadicFunction, ...) ELPP_VARIADIC_FUNC_MSVC(variadicFunction, (__VA_ARGS__)) +# define el_getVALength(...) ELPP_VARIADIC_FUNC_MSVC_RUN(el_resolveVALength, 0, ## __VA_ARGS__,\ +10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) +#else +# if ELPP_COMPILER_CLANG +# define el_getVALength(...) el_resolveVALength(0, __VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) +# else +# define el_getVALength(...) el_resolveVALength(0, ## __VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) +# endif // ELPP_COMPILER_CLANG +#endif // ELPP_COMPILER_MSVC +#define el_resolveVALength(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N +#define ELPP_WRITE_LOG(writer, level, dispatchAction, ...) \ +writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__) +#define ELPP_WRITE_LOG_IF(writer, condition, level, dispatchAction, ...) if (condition) \ +writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__) +#define ELPP_WRITE_LOG_EVERY_N(writer, occasion, level, dispatchAction, ...) \ +ELPP->validateEveryNCounter(__FILE__, __LINE__, occasion) && \ +writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__) +#define ELPP_WRITE_LOG_AFTER_N(writer, n, level, dispatchAction, ...) \ +ELPP->validateAfterNCounter(__FILE__, __LINE__, n) && \ +writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__) +#define ELPP_WRITE_LOG_N_TIMES(writer, n, level, dispatchAction, ...) \ +ELPP->validateNTimesCounter(__FILE__, __LINE__, n) && \ +writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__) +#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING) +class PerformanceTrackingData { + public: + enum class DataType : base::type::EnumType { + Checkpoint = 1, Complete = 2 + }; + // Do not use constructor, will run into multiple definition error, use init(PerformanceTracker*) + explicit PerformanceTrackingData(DataType dataType) : m_performanceTracker(nullptr), + m_dataType(dataType), m_firstCheckpoint(false), m_file(""), m_line(0), m_func("") {} + inline const std::string* blockName(void) const; + inline const struct timeval* startTime(void) const; + inline const struct timeval* endTime(void) const; + inline const struct timeval* lastCheckpointTime(void) const; + inline const base::PerformanceTracker* performanceTracker(void) const { + return m_performanceTracker; + } + inline PerformanceTrackingData::DataType dataType(void) const { + return m_dataType; + } + inline bool firstCheckpoint(void) const { + return m_firstCheckpoint; + } + inline std::string checkpointId(void) const { + return m_checkpointId; + } + inline const char* file(void) const { + return m_file; + } + inline base::type::LineNumber line(void) const { + return m_line; + } + inline const char* func(void) const { + return m_func; + } + inline const base::type::string_t* formattedTimeTaken() const { + return &m_formattedTimeTaken; + } + inline const std::string& loggerId(void) const; + private: + base::PerformanceTracker* m_performanceTracker; + base::type::string_t m_formattedTimeTaken; + PerformanceTrackingData::DataType m_dataType; + bool m_firstCheckpoint; + std::string m_checkpointId; + const char* m_file; + base::type::LineNumber m_line; + const char* m_func; + inline void init(base::PerformanceTracker* performanceTracker, bool firstCheckpoint = false) { + m_performanceTracker = performanceTracker; + m_firstCheckpoint = firstCheckpoint; + } + + friend class el::base::PerformanceTracker; +}; +namespace base { +/// @brief Represents performanceTracker block of code that conditionally adds performance status to log +/// either when goes outside the scope of when checkpoint() is called +class PerformanceTracker : public base::threading::ThreadSafe, public Loggable { + public: + PerformanceTracker(const std::string& blockName, + base::TimestampUnit timestampUnit = base::TimestampUnit::Millisecond, + const std::string& loggerId = std::string(el::base::consts::kPerformanceLoggerId), + bool scopedLog = true, Level level = base::consts::kPerformanceTrackerDefaultLevel); + /// @brief Copy constructor + PerformanceTracker(const PerformanceTracker& t) : + m_blockName(t.m_blockName), m_timestampUnit(t.m_timestampUnit), m_loggerId(t.m_loggerId), m_scopedLog(t.m_scopedLog), + m_level(t.m_level), m_hasChecked(t.m_hasChecked), m_lastCheckpointId(t.m_lastCheckpointId), m_enabled(t.m_enabled), + m_startTime(t.m_startTime), m_endTime(t.m_endTime), m_lastCheckpointTime(t.m_lastCheckpointTime) { + } + virtual ~PerformanceTracker(void); + /// @brief A checkpoint for current performanceTracker block. + void checkpoint(const std::string& id = std::string(), const char* file = __FILE__, + base::type::LineNumber line = __LINE__, + const char* func = ""); + inline Level level(void) const { + return m_level; + } + private: + std::string m_blockName; + base::TimestampUnit m_timestampUnit; + std::string m_loggerId; + bool m_scopedLog; + Level m_level; + bool m_hasChecked; + std::string m_lastCheckpointId; + bool m_enabled; + struct timeval m_startTime, m_endTime, m_lastCheckpointTime; + + PerformanceTracker(void); + + friend class el::PerformanceTrackingData; + friend class base::DefaultPerformanceTrackingCallback; + + const inline base::type::string_t getFormattedTimeTaken() const { + return getFormattedTimeTaken(m_startTime); + } + + const base::type::string_t getFormattedTimeTaken(struct timeval startTime) const; + + virtual inline void log(el::base::type::ostream_t& os) const { + os << getFormattedTimeTaken(); + } +}; +class DefaultPerformanceTrackingCallback : public PerformanceTrackingCallback { + protected: + void handle(const PerformanceTrackingData* data) { + m_data = data; + base::type::stringstream_t ss; + if (m_data->dataType() == PerformanceTrackingData::DataType::Complete) { + ss << ELPP_LITERAL("Executed [") << m_data->blockName()->c_str() << ELPP_LITERAL("] in [") << + *m_data->formattedTimeTaken() << ELPP_LITERAL("]"); + } else { + ss << ELPP_LITERAL("Performance checkpoint"); + if (!m_data->checkpointId().empty()) { + ss << ELPP_LITERAL(" [") << m_data->checkpointId().c_str() << ELPP_LITERAL("]"); + } + ss << ELPP_LITERAL(" for block [") << m_data->blockName()->c_str() << ELPP_LITERAL("] : [") << + *m_data->performanceTracker(); + if (!ELPP->hasFlag(LoggingFlag::DisablePerformanceTrackingCheckpointComparison) + && m_data->performanceTracker()->m_hasChecked) { + ss << ELPP_LITERAL(" ([") << *m_data->formattedTimeTaken() << ELPP_LITERAL("] from "); + if (m_data->performanceTracker()->m_lastCheckpointId.empty()) { + ss << ELPP_LITERAL("last checkpoint"); + } else { + ss << ELPP_LITERAL("checkpoint '") << m_data->performanceTracker()->m_lastCheckpointId.c_str() << ELPP_LITERAL("'"); } - _ELPP_STREAM(logger_) << "]"; - return *this; + ss << ELPP_LITERAL(")]"); + } else { + ss << ELPP_LITERAL("]"); + } } - template - inline Writer& operator<<(const QMultiHash& multiHash_) { - if (!proceed_) { return *this; } - operator << (static_cast >(multiHash_)); - return *this; - } - template - inline Writer& operator<<(const QLinkedList& linkedList_) { - if (!proceed_) { return *this; } - return writeIterator(linkedList_.begin(), linkedList_.end(), linkedList_.size()); - } - template - inline Writer& operator<<(const QStack& stack_) { - if (!proceed_) { return *this; } - return writeIterator(stack_.begin(), stack_.end(), stack_.size()); - } -#endif // defined(QT_CORE_LIB) && defined(_ELPP_QT_LOGGING) - template - inline Writer& operator<<(const Class& class_) { - if (!proceed_) { return *this; } - _ELPP_STREAM(logger_) << class_; - return *this; - } - private: - unsigned int aspect_; - unsigned int severity_; - const char* func_; - const char* file_; - const unsigned long int line_; - bool condition_; - int verboseLevel_; - int counter_; - Logger* logger_; - std::stringstream tempss_; - std::string currLine_; - bool proceed_; - internal::Constants* constants_; - internal::threading::Mutex mutex_; - - friend class Logger; - - template - inline Writer& writeIterator(Iterator begin_, Iterator end_, std::size_t size_) { - _ELPP_STREAM(logger_) << "["; - for (std::size_t i = 0; begin_ != end_ && i < constants_->MAX_LOG_PER_CONTAINER; ++i, ++begin_) { - operator << (*begin_); - _ELPP_STREAM(logger_) << ((i < size_ - 1) ? ", " : ""); - } - if (begin_ != end_) { - _ELPP_STREAM(logger_) << " ..."; - } - _ELPP_STREAM(logger_) << "]"; - return *this; - } - - void buildAndWriteLine(void) { - internal::RegisteredLoggers* rl_ = registeredLoggers.pointer(); - TypedConfigurations* conf_ = logger_->typedConfigurations_; - unsigned int f_ = conf_->formatFlag(severity_); // format spec - currLine_ = conf_->logFormat(severity_); - std::string dateFormat = conf_->dateFormat(severity_); - std::string fs_; // format specifier - std::string v_; // value - // App name - if (f_ & constants_->kAppName) { - v_ = logger_->applicationName(); - fs_ = constants_->APP_NAME_FORMAT_SPECIFIER; - internal::utilities::LogManipulator::updateFormatValue(fs_, v_, currLine_, constants_); - } - // Logger ID - if (f_ & constants_->kLoggerId) { - v_ = logger_->id(); - fs_ = constants_->LOGGER_ID_FORMAT_SPECIFIER; - internal::utilities::LogManipulator::updateFormatValue(fs_, v_, currLine_, constants_); - } - // Thread ID - if (f_ & constants_->kThreadId) { - std::stringstream ss; - ss << threading::getCurrentThreadId(); - fs_ = constants_->THREAD_ID_FORMAT_SPECIFIER; - internal::utilities::LogManipulator::updateFormatValue(fs_, ss.str(), currLine_, constants_); - } - // Date/Time - if ((f_ & constants_->kDateOnly) || (f_ & constants_->kTimeOnly) || (f_ & constants_->kDateTime)) { - v_ = internal::utilities::DateUtils::getDateTime(dateFormat, - f_, constants_, conf_->millisecondsWidth(Level::All)); - fs_ = conf_->dateFormatSpecifier(severity_); - internal::utilities::LogManipulator::updateFormatValue(fs_, v_, currLine_, constants_); - } - // Function - if (f_ & constants_->kFunction) { - v_ = std::string(func_); - fs_ = constants_->FUNCTION_FORMAT_SPECIFIER; - internal::utilities::LogManipulator::updateFormatValue(fs_, v_, currLine_, constants_); - } - // Location - if (f_ & constants_->kLocation) { - tempss_ << file_ << ":" << line_; - fs_ = constants_->LOCATION_FORMAT_SPECIFIER; - internal::utilities::LogManipulator::updateFormatValue(fs_, tempss_.str(), currLine_, constants_); - tempss_.str(""); - } - // User - if (f_ & constants_->kUser) { - v_ = rl_->username(); - fs_ = constants_->USER_FORMAT_SPECIFIER; - internal::utilities::LogManipulator::updateFormatValue(fs_, v_, currLine_, constants_); - } - // Host - if (f_ & constants_->kHost) { - v_ = rl_->hostname(); - fs_ = constants_->HOST_FORMAT_SPECIFIER; - internal::utilities::LogManipulator::updateFormatValue(fs_, v_, currLine_, constants_); - } - // Verbose level - if ((severity_ == Level::Verbose) && (f_ & constants_->kVerboseLevel)) { - tempss_ << verboseLevel_; - fs_ = constants_->VERBOSE_LEVEL_FORMAT_SPECIFIER; - internal::utilities::LogManipulator::updateFormatValue(fs_, tempss_.str(), currLine_, constants_); - } - // Log message - if (f_ & constants_->kLogMessage) { - fs_ = constants_->LOG_MESSAGE_FORMAT_SPECIFIER; - internal::utilities::LogManipulator::updateFormatValue(fs_, logger_->stream()->str(), currLine_, constants_); - } - log(); - } - -#if (defined(_ELPP_STRICT_ROLLOUT)) - bool checkRollOuts(unsigned int level_, Logger* baseLogger_) { - unsigned int validLevel_ = 0; - std::string rolledOutFile = std::string(); - if (baseLogger_->typedConfigurations_->checkRollOuts(level_, validLevel_, rolledOutFile)) { - Logger* currLogger_ = NULL; - for (unsigned int i = 0; i < registeredLoggers->count(); ++i) { - currLogger_ = registeredLoggers->list().at(i); - if (currLogger_ == baseLogger_) - continue; - std::string fname = currLogger_->typedConfigurations_->filename(validLevel_); - if (fname == rolledOutFile) { - currLogger_->typedConfigurations_->forceReinitiateFile(validLevel_, fname); - } - } - return true; - } - return false; + el::base::Writer(m_data->performanceTracker()->level(), m_data->file(), m_data->line(), m_data->func()).construct(1, + m_data->loggerId().c_str()) << ss.str(); + } + private: + const PerformanceTrackingData* m_data; +}; +} // namespace base +inline const std::string* PerformanceTrackingData::blockName() const { + return const_cast(&m_performanceTracker->m_blockName); +} +inline const struct timeval* PerformanceTrackingData::startTime() const { + return const_cast(&m_performanceTracker->m_startTime); +} +inline const struct timeval* PerformanceTrackingData::endTime() const { + return const_cast(&m_performanceTracker->m_endTime); +} +inline const struct timeval* PerformanceTrackingData::lastCheckpointTime() const { + return const_cast(&m_performanceTracker->m_lastCheckpointTime); +} +inline const std::string& PerformanceTrackingData::loggerId(void) const { + return m_performanceTracker->m_loggerId; +} +#endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING) +namespace base { +/// @brief Contains some internal debugging tools like crash handler and stack tracer +namespace debug { +#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG) +class StackTrace : base::NoCopy { + public: + static const unsigned int kMaxStack = 64; + static const unsigned int kStackStart = 2; // We want to skip c'tor and StackTrace::generateNew() + class StackTraceEntry { + public: + StackTraceEntry(std::size_t index, const std::string& loc, const std::string& demang, const std::string& hex, + const std::string& addr); + StackTraceEntry(std::size_t index, const std::string& loc) : + m_index(index), + m_location(loc) { } -#endif // (defined(_ELPP_STRICT_ROLLOUT)) - - inline void syncWritePointer(unsigned int level_, Logger* targetLogger_, std::fstream* baseStream_) { - targetLogger_->acquireLock(); - targetLogger_->typedConfigurations_->fileStream(level_)->seekg(baseStream_->tellg()); - targetLogger_->releaseLock(); - } - - void safeWriteToFile(unsigned int level_, Logger* logger_, const std::string& line) { - std::string baseFilename_ = logger_->typedConfigurations_->filename(level_); - std::fstream* fstr = logger_->typedConfigurations_->fileStream(level_); - (*fstr) << line; - fstr->flush(); - Logger* currLogger_ = NULL; - for (std::size_t i = 0; i < registeredLoggers->count(); ++i) { - currLogger_ = registeredLoggers->list().at(i); - if (currLogger_ == logger_) - continue; - std::string fname = currLogger_->typedConfigurations_->filename(level_); - if (fname == baseFilename_) { - syncWritePointer(level_, currLogger_, fstr); - } - } - } - - void log(void) { - if (logger_->stream_) { - if (logger_->typedConfigurations_->toFile(severity_)) { - safeWriteToFile(severity_, logger_, currLine_); - } - if (logger_->typedConfigurations_->toStandardOutput(severity_)) { - std::cout << currLine_; - } - logger_->stream_->str(""); - } - } - }; - } // namespace internal - - class VersionInfo : private internal::StaticClass { - public: - // Minimal formatted displayable information - static inline const std::string formattedInfo(void) { - std::stringstream ss; - ss << "EasyLogging++ v" << version() << " (" << releaseDate() << ")"; - ss << std::endl; - ss << website(); - ss << std::endl; - ss << copyright(); - return ss.str(); - } - - // Current version number - static inline const std::string version(void) { return std::string("8.91"); } - - // Release date of current version - static inline const std::string releaseDate(void) { return std::string("12-07-2013 1243hrs"); } - - // Original author and maintainer - static inline const std::string author(void) { return std::string("Majid Khan "); } - - // Web link - static inline const std::string website(void) { return std::string("http://icplusplus.com/tools/easylogging"); } - - // Link to source code - static inline const std::string sourceCodeLink(void) { return std::string("https://github.com/mkhan3189/EasyLoggingPP"); } - - // Copyright information - static inline const std::string copyright(void) { return std::string("Copyright (c) 2012 - 2013 Majid Khan"); } - - // Full licence - static const std::string licence(void) { - std::stringstream ss; - ss << " This software is provided 'as-is', without any express or implied" << std::endl; - ss << " warranty. In no event will the authors be held liable for any damages" << std::endl; - ss << " arising from the use of this software." << std::endl; - ss << std::endl; - ss << " Permission is granted to anyone to use this software for any purpose," << std::endl; - ss << " including commercial applications, and to alter it and redistribute" << std::endl; - ss << " it freely, subject to the following restrictions:" << std::endl; - ss << std::endl; - ss << " 1. The origin of this software must not be misrepresented; you must" << std::endl; - ss << " not claim that you wrote the original software. If you use this" << std::endl; - ss << " software in a product, an acknowledgment in the product documentation" << std::endl; - ss << " would be appreciated but is not required." << std::endl; - ss << std::endl; - ss << " 2. Altered source versions must be plainly marked as such, and must" << std::endl; - ss << " not be misrepresented as being the original software." << std::endl; - ss << std::endl; - ss << " 3. This notice may not be removed or altered from any source" << std::endl; - ss << " distribution"; - return ss.str(); - } - }; // class VersionInfo - -//! -//! \brief Helper class to manage loggers and configurations -//! -//! A static helper class for users of library. This class contains functions related to register -//! and configure logger/s -//! - class Loggers : private internal::StaticClass { - public: - - //! - //! Get existing logger, if logger does not exist a newly created logger is returned - //! \param identifier_ A unique ID for logger - //! \return Pointer to easyloggingpp::Logger from logger repository - //! - static inline Logger* getLogger(const std::string& identifier_) { - return internal::registeredLoggers->get(identifier_); - } - - //! - //! Reconfigures logger with easyloggingpp::Configurations - //! \param logger_ Pointer to Logger to configure. You get use getLogger() to get pointer from logger repository - //! \param configurations_ easyloggingpp::Configurations to configure logger against - //! \return Updated pointer to Logger - //! - static inline Logger* reconfigureLogger(Logger* logger_, const Configurations& configurations_) { - if (!logger_) return NULL; - logger_->configure(configurations_); - return logger_; - } - - //! - //! Reconfigures logger with easyloggingpp::Configurations - //! \param identifier_ Logger ID - //! \param configurations_ easyloggingpp::Configurations to configure logger against - //! \return Updated pointer to Logger - //! - static inline Logger* reconfigureLogger(const std::string& identifier_, Configurations& configurations_) { - Logger* logger_ = Loggers::getLogger(identifier_); - Loggers::reconfigureLogger(logger_, configurations_); - return logger_; - } - - //! - //! Reconfigures all loggers available in logger repository - //! \param configurations_ easyloggingpp::Configurations to configure logger against - //! - static inline void reconfigureAllLoggers(Configurations& configurations_) { - for (std::size_t i = 0; i < internal::registeredLoggers->count(); ++i) { - Logger* l = internal::registeredLoggers->at(i); - Loggers::reconfigureLogger(l, configurations_); - } - } - - //! - //! Reconfigures all loggers for single configuration. - //! \param configurationType_ Configuration type to update. Use easyloggingpp::ConfigurationType to prevent confusion - //! \param value_ Value to set. Values have to be std::string; For boolean values use "true", "false", for any integral values - //! use them in quotes. They will be parsed when configuring - //! - static inline void reconfigureAllLoggers(unsigned int configurationType_, const std::string& value_) { - for (std::size_t i = 0; i < internal::registeredLoggers->count(); ++i) { - Logger* l = internal::registeredLoggers->at(i); - l->configurations().setAll(configurationType_, value_); - l->reconfigure(); - } - } - - //! - //! Sets default configurations. This configuration is used for future loggers. - //! \param configurations - //! \param configureExistingLoggers If true, all loggers are updated against provided configuration otherwise only future loggers - //! will be updated and all the existing loggers will use configurations that have been set previously. - //! - static inline void setDefaultConfigurations(Configurations& configurations, bool configureExistingLoggers = false) { - internal::registeredLoggers->setDefaultConfigurations(configurations); - if (configureExistingLoggers) { - Loggers::reconfigureAllLoggers(configurations); - } - } - - //! - //! Sets application arguments and uses them where needed. Example use is when application is run with '--v=X' or '-v', verbose logging - //! turns on - //! \param argc Argument count - //! \param argv Argument value array pointer - //! - static inline void setApplicationArguments(int argc, char** argv) { - internal::registeredLoggers->setApplicationArguments(argc, argv); - } - - //! - //! Sets application arguments and uses them where needed. Example use is when application is run with '--v=X' or '-v', verbose logging - //! turns on - //! \param argc - //! \param argv - //! - static inline void setApplicationArguments(int argc, const char** argv) { - internal::registeredLoggers->setApplicationArguments(argc, argv); - } - - //! - //! Disables all loggers - //! - static inline void disableAll(void) { - reconfigureAllLoggers(ConfigurationType::Enabled, "false"); - } - - //! - //! Enable all loggers - //! - static inline void enableAll(void) { - reconfigureAllLoggers(ConfigurationType::Enabled, "true"); - } - - //! - //! Reconfigure all loggers to write to single log file - //! \param logFilename_ Full path to log file - //! - static inline void setFilename(const std::string& logFilename_) { - reconfigureAllLoggers(ConfigurationType::Filename, logFilename_); - } - - //! - //! Reconfigure specified logger to write to specified log file - //! \param logger_ Pointer to logger. You may use Loggers::get(id) to get pointer - //! \param logFilename_ Full path to log file - //! - static inline void setFilename(Logger* logger_, const std::string& logFilename_) { - if (!logger_) return; - logger_->configurations().setAll(ConfigurationType::Filename, logFilename_); - logger_->reconfigure(); - } + std::size_t m_index; + std::string m_location; + std::string m_demangled; + std::string m_hex; + std::string m_addr; + friend std::ostream& operator<<(std::ostream& ss, const StackTraceEntry& si); - //! - //! Determines whether or not performance tracking is enabled - //! \return True if enabled, false otherwise - //! - static inline bool performanceTrackingEnabled(void) { - return performanceLogger()->typedConfigurations_->performanceTracking(); - } - - //! - //! Disables performance tracking. - //! Performance tracking is logged using 'performance' logger. - //! - static inline void disablePerformanceTracking(void) { - Logger* l = Loggers::performanceLogger(); - l->configurations().setAll(ConfigurationType::PerformanceTracking, "false"); - l->reconfigure(); - } + private: + StackTraceEntry(void); + }; - //! - //! Enable performance tracking - //! Performance tracking is logged using 'performance' logger. - //! - static inline void enablePerformanceTracking(void) { - Logger* l = Loggers::performanceLogger(); - l->configurations().setAll(ConfigurationType::PerformanceTracking, "true"); - l->reconfigure(); - } + StackTrace(void) { + generateNew(); + } - //! - //! Iterates through logger repository and puts IDs into listOfIds - //! \param listOfIds (Passed by reference) Vector to fill up - //! - static inline void getAllLogIdentifiers(std::vector& listOfIds) { - listOfIds.clear(); - for (std::size_t i = 0; i < internal::registeredLoggers->count(); ++i) { - listOfIds.push_back(internal::registeredLoggers->at(i)->id()); - } - } + virtual ~StackTrace(void) { + } - //! - //! \return Returns one of default loggers 'trivial' logger - //! - static inline Logger* trivialLogger(void) { - return Loggers::getLogger("trivial"); - } + inline std::vector& getLatestStack(void) { + return m_stack; + } - //! - //! \return Returns one of default loggers 'business' logger - //! - static inline Logger* businessLogger(void) { - return Loggers::getLogger("business"); - } + friend std::ostream& operator<<(std::ostream& os, const StackTrace& st); - //! - //! \return Returns one of default loggers 'security' logger - //! - static inline Logger* securityLogger(void) { - return Loggers::getLogger("security"); - } + private: + std::vector m_stack; - //! - //! \return Returns one of default loggers 'performance' logger - //! - static inline Logger* performanceLogger(void) { - return Loggers::getLogger("performance"); - } + void generateNew(void); +}; +/// @brief Handles unexpected crashes +class CrashHandler : base::NoCopy { + public: + typedef void (*Handler)(int); + + explicit CrashHandler(bool useDefault); + explicit CrashHandler(const Handler& cHandler) { + setHandler(cHandler); + } + void setHandler(const Handler& cHandler); + + private: + Handler m_handler; +}; +#else +class CrashHandler { + public: + explicit CrashHandler(bool) {} +}; +#endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG) +} // namespace debug +} // namespace base +extern base::debug::CrashHandler elCrashHandler; +#define MAKE_LOGGABLE(ClassType, ClassInstance, OutputStreamInstance) \ +el::base::type::ostream_t& operator<<(el::base::type::ostream_t& OutputStreamInstance, const ClassType& ClassInstance) +/// @brief Initializes syslog with process ID, options and facility. calls closelog() on d'tor +class SysLogInitializer { + public: + SysLogInitializer(const char* processIdent, int options = 0, int facility = 0) { +#if defined(ELPP_SYSLOG) + openlog(processIdent, options, facility); +#else + ELPP_UNUSED(processIdent); + ELPP_UNUSED(options); + ELPP_UNUSED(facility); +#endif // defined(ELPP_SYSLOG) + } + virtual ~SysLogInitializer(void) { +#if defined(ELPP_SYSLOG) + closelog(); +#endif // defined(ELPP_SYSLOG) + } +}; +#define ELPP_INITIALIZE_SYSLOG(id, opt, fac) el::SysLogInitializer elSyslogInit(id, opt, fac) +/// @brief Static helpers for developers +class Helpers : base::StaticClass { + public: + /// @brief Shares logging repository (base::Storage) + static inline void setStorage(base::type::StoragePointer storage) { + ELPP = storage; + } + /// @return Main storage repository + static inline base::type::StoragePointer storage() { + return ELPP; + } + /// @brief Sets application arguments and figures out whats active for logging and whats not. + static inline void setArgs(int argc, char** argv) { + ELPP->setApplicationArguments(argc, argv); + } + /// @copydoc setArgs(int argc, char** argv) + static inline void setArgs(int argc, const char** argv) { + ELPP->setApplicationArguments(argc, const_cast(argv)); + } + /// @brief Sets thread name for current thread. Requires std::thread + static inline void setThreadName(const std::string& name) { + ELPP->setThreadName(name); + } + static inline std::string getThreadName() { + return ELPP->getThreadName(base::threading::getCurrentThreadId()); + } +#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG) + /// @brief Overrides default crash handler and installs custom handler. + /// @param crashHandler A functor with no return type that takes single int argument. + /// Handler is a typedef with specification: void (*Handler)(int) + static inline void setCrashHandler(const el::base::debug::CrashHandler::Handler& crashHandler) { + el::elCrashHandler.setHandler(crashHandler); + } + /// @brief Abort due to crash with signal in parameter + /// @param sig Crash signal + static void crashAbort(int sig, const char* sourceFile = "", unsigned int long line = 0); + /// @brief Logs reason of crash as per sig + /// @param sig Crash signal + /// @param stackTraceIfAvailable Includes stack trace if available + /// @param level Logging level + /// @param logger Logger to use for logging + static void logCrashReason(int sig, bool stackTraceIfAvailable = false, + Level level = Level::Fatal, const char* logger = base::consts::kDefaultLoggerId); +#endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG) + /// @brief Installs pre rollout callback, this callback is triggered when log file is about to be rolled out + /// (can be useful for backing up) + static inline void installPreRollOutCallback(const PreRollOutCallback& callback) { + ELPP->setPreRollOutCallback(callback); + } + /// @brief Uninstalls pre rollout callback + static inline void uninstallPreRollOutCallback(void) { + ELPP->unsetPreRollOutCallback(); + } + /// @brief Installs post log dispatch callback, this callback is triggered when log is dispatched + template + static inline bool installLogDispatchCallback(const std::string& id) { + return ELPP->installLogDispatchCallback(id); + } + /// @brief Uninstalls log dispatch callback + template + static inline void uninstallLogDispatchCallback(const std::string& id) { + ELPP->uninstallLogDispatchCallback(id); + } + template + static inline T* logDispatchCallback(const std::string& id) { + return ELPP->logDispatchCallback(id); + } +#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING) + /// @brief Installs post performance tracking callback, this callback is triggered when performance tracking is finished + template + static inline bool installPerformanceTrackingCallback(const std::string& id) { + return ELPP->installPerformanceTrackingCallback(id); + } + /// @brief Uninstalls post performance tracking handler + template + static inline void uninstallPerformanceTrackingCallback(const std::string& id) { + ELPP->uninstallPerformanceTrackingCallback(id); + } + template + static inline T* performanceTrackingCallback(const std::string& id) { + return ELPP->performanceTrackingCallback(id); + } +#endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING) + /// @brief Converts template to std::string - useful for loggable classes to log containers within log(std::ostream&) const + template + static std::string convertTemplateToStdString(const T& templ) { + el::Logger* logger = + ELPP->registeredLoggers()->get(el::base::consts::kDefaultLoggerId); + if (logger == nullptr) { + return std::string(); + } + base::MessageBuilder b; + b.initialize(logger); + logger->acquireLock(); + b << templ; +#if defined(ELPP_UNICODE) + std::string s = std::string(logger->stream().str().begin(), logger->stream().str().end()); +#else + std::string s = logger->stream().str(); +#endif // defined(ELPP_UNICODE) + logger->stream().str(ELPP_LITERAL("")); + logger->releaseLock(); + return s; + } + /// @brief Returns command line arguments (pointer) provided to easylogging++ + static inline const el::base::utils::CommandLineArgs* commandLineArgs(void) { + return ELPP->commandLineArgs(); + } + /// @brief Reserve space for custom format specifiers for performance + /// @see std::vector::reserve + static inline void reserveCustomFormatSpecifiers(std::size_t size) { + ELPP->m_customFormatSpecifiers.reserve(size); + } + /// @brief Installs user defined format specifier and handler + static inline void installCustomFormatSpecifier(const CustomFormatSpecifier& customFormatSpecifier) { + ELPP->installCustomFormatSpecifier(customFormatSpecifier); + } + /// @brief Uninstalls user defined format specifier and handler + static inline bool uninstallCustomFormatSpecifier(const char* formatSpecifier) { + return ELPP->uninstallCustomFormatSpecifier(formatSpecifier); + } + /// @brief Returns true if custom format specifier is installed + static inline bool hasCustomFormatSpecifier(const char* formatSpecifier) { + return ELPP->hasCustomFormatSpecifier(formatSpecifier); + } + static inline void validateFileRolling(Logger* logger, Level level) { + if (logger == nullptr) return; + logger->m_typedConfigurations->validateFileRolling(level, ELPP->preRollOutCallback()); + } +}; +/// @brief Static helpers to deal with loggers and their configurations +class Loggers : base::StaticClass { + public: + /// @brief Gets existing or registers new logger + static Logger* getLogger(const std::string& identity, bool registerIfNotAvailable = true); + /// @brief Changes default log builder for future loggers + static void setDefaultLogBuilder(el::LogBuilderPtr& logBuilderPtr); + /// @brief Installs logger registration callback, this callback is triggered when new logger is registered + template + static inline bool installLoggerRegistrationCallback(const std::string& id) { + return ELPP->registeredLoggers()->installLoggerRegistrationCallback(id); + } + /// @brief Uninstalls log dispatch callback + template + static inline void uninstallLoggerRegistrationCallback(const std::string& id) { + ELPP->registeredLoggers()->uninstallLoggerRegistrationCallback(id); + } + template + static inline T* loggerRegistrationCallback(const std::string& id) { + return ELPP->registeredLoggers()->loggerRegistrationCallback(id); + } + /// @brief Unregisters logger - use it only when you know what you are doing, you may unregister + /// loggers initialized / used by third-party libs. + static bool unregisterLogger(const std::string& identity); + /// @brief Whether or not logger with id is registered + static bool hasLogger(const std::string& identity); + /// @brief Reconfigures specified logger with new configurations + static Logger* reconfigureLogger(Logger* logger, const Configurations& configurations); + /// @brief Reconfigures logger with new configurations after looking it up using identity + static Logger* reconfigureLogger(const std::string& identity, const Configurations& configurations); + /// @brief Reconfigures logger's single configuration + static Logger* reconfigureLogger(const std::string& identity, ConfigurationType configurationType, + const std::string& value); + /// @brief Reconfigures all the existing loggers with new configurations + static void reconfigureAllLoggers(const Configurations& configurations); + /// @brief Reconfigures single configuration for all the loggers + static inline void reconfigureAllLoggers(ConfigurationType configurationType, const std::string& value) { + reconfigureAllLoggers(Level::Global, configurationType, value); + } + /// @brief Reconfigures single configuration for all the loggers for specified level + static void reconfigureAllLoggers(Level level, ConfigurationType configurationType, + const std::string& value); + /// @brief Sets default configurations. This configuration is used for future (and conditionally for existing) loggers + static void setDefaultConfigurations(const Configurations& configurations, + bool reconfigureExistingLoggers = false); + /// @brief Returns current default + static const Configurations* defaultConfigurations(void); + /// @brief Returns log stream reference pointer if needed by user + static const base::LogStreamsReferenceMap* logStreamsReference(void); + /// @brief Default typed configuration based on existing defaultConf + static base::TypedConfigurations defaultTypedConfigurations(void); + /// @brief Populates all logger IDs in current repository. + /// @param [out] targetList List of fill up. + static std::vector* populateAllLoggerIds(std::vector* targetList); + /// @brief Sets configurations from global configuration file. + static void configureFromGlobal(const char* globalConfigurationFilePath); + /// @brief Configures loggers using command line arg. Ensure you have already set command line args, + /// @return False if invalid argument or argument with no value provided, true if attempted to configure logger. + /// If true is returned that does not mean it has been configured successfully, it only means that it + /// has attempeted to configure logger using configuration file provided in argument + static bool configureFromArg(const char* argKey); + /// @brief Flushes all loggers for all levels - Be careful if you dont know how many loggers are registered + static void flushAll(void); + /// @brief Adds logging flag used internally. + static inline void addFlag(LoggingFlag flag) { + ELPP->addFlag(flag); + } + /// @brief Removes logging flag used internally. + static inline void removeFlag(LoggingFlag flag) { + ELPP->removeFlag(flag); + } + /// @brief Determines whether or not certain flag is active + static inline bool hasFlag(LoggingFlag flag) { + return ELPP->hasFlag(flag); + } + /// @brief Adds flag and removes it when scope goes out + class ScopedAddFlag { + public: + ScopedAddFlag(LoggingFlag flag) : m_flag(flag) { + Loggers::addFlag(m_flag); + } + ~ScopedAddFlag(void) { + Loggers::removeFlag(m_flag); + } + private: + LoggingFlag m_flag; + }; + /// @brief Removes flag and add it when scope goes out + class ScopedRemoveFlag { + public: + ScopedRemoveFlag(LoggingFlag flag) : m_flag(flag) { + Loggers::removeFlag(m_flag); + } + ~ScopedRemoveFlag(void) { + Loggers::addFlag(m_flag); + } + private: + LoggingFlag m_flag; + }; + /// @brief Sets hierarchy for logging. Needs to enable logging flag (HierarchicalLogging) + static void setLoggingLevel(Level level) { + ELPP->setLoggingLevel(level); + } + /// @brief Sets verbose level on the fly + static void setVerboseLevel(base::type::VerboseLevel level); + /// @brief Gets current verbose level + static base::type::VerboseLevel verboseLevel(void); + /// @brief Sets vmodules as specified (on the fly) + static void setVModules(const char* modules); + /// @brief Clears vmodules + static void clearVModules(void); +}; +class VersionInfo : base::StaticClass { + public: + /// @brief Current version number + static const std::string version(void); - //! - //! Static class that contains static helper functions used to read configurations - //! - class ConfigurationsReader : private internal::StaticClass { - public: - static inline bool enabled(Logger* logger_, unsigned int level_ = Level::All) { - __EASYLOGGINGPP_ASSERT(logger_ != NULL, "Invalid Logger provided - nullptr"); - return constConf(logger_)->enabled(level_); - } - - static inline bool enabled(internal::TypedConfigurations* conf_, unsigned int level_ = Level::All) { - __EASYLOGGINGPP_ASSERT(conf_ != NULL, "Invalid TypedConfigurations provided - nullptr"); - return conf_->enabled(level_); - } - - static inline bool toFile(Logger* logger_, unsigned int level_ = Level::All) { - __EASYLOGGINGPP_ASSERT(logger_ != NULL, "Invalid Logger provided - nullptr"); - return constConf(logger_)->toFile(level_); - } - - static inline bool toFile(internal::TypedConfigurations* conf_, unsigned int level_ = Level::All) { - __EASYLOGGINGPP_ASSERT(conf_ != NULL, "Invalid TypedConfigurations provided - nullptr"); - return conf_->toFile(level_); - } - - static inline const std::string& filename(Logger* logger_, unsigned int level_ = Level::All) { - __EASYLOGGINGPP_ASSERT(logger_ != NULL, "Invalid Logger provided - nullptr"); - return constConf(logger_)->filename(level_); - } - - static inline const std::string& filename(internal::TypedConfigurations* conf_, unsigned int level_ = Level::All) { - __EASYLOGGINGPP_ASSERT(conf_ != NULL, "Invalid TypedConfigurations provided - nullptr"); - return conf_->filename(level_); - } - - static inline bool toStandardOutput(Logger* logger_, unsigned int level_ = Level::All) { - __EASYLOGGINGPP_ASSERT(logger_ != NULL, "Invalid Logger provided - nullptr"); - return constConf(logger_)->toStandardOutput(level_); - } - - static inline bool toStandardOutput(internal::TypedConfigurations* conf_, unsigned int level_ = Level::All) { - __EASYLOGGINGPP_ASSERT(conf_ != NULL, "Invalid TypedConfigurations provided - nullptr"); - return conf_->toStandardOutput(level_); - } - - static inline const std::string& logFormat(Logger* logger_, unsigned int level_ = Level::All) { - __EASYLOGGINGPP_ASSERT(logger_ != NULL, "Invalid Logger provided - nullptr"); - return constConf(logger_)->logFormat(level_); - } - - static inline const std::string& logFormat(internal::TypedConfigurations* conf_, unsigned int level_ = Level::All) { - __EASYLOGGINGPP_ASSERT(conf_ != NULL, "Invalid TypedConfigurations provided - nullptr"); - return conf_->logFormat(level_); - } - - static inline int millisecondsWidth(Logger* logger_, unsigned int level_ = Level::All) { - __EASYLOGGINGPP_ASSERT(logger_ != NULL, "Invalid Logger provided - nullptr"); - return constConf(logger_)->millisecondsWidth(level_); - } - - static inline int millisecondsWidth(internal::TypedConfigurations* conf_, unsigned int level_ = Level::All) { - __EASYLOGGINGPP_ASSERT(conf_ != NULL, "Invalid TypedConfigurations provided - nullptr"); - return conf_->millisecondsWidth(level_); - } - - static inline bool performanceTracking(Logger* logger_, unsigned int level_ = Level::All) { - __EASYLOGGINGPP_ASSERT(logger_ != NULL, "Invalid Logger provided - nullptr"); - return constConf(logger_)->performanceTracking(level_); - } - - static inline bool performanceTracking(internal::TypedConfigurations* conf_, unsigned int level_ = Level::All) { - __EASYLOGGINGPP_ASSERT(conf_ != NULL, "Invalid TypedConfigurations provided - nullptr"); - return conf_->performanceTracking(level_); - } - - static inline std::size_t logRollOutSize(Logger* logger_, unsigned int level_ = Level::All) { - __EASYLOGGINGPP_ASSERT(logger_ != NULL, "Invalid Logger provided - nullptr"); - return constConf(logger_)->rollOutSize(level_); - } - - static inline std::size_t logRollOutSize(internal::TypedConfigurations* conf_, unsigned int level_ = Level::All) { - __EASYLOGGINGPP_ASSERT(conf_ != NULL, "Invalid TypedConfigurations provided - nullptr"); - return conf_->rollOutSize(level_); - } - - private: - static inline internal::TypedConfigurations* constConf(Logger* logger_) { - return logger_->typedConfigurations_; - } - }; // class ConfigurationsReader - private: - internal::threading::Mutex mutex_; - }; -// -// Helping Macros -// -// Performance tracking macros -#if ((!defined(_DISABLE_PERFORMANCE_TRACKING)) || (!defined(_DISABLE_INFO_LOGS))) -# if _ELPP_OS_UNIX -# define _ELPP_GET_CURR_TIME(tm) gettimeofday(tm, NULL); -# elif _ELPP_OS_WINDOWS -# define _ELPP_GET_CURR_TIME(tm) easyloggingpp::internal::utilities::DateUtils::gettimeofday(tm); -# endif -# define START_FUNCTION_LOG "Executing [" << __func__ << "]" -# define TIME_OUTPUT "Executed [" << __func__ << "] in [" << \ - easyloggingpp::internal::utilities::DateUtils::formatMilliSeconds( \ - easyloggingpp::internal::utilities::DateUtils::getTimeDifference(functionEndTime, functionStartTime)) << "]" -# define FUNC_SUB_COMMON_START { timeval functionStartTime, functionEndTime; _ELPP_GET_CURR_TIME(&functionStartTime) -# define WRITE_FUNC_PERFORMANCE _ELPP_GET_CURR_TIME(&functionEndTime); \ - if (easyloggingpp::Loggers::performanceTrackingEnabled()) { PINFO << TIME_OUTPUT; } -# define FUNC_SUB_COMMON_END WRITE_FUNC_PERFORMANCE; -# define SUB(FUNCTION_NAME,PARAMS) void FUNCTION_NAME PARAMS FUNC_SUB_COMMON_START -# define END_SUB FUNC_SUB_COMMON_END } -# define FUNC(RETURNING_TYPE,FUNCTION_NAME,PARAMS) RETURNING_TYPE FUNCTION_NAME PARAMS FUNC_SUB_COMMON_START -# define RETURN(return_value) FUNC_SUB_COMMON_END return return_value; -# define END_FUNC(return_value) RETURN(return_value) } -# define MAIN(argc, argv) FUNC(int, main, (argc, argv)) -# define END_MAIN(return_value) FUNC_SUB_COMMON_END; return return_value; } -# define RETURN_MAIN(exit_status) return exit_status; -#else -# define SUB(FUNCTION_NAME,PARAMS) void FUNCTION_NAME PARAMS { -# define END_SUB } -# define FUNC(RETURNING_TYPE,FUNCTION_NAME,PARAMS) RETURNING_TYPE FUNCTION_NAME PARAMS { -# define END_FUNC(x) return x; } -# define RETURN(expr) return expr; -# define MAIN(argc, argv) FUNC(int, main, (argc, argv)) -# define END_MAIN(x) return x; } -# define RETURN_MAIN(exit_status) return exit_status; -#endif // ((!defined(_DISABLE_PERFORMANCE_TRACKING)) || (!defined(_DISABLE_INFO_LOGS))) - -#define _ELPP_LOG_WRITER(_logger, _level) easyloggingpp::internal::Writer(\ - _logger, easyloggingpp::internal::Aspect::Normal, _level, __func__, __FILE__, __LINE__) -#define _ELPP_LOG_WRITER_COND(_c, _logger, _level) if (_c) easyloggingpp::internal::Writer(\ - _logger, easyloggingpp::internal::Aspect::Conditional, _level, __func__, __FILE__, __LINE__, _c) -#define _ELPP_LOG_WRITER_N(_n, _logger, _level) if (easyloggingpp::internal::registeredLoggers->validateCounter(\ - __FILE__, __LINE__, _n)) easyloggingpp::internal::Writer(_logger, easyloggingpp::internal::Aspect::Interval,\ - _level, __func__, __FILE__, __LINE__, true, 0, _n) + /// @brief Release date of current version + static const std::string releaseDate(void); +}; +} // namespace el #undef VLOG_IS_ON -#define VLOG_IS_ON(verboseLevel) verboseLevel <= easyloggingpp::internal::registeredLoggers->constants()->CURRENT_VERBOSE_LEVEL +/// @brief Determines whether verbose logging is on for specified level current file. +#define VLOG_IS_ON(verboseLevel) (ELPP->vRegistry()->allowed(verboseLevel, __FILE__)) +#undef TIMED_BLOCK +#undef TIMED_SCOPE +#undef TIMED_SCOPE_IF +#undef TIMED_FUNC +#undef TIMED_FUNC_IF +#undef ELPP_MIN_UNIT +#if defined(ELPP_PERFORMANCE_MICROSECONDS) +# define ELPP_MIN_UNIT el::base::TimestampUnit::Microsecond +#else +# define ELPP_MIN_UNIT el::base::TimestampUnit::Millisecond +#endif // (defined(ELPP_PERFORMANCE_MICROSECONDS)) +/// @brief Performance tracked scope. Performance gets written when goes out of scope using +/// 'performance' logger. +/// +/// @detail Please note in order to check the performance at a certain time you can use obj->checkpoint(); +/// @see el::base::PerformanceTracker +/// @see el::base::PerformanceTracker::checkpoint +// Note: Do not surround this definition with null macro because of obj instance +#define TIMED_SCOPE_IF(obj, blockname, condition) el::base::type::PerformanceTrackerPtr obj( condition ? \ + new el::base::PerformanceTracker(blockname, ELPP_MIN_UNIT) : nullptr ) +#define TIMED_SCOPE(obj, blockname) TIMED_SCOPE_IF(obj, blockname, true) +#define TIMED_BLOCK(obj, blockName) for (struct { int i; el::base::type::PerformanceTrackerPtr timer; } obj = { 0, \ + el::base::type::PerformanceTrackerPtr(new el::base::PerformanceTracker(blockName, ELPP_MIN_UNIT)) }; obj.i < 1; ++obj.i) +/// @brief Performance tracked function. Performance gets written when goes out of scope using +/// 'performance' logger. +/// +/// @detail Please note in order to check the performance at a certain time you can use obj->checkpoint(); +/// @see el::base::PerformanceTracker +/// @see el::base::PerformanceTracker::checkpoint +#define TIMED_FUNC_IF(obj,condition) TIMED_SCOPE_IF(obj, ELPP_FUNC, condition) +#define TIMED_FUNC(obj) TIMED_SCOPE(obj, ELPP_FUNC) +#undef PERFORMANCE_CHECKPOINT +#undef PERFORMANCE_CHECKPOINT_WITH_ID +#define PERFORMANCE_CHECKPOINT(obj) obj->checkpoint(std::string(), __FILE__, __LINE__, ELPP_FUNC) +#define PERFORMANCE_CHECKPOINT_WITH_ID(obj, id) obj->checkpoint(id, __FILE__, __LINE__, ELPP_FUNC) +#undef ELPP_COUNTER +#undef ELPP_COUNTER_POS +/// @brief Gets hit counter for file/line +#define ELPP_COUNTER (ELPP->hitCounters()->getCounter(__FILE__, __LINE__)) +/// @brief Gets hit counter position for file/line, -1 if not registered yet +#define ELPP_COUNTER_POS (ELPP_COUNTER == nullptr ? -1 : ELPP_COUNTER->hitCounts()) // Undef levels to support LOG(LEVEL) #undef INFO +#undef WARNING #undef DEBUG #undef ERROR #undef FATAL -#undef QA #undef TRACE #undef VERBOSE -// -// Custom loggers - macro names with levels - requires loggerId -// // Undef existing #undef CINFO #undef CWARNING #undef CDEBUG -#undef CERROR #undef CFATAL -#undef ERROR -#undef CQA +#undef CERROR #undef CTRACE #undef CVERBOSE #undef CINFO_IF @@ -3558,8 +3953,6 @@ class IterableStack : public IterableContainer, public std::stack< #undef CDEBUG_IF #undef CERROR_IF #undef CFATAL_IF -#undef ERROR_IF -#undef CQA_IF #undef CTRACE_IF #undef CVERBOSE_IF #undef CINFO_EVERY_N @@ -3567,139 +3960,233 @@ class IterableStack : public IterableContainer, public std::stack< #undef CDEBUG_EVERY_N #undef CERROR_EVERY_N #undef CFATAL_EVERY_N -#undef ERROR_EVERY_N -#undef CQA_EVERY_N #undef CTRACE_EVERY_N #undef CVERBOSE_EVERY_N +#undef CINFO_AFTER_N +#undef CWARNING_AFTER_N +#undef CDEBUG_AFTER_N +#undef CERROR_AFTER_N +#undef CFATAL_AFTER_N +#undef CTRACE_AFTER_N +#undef CVERBOSE_AFTER_N +#undef CINFO_N_TIMES +#undef CWARNING_N_TIMES +#undef CDEBUG_N_TIMES +#undef CERROR_N_TIMES +#undef CFATAL_N_TIMES +#undef CTRACE_N_TIMES +#undef CVERBOSE_N_TIMES // Normal logs -#if _ELPP_INFO_LOG -# define CINFO(loggerId) _ELPP_LOG_WRITER(loggerId, easyloggingpp::Level::Info) -#else -# define CINFO(loggerId) easyloggingpp::internal::NullWriter() -#endif // _ELPP_INFO_LOG -#if _ELPP_WARNING_LOG -# define CWARNING(loggerId) _ELPP_LOG_WRITER(loggerId, easyloggingpp::Level::Warning) -#else -# define CWARNING(loggerId) easyloggingpp::internal::NullWriter() -#endif // _ELPP_WARNING_LOG -#if _ELPP_DEBUG_LOG -# define CDEBUG(loggerId) _ELPP_LOG_WRITER(loggerId, easyloggingpp::Level::Debug) -#else -# define CDEBUG(loggerId) easyloggingpp::internal::NullWriter() -#endif // _ELPP_DEBUG_LOG -#if _ELPP_ERROR_LOG -# define CERROR(loggerId) _ELPP_LOG_WRITER(loggerId, easyloggingpp::Level::Error) -#else -# define CERROR(loggerId) easyloggingpp::internal::NullWriter() -#endif // _ELPP_ERROR_LOG -#if _ELPP_FATAL_LOG -# define CFATAL(loggerId) _ELPP_LOG_WRITER(loggerId, easyloggingpp::Level::Fatal) -#else -# define CFATAL(loggerId) easyloggingpp::internal::NullWriter() -#endif // _ELPP_FATAL_LOG -#if _ELPP_QA_LOG -# define CQA(loggerId) _ELPP_LOG_WRITER(loggerId, easyloggingpp::Level::QA) -#else -# define CQA(loggerId) easyloggingpp::internal::NullWriter() -#endif // _ELPP_QA_LOG -#if _ELPP_TRACE_LOG -# define CTRACE(loggerId) _ELPP_LOG_WRITER(loggerId, easyloggingpp::Level::Trace) -#else -# define CTRACE(loggerId) easyloggingpp::internal::NullWriter() -#endif // _ELPP_TRACE_LOG -#if _ELPP_VERBOSE_LOG -# define CVERBOSE(vlevel_, loggerId) easyloggingpp::internal::Writer(loggerId, easyloggingpp::internal::Aspect::Normal, \ - easyloggingpp::Level::Verbose, __func__, __FILE__, __LINE__, true, vlevel_) -#else -# define CVERBOSE(vlevel_, loggerId) easyloggingpp::internal::NullWriter() -#endif // _ELPP_VERBOSE_LOG +#if ELPP_INFO_LOG +# define CINFO(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Info, dispatchAction, __VA_ARGS__) +#else +# define CINFO(writer, dispatchAction, ...) el::base::NullWriter() +#endif // ELPP_INFO_LOG +#if ELPP_WARNING_LOG +# define CWARNING(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Warning, dispatchAction, __VA_ARGS__) +#else +# define CWARNING(writer, dispatchAction, ...) el::base::NullWriter() +#endif // ELPP_WARNING_LOG +#if ELPP_DEBUG_LOG +# define CDEBUG(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Debug, dispatchAction, __VA_ARGS__) +#else +# define CDEBUG(writer, dispatchAction, ...) el::base::NullWriter() +#endif // ELPP_DEBUG_LOG +#if ELPP_ERROR_LOG +# define CERROR(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Error, dispatchAction, __VA_ARGS__) +#else +# define CERROR(writer, dispatchAction, ...) el::base::NullWriter() +#endif // ELPP_ERROR_LOG +#if ELPP_FATAL_LOG +# define CFATAL(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Fatal, dispatchAction, __VA_ARGS__) +#else +# define CFATAL(writer, dispatchAction, ...) el::base::NullWriter() +#endif // ELPP_FATAL_LOG +#if ELPP_TRACE_LOG +# define CTRACE(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Trace, dispatchAction, __VA_ARGS__) +#else +# define CTRACE(writer, dispatchAction, ...) el::base::NullWriter() +#endif // ELPP_TRACE_LOG +#if ELPP_VERBOSE_LOG +# define CVERBOSE(writer, vlevel, dispatchAction, ...) if (VLOG_IS_ON(vlevel)) writer(\ +el::Level::Verbose, __FILE__, __LINE__, ELPP_FUNC, dispatchAction, vlevel).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__) +#else +# define CVERBOSE(writer, vlevel, dispatchAction, ...) el::base::NullWriter() +#endif // ELPP_VERBOSE_LOG // Conditional logs -#if _ELPP_INFO_LOG -# define CINFO_IF(condition_, loggerId) _ELPP_LOG_WRITER_COND(condition_, loggerId, easyloggingpp::Level::Info) -#else -# define CINFO_IF(condition_, loggerId) easyloggingpp::internal::NullWriter() -#endif // _ELPP_INFO_LOG -#if _ELPP_WARNING_LOG -# define CWARNING_IF(condition_, loggerId) _ELPP_LOG_WRITER_COND(condition_, loggerId, easyloggingpp::Level::Warning) -#else -# define CWARNING_IF(condition_, loggerId) easyloggingpp::internal::NullWriter() -#endif // _ELPP_WARNING_LOG -#if _ELPP_DEBUG_LOG -# define CDEBUG_IF(condition_, loggerId) _ELPP_LOG_WRITER_COND(condition_, loggerId, easyloggingpp::Level::Debug) -#else -# define CDEBUG_IF(condition_, loggerId) easyloggingpp::internal::NullWriter() -#endif // _ELPP_DEBUG_LOG -#if _ELPP_ERROR_LOG -# define CERROR_IF(condition_, loggerId) _ELPP_LOG_WRITER_COND(condition_, loggerId, easyloggingpp::Level::Error) -#else -# define CERROR_IF(condition_, loggerId) easyloggingpp::internal::NullWriter() -#endif // _ELPP_ERROR_LOG -#if _ELPP_FATAL_LOG -# define CFATAL_IF(condition_, loggerId) _ELPP_LOG_WRITER_COND(condition_, loggerId, easyloggingpp::Level::Fatal) -#else -# define CFATAL_IF(condition_, loggerId) easyloggingpp::internal::NullWriter() -#endif // _ELPP_FATAL_LOG -#if _ELPP_QA_LOG -# define CQA_IF(condition_, loggerId) _ELPP_LOG_WRITER_COND(condition_, loggerId, easyloggingpp::Level::QA) -#else -# define CQA_IF(condition_, loggerId) easyloggingpp::internal::NullWriter() -#endif // _ELPP_QA_LOG -#if _ELPP_TRACE_LOG -# define CTRACE_IF(condition_, loggerId) _ELPP_LOG_WRITER_COND(condition_, loggerId, easyloggingpp::Level::Trace) -#else -# define CTRACE_IF(condition_, loggerId) easyloggingpp::internal::NullWriter() -#endif // _ELPP_TRACE_LOG -#if _ELPP_VERBOSE_LOG -# define CVERBOSE_IF(condition_, vlevel_, loggerId) if (condition_) easyloggingpp::internal::Writer(loggerId, easyloggingpp::internal::Aspect::Conditional, \ - easyloggingpp::Level::Verbose, __func__, __FILE__, __LINE__, condition_, vlevel_) -#else -# define CVERBOSE_IF(condition_, vlevel_, loggerId) easyloggingpp::internal::NullWriter() -#endif // _ELPP_VERBOSE_LOG -// Interval logs -#if _ELPP_INFO_LOG -# define CINFO_EVERY_N(interval_, loggerId) _ELPP_LOG_WRITER_N(interval_, loggerId, easyloggingpp::Level::Info) -#else -# define CINFO_EVERY_N(interval_, loggerId) easyloggingpp::internal::NullWriter() -#endif // _ELPP_INFO_LOG -#if _ELPP_WARNING_LOG -# define CWARNING_EVERY_N(interval_, loggerId) _ELPP_LOG_WRITER_N(interval_, loggerId, easyloggingpp::Level::Warning) -#else -# define CWARNING_EVERY_N(interval_, loggerId) easyloggingpp::internal::NullWriter() -#endif // _ELPP_WARNING_LOG -#if _ELPP_DEBUG_LOG -# define CDEBUG_EVERY_N(interval_, loggerId) _ELPP_LOG_WRITER_N(interval_, loggerId, easyloggingpp::Level::Debug) -#else -# define CDEBUG_EVERY_N(interval_, loggerId) easyloggingpp::internal::NullWriter() -#endif // _ELPP_DEBUG_LOG -#if _ELPP_ERROR_LOG -# define CERROR_EVERY_N(interval_, loggerId) _ELPP_LOG_WRITER_N(interval_, loggerId, easyloggingpp::Level::Error) -#else -# define CERROR_EVERY_N(interval_, loggerId) easyloggingpp::internal::NullWriter() -#endif // _ELPP_ERROR_LOG -#if _ELPP_FATAL_LOG -# define CFATAL_EVERY_N(interval_, loggerId) _ELPP_LOG_WRITER_N(interval_, loggerId, easyloggingpp::Level::Fatal) -#else -# define CFATAL_EVERY_N(interval_, loggerId) easyloggingpp::internal::NullWriter() -#endif // _ELPP_FATAL_LOG -#if _ELPP_QA_LOG -# define CQA_EVERY_N(interval_, loggerId) _ELPP_LOG_WRITER_N(interval_, loggerId, easyloggingpp::Level::QA) -#else -# define CQA_EVERY_N(interval_, loggerId) easyloggingpp::internal::NullWriter() -#endif // _ELPP_QA_LOG -#if _ELPP_TRACE_LOG -# define CTRACE_EVERY_N(interval_, loggerId) _ELPP_LOG_WRITER_N(interval_, loggerId, easyloggingpp::Level::Trace) -#else -# define CTRACE_EVERY_N(interval_, loggerId) easyloggingpp::internal::NullWriter() -#endif // _ELPP_TRACE_LOG -#if _ELPP_VERBOSE_LOG -# define CVERBOSE_EVERY_N(interval_, vlevel_, loggerId) if (easyloggingpp::internal::registeredLoggers->validateCounter(__FILE__, __LINE__, interval_)) \ - easyloggingpp::internal::Writer(loggerId, easyloggingpp::internal::Aspect::Interval, \ - easyloggingpp::Level::Verbose, __func__, __FILE__, __LINE__, true, vlevel_, interval_) -#else -# define CVERBOSE_EVERY_N(interval_, vlevel_, loggerId) easyloggingpp::internal::NullWriter() -#endif // _ELPP_VERBOSE_LOG +#if ELPP_INFO_LOG +# define CINFO_IF(writer, condition_, dispatchAction, ...) \ +ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Info, dispatchAction, __VA_ARGS__) +#else +# define CINFO_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter() +#endif // ELPP_INFO_LOG +#if ELPP_WARNING_LOG +# define CWARNING_IF(writer, condition_, dispatchAction, ...)\ +ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Warning, dispatchAction, __VA_ARGS__) +#else +# define CWARNING_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter() +#endif // ELPP_WARNING_LOG +#if ELPP_DEBUG_LOG +# define CDEBUG_IF(writer, condition_, dispatchAction, ...)\ +ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Debug, dispatchAction, __VA_ARGS__) +#else +# define CDEBUG_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter() +#endif // ELPP_DEBUG_LOG +#if ELPP_ERROR_LOG +# define CERROR_IF(writer, condition_, dispatchAction, ...)\ +ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Error, dispatchAction, __VA_ARGS__) +#else +# define CERROR_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter() +#endif // ELPP_ERROR_LOG +#if ELPP_FATAL_LOG +# define CFATAL_IF(writer, condition_, dispatchAction, ...)\ +ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Fatal, dispatchAction, __VA_ARGS__) +#else +# define CFATAL_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter() +#endif // ELPP_FATAL_LOG +#if ELPP_TRACE_LOG +# define CTRACE_IF(writer, condition_, dispatchAction, ...)\ +ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Trace, dispatchAction, __VA_ARGS__) +#else +# define CTRACE_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter() +#endif // ELPP_TRACE_LOG +#if ELPP_VERBOSE_LOG +# define CVERBOSE_IF(writer, condition_, vlevel, dispatchAction, ...) if (VLOG_IS_ON(vlevel) && (condition_)) writer( \ +el::Level::Verbose, __FILE__, __LINE__, ELPP_FUNC, dispatchAction, vlevel).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__) +#else +# define CVERBOSE_IF(writer, condition_, vlevel, dispatchAction, ...) el::base::NullWriter() +#endif // ELPP_VERBOSE_LOG +// Occasional logs +#if ELPP_INFO_LOG +# define CINFO_EVERY_N(writer, occasion, dispatchAction, ...)\ +ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Info, dispatchAction, __VA_ARGS__) +#else +# define CINFO_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter() +#endif // ELPP_INFO_LOG +#if ELPP_WARNING_LOG +# define CWARNING_EVERY_N(writer, occasion, dispatchAction, ...)\ +ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Warning, dispatchAction, __VA_ARGS__) +#else +# define CWARNING_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter() +#endif // ELPP_WARNING_LOG +#if ELPP_DEBUG_LOG +# define CDEBUG_EVERY_N(writer, occasion, dispatchAction, ...)\ +ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Debug, dispatchAction, __VA_ARGS__) +#else +# define CDEBUG_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter() +#endif // ELPP_DEBUG_LOG +#if ELPP_ERROR_LOG +# define CERROR_EVERY_N(writer, occasion, dispatchAction, ...)\ +ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Error, dispatchAction, __VA_ARGS__) +#else +# define CERROR_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter() +#endif // ELPP_ERROR_LOG +#if ELPP_FATAL_LOG +# define CFATAL_EVERY_N(writer, occasion, dispatchAction, ...)\ +ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Fatal, dispatchAction, __VA_ARGS__) +#else +# define CFATAL_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter() +#endif // ELPP_FATAL_LOG +#if ELPP_TRACE_LOG +# define CTRACE_EVERY_N(writer, occasion, dispatchAction, ...)\ +ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Trace, dispatchAction, __VA_ARGS__) +#else +# define CTRACE_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter() +#endif // ELPP_TRACE_LOG +#if ELPP_VERBOSE_LOG +# define CVERBOSE_EVERY_N(writer, occasion, vlevel, dispatchAction, ...)\ +CVERBOSE_IF(writer, ELPP->validateEveryNCounter(__FILE__, __LINE__, occasion), vlevel, dispatchAction, __VA_ARGS__) +#else +# define CVERBOSE_EVERY_N(writer, occasion, vlevel, dispatchAction, ...) el::base::NullWriter() +#endif // ELPP_VERBOSE_LOG +// After N logs +#if ELPP_INFO_LOG +# define CINFO_AFTER_N(writer, n, dispatchAction, ...)\ +ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Info, dispatchAction, __VA_ARGS__) +#else +# define CINFO_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter() +#endif // ELPP_INFO_LOG +#if ELPP_WARNING_LOG +# define CWARNING_AFTER_N(writer, n, dispatchAction, ...)\ +ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Warning, dispatchAction, __VA_ARGS__) +#else +# define CWARNING_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter() +#endif // ELPP_WARNING_LOG +#if ELPP_DEBUG_LOG +# define CDEBUG_AFTER_N(writer, n, dispatchAction, ...)\ +ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Debug, dispatchAction, __VA_ARGS__) +#else +# define CDEBUG_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter() +#endif // ELPP_DEBUG_LOG +#if ELPP_ERROR_LOG +# define CERROR_AFTER_N(writer, n, dispatchAction, ...)\ +ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Error, dispatchAction, __VA_ARGS__) +#else +# define CERROR_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter() +#endif // ELPP_ERROR_LOG +#if ELPP_FATAL_LOG +# define CFATAL_AFTER_N(writer, n, dispatchAction, ...)\ +ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Fatal, dispatchAction, __VA_ARGS__) +#else +# define CFATAL_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter() +#endif // ELPP_FATAL_LOG +#if ELPP_TRACE_LOG +# define CTRACE_AFTER_N(writer, n, dispatchAction, ...)\ +ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Trace, dispatchAction, __VA_ARGS__) +#else +# define CTRACE_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter() +#endif // ELPP_TRACE_LOG +#if ELPP_VERBOSE_LOG +# define CVERBOSE_AFTER_N(writer, n, vlevel, dispatchAction, ...)\ +CVERBOSE_IF(writer, ELPP->validateAfterNCounter(__FILE__, __LINE__, n), vlevel, dispatchAction, __VA_ARGS__) +#else +# define CVERBOSE_AFTER_N(writer, n, vlevel, dispatchAction, ...) el::base::NullWriter() +#endif // ELPP_VERBOSE_LOG +// N Times logs +#if ELPP_INFO_LOG +# define CINFO_N_TIMES(writer, n, dispatchAction, ...)\ +ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Info, dispatchAction, __VA_ARGS__) +#else +# define CINFO_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter() +#endif // ELPP_INFO_LOG +#if ELPP_WARNING_LOG +# define CWARNING_N_TIMES(writer, n, dispatchAction, ...)\ +ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Warning, dispatchAction, __VA_ARGS__) +#else +# define CWARNING_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter() +#endif // ELPP_WARNING_LOG +#if ELPP_DEBUG_LOG +# define CDEBUG_N_TIMES(writer, n, dispatchAction, ...)\ +ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Debug, dispatchAction, __VA_ARGS__) +#else +# define CDEBUG_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter() +#endif // ELPP_DEBUG_LOG +#if ELPP_ERROR_LOG +# define CERROR_N_TIMES(writer, n, dispatchAction, ...)\ +ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Error, dispatchAction, __VA_ARGS__) +#else +# define CERROR_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter() +#endif // ELPP_ERROR_LOG +#if ELPP_FATAL_LOG +# define CFATAL_N_TIMES(writer, n, dispatchAction, ...)\ +ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Fatal, dispatchAction, __VA_ARGS__) +#else +# define CFATAL_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter() +#endif // ELPP_FATAL_LOG +#if ELPP_TRACE_LOG +# define CTRACE_N_TIMES(writer, n, dispatchAction, ...)\ +ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Trace, dispatchAction, __VA_ARGS__) +#else +# define CTRACE_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter() +#endif // ELPP_TRACE_LOG +#if ELPP_VERBOSE_LOG +# define CVERBOSE_N_TIMES(writer, n, vlevel, dispatchAction, ...)\ +CVERBOSE_IF(writer, ELPP->validateNTimesCounter(__FILE__, __LINE__, n), vlevel, dispatchAction, __VA_ARGS__) +#else +# define CVERBOSE_N_TIMES(writer, n, vlevel, dispatchAction, ...) el::base::NullWriter() +#endif // ELPP_VERBOSE_LOG // -// Custom Loggers - Requires (level, loggerId) +// Custom Loggers - Requires (level, dispatchAction, loggerId/s) // // undef existing #undef CLOG @@ -3709,294 +4196,365 @@ class IterableStack : public IterableContainer, public std::stack< #undef CLOG_VERBOSE_IF #undef CVLOG_IF #undef CLOG_EVERY_N -#undef CLOG_VERBOSE_EVERY_N #undef CVLOG_EVERY_N +#undef CLOG_AFTER_N +#undef CVLOG_AFTER_N +#undef CLOG_N_TIMES +#undef CVLOG_N_TIMES // Normal logs -#define CLOG(LEVEL, loggerId) C##LEVEL(loggerId) -#define CLOG_VERBOSE(vlevel, loggerId) CVERBOSE(vlevel, loggerId) -#define CVLOG(vlevel, loggerId) CVERBOSE(vlevel, loggerId) +#define CLOG(LEVEL, ...)\ +C##LEVEL(el::base::Writer, el::base::DispatchAction::NormalLog, __VA_ARGS__) +#define CVLOG(vlevel, ...) CVERBOSE(el::base::Writer, vlevel, el::base::DispatchAction::NormalLog, __VA_ARGS__) // Conditional logs -#define CLOG_IF(condition, LEVEL, loggerId) C##LEVEL##_IF(condition, loggerId) -#define CLOG_VERBOSE_IF(condition, vlevel, loggerId) CVERBOSE_IF(condition, vlevel, loggerId) -#define CVLOG_IF(condition, vlevel, loggerId) CVERBOSE_IF(condition, vlevel, loggerId) -// Interval logs -#define CLOG_EVERY_N(n, LEVEL, loggerId) C##LEVEL##_EVERY_N(n, loggerId) -#define CLOG_VERBOSE_EVERY_N(n, vlevel, loggerId) CVERBOSE_EVERY_N(n, vlevel, loggerId) -#define CVLOG_EVERY_N(n, vlevel, loggerId) CVERBOSE_EVERY_N(n, vlevel, loggerId) +#define CLOG_IF(condition, LEVEL, ...)\ +C##LEVEL##_IF(el::base::Writer, condition, el::base::DispatchAction::NormalLog, __VA_ARGS__) +#define CVLOG_IF(condition, vlevel, ...)\ +CVERBOSE_IF(el::base::Writer, condition, vlevel, el::base::DispatchAction::NormalLog, __VA_ARGS__) +// Hit counts based logs +#define CLOG_EVERY_N(n, LEVEL, ...)\ +C##LEVEL##_EVERY_N(el::base::Writer, n, el::base::DispatchAction::NormalLog, __VA_ARGS__) +#define CVLOG_EVERY_N(n, vlevel, ...)\ +CVERBOSE_EVERY_N(el::base::Writer, n, vlevel, el::base::DispatchAction::NormalLog, __VA_ARGS__) +#define CLOG_AFTER_N(n, LEVEL, ...)\ +C##LEVEL##_AFTER_N(el::base::Writer, n, el::base::DispatchAction::NormalLog, __VA_ARGS__) +#define CVLOG_AFTER_N(n, vlevel, ...)\ +CVERBOSE_AFTER_N(el::base::Writer, n, vlevel, el::base::DispatchAction::NormalLog, __VA_ARGS__) +#define CLOG_N_TIMES(n, LEVEL, ...)\ +C##LEVEL##_N_TIMES(el::base::Writer, n, el::base::DispatchAction::NormalLog, __VA_ARGS__) +#define CVLOG_N_TIMES(n, vlevel, ...)\ +CVERBOSE_N_TIMES(el::base::Writer, n, vlevel, el::base::DispatchAction::NormalLog, __VA_ARGS__) // // Default Loggers macro using CLOG(), CLOG_VERBOSE() and CVLOG() macros // // undef existing #undef LOG -#undef LOG_VERBOSE #undef VLOG #undef LOG_IF -#undef LOG_VERBOSE_IF #undef VLOG_IF #undef LOG_EVERY_N -#undef LOG_VERBOSE_EVERY_N #undef VLOG_EVERY_N +#undef LOG_AFTER_N +#undef VLOG_AFTER_N +#undef LOG_N_TIMES +#undef VLOG_N_TIMES +#undef ELPP_CURR_FILE_LOGGER_ID +#if defined(ELPP_DEFAULT_LOGGER) +# define ELPP_CURR_FILE_LOGGER_ID ELPP_DEFAULT_LOGGER +#else +# define ELPP_CURR_FILE_LOGGER_ID el::base::consts::kDefaultLoggerId +#endif +#undef ELPP_TRACE +#define ELPP_TRACE CLOG(TRACE, ELPP_CURR_FILE_LOGGER_ID) // Normal logs -#define LOG(LEVEL) CLOG(LEVEL, "trivial") -#define LOG_VERBOSE(vlevel) CLOG_VERBOSE(vlevel, "trivial") -#define VLOG(vlevel) CVLOG(vlevel, "trivial") -// Conditional logs -#define LOG_IF(condition, LEVEL) CLOG_IF(condition, LEVEL, "trivial") -#define LOG_VERBOSE_IF(condition, vlevel) CLOG_VERBOSE_IF(condition, vlevel, "trivial") -#define VLOG_IF(condition, vlevel) CVLOG_IF(condition, vlevel, "trivial") -// Interval logs -#define LOG_EVERY_N(n, LEVEL) CLOG_EVERY_N(n, LEVEL, "trivial") -#define LOG_VERBOSE_EVERY_N(n, vlevel) CLOG_VERBOSE_EVERY_N(n, vlevel, "trivial") -#define VLOG_EVERY_N(n, vlevel) CVLOG_EVERY_N(n, vlevel, "trivial") -// -// Default Loggers macro using C##LEVEL("trivial") -// -// undef existing -#undef LINFO -#undef LWARNING -#undef LDEBUG -#undef LERROR -#undef LFATAL -#undef LQA -#undef LTRACE -#undef LVERBOSE -#undef LINFO_IF -#undef LWARNING_IF -#undef LDEBUG_IF -#undef LERROR_IF -#undef LFATAL_IF -#undef LQA_IF -#undef LTRACE_IF -#undef LVERBOSE_IF -#undef LINFO_EVERY_N -#undef LWARNING_EVERY_N -#undef LDEBUG_EVERY_N -#undef LERROR_EVERY_N -#undef LFATAL_EVERY_N -#undef LQA_EVERY_N -#undef LTRACE_EVERY_N -#undef LVERBOSE_EVERY_N -// Normal logs -#define LINFO CINFO("trivial") -#define LWARNING CWARNING("trivial") -#define LDEBUG CDEBUG("trivial") -#define LERROR CERROR("trivial") -#define LFATAL CFATAL("trivial") -#define LQA CQA("trivial") -#define LTRACE CTRACE("trivial") -#define LVERBOSE(level) CVERBOSE(level, "trivial") -// Conditional logs -#define LINFO_IF(condition) CINFO_IF(condition, "trivial") -#define LWARNING_IF(condition) CWARNING_IF(condition, "trivial") -#define LDEBUG_IF(condition) CDEBUG_IF(condition, "trivial") -#define LERROR_IF(condition) CERROR_IF(condition, "trivial") -#define LFATAL_IF(condition) CFATAL_IF(condition, "trivial") -#define LQA_IF(condition) CQA_IF(condition, "trivial") -#define LTRACE_IF(condition) CTRACE_IF(condition, "trivial") -#define LVERBOSE_IF(condition, level) CVERBOSE_IF(condition, level, "trivial") -// Interval logs -#define LINFO_EVERY_N(n) CINFO_EVERY_N(n, "trivial") -#define LWARNING_EVERY_N(n) CWARNING_EVERY_N(n, "trivial") -#define LDEBUG_EVERY_N(n) CDEBUG_EVERY_N(n, "trivial") -#define LERROR_EVERY_N(n) CERROR_EVERY_N(n, "trivial") -#define LFATAL_EVERY_N(n) CFATAL_EVERY_N(n, "trivial") -#define LQA_EVERY_N(n) CQA_EVERY_N(n, "trivial") -#define LTRACE_EVERY_N(n) CTRACE_EVERY_N(n, "trivial") -#define LVERBOSE_EVERY_N(n, level) CVERBOSE_EVERY_N(n, level, "trivial") -// -// Default Loggers macro using C##LEVEL("business") -// -// undef existing -#undef BINFO -#undef BWARNING -#undef BDEBUG -#undef BERROR -#undef BFATAL -#undef BQA -#undef BTRACE -#undef BVERBOSE -#undef BINFO_IF -#undef BWARNING_IF -#undef BDEBUG_IF -#undef BERROR_IF -#undef BFATAL_IF -#undef BQA_IF -#undef BTRACE_IF -#undef BVERBOSE_IF -#undef BINFO_EVERY_N -#undef BWARNING_EVERY_N -#undef BDEBUG_EVERY_N -#undef BERROR_EVERY_N -#undef BFATAL_EVERY_N -#undef BQA_EVERY_N -#undef BTRACE_EVERY_N -#undef BVERBOSE_EVERY_N -// Normal logs -#define BINFO CINFO("business") -#define BWARNING CWARNING("business") -#define BDEBUG CDEBUG("business") -#define BERROR CERROR("business") -#define BFATAL CFATAL("business") -#define BQA CQA("business") -#define BTRACE CTRACE("business") -#define BVERBOSE(level) CVERBOSE(level, "business") +#define LOG(LEVEL) CLOG(LEVEL, ELPP_CURR_FILE_LOGGER_ID) +#define VLOG(vlevel) CVLOG(vlevel, ELPP_CURR_FILE_LOGGER_ID) // Conditional logs -#define BINFO_IF(condition) CINFO_IF(condition, "business") -#define BWARNING_IF(condition) CWARNING_IF(condition, "business") -#define BDEBUG_IF(condition) CDEBUG_IF(condition, "business") -#define BERROR_IF(condition) CERROR_IF(condition, "business") -#define BFATAL_IF(condition) CFATAL_IF(condition, "business") -#define BQA_IF(condition) CQA_IF(condition, "business") -#define BTRACE_IF(condition) CTRACE_IF(condition, "business") -#define BVERBOSE_IF(condition, level) CVERBOSE_IF(condition, level, "business") -// Interval logs -#define BINFO_EVERY_N(n) CINFO_EVERY_N(n, "business") -#define BWARNING_EVERY_N(n) CWARNING_EVERY_N(n, "business") -#define BDEBUG_EVERY_N(n) CDEBUG_EVERY_N(n, "business") -#define BERROR_EVERY_N(n) CERROR_EVERY_N(n, "business") -#define BFATAL_EVERY_N(n) CFATAL_EVERY_N(n, "business") -#define BQA_EVERY_N(n) CQA_EVERY_N(n, "business") -#define BTRACE_EVERY_N(n) CTRACE_EVERY_N(n, "business") -#define BVERBOSE_EVERY_N(n, level) CVERBOSE_EVERY_N(n, level, "business") +#define LOG_IF(condition, LEVEL) CLOG_IF(condition, LEVEL, ELPP_CURR_FILE_LOGGER_ID) +#define VLOG_IF(condition, vlevel) CVLOG_IF(condition, vlevel, ELPP_CURR_FILE_LOGGER_ID) +// Hit counts based logs +#define LOG_EVERY_N(n, LEVEL) CLOG_EVERY_N(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID) +#define VLOG_EVERY_N(n, vlevel) CVLOG_EVERY_N(n, vlevel, ELPP_CURR_FILE_LOGGER_ID) +#define LOG_AFTER_N(n, LEVEL) CLOG_AFTER_N(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID) +#define VLOG_AFTER_N(n, vlevel) CVLOG_AFTER_N(n, vlevel, ELPP_CURR_FILE_LOGGER_ID) +#define LOG_N_TIMES(n, LEVEL) CLOG_N_TIMES(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID) +#define VLOG_N_TIMES(n, vlevel) CVLOG_N_TIMES(n, vlevel, ELPP_CURR_FILE_LOGGER_ID) +// Generic PLOG() +#undef CPLOG +#undef CPLOG_IF +#undef PLOG +#undef PLOG_IF +#undef DCPLOG +#undef DCPLOG_IF +#undef DPLOG +#undef DPLOG_IF +#define CPLOG(LEVEL, ...)\ +C##LEVEL(el::base::PErrorWriter, el::base::DispatchAction::NormalLog, __VA_ARGS__) +#define CPLOG_IF(condition, LEVEL, ...)\ +C##LEVEL##_IF(el::base::PErrorWriter, condition, el::base::DispatchAction::NormalLog, __VA_ARGS__) +#define DCPLOG(LEVEL, ...)\ +if (ELPP_DEBUG_LOG) C##LEVEL(el::base::PErrorWriter, el::base::DispatchAction::NormalLog, __VA_ARGS__) +#define DCPLOG_IF(condition, LEVEL, ...)\ +C##LEVEL##_IF(el::base::PErrorWriter, (ELPP_DEBUG_LOG) && (condition), el::base::DispatchAction::NormalLog, __VA_ARGS__) +#define PLOG(LEVEL) CPLOG(LEVEL, ELPP_CURR_FILE_LOGGER_ID) +#define PLOG_IF(condition, LEVEL) CPLOG_IF(condition, LEVEL, ELPP_CURR_FILE_LOGGER_ID) +#define DPLOG(LEVEL) DCPLOG(LEVEL, ELPP_CURR_FILE_LOGGER_ID) +#define DPLOG_IF(condition, LEVEL) DCPLOG_IF(condition, LEVEL, ELPP_CURR_FILE_LOGGER_ID) +// Generic SYSLOG() +#undef CSYSLOG +#undef CSYSLOG_IF +#undef CSYSLOG_EVERY_N +#undef CSYSLOG_AFTER_N +#undef CSYSLOG_N_TIMES +#undef SYSLOG +#undef SYSLOG_IF +#undef SYSLOG_EVERY_N +#undef SYSLOG_AFTER_N +#undef SYSLOG_N_TIMES +#undef DCSYSLOG +#undef DCSYSLOG_IF +#undef DCSYSLOG_EVERY_N +#undef DCSYSLOG_AFTER_N +#undef DCSYSLOG_N_TIMES +#undef DSYSLOG +#undef DSYSLOG_IF +#undef DSYSLOG_EVERY_N +#undef DSYSLOG_AFTER_N +#undef DSYSLOG_N_TIMES +#if defined(ELPP_SYSLOG) +# define CSYSLOG(LEVEL, ...)\ +C##LEVEL(el::base::Writer, el::base::DispatchAction::SysLog, __VA_ARGS__) +# define CSYSLOG_IF(condition, LEVEL, ...)\ +C##LEVEL##_IF(el::base::Writer, condition, el::base::DispatchAction::SysLog, __VA_ARGS__) +# define CSYSLOG_EVERY_N(n, LEVEL, ...) C##LEVEL##_EVERY_N(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__) +# define CSYSLOG_AFTER_N(n, LEVEL, ...) C##LEVEL##_AFTER_N(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__) +# define CSYSLOG_N_TIMES(n, LEVEL, ...) C##LEVEL##_N_TIMES(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__) +# define SYSLOG(LEVEL) CSYSLOG(LEVEL, el::base::consts::kSysLogLoggerId) +# define SYSLOG_IF(condition, LEVEL) CSYSLOG_IF(condition, LEVEL, el::base::consts::kSysLogLoggerId) +# define SYSLOG_EVERY_N(n, LEVEL) CSYSLOG_EVERY_N(n, LEVEL, el::base::consts::kSysLogLoggerId) +# define SYSLOG_AFTER_N(n, LEVEL) CSYSLOG_AFTER_N(n, LEVEL, el::base::consts::kSysLogLoggerId) +# define SYSLOG_N_TIMES(n, LEVEL) CSYSLOG_N_TIMES(n, LEVEL, el::base::consts::kSysLogLoggerId) +# define DCSYSLOG(LEVEL, ...) if (ELPP_DEBUG_LOG) C##LEVEL(el::base::Writer, el::base::DispatchAction::SysLog, __VA_ARGS__) +# define DCSYSLOG_IF(condition, LEVEL, ...)\ +C##LEVEL##_IF(el::base::Writer, (ELPP_DEBUG_LOG) && (condition), el::base::DispatchAction::SysLog, __VA_ARGS__) +# define DCSYSLOG_EVERY_N(n, LEVEL, ...)\ +if (ELPP_DEBUG_LOG) C##LEVEL##_EVERY_N(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__) +# define DCSYSLOG_AFTER_N(n, LEVEL, ...)\ +if (ELPP_DEBUG_LOG) C##LEVEL##_AFTER_N(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__) +# define DCSYSLOG_N_TIMES(n, LEVEL, ...)\ +if (ELPP_DEBUG_LOG) C##LEVEL##_EVERY_N(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__) +# define DSYSLOG(LEVEL) DCSYSLOG(LEVEL, el::base::consts::kSysLogLoggerId) +# define DSYSLOG_IF(condition, LEVEL) DCSYSLOG_IF(condition, LEVEL, el::base::consts::kSysLogLoggerId) +# define DSYSLOG_EVERY_N(n, LEVEL) DCSYSLOG_EVERY_N(n, LEVEL, el::base::consts::kSysLogLoggerId) +# define DSYSLOG_AFTER_N(n, LEVEL) DCSYSLOG_AFTER_N(n, LEVEL, el::base::consts::kSysLogLoggerId) +# define DSYSLOG_N_TIMES(n, LEVEL) DCSYSLOG_N_TIMES(n, LEVEL, el::base::consts::kSysLogLoggerId) +#else +# define CSYSLOG(LEVEL, ...) el::base::NullWriter() +# define CSYSLOG_IF(condition, LEVEL, ...) el::base::NullWriter() +# define CSYSLOG_EVERY_N(n, LEVEL, ...) el::base::NullWriter() +# define CSYSLOG_AFTER_N(n, LEVEL, ...) el::base::NullWriter() +# define CSYSLOG_N_TIMES(n, LEVEL, ...) el::base::NullWriter() +# define SYSLOG(LEVEL) el::base::NullWriter() +# define SYSLOG_IF(condition, LEVEL) el::base::NullWriter() +# define SYSLOG_EVERY_N(n, LEVEL) el::base::NullWriter() +# define SYSLOG_AFTER_N(n, LEVEL) el::base::NullWriter() +# define SYSLOG_N_TIMES(n, LEVEL) el::base::NullWriter() +# define DCSYSLOG(LEVEL, ...) el::base::NullWriter() +# define DCSYSLOG_IF(condition, LEVEL, ...) el::base::NullWriter() +# define DCSYSLOG_EVERY_N(n, LEVEL, ...) el::base::NullWriter() +# define DCSYSLOG_AFTER_N(n, LEVEL, ...) el::base::NullWriter() +# define DCSYSLOG_N_TIMES(n, LEVEL, ...) el::base::NullWriter() +# define DSYSLOG(LEVEL) el::base::NullWriter() +# define DSYSLOG_IF(condition, LEVEL) el::base::NullWriter() +# define DSYSLOG_EVERY_N(n, LEVEL) el::base::NullWriter() +# define DSYSLOG_AFTER_N(n, LEVEL) el::base::NullWriter() +# define DSYSLOG_N_TIMES(n, LEVEL) el::base::NullWriter() +#endif // defined(ELPP_SYSLOG) // -// Default Loggers macro using C##LEVEL("security") +// Custom Debug Only Loggers - Requires (level, loggerId/s) // // undef existing -#undef SINFO -#undef SWARNING -#undef SDEBUG -#undef SERROR -#undef SFATAL -#undef SQA -#undef STRACE -#undef SVERBOSE -#undef SINFO_IF -#undef SWARNING_IF -#undef SDEBUG_IF -#undef SERROR_IF -#undef SFATAL_IF -#undef SQA_IF -#undef STRACE_IF -#undef SVERBOSE_IF -#undef SINFO_EVERY_N -#undef SWARNING_EVERY_N -#undef SDEBUG_EVERY_N -#undef SERROR_EVERY_N -#undef SFATAL_EVERY_N -#undef SQA_EVERY_N -#undef STRACE_EVERY_N -#undef SVERBOSE_EVERY_N +#undef DCLOG +#undef DCVLOG +#undef DCLOG_IF +#undef DCVLOG_IF +#undef DCLOG_EVERY_N +#undef DCVLOG_EVERY_N +#undef DCLOG_AFTER_N +#undef DCVLOG_AFTER_N +#undef DCLOG_N_TIMES +#undef DCVLOG_N_TIMES // Normal logs -#define SINFO CINFO("security") -#define SWARNING CWARNING("security") -#define SDEBUG CDEBUG("security") -#define SERROR CERROR("security") -#define SFATAL CFATAL("security") -#define SQA CQA("security") -#define STRACE CTRACE("security") -#define SVERBOSE(level) CVERBOSE(level, "security") +#define DCLOG(LEVEL, ...) if (ELPP_DEBUG_LOG) CLOG(LEVEL, __VA_ARGS__) +#define DCLOG_VERBOSE(vlevel, ...) if (ELPP_DEBUG_LOG) CLOG_VERBOSE(vlevel, __VA_ARGS__) +#define DCVLOG(vlevel, ...) if (ELPP_DEBUG_LOG) CVLOG(vlevel, __VA_ARGS__) // Conditional logs -#define SINFO_IF(condition) CINFO_IF(condition, "security") -#define SWARNING_IF(condition) CWARNING_IF(condition, "security") -#define SDEBUG_IF(condition) CDEBUG_IF(condition, "security") -#define SERROR_IF(condition) CERROR_IF(condition, "security") -#define SFATAL_IF(condition) CFATAL_IF(condition, "security") -#define SQA_IF(condition) CQA_IF(condition, "security") -#define STRACE_IF(condition) CQA_IF(condition, "security") -#define SVERBOSE_IF(condition, level) CVERBOSE_IF(condition, level, "security") -// Interval logs -#define SINFO_EVERY_N(n) CINFO_EVERY_N(n, "security") -#define SWARNING_EVERY_N(n) CWARNING_EVERY_N(n, "security") -#define SDEBUG_EVERY_N(n) CDEBUG_EVERY_N(n, "security") -#define SERROR_EVERY_N(n) CERROR_EVERY_N(n, "security") -#define SFATAL_EVERY_N(n) CFATAL_EVERY_N(n, "security") -#define SQA_EVERY_N(n) CQA_EVERY_N(n, "security") -#define STRACE_EVERY_N(n) CTRACE_EVERY_N(n, "security") -#define SVERBOSE_EVERY_N(n, level) CVERBOSE_EVERY_N(n, level, "security") +#define DCLOG_IF(condition, LEVEL, ...) if (ELPP_DEBUG_LOG) CLOG_IF(condition, LEVEL, __VA_ARGS__) +#define DCVLOG_IF(condition, vlevel, ...) if (ELPP_DEBUG_LOG) CVLOG_IF(condition, vlevel, __VA_ARGS__) +// Hit counts based logs +#define DCLOG_EVERY_N(n, LEVEL, ...) if (ELPP_DEBUG_LOG) CLOG_EVERY_N(n, LEVEL, __VA_ARGS__) +#define DCVLOG_EVERY_N(n, vlevel, ...) if (ELPP_DEBUG_LOG) CVLOG_EVERY_N(n, vlevel, __VA_ARGS__) +#define DCLOG_AFTER_N(n, LEVEL, ...) if (ELPP_DEBUG_LOG) CLOG_AFTER_N(n, LEVEL, __VA_ARGS__) +#define DCVLOG_AFTER_N(n, vlevel, ...) if (ELPP_DEBUG_LOG) CVLOG_AFTER_N(n, vlevel, __VA_ARGS__) +#define DCLOG_N_TIMES(n, LEVEL, ...) if (ELPP_DEBUG_LOG) CLOG_N_TIMES(n, LEVEL, __VA_ARGS__) +#define DCVLOG_N_TIMES(n, vlevel, ...) if (ELPP_DEBUG_LOG) CVLOG_N_TIMES(n, vlevel, __VA_ARGS__) // -// Default Loggers macro using C##LEVEL("performance") +// Default Debug Only Loggers macro using CLOG(), CLOG_VERBOSE() and CVLOG() macros // +#if !defined(ELPP_NO_DEBUG_MACROS) // undef existing -#undef PINFO -#undef PWARNING -#undef PDEBUG -#undef PERROR -#undef PFATAL -#undef PQA -#undef PTRACE -#undef PVERBOSE -#undef PINFO_IF -#undef PWARNING_IF -#undef PDEBUG_IF -#undef PERROR_IF -#undef PFATAL_IF -#undef PQA_IF -#undef PTRACE_IF -#undef PVERBOSE_IF -#undef PINFO_EVERY_N -#undef PWARNING_EVERY_N -#undef PDEBUG_EVERY_N -#undef PERROR_EVERY_N -#undef PFATAL_EVERY_N -#undef PQA_EVERY_N -#undef PTRACE_EVERY_N -#undef PVERBOSE_EVERY_N +#undef DLOG +#undef DVLOG +#undef DLOG_IF +#undef DVLOG_IF +#undef DLOG_EVERY_N +#undef DVLOG_EVERY_N +#undef DLOG_AFTER_N +#undef DVLOG_AFTER_N +#undef DLOG_N_TIMES +#undef DVLOG_N_TIMES // Normal logs -#define PINFO CINFO("performance") -#define PWARNING CWARNING("performance") -#define PDEBUG CDEBUG("performance") -#define PERROR CERROR("performance") -#define PFATAL CFATAL("performance") -#define PQA CQA("performance") -#define PTRACE CTRACE("performance") -#define PVERBOSE(level) CVERBOSE(level, "performance") +#define DLOG(LEVEL) DCLOG(LEVEL, ELPP_CURR_FILE_LOGGER_ID) +#define DVLOG(vlevel) DCVLOG(vlevel, ELPP_CURR_FILE_LOGGER_ID) // Conditional logs -#define PINFO_IF(condition) CINFO_IF(condition, "performance") -#define PWARNING_IF(condition) CWARNING_IF(condition, "performance") -#define PDEBUG_IF(condition) CDEBUG_IF(condition, "performance") -#define PERROR_IF(condition) CERROR_IF(condition, "performance") -#define PFATAL_IF(condition) CFATAL_IF(condition, "performance") -#define PQA_IF(condition) CQA_IF(condition, "performance") -#define PTRACE_IF(condition) CQA_IF(condition, "performance") -#define PVERBOSE_IF(condition, level) CVERBOSE_IF(condition, level, "performance") -// Interval logs -#define PINFO_EVERY_N(n) CINFO_EVERY_N(n, "performance") -#define PWARNING_EVERY_N(n) CWARNING_EVERY_N(n, "performance") -#define PDEBUG_EVERY_N(n) CDEBUG_EVERY_N(n, "performance") -#define PERROR_EVERY_N(n) CERROR_EVERY_N(n, "performance") -#define PFATAL_EVERY_N(n) CFATAL_EVERY_N(n, "performance") -#define PQA_EVERY_N(n) CQA_EVERY_N(n, "performance") -#define PTRACE_EVERY_N(n) CTRACE_EVERY_N(n, "performance") -#define PVERBOSE_EVERY_N(n, level) CVERBOSE_EVERY_N(n, level, "performance") -// Undefine macros that are not needed anymore -#undef _ELPP_ASSEMBLY_SUPPORTED -#undef _ELPP_STREAM -#undef _ELPP_MUTEX_LOCK_GNU_ASM -#undef _ELPP_MUTEX_UNLOCK_GNU_ASM -#undef _ELPP_ENABLE_MUTEX -#undef _ENABLE_EASYLOGGING -#undef __EASYLOGGINGPP_SUPPRESS_UNSED -#undef _ELPP_DEBUG_LOG -#undef _ELPP_INFO_LOG -#undef _ELPP_WARNING_LOG -#undef _ELPP_ERROR_LOG -#undef _ELPP_FATAL_LOG -#undef _ELPP_QA_LOG -#undef _ELPP_VERBOSE_LOG -#undef _ELPP_TRACE_LOG -#undef _INITIALIZE_EASYLOGGINGPP -#undef _START_EASYLOGGINGPP -#undef _ELPP_COUNTER -#undef _ELPP_COUNTER_POSITION -#define _INITIALIZE_EASYLOGGINGPP \ - namespace easyloggingpp { \ - namespace internal { \ - ScopedPointer registeredLoggers( \ - new RegisteredLoggers()); \ - } \ - } -#define _START_EASYLOGGINGPP(argc, argv) easyloggingpp::Loggers::setApplicationArguments(argc, argv); -#define _ELPP_COUNTER easyloggingpp::internal::registeredLoggers->counters()->get(__FILE__, __LINE__) -#define _ELPP_COUNTER_POSITION (_ELPP_COUNTER == NULL ? 0 : _ELPP_COUNTER->position()) -} // easyloggingpp -#endif // EASYLOGGINGPP_H \ No newline at end of file +#define DLOG_IF(condition, LEVEL) DCLOG_IF(condition, LEVEL, ELPP_CURR_FILE_LOGGER_ID) +#define DVLOG_IF(condition, vlevel) DCVLOG_IF(condition, vlevel, ELPP_CURR_FILE_LOGGER_ID) +// Hit counts based logs +#define DLOG_EVERY_N(n, LEVEL) DCLOG_EVERY_N(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID) +#define DVLOG_EVERY_N(n, vlevel) DCVLOG_EVERY_N(n, vlevel, ELPP_CURR_FILE_LOGGER_ID) +#define DLOG_AFTER_N(n, LEVEL) DCLOG_AFTER_N(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID) +#define DVLOG_AFTER_N(n, vlevel) DCVLOG_AFTER_N(n, vlevel, ELPP_CURR_FILE_LOGGER_ID) +#define DLOG_N_TIMES(n, LEVEL) DCLOG_N_TIMES(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID) +#define DVLOG_N_TIMES(n, vlevel) DCVLOG_N_TIMES(n, vlevel, ELPP_CURR_FILE_LOGGER_ID) +#endif // defined(ELPP_NO_DEBUG_MACROS) +#if !defined(ELPP_NO_CHECK_MACROS) +// Check macros +#undef CCHECK +#undef CPCHECK +#undef CCHECK_EQ +#undef CCHECK_NE +#undef CCHECK_LT +#undef CCHECK_GT +#undef CCHECK_LE +#undef CCHECK_GE +#undef CCHECK_BOUNDS +#undef CCHECK_NOTNULL +#undef CCHECK_STRCASEEQ +#undef CCHECK_STRCASENE +#undef CHECK +#undef PCHECK +#undef CHECK_EQ +#undef CHECK_NE +#undef CHECK_LT +#undef CHECK_GT +#undef CHECK_LE +#undef CHECK_GE +#undef CHECK_BOUNDS +#undef CHECK_NOTNULL +#undef CHECK_STRCASEEQ +#undef CHECK_STRCASENE +#define CCHECK(condition, ...) CLOG_IF(!(condition), FATAL, __VA_ARGS__) << "Check failed: [" << #condition << "] " +#define CPCHECK(condition, ...) CPLOG_IF(!(condition), FATAL, __VA_ARGS__) << "Check failed: [" << #condition << "] " +#define CHECK(condition) CCHECK(condition, ELPP_CURR_FILE_LOGGER_ID) +#define PCHECK(condition) CPCHECK(condition, ELPP_CURR_FILE_LOGGER_ID) +#define CCHECK_EQ(a, b, ...) CCHECK(a == b, __VA_ARGS__) +#define CCHECK_NE(a, b, ...) CCHECK(a != b, __VA_ARGS__) +#define CCHECK_LT(a, b, ...) CCHECK(a < b, __VA_ARGS__) +#define CCHECK_GT(a, b, ...) CCHECK(a > b, __VA_ARGS__) +#define CCHECK_LE(a, b, ...) CCHECK(a <= b, __VA_ARGS__) +#define CCHECK_GE(a, b, ...) CCHECK(a >= b, __VA_ARGS__) +#define CCHECK_BOUNDS(val, min, max, ...) CCHECK(val >= min && val <= max, __VA_ARGS__) +#define CHECK_EQ(a, b) CCHECK_EQ(a, b, ELPP_CURR_FILE_LOGGER_ID) +#define CHECK_NE(a, b) CCHECK_NE(a, b, ELPP_CURR_FILE_LOGGER_ID) +#define CHECK_LT(a, b) CCHECK_LT(a, b, ELPP_CURR_FILE_LOGGER_ID) +#define CHECK_GT(a, b) CCHECK_GT(a, b, ELPP_CURR_FILE_LOGGER_ID) +#define CHECK_LE(a, b) CCHECK_LE(a, b, ELPP_CURR_FILE_LOGGER_ID) +#define CHECK_GE(a, b) CCHECK_GE(a, b, ELPP_CURR_FILE_LOGGER_ID) +#define CHECK_BOUNDS(val, min, max) CCHECK_BOUNDS(val, min, max, ELPP_CURR_FILE_LOGGER_ID) +#define CCHECK_NOTNULL(ptr, ...) CCHECK((ptr) != nullptr, __VA_ARGS__) +#define CCHECK_STREQ(str1, str2, ...) CLOG_IF(!el::base::utils::Str::cStringEq(str1, str2), FATAL, __VA_ARGS__) \ +<< "Check failed: [" << #str1 << " == " << #str2 << "] " +#define CCHECK_STRNE(str1, str2, ...) CLOG_IF(el::base::utils::Str::cStringEq(str1, str2), FATAL, __VA_ARGS__) \ +<< "Check failed: [" << #str1 << " != " << #str2 << "] " +#define CCHECK_STRCASEEQ(str1, str2, ...) CLOG_IF(!el::base::utils::Str::cStringCaseEq(str1, str2), FATAL, __VA_ARGS__) \ +<< "Check failed: [" << #str1 << " == " << #str2 << "] " +#define CCHECK_STRCASENE(str1, str2, ...) CLOG_IF(el::base::utils::Str::cStringCaseEq(str1, str2), FATAL, __VA_ARGS__) \ +<< "Check failed: [" << #str1 << " != " << #str2 << "] " +#define CHECK_NOTNULL(ptr) CCHECK_NOTNULL((ptr), ELPP_CURR_FILE_LOGGER_ID) +#define CHECK_STREQ(str1, str2) CCHECK_STREQ(str1, str2, ELPP_CURR_FILE_LOGGER_ID) +#define CHECK_STRNE(str1, str2) CCHECK_STRNE(str1, str2, ELPP_CURR_FILE_LOGGER_ID) +#define CHECK_STRCASEEQ(str1, str2) CCHECK_STRCASEEQ(str1, str2, ELPP_CURR_FILE_LOGGER_ID) +#define CHECK_STRCASENE(str1, str2) CCHECK_STRCASENE(str1, str2, ELPP_CURR_FILE_LOGGER_ID) +#undef DCCHECK +#undef DCCHECK_EQ +#undef DCCHECK_NE +#undef DCCHECK_LT +#undef DCCHECK_GT +#undef DCCHECK_LE +#undef DCCHECK_GE +#undef DCCHECK_BOUNDS +#undef DCCHECK_NOTNULL +#undef DCCHECK_STRCASEEQ +#undef DCCHECK_STRCASENE +#undef DCPCHECK +#undef DCHECK +#undef DCHECK_EQ +#undef DCHECK_NE +#undef DCHECK_LT +#undef DCHECK_GT +#undef DCHECK_LE +#undef DCHECK_GE +#undef DCHECK_BOUNDS_ +#undef DCHECK_NOTNULL +#undef DCHECK_STRCASEEQ +#undef DCHECK_STRCASENE +#undef DPCHECK +#define DCCHECK(condition, ...) if (ELPP_DEBUG_LOG) CCHECK(condition, __VA_ARGS__) +#define DCCHECK_EQ(a, b, ...) if (ELPP_DEBUG_LOG) CCHECK_EQ(a, b, __VA_ARGS__) +#define DCCHECK_NE(a, b, ...) if (ELPP_DEBUG_LOG) CCHECK_NE(a, b, __VA_ARGS__) +#define DCCHECK_LT(a, b, ...) if (ELPP_DEBUG_LOG) CCHECK_LT(a, b, __VA_ARGS__) +#define DCCHECK_GT(a, b, ...) if (ELPP_DEBUG_LOG) CCHECK_GT(a, b, __VA_ARGS__) +#define DCCHECK_LE(a, b, ...) if (ELPP_DEBUG_LOG) CCHECK_LE(a, b, __VA_ARGS__) +#define DCCHECK_GE(a, b, ...) if (ELPP_DEBUG_LOG) CCHECK_GE(a, b, __VA_ARGS__) +#define DCCHECK_BOUNDS(val, min, max, ...) if (ELPP_DEBUG_LOG) CCHECK_BOUNDS(val, min, max, __VA_ARGS__) +#define DCCHECK_NOTNULL(ptr, ...) if (ELPP_DEBUG_LOG) CCHECK_NOTNULL((ptr), __VA_ARGS__) +#define DCCHECK_STREQ(str1, str2, ...) if (ELPP_DEBUG_LOG) CCHECK_STREQ(str1, str2, __VA_ARGS__) +#define DCCHECK_STRNE(str1, str2, ...) if (ELPP_DEBUG_LOG) CCHECK_STRNE(str1, str2, __VA_ARGS__) +#define DCCHECK_STRCASEEQ(str1, str2, ...) if (ELPP_DEBUG_LOG) CCHECK_STRCASEEQ(str1, str2, __VA_ARGS__) +#define DCCHECK_STRCASENE(str1, str2, ...) if (ELPP_DEBUG_LOG) CCHECK_STRCASENE(str1, str2, __VA_ARGS__) +#define DCPCHECK(condition, ...) if (ELPP_DEBUG_LOG) CPCHECK(condition, __VA_ARGS__) +#define DCHECK(condition) DCCHECK(condition, ELPP_CURR_FILE_LOGGER_ID) +#define DCHECK_EQ(a, b) DCCHECK_EQ(a, b, ELPP_CURR_FILE_LOGGER_ID) +#define DCHECK_NE(a, b) DCCHECK_NE(a, b, ELPP_CURR_FILE_LOGGER_ID) +#define DCHECK_LT(a, b) DCCHECK_LT(a, b, ELPP_CURR_FILE_LOGGER_ID) +#define DCHECK_GT(a, b) DCCHECK_GT(a, b, ELPP_CURR_FILE_LOGGER_ID) +#define DCHECK_LE(a, b) DCCHECK_LE(a, b, ELPP_CURR_FILE_LOGGER_ID) +#define DCHECK_GE(a, b) DCCHECK_GE(a, b, ELPP_CURR_FILE_LOGGER_ID) +#define DCHECK_BOUNDS(val, min, max) DCCHECK_BOUNDS(val, min, max, ELPP_CURR_FILE_LOGGER_ID) +#define DCHECK_NOTNULL(ptr) DCCHECK_NOTNULL((ptr), ELPP_CURR_FILE_LOGGER_ID) +#define DCHECK_STREQ(str1, str2) DCCHECK_STREQ(str1, str2, ELPP_CURR_FILE_LOGGER_ID) +#define DCHECK_STRNE(str1, str2) DCCHECK_STRNE(str1, str2, ELPP_CURR_FILE_LOGGER_ID) +#define DCHECK_STRCASEEQ(str1, str2) DCCHECK_STRCASEEQ(str1, str2, ELPP_CURR_FILE_LOGGER_ID) +#define DCHECK_STRCASENE(str1, str2) DCCHECK_STRCASENE(str1, str2, ELPP_CURR_FILE_LOGGER_ID) +#define DPCHECK(condition) DCPCHECK(condition, ELPP_CURR_FILE_LOGGER_ID) +#endif // defined(ELPP_NO_CHECK_MACROS) +#if defined(ELPP_DISABLE_DEFAULT_CRASH_HANDLING) +# define ELPP_USE_DEF_CRASH_HANDLER false +#else +# define ELPP_USE_DEF_CRASH_HANDLER true +#endif // defined(ELPP_DISABLE_DEFAULT_CRASH_HANDLING) +#define ELPP_CRASH_HANDLER_INIT +#define ELPP_INIT_EASYLOGGINGPP(val) \ +namespace el { \ +namespace base { \ +el::base::type::StoragePointer elStorage(val); \ +} \ +el::base::debug::CrashHandler elCrashHandler(ELPP_USE_DEF_CRASH_HANDLER); \ +} + +#if ELPP_ASYNC_LOGGING +# define INITIALIZE_EASYLOGGINGPP ELPP_INIT_EASYLOGGINGPP(new el::base::Storage(el::LogBuilderPtr(new el::base::DefaultLogBuilder()),\ +new el::base::AsyncDispatchWorker())) +#else +# define INITIALIZE_EASYLOGGINGPP ELPP_INIT_EASYLOGGINGPP(new el::base::Storage(el::LogBuilderPtr(new el::base::DefaultLogBuilder()))) +#endif // ELPP_ASYNC_LOGGING +#define INITIALIZE_NULL_EASYLOGGINGPP \ +namespace el {\ +namespace base {\ +el::base::type::StoragePointer elStorage;\ +}\ +el::base::debug::CrashHandler elCrashHandler(ELPP_USE_DEF_CRASH_HANDLER);\ +} +#define SHARE_EASYLOGGINGPP(initializedStorage)\ +namespace el {\ +namespace base {\ +el::base::type::StoragePointer elStorage(initializedStorage);\ +}\ +el::base::debug::CrashHandler elCrashHandler(ELPP_USE_DEF_CRASH_HANDLER);\ +} + +#if defined(ELPP_UNICODE) +# define START_EASYLOGGINGPP(argc, argv) el::Helpers::setArgs(argc, argv); std::locale::global(std::locale("")) +#else +# define START_EASYLOGGINGPP(argc, argv) el::Helpers::setArgs(argc, argv) +#endif // defined(ELPP_UNICODE) +#endif // EASYLOGGINGPP_H diff --git a/include/kerberos/Kerberos.h b/include/kerberos/Kerberos.h index 95cb976..674c3f0 100755 --- a/include/kerberos/Kerberos.h +++ b/include/kerberos/Kerberos.h @@ -51,7 +51,7 @@ namespace kerberos void setCaptureDelayTime(int delay){m_captureDelayTime=delay;}; void setParameters(StringMap & parameters) { - LINFO << helper::printStringMap("Parameters passed from commandline:", parameters); + LOG(INFO) << helper::printStringMap("Parameters passed from commandline:", parameters); m_parameters = parameters; }; StringMap getParameters(){return m_parameters;} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 025bbb2..597e268 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -11,6 +11,7 @@ include_directories(${CMAKE_SOURCE_DIR}/include/encode) include_directories(${CMAKE_SOURCE_DIR}/include/easylogging) + add_subdirectory(easylogging) add_subdirectory(tinyxml) add_subdirectory(executor) add_subdirectory(filewatcher) diff --git a/src/easylogging/CMakeLists.txt b/src/easylogging/CMakeLists.txt new file mode 100644 index 0000000..c506d4b --- /dev/null +++ b/src/easylogging/CMakeLists.txt @@ -0,0 +1,7 @@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# Build library +add_library(EASYLOGGING_LIBRARY STATIC + easylogging++.cpp) + +set(KERBEROS_DEPENDENCIES ${KERBEROS_DEPENDENCIES} EASYLOGGING_LIBRARY PARENT_SCOPE) +set(KERBEROS_LIBRARIES ${KERBEROS_LIBRARIES} EASYLOGGING_LIBRARY PARENT_SCOPE) diff --git a/src/easylogging/easylogging++.cpp b/src/easylogging/easylogging++.cpp new file mode 100644 index 0000000..a87f0b8 --- /dev/null +++ b/src/easylogging/easylogging++.cpp @@ -0,0 +1,3104 @@ +// +// Bismillah ar-Rahmaan ar-Raheem +// +// Easylogging++ v9.96.4 +// Cross-platform logging library for C++ applications +// +// Copyright (c) 2012-2018 Muflihun Labs +// Copyright (c) 2012-2018 @abumusamq +// +// This library is released under the MIT Licence. +// https://github.com/muflihun/easyloggingpp/blob/master/LICENSE +// +// https://github.com/muflihun/easyloggingpp +// https://muflihun.github.io/easyloggingpp +// http://muflihun.com +// + +#include "easylogging++.h" + +#if defined(AUTO_INITIALIZE_EASYLOGGINGPP) +INITIALIZE_EASYLOGGINGPP +#endif + +namespace el { + +// el::base +namespace base { +// el::base::consts +namespace consts { + +// Level log values - These are values that are replaced in place of %level format specifier +// Extra spaces after format specifiers are only for readability purposes in log files +static const base::type::char_t* kInfoLevelLogValue = ELPP_LITERAL("INFO"); +static const base::type::char_t* kDebugLevelLogValue = ELPP_LITERAL("DEBUG"); +static const base::type::char_t* kWarningLevelLogValue = ELPP_LITERAL("WARNING"); +static const base::type::char_t* kErrorLevelLogValue = ELPP_LITERAL("ERROR"); +static const base::type::char_t* kFatalLevelLogValue = ELPP_LITERAL("FATAL"); +static const base::type::char_t* kVerboseLevelLogValue = + ELPP_LITERAL("VERBOSE"); // will become VERBOSE-x where x = verbose level +static const base::type::char_t* kTraceLevelLogValue = ELPP_LITERAL("TRACE"); +static const base::type::char_t* kInfoLevelShortLogValue = ELPP_LITERAL("I"); +static const base::type::char_t* kDebugLevelShortLogValue = ELPP_LITERAL("D"); +static const base::type::char_t* kWarningLevelShortLogValue = ELPP_LITERAL("W"); +static const base::type::char_t* kErrorLevelShortLogValue = ELPP_LITERAL("E"); +static const base::type::char_t* kFatalLevelShortLogValue = ELPP_LITERAL("F"); +static const base::type::char_t* kVerboseLevelShortLogValue = ELPP_LITERAL("V"); +static const base::type::char_t* kTraceLevelShortLogValue = ELPP_LITERAL("T"); +// Format specifiers - These are used to define log format +static const base::type::char_t* kAppNameFormatSpecifier = ELPP_LITERAL("%app"); +static const base::type::char_t* kLoggerIdFormatSpecifier = ELPP_LITERAL("%logger"); +static const base::type::char_t* kThreadIdFormatSpecifier = ELPP_LITERAL("%thread"); +static const base::type::char_t* kSeverityLevelFormatSpecifier = ELPP_LITERAL("%level"); +static const base::type::char_t* kSeverityLevelShortFormatSpecifier = ELPP_LITERAL("%levshort"); +static const base::type::char_t* kDateTimeFormatSpecifier = ELPP_LITERAL("%datetime"); +static const base::type::char_t* kLogFileFormatSpecifier = ELPP_LITERAL("%file"); +static const base::type::char_t* kLogFileBaseFormatSpecifier = ELPP_LITERAL("%fbase"); +static const base::type::char_t* kLogLineFormatSpecifier = ELPP_LITERAL("%line"); +static const base::type::char_t* kLogLocationFormatSpecifier = ELPP_LITERAL("%loc"); +static const base::type::char_t* kLogFunctionFormatSpecifier = ELPP_LITERAL("%func"); +static const base::type::char_t* kCurrentUserFormatSpecifier = ELPP_LITERAL("%user"); +static const base::type::char_t* kCurrentHostFormatSpecifier = ELPP_LITERAL("%host"); +static const base::type::char_t* kMessageFormatSpecifier = ELPP_LITERAL("%msg"); +static const base::type::char_t* kVerboseLevelFormatSpecifier = ELPP_LITERAL("%vlevel"); +static const char* kDateTimeFormatSpecifierForFilename = "%datetime"; +// Date/time +static const char* kDays[7] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; +static const char* kDaysAbbrev[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; +static const char* kMonths[12] = { "January", "February", "March", "Apri", "May", "June", "July", "August", + "September", "October", "November", "December" + }; +static const char* kMonthsAbbrev[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; +static const char* kDefaultDateTimeFormat = "%Y-%M-%d %H:%m:%s,%g"; +static const char* kDefaultDateTimeFormatInFilename = "%Y-%M-%d_%H-%m"; +static const int kYearBase = 1900; +static const char* kAm = "AM"; +static const char* kPm = "PM"; +// Miscellaneous constants + +static const char* kNullPointer = "nullptr"; +#if ELPP_VARIADIC_TEMPLATES_SUPPORTED +#endif // ELPP_VARIADIC_TEMPLATES_SUPPORTED +static const base::type::VerboseLevel kMaxVerboseLevel = 9; +static const char* kUnknownUser = "user"; +static const char* kUnknownHost = "unknown-host"; + + +//---------------- DEFAULT LOG FILE ----------------------- + +#if defined(ELPP_NO_DEFAULT_LOG_FILE) +# if ELPP_OS_UNIX +static const char* kDefaultLogFile = "/dev/null"; +# elif ELPP_OS_WINDOWS +static const char* kDefaultLogFile = "nul"; +# endif // ELPP_OS_UNIX +#elif defined(ELPP_DEFAULT_LOG_FILE) +static const char* kDefaultLogFile = ELPP_DEFAULT_LOG_FILE; +#else +static const char* kDefaultLogFile = "myeasylog.log"; +#endif // defined(ELPP_NO_DEFAULT_LOG_FILE) + + +#if !defined(ELPP_DISABLE_LOG_FILE_FROM_ARG) +static const char* kDefaultLogFileParam = "--default-log-file"; +#endif // !defined(ELPP_DISABLE_LOG_FILE_FROM_ARG) +#if defined(ELPP_LOGGING_FLAGS_FROM_ARG) +static const char* kLoggingFlagsParam = "--logging-flags"; +#endif // defined(ELPP_LOGGING_FLAGS_FROM_ARG) +static const char* kValidLoggerIdSymbols = + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._"; +static const char* kConfigurationComment = "##"; +static const char* kConfigurationLevel = "*"; +static const char* kConfigurationLoggerId = "--"; +} +// el::base::utils +namespace utils { + +/// @brief Aborts application due with user-defined status +static void abort(int status, const std::string& reason) { + // Both status and reason params are there for debugging with tools like gdb etc + ELPP_UNUSED(status); + ELPP_UNUSED(reason); +#if defined(ELPP_COMPILER_MSVC) && defined(_M_IX86) && defined(_DEBUG) + // Ignore msvc critical error dialog - break instead (on debug mode) + _asm int 3 +#else + ::abort(); +#endif // defined(ELPP_COMPILER_MSVC) && defined(_M_IX86) && defined(_DEBUG) +} + +} // namespace utils +} // namespace base + +// el + +// LevelHelper + +const char* LevelHelper::convertToString(Level level) { + // Do not use switch over strongly typed enums because Intel C++ compilers dont support them yet. + if (level == Level::Global) return "GLOBAL"; + if (level == Level::Debug) return "DEBUG"; + if (level == Level::Info) return "INFO"; + if (level == Level::Warning) return "WARNING"; + if (level == Level::Error) return "ERROR"; + if (level == Level::Fatal) return "FATAL"; + if (level == Level::Verbose) return "VERBOSE"; + if (level == Level::Trace) return "TRACE"; + return "UNKNOWN"; +} + +struct StringToLevelItem { + const char* levelString; + Level level; +}; + +static struct StringToLevelItem stringToLevelMap[] = { + { "global", Level::Global }, + { "debug", Level::Debug }, + { "info", Level::Info }, + { "warning", Level::Warning }, + { "error", Level::Error }, + { "fatal", Level::Fatal }, + { "verbose", Level::Verbose }, + { "trace", Level::Trace } +}; + +Level LevelHelper::convertFromString(const char* levelStr) { + for (auto& item : stringToLevelMap) { + if (base::utils::Str::cStringCaseEq(levelStr, item.levelString)) { + return item.level; + } + } + return Level::Unknown; +} + +void LevelHelper::forEachLevel(base::type::EnumType* startIndex, const std::function& fn) { + base::type::EnumType lIndexMax = LevelHelper::kMaxValid; + do { + if (fn()) { + break; + } + *startIndex = static_cast(*startIndex << 1); + } while (*startIndex <= lIndexMax); +} + +// ConfigurationTypeHelper + +const char* ConfigurationTypeHelper::convertToString(ConfigurationType configurationType) { + // Do not use switch over strongly typed enums because Intel C++ compilers dont support them yet. + if (configurationType == ConfigurationType::Enabled) return "ENABLED"; + if (configurationType == ConfigurationType::Filename) return "FILENAME"; + if (configurationType == ConfigurationType::Format) return "FORMAT"; + if (configurationType == ConfigurationType::ToFile) return "TO_FILE"; + if (configurationType == ConfigurationType::ToStandardOutput) return "TO_STANDARD_OUTPUT"; + if (configurationType == ConfigurationType::SubsecondPrecision) return "SUBSECOND_PRECISION"; + if (configurationType == ConfigurationType::PerformanceTracking) return "PERFORMANCE_TRACKING"; + if (configurationType == ConfigurationType::MaxLogFileSize) return "MAX_LOG_FILE_SIZE"; + if (configurationType == ConfigurationType::LogFlushThreshold) return "LOG_FLUSH_THRESHOLD"; + return "UNKNOWN"; +} + +struct ConfigurationStringToTypeItem { + const char* configString; + ConfigurationType configType; +}; + +static struct ConfigurationStringToTypeItem configStringToTypeMap[] = { + { "enabled", ConfigurationType::Enabled }, + { "to_file", ConfigurationType::ToFile }, + { "to_standard_output", ConfigurationType::ToStandardOutput }, + { "format", ConfigurationType::Format }, + { "filename", ConfigurationType::Filename }, + { "subsecond_precision", ConfigurationType::SubsecondPrecision }, + { "milliseconds_width", ConfigurationType::MillisecondsWidth }, + { "performance_tracking", ConfigurationType::PerformanceTracking }, + { "max_log_file_size", ConfigurationType::MaxLogFileSize }, + { "log_flush_threshold", ConfigurationType::LogFlushThreshold }, +}; + +ConfigurationType ConfigurationTypeHelper::convertFromString(const char* configStr) { + for (auto& item : configStringToTypeMap) { + if (base::utils::Str::cStringCaseEq(configStr, item.configString)) { + return item.configType; + } + } + return ConfigurationType::Unknown; +} + +void ConfigurationTypeHelper::forEachConfigType(base::type::EnumType* startIndex, const std::function& fn) { + base::type::EnumType cIndexMax = ConfigurationTypeHelper::kMaxValid; + do { + if (fn()) { + break; + } + *startIndex = static_cast(*startIndex << 1); + } while (*startIndex <= cIndexMax); +} + +// Configuration + +Configuration::Configuration(const Configuration& c) : + m_level(c.m_level), + m_configurationType(c.m_configurationType), + m_value(c.m_value) { +} + +Configuration& Configuration::operator=(const Configuration& c) { + if (&c != this) { + m_level = c.m_level; + m_configurationType = c.m_configurationType; + m_value = c.m_value; + } + return *this; +} + +/// @brief Full constructor used to sets value of configuration +Configuration::Configuration(Level level, ConfigurationType configurationType, const std::string& value) : + m_level(level), + m_configurationType(configurationType), + m_value(value) { +} + +void Configuration::log(el::base::type::ostream_t& os) const { + os << LevelHelper::convertToString(m_level) + << ELPP_LITERAL(" ") << ConfigurationTypeHelper::convertToString(m_configurationType) + << ELPP_LITERAL(" = ") << m_value.c_str(); +} + +/// @brief Used to find configuration from configuration (pointers) repository. Avoid using it. +Configuration::Predicate::Predicate(Level level, ConfigurationType configurationType) : + m_level(level), + m_configurationType(configurationType) { +} + +bool Configuration::Predicate::operator()(const Configuration* conf) const { + return ((conf != nullptr) && (conf->level() == m_level) && (conf->configurationType() == m_configurationType)); +} + +// Configurations + +Configurations::Configurations(void) : + m_configurationFile(std::string()), + m_isFromFile(false) { +} + +Configurations::Configurations(const std::string& configurationFile, bool useDefaultsForRemaining, + Configurations* base) : + m_configurationFile(configurationFile), + m_isFromFile(false) { + parseFromFile(configurationFile, base); + if (useDefaultsForRemaining) { + setRemainingToDefault(); + } +} + +bool Configurations::parseFromFile(const std::string& configurationFile, Configurations* base) { + // We initial assertion with true because if we have assertion diabled, we want to pass this + // check and if assertion is enabled we will have values re-assigned any way. + bool assertionPassed = true; + ELPP_ASSERT((assertionPassed = base::utils::File::pathExists(configurationFile.c_str(), true)) == true, + "Configuration file [" << configurationFile << "] does not exist!"); + if (!assertionPassed) { + return false; + } + bool success = Parser::parseFromFile(configurationFile, this, base); + m_isFromFile = success; + return success; +} + +bool Configurations::parseFromText(const std::string& configurationsString, Configurations* base) { + bool success = Parser::parseFromText(configurationsString, this, base); + if (success) { + m_isFromFile = false; + } + return success; +} + +void Configurations::setFromBase(Configurations* base) { + if (base == nullptr || base == this) { + return; + } + base::threading::ScopedLock scopedLock(base->lock()); + for (Configuration*& conf : base->list()) { + set(conf); + } +} + +bool Configurations::hasConfiguration(ConfigurationType configurationType) { + base::type::EnumType lIndex = LevelHelper::kMinValid; + bool result = false; + LevelHelper::forEachLevel(&lIndex, [&](void) -> bool { + if (hasConfiguration(LevelHelper::castFromInt(lIndex), configurationType)) { + result = true; + } + return result; + }); + return result; +} + +bool Configurations::hasConfiguration(Level level, ConfigurationType configurationType) { + base::threading::ScopedLock scopedLock(lock()); +#if ELPP_COMPILER_INTEL + // We cant specify template types here, Intel C++ throws compilation error + // "error: type name is not allowed" + return RegistryWithPred::get(level, configurationType) != nullptr; +#else + return RegistryWithPred::get(level, configurationType) != nullptr; +#endif // ELPP_COMPILER_INTEL +} + +void Configurations::set(Level level, ConfigurationType configurationType, const std::string& value) { + base::threading::ScopedLock scopedLock(lock()); + unsafeSet(level, configurationType, value); // This is not unsafe anymore as we have locked mutex + if (level == Level::Global) { + unsafeSetGlobally(configurationType, value, false); // Again this is not unsafe either + } +} + +void Configurations::set(Configuration* conf) { + if (conf == nullptr) { + return; + } + set(conf->level(), conf->configurationType(), conf->value()); +} + +void Configurations::setToDefault(void) { + setGlobally(ConfigurationType::Enabled, std::string("true"), true); + setGlobally(ConfigurationType::Filename, std::string(base::consts::kDefaultLogFile), true); +#if defined(ELPP_NO_LOG_TO_FILE) + setGlobally(ConfigurationType::ToFile, std::string("false"), true); +#else + setGlobally(ConfigurationType::ToFile, std::string("true"), true); +#endif // defined(ELPP_NO_LOG_TO_FILE) + setGlobally(ConfigurationType::ToStandardOutput, std::string("true"), true); + setGlobally(ConfigurationType::SubsecondPrecision, std::string("3"), true); + setGlobally(ConfigurationType::PerformanceTracking, std::string("true"), true); + setGlobally(ConfigurationType::MaxLogFileSize, std::string("0"), true); + setGlobally(ConfigurationType::LogFlushThreshold, std::string("0"), true); + + setGlobally(ConfigurationType::Format, std::string("%datetime %level [%logger] %msg"), true); + set(Level::Debug, ConfigurationType::Format, + std::string("%datetime %level [%logger] [%user@%host] [%func] [%loc] %msg")); + // INFO and WARNING are set to default by Level::Global + set(Level::Error, ConfigurationType::Format, std::string("%datetime %level [%logger] %msg")); + set(Level::Fatal, ConfigurationType::Format, std::string("%datetime %level [%logger] %msg")); + set(Level::Verbose, ConfigurationType::Format, std::string("%datetime %level-%vlevel [%logger] %msg")); + set(Level::Trace, ConfigurationType::Format, std::string("%datetime %level [%logger] [%func] [%loc] %msg")); +} + +void Configurations::setRemainingToDefault(void) { + base::threading::ScopedLock scopedLock(lock()); +#if defined(ELPP_NO_LOG_TO_FILE) + unsafeSetIfNotExist(Level::Global, ConfigurationType::Enabled, std::string("false")); +#else + unsafeSetIfNotExist(Level::Global, ConfigurationType::Enabled, std::string("true")); +#endif // defined(ELPP_NO_LOG_TO_FILE) + unsafeSetIfNotExist(Level::Global, ConfigurationType::Filename, std::string(base::consts::kDefaultLogFile)); + unsafeSetIfNotExist(Level::Global, ConfigurationType::ToStandardOutput, std::string("true")); + unsafeSetIfNotExist(Level::Global, ConfigurationType::SubsecondPrecision, std::string("3")); + unsafeSetIfNotExist(Level::Global, ConfigurationType::PerformanceTracking, std::string("true")); + unsafeSetIfNotExist(Level::Global, ConfigurationType::MaxLogFileSize, std::string("0")); + unsafeSetIfNotExist(Level::Global, ConfigurationType::Format, std::string("%datetime %level [%logger] %msg")); + unsafeSetIfNotExist(Level::Debug, ConfigurationType::Format, + std::string("%datetime %level [%logger] [%user@%host] [%func] [%loc] %msg")); + // INFO and WARNING are set to default by Level::Global + unsafeSetIfNotExist(Level::Error, ConfigurationType::Format, std::string("%datetime %level [%logger] %msg")); + unsafeSetIfNotExist(Level::Fatal, ConfigurationType::Format, std::string("%datetime %level [%logger] %msg")); + unsafeSetIfNotExist(Level::Verbose, ConfigurationType::Format, std::string("%datetime %level-%vlevel [%logger] %msg")); + unsafeSetIfNotExist(Level::Trace, ConfigurationType::Format, + std::string("%datetime %level [%logger] [%func] [%loc] %msg")); +} + +bool Configurations::Parser::parseFromFile(const std::string& configurationFile, Configurations* sender, + Configurations* base) { + sender->setFromBase(base); + std::ifstream fileStream_(configurationFile.c_str(), std::ifstream::in); + ELPP_ASSERT(fileStream_.is_open(), "Unable to open configuration file [" << configurationFile << "] for parsing."); + bool parsedSuccessfully = false; + std::string line = std::string(); + Level currLevel = Level::Unknown; + std::string currConfigStr = std::string(); + std::string currLevelStr = std::string(); + while (fileStream_.good()) { + std::getline(fileStream_, line); + parsedSuccessfully = parseLine(&line, &currConfigStr, &currLevelStr, &currLevel, sender); + ELPP_ASSERT(parsedSuccessfully, "Unable to parse configuration line: " << line); + } + return parsedSuccessfully; +} + +bool Configurations::Parser::parseFromText(const std::string& configurationsString, Configurations* sender, + Configurations* base) { + sender->setFromBase(base); + bool parsedSuccessfully = false; + std::stringstream ss(configurationsString); + std::string line = std::string(); + Level currLevel = Level::Unknown; + std::string currConfigStr = std::string(); + std::string currLevelStr = std::string(); + while (std::getline(ss, line)) { + parsedSuccessfully = parseLine(&line, &currConfigStr, &currLevelStr, &currLevel, sender); + ELPP_ASSERT(parsedSuccessfully, "Unable to parse configuration line: " << line); + } + return parsedSuccessfully; +} + +void Configurations::Parser::ignoreComments(std::string* line) { + std::size_t foundAt = 0; + std::size_t quotesStart = line->find("\""); + std::size_t quotesEnd = std::string::npos; + if (quotesStart != std::string::npos) { + quotesEnd = line->find("\"", quotesStart + 1); + while (quotesEnd != std::string::npos && line->at(quotesEnd - 1) == '\\') { + // Do not erase slash yet - we will erase it in parseLine(..) while loop + quotesEnd = line->find("\"", quotesEnd + 2); + } + } + if ((foundAt = line->find(base::consts::kConfigurationComment)) != std::string::npos) { + if (foundAt < quotesEnd) { + foundAt = line->find(base::consts::kConfigurationComment, quotesEnd + 1); + } + *line = line->substr(0, foundAt); + } +} + +bool Configurations::Parser::isLevel(const std::string& line) { + return base::utils::Str::startsWith(line, std::string(base::consts::kConfigurationLevel)); +} + +bool Configurations::Parser::isComment(const std::string& line) { + return base::utils::Str::startsWith(line, std::string(base::consts::kConfigurationComment)); +} + +bool Configurations::Parser::isConfig(const std::string& line) { + std::size_t assignment = line.find('='); + return line != "" && + ((line[0] >= 'A' && line[0] <= 'Z') || (line[0] >= 'a' && line[0] <= 'z')) && + (assignment != std::string::npos) && + (line.size() > assignment); +} + +bool Configurations::Parser::parseLine(std::string* line, std::string* currConfigStr, std::string* currLevelStr, + Level* currLevel, + Configurations* conf) { + ConfigurationType currConfig = ConfigurationType::Unknown; + std::string currValue = std::string(); + *line = base::utils::Str::trim(*line); + if (isComment(*line)) return true; + ignoreComments(line); + *line = base::utils::Str::trim(*line); + if (line->empty()) { + // Comment ignored + return true; + } + if (isLevel(*line)) { + if (line->size() <= 2) { + return true; + } + *currLevelStr = line->substr(1, line->size() - 2); + *currLevelStr = base::utils::Str::toUpper(*currLevelStr); + *currLevelStr = base::utils::Str::trim(*currLevelStr); + *currLevel = LevelHelper::convertFromString(currLevelStr->c_str()); + return true; + } + if (isConfig(*line)) { + std::size_t assignment = line->find('='); + *currConfigStr = line->substr(0, assignment); + *currConfigStr = base::utils::Str::toUpper(*currConfigStr); + *currConfigStr = base::utils::Str::trim(*currConfigStr); + currConfig = ConfigurationTypeHelper::convertFromString(currConfigStr->c_str()); + currValue = line->substr(assignment + 1); + currValue = base::utils::Str::trim(currValue); + std::size_t quotesStart = currValue.find("\"", 0); + std::size_t quotesEnd = std::string::npos; + if (quotesStart != std::string::npos) { + quotesEnd = currValue.find("\"", quotesStart + 1); + while (quotesEnd != std::string::npos && currValue.at(quotesEnd - 1) == '\\') { + currValue = currValue.erase(quotesEnd - 1, 1); + quotesEnd = currValue.find("\"", quotesEnd + 2); + } + } + if (quotesStart != std::string::npos && quotesEnd != std::string::npos) { + // Quote provided - check and strip if valid + ELPP_ASSERT((quotesStart < quotesEnd), "Configuration error - No ending quote found in [" + << currConfigStr << "]"); + ELPP_ASSERT((quotesStart + 1 != quotesEnd), "Empty configuration value for [" << currConfigStr << "]"); + if ((quotesStart != quotesEnd) && (quotesStart + 1 != quotesEnd)) { + // Explicit check in case if assertion is disabled + currValue = currValue.substr(quotesStart + 1, quotesEnd - 1); + } + } + } + ELPP_ASSERT(*currLevel != Level::Unknown, "Unrecognized severity level [" << *currLevelStr << "]"); + ELPP_ASSERT(currConfig != ConfigurationType::Unknown, "Unrecognized configuration [" << *currConfigStr << "]"); + if (*currLevel == Level::Unknown || currConfig == ConfigurationType::Unknown) { + return false; // unrecognizable level or config + } + conf->set(*currLevel, currConfig, currValue); + return true; +} + +void Configurations::unsafeSetIfNotExist(Level level, ConfigurationType configurationType, const std::string& value) { + Configuration* conf = RegistryWithPred::get(level, configurationType); + if (conf == nullptr) { + unsafeSet(level, configurationType, value); + } +} + +void Configurations::unsafeSet(Level level, ConfigurationType configurationType, const std::string& value) { + Configuration* conf = RegistryWithPred::get(level, configurationType); + if (conf == nullptr) { + registerNew(new Configuration(level, configurationType, value)); + } else { + conf->setValue(value); + } + if (level == Level::Global) { + unsafeSetGlobally(configurationType, value, false); + } +} + +void Configurations::setGlobally(ConfigurationType configurationType, const std::string& value, + bool includeGlobalLevel) { + if (includeGlobalLevel) { + set(Level::Global, configurationType, value); + } + base::type::EnumType lIndex = LevelHelper::kMinValid; + LevelHelper::forEachLevel(&lIndex, [&](void) -> bool { + set(LevelHelper::castFromInt(lIndex), configurationType, value); + return false; // Do not break lambda function yet as we need to set all levels regardless + }); +} + +void Configurations::unsafeSetGlobally(ConfigurationType configurationType, const std::string& value, + bool includeGlobalLevel) { + if (includeGlobalLevel) { + unsafeSet(Level::Global, configurationType, value); + } + base::type::EnumType lIndex = LevelHelper::kMinValid; + LevelHelper::forEachLevel(&lIndex, [&](void) -> bool { + unsafeSet(LevelHelper::castFromInt(lIndex), configurationType, value); + return false; // Do not break lambda function yet as we need to set all levels regardless + }); +} + +// LogBuilder + +void LogBuilder::convertToColoredOutput(base::type::string_t* logLine, Level level) { + if (!m_termSupportsColor) return; + const base::type::char_t* resetColor = ELPP_LITERAL("\x1b[0m"); + if (level == Level::Error || level == Level::Fatal) + *logLine = ELPP_LITERAL("\x1b[31m") + *logLine + resetColor; + else if (level == Level::Warning) + *logLine = ELPP_LITERAL("\x1b[33m") + *logLine + resetColor; + else if (level == Level::Debug) + *logLine = ELPP_LITERAL("\x1b[32m") + *logLine + resetColor; + else if (level == Level::Info) + *logLine = ELPP_LITERAL("\x1b[36m") + *logLine + resetColor; + else if (level == Level::Trace) + *logLine = ELPP_LITERAL("\x1b[35m") + *logLine + resetColor; +} + +// Logger + +Logger::Logger(const std::string& id, base::LogStreamsReferenceMap* logStreamsReference) : + m_id(id), + m_typedConfigurations(nullptr), + m_parentApplicationName(std::string()), + m_isConfigured(false), + m_logStreamsReference(logStreamsReference) { + initUnflushedCount(); +} + +Logger::Logger(const std::string& id, const Configurations& configurations, + base::LogStreamsReferenceMap* logStreamsReference) : + m_id(id), + m_typedConfigurations(nullptr), + m_parentApplicationName(std::string()), + m_isConfigured(false), + m_logStreamsReference(logStreamsReference) { + initUnflushedCount(); + configure(configurations); +} + +Logger::Logger(const Logger& logger) { + base::utils::safeDelete(m_typedConfigurations); + m_id = logger.m_id; + m_typedConfigurations = logger.m_typedConfigurations; + m_parentApplicationName = logger.m_parentApplicationName; + m_isConfigured = logger.m_isConfigured; + m_configurations = logger.m_configurations; + m_unflushedCount = logger.m_unflushedCount; + m_logStreamsReference = logger.m_logStreamsReference; +} + +Logger& Logger::operator=(const Logger& logger) { + if (&logger != this) { + base::utils::safeDelete(m_typedConfigurations); + m_id = logger.m_id; + m_typedConfigurations = logger.m_typedConfigurations; + m_parentApplicationName = logger.m_parentApplicationName; + m_isConfigured = logger.m_isConfigured; + m_configurations = logger.m_configurations; + m_unflushedCount = logger.m_unflushedCount; + m_logStreamsReference = logger.m_logStreamsReference; + } + return *this; +} + +void Logger::configure(const Configurations& configurations) { + m_isConfigured = false; // we set it to false in case if we fail + initUnflushedCount(); + if (m_typedConfigurations != nullptr) { + Configurations* c = const_cast(m_typedConfigurations->configurations()); + if (c->hasConfiguration(Level::Global, ConfigurationType::Filename)) { + flush(); + } + } + base::threading::ScopedLock scopedLock(lock()); + if (m_configurations != configurations) { + m_configurations.setFromBase(const_cast(&configurations)); + } + base::utils::safeDelete(m_typedConfigurations); + m_typedConfigurations = new base::TypedConfigurations(&m_configurations, m_logStreamsReference); + resolveLoggerFormatSpec(); + m_isConfigured = true; +} + +void Logger::reconfigure(void) { + ELPP_INTERNAL_INFO(1, "Reconfiguring logger [" << m_id << "]"); + configure(m_configurations); +} + +bool Logger::isValidId(const std::string& id) { + for (std::string::const_iterator it = id.begin(); it != id.end(); ++it) { + if (!base::utils::Str::contains(base::consts::kValidLoggerIdSymbols, *it)) { + return false; + } + } + return true; +} + +void Logger::flush(void) { + ELPP_INTERNAL_INFO(3, "Flushing logger [" << m_id << "] all levels"); + base::threading::ScopedLock scopedLock(lock()); + base::type::EnumType lIndex = LevelHelper::kMinValid; + LevelHelper::forEachLevel(&lIndex, [&](void) -> bool { + flush(LevelHelper::castFromInt(lIndex), nullptr); + return false; + }); +} + +void Logger::flush(Level level, base::type::fstream_t* fs) { + if (fs == nullptr && m_typedConfigurations->toFile(level)) { + fs = m_typedConfigurations->fileStream(level); + } + if (fs != nullptr) { + fs->flush(); + std::unordered_map::iterator iter = m_unflushedCount.find(level); + if (iter != m_unflushedCount.end()) { + iter->second = 0; + } + Helpers::validateFileRolling(this, level); + } +} + +void Logger::initUnflushedCount(void) { + m_unflushedCount.clear(); + base::type::EnumType lIndex = LevelHelper::kMinValid; + LevelHelper::forEachLevel(&lIndex, [&](void) -> bool { + m_unflushedCount.insert(std::make_pair(LevelHelper::castFromInt(lIndex), 0)); + return false; + }); +} + +void Logger::resolveLoggerFormatSpec(void) const { + base::type::EnumType lIndex = LevelHelper::kMinValid; + LevelHelper::forEachLevel(&lIndex, [&](void) -> bool { + base::LogFormat* logFormat = + const_cast(&m_typedConfigurations->logFormat(LevelHelper::castFromInt(lIndex))); + base::utils::Str::replaceFirstWithEscape(logFormat->m_format, base::consts::kLoggerIdFormatSpecifier, m_id); + return false; + }); +} + +// el::base +namespace base { + +// el::base::utils +namespace utils { + +// File + +base::type::fstream_t* File::newFileStream(const std::string& filename) { + base::type::fstream_t *fs = new base::type::fstream_t(filename.c_str(), + base::type::fstream_t::out +#if !defined(ELPP_FRESH_LOG_FILE) + | base::type::fstream_t::app +#endif + ); +#if defined(ELPP_UNICODE) + std::locale elppUnicodeLocale(""); +# if ELPP_OS_WINDOWS + std::locale elppUnicodeLocaleWindows(elppUnicodeLocale, new std::codecvt_utf8_utf16); + elppUnicodeLocale = elppUnicodeLocaleWindows; +# endif // ELPP_OS_WINDOWS + fs->imbue(elppUnicodeLocale); +#endif // defined(ELPP_UNICODE) + if (fs->is_open()) { + fs->flush(); + } else { + base::utils::safeDelete(fs); + ELPP_INTERNAL_ERROR("Bad file [" << filename << "]", true); + } + return fs; +} + +std::size_t File::getSizeOfFile(base::type::fstream_t* fs) { + if (fs == nullptr) { + return 0; + } + // Since the file stream is appended to or truncated, the current + // offset is the file size. + std::size_t size = static_cast(fs->tellg()); + return size; +} + +bool File::pathExists(const char* path, bool considerFile) { + if (path == nullptr) { + return false; + } +#if ELPP_OS_UNIX + ELPP_UNUSED(considerFile); + struct stat st; + return (stat(path, &st) == 0); +#elif ELPP_OS_WINDOWS + DWORD fileType = GetFileAttributesA(path); + if (fileType == INVALID_FILE_ATTRIBUTES) { + return false; + } + return considerFile ? true : ((fileType & FILE_ATTRIBUTE_DIRECTORY) == 0 ? false : true); +#endif // ELPP_OS_UNIX +} + +bool File::createPath(const std::string& path) { + if (path.empty()) { + return false; + } + if (base::utils::File::pathExists(path.c_str())) { + return true; + } + int status = -1; + + char* currPath = const_cast(path.c_str()); + std::string builtPath = std::string(); +#if ELPP_OS_UNIX + if (path[0] == '/') { + builtPath = "/"; + } + currPath = STRTOK(currPath, base::consts::kFilePathSeperator, 0); +#elif ELPP_OS_WINDOWS + // Use secure functions API + char* nextTok_ = nullptr; + currPath = STRTOK(currPath, base::consts::kFilePathSeperator, &nextTok_); + ELPP_UNUSED(nextTok_); +#endif // ELPP_OS_UNIX + while (currPath != nullptr) { + builtPath.append(currPath); + builtPath.append(base::consts::kFilePathSeperator); +#if ELPP_OS_UNIX + status = mkdir(builtPath.c_str(), ELPP_LOG_PERMS); + currPath = STRTOK(nullptr, base::consts::kFilePathSeperator, 0); +#elif ELPP_OS_WINDOWS + status = _mkdir(builtPath.c_str()); + currPath = STRTOK(nullptr, base::consts::kFilePathSeperator, &nextTok_); +#endif // ELPP_OS_UNIX + } + if (status == -1) { + ELPP_INTERNAL_ERROR("Error while creating path [" << path << "]", true); + return false; + } + return true; +} + +std::string File::extractPathFromFilename(const std::string& fullPath, const char* separator) { + if ((fullPath == "") || (fullPath.find(separator) == std::string::npos)) { + return fullPath; + } + std::size_t lastSlashAt = fullPath.find_last_of(separator); + if (lastSlashAt == 0) { + return std::string(separator); + } + return fullPath.substr(0, lastSlashAt + 1); +} + +void File::buildStrippedFilename(const char* filename, char buff[], std::size_t limit) { + std::size_t sizeOfFilename = strlen(filename); + if (sizeOfFilename >= limit) { + filename += (sizeOfFilename - limit); + if (filename[0] != '.' && filename[1] != '.') { // prepend if not already + filename += 3; // 3 = '..' + STRCAT(buff, "..", limit); + } + } + STRCAT(buff, filename, limit); +} + +void File::buildBaseFilename(const std::string& fullPath, char buff[], std::size_t limit, const char* separator) { + const char *filename = fullPath.c_str(); + std::size_t lastSlashAt = fullPath.find_last_of(separator); + filename += lastSlashAt ? lastSlashAt+1 : 0; + std::size_t sizeOfFilename = strlen(filename); + if (sizeOfFilename >= limit) { + filename += (sizeOfFilename - limit); + if (filename[0] != '.' && filename[1] != '.') { // prepend if not already + filename += 3; // 3 = '..' + STRCAT(buff, "..", limit); + } + } + STRCAT(buff, filename, limit); +} + +// Str + +bool Str::wildCardMatch(const char* str, const char* pattern) { + while (*pattern) { + switch (*pattern) { + case '?': + if (!*str) + return false; + ++str; + ++pattern; + break; + case '*': + if (wildCardMatch(str, pattern + 1)) + return true; + if (*str && wildCardMatch(str + 1, pattern)) + return true; + return false; + default: + if (*str++ != *pattern++) + return false; + break; + } + } + return !*str && !*pattern; +} + +std::string& Str::ltrim(std::string& str) { + str.erase(str.begin(), std::find_if(str.begin(), str.end(), [](char c) { + return !std::isspace(c); + } )); + return str; +} + +std::string& Str::rtrim(std::string& str) { + str.erase(std::find_if(str.rbegin(), str.rend(), [](char c) { + return !std::isspace(c); + }).base(), str.end()); + return str; +} + +std::string& Str::trim(std::string& str) { + return ltrim(rtrim(str)); +} + +bool Str::startsWith(const std::string& str, const std::string& start) { + return (str.length() >= start.length()) && (str.compare(0, start.length(), start) == 0); +} + +bool Str::endsWith(const std::string& str, const std::string& end) { + return (str.length() >= end.length()) && (str.compare(str.length() - end.length(), end.length(), end) == 0); +} + +std::string& Str::replaceAll(std::string& str, char replaceWhat, char replaceWith) { + std::replace(str.begin(), str.end(), replaceWhat, replaceWith); + return str; +} + +std::string& Str::replaceAll(std::string& str, const std::string& replaceWhat, + const std::string& replaceWith) { + if (replaceWhat == replaceWith) + return str; + std::size_t foundAt = std::string::npos; + while ((foundAt = str.find(replaceWhat, foundAt + 1)) != std::string::npos) { + str.replace(foundAt, replaceWhat.length(), replaceWith); + } + return str; +} + +void Str::replaceFirstWithEscape(base::type::string_t& str, const base::type::string_t& replaceWhat, + const base::type::string_t& replaceWith) { + std::size_t foundAt = base::type::string_t::npos; + while ((foundAt = str.find(replaceWhat, foundAt + 1)) != base::type::string_t::npos) { + if (foundAt > 0 && str[foundAt - 1] == base::consts::kFormatSpecifierChar) { + str.erase(foundAt > 0 ? foundAt - 1 : 0, 1); + ++foundAt; + } else { + str.replace(foundAt, replaceWhat.length(), replaceWith); + return; + } + } +} +#if defined(ELPP_UNICODE) +void Str::replaceFirstWithEscape(base::type::string_t& str, const base::type::string_t& replaceWhat, + const std::string& replaceWith) { + replaceFirstWithEscape(str, replaceWhat, base::type::string_t(replaceWith.begin(), replaceWith.end())); +} +#endif // defined(ELPP_UNICODE) + +std::string& Str::toUpper(std::string& str) { + std::transform(str.begin(), str.end(), str.begin(), + [](char c) { + return static_cast(::toupper(c)); + }); + return str; +} + +bool Str::cStringEq(const char* s1, const char* s2) { + if (s1 == nullptr && s2 == nullptr) return true; + if (s1 == nullptr || s2 == nullptr) return false; + return strcmp(s1, s2) == 0; +} + +bool Str::cStringCaseEq(const char* s1, const char* s2) { + if (s1 == nullptr && s2 == nullptr) return true; + if (s1 == nullptr || s2 == nullptr) return false; + + // With thanks to cygwin for this code + int d = 0; + + while (true) { + const int c1 = toupper(*s1++); + const int c2 = toupper(*s2++); + + if (((d = c1 - c2) != 0) || (c2 == '\0')) { + break; + } + } + + return d == 0; +} + +bool Str::contains(const char* str, char c) { + for (; *str; ++str) { + if (*str == c) + return true; + } + return false; +} + +char* Str::convertAndAddToBuff(std::size_t n, int len, char* buf, const char* bufLim, bool zeroPadded) { + char localBuff[10] = ""; + char* p = localBuff + sizeof(localBuff) - 2; + if (n > 0) { + for (; n > 0 && p > localBuff && len > 0; n /= 10, --len) + *--p = static_cast(n % 10 + '0'); + } else { + *--p = '0'; + --len; + } + if (zeroPadded) + while (p > localBuff && len-- > 0) *--p = static_cast('0'); + return addToBuff(p, buf, bufLim); +} + +char* Str::addToBuff(const char* str, char* buf, const char* bufLim) { + while ((buf < bufLim) && ((*buf = *str++) != '\0')) + ++buf; + return buf; +} + +char* Str::clearBuff(char buff[], std::size_t lim) { + STRCPY(buff, "", lim); + ELPP_UNUSED(lim); // For *nix we dont have anything using lim in above STRCPY macro + return buff; +} + +/// @brief Converst wchar* to char* +/// NOTE: Need to free return value after use! +char* Str::wcharPtrToCharPtr(const wchar_t* line) { + std::size_t len_ = wcslen(line) + 1; + char* buff_ = static_cast(malloc(len_ + 1)); +# if ELPP_OS_UNIX || (ELPP_OS_WINDOWS && !ELPP_CRT_DBG_WARNINGS) + std::wcstombs(buff_, line, len_); +# elif ELPP_OS_WINDOWS + std::size_t convCount_ = 0; + mbstate_t mbState_; + ::memset(static_cast(&mbState_), 0, sizeof(mbState_)); + wcsrtombs_s(&convCount_, buff_, len_, &line, len_, &mbState_); +# endif // ELPP_OS_UNIX || (ELPP_OS_WINDOWS && !ELPP_CRT_DBG_WARNINGS) + return buff_; +} + +// OS + +#if ELPP_OS_WINDOWS +/// @brief Gets environment variables for Windows based OS. +/// We are not using getenv(const char*) because of CRT deprecation +/// @param varname Variable name to get environment variable value for +/// @return If variable exist the value of it otherwise nullptr +const char* OS::getWindowsEnvironmentVariable(const char* varname) { + const DWORD bufferLen = 50; + static char buffer[bufferLen]; + if (GetEnvironmentVariableA(varname, buffer, bufferLen)) { + return buffer; + } + return nullptr; +} +#endif // ELPP_OS_WINDOWS +#if ELPP_OS_ANDROID +std::string OS::getProperty(const char* prop) { + char propVal[PROP_VALUE_MAX + 1]; + int ret = __system_property_get(prop, propVal); + return ret == 0 ? std::string() : std::string(propVal); +} + +std::string OS::getDeviceName(void) { + std::stringstream ss; + std::string manufacturer = getProperty("ro.product.manufacturer"); + std::string model = getProperty("ro.product.model"); + if (manufacturer.empty() || model.empty()) { + return std::string(); + } + ss << manufacturer << "-" << model; + return ss.str(); +} +#endif // ELPP_OS_ANDROID + +const std::string OS::getBashOutput(const char* command) { +#if (ELPP_OS_UNIX && !ELPP_OS_ANDROID && !ELPP_CYGWIN) + if (command == nullptr) { + return std::string(); + } + FILE* proc = nullptr; + if ((proc = popen(command, "r")) == nullptr) { + ELPP_INTERNAL_ERROR("\nUnable to run command [" << command << "]", true); + return std::string(); + } + char hBuff[4096]; + if (fgets(hBuff, sizeof(hBuff), proc) != nullptr) { + pclose(proc); + const std::size_t buffLen = strlen(hBuff); + if (buffLen > 0 && hBuff[buffLen - 1] == '\n') { + hBuff[buffLen - 1] = '\0'; + } + return std::string(hBuff); + } else { + pclose(proc); + } + return std::string(); +#else + ELPP_UNUSED(command); + return std::string(); +#endif // (ELPP_OS_UNIX && !ELPP_OS_ANDROID && !ELPP_CYGWIN) +} + +std::string OS::getEnvironmentVariable(const char* variableName, const char* defaultVal, + const char* alternativeBashCommand) { +#if ELPP_OS_UNIX + const char* val = getenv(variableName); +#elif ELPP_OS_WINDOWS + const char* val = getWindowsEnvironmentVariable(variableName); +#endif // ELPP_OS_UNIX + if ((val == nullptr) || ((strcmp(val, "") == 0))) { +#if ELPP_OS_UNIX && defined(ELPP_FORCE_ENV_VAR_FROM_BASH) + // Try harder on unix-based systems + std::string valBash = base::utils::OS::getBashOutput(alternativeBashCommand); + if (valBash.empty()) { + return std::string(defaultVal); + } else { + return valBash; + } +#elif ELPP_OS_WINDOWS || ELPP_OS_UNIX + ELPP_UNUSED(alternativeBashCommand); + return std::string(defaultVal); +#endif // ELPP_OS_UNIX && defined(ELPP_FORCE_ENV_VAR_FROM_BASH) + } + return std::string(val); +} + +std::string OS::currentUser(void) { +#if ELPP_OS_UNIX && !ELPP_OS_ANDROID + return getEnvironmentVariable("USER", base::consts::kUnknownUser, "whoami"); +#elif ELPP_OS_WINDOWS + return getEnvironmentVariable("USERNAME", base::consts::kUnknownUser); +#elif ELPP_OS_ANDROID + ELPP_UNUSED(base::consts::kUnknownUser); + return std::string("android"); +#else + return std::string(); +#endif // ELPP_OS_UNIX && !ELPP_OS_ANDROID +} + +std::string OS::currentHost(void) { +#if ELPP_OS_UNIX && !ELPP_OS_ANDROID + return getEnvironmentVariable("HOSTNAME", base::consts::kUnknownHost, "hostname"); +#elif ELPP_OS_WINDOWS + return getEnvironmentVariable("COMPUTERNAME", base::consts::kUnknownHost); +#elif ELPP_OS_ANDROID + ELPP_UNUSED(base::consts::kUnknownHost); + return getDeviceName(); +#else + return std::string(); +#endif // ELPP_OS_UNIX && !ELPP_OS_ANDROID +} + +bool OS::termSupportsColor(void) { + std::string term = getEnvironmentVariable("TERM", ""); + return term == "xterm" || term == "xterm-color" || term == "xterm-256color" + || term == "screen" || term == "linux" || term == "cygwin" + || term == "screen-256color"; +} + +// DateTime + +void DateTime::gettimeofday(struct timeval* tv) { +#if ELPP_OS_WINDOWS + if (tv != nullptr) { +# if ELPP_COMPILER_MSVC || defined(_MSC_EXTENSIONS) + const unsigned __int64 delta_ = 11644473600000000Ui64; +# else + const unsigned __int64 delta_ = 11644473600000000ULL; +# endif // ELPP_COMPILER_MSVC || defined(_MSC_EXTENSIONS) + const double secOffSet = 0.000001; + const unsigned long usecOffSet = 1000000; + FILETIME fileTime; + GetSystemTimeAsFileTime(&fileTime); + unsigned __int64 present = 0; + present |= fileTime.dwHighDateTime; + present = present << 32; + present |= fileTime.dwLowDateTime; + present /= 10; // mic-sec + // Subtract the difference + present -= delta_; + tv->tv_sec = static_cast(present * secOffSet); + tv->tv_usec = static_cast(present % usecOffSet); + } +#else + ::gettimeofday(tv, nullptr); +#endif // ELPP_OS_WINDOWS +} + +std::string DateTime::getDateTime(const char* format, const base::SubsecondPrecision* ssPrec) { + struct timeval currTime; + gettimeofday(&currTime); + return timevalToString(currTime, format, ssPrec); +} + +std::string DateTime::timevalToString(struct timeval tval, const char* format, + const el::base::SubsecondPrecision* ssPrec) { + struct ::tm timeInfo; + buildTimeInfo(&tval, &timeInfo); + const int kBuffSize = 30; + char buff_[kBuffSize] = ""; + parseFormat(buff_, kBuffSize, format, &timeInfo, static_cast(tval.tv_usec / ssPrec->m_offset), + ssPrec); + return std::string(buff_); +} + +base::type::string_t DateTime::formatTime(unsigned long long time, base::TimestampUnit timestampUnit) { + base::type::EnumType start = static_cast(timestampUnit); + const base::type::char_t* unit = base::consts::kTimeFormats[start].unit; + for (base::type::EnumType i = start; i < base::consts::kTimeFormatsCount - 1; ++i) { + if (time <= base::consts::kTimeFormats[i].value) { + break; + } + if (base::consts::kTimeFormats[i].value == 1000.0f && time / 1000.0f < 1.9f) { + break; + } + time /= static_cast(base::consts::kTimeFormats[i].value); + unit = base::consts::kTimeFormats[i + 1].unit; + } + base::type::stringstream_t ss; + ss << time << " " << unit; + return ss.str(); +} + +unsigned long long DateTime::getTimeDifference(const struct timeval& endTime, const struct timeval& startTime, + base::TimestampUnit timestampUnit) { + if (timestampUnit == base::TimestampUnit::Microsecond) { + return static_cast(static_cast(1000000 * endTime.tv_sec + endTime.tv_usec) - + static_cast(1000000 * startTime.tv_sec + startTime.tv_usec)); + } + // milliseconds + auto conv = [](const struct timeval& tim) { + return static_cast((tim.tv_sec * 1000) + (tim.tv_usec / 1000)); + }; + return static_cast(conv(endTime) - conv(startTime)); +} + +struct ::tm* DateTime::buildTimeInfo(struct timeval* currTime, struct ::tm* timeInfo) { +#if ELPP_OS_UNIX + time_t rawTime = currTime->tv_sec; + ::elpptime_r(&rawTime, timeInfo); + return timeInfo; +#else +# if ELPP_COMPILER_MSVC + ELPP_UNUSED(currTime); + time_t t; +# if defined(_USE_32BIT_TIME_T) + _time32(&t); +# else + _time64(&t); +# endif + elpptime_s(timeInfo, &t); + return timeInfo; +# else + // For any other compilers that don't have CRT warnings issue e.g, MinGW or TDM GCC- we use different method + time_t rawTime = currTime->tv_sec; + struct tm* tmInf = elpptime(&rawTime); + *timeInfo = *tmInf; + return timeInfo; +# endif // ELPP_COMPILER_MSVC +#endif // ELPP_OS_UNIX +} + +char* DateTime::parseFormat(char* buf, std::size_t bufSz, const char* format, const struct tm* tInfo, + std::size_t msec, const base::SubsecondPrecision* ssPrec) { + const char* bufLim = buf + bufSz; + for (; *format; ++format) { + if (*format == base::consts::kFormatSpecifierChar) { + switch (*++format) { + case base::consts::kFormatSpecifierChar: // Escape + break; + case '\0': // End + --format; + break; + case 'd': // Day + buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_mday, 2, buf, bufLim); + continue; + case 'a': // Day of week (short) + buf = base::utils::Str::addToBuff(base::consts::kDaysAbbrev[tInfo->tm_wday], buf, bufLim); + continue; + case 'A': // Day of week (long) + buf = base::utils::Str::addToBuff(base::consts::kDays[tInfo->tm_wday], buf, bufLim); + continue; + case 'M': // month + buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_mon + 1, 2, buf, bufLim); + continue; + case 'b': // month (short) + buf = base::utils::Str::addToBuff(base::consts::kMonthsAbbrev[tInfo->tm_mon], buf, bufLim); + continue; + case 'B': // month (long) + buf = base::utils::Str::addToBuff(base::consts::kMonths[tInfo->tm_mon], buf, bufLim); + continue; + case 'y': // year (two digits) + buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_year + base::consts::kYearBase, 2, buf, bufLim); + continue; + case 'Y': // year (four digits) + buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_year + base::consts::kYearBase, 4, buf, bufLim); + continue; + case 'h': // hour (12-hour) + buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_hour % 12, 2, buf, bufLim); + continue; + case 'H': // hour (24-hour) + buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_hour, 2, buf, bufLim); + continue; + case 'm': // minute + buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_min, 2, buf, bufLim); + continue; + case 's': // second + buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_sec, 2, buf, bufLim); + continue; + case 'z': // subsecond part + case 'g': + buf = base::utils::Str::convertAndAddToBuff(msec, ssPrec->m_width, buf, bufLim); + continue; + case 'F': // AM/PM + buf = base::utils::Str::addToBuff((tInfo->tm_hour >= 12) ? base::consts::kPm : base::consts::kAm, buf, bufLim); + continue; + default: + continue; + } + } + if (buf == bufLim) break; + *buf++ = *format; + } + return buf; +} + +// CommandLineArgs + +void CommandLineArgs::setArgs(int argc, char** argv) { + m_params.clear(); + m_paramsWithValue.clear(); + if (argc == 0 || argv == nullptr) { + return; + } + m_argc = argc; + m_argv = argv; + for (int i = 1; i < m_argc; ++i) { + const char* v = (strstr(m_argv[i], "=")); + if (v != nullptr && strlen(v) > 0) { + std::string key = std::string(m_argv[i]); + key = key.substr(0, key.find_first_of('=')); + if (hasParamWithValue(key.c_str())) { + ELPP_INTERNAL_INFO(1, "Skipping [" << key << "] arg since it already has value [" + << getParamValue(key.c_str()) << "]"); + } else { + m_paramsWithValue.insert(std::make_pair(key, std::string(v + 1))); + } + } + if (v == nullptr) { + if (hasParam(m_argv[i])) { + ELPP_INTERNAL_INFO(1, "Skipping [" << m_argv[i] << "] arg since it already exists"); + } else { + m_params.push_back(std::string(m_argv[i])); + } + } + } +} + +bool CommandLineArgs::hasParamWithValue(const char* paramKey) const { + return m_paramsWithValue.find(std::string(paramKey)) != m_paramsWithValue.end(); +} + +const char* CommandLineArgs::getParamValue(const char* paramKey) const { + std::unordered_map::const_iterator iter = m_paramsWithValue.find(std::string(paramKey)); + return iter != m_paramsWithValue.end() ? iter->second.c_str() : ""; +} + +bool CommandLineArgs::hasParam(const char* paramKey) const { + return std::find(m_params.begin(), m_params.end(), std::string(paramKey)) != m_params.end(); +} + +bool CommandLineArgs::empty(void) const { + return m_params.empty() && m_paramsWithValue.empty(); +} + +std::size_t CommandLineArgs::size(void) const { + return m_params.size() + m_paramsWithValue.size(); +} + +base::type::ostream_t& operator<<(base::type::ostream_t& os, const CommandLineArgs& c) { + for (int i = 1; i < c.m_argc; ++i) { + os << ELPP_LITERAL("[") << c.m_argv[i] << ELPP_LITERAL("]"); + if (i < c.m_argc - 1) { + os << ELPP_LITERAL(" "); + } + } + return os; +} + +} // namespace utils + +// el::base::threading +namespace threading { + +#if ELPP_THREADING_ENABLED +# if ELPP_USE_STD_THREADING +# if ELPP_ASYNC_LOGGING +static void msleep(int ms) { + // Only when async logging enabled - this is because async is strict on compiler +# if defined(ELPP_NO_SLEEP_FOR) + usleep(ms * 1000); +# else + std::this_thread::sleep_for(std::chrono::milliseconds(ms)); +# endif // defined(ELPP_NO_SLEEP_FOR) +} +# endif // ELPP_ASYNC_LOGGING +# endif // !ELPP_USE_STD_THREADING +#endif // ELPP_THREADING_ENABLED + +} // namespace threading + +// el::base + +// SubsecondPrecision + +void SubsecondPrecision::init(int width) { + if (width < 1 || width > 6) { + width = base::consts::kDefaultSubsecondPrecision; + } + m_width = width; + switch (m_width) { + case 3: + m_offset = 1000; + break; + case 4: + m_offset = 100; + break; + case 5: + m_offset = 10; + break; + case 6: + m_offset = 1; + break; + default: + m_offset = 1000; + break; + } +} + +// LogFormat + +LogFormat::LogFormat(void) : + m_level(Level::Unknown), + m_userFormat(base::type::string_t()), + m_format(base::type::string_t()), + m_dateTimeFormat(std::string()), + m_flags(0x0), + m_currentUser(base::utils::OS::currentUser()), + m_currentHost(base::utils::OS::currentHost()) { +} + +LogFormat::LogFormat(Level level, const base::type::string_t& format) + : m_level(level), m_userFormat(format), m_currentUser(base::utils::OS::currentUser()), + m_currentHost(base::utils::OS::currentHost()) { + parseFromFormat(m_userFormat); +} + +LogFormat::LogFormat(const LogFormat& logFormat): + m_level(logFormat.m_level), + m_userFormat(logFormat.m_userFormat), + m_format(logFormat.m_format), + m_dateTimeFormat(logFormat.m_dateTimeFormat), + m_flags(logFormat.m_flags), + m_currentUser(logFormat.m_currentUser), + m_currentHost(logFormat.m_currentHost) { +} + +LogFormat::LogFormat(LogFormat&& logFormat) { + m_level = std::move(logFormat.m_level); + m_userFormat = std::move(logFormat.m_userFormat); + m_format = std::move(logFormat.m_format); + m_dateTimeFormat = std::move(logFormat.m_dateTimeFormat); + m_flags = std::move(logFormat.m_flags); + m_currentUser = std::move(logFormat.m_currentUser); + m_currentHost = std::move(logFormat.m_currentHost); +} + +LogFormat& LogFormat::operator=(const LogFormat& logFormat) { + if (&logFormat != this) { + m_level = logFormat.m_level; + m_userFormat = logFormat.m_userFormat; + m_dateTimeFormat = logFormat.m_dateTimeFormat; + m_flags = logFormat.m_flags; + m_currentUser = logFormat.m_currentUser; + m_currentHost = logFormat.m_currentHost; + } + return *this; +} + +bool LogFormat::operator==(const LogFormat& other) { + return m_level == other.m_level && m_userFormat == other.m_userFormat && m_format == other.m_format && + m_dateTimeFormat == other.m_dateTimeFormat && m_flags == other.m_flags; +} + +/// @brief Updates format to be used while logging. +/// @param userFormat User provided format +void LogFormat::parseFromFormat(const base::type::string_t& userFormat) { + // We make copy because we will be changing the format + // i.e, removing user provided date format from original format + // and then storing it. + base::type::string_t formatCopy = userFormat; + m_flags = 0x0; + auto conditionalAddFlag = [&](const base::type::char_t* specifier, base::FormatFlags flag) { + std::size_t foundAt = base::type::string_t::npos; + while ((foundAt = formatCopy.find(specifier, foundAt + 1)) != base::type::string_t::npos) { + if (foundAt > 0 && formatCopy[foundAt - 1] == base::consts::kFormatSpecifierChar) { + if (hasFlag(flag)) { + // If we already have flag we remove the escape chars so that '%%' is turned to '%' + // even after specifier resolution - this is because we only replaceFirst specifier + formatCopy.erase(foundAt > 0 ? foundAt - 1 : 0, 1); + ++foundAt; + } + } else { + if (!hasFlag(flag)) addFlag(flag); + } + } + }; + conditionalAddFlag(base::consts::kAppNameFormatSpecifier, base::FormatFlags::AppName); + conditionalAddFlag(base::consts::kSeverityLevelFormatSpecifier, base::FormatFlags::Level); + conditionalAddFlag(base::consts::kSeverityLevelShortFormatSpecifier, base::FormatFlags::LevelShort); + conditionalAddFlag(base::consts::kLoggerIdFormatSpecifier, base::FormatFlags::LoggerId); + conditionalAddFlag(base::consts::kThreadIdFormatSpecifier, base::FormatFlags::ThreadId); + conditionalAddFlag(base::consts::kLogFileFormatSpecifier, base::FormatFlags::File); + conditionalAddFlag(base::consts::kLogFileBaseFormatSpecifier, base::FormatFlags::FileBase); + conditionalAddFlag(base::consts::kLogLineFormatSpecifier, base::FormatFlags::Line); + conditionalAddFlag(base::consts::kLogLocationFormatSpecifier, base::FormatFlags::Location); + conditionalAddFlag(base::consts::kLogFunctionFormatSpecifier, base::FormatFlags::Function); + conditionalAddFlag(base::consts::kCurrentUserFormatSpecifier, base::FormatFlags::User); + conditionalAddFlag(base::consts::kCurrentHostFormatSpecifier, base::FormatFlags::Host); + conditionalAddFlag(base::consts::kMessageFormatSpecifier, base::FormatFlags::LogMessage); + conditionalAddFlag(base::consts::kVerboseLevelFormatSpecifier, base::FormatFlags::VerboseLevel); + // For date/time we need to extract user's date format first + std::size_t dateIndex = std::string::npos; + if ((dateIndex = formatCopy.find(base::consts::kDateTimeFormatSpecifier)) != std::string::npos) { + while (dateIndex > 0 && formatCopy[dateIndex - 1] == base::consts::kFormatSpecifierChar) { + dateIndex = formatCopy.find(base::consts::kDateTimeFormatSpecifier, dateIndex + 1); + } + if (dateIndex != std::string::npos) { + addFlag(base::FormatFlags::DateTime); + updateDateFormat(dateIndex, formatCopy); + } + } + m_format = formatCopy; + updateFormatSpec(); +} + +void LogFormat::updateDateFormat(std::size_t index, base::type::string_t& currFormat) { + if (hasFlag(base::FormatFlags::DateTime)) { + index += ELPP_STRLEN(base::consts::kDateTimeFormatSpecifier); + } + const base::type::char_t* ptr = currFormat.c_str() + index; + if ((currFormat.size() > index) && (ptr[0] == '{')) { + // User has provided format for date/time + ++ptr; + int count = 1; // Start by 1 in order to remove starting brace + std::stringstream ss; + for (; *ptr; ++ptr, ++count) { + if (*ptr == '}') { + ++count; // In order to remove ending brace + break; + } + ss << static_cast(*ptr); + } + currFormat.erase(index, count); + m_dateTimeFormat = ss.str(); + } else { + // No format provided, use default + if (hasFlag(base::FormatFlags::DateTime)) { + m_dateTimeFormat = std::string(base::consts::kDefaultDateTimeFormat); + } + } +} + +void LogFormat::updateFormatSpec(void) { + // Do not use switch over strongly typed enums because Intel C++ compilers dont support them yet. + if (m_level == Level::Debug) { + base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelFormatSpecifier, + base::consts::kDebugLevelLogValue); + base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelShortFormatSpecifier, + base::consts::kDebugLevelShortLogValue); + } else if (m_level == Level::Info) { + base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelFormatSpecifier, + base::consts::kInfoLevelLogValue); + base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelShortFormatSpecifier, + base::consts::kInfoLevelShortLogValue); + } else if (m_level == Level::Warning) { + base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelFormatSpecifier, + base::consts::kWarningLevelLogValue); + base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelShortFormatSpecifier, + base::consts::kWarningLevelShortLogValue); + } else if (m_level == Level::Error) { + base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelFormatSpecifier, + base::consts::kErrorLevelLogValue); + base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelShortFormatSpecifier, + base::consts::kErrorLevelShortLogValue); + } else if (m_level == Level::Fatal) { + base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelFormatSpecifier, + base::consts::kFatalLevelLogValue); + base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelShortFormatSpecifier, + base::consts::kFatalLevelShortLogValue); + } else if (m_level == Level::Verbose) { + base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelFormatSpecifier, + base::consts::kVerboseLevelLogValue); + base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelShortFormatSpecifier, + base::consts::kVerboseLevelShortLogValue); + } else if (m_level == Level::Trace) { + base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelFormatSpecifier, + base::consts::kTraceLevelLogValue); + base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kSeverityLevelShortFormatSpecifier, + base::consts::kTraceLevelShortLogValue); + } + if (hasFlag(base::FormatFlags::User)) { + base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kCurrentUserFormatSpecifier, + m_currentUser); + } + if (hasFlag(base::FormatFlags::Host)) { + base::utils::Str::replaceFirstWithEscape(m_format, base::consts::kCurrentHostFormatSpecifier, + m_currentHost); + } + // Ignore Level::Global and Level::Unknown +} + +// TypedConfigurations + +TypedConfigurations::TypedConfigurations(Configurations* configurations, + base::LogStreamsReferenceMap* logStreamsReference) { + m_configurations = configurations; + m_logStreamsReference = logStreamsReference; + build(m_configurations); +} + +TypedConfigurations::TypedConfigurations(const TypedConfigurations& other) { + this->m_configurations = other.m_configurations; + this->m_logStreamsReference = other.m_logStreamsReference; + build(m_configurations); +} + +bool TypedConfigurations::enabled(Level level) { + return getConfigByVal(level, &m_enabledMap, "enabled"); +} + +bool TypedConfigurations::toFile(Level level) { + return getConfigByVal(level, &m_toFileMap, "toFile"); +} + +const std::string& TypedConfigurations::filename(Level level) { + return getConfigByRef(level, &m_filenameMap, "filename"); +} + +bool TypedConfigurations::toStandardOutput(Level level) { + return getConfigByVal(level, &m_toStandardOutputMap, "toStandardOutput"); +} + +const base::LogFormat& TypedConfigurations::logFormat(Level level) { + return getConfigByRef(level, &m_logFormatMap, "logFormat"); +} + +const base::SubsecondPrecision& TypedConfigurations::subsecondPrecision(Level level) { + return getConfigByRef(level, &m_subsecondPrecisionMap, "subsecondPrecision"); +} + +const base::MillisecondsWidth& TypedConfigurations::millisecondsWidth(Level level) { + return getConfigByRef(level, &m_subsecondPrecisionMap, "millisecondsWidth"); +} + +bool TypedConfigurations::performanceTracking(Level level) { + return getConfigByVal(level, &m_performanceTrackingMap, "performanceTracking"); +} + +base::type::fstream_t* TypedConfigurations::fileStream(Level level) { + return getConfigByRef(level, &m_fileStreamMap, "fileStream").get(); +} + +std::size_t TypedConfigurations::maxLogFileSize(Level level) { + return getConfigByVal(level, &m_maxLogFileSizeMap, "maxLogFileSize"); +} + +std::size_t TypedConfigurations::logFlushThreshold(Level level) { + return getConfigByVal(level, &m_logFlushThresholdMap, "logFlushThreshold"); +} + +void TypedConfigurations::build(Configurations* configurations) { + base::threading::ScopedLock scopedLock(lock()); + auto getBool = [] (std::string boolStr) -> bool { // Pass by value for trimming + base::utils::Str::trim(boolStr); + return (boolStr == "TRUE" || boolStr == "true" || boolStr == "1"); + }; + std::vector withFileSizeLimit; + for (Configurations::const_iterator it = configurations->begin(); it != configurations->end(); ++it) { + Configuration* conf = *it; + // We cannot use switch on strong enums because Intel C++ dont support them yet + if (conf->configurationType() == ConfigurationType::Enabled) { + setValue(conf->level(), getBool(conf->value()), &m_enabledMap); + } else if (conf->configurationType() == ConfigurationType::ToFile) { + setValue(conf->level(), getBool(conf->value()), &m_toFileMap); + } else if (conf->configurationType() == ConfigurationType::ToStandardOutput) { + setValue(conf->level(), getBool(conf->value()), &m_toStandardOutputMap); + } else if (conf->configurationType() == ConfigurationType::Filename) { + // We do not yet configure filename but we will configure in another + // loop. This is because if file cannot be created, we will force ToFile + // to be false. Because configuring logger is not necessarily performance + // sensative operation, we can live with another loop; (by the way this loop + // is not very heavy either) + } else if (conf->configurationType() == ConfigurationType::Format) { + setValue(conf->level(), base::LogFormat(conf->level(), + base::type::string_t(conf->value().begin(), conf->value().end())), &m_logFormatMap); + } else if (conf->configurationType() == ConfigurationType::SubsecondPrecision) { + setValue(Level::Global, + base::SubsecondPrecision(static_cast(getULong(conf->value()))), &m_subsecondPrecisionMap); + } else if (conf->configurationType() == ConfigurationType::PerformanceTracking) { + setValue(Level::Global, getBool(conf->value()), &m_performanceTrackingMap); + } else if (conf->configurationType() == ConfigurationType::MaxLogFileSize) { + auto v = getULong(conf->value()); + setValue(conf->level(), static_cast(v), &m_maxLogFileSizeMap); + if (v != 0) { + withFileSizeLimit.push_back(conf); + } + } else if (conf->configurationType() == ConfigurationType::LogFlushThreshold) { + setValue(conf->level(), static_cast(getULong(conf->value())), &m_logFlushThresholdMap); + } + } + // As mentioned earlier, we will now set filename configuration in separate loop to deal with non-existent files + for (Configurations::const_iterator it = configurations->begin(); it != configurations->end(); ++it) { + Configuration* conf = *it; + if (conf->configurationType() == ConfigurationType::Filename) { + insertFile(conf->level(), conf->value()); + } + } + for (std::vector::iterator conf = withFileSizeLimit.begin(); + conf != withFileSizeLimit.end(); ++conf) { + // This is not unsafe as mutex is locked in currect scope + unsafeValidateFileRolling((*conf)->level(), base::defaultPreRollOutCallback); + } +} + +unsigned long TypedConfigurations::getULong(std::string confVal) { + bool valid = true; + base::utils::Str::trim(confVal); + valid = !confVal.empty() && std::find_if(confVal.begin(), confVal.end(), + [](char c) { + return !base::utils::Str::isDigit(c); + }) == confVal.end(); + if (!valid) { + valid = false; + ELPP_ASSERT(valid, "Configuration value not a valid integer [" << confVal << "]"); + return 0; + } + return atol(confVal.c_str()); +} + +std::string TypedConfigurations::resolveFilename(const std::string& filename) { + std::string resultingFilename = filename; + std::size_t dateIndex = std::string::npos; + std::string dateTimeFormatSpecifierStr = std::string(base::consts::kDateTimeFormatSpecifierForFilename); + if ((dateIndex = resultingFilename.find(dateTimeFormatSpecifierStr.c_str())) != std::string::npos) { + while (dateIndex > 0 && resultingFilename[dateIndex - 1] == base::consts::kFormatSpecifierChar) { + dateIndex = resultingFilename.find(dateTimeFormatSpecifierStr.c_str(), dateIndex + 1); + } + if (dateIndex != std::string::npos) { + const char* ptr = resultingFilename.c_str() + dateIndex; + // Goto end of specifier + ptr += dateTimeFormatSpecifierStr.size(); + std::string fmt; + if ((resultingFilename.size() > dateIndex) && (ptr[0] == '{')) { + // User has provided format for date/time + ++ptr; + int count = 1; // Start by 1 in order to remove starting brace + std::stringstream ss; + for (; *ptr; ++ptr, ++count) { + if (*ptr == '}') { + ++count; // In order to remove ending brace + break; + } + ss << *ptr; + } + resultingFilename.erase(dateIndex + dateTimeFormatSpecifierStr.size(), count); + fmt = ss.str(); + } else { + fmt = std::string(base::consts::kDefaultDateTimeFormatInFilename); + } + base::SubsecondPrecision ssPrec(3); + std::string now = base::utils::DateTime::getDateTime(fmt.c_str(), &ssPrec); + base::utils::Str::replaceAll(now, '/', '-'); // Replace path element since we are dealing with filename + base::utils::Str::replaceAll(resultingFilename, dateTimeFormatSpecifierStr, now); + } + } + return resultingFilename; +} + +void TypedConfigurations::insertFile(Level level, const std::string& fullFilename) { + std::string resolvedFilename = resolveFilename(fullFilename); + if (resolvedFilename.empty()) { + std::cerr << "Could not load empty file for logging, please re-check your configurations for level [" + << LevelHelper::convertToString(level) << "]"; + } + std::string filePath = base::utils::File::extractPathFromFilename(resolvedFilename, base::consts::kFilePathSeperator); + if (filePath.size() < resolvedFilename.size()) { + base::utils::File::createPath(filePath); + } + auto create = [&](Level level) { + base::LogStreamsReferenceMap::iterator filestreamIter = m_logStreamsReference->find(resolvedFilename); + base::type::fstream_t* fs = nullptr; + if (filestreamIter == m_logStreamsReference->end()) { + // We need a completely new stream, nothing to share with + fs = base::utils::File::newFileStream(resolvedFilename); + m_filenameMap.insert(std::make_pair(level, resolvedFilename)); + m_fileStreamMap.insert(std::make_pair(level, base::FileStreamPtr(fs))); + m_logStreamsReference->insert(std::make_pair(resolvedFilename, base::FileStreamPtr(m_fileStreamMap.at(level)))); + } else { + // Woops! we have an existing one, share it! + m_filenameMap.insert(std::make_pair(level, filestreamIter->first)); + m_fileStreamMap.insert(std::make_pair(level, base::FileStreamPtr(filestreamIter->second))); + fs = filestreamIter->second.get(); + } + if (fs == nullptr) { + // We display bad file error from newFileStream() + ELPP_INTERNAL_ERROR("Setting [TO_FILE] of [" + << LevelHelper::convertToString(level) << "] to FALSE", false); + setValue(level, false, &m_toFileMap); + } + }; + // If we dont have file conf for any level, create it for Level::Global first + // otherwise create for specified level + create(m_filenameMap.empty() && m_fileStreamMap.empty() ? Level::Global : level); +} + +bool TypedConfigurations::unsafeValidateFileRolling(Level level, const PreRollOutCallback& preRollOutCallback) { + base::type::fstream_t* fs = unsafeGetConfigByRef(level, &m_fileStreamMap, "fileStream").get(); + if (fs == nullptr) { + return true; + } + std::size_t maxLogFileSize = unsafeGetConfigByVal(level, &m_maxLogFileSizeMap, "maxLogFileSize"); + std::size_t currFileSize = base::utils::File::getSizeOfFile(fs); + if (maxLogFileSize != 0 && currFileSize >= maxLogFileSize) { + std::string fname = unsafeGetConfigByRef(level, &m_filenameMap, "filename"); + ELPP_INTERNAL_INFO(1, "Truncating log file [" << fname << "] as a result of configurations for level [" + << LevelHelper::convertToString(level) << "]"); + fs->close(); + preRollOutCallback(fname.c_str(), currFileSize); + fs->open(fname, std::fstream::out | std::fstream::trunc); + return true; + } + return false; +} + +// RegisteredHitCounters + +bool RegisteredHitCounters::validateEveryN(const char* filename, base::type::LineNumber lineNumber, std::size_t n) { + base::threading::ScopedLock scopedLock(lock()); + base::HitCounter* counter = get(filename, lineNumber); + if (counter == nullptr) { + registerNew(counter = new base::HitCounter(filename, lineNumber)); + } + counter->validateHitCounts(n); + bool result = (n >= 1 && counter->hitCounts() != 0 && counter->hitCounts() % n == 0); + return result; +} + +/// @brief Validates counter for hits >= N, i.e, registers new if does not exist otherwise updates original one +/// @return True if validation resulted in triggering hit. Meaning logs should be written everytime true is returned +bool RegisteredHitCounters::validateAfterN(const char* filename, base::type::LineNumber lineNumber, std::size_t n) { + base::threading::ScopedLock scopedLock(lock()); + base::HitCounter* counter = get(filename, lineNumber); + if (counter == nullptr) { + registerNew(counter = new base::HitCounter(filename, lineNumber)); + } + // Do not use validateHitCounts here since we do not want to reset counter here + // Note the >= instead of > because we are incrementing + // after this check + if (counter->hitCounts() >= n) + return true; + counter->increment(); + return false; +} + +/// @brief Validates counter for hits are <= n, i.e, registers new if does not exist otherwise updates original one +/// @return True if validation resulted in triggering hit. Meaning logs should be written everytime true is returned +bool RegisteredHitCounters::validateNTimes(const char* filename, base::type::LineNumber lineNumber, std::size_t n) { + base::threading::ScopedLock scopedLock(lock()); + base::HitCounter* counter = get(filename, lineNumber); + if (counter == nullptr) { + registerNew(counter = new base::HitCounter(filename, lineNumber)); + } + counter->increment(); + // Do not use validateHitCounts here since we do not want to reset counter here + if (counter->hitCounts() <= n) + return true; + return false; +} + +// RegisteredLoggers + +RegisteredLoggers::RegisteredLoggers(const LogBuilderPtr& defaultLogBuilder) : + m_defaultLogBuilder(defaultLogBuilder) { + m_defaultConfigurations.setToDefault(); +} + +Logger* RegisteredLoggers::get(const std::string& id, bool forceCreation) { + base::threading::ScopedLock scopedLock(lock()); + Logger* logger_ = base::utils::Registry::get(id); + if (logger_ == nullptr && forceCreation) { + bool validId = Logger::isValidId(id); + if (!validId) { + ELPP_ASSERT(validId, "Invalid logger ID [" << id << "]. Not registering this logger."); + return nullptr; + } + logger_ = new Logger(id, m_defaultConfigurations, &m_logStreamsReference); + logger_->m_logBuilder = m_defaultLogBuilder; + registerNew(id, logger_); + LoggerRegistrationCallback* callback = nullptr; + for (const std::pair& h + : m_loggerRegistrationCallbacks) { + callback = h.second.get(); + if (callback != nullptr && callback->enabled()) { + callback->handle(logger_); + } + } + } + return logger_; +} + +bool RegisteredLoggers::remove(const std::string& id) { + if (id == base::consts::kDefaultLoggerId) { + return false; + } + // get has internal lock + Logger* logger = base::utils::Registry::get(id); + if (logger != nullptr) { + // unregister has internal lock + unregister(logger); + } + return true; +} + +void RegisteredLoggers::unsafeFlushAll(void) { + ELPP_INTERNAL_INFO(1, "Flushing all log files"); + for (base::LogStreamsReferenceMap::iterator it = m_logStreamsReference.begin(); + it != m_logStreamsReference.end(); ++it) { + if (it->second.get() == nullptr) continue; + it->second->flush(); + } +} + +// VRegistry + +VRegistry::VRegistry(base::type::VerboseLevel level, base::type::EnumType* pFlags) : m_level(level), m_pFlags(pFlags) { +} + +/// @brief Sets verbose level. Accepted range is 0-9 +void VRegistry::setLevel(base::type::VerboseLevel level) { + base::threading::ScopedLock scopedLock(lock()); + if (level > 9) + m_level = base::consts::kMaxVerboseLevel; + else + m_level = level; +} + +void VRegistry::setModules(const char* modules) { + base::threading::ScopedLock scopedLock(lock()); + auto addSuffix = [](std::stringstream& ss, const char* sfx, const char* prev) { + if (prev != nullptr && base::utils::Str::endsWith(ss.str(), std::string(prev))) { + std::string chr(ss.str().substr(0, ss.str().size() - strlen(prev))); + ss.str(std::string("")); + ss << chr; + } + if (base::utils::Str::endsWith(ss.str(), std::string(sfx))) { + std::string chr(ss.str().substr(0, ss.str().size() - strlen(sfx))); + ss.str(std::string("")); + ss << chr; + } + ss << sfx; + }; + auto insert = [&](std::stringstream& ss, base::type::VerboseLevel level) { + if (!base::utils::hasFlag(LoggingFlag::DisableVModulesExtensions, *m_pFlags)) { + addSuffix(ss, ".h", nullptr); + m_modules.insert(std::make_pair(ss.str(), level)); + addSuffix(ss, ".c", ".h"); + m_modules.insert(std::make_pair(ss.str(), level)); + addSuffix(ss, ".cpp", ".c"); + m_modules.insert(std::make_pair(ss.str(), level)); + addSuffix(ss, ".cc", ".cpp"); + m_modules.insert(std::make_pair(ss.str(), level)); + addSuffix(ss, ".cxx", ".cc"); + m_modules.insert(std::make_pair(ss.str(), level)); + addSuffix(ss, ".-inl.h", ".cxx"); + m_modules.insert(std::make_pair(ss.str(), level)); + addSuffix(ss, ".hxx", ".-inl.h"); + m_modules.insert(std::make_pair(ss.str(), level)); + addSuffix(ss, ".hpp", ".hxx"); + m_modules.insert(std::make_pair(ss.str(), level)); + addSuffix(ss, ".hh", ".hpp"); + } + m_modules.insert(std::make_pair(ss.str(), level)); + }; + bool isMod = true; + bool isLevel = false; + std::stringstream ss; + int level = -1; + for (; *modules; ++modules) { + switch (*modules) { + case '=': + isLevel = true; + isMod = false; + break; + case ',': + isLevel = false; + isMod = true; + if (!ss.str().empty() && level != -1) { + insert(ss, static_cast(level)); + ss.str(std::string("")); + level = -1; + } + break; + default: + if (isMod) { + ss << *modules; + } else if (isLevel) { + if (isdigit(*modules)) { + level = static_cast(*modules) - 48; + } + } + break; + } + } + if (!ss.str().empty() && level != -1) { + insert(ss, static_cast(level)); + } +} + +bool VRegistry::allowed(base::type::VerboseLevel vlevel, const char* file) { + base::threading::ScopedLock scopedLock(lock()); + if (m_modules.empty() || file == nullptr) { + return vlevel <= m_level; + } else { + char baseFilename[base::consts::kSourceFilenameMaxLength] = ""; + base::utils::File::buildBaseFilename(file, baseFilename); + std::unordered_map::iterator it = m_modules.begin(); + for (; it != m_modules.end(); ++it) { + if (base::utils::Str::wildCardMatch(baseFilename, it->first.c_str())) { + return vlevel <= it->second; + } + } + if (base::utils::hasFlag(LoggingFlag::AllowVerboseIfModuleNotSpecified, *m_pFlags)) { + return true; + } + return false; + } +} + +void VRegistry::setFromArgs(const base::utils::CommandLineArgs* commandLineArgs) { + if (commandLineArgs->hasParam("-v") || commandLineArgs->hasParam("--verbose") || + commandLineArgs->hasParam("-V") || commandLineArgs->hasParam("--VERBOSE")) { + setLevel(base::consts::kMaxVerboseLevel); + } else if (commandLineArgs->hasParamWithValue("--v")) { + setLevel(static_cast(atoi(commandLineArgs->getParamValue("--v")))); + } else if (commandLineArgs->hasParamWithValue("--V")) { + setLevel(static_cast(atoi(commandLineArgs->getParamValue("--V")))); + } else if ((commandLineArgs->hasParamWithValue("-vmodule")) && vModulesEnabled()) { + setModules(commandLineArgs->getParamValue("-vmodule")); + } else if (commandLineArgs->hasParamWithValue("-VMODULE") && vModulesEnabled()) { + setModules(commandLineArgs->getParamValue("-VMODULE")); + } +} + +#if !defined(ELPP_DEFAULT_LOGGING_FLAGS) +# define ELPP_DEFAULT_LOGGING_FLAGS 0x0 +#endif // !defined(ELPP_DEFAULT_LOGGING_FLAGS) +// Storage +#if ELPP_ASYNC_LOGGING +Storage::Storage(const LogBuilderPtr& defaultLogBuilder, base::IWorker* asyncDispatchWorker) : +#else +Storage::Storage(const LogBuilderPtr& defaultLogBuilder) : +#endif // ELPP_ASYNC_LOGGING + m_registeredHitCounters(new base::RegisteredHitCounters()), + m_registeredLoggers(new base::RegisteredLoggers(defaultLogBuilder)), + m_flags(ELPP_DEFAULT_LOGGING_FLAGS), + m_vRegistry(new base::VRegistry(0, &m_flags)), +#if ELPP_ASYNC_LOGGING + m_asyncLogQueue(new base::AsyncLogQueue()), + m_asyncDispatchWorker(asyncDispatchWorker), +#endif // ELPP_ASYNC_LOGGING + m_preRollOutCallback(base::defaultPreRollOutCallback) { + // Register default logger + m_registeredLoggers->get(std::string(base::consts::kDefaultLoggerId)); + // We register default logger anyway (worse case it's not going to register) just in case + m_registeredLoggers->get("default"); + // Register performance logger and reconfigure format + Logger* performanceLogger = m_registeredLoggers->get(std::string(base::consts::kPerformanceLoggerId)); + m_registeredLoggers->get("performance"); + performanceLogger->configurations()->setGlobally(ConfigurationType::Format, std::string("%datetime %level %msg")); + performanceLogger->reconfigure(); +#if defined(ELPP_SYSLOG) + // Register syslog logger and reconfigure format + Logger* sysLogLogger = m_registeredLoggers->get(std::string(base::consts::kSysLogLoggerId)); + sysLogLogger->configurations()->setGlobally(ConfigurationType::Format, std::string("%level: %msg")); + sysLogLogger->reconfigure(); +#endif // defined(ELPP_SYSLOG) + addFlag(LoggingFlag::AllowVerboseIfModuleNotSpecified); +#if ELPP_ASYNC_LOGGING + installLogDispatchCallback(std::string("AsyncLogDispatchCallback")); +#else + installLogDispatchCallback(std::string("DefaultLogDispatchCallback")); +#endif // ELPP_ASYNC_LOGGING +#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING) + installPerformanceTrackingCallback + (std::string("DefaultPerformanceTrackingCallback")); +#endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING) + ELPP_INTERNAL_INFO(1, "Easylogging++ has been initialized"); +#if ELPP_ASYNC_LOGGING + m_asyncDispatchWorker->start(); +#endif // ELPP_ASYNC_LOGGING +} + +Storage::~Storage(void) { + ELPP_INTERNAL_INFO(4, "Destroying storage"); +#if ELPP_ASYNC_LOGGING + ELPP_INTERNAL_INFO(5, "Replacing log dispatch callback to synchronous"); + uninstallLogDispatchCallback(std::string("AsyncLogDispatchCallback")); + installLogDispatchCallback(std::string("DefaultLogDispatchCallback")); + ELPP_INTERNAL_INFO(5, "Destroying asyncDispatchWorker"); + base::utils::safeDelete(m_asyncDispatchWorker); + ELPP_INTERNAL_INFO(5, "Destroying asyncLogQueue"); + base::utils::safeDelete(m_asyncLogQueue); +#endif // ELPP_ASYNC_LOGGING + ELPP_INTERNAL_INFO(5, "Destroying registeredHitCounters"); + base::utils::safeDelete(m_registeredHitCounters); + ELPP_INTERNAL_INFO(5, "Destroying registeredLoggers"); + base::utils::safeDelete(m_registeredLoggers); + ELPP_INTERNAL_INFO(5, "Destroying vRegistry"); + base::utils::safeDelete(m_vRegistry); +} + +bool Storage::hasCustomFormatSpecifier(const char* formatSpecifier) { + base::threading::ScopedLock scopedLock(customFormatSpecifiersLock()); + return std::find(m_customFormatSpecifiers.begin(), m_customFormatSpecifiers.end(), + formatSpecifier) != m_customFormatSpecifiers.end(); +} + +void Storage::installCustomFormatSpecifier(const CustomFormatSpecifier& customFormatSpecifier) { + if (hasCustomFormatSpecifier(customFormatSpecifier.formatSpecifier())) { + return; + } + base::threading::ScopedLock scopedLock(customFormatSpecifiersLock()); + m_customFormatSpecifiers.push_back(customFormatSpecifier); +} + +bool Storage::uninstallCustomFormatSpecifier(const char* formatSpecifier) { + base::threading::ScopedLock scopedLock(customFormatSpecifiersLock()); + std::vector::iterator it = std::find(m_customFormatSpecifiers.begin(), + m_customFormatSpecifiers.end(), formatSpecifier); + if (it != m_customFormatSpecifiers.end() && strcmp(formatSpecifier, it->formatSpecifier()) == 0) { + m_customFormatSpecifiers.erase(it); + return true; + } + return false; +} + +void Storage::setApplicationArguments(int argc, char** argv) { + m_commandLineArgs.setArgs(argc, argv); + m_vRegistry->setFromArgs(commandLineArgs()); + // default log file +#if !defined(ELPP_DISABLE_LOG_FILE_FROM_ARG) + if (m_commandLineArgs.hasParamWithValue(base::consts::kDefaultLogFileParam)) { + Configurations c; + c.setGlobally(ConfigurationType::Filename, + std::string(m_commandLineArgs.getParamValue(base::consts::kDefaultLogFileParam))); + registeredLoggers()->setDefaultConfigurations(c); + for (base::RegisteredLoggers::iterator it = registeredLoggers()->begin(); + it != registeredLoggers()->end(); ++it) { + it->second->configure(c); + } + } +#endif // !defined(ELPP_DISABLE_LOG_FILE_FROM_ARG) +#if defined(ELPP_LOGGING_FLAGS_FROM_ARG) + if (m_commandLineArgs.hasParamWithValue(base::consts::kLoggingFlagsParam)) { + int userInput = atoi(m_commandLineArgs.getParamValue(base::consts::kLoggingFlagsParam)); + if (ELPP_DEFAULT_LOGGING_FLAGS == 0x0) { + m_flags = userInput; + } else { + base::utils::addFlag(userInput, &m_flags); + } + } +#endif // defined(ELPP_LOGGING_FLAGS_FROM_ARG) +} + +} // namespace base + +// LogDispatchCallback +void LogDispatchCallback::handle(const LogDispatchData* data) { +#if defined(ELPP_THREAD_SAFE) + base::threading::ScopedLock scopedLock(m_fileLocksMapLock); + std::string filename = data->logMessage()->logger()->typedConfigurations()->filename(data->logMessage()->level()); + auto lock = m_fileLocks.find(filename); + if (lock == m_fileLocks.end()) { + m_fileLocks.emplace(std::make_pair(filename, std::unique_ptr(new base::threading::Mutex))); + } +#endif +} + +base::threading::Mutex& LogDispatchCallback::fileHandle(const LogDispatchData* data) { + auto it = m_fileLocks.find(data->logMessage()->logger()->typedConfigurations()->filename(data->logMessage()->level())); + return *(it->second.get()); +} + +namespace base { +// DefaultLogDispatchCallback + +void DefaultLogDispatchCallback::handle(const LogDispatchData* data) { +#if defined(ELPP_THREAD_SAFE) + LogDispatchCallback::handle(data); + base::threading::ScopedLock scopedLock(fileHandle(data)); +#endif + m_data = data; + dispatch(m_data->logMessage()->logger()->logBuilder()->build(m_data->logMessage(), + m_data->dispatchAction() == base::DispatchAction::NormalLog)); +} + +void DefaultLogDispatchCallback::dispatch(base::type::string_t&& logLine) { + if (m_data->dispatchAction() == base::DispatchAction::NormalLog) { + if (m_data->logMessage()->logger()->m_typedConfigurations->toFile(m_data->logMessage()->level())) { + base::type::fstream_t* fs = m_data->logMessage()->logger()->m_typedConfigurations->fileStream( + m_data->logMessage()->level()); + if (fs != nullptr) { + fs->write(logLine.c_str(), logLine.size()); + if (fs->fail()) { + ELPP_INTERNAL_ERROR("Unable to write log to file [" + << m_data->logMessage()->logger()->m_typedConfigurations->filename(m_data->logMessage()->level()) << "].\n" + << "Few possible reasons (could be something else):\n" << " * Permission denied\n" + << " * Disk full\n" << " * Disk is not writable", true); + } else { + if (ELPP->hasFlag(LoggingFlag::ImmediateFlush) + || (m_data->logMessage()->logger()->isFlushNeeded(m_data->logMessage()->level()))) { + m_data->logMessage()->logger()->flush(m_data->logMessage()->level(), fs); + } + } + } else { + ELPP_INTERNAL_ERROR("Log file for [" << LevelHelper::convertToString(m_data->logMessage()->level()) << "] " + << "has not been configured but [TO_FILE] is configured to TRUE. [Logger ID: " + << m_data->logMessage()->logger()->id() << "]", false); + } + } + if (m_data->logMessage()->logger()->m_typedConfigurations->toStandardOutput(m_data->logMessage()->level())) { + if (ELPP->hasFlag(LoggingFlag::ColoredTerminalOutput)) + m_data->logMessage()->logger()->logBuilder()->convertToColoredOutput(&logLine, m_data->logMessage()->level()); + ELPP_COUT << ELPP_COUT_LINE(logLine); + } + } +#if defined(ELPP_SYSLOG) + else if (m_data->dispatchAction() == base::DispatchAction::SysLog) { + // Determine syslog priority + int sysLogPriority = 0; + if (m_data->logMessage()->level() == Level::Fatal) + sysLogPriority = LOG_EMERG; + else if (m_data->logMessage()->level() == Level::Error) + sysLogPriority = LOG_ERR; + else if (m_data->logMessage()->level() == Level::Warning) + sysLogPriority = LOG_WARNING; + else if (m_data->logMessage()->level() == Level::Info) + sysLogPriority = LOG_INFO; + else if (m_data->logMessage()->level() == Level::Debug) + sysLogPriority = LOG_DEBUG; + else + sysLogPriority = LOG_NOTICE; +# if defined(ELPP_UNICODE) + char* line = base::utils::Str::wcharPtrToCharPtr(logLine.c_str()); + syslog(sysLogPriority, "%s", line); + free(line); +# else + syslog(sysLogPriority, "%s", logLine.c_str()); +# endif + } +#endif // defined(ELPP_SYSLOG) +} + +#if ELPP_ASYNC_LOGGING + +// AsyncLogDispatchCallback + +void AsyncLogDispatchCallback::handle(const LogDispatchData* data) { + base::type::string_t logLine = data->logMessage()->logger()->logBuilder()->build(data->logMessage(), + data->dispatchAction() == base::DispatchAction::NormalLog); + if (data->dispatchAction() == base::DispatchAction::NormalLog + && data->logMessage()->logger()->typedConfigurations()->toStandardOutput(data->logMessage()->level())) { + if (ELPP->hasFlag(LoggingFlag::ColoredTerminalOutput)) + data->logMessage()->logger()->logBuilder()->convertToColoredOutput(&logLine, data->logMessage()->level()); + ELPP_COUT << ELPP_COUT_LINE(logLine); + } + // Save resources and only queue if we want to write to file otherwise just ignore handler + if (data->logMessage()->logger()->typedConfigurations()->toFile(data->logMessage()->level())) { + ELPP->asyncLogQueue()->push(AsyncLogItem(*(data->logMessage()), *data, logLine)); + } +} + +// AsyncDispatchWorker +AsyncDispatchWorker::AsyncDispatchWorker() { + setContinueRunning(false); +} + +AsyncDispatchWorker::~AsyncDispatchWorker() { + setContinueRunning(false); + ELPP_INTERNAL_INFO(6, "Stopping dispatch worker - Cleaning log queue"); + clean(); + ELPP_INTERNAL_INFO(6, "Log queue cleaned"); +} + +bool AsyncDispatchWorker::clean(void) { + std::mutex m; + std::unique_lock lk(m); + cv.wait(lk, [] { return !ELPP->asyncLogQueue()->empty(); }); + emptyQueue(); + lk.unlock(); + cv.notify_one(); + return ELPP->asyncLogQueue()->empty(); +} + +void AsyncDispatchWorker::emptyQueue(void) { + while (!ELPP->asyncLogQueue()->empty()) { + AsyncLogItem data = ELPP->asyncLogQueue()->next(); + handle(&data); + base::threading::msleep(100); + } +} + +void AsyncDispatchWorker::start(void) { + base::threading::msleep(5000); // 5s (why?) + setContinueRunning(true); + std::thread t1(&AsyncDispatchWorker::run, this); + t1.join(); +} + +void AsyncDispatchWorker::handle(AsyncLogItem* logItem) { + LogDispatchData* data = logItem->data(); + LogMessage* logMessage = logItem->logMessage(); + Logger* logger = logMessage->logger(); + base::TypedConfigurations* conf = logger->typedConfigurations(); + base::type::string_t logLine = logItem->logLine(); + if (data->dispatchAction() == base::DispatchAction::NormalLog) { + if (conf->toFile(logMessage->level())) { + base::type::fstream_t* fs = conf->fileStream(logMessage->level()); + if (fs != nullptr) { + fs->write(logLine.c_str(), logLine.size()); + if (fs->fail()) { + ELPP_INTERNAL_ERROR("Unable to write log to file [" + << conf->filename(logMessage->level()) << "].\n" + << "Few possible reasons (could be something else):\n" << " * Permission denied\n" + << " * Disk full\n" << " * Disk is not writable", true); + } else { + if (ELPP->hasFlag(LoggingFlag::ImmediateFlush) || (logger->isFlushNeeded(logMessage->level()))) { + logger->flush(logMessage->level(), fs); + } + } + } else { + ELPP_INTERNAL_ERROR("Log file for [" << LevelHelper::convertToString(logMessage->level()) << "] " + << "has not been configured but [TO_FILE] is configured to TRUE. [Logger ID: " << logger->id() << "]", false); + } + } + } +# if defined(ELPP_SYSLOG) + else if (data->dispatchAction() == base::DispatchAction::SysLog) { + // Determine syslog priority + int sysLogPriority = 0; + if (logMessage->level() == Level::Fatal) + sysLogPriority = LOG_EMERG; + else if (logMessage->level() == Level::Error) + sysLogPriority = LOG_ERR; + else if (logMessage->level() == Level::Warning) + sysLogPriority = LOG_WARNING; + else if (logMessage->level() == Level::Info) + sysLogPriority = LOG_INFO; + else if (logMessage->level() == Level::Debug) + sysLogPriority = LOG_DEBUG; + else + sysLogPriority = LOG_NOTICE; +# if defined(ELPP_UNICODE) + char* line = base::utils::Str::wcharPtrToCharPtr(logLine.c_str()); + syslog(sysLogPriority, "%s", line); + free(line); +# else + syslog(sysLogPriority, "%s", logLine.c_str()); +# endif + } +# endif // defined(ELPP_SYSLOG) +} + +void AsyncDispatchWorker::run(void) { + while (continueRunning()) { + emptyQueue(); + base::threading::msleep(10); // 10ms + } +} +#endif // ELPP_ASYNC_LOGGING + +// DefaultLogBuilder + +base::type::string_t DefaultLogBuilder::build(const LogMessage* logMessage, bool appendNewLine) const { + base::TypedConfigurations* tc = logMessage->logger()->typedConfigurations(); + const base::LogFormat* logFormat = &tc->logFormat(logMessage->level()); + base::type::string_t logLine = logFormat->format(); + char buff[base::consts::kSourceFilenameMaxLength + base::consts::kSourceLineMaxLength] = ""; + const char* bufLim = buff + sizeof(buff); + if (logFormat->hasFlag(base::FormatFlags::AppName)) { + // App name + base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kAppNameFormatSpecifier, + logMessage->logger()->parentApplicationName()); + } + if (logFormat->hasFlag(base::FormatFlags::ThreadId)) { + // Thread ID + base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kThreadIdFormatSpecifier, + ELPP->getThreadName(base::threading::getCurrentThreadId())); + } + if (logFormat->hasFlag(base::FormatFlags::DateTime)) { + // DateTime + base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kDateTimeFormatSpecifier, + base::utils::DateTime::getDateTime(logFormat->dateTimeFormat().c_str(), + &tc->subsecondPrecision(logMessage->level()))); + } + if (logFormat->hasFlag(base::FormatFlags::Function)) { + // Function + base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kLogFunctionFormatSpecifier, logMessage->func()); + } + if (logFormat->hasFlag(base::FormatFlags::File)) { + // File + base::utils::Str::clearBuff(buff, base::consts::kSourceFilenameMaxLength); + base::utils::File::buildStrippedFilename(logMessage->file().c_str(), buff); + base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kLogFileFormatSpecifier, std::string(buff)); + } + if (logFormat->hasFlag(base::FormatFlags::FileBase)) { + // FileBase + base::utils::Str::clearBuff(buff, base::consts::kSourceFilenameMaxLength); + base::utils::File::buildBaseFilename(logMessage->file(), buff); + base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kLogFileBaseFormatSpecifier, std::string(buff)); + } + if (logFormat->hasFlag(base::FormatFlags::Line)) { + // Line + char* buf = base::utils::Str::clearBuff(buff, base::consts::kSourceLineMaxLength); + buf = base::utils::Str::convertAndAddToBuff(logMessage->line(), base::consts::kSourceLineMaxLength, buf, bufLim, false); + base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kLogLineFormatSpecifier, std::string(buff)); + } + if (logFormat->hasFlag(base::FormatFlags::Location)) { + // Location + char* buf = base::utils::Str::clearBuff(buff, + base::consts::kSourceFilenameMaxLength + base::consts::kSourceLineMaxLength); + base::utils::File::buildStrippedFilename(logMessage->file().c_str(), buff); + buf = base::utils::Str::addToBuff(buff, buf, bufLim); + buf = base::utils::Str::addToBuff(":", buf, bufLim); + buf = base::utils::Str::convertAndAddToBuff(logMessage->line(), base::consts::kSourceLineMaxLength, buf, bufLim, + false); + base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kLogLocationFormatSpecifier, std::string(buff)); + } + if (logMessage->level() == Level::Verbose && logFormat->hasFlag(base::FormatFlags::VerboseLevel)) { + // Verbose level + char* buf = base::utils::Str::clearBuff(buff, 1); + buf = base::utils::Str::convertAndAddToBuff(logMessage->verboseLevel(), 1, buf, bufLim, false); + base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kVerboseLevelFormatSpecifier, std::string(buff)); + } + if (logFormat->hasFlag(base::FormatFlags::LogMessage)) { + // Log message + base::utils::Str::replaceFirstWithEscape(logLine, base::consts::kMessageFormatSpecifier, logMessage->message()); + } +#if !defined(ELPP_DISABLE_CUSTOM_FORMAT_SPECIFIERS) + el::base::threading::ScopedLock lock_(ELPP->customFormatSpecifiersLock()); + ELPP_UNUSED(lock_); + for (std::vector::const_iterator it = ELPP->customFormatSpecifiers()->begin(); + it != ELPP->customFormatSpecifiers()->end(); ++it) { + std::string fs(it->formatSpecifier()); + base::type::string_t wcsFormatSpecifier(fs.begin(), fs.end()); + base::utils::Str::replaceFirstWithEscape(logLine, wcsFormatSpecifier, it->resolver()(logMessage)); + } +#endif // !defined(ELPP_DISABLE_CUSTOM_FORMAT_SPECIFIERS) + if (appendNewLine) logLine += ELPP_LITERAL("\n"); + return logLine; +} + +// LogDispatcher + +void LogDispatcher::dispatch(void) { + if (m_proceed && m_dispatchAction == base::DispatchAction::None) { + m_proceed = false; + } + if (!m_proceed) { + return; + } +#ifndef ELPP_NO_GLOBAL_LOCK + // see https://github.com/muflihun/easyloggingpp/issues/580 + // global lock is turned off by default unless + // ELPP_NO_GLOBAL_LOCK is defined + base::threading::ScopedLock scopedLock(ELPP->lock()); +#endif + base::TypedConfigurations* tc = m_logMessage->logger()->m_typedConfigurations; + if (ELPP->hasFlag(LoggingFlag::StrictLogFileSizeCheck)) { + tc->validateFileRolling(m_logMessage->level(), ELPP->preRollOutCallback()); + } + LogDispatchCallback* callback = nullptr; + LogDispatchData data; + for (const std::pair& h + : ELPP->m_logDispatchCallbacks) { + callback = h.second.get(); + if (callback != nullptr && callback->enabled()) { + data.setLogMessage(m_logMessage); + data.setDispatchAction(m_dispatchAction); + callback->handle(&data); + } + } +} + +// MessageBuilder + +void MessageBuilder::initialize(Logger* logger) { + m_logger = logger; + m_containerLogSeperator = ELPP->hasFlag(LoggingFlag::NewLineForContainer) ? + ELPP_LITERAL("\n ") : ELPP_LITERAL(", "); +} + +MessageBuilder& MessageBuilder::operator<<(const wchar_t* msg) { + if (msg == nullptr) { + m_logger->stream() << base::consts::kNullPointer; + return *this; + } +# if defined(ELPP_UNICODE) + m_logger->stream() << msg; +# else + char* buff_ = base::utils::Str::wcharPtrToCharPtr(msg); + m_logger->stream() << buff_; + free(buff_); +# endif + if (ELPP->hasFlag(LoggingFlag::AutoSpacing)) { + m_logger->stream() << " "; + } + return *this; +} + +// Writer + +Writer& Writer::construct(Logger* logger, bool needLock) { + m_logger = logger; + initializeLogger(logger->id(), false, needLock); + m_messageBuilder.initialize(m_logger); + return *this; +} + +Writer& Writer::construct(int count, const char* loggerIds, ...) { + if (ELPP->hasFlag(LoggingFlag::MultiLoggerSupport)) { + va_list loggersList; + va_start(loggersList, loggerIds); + const char* id = loggerIds; + m_loggerIds.reserve(count); + for (int i = 0; i < count; ++i) { + m_loggerIds.push_back(std::string(id)); + id = va_arg(loggersList, const char*); + } + va_end(loggersList); + initializeLogger(m_loggerIds.at(0)); + } else { + initializeLogger(std::string(loggerIds)); + } + m_messageBuilder.initialize(m_logger); + return *this; +} + +void Writer::initializeLogger(const std::string& loggerId, bool lookup, bool needLock) { + if (lookup) { + m_logger = ELPP->registeredLoggers()->get(loggerId, ELPP->hasFlag(LoggingFlag::CreateLoggerAutomatically)); + } + if (m_logger == nullptr) { + { + if (!ELPP->registeredLoggers()->has(std::string(base::consts::kDefaultLoggerId))) { + // Somehow default logger has been unregistered. Not good! Register again + ELPP->registeredLoggers()->get(std::string(base::consts::kDefaultLoggerId)); + } + } + Writer(Level::Debug, m_file, m_line, m_func).construct(1, base::consts::kDefaultLoggerId) + << "Logger [" << loggerId << "] is not registered yet!"; + m_proceed = false; + } else { + if (needLock) { + m_logger->acquireLock(); // This should not be unlocked by checking m_proceed because + // m_proceed can be changed by lines below + } + if (ELPP->hasFlag(LoggingFlag::HierarchicalLogging)) { + m_proceed = m_level == Level::Verbose ? m_logger->enabled(m_level) : + LevelHelper::castToInt(m_level) >= LevelHelper::castToInt(ELPP->m_loggingLevel); + } else { + m_proceed = m_logger->enabled(m_level); + } + } +} + +void Writer::processDispatch() { +#if ELPP_LOGGING_ENABLED + if (ELPP->hasFlag(LoggingFlag::MultiLoggerSupport)) { + bool firstDispatched = false; + base::type::string_t logMessage; + std::size_t i = 0; + do { + if (m_proceed) { + if (firstDispatched) { + m_logger->stream() << logMessage; + } else { + firstDispatched = true; + if (m_loggerIds.size() > 1) { + logMessage = m_logger->stream().str(); + } + } + triggerDispatch(); + } else if (m_logger != nullptr) { + m_logger->stream().str(ELPP_LITERAL("")); + m_logger->releaseLock(); + } + if (i + 1 < m_loggerIds.size()) { + initializeLogger(m_loggerIds.at(i + 1)); + } + } while (++i < m_loggerIds.size()); + } else { + if (m_proceed) { + triggerDispatch(); + } else if (m_logger != nullptr) { + m_logger->stream().str(ELPP_LITERAL("")); + m_logger->releaseLock(); + } + } +#else + if (m_logger != nullptr) { + m_logger->stream().str(ELPP_LITERAL("")); + m_logger->releaseLock(); + } +#endif // ELPP_LOGGING_ENABLED +} + +void Writer::triggerDispatch(void) { + if (m_proceed) { + if (m_msg == nullptr) { + LogMessage msg(m_level, m_file, m_line, m_func, m_verboseLevel, + m_logger); + base::LogDispatcher(m_proceed, &msg, m_dispatchAction).dispatch(); + } else { + base::LogDispatcher(m_proceed, m_msg, m_dispatchAction).dispatch(); + } + } + if (m_logger != nullptr) { + m_logger->stream().str(ELPP_LITERAL("")); + m_logger->releaseLock(); + } + if (m_proceed && m_level == Level::Fatal + && !ELPP->hasFlag(LoggingFlag::DisableApplicationAbortOnFatalLog)) { + base::Writer(Level::Warning, m_file, m_line, m_func).construct(1, base::consts::kDefaultLoggerId) + << "Aborting application. Reason: Fatal log at [" << m_file << ":" << m_line << "]"; + std::stringstream reasonStream; + reasonStream << "Fatal log at [" << m_file << ":" << m_line << "]" + << " If you wish to disable 'abort on fatal log' please use " + << "el::Loggers::addFlag(el::LoggingFlag::DisableApplicationAbortOnFatalLog)"; + base::utils::abort(1, reasonStream.str()); + } + m_proceed = false; +} + +// PErrorWriter + +PErrorWriter::~PErrorWriter(void) { + if (m_proceed) { +#if ELPP_COMPILER_MSVC + char buff[256]; + strerror_s(buff, 256, errno); + m_logger->stream() << ": " << buff << " [" << errno << "]"; +#else + m_logger->stream() << ": " << strerror(errno) << " [" << errno << "]"; +#endif + } +} + +// PerformanceTracker + +#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING) + +PerformanceTracker::PerformanceTracker(const std::string& blockName, + base::TimestampUnit timestampUnit, + const std::string& loggerId, + bool scopedLog, Level level) : + m_blockName(blockName), m_timestampUnit(timestampUnit), m_loggerId(loggerId), m_scopedLog(scopedLog), + m_level(level), m_hasChecked(false), m_lastCheckpointId(std::string()), m_enabled(false) { +#if !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED + // We store it locally so that if user happen to change configuration by the end of scope + // or before calling checkpoint, we still depend on state of configuraton at time of construction + el::Logger* loggerPtr = ELPP->registeredLoggers()->get(loggerId, false); + m_enabled = loggerPtr != nullptr && loggerPtr->m_typedConfigurations->performanceTracking(m_level); + if (m_enabled) { + base::utils::DateTime::gettimeofday(&m_startTime); + } +#endif // !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED +} + +PerformanceTracker::~PerformanceTracker(void) { +#if !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED + if (m_enabled) { + base::threading::ScopedLock scopedLock(lock()); + if (m_scopedLog) { + base::utils::DateTime::gettimeofday(&m_endTime); + base::type::string_t formattedTime = getFormattedTimeTaken(); + PerformanceTrackingData data(PerformanceTrackingData::DataType::Complete); + data.init(this); + data.m_formattedTimeTaken = formattedTime; + PerformanceTrackingCallback* callback = nullptr; + for (const std::pair& h + : ELPP->m_performanceTrackingCallbacks) { + callback = h.second.get(); + if (callback != nullptr && callback->enabled()) { + callback->handle(&data); + } + } + } + } +#endif // !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) +} + +void PerformanceTracker::checkpoint(const std::string& id, const char* file, base::type::LineNumber line, + const char* func) { +#if !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED + if (m_enabled) { + base::threading::ScopedLock scopedLock(lock()); + base::utils::DateTime::gettimeofday(&m_endTime); + base::type::string_t formattedTime = m_hasChecked ? getFormattedTimeTaken(m_lastCheckpointTime) : ELPP_LITERAL(""); + PerformanceTrackingData data(PerformanceTrackingData::DataType::Checkpoint); + data.init(this); + data.m_checkpointId = id; + data.m_file = file; + data.m_line = line; + data.m_func = func; + data.m_formattedTimeTaken = formattedTime; + PerformanceTrackingCallback* callback = nullptr; + for (const std::pair& h + : ELPP->m_performanceTrackingCallbacks) { + callback = h.second.get(); + if (callback != nullptr && callback->enabled()) { + callback->handle(&data); + } + } + base::utils::DateTime::gettimeofday(&m_lastCheckpointTime); + m_hasChecked = true; + m_lastCheckpointId = id; + } +#endif // !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED + ELPP_UNUSED(id); + ELPP_UNUSED(file); + ELPP_UNUSED(line); + ELPP_UNUSED(func); +} + +const base::type::string_t PerformanceTracker::getFormattedTimeTaken(struct timeval startTime) const { + if (ELPP->hasFlag(LoggingFlag::FixedTimeFormat)) { + base::type::stringstream_t ss; + ss << base::utils::DateTime::getTimeDifference(m_endTime, + startTime, m_timestampUnit) << " " << base::consts::kTimeFormats[static_cast + (m_timestampUnit)].unit; + return ss.str(); + } + return base::utils::DateTime::formatTime(base::utils::DateTime::getTimeDifference(m_endTime, + startTime, m_timestampUnit), m_timestampUnit); +} + +#endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING) + +namespace debug { +#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG) + +// StackTrace + +StackTrace::StackTraceEntry::StackTraceEntry(std::size_t index, const std::string& loc, const std::string& demang, + const std::string& hex, + const std::string& addr) : + m_index(index), + m_location(loc), + m_demangled(demang), + m_hex(hex), + m_addr(addr) { +} + +std::ostream& operator<<(std::ostream& ss, const StackTrace::StackTraceEntry& si) { + ss << "[" << si.m_index << "] " << si.m_location << (si.m_hex.empty() ? "" : "+") << si.m_hex << " " << si.m_addr << + (si.m_demangled.empty() ? "" : ":") << si.m_demangled; + return ss; +} + +std::ostream& operator<<(std::ostream& os, const StackTrace& st) { + std::vector::const_iterator it = st.m_stack.begin(); + while (it != st.m_stack.end()) { + os << " " << *it++ << "\n"; + } + return os; +} + +void StackTrace::generateNew(void) { +#if ELPP_STACKTRACE + m_stack.clear(); + void* stack[kMaxStack]; + unsigned int size = backtrace(stack, kMaxStack); + char** strings = backtrace_symbols(stack, size); + if (size > kStackStart) { // Skip StackTrace c'tor and generateNew + for (std::size_t i = kStackStart; i < size; ++i) { + std::string mangName; + std::string location; + std::string hex; + std::string addr; + + // entry: 2 crash.cpp.bin 0x0000000101552be5 _ZN2el4base5debug10StackTraceC1Ev + 21 + const std::string line(strings[i]); + auto p = line.find("_"); + if (p != std::string::npos) { + mangName = line.substr(p); + mangName = mangName.substr(0, mangName.find(" +")); + } + p = line.find("0x"); + if (p != std::string::npos) { + addr = line.substr(p); + addr = addr.substr(0, addr.find("_")); + } + // Perform demangling if parsed properly + if (!mangName.empty()) { + int status = 0; + char* demangName = abi::__cxa_demangle(mangName.data(), 0, 0, &status); + // if demangling is successful, output the demangled function name + if (status == 0) { + // Success (see http://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-html-USERS-4.3/a01696.html) + StackTraceEntry entry(i - 1, location, demangName, hex, addr); + m_stack.push_back(entry); + } else { + // Not successful - we will use mangled name + StackTraceEntry entry(i - 1, location, mangName, hex, addr); + m_stack.push_back(entry); + } + free(demangName); + } else { + StackTraceEntry entry(i - 1, line); + m_stack.push_back(entry); + } + } + } + free(strings); +#else + ELPP_INTERNAL_INFO(1, "Stacktrace generation not supported for selected compiler"); +#endif // ELPP_STACKTRACE +} + +// Static helper functions + +static std::string crashReason(int sig) { + std::stringstream ss; + bool foundReason = false; + for (int i = 0; i < base::consts::kCrashSignalsCount; ++i) { + if (base::consts::kCrashSignals[i].numb == sig) { + ss << "Application has crashed due to [" << base::consts::kCrashSignals[i].name << "] signal"; + if (ELPP->hasFlag(el::LoggingFlag::LogDetailedCrashReason)) { + ss << std::endl << + " " << base::consts::kCrashSignals[i].brief << std::endl << + " " << base::consts::kCrashSignals[i].detail; + } + foundReason = true; + } + } + if (!foundReason) { + ss << "Application has crashed due to unknown signal [" << sig << "]"; + } + return ss.str(); +} +/// @brief Logs reason of crash from sig +static void logCrashReason(int sig, bool stackTraceIfAvailable, Level level, const char* logger) { + std::stringstream ss; + ss << "CRASH HANDLED; "; + ss << crashReason(sig); +#if ELPP_STACKTRACE + if (stackTraceIfAvailable) { + ss << std::endl << " ======= Backtrace: =========" << std::endl << base::debug::StackTrace(); + } +#else + ELPP_UNUSED(stackTraceIfAvailable); +#endif // ELPP_STACKTRACE + ELPP_WRITE_LOG(el::base::Writer, level, base::DispatchAction::NormalLog, logger) << ss.str(); +} + +static inline void crashAbort(int sig) { + base::utils::abort(sig, std::string()); +} + +/// @brief Default application crash handler +/// +/// @detail This function writes log using 'default' logger, prints stack trace for GCC based compilers and aborts program. +static inline void defaultCrashHandler(int sig) { + base::debug::logCrashReason(sig, true, Level::Fatal, base::consts::kDefaultLoggerId); + base::debug::crashAbort(sig); +} + +// CrashHandler + +CrashHandler::CrashHandler(bool useDefault) { + if (useDefault) { + setHandler(defaultCrashHandler); + } +} + +void CrashHandler::setHandler(const Handler& cHandler) { + m_handler = cHandler; +#if defined(ELPP_HANDLE_SIGABRT) + int i = 0; // SIGABRT is at base::consts::kCrashSignals[0] +#else + int i = 1; +#endif // defined(ELPP_HANDLE_SIGABRT) + for (; i < base::consts::kCrashSignalsCount; ++i) { + m_handler = signal(base::consts::kCrashSignals[i].numb, cHandler); + } +} + +#endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG) +} // namespace debug +} // namespace base + +// el + +// Helpers + +#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG) + +void Helpers::crashAbort(int sig, const char* sourceFile, unsigned int long line) { + std::stringstream ss; + ss << base::debug::crashReason(sig).c_str(); + ss << " - [Called el::Helpers::crashAbort(" << sig << ")]"; + if (sourceFile != nullptr && strlen(sourceFile) > 0) { + ss << " - Source: " << sourceFile; + if (line > 0) + ss << ":" << line; + else + ss << " (line number not specified)"; + } + base::utils::abort(sig, ss.str()); +} + +void Helpers::logCrashReason(int sig, bool stackTraceIfAvailable, Level level, const char* logger) { + el::base::debug::logCrashReason(sig, stackTraceIfAvailable, level, logger); +} + +#endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG) + +// Loggers + +Logger* Loggers::getLogger(const std::string& identity, bool registerIfNotAvailable) { + return ELPP->registeredLoggers()->get(identity, registerIfNotAvailable); +} + +void Loggers::setDefaultLogBuilder(el::LogBuilderPtr& logBuilderPtr) { + ELPP->registeredLoggers()->setDefaultLogBuilder(logBuilderPtr); +} + +bool Loggers::unregisterLogger(const std::string& identity) { + return ELPP->registeredLoggers()->remove(identity); +} + +bool Loggers::hasLogger(const std::string& identity) { + return ELPP->registeredLoggers()->has(identity); +} + +Logger* Loggers::reconfigureLogger(Logger* logger, const Configurations& configurations) { + if (!logger) return nullptr; + logger->configure(configurations); + return logger; +} + +Logger* Loggers::reconfigureLogger(const std::string& identity, const Configurations& configurations) { + return Loggers::reconfigureLogger(Loggers::getLogger(identity), configurations); +} + +Logger* Loggers::reconfigureLogger(const std::string& identity, ConfigurationType configurationType, + const std::string& value) { + Logger* logger = Loggers::getLogger(identity); + if (logger == nullptr) { + return nullptr; + } + logger->configurations()->set(Level::Global, configurationType, value); + logger->reconfigure(); + return logger; +} + +void Loggers::reconfigureAllLoggers(const Configurations& configurations) { + for (base::RegisteredLoggers::iterator it = ELPP->registeredLoggers()->begin(); + it != ELPP->registeredLoggers()->end(); ++it) { + Loggers::reconfigureLogger(it->second, configurations); + } +} + +void Loggers::reconfigureAllLoggers(Level level, ConfigurationType configurationType, + const std::string& value) { + for (base::RegisteredLoggers::iterator it = ELPP->registeredLoggers()->begin(); + it != ELPP->registeredLoggers()->end(); ++it) { + Logger* logger = it->second; + logger->configurations()->set(level, configurationType, value); + logger->reconfigure(); + } +} + +void Loggers::setDefaultConfigurations(const Configurations& configurations, bool reconfigureExistingLoggers) { + ELPP->registeredLoggers()->setDefaultConfigurations(configurations); + if (reconfigureExistingLoggers) { + Loggers::reconfigureAllLoggers(configurations); + } +} + +const Configurations* Loggers::defaultConfigurations(void) { + return ELPP->registeredLoggers()->defaultConfigurations(); +} + +const base::LogStreamsReferenceMap* Loggers::logStreamsReference(void) { + return ELPP->registeredLoggers()->logStreamsReference(); +} + +base::TypedConfigurations Loggers::defaultTypedConfigurations(void) { + return base::TypedConfigurations( + ELPP->registeredLoggers()->defaultConfigurations(), + ELPP->registeredLoggers()->logStreamsReference()); +} + +std::vector* Loggers::populateAllLoggerIds(std::vector* targetList) { + targetList->clear(); + for (base::RegisteredLoggers::iterator it = ELPP->registeredLoggers()->list().begin(); + it != ELPP->registeredLoggers()->list().end(); ++it) { + targetList->push_back(it->first); + } + return targetList; +} + +void Loggers::configureFromGlobal(const char* globalConfigurationFilePath) { + std::ifstream gcfStream(globalConfigurationFilePath, std::ifstream::in); + ELPP_ASSERT(gcfStream.is_open(), "Unable to open global configuration file [" << globalConfigurationFilePath + << "] for parsing."); + std::string line = std::string(); + std::stringstream ss; + Logger* logger = nullptr; + auto configure = [&](void) { + ELPP_INTERNAL_INFO(8, "Configuring logger: '" << logger->id() << "' with configurations \n" << ss.str() + << "\n--------------"); + Configurations c; + c.parseFromText(ss.str()); + logger->configure(c); + }; + while (gcfStream.good()) { + std::getline(gcfStream, line); + ELPP_INTERNAL_INFO(1, "Parsing line: " << line); + base::utils::Str::trim(line); + if (Configurations::Parser::isComment(line)) continue; + Configurations::Parser::ignoreComments(&line); + base::utils::Str::trim(line); + if (line.size() > 2 && base::utils::Str::startsWith(line, std::string(base::consts::kConfigurationLoggerId))) { + if (!ss.str().empty() && logger != nullptr) { + configure(); + } + ss.str(std::string("")); + line = line.substr(2); + base::utils::Str::trim(line); + if (line.size() > 1) { + ELPP_INTERNAL_INFO(1, "Getting logger: '" << line << "'"); + logger = getLogger(line); + } + } else { + ss << line << "\n"; + } + } + if (!ss.str().empty() && logger != nullptr) { + configure(); + } +} + +bool Loggers::configureFromArg(const char* argKey) { +#if defined(ELPP_DISABLE_CONFIGURATION_FROM_PROGRAM_ARGS) + ELPP_UNUSED(argKey); +#else + if (!Helpers::commandLineArgs()->hasParamWithValue(argKey)) { + return false; + } + configureFromGlobal(Helpers::commandLineArgs()->getParamValue(argKey)); +#endif // defined(ELPP_DISABLE_CONFIGURATION_FROM_PROGRAM_ARGS) + return true; +} + +void Loggers::flushAll(void) { + ELPP->registeredLoggers()->flushAll(); +} + +void Loggers::setVerboseLevel(base::type::VerboseLevel level) { + ELPP->vRegistry()->setLevel(level); +} + +base::type::VerboseLevel Loggers::verboseLevel(void) { + return ELPP->vRegistry()->level(); +} + +void Loggers::setVModules(const char* modules) { + if (ELPP->vRegistry()->vModulesEnabled()) { + ELPP->vRegistry()->setModules(modules); + } +} + +void Loggers::clearVModules(void) { + ELPP->vRegistry()->clearModules(); +} + +// VersionInfo + +const std::string VersionInfo::version(void) { + return std::string("9.96.4"); +} +/// @brief Release date of current version +const std::string VersionInfo::releaseDate(void) { + return std::string("03-04-2018 1019hrs"); +} + +} // namespace el diff --git a/src/kerberos/Kerberos.cpp b/src/kerberos/Kerberos.cpp index 95f2ec1..dd5e1d9 100755 --- a/src/kerberos/Kerberos.cpp +++ b/src/kerberos/Kerberos.cpp @@ -55,7 +55,7 @@ namespace kerberos if(!machinery->allowed(m_images)) { - BINFO << "Machinery on hold, conditions failed."; + VLOG(1) << "Machinery on hold, conditions failed."; continue; } @@ -128,7 +128,7 @@ namespace kerberos // --------------------------- // Get settings from XML file - LINFO << "Reading configuration file: " << configuration; + VLOG(0) << "Reading configuration file: " << configuration; StringMap settings = kerberos::helper::getSettingsFromXML(configuration); settings["configuration"] = configuration; @@ -144,7 +144,7 @@ namespace kerberos settings[begin->first] = begin->second; } - LINFO << helper::printStringMap("Final configuration:", settings); + VLOG(0) << helper::printStringMap("Final configuration:", settings); // ----------------- // Get instance name @@ -154,19 +154,16 @@ namespace kerberos // ------------------------------------------- // Check if we need to disable verbose logging - easyloggingpp::Logger * logger = easyloggingpp::Loggers::getLogger("business"); - easyloggingpp::Configurations & config = logger->configurations(); if(settings.at("logging") == "false") { - LINFO << "Logging is set to info"; - config.set(easyloggingpp::Level::Info, easyloggingpp::ConfigurationType::Enabled, "false"); + VLOG(0) << "Logging is set to info"; + el::Loggers::setVerboseLevel(0); } else { - LINFO << "Logging is set to verbose"; - config.set(easyloggingpp::Level::Info, easyloggingpp::ConfigurationType::Enabled, "true"); + VLOG(0) << "Logging is set to verbose"; + el::Loggers::setVerboseLevel(1); } - logger->reconfigure(); // ------------------ // Configure capture @@ -223,7 +220,7 @@ namespace kerberos if(stream != 0) { - LINFO << "Stopping streaming"; + VLOG(0) << "Stopping streaming"; stopStreamThread(); delete stream; stream = 0; @@ -231,7 +228,7 @@ namespace kerberos if(capture != 0) { - LINFO << "Stopping capture device"; + VLOG(0) << "Stopping capture device"; if(capture->isOpened()) { machinery->disableCapture(); @@ -248,7 +245,7 @@ namespace kerberos // --------------------------- // Initialize capture device - LINFO << "Starting capture device: " + settings.at("capture"); + VLOG(0) << "Starting capture device: " + settings.at("capture"); capture = Factory::getInstance()->create(settings.at("capture")); capture->setup(settings); capture->startGrabThread(); @@ -257,7 +254,6 @@ namespace kerberos // ------------------ // Initialize stream - usleep(1000*5000); stream = new Stream(); stream->configureStream(settings); startStreamThread(); @@ -273,14 +269,14 @@ namespace kerberos if(cloud != 0) { - LINFO << "Stopping cloud service"; + VLOG(0) << "Stopping cloud service"; cloud->stopUploadThread(); cloud->stopPollThread(); cloud->stopHealthThread(); delete cloud; } - LINFO << "Starting cloud service: " + settings.at("cloud"); + VLOG(0) << "Starting cloud service: " + settings.at("cloud"); cloud = Factory::getInstance()->create(settings.at("cloud")); cloud->setCapture(capture); cloud->setup(settings); @@ -387,7 +383,7 @@ namespace kerberos // If no new detections are found, we will run the IO devices (or max 30 images in memory) if((currentCount > 0 && timesEqual > 4) || currentCount >= 30) { - BINFO << "Executing IO devices for " + helper::to_string(currentCount) + " detection(s)"; + VLOG(1) << "Executing IO devices for " + helper::to_string(currentCount) + " detection(s)"; for (int i = 0; i < currentCount; i++) { @@ -402,7 +398,7 @@ namespace kerberos } else { - LERROR << "IO: can't execute"; + LOG(ERROR) << "IO: can't execute"; } pthread_mutex_unlock(&kerberos->m_ioLock); usleep(500*1000); diff --git a/src/kerberos/capture/Capture.cpp b/src/kerberos/capture/Capture.cpp index f963b9b..abf8a36 100755 --- a/src/kerberos/capture/Capture.cpp +++ b/src/kerberos/capture/Capture.cpp @@ -94,7 +94,8 @@ namespace kerberos } catch(cv::Exception & ex) { - LERROR << ex.what(); + //LERROR << ex.what(); + LOG(ERROR) << "Capture: devices is blocking, and not grabbing any more frames."; } } usleep(333*100); @@ -135,11 +136,11 @@ namespace kerberos healthCounter = capture->healthCounter.load(); usleep(5000*1000); // every 5s. - BINFO << "Capture: checking health status of camera."; + VLOG(1) << "Capture: checking health status of camera."; if(healthCounter == capture->healthCounter.load()) { - LINFO << "Capture: devices is blocking, and not grabbing any more frames."; + VLOG(0) << "Capture: devices is blocking, and not grabbing any more frames."; throw KerberosCouldNotGrabFromCamera("devices is blocking, and not grabbin any more frames."); } } diff --git a/src/kerberos/capture/IPCamera.cpp b/src/kerberos/capture/IPCamera.cpp index 3b424fa..48446d9 100755 --- a/src/kerberos/capture/IPCamera.cpp +++ b/src/kerberos/capture/IPCamera.cpp @@ -190,8 +190,8 @@ namespace kerberos } void IPCamera::reopen() { - LINFO << "Capture: Trying to open IP camera."; - LINFO << "Capture: (Warning) You can change the capture device with the configuration files."; + VLOG(0) << "Capture: Trying to open IP camera."; + VLOG(0) << "Capture: (Warning) You can change the capture device with the configuration files."; m_camera->release(); open(m_url.c_str()); @@ -208,7 +208,7 @@ namespace kerberos } } - LINFO << "Capture: Succesfully opened IP camera."; + VLOG(0) << "Capture: Succesfully opened IP camera."; } void IPCamera::close() diff --git a/src/kerberos/capture/RaspiCamera.cpp b/src/kerberos/capture/RaspiCamera.cpp index 07c1a97..43bc7a8 100755 --- a/src/kerberos/capture/RaspiCamera.cpp +++ b/src/kerberos/capture/RaspiCamera.cpp @@ -48,7 +48,7 @@ void* preview_thread(void* self) // a good solution is to implement frame skipping (measure time between to loops, if this time // is too big, just skip image processing and MJPEG sendout) - BINFO << "RaspiCamera: Entering preview thread."; + VLOG(1) << "RaspiCamera: Entering preview thread."; while (state.running) { capture->incrementHealth(); @@ -57,7 +57,7 @@ void* preview_thread(void* self) // If zero-copy is activated, we don't pass any buffer capture->data_length = state.camera->getOutputData(70, nullptr); } - BINFO << "RaspiCamera: Exiting preview thread."; + VLOG(1) << "RaspiCamera: Exiting preview thread."; return nullptr; } @@ -69,7 +69,7 @@ void* record_thread(void* self) uint8_t* data = new uint8_t[65536*4]; - BINFO << "RaspiCamera: Entering record thread."; + VLOG(1) << "RaspiCamera: Entering record thread."; while(state.running) { // Consume h264 data, this is a blocking call @@ -80,7 +80,7 @@ void* record_thread(void* self) file.flush(); } } - BINFO << "RaspiCamera: Exiting record thread."; + VLOG(1) << "RaspiCamera: Exiting record thread."; return nullptr; } @@ -200,9 +200,9 @@ namespace kerberos void RaspiCamera::open() { - LINFO << "Capture: Trying to open Raspberry Pi camera module."; - LINFO << "Capture: (Warning) If you see a OMX_GetHandle error, this means that you don't have a working RPi camera module attached."; - LINFO << "Capture: (Warning) You can change the capture device with the configuration files."; + VLOG(0) << "Capture: Trying to open Raspberry Pi camera module."; + VLOG(0) << "Capture: (Warning) If you see a OMX_GetHandle error, this means that you don't have a working RPi camera module attached."; + VLOG(0) << "Capture: (Warning) You can change the capture device with the configuration files."; // Initialize hardware bcm_host_init(); @@ -257,7 +257,7 @@ namespace kerberos pthread_create(&state.record_thid, nullptr, &record_thread, this); pthread_detach(state.record_thid); - LINFO << "Capture: Succesfully opened Raspberry Pi camera module."; + VLOG(0) << "Capture: Succesfully opened Raspberry Pi camera module."; } void RaspiCamera::stopThreads() diff --git a/src/kerberos/capture/Stream.cpp b/src/kerberos/capture/Stream.cpp index 387f116..71d026a 100755 --- a/src/kerberos/capture/Stream.cpp +++ b/src/kerberos/capture/Stream.cpp @@ -30,7 +30,7 @@ namespace kerberos } else { - LERROR << "Settings: can't use invalid port"; + LOG(ERROR) << "Settings: can't use invalid port"; //TODO: manage invalid port error } } @@ -57,7 +57,7 @@ namespace kerberos } sock = (INVALID_SOCKET); - LINFO << "Stream: Succesfully closed streaming"; + VLOG(0) << "Stream: Succesfully closed streaming"; return false; } @@ -83,7 +83,7 @@ namespace kerberos while(bind(sock, (SOCKADDR*) &address, sizeof(SOCKADDR_IN)) == SOCKET_ERROR) { - LERROR << "Stream: couldn't bind sock"; + LOG(ERROR) << "Stream: couldn't bind sock"; release(); usleep(1000*10000); sock = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); @@ -91,14 +91,13 @@ namespace kerberos while(listen(sock, 2) == SOCKET_ERROR) { - LERROR << "Stream: couldn't listen on sock"; + LOG(ERROR) << "Stream: couldn't listen on sock"; usleep(1000*10000); } FD_SET(sock, &master); - - LINFO << "Stream: Configured stream on port " << helper::to_string(m_streamPort) << " with quality: " << helper::to_string(m_quality); + VLOG(0) << "Stream: Configured stream on port " << helper::to_string(m_streamPort) << " with quality: " << helper::to_string(m_quality); return true; } @@ -174,12 +173,14 @@ namespace kerberos if(!tokenFound) { - LERROR << "Stream: no token found in client request."; + //LERROR << "Stream: no token found in client request."; + LOG(ERROR) << "Stream: no token found in client request."; return false; } else if(token != credentialsBase64) { - LERROR << "Stream: token found, but it's not correct."; + //LERROR << "Stream: token found, but it's not correct."; + LOG(ERROR) << "Stream: token found, but it's not correct."; return false; } @@ -187,7 +188,8 @@ namespace kerberos } else { - LERROR << "Stream: no token found in client request."; + //LERROR << "Stream: no token found in client request."; + LOG(ERROR) << "Stream: no token found in client request."; return false; } @@ -212,8 +214,10 @@ namespace kerberos if (client == SOCKET_ERROR) { - LERROR << "Stream: couldn't accept connection on sock"; - LERROR << "Stream: reopening master sock"; + //LERROR << "Stream: couldn't accept connection on sock"; + //LERROR << "Stream: reopening master sock"; + LOG(ERROR) << "Stream: couldn't accept connection on sock"; + LOG(ERROR) << "Stream: reopening master sock"; release(); open(); return false; @@ -251,9 +255,10 @@ namespace kerberos "\r\n",0); - LINFO << "Stream: authentication success"; - LINFO << "Stream: opening socket for new client."; - + //LINFO << "Stream: authentication success"; + //LINFO << "Stream: opening socket for new client."; + LOG(INFO) << "Stream: authentication success"; + LOG(INFO) << "Stream: opening socket for new client."; clients.push_back(client); packetsSend[client] = 0; @@ -271,7 +276,8 @@ namespace kerberos snprintf (response, sizeof (response), unauthorized, requestInfo["method"].c_str()); _write (client, response, strlen(response)); - LINFO << "Stream: authentication failed."; + //LINFO << "Stream: authentication failed."; + LOG(INFO) << "Stream: authentication failed."; FD_CLR(client, &master); shutdown(client, 2); diff --git a/src/kerberos/capture/USBCamera.cpp b/src/kerberos/capture/USBCamera.cpp index 134aae6..d8542d1 100755 --- a/src/kerberos/capture/USBCamera.cpp +++ b/src/kerberos/capture/USBCamera.cpp @@ -124,8 +124,8 @@ namespace kerberos void USBCamera::open() { - LINFO << "Capture: Trying to open USB camera."; - LINFO << "Capture: (Warning) You can change the capture device with the configuration files."; + VLOG(0) << "Capture: Trying to open USB camera."; + VLOG(0) << "Capture: (Warning) You can change the capture device with the configuration files."; try { @@ -146,7 +146,7 @@ namespace kerberos throw OpenCVException(ex.msg.c_str()); } - LINFO << "Capture: Succesfully opened USB camera."; + VLOG(0) << "Capture: Succesfully opened USB camera."; } void USBCamera::close() diff --git a/src/kerberos/cloud/Cloud.cpp b/src/kerberos/cloud/Cloud.cpp index d5a5ef7..72e3ffb 100755 --- a/src/kerberos/cloud/Cloud.cpp +++ b/src/kerberos/cloud/Cloud.cpp @@ -64,17 +64,16 @@ namespace kerberos // Create product key file std::string command = "touch " + m_keyFile; std::string createProductKeyFile = helper::GetStdoutFromCommand(command); - BINFO << "Cloud: create key file"; + VLOG(1) << "Cloud: create key file"; // Write product key command = "echo " + key + " > " + m_keyFile; std::string writeProductKey = helper::GetStdoutFromCommand(command); - BINFO << "Cloud: write key"; + VLOG(1) << "Cloud: write key"; // Reset key setProductKey(key); - - BINFO << "Cloud: reset product key (" << key << ")"; + VLOG(1) << "Cloud: reset product key (" << key << ")"; } startPollThread(); @@ -286,9 +285,9 @@ namespace kerberos health += "}"; RestClient::Response r = conn->post("/api/v1/health", health); - BINFO << "Cloud: data - " << health; - BINFO << "Cloud: send device health - " << r.code; - BINFO << "Cloud: send device health - " << r.body; + VLOG(1) << "Cloud: data - " << health; + VLOG(1) << "Cloud: send device health - " << r.code; + VLOG(1) << "Cloud: send device health - " << r.body; usleep(15*1000*1000); // every 15s } diff --git a/src/kerberos/cloud/S3.cpp b/src/kerberos/cloud/S3.cpp index ab28d1d..62948c3 100755 --- a/src/kerberos/cloud/S3.cpp +++ b/src/kerberos/cloud/S3.cpp @@ -114,13 +114,13 @@ namespace kerberos // ---------------------------------------------- // Before send the headers, we need to sort them! - BINFO << "S3: Sending new file to cloud."; + VLOG(1) << "S3: Sending new file to cloud."; std::sort(canonicalizedAmzHeaders.begin(), canonicalizedAmzHeaders.end()); for(int i = 0; i < canonicalizedAmzHeaders.size(); i++) { - BINFO << "S3 - File info: " << canonicalizedAmzHeaders[i]; + VLOG(1) << "S3 - File info: " << canonicalizedAmzHeaders[i]; } return canonicalizedAmzHeaders; @@ -240,7 +240,7 @@ namespace kerberos curl_easy_setopt(curlHandle, CURLOPT_WRITEFUNCTION, write); curl_easy_setopt(curlHandle, CURLOPT_WRITEDATA, &output); - BINFO << "S3: uploading image to bucket."; + VLOG(1) << "S3: uploading image to bucket."; result = curl_easy_perform(curlHandle); //Perform long http_code = 0; @@ -254,7 +254,7 @@ namespace kerberos // Check if file really was uploaded. // We'll query the S3 bucket and check if it's there. - BINFO << "S3: file succesfully uploaded."; + VLOG(1) << "S3: file succesfully uploaded."; return doesExist(pathToImage); @@ -264,7 +264,7 @@ namespace kerberos // User is not allowed to push with these credentials. // We remove the symbol. - BINFO << "S3: permission denied, your file wasn't uploaded."; + VLOG(1) << "S3: permission denied, your file wasn't uploaded."; return true; @@ -272,7 +272,7 @@ namespace kerberos else { - BINFO << "S3: file was not uploaded, something went wrong. Please check if you internet connectivity works."; + VLOG(1) << "S3: file was not uploaded, something went wrong. Please check if you internet connectivity works."; } } @@ -349,7 +349,7 @@ namespace kerberos curl_easy_setopt(curlHandle, CURLOPT_WRITEFUNCTION, write); curl_easy_setopt(curlHandle, CURLOPT_WRITEDATA, &output); - BINFO << "S3: checking if file exists in bucket."; + VLOG(1) << "S3: checking if file exists in bucket."; result = curl_easy_perform(curlHandle); //Perform long http_code = 0; @@ -359,11 +359,11 @@ namespace kerberos if(http_code == 200 && result != CURLE_ABORTED_BY_CALLBACK) { - BINFO << "S3: file exists in bucket, succesfully uploaded."; + VLOG(1) << "S3: file exists in bucket, succesfully uploaded."; return true; } - BINFO << "S3: file wasn't uploaded, something went wrong."; + VLOG(1) << "S3: file wasn't uploaded, something went wrong."; return false; } diff --git a/src/kerberos/machinery/Machinery.cpp b/src/kerberos/machinery/Machinery.cpp index d9e0631..be0442a 100755 --- a/src/kerberos/machinery/Machinery.cpp +++ b/src/kerberos/machinery/Machinery.cpp @@ -8,7 +8,7 @@ namespace kerberos // ----------------------------------------------------------- // Creates condition, algorithms, expositors, heuristics and io handlers. - LINFO << "Starting conditions: " + settings.at("condition"); + VLOG(0) << "Starting conditions: " + settings.at("condition"); std::vector conditions = Factory::getInstance()->createMultiple(settings.at("condition")); for(int i = 0; i < conditions.size(); i++) { @@ -16,22 +16,22 @@ namespace kerberos } setCondition(conditions); - LINFO << "Starting algorithm: " + settings.at("algorithm"); + VLOG(0) << "Starting algorithm: " + settings.at("algorithm"); Algorithm * algorithm = Factory::getInstance()->create(settings.at("algorithm")); algorithm->setup(settings); setAlgorithm(algorithm); - LINFO << "Starting expositor: " + settings.at("expositor"); + VLOG(0) << "Starting expositor: " + settings.at("expositor"); Expositor * expositor = Factory::getInstance()->create(settings.at("expositor")); expositor->setup(settings); setExpositor(expositor); - LINFO << "Starting heuristic: " + settings.at("heuristic"); + VLOG(0) << "Starting heuristic: " + settings.at("heuristic"); Heuristic * heuristic = Factory::getInstance()->create(settings.at("heuristic")); heuristic->setup(settings); setHeuristic(heuristic); - LINFO << "Starting io devices: " + settings.at("io"); + VLOG(0) << "Starting io devices: " + settings.at("io"); std::vector ios = Factory::getInstance()->createMultiple(settings.at("io")); for(int i = 0; i < ios.size(); i++) { diff --git a/src/kerberos/machinery/condition/Enabled.cpp b/src/kerberos/machinery/condition/Enabled.cpp index 6917e49..819ef66 100755 --- a/src/kerberos/machinery/condition/Enabled.cpp +++ b/src/kerberos/machinery/condition/Enabled.cpp @@ -5,7 +5,7 @@ namespace kerberos void Enabled::setup(const StringMap & settings) { Condition::setup(settings); - + bool enabled = false; if(settings.at("conditions.Enabled.active") == "true") { @@ -20,10 +20,10 @@ namespace kerberos { if(!isEnabled()) { - BINFO << "Condition: not enabled."; + VLOG(0) << "Condition: not enabled."; usleep(getDelay()*1000); } - + return m_enabled; } -} \ No newline at end of file +} diff --git a/src/kerberos/machinery/condition/Time.cpp b/src/kerberos/machinery/condition/Time.cpp index 868c2b3..6ca1f41 100755 --- a/src/kerberos/machinery/condition/Time.cpp +++ b/src/kerberos/machinery/condition/Time.cpp @@ -6,10 +6,10 @@ namespace kerberos { Condition::setup(settings); std::vector > times; - + std::vector days; helper::tokenize(settings.at("conditions.Time.times").c_str(), days, "-"); - + for(int i = 0; i < days.size(); i++) { std::vector startAndStop; @@ -22,37 +22,37 @@ namespace kerberos std::replace(timezone.begin(), timezone.end(), '-', '/'); std::replace(timezone.begin(), timezone.end(), '$', '_'); setTimezone(timezone); - + setDelay(std::atoi(settings.at("conditions.Time.delay").c_str())); } bool Time::allowed(const ImageVector & images) { std::string currentDateTime = helper::currentDateTime(m_timezone); - + // Split currentDateTime by space std::vector tokens; helper::tokenize(currentDateTime, tokens, " "); int dayOfWeek = std::atoi(tokens[2].c_str())-1; - + // Get time and remove leading zero (e.g. 09:10:23 -> 9:10:23) std::string currentTime = tokens[1]; if(currentTime[0] == '0') currentTime.erase(0, 1); - + std::string from = m_times[dayOfWeek].first + ":00"; std::string to = m_times[dayOfWeek].second + ":00"; - + int isAllowedFrom = helper::compareTime(currentTime, from); int isAllowedTo = helper::compareTime(to, currentTime); bool isAllowed = (isAllowedFrom >= 0 && isAllowedTo >= 0); if(!isAllowed) { - BINFO << "Condition: not in time interval."; + VLOG(0) << "Condition: not in time interval."; usleep(getDelay()*1000); } - + return isAllowed; } } diff --git a/src/kerberos/machinery/expositor/HullExpositor.cpp b/src/kerberos/machinery/expositor/HullExpositor.cpp index b8c793e..b0830b1 100755 --- a/src/kerberos/machinery/expositor/HullExpositor.cpp +++ b/src/kerberos/machinery/expositor/HullExpositor.cpp @@ -97,7 +97,7 @@ namespace kerberos if(numberOfChanges) { - BINFO << "HullExpositor: activity detected from (" + helper::to_string(rectangle.m_x1) + "," + helper::to_string(rectangle.m_y1) + ") to (" + helper::to_string(rectangle.m_x2) + "," + helper::to_string(rectangle.m_y2) + ")"; + VLOG(0) << "HullExpositor: activity detected from (" + helper::to_string(rectangle.m_x1) + "," + helper::to_string(rectangle.m_y1) + ") to (" + helper::to_string(rectangle.m_x2) + "," + helper::to_string(rectangle.m_y2) + ")"; } data.AddMember("numberOfChanges", numberOfChanges, allocator); diff --git a/src/kerberos/machinery/expositor/RectangleExpositor.cpp b/src/kerberos/machinery/expositor/RectangleExpositor.cpp index c285e6a..537412a 100755 --- a/src/kerberos/machinery/expositor/RectangleExpositor.cpp +++ b/src/kerberos/machinery/expositor/RectangleExpositor.cpp @@ -19,7 +19,7 @@ namespace kerberos m_x2 = x2; m_y2 = y2; } - + void RectangleExpositor::calculate(Image & evaluation, JSON & data) { int numberOfChanges = 0; @@ -42,20 +42,20 @@ namespace kerberos } } } - + // ------------------------- //check if not out of bounds - + if(rectangle.m_x1-10 > 0) rectangle.m_x1 -= 10; if(rectangle.m_y1-10 > 0) rectangle.m_y1 -= 10; if(rectangle.m_x2+10 < evaluation.getColumns()-1) rectangle.m_x2 += 10; if(rectangle.m_y2+10 < evaluation.getRows()-1) rectangle.m_y2 += 10; - + // -------------------------- // Add coordinates to object - + JSON::AllocatorType& allocator = data.GetAllocator(); - + JSONValue region; region.SetArray(); region.PushBack(rectangle.m_x1, allocator); @@ -64,15 +64,15 @@ namespace kerberos region.PushBack(rectangle.m_y2, allocator); data.AddMember("regionCoordinates", region, allocator); - + // -------------------------- // Add number of changes if(numberOfChanges) { - BINFO << "RectangleExpositor: activity detected from (" + helper::to_string(rectangle.m_x1) + "," + helper::to_string(rectangle.m_y1) + ") to (" + helper::to_string(rectangle.m_x2) + "," + helper::to_string(rectangle.m_y2) + ")"; + VLOG(0) << "RectangleExpositor: activity detected from (" + helper::to_string(rectangle.m_x1) + "," + helper::to_string(rectangle.m_y1) + ") to (" + helper::to_string(rectangle.m_x2) + "," + helper::to_string(rectangle.m_y2) + ")"; } data.AddMember("numberOfChanges", numberOfChanges, allocator); } -} \ No newline at end of file +} diff --git a/src/kerberos/machinery/heuristic/Counter.cpp b/src/kerberos/machinery/heuristic/Counter.cpp index 78aaddf..ae5f1e9 100755 --- a/src/kerberos/machinery/heuristic/Counter.cpp +++ b/src/kerberos/machinery/heuristic/Counter.cpp @@ -5,7 +5,7 @@ namespace kerberos void Counter::setup(const StringMap & settings) { std::vector coordinates; - + // Set incoming coordinates helper::tokenize(settings.at("heuristics.Counter.markers"), coordinates, "|"); for(int i = 0; i < 2; i++) @@ -17,7 +17,7 @@ namespace kerberos cv::Point p(from ,to); m_in.push_back(p); } - + // Set outgoing coordinates for(int i = 2; i < 4; i++) @@ -43,23 +43,23 @@ namespace kerberos cv::Point2f x = o2 - o1; cv::Point2f d1 = p1 - o1; cv::Point2f d2 = p2 - o2; - + float cross = d1.x * d2.y - d1.y * d2.x; - + if (std::abs(cross) < 1e-8) { return false; } - + double t1 = (x.x * d2.y - x.y * d2.x)/cross; r = o1 + d1 * t1; - + if((r.x <= MAX(o1.x, p1.x) && r.x >= MIN(o1.x, p1.x) && r.y <= MAX(o1.y, p1.y) && r.y >= MIN(o1.y, p1.y)) && (r.x <= MAX(o2.x, p2.x) && r.x >= MIN(o2.x, p2.x) && r.y <= MAX(o2.y, p2.y) && r.y >= MIN(o2.y, p2.y))) { return true; } - + return false; } @@ -71,7 +71,7 @@ namespace kerberos int incoming = 0; int outgoing = 0; - + kerberos::Image image = evaluation; cv::Mat img = image.getImage(); cv::dilate(img, img, cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(25,25))); @@ -79,21 +79,21 @@ namespace kerberos cv::Point & outTop = m_out[0]; cv::Point & outBottom = m_out[1]; - + cv::Point & inTop = m_in[0]; cv::Point & inBottom = m_in[1]; - + std::vector > contours; std::vector hierarchy; cv::findContours(image.getImage(), contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_NONE); - + int numberOfContours= 0; for(int i = 0; i < m_features.size(); i++) { int mostRecent = m_features[i].size() - 1; m_features[i][mostRecent].decreaseAppearance(); } - + // Find new tracks if(contours.size() > 0) { @@ -103,20 +103,20 @@ namespace kerberos int x = moments.m10/moments.m00; int y = moments.m01/moments.m00; int area = cv::contourArea(contours[i]); - + if(area < m_minArea) continue; - + Feature current(x, y, area, m_appearance); int best = -1; double bestValue = 99999999; double bestArea = 99999999; - + for(int j = 0; j < m_features.size(); j++) { int mostRecent = m_features[j].size() - 1; double distance = current.distance(m_features[j][mostRecent]); double areaDistance = current.areaDistance(m_features[j][mostRecent]); - + if(distance < m_maxDistance && distance < bestValue + m_maxDistance/2) { if(areaDistance < bestArea) @@ -126,7 +126,7 @@ namespace kerberos } } } - + if(best == -1) { std::vector tracking; @@ -137,18 +137,18 @@ namespace kerberos { m_features[best].push_back(current); } - + numberOfContours++; } } - + // Remove old tracks std::vector >::iterator it = m_features.begin(); while(it != m_features.end()) { Feature & back = it->back(); back.decreaseAppearance(); - + if(back.getAppearance() < 0) { it = m_features.erase(it); @@ -158,7 +158,7 @@ namespace kerberos it++; } } - + // Check existing tracks if they crossed the line it = m_features.begin(); while(it != m_features.end()) @@ -170,11 +170,11 @@ namespace kerberos cv::Point2f prev((*it)[j-1].getX(),(*it)[j-1].getY()); cv::Point2f curr((*it)[j].getX(),(*it)[j].getY()); } - + // Check if cross line cv::Point2f start((*it)[0].getX(),(*it)[0].getY()); cv::Point2f end((*it)[it->size()-1].getX(),(*it)[it->size()-1].getY()); - + // Check if interset in line cv::Point2f intersectionPointOutgoing; bool inLine = false; @@ -189,11 +189,11 @@ namespace kerberos { outLine = true; } - + // Check if interesected both Direction xDirection = parallell; Direction yDirection = parallell; - + if(inLine && outLine) { // What is the direction (incoming our outgoing?) @@ -213,7 +213,7 @@ namespace kerberos { yDirection = top; } - + // Check which intersection point comes first if(xDirection != parallell) { @@ -244,9 +244,9 @@ namespace kerberos } else { - + } - + it = m_features.erase(it); } else @@ -265,12 +265,12 @@ namespace kerberos JSON::AllocatorType& allocator = data.GetAllocator(); data.AddMember("incoming", incoming, allocator); data.AddMember("outgoing", outgoing, allocator); - + if(m_onlyTrueWhenCounted) { if(incoming > 0 || outgoing > 0) { - BINFO << "Counter: in (" << helper::to_string(incoming) << "), out (" << helper::to_string(outgoing) << ")"; + VLOG(0) << "Counter: in (" << helper::to_string(incoming) << "), out (" << helper::to_string(outgoing) << ")"; return true; } } @@ -283,7 +283,7 @@ namespace kerberos { usleep(m_noMotionDelayTime*1000); } - + return false; } } diff --git a/src/kerberos/machinery/heuristic/Sequence.cpp b/src/kerberos/machinery/heuristic/Sequence.cpp index bf29017..31e3c56 100755 --- a/src/kerberos/machinery/heuristic/Sequence.cpp +++ b/src/kerberos/machinery/heuristic/Sequence.cpp @@ -9,7 +9,7 @@ namespace kerberos setSequenceDuration(std::atoi(settings.at("heuristics.Sequence.minimumDuration").c_str())); setNoMotionDelayTime(std::atoi(settings.at("heuristics.Sequence.noMotionDelayTime").c_str())); } - + bool Sequence::isValid(const Image & evaluation, const ImageVector & images, JSON & data) { int numberOfChanges; @@ -22,7 +22,7 @@ namespace kerberos duration++; if(duration >= m_sequenceDuration) { - BINFO << "Heuristic is valid; numberOfChanges: " + helper::to_string(numberOfChanges) + ", Sequence duration: " + helper::to_string(m_sequenceDuration); + VLOG(0) << "Heuristic is valid; numberOfChanges: " + helper::to_string(numberOfChanges) + ", Sequence duration: " + helper::to_string(m_sequenceDuration); return true; } } @@ -40,7 +40,7 @@ namespace kerberos usleep(m_noMotionDelayTime*1000); } } - + return false; } } diff --git a/src/kerberos/machinery/io/IoDisk.cpp b/src/kerberos/machinery/io/IoDisk.cpp index ccd36d7..d880950 100755 --- a/src/kerberos/machinery/io/IoDisk.cpp +++ b/src/kerberos/machinery/io/IoDisk.cpp @@ -271,7 +271,7 @@ namespace kerberos // ------------------------- // Save original version - BINFO << "IoDisk: saving image " + pathToImage; + VLOG(0) << "IoDisk: saving image " + pathToImage; return m_fileManager.save(image, pathToImage, m_createSymbol); } diff --git a/src/kerberos/machinery/io/IoGPIO.cpp b/src/kerberos/machinery/io/IoGPIO.cpp index f7c45ea..7bab7ff 100755 --- a/src/kerberos/machinery/io/IoGPIO.cpp +++ b/src/kerberos/machinery/io/IoGPIO.cpp @@ -54,7 +54,7 @@ namespace kerberos // ------------------------ // Trigger the GPIO pin - BINFO << "IoGPIO: triggering GPIO pin " + helper::to_string(m_pin); + VLOG(0) << "IoGPIO: triggering GPIO pin " + helper::to_string(m_pin); for(int i = 0; i < m_periods; i++) { diff --git a/src/kerberos/machinery/io/IoMQTT.cpp b/src/kerberos/machinery/io/IoMQTT.cpp index 8100b5c..fb05738 100644 --- a/src/kerberos/machinery/io/IoMQTT.cpp +++ b/src/kerberos/machinery/io/IoMQTT.cpp @@ -71,7 +71,7 @@ namespace kerberos std::string message { buffer.GetString() }; bool sendSuccessfully = send_message(message); - BINFO << "IoMQTT: sending message..." << ((sendSuccessfully) ? "sent" : "error"); + VLOG(0) << "IoMQTT: sending message..." << ((sendSuccessfully) ? "sent" : "error"); return sendSuccessfully; } diff --git a/src/kerberos/machinery/io/IoPushbullet.cpp b/src/kerberos/machinery/io/IoPushbullet.cpp index 7bca509..8f8a61f 100755 --- a/src/kerberos/machinery/io/IoPushbullet.cpp +++ b/src/kerberos/machinery/io/IoPushbullet.cpp @@ -19,7 +19,7 @@ namespace kerberos //------ //set pushbullet token - + setToken((settings.at("ios.Pushbullet.token").c_str())); // ------------- @@ -64,7 +64,7 @@ namespace kerberos std::string upUrl ; std::string fileUrl ; RestClient::Response r; - + /* * Step 1 : save file to tmp and provide path in a string var */ @@ -77,36 +77,36 @@ namespace kerberos */ r = pushbulletConnection->post("/v2/upload-request", "{\"file_name\":\"detection.jpg\",\"file_type\":\"image/jpeg\"}"); - + if(r.code == 200){ pbResp.Parse(r.body.c_str()); upUrl = pbResp["upload_url"].GetString(); fileUrl = pbResp["file_url"].GetString(); - BINFO << "IoPushbullet: response to upload request " + r.body; + VLOG(0) << "IoPushbullet: response to upload request " + r.body; /* * Step 3 : upload file to pushbullet */ - if (pbUploadImage(tmpFile, upUrl)) { + if (pbUploadImage(tmpFile, upUrl)) { /* * Step 4 : create text push for detection */ r = pushbulletConnection->post("/v2/pushes", "{\"type\":\"file\",\"file_url\":\""+ fileUrl +"\"}"); - if(r.code==200) - BINFO << "IoPushbullet: response to push file request " + r.body ; + if(r.code==200) + VLOG(0) << "IoPushbullet: response to push file request " + r.body ; } - } + } } // ------------------- // Send a message to pushbullet r = pushbulletConnection->post("/v2/pushes", "{\"body\":\"Motion detected\",\"title\":\"Kios\",\"type\":\"note\"}"); - + if(r.code == 200) { - BINFO << "IoPushbullet: response to post to pushbullet " + r.body; + VLOG(0) << "IoPushbullet: response to post to pushbullet " + r.body; return true; } @@ -116,7 +116,7 @@ namespace kerberos } bool IoPushbullet::pbUploadImage(std::string tmpFile, std::string upUrl) { - + CURL *curl; CURLcode res; @@ -124,11 +124,11 @@ namespace kerberos struct curl_httppost *lastptr = NULL; curl_global_init(CURL_GLOBAL_ALL); - curl_formadd(&formpost, &lastptr, + curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "file", CURLFORM_FILENAME, "detection.jpg", CURLFORM_FILE, tmpFile.c_str(), - CURLFORM_CONTENTTYPE, "image/jpeg", + CURLFORM_CONTENTTYPE, "image/jpeg", CURLFORM_END); curl = curl_easy_init(); @@ -141,10 +141,10 @@ namespace kerberos curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost); res = curl_easy_perform(curl); - + curl_easy_cleanup(curl); curl_formfree(formpost); - + if (res != CURLE_OK){ fprintf(stderr, "curl_easy_perform() failed: %s\n",curl_easy_strerror(res)); return false; diff --git a/src/kerberos/machinery/io/IoScript.cpp b/src/kerberos/machinery/io/IoScript.cpp index 18c9eb0..232d008 100755 --- a/src/kerberos/machinery/io/IoScript.cpp +++ b/src/kerberos/machinery/io/IoScript.cpp @@ -49,7 +49,7 @@ namespace kerberos // Send a post to URL std::string path = (std::string) getPath(); - BINFO << "IoScript: calling script at " + path; + VLOG(0) << "IoScript: calling script at " + path; if(path != "") { diff --git a/src/kerberos/machinery/io/IoTCP.cpp b/src/kerberos/machinery/io/IoTCP.cpp index 89e1ec8..2fbcd8f 100755 --- a/src/kerberos/machinery/io/IoTCP.cpp +++ b/src/kerberos/machinery/io/IoTCP.cpp @@ -40,7 +40,7 @@ namespace kerberos if (connect(sock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) >= 0) { - BINFO << "IoTCP: sending TCP packet to " + (std::string) getIp() + ":" + helper::to_string(getPort()); + VLOG(0) << "IoTCP: sending TCP packet to " + (std::string) getIp() + ":" + helper::to_string(getPort()); if (send(sock, getMessage(), strlen(getMessage()), 0) != strlen(getMessage())) { throw new SocketException("send() sent a different number of bytes than expected"); diff --git a/src/kerberos/machinery/io/IoVideo.cpp b/src/kerberos/machinery/io/IoVideo.cpp index 6008baa..2cc5b28 100755 --- a/src/kerberos/machinery/io/IoVideo.cpp +++ b/src/kerberos/machinery/io/IoVideo.cpp @@ -260,7 +260,7 @@ namespace kerberos pthread_mutex_lock(&m_release_lock); - BINFO << "IoVideo: firing"; + VLOG(0) << "IoVideo: firing"; // ------------------ // Check if the camera supports on board recording (camera specific), @@ -324,7 +324,7 @@ namespace kerberos // --------------- // Start recording - BINFO << "IoVideo: start new recording " << m_fileName; + VLOG(0) << "IoVideo: start new recording " << m_fileName; m_writer = new cv::VideoWriter(); m_writer->open(m_path, m_codec, m_fps, cv::Size(image.getColumns(), image.getRows())); @@ -408,14 +408,14 @@ namespace kerberos double cronoTime = (double) (cv::getTickCount() / cv::getTickFrequency()); double startedRecording = cronoTime; - BINFO << "IoVideo (FFMPEG): start writing images"; + VLOG(0) << "IoVideo (FFMPEG): start writing images"; pthread_mutex_lock(&video->m_write_lock); // Todo write video with FFMPEG.. // .. (video->m_path); - BINFO << "IoVideo: locked write thread"; + VLOG(0) << "IoVideo: locked write thread"; pthread_mutex_lock(&video->m_time_lock); double timeToRecord = video->m_timeStartedRecording + video->m_recordingTimeAfter; @@ -441,10 +441,10 @@ namespace kerberos { pthread_mutex_unlock(&video->m_lock); pthread_mutex_unlock(&video->m_time_lock); - LERROR << ex.what(); + LOG(ERROR) << ex.what(); } - BINFO << "IoVideo: end writing images"; + VLOG(0) << "IoVideo: end writing images"; pthread_mutex_lock(&video->m_release_lock); @@ -463,16 +463,16 @@ namespace kerberos } catch(cv::Exception & ex) { - LERROR << ex.what(); + LOG(ERROR) << ex.what(); } - BINFO << "IoVideo: remove videowriter"; + VLOG(0) << "IoVideo: remove videowriter"; pthread_mutex_unlock(&video->m_release_lock); pthread_mutex_unlock(&video->m_write_lock); - BINFO << "IoVideo: unlocking write thread"; + VLOG(0) << "IoVideo: unlocking write thread"; } void * recordOnboard(void * self) @@ -483,13 +483,13 @@ namespace kerberos double cronoTime = (double) (cv::getTickCount() / cv::getTickFrequency()); double startedRecording = cronoTime; - BINFO << "IoVideo (OnBoard): start writing images"; + VLOG(0) << "IoVideo (OnBoard): start writing images"; pthread_mutex_lock(&video->m_write_lock); video->m_capture->startRecord(video->m_path); - BINFO << "IoVideo: locked write thread"; + VLOG(0) << "IoVideo: locked write thread"; pthread_mutex_lock(&video->m_time_lock); double timeToRecord = video->m_timeStartedRecording + video->m_recordingTimeAfter; @@ -515,10 +515,10 @@ namespace kerberos { pthread_mutex_unlock(&video->m_lock); pthread_mutex_unlock(&video->m_time_lock); - LERROR << ex.what(); + LOG(ERROR) << ex.what(); } - BINFO << "IoVideo: end writing images"; + VLOG(0) << "IoVideo: end writing images"; pthread_mutex_lock(&video->m_release_lock); @@ -534,16 +534,16 @@ namespace kerberos } catch(cv::Exception & ex) { - LERROR << ex.what(); + LOG(ERROR) << ex.what(); } - BINFO << "IoVideo: remove videowriter"; + VLOG(0) << "IoVideo: remove videowriter"; pthread_mutex_unlock(&video->m_release_lock); pthread_mutex_unlock(&video->m_write_lock); - BINFO << "IoVideo: unlocking write thread"; + VLOG(0) << "IoVideo: unlocking write thread"; } // ------------------------------------------- @@ -562,11 +562,11 @@ namespace kerberos double startedRecording = cronoTime; double fpsToTime = 1. / video->m_fps; - BINFO << "IoVideo (OpenCV): start writing images"; + VLOG(0) << "IoVideo (OpenCV): start writing images"; pthread_mutex_lock(&video->m_write_lock); - BINFO << "IoVideo: locked write thread"; + VLOG(0) << "IoVideo: locked write thread"; pthread_mutex_lock(&video->m_time_lock); double timeToRecord = video->m_timeStartedRecording + video->m_recordingTimeAfter; @@ -589,7 +589,7 @@ namespace kerberos video->m_writer->write(video->m_mostRecentImage.getImage()); pthread_mutex_unlock(&video->m_lock); - BINFO << "IoVideo: writing image"; + VLOG(1) << "IoVideo: writing image"; // update time to record; (locking) pthread_mutex_lock(&video->m_time_lock); @@ -606,7 +606,7 @@ namespace kerberos } else { - BINFO << "IoVideo: framerate is too fast, can't record video at this speed (" << video->m_fps << "/FPS)"; + VLOG(0) << "IoVideo: framerate is too fast, can't record video at this speed (" << video->m_fps << "/FPS)"; } } } @@ -614,10 +614,10 @@ namespace kerberos { pthread_mutex_unlock(&video->m_lock); pthread_mutex_unlock(&video->m_time_lock); - LERROR << ex.what(); + LOG(ERROR) << ex.what(); } - BINFO << "IoVideo: end writing images"; + VLOG(0) << "IoVideo: end writing images"; pthread_mutex_lock(&video->m_release_lock); @@ -643,16 +643,16 @@ namespace kerberos } catch(cv::Exception & ex) { - LERROR << ex.what(); + LOG(ERROR) << ex.what(); } - BINFO << "IoVideo: remove videowriter"; + VLOG(0) << "IoVideo: remove videowriter"; pthread_mutex_unlock(&video->m_release_lock); pthread_mutex_unlock(&video->m_write_lock); - BINFO << "IoVideo: unlocking write thread"; + VLOG(0) << "IoVideo: unlocking write thread"; } void IoVideo::drawDateOnImage(Image & image, std::string timestamp) @@ -690,7 +690,7 @@ namespace kerberos bool recording = true; - BINFO << "IoVideo: initializing capture thread"; + VLOG(0) << "IoVideo: initializing capture thread"; while(recording) { @@ -703,7 +703,7 @@ namespace kerberos if(video->m_capture != 0 && recording) { - BINFO << "IoVideo: grabbing images"; + VLOG(1) << "IoVideo: grabbing images"; try { @@ -718,7 +718,7 @@ namespace kerberos catch(cv::Exception & ex) { pthread_mutex_unlock(&video->m_lock); - LERROR << ex.what(); + LOG(ERROR) << ex.what(); } } @@ -726,7 +726,7 @@ namespace kerberos usleep(1000); // sleep 1 ms } - BINFO << "IoVideo: closing capture thread"; + VLOG(0) << "IoVideo: closing capture thread"; } Image IoVideo::getImage() diff --git a/src/kerberos/machinery/io/IoWebhook.cpp b/src/kerberos/machinery/io/IoWebhook.cpp index 0bee6a5..3991276 100755 --- a/src/kerberos/machinery/io/IoWebhook.cpp +++ b/src/kerberos/machinery/io/IoWebhook.cpp @@ -57,7 +57,7 @@ namespace kerberos // ------------------- // Send a post to URL - BINFO << "IoWebhook: post to webhook " + (std::string) getUrl(); + VLOG(0) << "IoWebhook: post to webhook " + (std::string) getUrl(); RestClient::Response r = webhookConnection->post("/", buffer.GetString()); if(r.code == 200) diff --git a/src/main.cpp b/src/main.cpp index 02fa2e4..b408411 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -21,8 +21,7 @@ #include #include #include "easylogging++.h" - -_INITIALIZE_EASYLOGGINGPP +INITIALIZE_EASYLOGGINGPP using namespace kerberos; @@ -54,16 +53,20 @@ int main(int argc, char** argv) // ----------------- // Initialize logger - easyloggingpp::Configurations config; + el::Configurations config; config.setToDefault(); - config.setAll(easyloggingpp::ConfigurationType::Enabled, "true"); - config.setAll(easyloggingpp::ConfigurationType::ToFile, "true"); + config.set(el::Level::Global, el::ConfigurationType::Enabled, "true"); + config.set(el::Level::Global, el::ConfigurationType::ToFile, "true"); + config.set(el::Level::Global, el::ConfigurationType::ToStandardOutput, "true"); + config.set(el::Level::Global, el::ConfigurationType::LogFlushThreshold, "100"); + config.set(el::Level::Global, el::ConfigurationType::MaxLogFileSize, "5000000"); // 5MB std::string logFile = (helper::getValueByKey(parameters, "log")) ?: LOG_PATH; - config.setAll(easyloggingpp::ConfigurationType::Filename, logFile); - config.setAll(easyloggingpp::ConfigurationType::RollOutSize, "2048"); // 2KB - easyloggingpp::Loggers::reconfigureAllLoggers(config); + config.set(el::Level::Global, el::ConfigurationType::Filename, logFile.c_str()); + el::Loggers::addFlag(el::LoggingFlag::StrictLogFileSizeCheck); + el::Loggers::addFlag(el::LoggingFlag::ColoredTerminalOutput); + el::Loggers::reconfigureAllLoggers(config); - LINFO << "Logging is written to: " + logFile; + VLOG(0) << "Logging is written to: " + logFile; while(true) { @@ -77,7 +80,7 @@ int main(int argc, char** argv) } catch(Exception & ex) { - LERROR << ex.what(); + LOG(ERROR) << ex.what(); // Try again in 3 seconds.. usleep(3 * 1000000); diff --git a/test/test_main.cpp b/test/test_main.cpp index 7a171c9..b7a8267 100755 --- a/test/test_main.cpp +++ b/test/test_main.cpp @@ -2,14 +2,15 @@ #include "gmock/gmock.h" #include "easylogging++.h" -_INITIALIZE_EASYLOGGINGPP - +INITIALIZE_EASYLOGGINGPP + int main(int argc, char** argv) { - easyloggingpp::Configurations config; - config.setAll(easyloggingpp::ConfigurationType::Enabled , "false"); - easyloggingpp::Loggers::reconfigureAllLoggers(config); - - ::testing::InitGoogleMock(&argc, argv); + el::Configurations config; + config.setToDefault(); + config.set(el::Level::Info, el::ConfigurationType::Enabled, "false"); + el::Loggers::reconfigureAllLoggers(config); + + ::testing::InitGoogleMock(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} From f74d74cde3c1fca92dee6df1b5488d616e5a9ac6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Verstraeten?= Date: Mon, 21 May 2018 22:22:05 +0200 Subject: [PATCH 23/35] move cloud logging to verbose level 0 --- src/kerberos/cloud/S3.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/kerberos/cloud/S3.cpp b/src/kerberos/cloud/S3.cpp index 62948c3..7ec6373 100755 --- a/src/kerberos/cloud/S3.cpp +++ b/src/kerberos/cloud/S3.cpp @@ -114,7 +114,7 @@ namespace kerberos // ---------------------------------------------- // Before send the headers, we need to sort them! - VLOG(1) << "S3: Sending new file to cloud."; + VLOG(0) << "S3: Sending new file to cloud."; std::sort(canonicalizedAmzHeaders.begin(), canonicalizedAmzHeaders.end()); @@ -254,7 +254,7 @@ namespace kerberos // Check if file really was uploaded. // We'll query the S3 bucket and check if it's there. - VLOG(1) << "S3: file succesfully uploaded."; + VLOG(0) << "S3: file uploaded."; return doesExist(pathToImage); @@ -264,7 +264,7 @@ namespace kerberos // User is not allowed to push with these credentials. // We remove the symbol. - VLOG(1) << "S3: permission denied, your file wasn't uploaded."; + VLOG(0) << "S3: permission denied, your file wasn't uploaded."; return true; @@ -272,7 +272,7 @@ namespace kerberos else { - VLOG(1) << "S3: file was not uploaded, something went wrong. Please check if you internet connectivity works."; + VLOG(0) << "S3: file was not uploaded, something went wrong. Please check if you internet connectivity works."; } } @@ -359,11 +359,12 @@ namespace kerberos if(http_code == 200 && result != CURLE_ABORTED_BY_CALLBACK) { - VLOG(1) << "S3: file exists in bucket, succesfully uploaded."; + VLOG(0) << "S3: file exists in bucket, succesfully uploaded."; return true; } - VLOG(1) << "S3: file wasn't uploaded, something went wrong."; + VLOG(0) << "S3: file wasn't uploaded, something went wrong."; + return false; } From 15e38fb9efa4aa02250b4c2a340593679a3499a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Verstraeten?= Date: Mon, 21 May 2018 22:59:29 +0200 Subject: [PATCH 24/35] update to floating ip --- src/kerberos/cloud/ForwardStream.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kerberos/cloud/ForwardStream.cpp b/src/kerberos/cloud/ForwardStream.cpp index a1b973a..3e053bc 100644 --- a/src/kerberos/cloud/ForwardStream.cpp +++ b/src/kerberos/cloud/ForwardStream.cpp @@ -4,7 +4,7 @@ namespace kerberos { void ForwardStream::setup(std::string publicKey, std::string deviceKey) { - std::string ip = "178.62.38.102"; + std::string ip = "159.65.215.225"; int port = 1883; m_publicKey = publicKey; m_deviceKey = deviceKey; From c4b48c85eff5fa4dc4c2ee32c8809a4cf8898dac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Verstraeten?= Date: Tue, 22 May 2018 20:57:10 +0200 Subject: [PATCH 25/35] enable thread safe macro --- include/kerberos/Kerberos.h | 2 +- src/kerberos/capture/Stream.cpp | 7 ++----- src/main.cpp | 1 + 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/include/kerberos/Kerberos.h b/include/kerberos/Kerberos.h index 674c3f0..9037f28 100755 --- a/include/kerberos/Kerberos.h +++ b/include/kerberos/Kerberos.h @@ -51,7 +51,7 @@ namespace kerberos void setCaptureDelayTime(int delay){m_captureDelayTime=delay;}; void setParameters(StringMap & parameters) { - LOG(INFO) << helper::printStringMap("Parameters passed from commandline:", parameters); + VLOG(0) << helper::printStringMap("Parameters passed from commandline:", parameters); m_parameters = parameters; }; StringMap getParameters(){return m_parameters;} diff --git a/src/kerberos/capture/Stream.cpp b/src/kerberos/capture/Stream.cpp index 71d026a..9341bad 100755 --- a/src/kerberos/capture/Stream.cpp +++ b/src/kerberos/capture/Stream.cpp @@ -254,11 +254,8 @@ namespace kerberos "Content-Type: multipart/x-mixed-replace; boundary=mjpegstream\r\n" "\r\n",0); - - //LINFO << "Stream: authentication success"; - //LINFO << "Stream: opening socket for new client."; - LOG(INFO) << "Stream: authentication success"; - LOG(INFO) << "Stream: opening socket for new client."; + VLOG(0) << "Stream: authentication success"; + VLOG(0) << "Stream: opening socket for new client."; clients.push_back(client); packetsSend[client] = 0; diff --git a/src/main.cpp b/src/main.cpp index b408411..38c77ba 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -21,6 +21,7 @@ #include #include #include "easylogging++.h" +#define ELPP_THREAD_SAFE INITIALIZE_EASYLOGGINGPP using namespace kerberos; From bcd2c3a6b69987479530d97dad48af02f9f0bbe1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Verstraeten?= Date: Tue, 22 May 2018 20:58:48 +0200 Subject: [PATCH 26/35] thread safe --- src/main.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 38c77ba..30de215 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -20,8 +20,9 @@ #include #include #include -#include "easylogging++.h" + #define ELPP_THREAD_SAFE +#include "easylogging++.h" INITIALIZE_EASYLOGGINGPP using namespace kerberos; From 1e2ac88b5e8cb28ae38208bad07ac80f28d63797 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Verstraeten?= Date: Tue, 22 May 2018 23:26:28 +0200 Subject: [PATCH 27/35] move macro --- include/easylogging/easylogging++.h | 2 ++ src/main.cpp | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/include/easylogging/easylogging++.h b/include/easylogging/easylogging++.h index c425a44..ad31beb 100755 --- a/include/easylogging/easylogging++.h +++ b/include/easylogging/easylogging++.h @@ -15,6 +15,8 @@ // http://muflihun.com // +#define ELPP_THREAD_SAFE + #ifndef EASYLOGGINGPP_H #define EASYLOGGINGPP_H // Compilers and C++0x/C++11 Evaluation diff --git a/src/main.cpp b/src/main.cpp index 30de215..83f0e75 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -21,7 +21,6 @@ #include #include -#define ELPP_THREAD_SAFE #include "easylogging++.h" INITIALIZE_EASYLOGGINGPP From 9187c6164a7bc9390188d0f6d16cbdc9e81d2bbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Verstraeten?= Date: Wed, 23 May 2018 09:31:40 +0200 Subject: [PATCH 28/35] set define to 1 --- include/easylogging/easylogging++.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/easylogging/easylogging++.h b/include/easylogging/easylogging++.h index ad31beb..933595f 100755 --- a/include/easylogging/easylogging++.h +++ b/include/easylogging/easylogging++.h @@ -15,10 +15,9 @@ // http://muflihun.com // -#define ELPP_THREAD_SAFE - #ifndef EASYLOGGINGPP_H #define EASYLOGGINGPP_H +#define ELPP_THREAD_SAFE 1 // Compilers and C++0x/C++11 Evaluation #if __cplusplus >= 201103L # define ELPP_CXX11 1 From d34a1d01871f1f48eb1b3962ff2d50ed87cfa477 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Verstraeten?= Date: Wed, 23 May 2018 11:06:13 +0200 Subject: [PATCH 29/35] add sleep again --- src/kerberos/Kerberos.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/kerberos/Kerberos.cpp b/src/kerberos/Kerberos.cpp index dd5e1d9..adb79ac 100755 --- a/src/kerberos/Kerberos.cpp +++ b/src/kerberos/Kerberos.cpp @@ -254,6 +254,7 @@ namespace kerberos // ------------------ // Initialize stream + usleep(1000*5000); stream = new Stream(); stream->configureStream(settings); startStreamThread(); From 86f670d5a54da5f61da0097d36e6af6a108df858 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Verstraeten?= Date: Wed, 23 May 2018 13:19:18 +0200 Subject: [PATCH 30/35] change log levels --- src/kerberos/Kerberos.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/kerberos/Kerberos.cpp b/src/kerberos/Kerberos.cpp index adb79ac..8f5e57c 100755 --- a/src/kerberos/Kerberos.cpp +++ b/src/kerberos/Kerberos.cpp @@ -157,12 +157,12 @@ namespace kerberos if(settings.at("logging") == "false") { VLOG(0) << "Logging is set to info"; - el::Loggers::setVerboseLevel(0); + el::Loggers::setVerboseLevel(1); } else { VLOG(0) << "Logging is set to verbose"; - el::Loggers::setVerboseLevel(1); + el::Loggers::setVerboseLevel(2); } // ------------------ From 103105155be25d111dcea89b1428e5a3320d57e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Verstraeten?= Date: Wed, 23 May 2018 13:19:41 +0200 Subject: [PATCH 31/35] remove waiting --- src/kerberos/Kerberos.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/kerberos/Kerberos.cpp b/src/kerberos/Kerberos.cpp index 8f5e57c..25a13bd 100755 --- a/src/kerberos/Kerberos.cpp +++ b/src/kerberos/Kerberos.cpp @@ -254,7 +254,6 @@ namespace kerberos // ------------------ // Initialize stream - usleep(1000*5000); stream = new Stream(); stream->configureStream(settings); startStreamThread(); From 948d1498605d4203df659f641c85e96f1c3de0d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Verstraeten?= Date: Wed, 23 May 2018 13:30:46 +0200 Subject: [PATCH 32/35] update logging verbose levels --- src/kerberos/Kerberos.cpp | 18 ++++---- src/kerberos/capture/Capture.cpp | 4 +- src/kerberos/capture/IPCamera.cpp | 6 +-- src/kerberos/capture/RaspiCamera.cpp | 16 +++---- src/kerberos/capture/Stream.cpp | 8 ++-- src/kerberos/capture/USBCamera.cpp | 6 +-- src/kerberos/cloud/Cloud.cpp | 12 ++--- src/kerberos/cloud/S3.cpp | 20 ++++----- src/kerberos/machinery/Machinery.cpp | 10 ++--- src/kerberos/machinery/condition/Enabled.cpp | 2 +- src/kerberos/machinery/condition/Time.cpp | 2 +- .../machinery/expositor/HullExpositor.cpp | 2 +- .../expositor/RectangleExpositor.cpp | 2 +- src/kerberos/machinery/heuristic/Counter.cpp | 2 +- src/kerberos/machinery/heuristic/Sequence.cpp | 2 +- src/kerberos/machinery/io/IoDisk.cpp | 2 +- src/kerberos/machinery/io/IoGPIO.cpp | 2 +- src/kerberos/machinery/io/IoMQTT.cpp | 2 +- src/kerberos/machinery/io/IoPushbullet.cpp | 6 +-- src/kerberos/machinery/io/IoScript.cpp | 2 +- src/kerberos/machinery/io/IoTCP.cpp | 2 +- src/kerberos/machinery/io/IoVideo.cpp | 44 +++++++++---------- src/kerberos/machinery/io/IoWebhook.cpp | 2 +- 23 files changed, 87 insertions(+), 87 deletions(-) diff --git a/src/kerberos/Kerberos.cpp b/src/kerberos/Kerberos.cpp index 25a13bd..c831fd5 100755 --- a/src/kerberos/Kerberos.cpp +++ b/src/kerberos/Kerberos.cpp @@ -128,7 +128,7 @@ namespace kerberos // --------------------------- // Get settings from XML file - VLOG(0) << "Reading configuration file: " << configuration; + VLOG(1) << "Reading configuration file: " << configuration; StringMap settings = kerberos::helper::getSettingsFromXML(configuration); settings["configuration"] = configuration; @@ -144,7 +144,7 @@ namespace kerberos settings[begin->first] = begin->second; } - VLOG(0) << helper::printStringMap("Final configuration:", settings); + VLOG(1) << helper::printStringMap("Final configuration:", settings); // ----------------- // Get instance name @@ -156,12 +156,12 @@ namespace kerberos if(settings.at("logging") == "false") { - VLOG(0) << "Logging is set to info"; + VLOG(1) << "Logging is set to info"; el::Loggers::setVerboseLevel(1); } else { - VLOG(0) << "Logging is set to verbose"; + VLOG(1) << "Logging is set to verbose"; el::Loggers::setVerboseLevel(2); } @@ -220,7 +220,7 @@ namespace kerberos if(stream != 0) { - VLOG(0) << "Stopping streaming"; + VLOG(1) << "Stopping streaming"; stopStreamThread(); delete stream; stream = 0; @@ -228,7 +228,7 @@ namespace kerberos if(capture != 0) { - VLOG(0) << "Stopping capture device"; + VLOG(1) << "Stopping capture device"; if(capture->isOpened()) { machinery->disableCapture(); @@ -245,7 +245,7 @@ namespace kerberos // --------------------------- // Initialize capture device - VLOG(0) << "Starting capture device: " + settings.at("capture"); + VLOG(1) << "Starting capture device: " + settings.at("capture"); capture = Factory::getInstance()->create(settings.at("capture")); capture->setup(settings); capture->startGrabThread(); @@ -269,14 +269,14 @@ namespace kerberos if(cloud != 0) { - VLOG(0) << "Stopping cloud service"; + VLOG(1) << "Stopping cloud service"; cloud->stopUploadThread(); cloud->stopPollThread(); cloud->stopHealthThread(); delete cloud; } - VLOG(0) << "Starting cloud service: " + settings.at("cloud"); + VLOG(1) << "Starting cloud service: " + settings.at("cloud"); cloud = Factory::getInstance()->create(settings.at("cloud")); cloud->setCapture(capture); cloud->setup(settings); diff --git a/src/kerberos/capture/Capture.cpp b/src/kerberos/capture/Capture.cpp index abf8a36..60fb121 100755 --- a/src/kerberos/capture/Capture.cpp +++ b/src/kerberos/capture/Capture.cpp @@ -136,11 +136,11 @@ namespace kerberos healthCounter = capture->healthCounter.load(); usleep(5000*1000); // every 5s. - VLOG(1) << "Capture: checking health status of camera."; + VLOG(2) << "Capture: checking health status of camera."; if(healthCounter == capture->healthCounter.load()) { - VLOG(0) << "Capture: devices is blocking, and not grabbing any more frames."; + VLOG(1) << "Capture: devices is blocking, and not grabbing any more frames."; throw KerberosCouldNotGrabFromCamera("devices is blocking, and not grabbin any more frames."); } } diff --git a/src/kerberos/capture/IPCamera.cpp b/src/kerberos/capture/IPCamera.cpp index 48446d9..8805c3f 100755 --- a/src/kerberos/capture/IPCamera.cpp +++ b/src/kerberos/capture/IPCamera.cpp @@ -190,8 +190,8 @@ namespace kerberos } void IPCamera::reopen() { - VLOG(0) << "Capture: Trying to open IP camera."; - VLOG(0) << "Capture: (Warning) You can change the capture device with the configuration files."; + VLOG(1) << "Capture: Trying to open IP camera."; + VLOG(1) << "Capture: (Warning) You can change the capture device with the configuration files."; m_camera->release(); open(m_url.c_str()); @@ -208,7 +208,7 @@ namespace kerberos } } - VLOG(0) << "Capture: Succesfully opened IP camera."; + VLOG(1) << "Capture: Succesfully opened IP camera."; } void IPCamera::close() diff --git a/src/kerberos/capture/RaspiCamera.cpp b/src/kerberos/capture/RaspiCamera.cpp index 43bc7a8..3d7e08e 100755 --- a/src/kerberos/capture/RaspiCamera.cpp +++ b/src/kerberos/capture/RaspiCamera.cpp @@ -48,7 +48,7 @@ void* preview_thread(void* self) // a good solution is to implement frame skipping (measure time between to loops, if this time // is too big, just skip image processing and MJPEG sendout) - VLOG(1) << "RaspiCamera: Entering preview thread."; + VLOG(2) << "RaspiCamera: Entering preview thread."; while (state.running) { capture->incrementHealth(); @@ -57,7 +57,7 @@ void* preview_thread(void* self) // If zero-copy is activated, we don't pass any buffer capture->data_length = state.camera->getOutputData(70, nullptr); } - VLOG(1) << "RaspiCamera: Exiting preview thread."; + VLOG(2) << "RaspiCamera: Exiting preview thread."; return nullptr; } @@ -69,7 +69,7 @@ void* record_thread(void* self) uint8_t* data = new uint8_t[65536*4]; - VLOG(1) << "RaspiCamera: Entering record thread."; + VLOG(2) << "RaspiCamera: Entering record thread."; while(state.running) { // Consume h264 data, this is a blocking call @@ -80,7 +80,7 @@ void* record_thread(void* self) file.flush(); } } - VLOG(1) << "RaspiCamera: Exiting record thread."; + VLOG(2) << "RaspiCamera: Exiting record thread."; return nullptr; } @@ -200,9 +200,9 @@ namespace kerberos void RaspiCamera::open() { - VLOG(0) << "Capture: Trying to open Raspberry Pi camera module."; - VLOG(0) << "Capture: (Warning) If you see a OMX_GetHandle error, this means that you don't have a working RPi camera module attached."; - VLOG(0) << "Capture: (Warning) You can change the capture device with the configuration files."; + VLOG(1) << "Capture: Trying to open Raspberry Pi camera module."; + VLOG(1) << "Capture: (Warning) If you see a OMX_GetHandle error, this means that you don't have a working RPi camera module attached."; + VLOG(1) << "Capture: (Warning) You can change the capture device with the configuration files."; // Initialize hardware bcm_host_init(); @@ -257,7 +257,7 @@ namespace kerberos pthread_create(&state.record_thid, nullptr, &record_thread, this); pthread_detach(state.record_thid); - VLOG(0) << "Capture: Succesfully opened Raspberry Pi camera module."; + VLOG(1) << "Capture: Succesfully opened Raspberry Pi camera module."; } void RaspiCamera::stopThreads() diff --git a/src/kerberos/capture/Stream.cpp b/src/kerberos/capture/Stream.cpp index 9341bad..4cb40e5 100755 --- a/src/kerberos/capture/Stream.cpp +++ b/src/kerberos/capture/Stream.cpp @@ -57,7 +57,7 @@ namespace kerberos } sock = (INVALID_SOCKET); - VLOG(0) << "Stream: Succesfully closed streaming"; + VLOG(1) << "Stream: Succesfully closed streaming"; return false; } @@ -97,7 +97,7 @@ namespace kerberos FD_SET(sock, &master); - VLOG(0) << "Stream: Configured stream on port " << helper::to_string(m_streamPort) << " with quality: " << helper::to_string(m_quality); + VLOG(1) << "Stream: Configured stream on port " << helper::to_string(m_streamPort) << " with quality: " << helper::to_string(m_quality); return true; } @@ -254,8 +254,8 @@ namespace kerberos "Content-Type: multipart/x-mixed-replace; boundary=mjpegstream\r\n" "\r\n",0); - VLOG(0) << "Stream: authentication success"; - VLOG(0) << "Stream: opening socket for new client."; + VLOG(1) << "Stream: authentication success"; + VLOG(1) << "Stream: opening socket for new client."; clients.push_back(client); packetsSend[client] = 0; diff --git a/src/kerberos/capture/USBCamera.cpp b/src/kerberos/capture/USBCamera.cpp index d8542d1..84b54a8 100755 --- a/src/kerberos/capture/USBCamera.cpp +++ b/src/kerberos/capture/USBCamera.cpp @@ -124,8 +124,8 @@ namespace kerberos void USBCamera::open() { - VLOG(0) << "Capture: Trying to open USB camera."; - VLOG(0) << "Capture: (Warning) You can change the capture device with the configuration files."; + VLOG(1) << "Capture: Trying to open USB camera."; + VLOG(1) << "Capture: (Warning) You can change the capture device with the configuration files."; try { @@ -146,7 +146,7 @@ namespace kerberos throw OpenCVException(ex.msg.c_str()); } - VLOG(0) << "Capture: Succesfully opened USB camera."; + VLOG(1) << "Capture: Succesfully opened USB camera."; } void USBCamera::close() diff --git a/src/kerberos/cloud/Cloud.cpp b/src/kerberos/cloud/Cloud.cpp index 72e3ffb..00ba7d9 100755 --- a/src/kerberos/cloud/Cloud.cpp +++ b/src/kerberos/cloud/Cloud.cpp @@ -64,16 +64,16 @@ namespace kerberos // Create product key file std::string command = "touch " + m_keyFile; std::string createProductKeyFile = helper::GetStdoutFromCommand(command); - VLOG(1) << "Cloud: create key file"; + VLOG(2) << "Cloud: create key file"; // Write product key command = "echo " + key + " > " + m_keyFile; std::string writeProductKey = helper::GetStdoutFromCommand(command); - VLOG(1) << "Cloud: write key"; + VLOG(2) << "Cloud: write key"; // Reset key setProductKey(key); - VLOG(1) << "Cloud: reset product key (" << key << ")"; + VLOG(2) << "Cloud: reset product key (" << key << ")"; } startPollThread(); @@ -285,9 +285,9 @@ namespace kerberos health += "}"; RestClient::Response r = conn->post("/api/v1/health", health); - VLOG(1) << "Cloud: data - " << health; - VLOG(1) << "Cloud: send device health - " << r.code; - VLOG(1) << "Cloud: send device health - " << r.body; + VLOG(2) << "Cloud: data - " << health; + VLOG(2) << "Cloud: send device health - " << r.code; + VLOG(2) << "Cloud: send device health - " << r.body; usleep(15*1000*1000); // every 15s } diff --git a/src/kerberos/cloud/S3.cpp b/src/kerberos/cloud/S3.cpp index 7ec6373..6cdc56c 100755 --- a/src/kerberos/cloud/S3.cpp +++ b/src/kerberos/cloud/S3.cpp @@ -114,13 +114,13 @@ namespace kerberos // ---------------------------------------------- // Before send the headers, we need to sort them! - VLOG(0) << "S3: Sending new file to cloud."; + VLOG(1) << "S3: Sending new file to cloud."; std::sort(canonicalizedAmzHeaders.begin(), canonicalizedAmzHeaders.end()); for(int i = 0; i < canonicalizedAmzHeaders.size(); i++) { - VLOG(1) << "S3 - File info: " << canonicalizedAmzHeaders[i]; + VLOG(2) << "S3 - File info: " << canonicalizedAmzHeaders[i]; } return canonicalizedAmzHeaders; @@ -240,7 +240,7 @@ namespace kerberos curl_easy_setopt(curlHandle, CURLOPT_WRITEFUNCTION, write); curl_easy_setopt(curlHandle, CURLOPT_WRITEDATA, &output); - VLOG(1) << "S3: uploading image to bucket."; + VLOG(2) << "S3: uploading image to bucket."; result = curl_easy_perform(curlHandle); //Perform long http_code = 0; @@ -254,7 +254,7 @@ namespace kerberos // Check if file really was uploaded. // We'll query the S3 bucket and check if it's there. - VLOG(0) << "S3: file uploaded."; + VLOG(1) << "S3: file uploaded."; return doesExist(pathToImage); @@ -264,7 +264,7 @@ namespace kerberos // User is not allowed to push with these credentials. // We remove the symbol. - VLOG(0) << "S3: permission denied, your file wasn't uploaded."; + VLOG(1) << "S3: permission denied, your file wasn't uploaded."; return true; @@ -272,7 +272,7 @@ namespace kerberos else { - VLOG(0) << "S3: file was not uploaded, something went wrong. Please check if you internet connectivity works."; + VLOG(1) << "S3: file was not uploaded, something went wrong. Please check if you internet connectivity works."; } } @@ -349,7 +349,7 @@ namespace kerberos curl_easy_setopt(curlHandle, CURLOPT_WRITEFUNCTION, write); curl_easy_setopt(curlHandle, CURLOPT_WRITEDATA, &output); - VLOG(1) << "S3: checking if file exists in bucket."; + VLOG(2) << "S3: checking if file exists in bucket."; result = curl_easy_perform(curlHandle); //Perform long http_code = 0; @@ -359,12 +359,12 @@ namespace kerberos if(http_code == 200 && result != CURLE_ABORTED_BY_CALLBACK) { - VLOG(0) << "S3: file exists in bucket, succesfully uploaded."; + VLOG(1) << "S3: file exists in bucket, succesfully uploaded."; return true; } - VLOG(0) << "S3: file wasn't uploaded, something went wrong."; - + VLOG(1) << "S3: file wasn't uploaded, something went wrong."; + return false; } diff --git a/src/kerberos/machinery/Machinery.cpp b/src/kerberos/machinery/Machinery.cpp index be0442a..7deabc8 100755 --- a/src/kerberos/machinery/Machinery.cpp +++ b/src/kerberos/machinery/Machinery.cpp @@ -8,7 +8,7 @@ namespace kerberos // ----------------------------------------------------------- // Creates condition, algorithms, expositors, heuristics and io handlers. - VLOG(0) << "Starting conditions: " + settings.at("condition"); + VLOG(1) << "Starting conditions: " + settings.at("condition"); std::vector conditions = Factory::getInstance()->createMultiple(settings.at("condition")); for(int i = 0; i < conditions.size(); i++) { @@ -16,22 +16,22 @@ namespace kerberos } setCondition(conditions); - VLOG(0) << "Starting algorithm: " + settings.at("algorithm"); + VLOG(1) << "Starting algorithm: " + settings.at("algorithm"); Algorithm * algorithm = Factory::getInstance()->create(settings.at("algorithm")); algorithm->setup(settings); setAlgorithm(algorithm); - VLOG(0) << "Starting expositor: " + settings.at("expositor"); + VLOG(1) << "Starting expositor: " + settings.at("expositor"); Expositor * expositor = Factory::getInstance()->create(settings.at("expositor")); expositor->setup(settings); setExpositor(expositor); - VLOG(0) << "Starting heuristic: " + settings.at("heuristic"); + VLOG(1) << "Starting heuristic: " + settings.at("heuristic"); Heuristic * heuristic = Factory::getInstance()->create(settings.at("heuristic")); heuristic->setup(settings); setHeuristic(heuristic); - VLOG(0) << "Starting io devices: " + settings.at("io"); + VLOG(1) << "Starting io devices: " + settings.at("io"); std::vector ios = Factory::getInstance()->createMultiple(settings.at("io")); for(int i = 0; i < ios.size(); i++) { diff --git a/src/kerberos/machinery/condition/Enabled.cpp b/src/kerberos/machinery/condition/Enabled.cpp index 819ef66..4b36fac 100755 --- a/src/kerberos/machinery/condition/Enabled.cpp +++ b/src/kerberos/machinery/condition/Enabled.cpp @@ -20,7 +20,7 @@ namespace kerberos { if(!isEnabled()) { - VLOG(0) << "Condition: not enabled."; + VLOG(1) << "Condition: not enabled."; usleep(getDelay()*1000); } diff --git a/src/kerberos/machinery/condition/Time.cpp b/src/kerberos/machinery/condition/Time.cpp index 6ca1f41..04a3314 100755 --- a/src/kerberos/machinery/condition/Time.cpp +++ b/src/kerberos/machinery/condition/Time.cpp @@ -49,7 +49,7 @@ namespace kerberos if(!isAllowed) { - VLOG(0) << "Condition: not in time interval."; + VLOG(1) << "Condition: not in time interval."; usleep(getDelay()*1000); } diff --git a/src/kerberos/machinery/expositor/HullExpositor.cpp b/src/kerberos/machinery/expositor/HullExpositor.cpp index b0830b1..815e02a 100755 --- a/src/kerberos/machinery/expositor/HullExpositor.cpp +++ b/src/kerberos/machinery/expositor/HullExpositor.cpp @@ -97,7 +97,7 @@ namespace kerberos if(numberOfChanges) { - VLOG(0) << "HullExpositor: activity detected from (" + helper::to_string(rectangle.m_x1) + "," + helper::to_string(rectangle.m_y1) + ") to (" + helper::to_string(rectangle.m_x2) + "," + helper::to_string(rectangle.m_y2) + ")"; + VLOG(1) << "HullExpositor: activity detected from (" + helper::to_string(rectangle.m_x1) + "," + helper::to_string(rectangle.m_y1) + ") to (" + helper::to_string(rectangle.m_x2) + "," + helper::to_string(rectangle.m_y2) + ")"; } data.AddMember("numberOfChanges", numberOfChanges, allocator); diff --git a/src/kerberos/machinery/expositor/RectangleExpositor.cpp b/src/kerberos/machinery/expositor/RectangleExpositor.cpp index 537412a..e5cb3d0 100755 --- a/src/kerberos/machinery/expositor/RectangleExpositor.cpp +++ b/src/kerberos/machinery/expositor/RectangleExpositor.cpp @@ -70,7 +70,7 @@ namespace kerberos if(numberOfChanges) { - VLOG(0) << "RectangleExpositor: activity detected from (" + helper::to_string(rectangle.m_x1) + "," + helper::to_string(rectangle.m_y1) + ") to (" + helper::to_string(rectangle.m_x2) + "," + helper::to_string(rectangle.m_y2) + ")"; + VLOG(1) << "RectangleExpositor: activity detected from (" + helper::to_string(rectangle.m_x1) + "," + helper::to_string(rectangle.m_y1) + ") to (" + helper::to_string(rectangle.m_x2) + "," + helper::to_string(rectangle.m_y2) + ")"; } data.AddMember("numberOfChanges", numberOfChanges, allocator); diff --git a/src/kerberos/machinery/heuristic/Counter.cpp b/src/kerberos/machinery/heuristic/Counter.cpp index ae5f1e9..f18bc98 100755 --- a/src/kerberos/machinery/heuristic/Counter.cpp +++ b/src/kerberos/machinery/heuristic/Counter.cpp @@ -270,7 +270,7 @@ namespace kerberos { if(incoming > 0 || outgoing > 0) { - VLOG(0) << "Counter: in (" << helper::to_string(incoming) << "), out (" << helper::to_string(outgoing) << ")"; + VLOG(1) << "Counter: in (" << helper::to_string(incoming) << "), out (" << helper::to_string(outgoing) << ")"; return true; } } diff --git a/src/kerberos/machinery/heuristic/Sequence.cpp b/src/kerberos/machinery/heuristic/Sequence.cpp index 31e3c56..ab262f3 100755 --- a/src/kerberos/machinery/heuristic/Sequence.cpp +++ b/src/kerberos/machinery/heuristic/Sequence.cpp @@ -22,7 +22,7 @@ namespace kerberos duration++; if(duration >= m_sequenceDuration) { - VLOG(0) << "Heuristic is valid; numberOfChanges: " + helper::to_string(numberOfChanges) + ", Sequence duration: " + helper::to_string(m_sequenceDuration); + VLOG(1) << "Heuristic is valid; numberOfChanges: " + helper::to_string(numberOfChanges) + ", Sequence duration: " + helper::to_string(m_sequenceDuration); return true; } } diff --git a/src/kerberos/machinery/io/IoDisk.cpp b/src/kerberos/machinery/io/IoDisk.cpp index d880950..e7cdce6 100755 --- a/src/kerberos/machinery/io/IoDisk.cpp +++ b/src/kerberos/machinery/io/IoDisk.cpp @@ -271,7 +271,7 @@ namespace kerberos // ------------------------- // Save original version - VLOG(0) << "IoDisk: saving image " + pathToImage; + VLOG(1) << "IoDisk: saving image " + pathToImage; return m_fileManager.save(image, pathToImage, m_createSymbol); } diff --git a/src/kerberos/machinery/io/IoGPIO.cpp b/src/kerberos/machinery/io/IoGPIO.cpp index 7bab7ff..390b6f5 100755 --- a/src/kerberos/machinery/io/IoGPIO.cpp +++ b/src/kerberos/machinery/io/IoGPIO.cpp @@ -54,7 +54,7 @@ namespace kerberos // ------------------------ // Trigger the GPIO pin - VLOG(0) << "IoGPIO: triggering GPIO pin " + helper::to_string(m_pin); + VLOG(1) << "IoGPIO: triggering GPIO pin " + helper::to_string(m_pin); for(int i = 0; i < m_periods; i++) { diff --git a/src/kerberos/machinery/io/IoMQTT.cpp b/src/kerberos/machinery/io/IoMQTT.cpp index fb05738..98da293 100644 --- a/src/kerberos/machinery/io/IoMQTT.cpp +++ b/src/kerberos/machinery/io/IoMQTT.cpp @@ -71,7 +71,7 @@ namespace kerberos std::string message { buffer.GetString() }; bool sendSuccessfully = send_message(message); - VLOG(0) << "IoMQTT: sending message..." << ((sendSuccessfully) ? "sent" : "error"); + VLOG(1) << "IoMQTT: sending message..." << ((sendSuccessfully) ? "sent" : "error"); return sendSuccessfully; } diff --git a/src/kerberos/machinery/io/IoPushbullet.cpp b/src/kerberos/machinery/io/IoPushbullet.cpp index 8f8a61f..0e62248 100755 --- a/src/kerberos/machinery/io/IoPushbullet.cpp +++ b/src/kerberos/machinery/io/IoPushbullet.cpp @@ -82,7 +82,7 @@ namespace kerberos pbResp.Parse(r.body.c_str()); upUrl = pbResp["upload_url"].GetString(); fileUrl = pbResp["file_url"].GetString(); - VLOG(0) << "IoPushbullet: response to upload request " + r.body; + VLOG(1) << "IoPushbullet: response to upload request " + r.body; /* * Step 3 : upload file to pushbullet @@ -94,7 +94,7 @@ namespace kerberos */ r = pushbulletConnection->post("/v2/pushes", "{\"type\":\"file\",\"file_url\":\""+ fileUrl +"\"}"); if(r.code==200) - VLOG(0) << "IoPushbullet: response to push file request " + r.body ; + VLOG(1) << "IoPushbullet: response to push file request " + r.body ; } } @@ -106,7 +106,7 @@ namespace kerberos if(r.code == 200) { - VLOG(0) << "IoPushbullet: response to post to pushbullet " + r.body; + VLOG(1) << "IoPushbullet: response to post to pushbullet " + r.body; return true; } diff --git a/src/kerberos/machinery/io/IoScript.cpp b/src/kerberos/machinery/io/IoScript.cpp index 232d008..ef0d06f 100755 --- a/src/kerberos/machinery/io/IoScript.cpp +++ b/src/kerberos/machinery/io/IoScript.cpp @@ -49,7 +49,7 @@ namespace kerberos // Send a post to URL std::string path = (std::string) getPath(); - VLOG(0) << "IoScript: calling script at " + path; + VLOG(1) << "IoScript: calling script at " + path; if(path != "") { diff --git a/src/kerberos/machinery/io/IoTCP.cpp b/src/kerberos/machinery/io/IoTCP.cpp index 2fbcd8f..12b882c 100755 --- a/src/kerberos/machinery/io/IoTCP.cpp +++ b/src/kerberos/machinery/io/IoTCP.cpp @@ -40,7 +40,7 @@ namespace kerberos if (connect(sock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) >= 0) { - VLOG(0) << "IoTCP: sending TCP packet to " + (std::string) getIp() + ":" + helper::to_string(getPort()); + VLOG(1) << "IoTCP: sending TCP packet to " + (std::string) getIp() + ":" + helper::to_string(getPort()); if (send(sock, getMessage(), strlen(getMessage()), 0) != strlen(getMessage())) { throw new SocketException("send() sent a different number of bytes than expected"); diff --git a/src/kerberos/machinery/io/IoVideo.cpp b/src/kerberos/machinery/io/IoVideo.cpp index 2cc5b28..b826353 100755 --- a/src/kerberos/machinery/io/IoVideo.cpp +++ b/src/kerberos/machinery/io/IoVideo.cpp @@ -260,7 +260,7 @@ namespace kerberos pthread_mutex_lock(&m_release_lock); - VLOG(0) << "IoVideo: firing"; + VLOG(1) << "IoVideo: firing"; // ------------------ // Check if the camera supports on board recording (camera specific), @@ -324,7 +324,7 @@ namespace kerberos // --------------- // Start recording - VLOG(0) << "IoVideo: start new recording " << m_fileName; + VLOG(1) << "IoVideo: start new recording " << m_fileName; m_writer = new cv::VideoWriter(); m_writer->open(m_path, m_codec, m_fps, cv::Size(image.getColumns(), image.getRows())); @@ -408,14 +408,14 @@ namespace kerberos double cronoTime = (double) (cv::getTickCount() / cv::getTickFrequency()); double startedRecording = cronoTime; - VLOG(0) << "IoVideo (FFMPEG): start writing images"; + VLOG(1) << "IoVideo (FFMPEG): start writing images"; pthread_mutex_lock(&video->m_write_lock); // Todo write video with FFMPEG.. // .. (video->m_path); - VLOG(0) << "IoVideo: locked write thread"; + VLOG(1) << "IoVideo: locked write thread"; pthread_mutex_lock(&video->m_time_lock); double timeToRecord = video->m_timeStartedRecording + video->m_recordingTimeAfter; @@ -444,7 +444,7 @@ namespace kerberos LOG(ERROR) << ex.what(); } - VLOG(0) << "IoVideo: end writing images"; + VLOG(1) << "IoVideo: end writing images"; pthread_mutex_lock(&video->m_release_lock); @@ -467,12 +467,12 @@ namespace kerberos } - VLOG(0) << "IoVideo: remove videowriter"; + VLOG(1) << "IoVideo: remove videowriter"; pthread_mutex_unlock(&video->m_release_lock); pthread_mutex_unlock(&video->m_write_lock); - VLOG(0) << "IoVideo: unlocking write thread"; + VLOG(1) << "IoVideo: unlocking write thread"; } void * recordOnboard(void * self) @@ -483,13 +483,13 @@ namespace kerberos double cronoTime = (double) (cv::getTickCount() / cv::getTickFrequency()); double startedRecording = cronoTime; - VLOG(0) << "IoVideo (OnBoard): start writing images"; + VLOG(1) << "IoVideo (OnBoard): start writing images"; pthread_mutex_lock(&video->m_write_lock); video->m_capture->startRecord(video->m_path); - VLOG(0) << "IoVideo: locked write thread"; + VLOG(1) << "IoVideo: locked write thread"; pthread_mutex_lock(&video->m_time_lock); double timeToRecord = video->m_timeStartedRecording + video->m_recordingTimeAfter; @@ -518,7 +518,7 @@ namespace kerberos LOG(ERROR) << ex.what(); } - VLOG(0) << "IoVideo: end writing images"; + VLOG(1) << "IoVideo: end writing images"; pthread_mutex_lock(&video->m_release_lock); @@ -538,12 +538,12 @@ namespace kerberos } - VLOG(0) << "IoVideo: remove videowriter"; + VLOG(1) << "IoVideo: remove videowriter"; pthread_mutex_unlock(&video->m_release_lock); pthread_mutex_unlock(&video->m_write_lock); - VLOG(0) << "IoVideo: unlocking write thread"; + VLOG(1) << "IoVideo: unlocking write thread"; } // ------------------------------------------- @@ -562,11 +562,11 @@ namespace kerberos double startedRecording = cronoTime; double fpsToTime = 1. / video->m_fps; - VLOG(0) << "IoVideo (OpenCV): start writing images"; + VLOG(1) << "IoVideo (OpenCV): start writing images"; pthread_mutex_lock(&video->m_write_lock); - VLOG(0) << "IoVideo: locked write thread"; + VLOG(1) << "IoVideo: locked write thread"; pthread_mutex_lock(&video->m_time_lock); double timeToRecord = video->m_timeStartedRecording + video->m_recordingTimeAfter; @@ -589,7 +589,7 @@ namespace kerberos video->m_writer->write(video->m_mostRecentImage.getImage()); pthread_mutex_unlock(&video->m_lock); - VLOG(1) << "IoVideo: writing image"; + VLOG(2) << "IoVideo: writing image"; // update time to record; (locking) pthread_mutex_lock(&video->m_time_lock); @@ -606,7 +606,7 @@ namespace kerberos } else { - VLOG(0) << "IoVideo: framerate is too fast, can't record video at this speed (" << video->m_fps << "/FPS)"; + VLOG(1) << "IoVideo: framerate is too fast, can't record video at this speed (" << video->m_fps << "/FPS)"; } } } @@ -617,7 +617,7 @@ namespace kerberos LOG(ERROR) << ex.what(); } - VLOG(0) << "IoVideo: end writing images"; + VLOG(1) << "IoVideo: end writing images"; pthread_mutex_lock(&video->m_release_lock); @@ -647,12 +647,12 @@ namespace kerberos } - VLOG(0) << "IoVideo: remove videowriter"; + VLOG(1) << "IoVideo: remove videowriter"; pthread_mutex_unlock(&video->m_release_lock); pthread_mutex_unlock(&video->m_write_lock); - VLOG(0) << "IoVideo: unlocking write thread"; + VLOG(1) << "IoVideo: unlocking write thread"; } void IoVideo::drawDateOnImage(Image & image, std::string timestamp) @@ -690,7 +690,7 @@ namespace kerberos bool recording = true; - VLOG(0) << "IoVideo: initializing capture thread"; + VLOG(1) << "IoVideo: initializing capture thread"; while(recording) { @@ -703,7 +703,7 @@ namespace kerberos if(video->m_capture != 0 && recording) { - VLOG(1) << "IoVideo: grabbing images"; + VLOG(2) << "IoVideo: grabbing images"; try { @@ -726,7 +726,7 @@ namespace kerberos usleep(1000); // sleep 1 ms } - VLOG(0) << "IoVideo: closing capture thread"; + VLOG(1) << "IoVideo: closing capture thread"; } Image IoVideo::getImage() diff --git a/src/kerberos/machinery/io/IoWebhook.cpp b/src/kerberos/machinery/io/IoWebhook.cpp index 3991276..5531e08 100755 --- a/src/kerberos/machinery/io/IoWebhook.cpp +++ b/src/kerberos/machinery/io/IoWebhook.cpp @@ -57,7 +57,7 @@ namespace kerberos // ------------------- // Send a post to URL - VLOG(0) << "IoWebhook: post to webhook " + (std::string) getUrl(); + VLOG(1) << "IoWebhook: post to webhook " + (std::string) getUrl(); RestClient::Response r = webhookConnection->post("/", buffer.GetString()); if(r.code == 200) From 6fa49444d9a132fdf8c617983b3fd1c24cf21c17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Verstraeten?= Date: Wed, 23 May 2018 13:58:24 +0200 Subject: [PATCH 33/35] log --- include/kerberos/Kerberos.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/kerberos/Kerberos.h b/include/kerberos/Kerberos.h index 9037f28..08f0453 100755 --- a/include/kerberos/Kerberos.h +++ b/include/kerberos/Kerberos.h @@ -51,7 +51,7 @@ namespace kerberos void setCaptureDelayTime(int delay){m_captureDelayTime=delay;}; void setParameters(StringMap & parameters) { - VLOG(0) << helper::printStringMap("Parameters passed from commandline:", parameters); + VLOG(1) << helper::printStringMap("Parameters passed from commandline:", parameters); m_parameters = parameters; }; StringMap getParameters(){return m_parameters;} From 8cc9d6d452f425f49937adecab65925eb2474e12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Verstraeten?= Date: Wed, 23 May 2018 16:41:32 +0200 Subject: [PATCH 34/35] Revert "remove waiting" This reverts commit 103105155be25d111dcea89b1428e5a3320d57e5. --- src/kerberos/Kerberos.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/kerberos/Kerberos.cpp b/src/kerberos/Kerberos.cpp index c831fd5..faefaaf 100755 --- a/src/kerberos/Kerberos.cpp +++ b/src/kerberos/Kerberos.cpp @@ -254,6 +254,7 @@ namespace kerberos // ------------------ // Initialize stream + usleep(1000*5000); stream = new Stream(); stream->configureStream(settings); startStreamThread(); From 223ecfafc3c43b829519c06d886cbc2e466e58cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Verstraeten?= Date: Wed, 23 May 2018 22:29:18 +0200 Subject: [PATCH 35/35] fix --- src/main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main.cpp b/src/main.cpp index 83f0e75..0f98a4b 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -66,6 +66,7 @@ int main(int argc, char** argv) el::Loggers::addFlag(el::LoggingFlag::StrictLogFileSizeCheck); el::Loggers::addFlag(el::LoggingFlag::ColoredTerminalOutput); el::Loggers::reconfigureAllLoggers(config); + el::Loggers::setVerboseLevel(1); VLOG(0) << "Logging is written to: " + logFile;