use new LoggerCPP library instead of boost::log

This commit is contained in:
Justin Hammond 2015-10-19 23:51:19 +08:00
parent ee8bf4a48a
commit 848daf5b19
33 changed files with 2332 additions and 55 deletions

View file

@ -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})

View file

@ -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": ""

View file

@ -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;
}

View file

@ -31,6 +31,7 @@
#include "lmbd.hpp"
class iDriver {
public:
iDriver() {}

View file

@ -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
View 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
View 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
View 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

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

View 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.

View file

@ -0,0 +1,138 @@
LoggerC++
---------
![LoggerC++ build status](https://api.travis-ci.org/SRombauts/LoggerCpp.png "LoggerC++ build status")
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
View 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
View 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
View 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
View 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

View 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

View 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

View 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

View 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

View 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

View 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
View 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

View 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

View file

@ -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;
}

View file

@ -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);
}
}

View file

@ -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;