mirror of
https://github.com/Fishwaldo/LEDMessageBoard.git
synced 2025-03-15 11:21:24 +00:00
use new LoggerCPP library instead of boost::log
This commit is contained in:
parent
ee8bf4a48a
commit
848daf5b19
33 changed files with 2332 additions and 55 deletions
|
@ -3,8 +3,6 @@ cmake_minimum_required (VERSION 2.8)
|
|||
project (LMBd)
|
||||
|
||||
|
||||
add_definitions(-DBOOST_LOG_DYN_LINK)
|
||||
|
||||
option(LMB_DEBUG "Enable additional debugging information" OFF)
|
||||
|
||||
if(LMB_DEBUG)
|
||||
|
@ -15,13 +13,27 @@ else()
|
|||
set(CMAKE_BUILD_TYPE Release)
|
||||
endif(LMB_DEBUG)
|
||||
|
||||
add_executable(LMBd src/Driver-DX.cpp src/FileMonitor.cpp src/lmbcli.cpp src/lmbd.cpp
|
||||
src/serial/src/serial.cc src/serial/src/impl/unix.cc
|
||||
src/serial/src/impl/list_ports/list_ports_linux.cc src/libcli/libcli.c)
|
||||
add_executable(LMBd
|
||||
src/Driver-DX.cpp
|
||||
src/FileMonitor.cpp
|
||||
src/lmbcli.cpp
|
||||
src/lmbd.cpp
|
||||
src/serial/src/serial.cc
|
||||
src/serial/src/impl/unix.cc
|
||||
src/serial/src/impl/list_ports/list_ports_linux.cc
|
||||
src/libcli/libcli.c
|
||||
src/LoggerCpp/Config.cpp
|
||||
src/LoggerCpp/DateTime.cpp
|
||||
src/LoggerCpp/Log.cpp
|
||||
src/LoggerCpp/Logger.cpp
|
||||
src/LoggerCpp/Manager.cpp
|
||||
src/LoggerCpp/OutputConsole.cpp
|
||||
src/LoggerCpp/OutputDebug.cpp
|
||||
src/LoggerCpp/OutputFile.cpp)
|
||||
|
||||
|
||||
|
||||
find_package(Boost REQUIRED COMPONENTS thread log filesystem)
|
||||
find_package(Boost REQUIRED COMPONENTS thread filesystem)
|
||||
if(Boost_FOUND)
|
||||
include_directories(${Boost_INCLUDE_DIRS})
|
||||
target_link_libraries(LMBd -pthread ${Boost_LIBRARIES})
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"serial": {
|
||||
"port": "\/dev\/ttyUSB0"
|
||||
"port": "\/dev\/ttyUSB1"
|
||||
},
|
||||
"debug": {
|
||||
"level": "0"
|
||||
|
@ -9,10 +9,12 @@
|
|||
"password": "password",
|
||||
"enablepass": "enable",
|
||||
"monitorpath": "\/tmp\/test\/",
|
||||
"ConsoleLogging": "true",
|
||||
"ConsoleLogLevel": "INFO",
|
||||
"startupmessage": {
|
||||
"1": "\\DW - \\DD\/\\DL\/\\DY - \\DH:\\DM:\\DS",
|
||||
"2": "No Messages ~S",
|
||||
"3": "test message 3",
|
||||
"3": "",
|
||||
"4": "",
|
||||
"5": "",
|
||||
"6": ""
|
||||
|
|
|
@ -33,14 +33,14 @@ void doChkSum(uint8_t *data, uint8_t length) {
|
|||
for (i = 1; i < length; i++) {
|
||||
csum += data[i];
|
||||
}
|
||||
BOOST_LOG_TRIVIAL(trace) << "csum " << std::hex << (int)csum << " old " << std::hex << (int)data[i];
|
||||
LMB_LOG_DEBUG() << "csum " << std::hex << (int)csum << " old " << std::hex << (int)data[i];
|
||||
data[i] = csum;
|
||||
}
|
||||
void insertMessage(uint8_t part, uint8_t *data, std::string message) {
|
||||
uint8_t startpos = 4;
|
||||
uint8_t size = 60;
|
||||
uint8_t messagestart = 0;
|
||||
BOOST_LOG_TRIVIAL(trace) << "message length: " << std::dec << message.length();
|
||||
LMB_LOG_DEBUG() << "message length: " << std::dec << message.length();
|
||||
if (part == 1) {
|
||||
startpos = 8;
|
||||
data[7] = message.length();
|
||||
|
@ -58,7 +58,7 @@ void insertMessage(uint8_t part, uint8_t *data, std::string message) {
|
|||
if ((message.length() - messagestart) < size)
|
||||
size = (message.length() - messagestart);
|
||||
|
||||
BOOST_LOG_TRIVIAL(trace) << "size " << (int)message.length() << std::dec << " StartPos: " << (int)startpos << " size " << (int)size << " messagestart " << (int)messagestart ;
|
||||
LMB_LOG_DEBUG() << "size " << (int)message.length() << std::dec << " StartPos: " << (int)startpos << " size " << (int)size << " messagestart " << (int)messagestart ;
|
||||
|
||||
|
||||
if (size > message.length())
|
||||
|
@ -73,16 +73,16 @@ void insertMessage(uint8_t part, uint8_t *data, std::string message) {
|
|||
|
||||
void printMessage(uint8_t *data, size_t length) {
|
||||
std::stringstream ss;
|
||||
BOOST_LOG_TRIVIAL(trace) << "Raw Message: ";
|
||||
LMB_LOG_DEBUG() << "Raw Message: ";
|
||||
for (unsigned int i = 0; i < length; ++i) {
|
||||
ss << std::setw(2) << std::uppercase << std::hex << std::setfill('0') << (int)data[i] << " ";
|
||||
if ((i+1) % 16 == 0) {
|
||||
BOOST_LOG_TRIVIAL(trace) << ss.str();
|
||||
LMB_LOG_DEBUG() << ss.str();
|
||||
ss.str("");
|
||||
}
|
||||
}
|
||||
if (ss.gcount() > 0)
|
||||
BOOST_LOG_TRIVIAL(trace) << ss.str();
|
||||
LMB_LOG_DEBUG() << ss.str();
|
||||
}
|
||||
|
||||
void setMessageNumber(uint8_t *data, uint8_t pos, bool firstmsg) {
|
||||
|
@ -107,14 +107,19 @@ bool Driver_DX::Init(LMBCTX *lmbctx) {
|
|||
this->lmbctx->sp->setRTS(true);
|
||||
this->lmbctx->sp->setDTR(true);
|
||||
/* construct the Message Header */
|
||||
BOOST_LOG_TRIVIAL(trace) << "Port Open: " << this->lmbctx->sp->isOpen();
|
||||
LMB_LOG_DEBUG() << "Port Open: " << this->lmbctx->sp->isOpen();
|
||||
std::vector<uint8_t> data;
|
||||
uint8_t start[] = { 0x54 };
|
||||
this->lmbctx->sp->write(start, 1);
|
||||
this->lmbctx->sp->flush();
|
||||
std::string query = this->lmbctx->sp->read(1);
|
||||
BOOST_LOG_TRIVIAL(trace) << "Reply to Inquiry: " << std::hex << query.at(1);
|
||||
BOOST_LOG_TRIVIAL(trace) << "Send Out Start Sequence";
|
||||
if (query.length() > 0) {
|
||||
LMB_LOG_DEBUG() << "Reply to Inquiry: " << std::hex << query.at(0);
|
||||
} else {
|
||||
LMB_LOG_ERROR() << "No Reply to Inquiry";
|
||||
return false;
|
||||
}
|
||||
LMB_LOG_DEBUG() << "Send Out Start Sequence";
|
||||
|
||||
this->lmbctx->sp->flush();
|
||||
start[0] = 0x41;
|
||||
|
@ -139,12 +144,12 @@ bool Driver_DX::Init(LMBCTX *lmbctx) {
|
|||
bool Driver_DX::setMessage(int pos, std::string message) {
|
||||
|
||||
if (this->lmbctx->messages < (unsigned int)pos) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Invalid Message Position " << pos;
|
||||
LMB_LOG_WARN() << "Invalid Message Position " << pos;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (message.length() > 250) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Message is " << std::dec << message.length() << " chars long. Trimming to 250 Chars";
|
||||
LMB_LOG_WARN() << "Message is " << std::dec << message.length() << " chars long. Trimming to 250 Chars";
|
||||
message = message.substr(0, 250);
|
||||
}
|
||||
|
||||
|
@ -209,28 +214,28 @@ bool Driver_DX::setMessage(int pos, std::string message) {
|
|||
for (int i = 0; i < 69; i++)
|
||||
finalpck[1+69+69+69+i] = header4[i];
|
||||
printMessage(finalpck, 277);
|
||||
BOOST_LOG_TRIVIAL(trace) << "sending packets: ";
|
||||
LMB_LOG_DEBUG() << "sending packets: ";
|
||||
int sent = (int)this->lmbctx->sp->write(header1, 69);
|
||||
BOOST_LOG_TRIVIAL(trace) << "size: " << std::dec << sent;
|
||||
LMB_LOG_DEBUG() << "size: " << std::dec << sent;
|
||||
usleep(100 * 1000);
|
||||
sent = (int)this->lmbctx->sp->write(header2, 69);
|
||||
BOOST_LOG_TRIVIAL(trace) << "size: " << std::dec << sent;
|
||||
LMB_LOG_DEBUG() << "size: " << std::dec << sent;
|
||||
usleep(100 * 1000);
|
||||
sent = (int)this->lmbctx->sp->write(header3, 69);
|
||||
BOOST_LOG_TRIVIAL(trace) << "size: " << std::dec << sent;
|
||||
LMB_LOG_DEBUG() << "size: " << std::dec << sent;
|
||||
usleep(100 * 1000);
|
||||
sent =(int)this->lmbctx->sp->write(header4, 69);
|
||||
BOOST_LOG_TRIVIAL(trace) << "size: " << std::dec << sent;
|
||||
LMB_LOG_DEBUG() << "size: " << std::dec << sent;
|
||||
usleep(100 * 1000);
|
||||
} else {
|
||||
BOOST_LOG_TRIVIAL(trace) << "Clearing Message " << pos;
|
||||
LMB_LOG_DEBUG() << "Clearing Message " << pos;
|
||||
this->lmbctx->displayedmsgs[pos] = "";
|
||||
this->lmbctx->msgdisplay[pos-1] = 0;
|
||||
}
|
||||
uint8_t header5[] = { 0x02, 0x33, (uint8_t)this->lmbctx->msgdisplay.to_ulong() };
|
||||
int sent = (int)this->lmbctx->sp->write(header5, 3);
|
||||
BOOST_LOG_TRIVIAL(trace) << "size: " << std::dec << sent;
|
||||
BOOST_LOG_TRIVIAL(info) << "Set Message " << pos << " to " << this->lmbctx->displayedmsgs[pos];
|
||||
LMB_LOG_DEBUG() << "size: " << std::dec << sent;
|
||||
LMB_LOG_INFO() << "Set Message " << pos << " to " << this->lmbctx->displayedmsgs[pos];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -270,6 +275,6 @@ bool Driver_DX::StartUp() {
|
|||
uint8_t setTime[] = { 0x02, 0x34, InsertString(timePtr->tm_year -100), InsertString(timePtr->tm_mon +1), InsertString(timePtr->tm_mday), InsertString(timePtr->tm_hour), InsertString(timePtr->tm_min), InsertString(timePtr->tm_sec), InsertString(timePtr->tm_wday), 0x00 };
|
||||
doChkSum(&setTime[0], 9);
|
||||
int sent = (int)this->lmbctx->sp->write(setTime, 10);
|
||||
BOOST_LOG_TRIVIAL(trace) << "Set Clock: " << std::dec << sent;
|
||||
LMB_LOG_DEBUG() << "Set Clock: " << std::dec << sent;
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
|
||||
#include "lmbd.hpp"
|
||||
|
||||
|
||||
class iDriver {
|
||||
public:
|
||||
iDriver() {}
|
||||
|
|
|
@ -34,7 +34,7 @@ Inotify inotify(IN_CLOSE_WRITE);
|
|||
void MonitorFiles(LMBCTX *lmbctx) {
|
||||
while(true) {
|
||||
FileSystemEvent event = inotify.getNextEvent();
|
||||
BOOST_LOG_TRIVIAL(debug) << "Event wd(" << event.wd << ") " << event.getMaskString() << " for " << event.path << " was triggered!";
|
||||
LMB_LOG_DEBUG() << "Event wd(" << event.wd << ") " << event.getMaskString() << " for " << event.path << " was triggered!";
|
||||
boost::filesystem::ifstream ifs;
|
||||
ifs.open(event.path, std::ios::in);
|
||||
std::stringstream ss;
|
||||
|
@ -43,7 +43,7 @@ void MonitorFiles(LMBCTX *lmbctx) {
|
|||
message.erase(std::remove(message.begin(), message.end(), '\n'), message.end());
|
||||
// int messageid = boost::lexical_cast<int>(event.path.generic_string().at(event.path.generic_string().length()-1));
|
||||
int messageid = event.wd;
|
||||
BOOST_LOG_TRIVIAL(info) << "Message in Slot " << messageid << " was " << message;
|
||||
LMB_LOG_INFO() << "Message in Slot " << messageid << " was " << message;
|
||||
{
|
||||
boost::unique_lock<boost::mutex> scoped_lock(lmbctx->io_mutex);
|
||||
lmbctx->driver->Init(lmbctx);
|
||||
|
@ -70,7 +70,7 @@ bool FileMonitor::init(LMBCTX *lmbctx) {
|
|||
snprintf(filename, 255, "message-%d", i);
|
||||
boost::filesystem::path messagefile = monpath;
|
||||
messagefile /= filename;
|
||||
BOOST_LOG_TRIVIAL(info) << "Creating Message File: " << messagefile;
|
||||
LMB_LOG_INFO() << "Creating Message File: " << messagefile;
|
||||
std::ofstream f{messagefile.c_str(), std::ios::app};
|
||||
f.close();
|
||||
inotify.watchFile(messagefile);
|
||||
|
@ -78,11 +78,11 @@ bool FileMonitor::init(LMBCTX *lmbctx) {
|
|||
|
||||
|
||||
} else {
|
||||
BOOST_LOG_TRIVIAL(error) << "Monitor Path is not a directory";
|
||||
LMB_LOG_ERROR() << "Monitor Path is not a directory";
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
BOOST_LOG_TRIVIAL(error) << "Monitor Path does not exist";
|
||||
LMB_LOG_ERROR() << "Monitor Path does not exist";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
89
src/LoggerCpp/Channel.h
Normal file
89
src/LoggerCpp/Channel.h
Normal file
|
@ -0,0 +1,89 @@
|
|||
/**
|
||||
* @file Channel.h
|
||||
* @ingroup LoggerCpp
|
||||
* @brief The named channel shared by Logger objects using the same name
|
||||
*
|
||||
* Copyright (c) 2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "LoggerCpp/Log.h"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
// The following includes "boost/shared_ptr.hpp" if LOGGER_USE_BOOST_SHARED_PTR is defined,
|
||||
// or <memory> (or <tr1/memory>) when C++11 (or experimental C++0x) is available,
|
||||
// or a custom minimal shared_ptr implementation,
|
||||
// and imports the "shared_ptr" symbol inside the Log namespace (ie. Log::shared_ptr)
|
||||
#include "LoggerCpp/shared_ptr.hpp"
|
||||
|
||||
namespace LMB {
|
||||
|
||||
namespace Log {
|
||||
|
||||
|
||||
/**
|
||||
* @brief The named channel shared by Logger objects using the same name
|
||||
* @ingroup LoggerCpp
|
||||
*
|
||||
* A Channel is the underlying object used by one or many Logger objects to
|
||||
* associate a named prefix and an output Log::Level.
|
||||
* Sharing a same Channel between multiple Logger enable changing the
|
||||
* Level of many Logger objects at once.
|
||||
*/
|
||||
class Channel {
|
||||
public:
|
||||
/// @brief Shared Pointer to a Channel object
|
||||
typedef shared_ptr<Channel> Ptr;
|
||||
/// @brief Map of shared pointer of Channel objects
|
||||
typedef std::map<std::string, Ptr> Map;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Initialize a named Channel
|
||||
*
|
||||
* @param[in] apChannelName String to identify origin of Log output by this Channel
|
||||
* @param[in] aChannelLevel The default minimum Log::Level of severity from which to output Log
|
||||
*/
|
||||
Channel(const char* apChannelName, Log::Level aChannelLevel) :
|
||||
mName(apChannelName),
|
||||
mLevel(aChannelLevel)
|
||||
{}
|
||||
|
||||
/// @brief Non virtual destructor
|
||||
~Channel(void) {
|
||||
}
|
||||
|
||||
/// @brief Name of the Channel
|
||||
inline const std::string& getName(void) const {
|
||||
return mName;
|
||||
}
|
||||
|
||||
/// @brief Set the current output Log::Level of the Channel
|
||||
inline void setLevel(Log::Level aLevel) {
|
||||
mLevel = aLevel;
|
||||
}
|
||||
|
||||
/// @brief Current Log::Level of the Channel
|
||||
inline Log::Level getLevel(void) const {
|
||||
return mLevel;
|
||||
}
|
||||
|
||||
private:
|
||||
/// @{ Non-copyable object
|
||||
Channel(Channel&);
|
||||
void operator=(Channel&);
|
||||
/// @}
|
||||
|
||||
private:
|
||||
std::string mName; ///< Name of the Channel
|
||||
Log::Level mLevel; ///< Current Log::Level of the Channel
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
} // namespace Log
|
65
src/LoggerCpp/Config.cpp
Normal file
65
src/LoggerCpp/Config.cpp
Normal file
|
@ -0,0 +1,65 @@
|
|||
/**
|
||||
* @file Config.cpp
|
||||
* @ingroup LoggerCpp
|
||||
* @brief Configuration for an Output object
|
||||
*
|
||||
* Copyright (c) 2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
|
||||
#include "LoggerCpp/Config.h"
|
||||
#include "LoggerCpp/Exception.h"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
namespace LMB {
|
||||
namespace Log {
|
||||
|
||||
|
||||
// Constructor
|
||||
Config::Config(const char* apName) :
|
||||
mName(apName) {
|
||||
}
|
||||
|
||||
// Destructor
|
||||
Config::~Config(void) {
|
||||
}
|
||||
|
||||
// Get a string value
|
||||
const char* Config::get(const char* apKey, const char* apDefaultValue) const {
|
||||
const char* pValue;
|
||||
Config::Values::const_iterator iValue = mValues.find(apKey);
|
||||
if (mValues.end() != iValue) {
|
||||
pValue = iValue->second.c_str();
|
||||
} else {
|
||||
pValue = apDefaultValue;
|
||||
}
|
||||
return pValue;
|
||||
}
|
||||
|
||||
// Get a string value
|
||||
long Config::get(const char* apKey, long aDefaultValue) const {
|
||||
long value;
|
||||
Config::Values::const_iterator iValue = mValues.find(apKey);
|
||||
if (mValues.end() != iValue) {
|
||||
value = atol(iValue->second.c_str());
|
||||
} else {
|
||||
value = aDefaultValue;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
// Create the Config for a new Output
|
||||
void Config::addOutput(Vector& aConfigList, const char* apOutputName) {
|
||||
Log::Config::Ptr configPtr(new Log::Config(apOutputName));
|
||||
aConfigList.push_back(configPtr);
|
||||
}
|
||||
|
||||
// Set an option for the last added Output
|
||||
void Config::setOption(Vector& aConfigList, const char* apKey, const char* apValue) {
|
||||
(*aConfigList.back()).setValue(apKey, apValue);
|
||||
}
|
||||
}
|
||||
} // namespace Log
|
125
src/LoggerCpp/Config.h
Normal file
125
src/LoggerCpp/Config.h
Normal file
|
@ -0,0 +1,125 @@
|
|||
/**
|
||||
* @file Config.h
|
||||
* @ingroup LoggerCpp
|
||||
* @brief Configuration for an Output object
|
||||
*
|
||||
* Copyright (c) 2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
// The following includes "boost/shared_ptr.hpp" if LOGGER_USE_BOOST_SHARED_PTR is defined,
|
||||
// or <memory> (or <tr1/memory>) when C++11 (or experimental C++0x) is available,
|
||||
// or a custom minimal shared_ptr implementation,
|
||||
// and imports the "shared_ptr" symbol inside the Log namespace (ie. Log::shared_ptr)
|
||||
#include "LoggerCpp/shared_ptr.hpp"
|
||||
|
||||
namespace LMB {
|
||||
|
||||
namespace Log {
|
||||
|
||||
|
||||
// forward declaration
|
||||
class Logger;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Configuration for an Output object
|
||||
* @ingroup LoggerCpp
|
||||
*
|
||||
* A Config object is an associative container of strings key and values,
|
||||
* with easy to use helper manipulation functions.
|
||||
*/
|
||||
class Config {
|
||||
public:
|
||||
/// @brief Shared Pointer to a Config object
|
||||
typedef shared_ptr<Config> Ptr;
|
||||
/// @brief List of Config objects
|
||||
typedef std::vector<Ptr> Vector;
|
||||
/// @brief Map of string values
|
||||
typedef std::map<std::string, std::string> Values;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor
|
||||
*
|
||||
* @param[in] apName Name of the Config object
|
||||
*/
|
||||
explicit Config(const char* apName);
|
||||
|
||||
/// @brief Non virtual destructor
|
||||
~Config(void);
|
||||
|
||||
/// @brief Get the name of this Config object
|
||||
inline const std::string& getName(void) const {
|
||||
return mName;
|
||||
}
|
||||
|
||||
/// @brief Get the string values of this Config object
|
||||
inline const Values& getValues(void) const {
|
||||
return mValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set a string value
|
||||
*
|
||||
* @param[in] apKey String key identifying the string value
|
||||
* @param[in] apValue String value associated to the given key
|
||||
*/
|
||||
inline void setValue(const char* apKey, const char* apValue) {
|
||||
mValues[apKey] = apValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a string value, or return the provided default one
|
||||
*
|
||||
* @param[in] apKey String key identifying the string value
|
||||
* @param[in] apDefaultValue String default value
|
||||
*
|
||||
* @return String value associated to the given key
|
||||
*/
|
||||
const char* get(const char* apKey, const char* apDefaultValue) const;
|
||||
|
||||
/**
|
||||
* @brief Get a long value, or return the provided default one
|
||||
*
|
||||
* @param[in] apKey String key identifying the string value
|
||||
* @param[in] aDefaultValue Long default value
|
||||
*
|
||||
* @return Long value associated to the given key
|
||||
*/
|
||||
long get(const char* apKey, const long aDefaultValue) const;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Create the Config for a new Output
|
||||
*
|
||||
* @param[in,out] aConfigList Config list to complete with a new Output
|
||||
* @param[in] apOutputName Name of the new Output
|
||||
*/
|
||||
|
||||
static void addOutput(Vector& aConfigList, const char* apOutputName);
|
||||
/**
|
||||
* @brief Set an option for the last added Output
|
||||
*
|
||||
* @param[in,out] aConfigList Config list to complete with a new option value
|
||||
* @param[in] apKey String key identifying the string value
|
||||
* @param[in] apValue String value associated to the given key
|
||||
*/
|
||||
static void setOption(Vector& aConfigList, const char* apKey, const char* apValue);
|
||||
|
||||
private:
|
||||
std::string mName; ///< Name of the Config
|
||||
Values mValues; ///< Map of string values
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
} // namespace Log
|
||||
|
70
src/LoggerCpp/DateTime.cpp
Normal file
70
src/LoggerCpp/DateTime.cpp
Normal file
|
@ -0,0 +1,70 @@
|
|||
/**
|
||||
* @file DateTime.cpp
|
||||
* @ingroup LoggerCpp
|
||||
* @brief Current time precise to the millisecond.
|
||||
*
|
||||
* Copyright (c) 2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
|
||||
#include "LoggerCpp/DateTime.h"
|
||||
#include "LoggerCpp/Utils.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
namespace LMB {
|
||||
namespace Log {
|
||||
|
||||
|
||||
/// Constructor
|
||||
DateTime::DateTime(void) :
|
||||
year(0),
|
||||
month(0),
|
||||
day(0),
|
||||
hour(0),
|
||||
minute(0),
|
||||
second(0),
|
||||
ms(0),
|
||||
us(0) {
|
||||
}
|
||||
|
||||
|
||||
/// Set to current time
|
||||
void DateTime::make(void) {
|
||||
#ifdef WIN32
|
||||
SYSTEMTIME now;
|
||||
GetLocalTime(&now);
|
||||
|
||||
year = now.wYear;
|
||||
month = now.wMonth;
|
||||
day = now.wDay;
|
||||
hour = now.wHour;
|
||||
minute = now.wMinute;
|
||||
second = now.wSecond;
|
||||
ms = now.wMilliseconds;
|
||||
us = 0;
|
||||
#else
|
||||
struct timeval now;
|
||||
gettimeofday(&now, nullptr);
|
||||
struct tm* timeinfo = localtime(&now.tv_sec);
|
||||
|
||||
year = timeinfo->tm_year + 1900;
|
||||
month = timeinfo->tm_mon + 1;
|
||||
day = timeinfo->tm_mday;
|
||||
hour = timeinfo->tm_hour;
|
||||
minute = timeinfo->tm_min;
|
||||
second = timeinfo->tm_sec;
|
||||
ms = now.tv_usec / 1000;
|
||||
us = now.tv_usec % 1000;
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace Log
|
50
src/LoggerCpp/DateTime.h
Normal file
50
src/LoggerCpp/DateTime.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
/**
|
||||
* @file DateTime.h
|
||||
* @ingroup LoggerCpp
|
||||
* @brief Current time precise to the millisecond.
|
||||
*
|
||||
* Copyright (c) 2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
namespace LMB {
|
||||
|
||||
namespace Log {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Current time precise to the millisecond.
|
||||
* @ingroup LoggerCpp
|
||||
*
|
||||
* Using a struct to enable easy direct access to public members.
|
||||
*
|
||||
* Under Windows, the time is given to the millisecond.
|
||||
* Under Linux, the time is given to the microsecond.
|
||||
*/
|
||||
struct DateTime {
|
||||
/**
|
||||
* @brief Constructor
|
||||
*/
|
||||
DateTime(void);
|
||||
|
||||
/**
|
||||
* @brief Set to current time
|
||||
*/
|
||||
void make(void);
|
||||
|
||||
int year; ///< year [0,30827]
|
||||
int month; ///< month [1,12]
|
||||
int day; ///< day [1,31]
|
||||
int hour; ///< hour [0,23]
|
||||
int minute; ///< minute [0,59]
|
||||
int second; ///< second [0,59]
|
||||
int ms; ///< millisecond
|
||||
int us; ///< microsecond (not under Windows)
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
} // namespace Log
|
68
src/LoggerCpp/Exception.h
Normal file
68
src/LoggerCpp/Exception.h
Normal file
|
@ -0,0 +1,68 @@
|
|||
/**
|
||||
* @file Exception.h
|
||||
* @ingroup LoggerCpp
|
||||
* @brief Encapsulation of an error message on a std::runtime_error.
|
||||
*
|
||||
* Copyright (c) 2012-2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "LoggerCpp/Formatter.h"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
|
||||
|
||||
/// assert() is used in destructors, where exceptions are not allowed
|
||||
/// (only asserting in debug mode)
|
||||
/// @todo Enable assertion callback like in SQLiteC++
|
||||
#define LOGGER_ASSERT(expression) assert(expression)
|
||||
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
// Disable warning C4290: C++ exception specification ignored except to indicate a function is not __declspec(nothrow)
|
||||
#pragma warning(disable:4290)
|
||||
#endif
|
||||
|
||||
namespace LMB {
|
||||
|
||||
namespace Log {
|
||||
|
||||
/**
|
||||
* @brief Encapsulation of an error message based on std::runtime_error.
|
||||
* @ingroup LoggerCpp
|
||||
*/
|
||||
class Exception : public std::runtime_error {
|
||||
public:
|
||||
/**
|
||||
* @brief Encapsulation of an error message based on std::runtime_error.
|
||||
*
|
||||
* @param[in] aErrorMessage The string message describing the error
|
||||
*/
|
||||
explicit Exception(const std::string& aErrorMessage) :
|
||||
std::runtime_error(aErrorMessage)
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
/// @brief Stringify 1/2 : convert an integer to a string (using the following macro)
|
||||
#define TOSTRING(x) _XSTRING(x)
|
||||
/// @brief Stringify 2/2 : convert an integer to a string (inner macro)
|
||||
#define _XSTRING(x) #x
|
||||
|
||||
#ifdef __FUNCTION__
|
||||
/// @brief Define __func__ under Windows, to use the same name as with GCC
|
||||
#define __func__ __FUNCTION__
|
||||
#endif
|
||||
|
||||
/// @brief Helper macro to throw an Exception with file/line/function information, using the string stream Formatter
|
||||
#define LOGGER_THROW(x) throw Exception(Formatter() << __FILE__ << ":" << TOSTRING(__LINE__) << ": " << __func__ << "(): " << x)
|
||||
|
||||
}
|
||||
|
||||
} // namespace Log
|
69
src/LoggerCpp/Formatter.h
Normal file
69
src/LoggerCpp/Formatter.h
Normal file
|
@ -0,0 +1,69 @@
|
|||
/**
|
||||
* @file Formatter.h
|
||||
* @ingroup LoggerCpp
|
||||
* @brief A standard string stream formatter with implicit string conversion
|
||||
*
|
||||
* Copyright (c) 2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
namespace LMB {
|
||||
|
||||
namespace Log {
|
||||
|
||||
/**
|
||||
* @brief A standard string stream formatter with implicit string conversion
|
||||
* @ingroup LoggerCpp
|
||||
*
|
||||
* It is constructed and initialized by a call to the Formatter() constructor.
|
||||
* Is is then used by successive standard stream call "<<" to insert data into the stream.
|
||||
* It is ultimately implicitly converted to std::string when required.
|
||||
*
|
||||
* A typical use case is to format a std::exception string message :
|
||||
* - throw std::runtime_error(Formatter() << "no value for key '" << apKey << "'");
|
||||
*/
|
||||
class Formatter {
|
||||
public:
|
||||
/// @brief Constructor
|
||||
Formatter(void) {}
|
||||
/// @brief Non virtual destructor
|
||||
~Formatter(void) {}
|
||||
|
||||
/**
|
||||
* @brief stream inserter operator
|
||||
*
|
||||
* @param[in] aValue Value to be formatted and inserted into the string stream
|
||||
*
|
||||
* @return Current Formatter instance
|
||||
*/
|
||||
template <typename T>
|
||||
Formatter& operator<< (const T& aValue) {
|
||||
mStream << aValue;
|
||||
return (*this);
|
||||
}
|
||||
|
||||
/// @brief std::string cast operator for implicit conversion
|
||||
inline operator std::string() const {
|
||||
return mStream.str();
|
||||
}
|
||||
|
||||
private:
|
||||
/// @{ Non-copyable object
|
||||
Formatter(const Formatter&);
|
||||
void operator=(const Formatter&);
|
||||
/// @}
|
||||
|
||||
private:
|
||||
std::ostringstream mStream; ///< The underlying string stream
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
} // namespace Log
|
||||
|
75
src/LoggerCpp/Log.cpp
Normal file
75
src/LoggerCpp/Log.cpp
Normal file
|
@ -0,0 +1,75 @@
|
|||
/**
|
||||
* @file Log.cpp
|
||||
* @ingroup LoggerCpp
|
||||
* @brief A RAII (private) log object constructed by the Logger class
|
||||
*
|
||||
* Copyright (c) 2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
|
||||
#include "LoggerCpp/Log.h"
|
||||
#include "LoggerCpp/Logger.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace LMB {
|
||||
namespace Log {
|
||||
|
||||
|
||||
// Construct a RAII (private) log object for the Logger class
|
||||
Log::Log(const Logger& aLogger, Level aSeverity) :
|
||||
mLogger(aLogger),
|
||||
mSeverity(aSeverity),
|
||||
mpStream(nullptr) {
|
||||
// Construct a stream only if the severity of the Log is above its Logger Log::Level
|
||||
if (aSeverity >= aLogger.getLevel()) {
|
||||
mpStream = new(std::ostringstream);
|
||||
}
|
||||
}
|
||||
|
||||
// Destructor : output the Log string stream
|
||||
Log::~Log(void) {
|
||||
if (nullptr != mpStream) {
|
||||
mTime.make();
|
||||
mLogger.output(*this);
|
||||
|
||||
delete mpStream;
|
||||
mpStream = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Convert a Level to its string representation
|
||||
const char* Log::toString(Log::Level aLevel) {
|
||||
const char* pString = nullptr;
|
||||
|
||||
switch (aLevel) {
|
||||
case Log::eDebug: pString = "DBUG"; break;
|
||||
case Log::eInfo: pString = "INFO"; break;
|
||||
case Log::eNotice: pString = "NOTE"; break;
|
||||
case Log::eWarning: pString = "WARN"; break;
|
||||
case Log::eError: pString = "EROR"; break;
|
||||
case Log::eCritic: pString = "CRIT"; break;
|
||||
default: pString = "????"; break;
|
||||
}
|
||||
|
||||
return pString;
|
||||
}
|
||||
|
||||
// Convert a string representation of a Level to its corresponding value
|
||||
Log::Level Log::toLevel(const char* apLevel) {
|
||||
Log::Level level;
|
||||
|
||||
if (0 == strncmp(apLevel, "DBUG", 4)) level = Log::eDebug;
|
||||
else if (0 == strncmp(apLevel, "INFO", 4)) level = Log::eInfo;
|
||||
else if (0 == strncmp(apLevel, "NOTE", 4)) level = Log::eNotice;
|
||||
else if (0 == strncmp(apLevel, "WARN", 4)) level = Log::eWarning;
|
||||
else if (0 == strncmp(apLevel, "EROR", 4)) level = Log::eError;
|
||||
else /* (0 == strncmp(apLevel, "CRIT", 4)*/ level = Log::eCritic; // NOLINT(whitespace/newline)
|
||||
|
||||
return level;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace Log
|
135
src/LoggerCpp/Log.h
Normal file
135
src/LoggerCpp/Log.h
Normal file
|
@ -0,0 +1,135 @@
|
|||
/**
|
||||
* @file Log.h
|
||||
* @ingroup LoggerCpp
|
||||
* @brief A RAII (private) log object constructed by the Logger class
|
||||
*
|
||||
* Copyright (c) 2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "LoggerCpp/DateTime.h"
|
||||
#include "LoggerCpp/Utils.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <iomanip> // For easy use of parametric manipulators (setfill, setprecision) by client code
|
||||
|
||||
namespace LMB {
|
||||
namespace Log {
|
||||
|
||||
|
||||
// forward declaration
|
||||
class Logger;
|
||||
|
||||
|
||||
/**
|
||||
* @brief A RAII (private) log object constructed by the Logger class
|
||||
* @ingroup LoggerCpp
|
||||
*
|
||||
* a Log represents a full line of log, at a certain Log::Level of severity.
|
||||
*
|
||||
* It is constructed and initialized by a call to Logger::debug(),
|
||||
* Logger::info(), ... or Logger::critic().
|
||||
* Is is then used by successive stream call "<<", and is naturally terminated
|
||||
* by it destructor at the end of the line, calling the Logger::output() method.
|
||||
*
|
||||
* It contains all required information for further formating, printing and transmitting
|
||||
* by the Logger class.
|
||||
*/
|
||||
class Log {
|
||||
friend class Logger;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Enumeration of the severity levels
|
||||
*/
|
||||
enum Level {
|
||||
eDebug = 0,
|
||||
eInfo,
|
||||
eNotice,
|
||||
eWarning,
|
||||
eError,
|
||||
eCritic
|
||||
};
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief stream inserter operator
|
||||
*
|
||||
* @param[in] aValue Value to be formatted and inserted into the Log string stream
|
||||
*
|
||||
* @return Currents Log instance
|
||||
*/
|
||||
template <typename T>
|
||||
Log& operator<< (const T& aValue) {
|
||||
if (nullptr != mpStream) {
|
||||
*mpStream << aValue;
|
||||
}
|
||||
return (*this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Destructor : output the Log string stream
|
||||
*/
|
||||
~Log(void);
|
||||
|
||||
/// @brief Severity Level of this Log
|
||||
inline Level getSeverity(void) const {
|
||||
return mSeverity;
|
||||
}
|
||||
|
||||
/// @brief Timestamp of this Log
|
||||
inline const DateTime& getTime(void) const {
|
||||
return mTime;
|
||||
}
|
||||
|
||||
/// @brief The underlying string stream
|
||||
inline const std::ostringstream& getStream(void) const {
|
||||
return *mpStream;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convert a Level to its string representation
|
||||
*
|
||||
* @param[in] aLevel Log severity Level to convert
|
||||
*
|
||||
* @return Severity Level description
|
||||
*/
|
||||
static const char* toString(Log::Level aLevel);
|
||||
|
||||
/**
|
||||
* @brief Convert a string representation of a Level to its corresponding value
|
||||
*
|
||||
* @param[in] apLevel Log severity string Level
|
||||
*
|
||||
* @return Severity Level value
|
||||
*/
|
||||
static Log::Level toLevel(const char* apLevel);
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Construct a RAII (private) log object for the Logger class
|
||||
*
|
||||
* @param[in] aLogger Reference to the parent Logger
|
||||
* @param[in] aSeverity Severity of this Log
|
||||
*/
|
||||
Log(const Logger& aLogger, Level aSeverity);
|
||||
|
||||
/// @{ Non-copyable object
|
||||
Log(const Log&);
|
||||
void operator=(const Log&);
|
||||
/// @}
|
||||
|
||||
private:
|
||||
const Logger& mLogger; ///< Reference to the parent Logger
|
||||
Level mSeverity; ///< Severity of this Log
|
||||
DateTime mTime; ///< Timestamp of the output
|
||||
std::ostringstream* mpStream; ///< The underlying string stream
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
} // namespace Log
|
||||
|
61
src/LoggerCpp/Logger.cpp
Normal file
61
src/LoggerCpp/Logger.cpp
Normal file
|
@ -0,0 +1,61 @@
|
|||
/**
|
||||
* @file Logger.cpp
|
||||
* @ingroup LoggerCpp
|
||||
* @brief A simple thread-safe Logger class
|
||||
*
|
||||
* Copyright (c) 2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
|
||||
#include "LoggerCpp/Logger.h"
|
||||
#include "LoggerCpp/Manager.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace LMB {
|
||||
namespace Log {
|
||||
|
||||
|
||||
// Initialize a Logger utility object
|
||||
Logger::Logger(const char* apChannelName) {
|
||||
assert(nullptr != apChannelName);
|
||||
|
||||
mChannelPtr = Manager::get(apChannelName);
|
||||
|
||||
assert(mChannelPtr);
|
||||
}
|
||||
|
||||
// Non virtual destructor
|
||||
Logger::~Logger(void) {
|
||||
}
|
||||
|
||||
// Utility const method to produce Log objets, used to collect the stream to output
|
||||
Log Logger::debug(void) const {
|
||||
return Log(*this, Log::eDebug);
|
||||
}
|
||||
Log Logger::info(void) const {
|
||||
return Log(*this, Log::eInfo);
|
||||
}
|
||||
Log Logger::notice(void) const {
|
||||
return Log(*this, Log::eNotice);
|
||||
}
|
||||
Log Logger::warning(void) const {
|
||||
return Log(*this, Log::eWarning);
|
||||
}
|
||||
Log Logger::error(void) const {
|
||||
return Log(*this, Log::eError);
|
||||
}
|
||||
Log Logger::critic(void) const {
|
||||
return Log(*this, Log::eCritic);
|
||||
}
|
||||
|
||||
// To be used only by the Log class
|
||||
void Logger::output(const Log& aLog) const {
|
||||
Manager::output(mChannelPtr, aLog);
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace Log
|
||||
|
93
src/LoggerCpp/Logger.h
Normal file
93
src/LoggerCpp/Logger.h
Normal file
|
@ -0,0 +1,93 @@
|
|||
/**
|
||||
* @file Logger.h
|
||||
* @ingroup LoggerCpp
|
||||
* @brief A simple thread-safe Logger class
|
||||
*
|
||||
* Copyright (c) 2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "LoggerCpp/Log.h"
|
||||
#include "LoggerCpp/Channel.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace LMB {
|
||||
|
||||
/**
|
||||
* @brief LoggerC++ (LoggerCpp) is a simple, elegant and efficient C++ logger library.
|
||||
* @ingroup LoggerCpp
|
||||
*/
|
||||
namespace Log {
|
||||
|
||||
|
||||
/**
|
||||
* @brief A simple thread-safe logger class
|
||||
* @ingroup LoggerCpp
|
||||
*
|
||||
* Logger is designed to be easy to use, light (size of a shared_ptr) and efficient.
|
||||
* It can be used as a member variable, and will not consume much CPU
|
||||
* if the log severity is below the Logger current Log::Level.
|
||||
*
|
||||
* @note A Logger object is copyable without any limitations
|
||||
*/
|
||||
class Logger {
|
||||
friend class Log;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Initialize a Logger utility object
|
||||
*
|
||||
* @param[in] apChannelName String to identify origin of Log output by this Logger
|
||||
*/
|
||||
explicit Logger(const char* apChannelName);
|
||||
/**
|
||||
* @brief Non virtual destructor
|
||||
*/
|
||||
~Logger(void);
|
||||
|
||||
// A Logger is copyable with its a default copy constructor and copy operator without any problem
|
||||
|
||||
/// @{ Utility const method to produce Log objets, used to collect the stream to output
|
||||
Log debug(void) const;
|
||||
Log info(void) const;
|
||||
Log notice(void) const;
|
||||
Log warning(void) const;
|
||||
Log error(void) const;
|
||||
Log critic(void) const;
|
||||
/// @}
|
||||
|
||||
/// @brief Name of the underlying Channel
|
||||
inline const std::string& getName(void) const {
|
||||
return mChannelPtr->getName();
|
||||
}
|
||||
|
||||
/// @brief Set the current output Log::Level of the underlying Channel
|
||||
inline void setLevel(Log::Level aLevel) {
|
||||
mChannelPtr->setLevel(aLevel);
|
||||
}
|
||||
|
||||
/// @brief Current Log::Level of the underlying Channel
|
||||
inline Log::Level getLevel(void) const {
|
||||
return mChannelPtr->getLevel();
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Output the Log. Used only by the Log class destructor.
|
||||
*
|
||||
* @param[in] aLog The Log to output
|
||||
*/
|
||||
void output(const Log& aLog) const;
|
||||
|
||||
private:
|
||||
Channel::Ptr mChannelPtr; ///< Shared pointer to the underlying Channel
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
} // namespace Log
|
||||
|
20
src/LoggerCpp/LoggerCpp-LICENSE.txt
Normal file
20
src/LoggerCpp/LoggerCpp-LICENSE.txt
Normal file
|
@ -0,0 +1,20 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
138
src/LoggerCpp/LoggerCpp-README.md
Normal file
138
src/LoggerCpp/LoggerCpp-README.md
Normal file
|
@ -0,0 +1,138 @@
|
|||
LoggerC++
|
||||
---------
|
||||
|
||||

|
||||
|
||||
LoggerC++ (LoggerCpp) is a simple, elegant and efficient C++ logger library.
|
||||
|
||||
### The goals of LoggerC++ are:
|
||||
|
||||
- to keep dependencies to a minimum (STL and shared_ptr)
|
||||
- to be portable
|
||||
- to minimize cpu utilisation when no log are outputed
|
||||
- to be thread-safe (output logs in same channel accross multiple threads)
|
||||
- to be well documented with Doxygen tags
|
||||
- to use a permissive MIT license, similar to BSD or Boost, for proprietary/commercial usage
|
||||
|
||||
### Limitations:
|
||||
|
||||
Thread-safety is only for Log outputs.
|
||||
You shall not dynamically create and destroy Logger objects in multiple threads.
|
||||
Instead, build them all at startup in you main thread, before other thread startup.
|
||||
Then you are allowed to use them all in parallel.
|
||||
|
||||
### Suported platforms:
|
||||
|
||||
Developements and tests are done under the following OSs :
|
||||
- Debian 7 (testing)
|
||||
- Ubuntu 12.10
|
||||
- Windows XP/7/8
|
||||
And following IDEs/Compilers
|
||||
- GCC 4.7.x with a provided Makefile
|
||||
- Eclipse CDT under Linux, using the provided Makefile
|
||||
- Visual Studio Express 2008/2010/2012 for testing compatibility purpose
|
||||
|
||||
### Dependencies:
|
||||
|
||||
- a STL implementation with RTTI (even an old one, like the one provided with VC6 should work).
|
||||
- optionnaly: the C++ 11 std::shared_ptr or boost::shared_ptr (a minimal shared_ptr implementation is provided).
|
||||
|
||||
### Installation
|
||||
|
||||
To use this C++ Logger, you need to include the sources files into your project codebase.
|
||||
|
||||
### License
|
||||
|
||||
Copyright (c) 2013 Sébastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
|
||||
Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
or copy at http://opensource.org/licenses/MIT)
|
||||
|
||||
## Getting started
|
||||
### Principles
|
||||
|
||||
- Add a small named Logger object to your code to output logs prefixed by the given name.
|
||||
A Logger is as small as a shared_ptr, typicaly 8 bytes.
|
||||
Use it as a member variable to your class, or as a free variable.
|
||||
- Build a Log with standard stream manipulations (like with std::cout)
|
||||
but in a thread-safe manner: the Log is outputed atomically at the end of the line.
|
||||
- Use one of the 6 Log Level, ranging from Debug to Critic in a standard fashion.
|
||||
- Set the Channel Level of the Logger to dynamicaly filter Log to be outputed
|
||||
- Multiple Logger objects with the same name will share the same underlying named Channel.
|
||||
Any of theses Logger can manipulate the Channel output Level.
|
||||
- Configure the availlable Output objects, for console, file or MSVC Debugger output.
|
||||
|
||||
### First sample demonstrates how to create a Logger and print some logs:
|
||||
|
||||
```C++
|
||||
int main ()
|
||||
{
|
||||
// Configure the default severity Level of new Channel objects
|
||||
Log::Manager::setDefaultLevel(Log::Log::eNotice);
|
||||
|
||||
// Setup the list of Config for the Output objects,
|
||||
Log::Config::Vector configList;
|
||||
Log::Config::addOutput(configList, "OutputConsole");
|
||||
Log::Config::addOutput(configList, "OutputFile");
|
||||
Log::Config::setOption(configList, "filename", "log.txt");
|
||||
Log::Config::setOption(configList, "max_size", "10000");
|
||||
// and configure the Log Manager (create the Output objects)
|
||||
Log::Manager::configure(configList);
|
||||
|
||||
// Create a Logger object, using a "Main.Example" Channel
|
||||
Log::Logger logger("Main.Example");
|
||||
|
||||
// Test outputs of various kind of variables, and some common stream manipulations.
|
||||
std::string str("string");
|
||||
unsigned int ui = 123;
|
||||
double dbl = -0.023f;
|
||||
logger.debug() << "Variables ; '" << str << "', '" << ui << "', '" << dbl << "'";
|
||||
logger.debug() << "Hexa = " << std::hex << 0x75af0 << " test";
|
||||
logger.debug() << "Deci = " << std::right << std::setfill('0') << std::setw(8) << 76035 << " test";
|
||||
|
||||
// Test outputs of various severity Level
|
||||
logger.debug() << "Debug.";
|
||||
logger.info() << "Info.";
|
||||
logger.notice() << "Notice.";
|
||||
logger.warning()<< "Warning.";
|
||||
logger.error() << "Error.";
|
||||
logger.critic() << "Critic.";
|
||||
|
||||
// Modify the output Level of the underlying Channel, and test various severity Level again
|
||||
logger.setLevel(Log::Log::eWarning);
|
||||
logger.debug() << "NO Debug."; // NO more debug logs
|
||||
logger.info() << "NO Info."; // NO more info logs
|
||||
logger.notice() << "NO Notice."; // NO more notice logs
|
||||
logger.warning()<< "Warning.";
|
||||
logger.error() << "Error.";
|
||||
logger.critic() << "Critic.";
|
||||
|
||||
// Reset Level of the "Main.example" channel by its name
|
||||
Log::Manager::get("Main.Example")->setLevel(Log::Log::eDebug);
|
||||
```
|
||||
|
||||
## How to contribute
|
||||
### GitHub website
|
||||
The most efficient way to help and contribute to this wrapper project is to
|
||||
use the tools provided by GitHub:
|
||||
- please fill bug reports and feature requests here: https://github.com/SRombauts/LoggerCpp/issues
|
||||
- fork the repository, make some small changes and submit them with pull-request
|
||||
|
||||
### Contact
|
||||
You can also email me directly, I will answer any questions and requests.
|
||||
|
||||
### Coding Style Guidelines
|
||||
The source code use the CamelCase naming style variant where :
|
||||
- type names (class, struct, typedef, enums...) begins with a capital letter
|
||||
- files (.cpp/.h) are named like the class they contains
|
||||
- function and variable names begins with a lower case letter
|
||||
- member variables begins with a 'm', function arguments begins with a 'a', boolean with a 'b', pointers with a 'p'
|
||||
- each file, class, method and member variable is documented using Doxygen tags
|
||||
See also http://www.appinf.com/download/CppCodingStyleGuide.pdf for good guidelines
|
||||
|
||||
### Continuous Integration
|
||||
|
||||
This project is continuously tested under Ubuntu Linux with the gcc and clang compilers
|
||||
using the Travis CI community service with the above CMake building and testing procedure.
|
||||
|
||||
Detailed results can be seen online: https://travis-ci.org/SRombauts/LoggerCpp
|
45
src/LoggerCpp/LoggerCpp.h
Normal file
45
src/LoggerCpp/LoggerCpp.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
/**
|
||||
* @file LoggerCpp.h
|
||||
* @ingroup LoggerCpp
|
||||
* @brief LoggerC++ (LoggerCpp) is a simple, elegant and efficient C++ logger library.
|
||||
*
|
||||
* Include this main header file in your project to gain access to all functionality provided by the logger.
|
||||
*
|
||||
* Copyright (c) 2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
/**
|
||||
* @defgroup LoggerCpp LoggerC++
|
||||
* @brief LoggerC++ (LoggerCpp) is a simple, elegant and efficient C++ logger library.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
||||
// Include useful headers of LoggerC++
|
||||
#include "LoggerCpp/Logger.h"
|
||||
#include "LoggerCpp/Manager.h"
|
||||
|
||||
|
||||
/**
|
||||
* @def LOGGERCPP_VERSION
|
||||
* @brief Srting version numbers for LoggerC++
|
||||
* @ingroup LoggerCpp
|
||||
*
|
||||
* The LOGGERCPP_VERSION C preprocessor macro in the LoggerCpp.h header
|
||||
* evaluates to a string literal that is the LoggerC++ version in the
|
||||
* format "X.Y.Z" where X is the major version number
|
||||
* and Y is the minor version number and Z is the release number.
|
||||
*/
|
||||
#define LOGGERCPP_VERSION "0.2.0"
|
||||
/**
|
||||
* @def LOGGERCPP_VERSION_NUMBER
|
||||
* @brief Numeric version numbers for LoggerC++
|
||||
* @ingroup LoggerCpp
|
||||
*
|
||||
* The LOGGERCPP_VERSION_NUMBER C preprocessor macro resolves to an integer
|
||||
* with the value (X*1000000 + Y*1000 + Z) where X, Y, and Z are the same
|
||||
* numbers used in [LOGGERCPP_VERSION].
|
||||
*/
|
||||
#define LOGGERCPP_VERSION_NUMBER 0002000
|
140
src/LoggerCpp/Manager.cpp
Normal file
140
src/LoggerCpp/Manager.cpp
Normal file
|
@ -0,0 +1,140 @@
|
|||
/**
|
||||
* @file Manager.cpp
|
||||
* @ingroup LoggerCpp
|
||||
* @brief The static class that manage the registered channels and outputs
|
||||
*
|
||||
* Copyright (c) 2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
|
||||
#include "LoggerCpp/Manager.h"
|
||||
#include "LoggerCpp/Exception.h"
|
||||
|
||||
#include "LoggerCpp/OutputConsole.h"
|
||||
#include "LoggerCpp/OutputFile.h"
|
||||
#ifdef WIN32
|
||||
#include "LoggerCpp/OutputDebug.h"
|
||||
#endif
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
namespace LMB {
|
||||
namespace Log {
|
||||
|
||||
|
||||
Channel::Map Manager::mChannelMap;
|
||||
Output::Vector Manager::mOutputList;
|
||||
Log::Level Manager::mDefaultLevel = Log::eDebug;
|
||||
|
||||
|
||||
// Create and configure the Output objects.
|
||||
void Manager::configure(const Config::Vector& aConfigList) {
|
||||
// List of all Output class ; those names are in the form
|
||||
// - "class Log::OutputConsole" under Visual Studio 2010
|
||||
// - "N3Log13OutputConsoleE" under GCC
|
||||
std::string outputConsole = typeid(OutputConsole).name();
|
||||
std::string outputFile = typeid(OutputFile).name();
|
||||
#ifdef WIN32
|
||||
std::string outputDebug = typeid(OutputDebug).name();
|
||||
#endif
|
||||
|
||||
Config::Vector::const_iterator iConfig;
|
||||
for ( iConfig = aConfigList.begin();
|
||||
iConfig != aConfigList.end();
|
||||
++iConfig) {
|
||||
Output::Ptr outputPtr;
|
||||
const std::string& configName = (*iConfig)->getName();
|
||||
|
||||
// Compare the provided Output name with the known class name
|
||||
if (std::string::npos != outputConsole.find(configName)) {
|
||||
outputPtr.reset(new OutputConsole((*iConfig)));
|
||||
} else if (std::string::npos != outputFile.find(configName)) {
|
||||
outputPtr.reset(new OutputFile((*iConfig)));
|
||||
#ifdef WIN32
|
||||
} else if (std::string::npos != outputDebug.find(configName)) {
|
||||
outputPtr.reset(new OutputDebug((*iConfig)));
|
||||
#endif
|
||||
} else {
|
||||
LOGGER_THROW("Unknown Output name '" << configName << "'");
|
||||
}
|
||||
mOutputList.push_back(outputPtr);
|
||||
}
|
||||
}
|
||||
|
||||
// Destroy the Output objects.
|
||||
void Manager::terminate(void) {
|
||||
// This effectively destroys the Output objects
|
||||
mOutputList.clear();
|
||||
}
|
||||
|
||||
// Return the Channel corresponding to the provided name
|
||||
Channel::Ptr Manager::get(const char* apChannelName) {
|
||||
Channel::Ptr ChannelPtr;
|
||||
Channel::Map::iterator iChannelPtr = mChannelMap.find(apChannelName);
|
||||
|
||||
if (mChannelMap.end() != iChannelPtr) {
|
||||
ChannelPtr = iChannelPtr->second;
|
||||
} else {
|
||||
/// @todo Add a basic thread-safety security (throw if multiple threads create Loggers)
|
||||
ChannelPtr.reset(new Channel(apChannelName, mDefaultLevel));
|
||||
mChannelMap[apChannelName] = ChannelPtr;
|
||||
}
|
||||
|
||||
return ChannelPtr;
|
||||
}
|
||||
|
||||
// Output the Log to all the active Output objects.
|
||||
void Manager::output(const Channel::Ptr& aChannelPtr, const Log& aLog) {
|
||||
Output::Vector::iterator iOutputPtr;
|
||||
if (mOutputList.size() == 0) {
|
||||
OutputConsole output(NULL);
|
||||
output.output(aChannelPtr, aLog);
|
||||
}
|
||||
|
||||
|
||||
for ( iOutputPtr = mOutputList.begin();
|
||||
iOutputPtr != mOutputList.end();
|
||||
++iOutputPtr) {
|
||||
(*iOutputPtr)->output(aChannelPtr, aLog);
|
||||
}
|
||||
}
|
||||
|
||||
// Serialize the current Log::Level of Channel objects and return them as a Config instance
|
||||
Config::Ptr Manager::getChannelConfig(void) {
|
||||
Config::Ptr ConfigPtr(new Config("ChannelConfig"));
|
||||
|
||||
Channel::Map::const_iterator iChannel;
|
||||
for (iChannel = mChannelMap.begin();
|
||||
iChannel != mChannelMap.end();
|
||||
++iChannel) {
|
||||
ConfigPtr->setValue(iChannel->first.c_str(), Log::toString(iChannel->second->getLevel()));
|
||||
}
|
||||
|
||||
return ConfigPtr;
|
||||
}
|
||||
|
||||
// Set the Log::Level of Channel objects from the provided Config instance
|
||||
void Manager::setChannelConfig(const Config::Ptr& aConfigPtr) {
|
||||
const Config::Values& ConfigValues = aConfigPtr->getValues();
|
||||
|
||||
Config::Values::const_iterator iValue;
|
||||
for (iValue = ConfigValues.begin();
|
||||
iValue != ConfigValues.end();
|
||||
++iValue) {
|
||||
Manager::get(iValue->first.c_str())->setLevel(Log::toLevel(iValue->second.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
void Manager::setCustomLogger(Output *logger) {
|
||||
mOutputList.clear();
|
||||
Output::Ptr outputPtr;
|
||||
outputPtr.reset(logger);
|
||||
mOutputList.push_back(outputPtr);
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace Log
|
||||
|
104
src/LoggerCpp/Manager.h
Normal file
104
src/LoggerCpp/Manager.h
Normal file
|
@ -0,0 +1,104 @@
|
|||
/**
|
||||
* @file Manager.h
|
||||
* @ingroup LoggerCpp
|
||||
* @brief The static class that manage the registered Channel and Output objects
|
||||
*
|
||||
* Copyright (c) 2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "LoggerCpp/Log.h"
|
||||
#include "LoggerCpp/Channel.h"
|
||||
#include "LoggerCpp/Output.h"
|
||||
#include "LoggerCpp/Config.h"
|
||||
|
||||
namespace LMB {
|
||||
|
||||
namespace Log {
|
||||
|
||||
|
||||
/**
|
||||
* @brief The static class that manage the registered channels and outputs
|
||||
* @ingroup LoggerCpp
|
||||
*
|
||||
* The Manager keeps a map of all the named Channel objects
|
||||
* and share them on demand by new Logger objects created with the same name.
|
||||
*
|
||||
* Thus the Manager is able to change the Log::Level of selected Channel object,
|
||||
* impacting all the Logger objects using it.
|
||||
*
|
||||
* The Manager also keeps a list of all configured Output object to output the Log objects.
|
||||
*/
|
||||
struct Manager {
|
||||
public:
|
||||
/**
|
||||
* @brief Create and configure the Output objects.
|
||||
*
|
||||
* @see setChannelConfig()
|
||||
*
|
||||
* @param[in] aConfigList List of Config for Output objects
|
||||
*/
|
||||
static void configure(const Config::Vector& aConfigList);
|
||||
|
||||
/**
|
||||
* @brief Destroy the Output objects.
|
||||
*
|
||||
* Clear the Output list to release the ownership.
|
||||
*/
|
||||
static void terminate(void);
|
||||
|
||||
/**
|
||||
* @brief Return the Channel corresponding to the provided name
|
||||
*
|
||||
* Create a new Channel or get the existing one.
|
||||
*
|
||||
* @param[in] apChannelName String to identify the underlying Channel of a Logger
|
||||
*
|
||||
* @return Pointer to the corresponding Channel (never nullptr)
|
||||
*/
|
||||
static Channel::Ptr get(const char* apChannelName);
|
||||
|
||||
/**
|
||||
* @brief Output the Log to all the active Output objects.
|
||||
*
|
||||
* Dispatch the Log to OutputConsole/OutputFile/OutputVS/OutputMemory...
|
||||
*
|
||||
* @param[in] aChannelPtr The underlying Channel of the Log
|
||||
* @param[in] aLog The Log to output
|
||||
*/
|
||||
static void output(const Channel::Ptr& aChannelPtr, const Log& aLog);
|
||||
|
||||
/**
|
||||
* @brief Set the default output Log::Level of any new Channel
|
||||
*/
|
||||
static inline void setDefaultLevel(Log::Level aLevel) {
|
||||
mDefaultLevel = aLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Serialize the current Log::Level of Channel objects and return them as a Config instance
|
||||
*/
|
||||
static Config::Ptr getChannelConfig(void);
|
||||
|
||||
/**
|
||||
* @brief Set the Log::Level of Channel objects from the provided Config instance
|
||||
*/
|
||||
static void setChannelConfig(const Config::Ptr& aConfigPtr);
|
||||
|
||||
/**
|
||||
* @brief Set a Custom Logger
|
||||
*/
|
||||
static void setCustomLogger(Output *logger);
|
||||
|
||||
private:
|
||||
static Channel::Map mChannelMap; ///< Map of shared pointer of Channel objects
|
||||
static Output::Vector mOutputList; ///< List of Output objects
|
||||
static Log::Level mDefaultLevel; ///< Default Log::Level of any new Channel
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
} // namespace Log
|
61
src/LoggerCpp/Output.h
Normal file
61
src/LoggerCpp/Output.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
/**
|
||||
* @file Output.h
|
||||
* @ingroup LoggerCpp
|
||||
* @brief Interface of an Output
|
||||
*
|
||||
* Copyright (c) 2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "LoggerCpp/Channel.h"
|
||||
|
||||
#include <vector>
|
||||
#include <typeinfo>
|
||||
|
||||
// The following includes "boost/shared_ptr.hpp" if LOGGER_USE_BOOST_SHARED_PTR is defined,
|
||||
// or <memory> (or <tr1/memory>) when C++11 (or experimental C++0x) is available,
|
||||
// or a custom minimal shared_ptr implementation,
|
||||
// and imports the "shared_ptr" symbol inside the Log namespace (ie. Log::shared_ptr)
|
||||
#include "LoggerCpp/shared_ptr.hpp"
|
||||
|
||||
namespace LMB {
|
||||
namespace Log {
|
||||
|
||||
|
||||
// Forward declaration
|
||||
class Log;
|
||||
|
||||
/**
|
||||
* @brief Interface of an Output
|
||||
* @ingroup LoggerCpp
|
||||
*/
|
||||
class Output {
|
||||
public:
|
||||
/// @brief Virtual destructor
|
||||
virtual ~Output() {}
|
||||
|
||||
public:
|
||||
/// @brief Shared Pointer to an Output
|
||||
typedef shared_ptr<Output> Ptr;
|
||||
/// @brief List of Output objects
|
||||
typedef std::vector<Ptr> Vector;
|
||||
|
||||
/**
|
||||
* @brief Output the Log
|
||||
*
|
||||
* @param[in] aChannelPtr The underlying Channel of the Log
|
||||
* @param[in] aLog The Log to output
|
||||
*/
|
||||
virtual void output(const Channel::Ptr& aChannelPtr, const Log& aLog) const = 0;
|
||||
|
||||
/// @brief Return the type name of the Output object
|
||||
inline const char* name() const {
|
||||
return typeid(this).name();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace Log
|
94
src/LoggerCpp/OutputConsole.cpp
Normal file
94
src/LoggerCpp/OutputConsole.cpp
Normal file
|
@ -0,0 +1,94 @@
|
|||
/**
|
||||
* @file OutputConsole.cpp
|
||||
* @ingroup LoggerCpp
|
||||
* @brief Output to the standard console using fprintf() with stdout
|
||||
*
|
||||
* Copyright (c) 2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
|
||||
#include "LoggerCpp/OutputConsole.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
namespace LMB {
|
||||
namespace Log {
|
||||
|
||||
|
||||
// Constructor
|
||||
OutputConsole::OutputConsole(const Config::Ptr& aConfigPtr) {
|
||||
(void)aConfigPtr;
|
||||
}
|
||||
|
||||
// Destructor
|
||||
OutputConsole::~OutputConsole() {
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
// Convert a Level to a Win32 console color text attribute
|
||||
unsigned short OutputConsole::toWin32Attribute(Log::Level aLevel) {
|
||||
unsigned short code;
|
||||
|
||||
switch (aLevel) {
|
||||
case Log::eDebug : code = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; break; // white
|
||||
case Log::eInfo : code = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY; break;
|
||||
case Log::eNotice : code = FOREGROUND_GREEN; break; // green
|
||||
case Log::eWarning : code = FOREGROUND_RED | FOREGROUND_GREEN; break; // orange
|
||||
case Log::eError : code = FOREGROUND_RED; break; // red
|
||||
case Log::eCritic : code = FOREGROUND_RED | FOREGROUND_INTENSITY; break; // light red
|
||||
default : code = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; break; // white
|
||||
}
|
||||
|
||||
return (code);
|
||||
}
|
||||
|
||||
#else // _WIN32
|
||||
|
||||
// Convert a Level to its ANSI escape color code
|
||||
unsigned int OutputConsole::toEscapeCode(Log::Level aLevel) {
|
||||
unsigned int code;
|
||||
|
||||
switch (aLevel) {
|
||||
case Log::eDebug: code = 34; break; // 34=blue
|
||||
case Log::eInfo: code = 39; break; // 39=white
|
||||
case Log::eNotice: code = 32; break; // 32=green
|
||||
case Log::eWarning: code = 33; break; // 33=orange
|
||||
case Log::eError: code = 31; break; // 31=red
|
||||
case Log::eCritic: code = 95; break; // 95=magenta
|
||||
default: code = 39; break; // 39=white (reset to default)
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
// Output the Log to the standard console using fprintf
|
||||
void OutputConsole::output(const Channel::Ptr& aChannelPtr, const Log& aLog) const {
|
||||
const DateTime& time = aLog.getTime();
|
||||
|
||||
// uses fprintf for atomic thread-safe operation
|
||||
#ifdef _WIN32
|
||||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), toWin32Attribute(aLog.getSeverity()));
|
||||
fprintf(stdout, "%.4u-%.2u-%.2u %.2u:%.2u:%.2u.%.3u %-12s %s %s\n",
|
||||
#else // _WIN32
|
||||
fprintf(stdout, "\x1B[%02um%.4u-%.2u-%.2u %.2u:%.2u:%.2u.%.3u %-12s %s %s\x1b[39m\n",
|
||||
toEscapeCode(aLog.getSeverity()),
|
||||
#endif // _WIN32
|
||||
time.year, time.month, time.day,
|
||||
time.hour, time.minute, time.second, time.ms,
|
||||
aChannelPtr->getName().c_str(), Log::toString(aLog.getSeverity()), (aLog.getStream()).str().c_str());
|
||||
#ifdef _WIN32
|
||||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
|
||||
#endif // _WIN32
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace Log
|
62
src/LoggerCpp/OutputConsole.h
Normal file
62
src/LoggerCpp/OutputConsole.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
/**
|
||||
* @file OutputConsole.h
|
||||
* @ingroup LoggerCpp
|
||||
* @brief Output to the standard console using fprintf() with stdout
|
||||
*
|
||||
* Copyright (c) 2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "LoggerCpp/Output.h"
|
||||
#include "LoggerCpp/Config.h"
|
||||
|
||||
namespace LMB {
|
||||
namespace Log {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Output to the standard console using fprintf() with stdout
|
||||
* @ingroup LoggerCpp
|
||||
*/
|
||||
class OutputConsole : public Output {
|
||||
public:
|
||||
/// @brief Constructor : no config
|
||||
explicit OutputConsole(const Config::Ptr& aConfigPtr);
|
||||
|
||||
/// @brief Destructor
|
||||
virtual ~OutputConsole();
|
||||
|
||||
#ifdef _WIN32
|
||||
/**
|
||||
* @brief Convert a Level to a Win32 console color text attribute
|
||||
*
|
||||
* @param[in] aLevel Log severity Level to convert
|
||||
*
|
||||
* @return Win32 console color text attribute
|
||||
*/
|
||||
static unsigned short toWin32Attribute(Log::Level aLevel);
|
||||
#else // _WIN32
|
||||
/**
|
||||
* @brief Convert a Level to an ANSI escape color code
|
||||
*
|
||||
* @param[in] aLevel Log severity Level to convert
|
||||
*
|
||||
* @return ANSI escape code for console color output
|
||||
*/
|
||||
static unsigned int toEscapeCode(Log::Level aLevel);
|
||||
#endif // _WIN32
|
||||
|
||||
/**
|
||||
* @brief Output the Log to the standard console using fprintf
|
||||
*
|
||||
* @param[in] aChannelPtr The underlying Channel of the Log
|
||||
* @param[in] aLog The Log to output
|
||||
*/
|
||||
virtual void output(const Channel::Ptr& aChannelPtr, const Log& aLog) const;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace Log
|
49
src/LoggerCpp/OutputDebug.cpp
Normal file
49
src/LoggerCpp/OutputDebug.cpp
Normal file
|
@ -0,0 +1,49 @@
|
|||
/**
|
||||
* @file OutputDebug.cpp
|
||||
* @ingroup LoggerCpp
|
||||
* @brief Output to the Visual Studio debugger using OutputDebugString()
|
||||
*
|
||||
* Copyright (c) 2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
#include "LoggerCpp/OutputDebug.h"
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
namespace LMB {
|
||||
namespace Log {
|
||||
|
||||
|
||||
// Constructor
|
||||
OutputDebug::OutputDebug(const Config::Ptr& aConfigPtr) {
|
||||
}
|
||||
|
||||
// Destructor
|
||||
OutputDebug::~OutputDebug() {
|
||||
}
|
||||
|
||||
// Output the Log to the Visual Studio debugger using OutputDebugString()
|
||||
void OutputDebug::output(const Channel::Ptr& aChannelPtr, const Log& aLog) const {
|
||||
const DateTime& time = aLog.getTime();
|
||||
char buffer[256];
|
||||
|
||||
// uses snprintf for atomic thread-safe operation
|
||||
_snprintf(buffer, sizeof(buffer), "%.4u-%.2u-%.2u %.2u:%.2u:%.2u.%.3u %-12s %s %s\n",
|
||||
time.year, time.month, time.day,
|
||||
time.hour, time.minute, time.second, time.ms,
|
||||
aChannelPtr->getName().c_str(), Log::toString(aLog.getSeverity()), (aLog.getStream()).str().c_str());
|
||||
buffer[255] = '\0';
|
||||
OutputDebugStringA(buffer);
|
||||
}
|
||||
|
||||
|
||||
} // namespace Log
|
||||
}
|
||||
#endif // WIN32
|
43
src/LoggerCpp/OutputDebug.h
Normal file
43
src/LoggerCpp/OutputDebug.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
/**
|
||||
* @file OutputDebug.h
|
||||
* @ingroup LoggerCpp
|
||||
* @brief Output to the Visual Studio debugger using OutputDebugString()
|
||||
*
|
||||
* Copyright (c) 2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "LoggerCpp/Output.h"
|
||||
#include "LoggerCpp/Config.h"
|
||||
|
||||
namespace LMB {
|
||||
namespace Log {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Output to the Visual Studio debugger using OutputDebugString()
|
||||
* @ingroup LoggerCpp
|
||||
*/
|
||||
class OutputDebug : public Output {
|
||||
public:
|
||||
/// @brief Constructor : no config
|
||||
explicit OutputDebug(const Config::Ptr& aConfigPtr);
|
||||
|
||||
/// @brief Destructor
|
||||
virtual ~OutputDebug();
|
||||
|
||||
/**
|
||||
* @brief Output the Log to the Visual Studio debugger using OutputDebugString()
|
||||
*
|
||||
* @param[in] aChannelPtr The underlying Channel of the Log
|
||||
* @param[in] aLog The Log to output
|
||||
*/
|
||||
virtual void output(const Channel::Ptr& aChannelPtr, const Log& aLog) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
} // namespace Log
|
101
src/LoggerCpp/OutputFile.cpp
Normal file
101
src/LoggerCpp/OutputFile.cpp
Normal file
|
@ -0,0 +1,101 @@
|
|||
/**
|
||||
* @file OutputFile.cpp
|
||||
* @ingroup LoggerCpp
|
||||
* @brief Output to the standard console using printf
|
||||
*
|
||||
* Copyright (c) 2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
|
||||
#include "LoggerCpp/OutputFile.h"
|
||||
#include "LoggerCpp/Exception.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
namespace LMB {
|
||||
namespace Log {
|
||||
|
||||
|
||||
// Open the output file
|
||||
OutputFile::OutputFile(const Config::Ptr& aConfigPtr) :
|
||||
mpFile(nullptr) {
|
||||
assert(aConfigPtr);
|
||||
|
||||
mMaxStartupSize = aConfigPtr->get("max_startup_size", (long)0);
|
||||
mMaxSize = aConfigPtr->get("max_size", (long)1024*1024);
|
||||
mFilename = aConfigPtr->get("filename", "log.txt");
|
||||
mFilenameOld = aConfigPtr->get("filename_old", "log.old.txt");
|
||||
|
||||
// Test the size of the existing log file, rename it and open a new one if needed
|
||||
struct stat statFile;
|
||||
int ret = stat(mFilename.c_str(), &statFile);
|
||||
if (0 == ret) {
|
||||
mSize = statFile.st_size;
|
||||
}
|
||||
|
||||
if (mSize > mMaxStartupSize) {
|
||||
rotate();
|
||||
} else {
|
||||
open();
|
||||
}
|
||||
}
|
||||
|
||||
// Close the file
|
||||
OutputFile::~OutputFile() {
|
||||
close();
|
||||
}
|
||||
|
||||
// Open the file
|
||||
void OutputFile::open() const {
|
||||
mpFile = fopen(mFilename.c_str(), "ab");
|
||||
if (nullptr == mpFile) {
|
||||
LOGGER_THROW("file \"" << mFilename << "\" not opened");
|
||||
}
|
||||
}
|
||||
|
||||
// Close the file if it is opened
|
||||
void OutputFile::close() const {
|
||||
if (nullptr != mpFile) {
|
||||
fclose(mpFile);
|
||||
mpFile = nullptr;
|
||||
mSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Rotate a file : close, remove, rename, open
|
||||
void OutputFile::rotate() const {
|
||||
close();
|
||||
|
||||
remove(mFilenameOld.c_str());
|
||||
rename(mFilename.c_str(), mFilenameOld.c_str());
|
||||
|
||||
open();
|
||||
}
|
||||
|
||||
// Output the Log to the standard console using printf
|
||||
void OutputFile::output(const Channel::Ptr& aChannelPtr, const Log& aLog) const {
|
||||
const DateTime& time = aLog.getTime();
|
||||
|
||||
if (mSize > mMaxSize) {
|
||||
rotate();
|
||||
}
|
||||
|
||||
if (nullptr != mpFile) {
|
||||
// uses fprintf for atomic thread-safe operation
|
||||
int nbWritten = fprintf(mpFile, "%.4u-%.2u-%.2u %.2u:%.2u:%.2u.%.3u %-12s %s %s\n",
|
||||
time.year, time.month, time.day,
|
||||
time.hour, time.minute, time.second, time.ms,
|
||||
aChannelPtr->getName().c_str(), Log::toString(aLog.getSeverity()),
|
||||
(aLog.getStream()).str().c_str());
|
||||
fflush(stdout);
|
||||
|
||||
mSize += nbWritten;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace Log
|
84
src/LoggerCpp/OutputFile.h
Normal file
84
src/LoggerCpp/OutputFile.h
Normal file
|
@ -0,0 +1,84 @@
|
|||
/**
|
||||
* @file OutputFile.h
|
||||
* @ingroup LoggerCpp
|
||||
* @brief Output to the a file using fprintf
|
||||
*
|
||||
* Copyright (c) 2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "LoggerCpp/Output.h"
|
||||
#include "LoggerCpp/Config.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace LMB {
|
||||
namespace Log {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Output to the standard console using fprintf
|
||||
* @ingroup LoggerCpp
|
||||
*/
|
||||
class OutputFile : public Output {
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor : open the output file
|
||||
*
|
||||
* @param[in] aConfigPtr Config the output file with "filename"
|
||||
*/
|
||||
explicit OutputFile(const Config::Ptr& aConfigPtr);
|
||||
|
||||
/// @brief Destructor : close the file
|
||||
virtual ~OutputFile();
|
||||
|
||||
/**
|
||||
* @brief Output the Log to the standard console using fprintf
|
||||
*
|
||||
* @param[in] aChannelPtr The underlying Channel of the Log
|
||||
* @param[in] aLog The Log to output
|
||||
*/
|
||||
virtual void output(const Channel::Ptr& aChannelPtr, const Log& aLog) const;
|
||||
|
||||
private:
|
||||
/// @brief Open the log file
|
||||
void open() const;
|
||||
/// @brief Close the log file
|
||||
void close() const;
|
||||
/// @brief Rotate the log file : close, remove, rename, open
|
||||
void rotate() const;
|
||||
|
||||
private:
|
||||
mutable FILE* mpFile; ///< @brief File pointer (mutable to be modified in the const output method)
|
||||
mutable long mSize; ///< @brief Current size of the log file (mutable to be modified in the const output method)
|
||||
|
||||
/**
|
||||
* @brief "max_startup_size" : Size of the file above which to create a new file instead of appending to it (at startup).
|
||||
*
|
||||
* Default (0) creates a new file at each startup (never append to an existing one).
|
||||
*/
|
||||
long mMaxStartupSize;
|
||||
|
||||
/**
|
||||
* @brief "max_size" : Size of the file above which to create a new file instead of appending to it (at runtime).
|
||||
*
|
||||
* Default (1024*1024=1Mo) creates a new file each time the current one grow above 1Mo.
|
||||
*/
|
||||
long mMaxSize;
|
||||
|
||||
/**
|
||||
* @brief "filename" : Name of the log file
|
||||
*/
|
||||
std::string mFilename;
|
||||
|
||||
/**
|
||||
* @brief "filename_old" : Name of the log file renamed after max_size is reach
|
||||
*/
|
||||
std::string mFilenameOld;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace Log
|
78
src/LoggerCpp/Utils.h
Normal file
78
src/LoggerCpp/Utils.h
Normal file
|
@ -0,0 +1,78 @@
|
|||
/**
|
||||
* @file Utils.h
|
||||
* @ingroup Utils
|
||||
* @brief Shared utility macros and functions.
|
||||
*
|
||||
* Copyright (c) 2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
/**
|
||||
* @defgroup Utils Utils
|
||||
* @brief Shared utilities.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* @brief Shared utilities.
|
||||
* @ingroup Utils Utils
|
||||
*/
|
||||
namespace Utils {
|
||||
} // namespace Utils
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
/**
|
||||
* @brief A macro to disallow the copy constructor and operator= functions.
|
||||
*
|
||||
* This should be used in the private: declarations for a class
|
||||
*
|
||||
* @param[in] TypeName Class name to protect
|
||||
*/
|
||||
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
|
||||
TypeName(const TypeName&); \
|
||||
void operator=(const TypeName&)
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if _MSC_VER < 1600
|
||||
/// A macro to enable the use of the nullptr keyword (NULL on older MSVC compilers, as they does not accept "nullptr_t")
|
||||
#ifndef nullptr
|
||||
#define nullptr NULL
|
||||
#endif // nullptr
|
||||
#endif // _MSC_VER < 1600
|
||||
#else // _MSC_VER
|
||||
#if (__cplusplus < 201103L) && !defined(__GXX_EXPERIMENTAL_CXX0X__) // before C++11 on GCC4.7 and Visual Studio 2010
|
||||
#ifndef HAVE_NULLPTR
|
||||
#define HAVE_NULLPTR ///< A macro to avoid double definition of nullptr
|
||||
/**
|
||||
* @brief nullptr_t is the type of the null pointer literal, nullptr.
|
||||
*/
|
||||
class nullptr_t {
|
||||
public:
|
||||
template<typename T>
|
||||
inline operator T* () const { ///< convertible to any type of null non-member pointer...
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename C, typename T>
|
||||
inline operator T C::* () const { ///< convertible to any type of null member pointer...
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
void operator&() const; ///< Can't take address of nullptr NOLINT
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Better way to enable nullptr on older GCC/Clang compilers
|
||||
*/
|
||||
const nullptr_t nullptr = {};
|
||||
#endif // HAVE_NULLPTR
|
||||
#endif // (__cplusplus < 201103L) && !defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
#endif // _MSC_VER
|
||||
|
||||
// A macro for snprintf support in Visual Studio
|
||||
#if _MSC_VER
|
||||
#define snprintf _snprintf
|
||||
#endif
|
317
src/LoggerCpp/shared_ptr.hpp
Normal file
317
src/LoggerCpp/shared_ptr.hpp
Normal file
|
@ -0,0 +1,317 @@
|
|||
/**
|
||||
* @file shared_ptr.hpp
|
||||
* @brief shared_ptr is a minimal implementation of smart pointer, a subset of the C++11 std::shared_ptr or boost::shared_ptr.
|
||||
*
|
||||
* This file includes "boost/shared_ptr.hpp" if LOGGER_USE_BOOST_SHARED_PTR is defined,
|
||||
* or <memory> (or <tr1/memory>) when C++11 (or experimental C++0x) is available,
|
||||
* and imports the symbol "shared_ptr" inside the current namespace (ie. Log::shared_ptr).
|
||||
* If no std::shared_ptr is available, it defines a minimal shared_ptr implementation.
|
||||
*
|
||||
* Copyright (c) 2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
||||
/// Compatibility with non-clang compilers.
|
||||
#ifndef __has_feature
|
||||
#define __has_feature(x) 0
|
||||
#endif
|
||||
|
||||
//
|
||||
// Try to detect the better shared_ptr to use, and then imports the symbol in the current namespace
|
||||
// => if you include this "shared_ptr.hpp" file inside your own namespace you will
|
||||
// get a kind of universal easy to use "shared_ptr" type
|
||||
//
|
||||
#ifdef LOGGER_USE_BOOST_SHARED_PTR
|
||||
// Use Boost only if explicitly told
|
||||
#include <boost/shared_ptr.hpp>
|
||||
namespace fl {
|
||||
namespace Log {
|
||||
using boost::shared_ptr;
|
||||
} // namespace Log
|
||||
}
|
||||
// Detect whether the compiler supports C++11 shared_ptr or its TR1 pre-version.
|
||||
#elif (defined(__GNUC__) && \
|
||||
(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2)) && \
|
||||
defined(__GXX_EXPERIMENTAL_CXX0X__))
|
||||
// GCC 4.3 and following have std::shared_ptr support when called with -std=c++0x (or -std=c++11 starting with GCC 4.7)
|
||||
#include <memory>
|
||||
namespace LMB {
|
||||
namespace Log {
|
||||
using std::shared_ptr;
|
||||
} // namespace Log
|
||||
}
|
||||
#elif (defined(__GNUC__) && (__GNUC__ == 4) && defined(__GXX_EXPERIMENTAL_CXX0X__))
|
||||
// GCC 4.0/4.1/4.2 have std::shared_ptr support when when called with -std=c++0x
|
||||
#include <tr1/memory>
|
||||
namespace fl {
|
||||
namespace Log {
|
||||
using std::tr1::shared_ptr;
|
||||
} // namespace Log
|
||||
}
|
||||
#elif defined(__clang__) && __has_feature(cxx_nullptr)
|
||||
// Clang 2.9 and above ?
|
||||
#include <memory>
|
||||
namespace fl {
|
||||
namespace Log {
|
||||
using std::shared_ptr;
|
||||
} // namespace Log
|
||||
}
|
||||
#elif defined(_MSC_VER) && (_MSC_VER >= 1600)
|
||||
// Visual Studio 2010 compile by default in C++11 mode
|
||||
#include <memory>
|
||||
namespace fl {
|
||||
namespace Log {
|
||||
using std::shared_ptr;
|
||||
} // namespace Log
|
||||
}
|
||||
#elif defined(_MSC_VER) && (_MSC_VER >= 1500)
|
||||
// Visual Studio 2008 : beware, TR1 is provided with the Service Pack 1 only !
|
||||
#include <memory>
|
||||
namespace fl {
|
||||
namespace Log {
|
||||
using std::tr1:shared_ptr;
|
||||
} // namespace Log
|
||||
}
|
||||
#else
|
||||
|
||||
|
||||
#include <cstddef> // NULL
|
||||
#include <algorithm> // std::swap
|
||||
#include <cassert>
|
||||
|
||||
// can be replaced by other error mechanism
|
||||
#define SHARED_ASSERT(x) assert(x)
|
||||
namespace fl {
|
||||
namespace Log {
|
||||
|
||||
/**
|
||||
* @brief minimal implementation of smart pointer, a subset of the C++11 std::shared_ptr or boost::shared_ptr.
|
||||
*
|
||||
* shared_ptr is a smart pointer retaining ownership of an object through a provided pointer,
|
||||
* and sharing this ownership with a reference counter.
|
||||
* It destroys the object when the last shared pointer pointing to it is destroyed or reset.
|
||||
*/
|
||||
template<class T>
|
||||
class shared_ptr
|
||||
{
|
||||
public:
|
||||
/// The type of the managed object, aliased as member type
|
||||
typedef T element_type;
|
||||
|
||||
/// @brief Default constructor
|
||||
shared_ptr(void) throw() : // never throws
|
||||
px(NULL),
|
||||
pn(NULL)
|
||||
{
|
||||
}
|
||||
/// @brief Constructor with the provided pointer to manage
|
||||
explicit shared_ptr(T* p) : // may throw std::bad_alloc
|
||||
//px(p), would be unsafe as acquire() may throw, which would call release() in destructor
|
||||
pn(NULL)
|
||||
{
|
||||
acquire(p); // may throw std::bad_alloc
|
||||
}
|
||||
/// @brief Constructor to share ownership. Warning : to be used for pointer_cast only ! (does not manage two separate <T> and <U> pointers)
|
||||
template <class U>
|
||||
shared_ptr(const shared_ptr<U>& ptr, T* p) :
|
||||
//px(p), would be unsafe as acquire() may throw, which would call release() in destructor
|
||||
pn(ptr.pn)
|
||||
{
|
||||
acquire(p); // may throw std::bad_alloc
|
||||
}
|
||||
/// @brief Copy constructor to convert from another pointer type
|
||||
template <class U>
|
||||
shared_ptr(const shared_ptr<U>& ptr) throw() : // never throws (see comment below)
|
||||
//px(ptr.px),
|
||||
pn(ptr.pn)
|
||||
{
|
||||
SHARED_ASSERT((NULL == ptr.px) || (NULL != ptr.pn)); // must be cohérent : no allocation allowed in this path
|
||||
acquire(static_cast<typename shared_ptr<T>::element_type*>(ptr.px)); // will never throw std::bad_alloc
|
||||
}
|
||||
/// @brief Copy constructor (used by the copy-and-swap idiom)
|
||||
shared_ptr(const shared_ptr& ptr) throw() : // never throws (see comment below)
|
||||
//px(ptr.px),
|
||||
pn(ptr.pn)
|
||||
{
|
||||
SHARED_ASSERT((NULL == ptr.px) || (NULL != ptr.pn)); // must be cohérent : no allocation allowed in this path
|
||||
acquire(ptr.px); // will never throw std::bad_alloc
|
||||
}
|
||||
/// @brief Assignment operator using the copy-and-swap idiom (copy constructor and swap method)
|
||||
shared_ptr& operator=(shared_ptr ptr) throw() // never throws
|
||||
{
|
||||
swap(ptr);
|
||||
return *this;
|
||||
}
|
||||
/// @brief the destructor releases its ownership
|
||||
inline ~shared_ptr(void) throw() // never throws
|
||||
{
|
||||
release();
|
||||
}
|
||||
/// @brief this reset releases its ownership
|
||||
inline void reset(void) throw() // never throws
|
||||
{
|
||||
release();
|
||||
}
|
||||
/// @brief this reset release its ownership and re-acquire another one
|
||||
void reset(T* p) throw() // may throw std::bad_alloc
|
||||
{
|
||||
SHARED_ASSERT((NULL == p) || (px != p)); // auto-reset not allowed
|
||||
release();
|
||||
acquire(p); // may throw std::bad_alloc
|
||||
}
|
||||
|
||||
/// @brief Swap method for the copy-and-swap idiom (copy constructor and swap method)
|
||||
void swap(shared_ptr& lhs) throw() // never throws
|
||||
{
|
||||
// Would be nice to enable use of ustl::swap by define
|
||||
std::swap(px, lhs.px);
|
||||
std::swap(pn, lhs.pn);
|
||||
}
|
||||
|
||||
// reference counter operations :
|
||||
inline operator bool() const throw() // never throws
|
||||
{
|
||||
return (0 < use_count());
|
||||
}
|
||||
inline bool unique(void) const throw() // never throws
|
||||
{
|
||||
return (1 == use_count());
|
||||
}
|
||||
long use_count(void) const throw() // never throws
|
||||
{
|
||||
long count = 0;
|
||||
if (NULL != pn)
|
||||
{
|
||||
count = *pn;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
// underlying pointer operations :
|
||||
inline T& operator*() const throw() // never throws
|
||||
{
|
||||
SHARED_ASSERT(NULL != px);
|
||||
return *px;
|
||||
}
|
||||
inline T* operator->() const throw() // never throws
|
||||
{
|
||||
SHARED_ASSERT(NULL != px);
|
||||
return px;
|
||||
}
|
||||
inline T* get(void) const throw() // never throws
|
||||
{
|
||||
// no assert, car return NULL
|
||||
return px;
|
||||
}
|
||||
|
||||
private:
|
||||
/// @brief acquire/share the ownership of the px pointer, initializing the reference counter
|
||||
void acquire(T* p) // may throw std::bad_alloc
|
||||
{
|
||||
if (NULL != p)
|
||||
{
|
||||
if (NULL == pn)
|
||||
{
|
||||
try
|
||||
{
|
||||
pn = new long(1); // may throw std::bad_alloc
|
||||
}
|
||||
catch (std::bad_alloc&)
|
||||
{
|
||||
delete p;
|
||||
throw; // rethrow the std::bad_alloc
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
++(*pn);
|
||||
}
|
||||
}
|
||||
// here it is safe to acquire the ownership of the provided raw pointer, where exception cannot be thrown any more
|
||||
px = p;
|
||||
}
|
||||
|
||||
/// @brief release the ownership of the px pointer, destroying the object when appropriate
|
||||
void release(void) throw() // never throws
|
||||
{
|
||||
if (NULL != pn)
|
||||
{
|
||||
--(*pn);
|
||||
if (0 == *pn)
|
||||
{
|
||||
delete px;
|
||||
delete pn;
|
||||
}
|
||||
px = NULL;
|
||||
pn = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// This allow pointer_cast functions to share the reference counter between different shared_ptr types
|
||||
template<class U>
|
||||
friend class shared_ptr;
|
||||
|
||||
private:
|
||||
T* px; //!< Native pointer
|
||||
long* pn; //!< Reference counter
|
||||
};
|
||||
|
||||
|
||||
// comparaison operators
|
||||
template<class T, class U> inline bool operator==(const shared_ptr<T>& l, const shared_ptr<U>& r) throw() // never throws
|
||||
{
|
||||
return (l.get() == r.get());
|
||||
}
|
||||
template<class T, class U> inline bool operator!=(const shared_ptr<T>& l, const shared_ptr<U>& r) throw() // never throws
|
||||
{
|
||||
return (l.get() != r.get());
|
||||
}
|
||||
template<class T, class U> inline bool operator<=(const shared_ptr<T>& l, const shared_ptr<U>& r) throw() // never throws
|
||||
{
|
||||
return (l.get() <= r.get());
|
||||
}
|
||||
template<class T, class U> inline bool operator<(const shared_ptr<T>& l, const shared_ptr<U>& r) throw() // never throws
|
||||
{
|
||||
return (l.get() < r.get());
|
||||
}
|
||||
template<class T, class U> inline bool operator>=(const shared_ptr<T>& l, const shared_ptr<U>& r) throw() // never throws
|
||||
{
|
||||
return (l.get() >= r.get());
|
||||
}
|
||||
template<class T, class U> inline bool operator>(const shared_ptr<T>& l, const shared_ptr<U>& r) throw() // never throws
|
||||
{
|
||||
return (l.get() > r.get());
|
||||
}
|
||||
|
||||
|
||||
|
||||
// static cast of shared_ptr
|
||||
template<class T, class U>
|
||||
shared_ptr<T> static_pointer_cast(const shared_ptr<U>& ptr) // never throws
|
||||
{
|
||||
return shared_ptr<T>(ptr, static_cast<typename shared_ptr<T>::element_type*>(ptr.get()));
|
||||
}
|
||||
|
||||
// dynamic cast of shared_ptr
|
||||
template<class T, class U>
|
||||
shared_ptr<T> dynamic_pointer_cast(const shared_ptr<U>& ptr) // never throws
|
||||
{
|
||||
T* p = dynamic_cast<typename shared_ptr<T>::element_type*>(ptr.get());
|
||||
if (NULL != p)
|
||||
{
|
||||
return shared_ptr<T>(ptr, p);
|
||||
}
|
||||
else
|
||||
{
|
||||
return shared_ptr<T>();
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace Log
|
||||
|
||||
#endif
|
|
@ -78,7 +78,7 @@ int cmd_save(struct cli_def *cli, const char *command, char *argv[], int argc)
|
|||
boost::unique_lock<boost::mutex> scoped_lock(lmbctx->io_mutex);
|
||||
lmbctx->save("/etc/LMBd.conf");
|
||||
cli_print(cli, "Saved Config");
|
||||
BOOST_LOG_TRIVIAL(info) << "Saved Config From Terminal";
|
||||
LMB_LOG_INFO() << "Saved Config From Terminal";
|
||||
return CLI_OK;
|
||||
}
|
||||
|
||||
|
@ -166,7 +166,7 @@ int cmd_set_port(struct cli_def *cli, UNUSED(const char *command), char *argv[],
|
|||
boost::unique_lock<boost::mutex> scoped_lock(lmbctx->io_mutex);
|
||||
|
||||
lmbctx->port = pii->port;
|
||||
BOOST_LOG_TRIVIAL(info) << "Set a New Serial Port from Terminal: " << lmbctx->port;
|
||||
LMB_LOG_INFO() << "Set a New Serial Port from Terminal: " << lmbctx->port;
|
||||
return CLI_OK;
|
||||
}
|
||||
}
|
||||
|
@ -290,9 +290,9 @@ int Startcliloop(LMBCTX *lmbctx, int sockfd) {
|
|||
|
||||
|
||||
cli_set_context(cli, (void*)lmbctx);
|
||||
BOOST_LOG_TRIVIAL(info) << "accepted new CLI Connection";
|
||||
LMB_LOG_INFO() << "accepted new CLI Connection";
|
||||
cli_loop(cli, sockfd);
|
||||
BOOST_LOG_TRIVIAL(info) << "closed CLI Connection";
|
||||
LMB_LOG_INFO() << "closed CLI Connection";
|
||||
cli_done(cli);
|
||||
return 0;
|
||||
}
|
||||
|
|
29
src/lmbd.cpp
29
src/lmbd.cpp
|
@ -25,6 +25,7 @@
|
|||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <cstdio>
|
||||
#include <sys/types.h>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
@ -51,7 +52,7 @@
|
|||
|
||||
#define CLITEST_PORT 8000
|
||||
|
||||
|
||||
LMB::Log::Logger *logger = NULL;
|
||||
|
||||
|
||||
int main()
|
||||
|
@ -71,10 +72,10 @@ int main()
|
|||
}
|
||||
#endif
|
||||
|
||||
boost::log::core::get()->set_filter
|
||||
(
|
||||
boost::log::trivial::severity >= boost::log::trivial::info
|
||||
);
|
||||
LMB::Log::Manager::setDefaultLevel(LMB::Log::Log::eInfo);
|
||||
|
||||
|
||||
logger = new LMB::Log::Logger("LMBd");
|
||||
|
||||
|
||||
struct LMBCTX *lmbctx = new LMBCTX;
|
||||
|
@ -94,10 +95,14 @@ int main()
|
|||
|
||||
try {
|
||||
lmbctx->load("/etc/LMBd.conf");
|
||||
} catch (...) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Could Not Load Config File";
|
||||
} catch (std::exception& e) {
|
||||
std::cerr << "Could Not Load Config File " << e.what() << std::endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
LMB::Log::Manager::configure(lmbctx->configList);
|
||||
|
||||
|
||||
lmbctx->driver->Init(lmbctx);
|
||||
lmbctx->driver->StartUp();
|
||||
lmbctx->driver->Fini();
|
||||
|
@ -118,7 +123,7 @@ int main()
|
|||
|
||||
if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(error) << "Socket Error";
|
||||
LMB_LOG_ERROR() << "Socket Error";
|
||||
return 1;
|
||||
}
|
||||
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
|
||||
|
@ -129,23 +134,23 @@ int main()
|
|||
addr.sin_port = htons(CLITEST_PORT);
|
||||
if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(error) << "bind Error";
|
||||
LMB_LOG_ERROR() << "bind Error";
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (listen(s, 50) < 0)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(error) << "listen Error";
|
||||
LMB_LOG_ERROR() << "listen Error";
|
||||
return 1;
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << "Listening on port " << CLITEST_PORT;
|
||||
LMB_LOG_INFO() << "Listening on port " << CLITEST_PORT;
|
||||
while ((x = accept(s, NULL, 0)))
|
||||
{
|
||||
if (lmbctx->Clients.size() < lmbctx->max_cli) {
|
||||
lmbctx->Clients.push_back(boost::make_shared<boost::thread>(Startcliloop, boost::ref(lmbctx), x));
|
||||
} else {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Dropping Client Connection as we are at our Max";
|
||||
LMB_LOG_WARN() << "Dropping Client Connection as we are at our Max";
|
||||
close(x);
|
||||
}
|
||||
}
|
||||
|
|
28
src/lmbd.hpp
28
src/lmbd.hpp
|
@ -29,9 +29,6 @@
|
|||
#ifndef SRC_LMBD_HPP_
|
||||
#define SRC_LMBD_HPP_
|
||||
#include <boost/make_shared.hpp>
|
||||
#include <boost/log/core.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/log/expressions.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
|
@ -40,11 +37,24 @@
|
|||
#include <boost/dynamic_bitset.hpp>
|
||||
#include "serial/serial.h"
|
||||
#include "libcli/libcli.h"
|
||||
#include "LoggerCpp/LoggerCpp.h"
|
||||
|
||||
class iDriver;
|
||||
|
||||
|
||||
|
||||
|
||||
#define LMB_LOG_DEBUG() logger->debug()
|
||||
#define LMB_LOG_INFO() logger->info()
|
||||
#define LMB_LOG_WARN() logger->warning()
|
||||
#define LMB_LOG_ERROR() logger->error()
|
||||
|
||||
|
||||
extern LMB::Log::Logger *logger;
|
||||
|
||||
|
||||
struct LMBCTX {
|
||||
LMB::Log::Config::Vector configList;
|
||||
serial::Serial *sp;
|
||||
boost::mutex io_mutex;
|
||||
std::string port;
|
||||
|
@ -61,6 +71,7 @@ struct LMBCTX {
|
|||
std::map<int, std::string> startupmsg;
|
||||
std::vector<boost::shared_ptr<boost::thread> > Clients;
|
||||
unsigned int max_cli;
|
||||
bool consolelog;
|
||||
void load(const std::string &filename)
|
||||
{
|
||||
// Create empty property tree object
|
||||
|
@ -75,11 +86,16 @@ struct LMBCTX {
|
|||
|
||||
// Use the default-value version of get to find the debug level.
|
||||
// Note that the default value is used to deduce the target type.
|
||||
debug_level = tree.get("debug.level", 0);
|
||||
username = tree.get<std::string>("username");
|
||||
password = tree.get<std::string>("password");
|
||||
enablepass = tree.get<std::string>("enablepass");
|
||||
monitorpath = tree.get<std::string>("monitorpath");
|
||||
if (tree.get<bool>("ConsoleLogging") == true) {
|
||||
LMB::Log::Config::addOutput(configList, "OutputConsole");
|
||||
consolelog = true;
|
||||
}
|
||||
logger->setLevel(LMB::Log::Log::toLevel(tree.get<std::string>("ConsoleLogLevel").c_str()));
|
||||
|
||||
for (unsigned int i = 1; i <= this->messages; i++) {
|
||||
std::stringstream ss;
|
||||
ss << "startupmessage." << std::dec << i;
|
||||
|
@ -98,12 +114,12 @@ struct LMBCTX {
|
|||
// converted to a string. Note that the "debug" node is automatically
|
||||
// created if it doesn't exist.
|
||||
tree.put("serial.port", port);
|
||||
tree.put("debug.level", debug_level);
|
||||
tree.put("username", username);
|
||||
tree.put("password", password);
|
||||
tree.put("enablepass", enablepass);
|
||||
tree.put("monitorpath", monitorpath);
|
||||
|
||||
tree.put("ConsoleLogging", consolelog);
|
||||
tree.put("ConsoleLogLevel", LMB::Log::Log::toString(logger->getLevel()));
|
||||
for (unsigned int i = 1; i <= this->messages; i++) {
|
||||
std::stringstream ss;
|
||||
ss << "startupmessage." << std::dec << i;
|
||||
|
|
Loading…
Add table
Reference in a new issue