build LoggerCpp into FL Sources

This commit is contained in:
Justin Hammond 2015-01-12 23:05:57 +08:00
parent 9b11338dce
commit ee1a7fee77
50 changed files with 1903 additions and 4049 deletions

View file

@ -77,7 +77,7 @@ if(NOT FL_BACKTRACE)
endif() endif()
include_directories(.) include_directories(.)
include_directories ("${PROJECT_SOURCE_DIR}/LoggerCpp/include/") include_directories ("${PROJECT_SOURCE_DIR}/fl/")
add_definitions (-std=c++0x) # -std=c++11 add_definitions (-std=c++0x) # -std=c++11
file(STRINGS FL_HEADERS fl-headers) file(STRINGS FL_HEADERS fl-headers)
@ -91,29 +91,29 @@ message("${exepath}")
# add sources of the logger library as a "LoggerCpp" library # add sources of the logger library as a "LoggerCpp" library
add_library (LoggerCpp STATIC add_library (LoggerCpp STATIC
LoggerCpp/include/LoggerCpp/Channel.h fl/LoggerCpp/Channel.h
LoggerCpp/include/LoggerCpp/Config.h fl/LoggerCpp/Config.h
LoggerCpp/include/LoggerCpp/DateTime.h fl/LoggerCpp/DateTime.h
LoggerCpp/include/LoggerCpp/Exception.h fl/LoggerCpp/Exception.h
LoggerCpp/include/LoggerCpp/Formatter.h fl/LoggerCpp/Formatter.h
LoggerCpp/include/LoggerCpp/Log.h fl/LoggerCpp/Log.h
LoggerCpp/include/LoggerCpp/Logger.h fl/LoggerCpp/Logger.h
LoggerCpp/include/LoggerCpp/LoggerCpp.h fl/LoggerCpp/LoggerCpp.h
LoggerCpp/include/LoggerCpp/Manager.h fl/LoggerCpp/Manager.h
LoggerCpp/include/LoggerCpp/Output.h fl/LoggerCpp/Output.h
LoggerCpp/include/LoggerCpp/OutputConsole.h fl/LoggerCpp/OutputConsole.h
LoggerCpp/include/LoggerCpp/OutputDebug.h fl/LoggerCpp/OutputDebug.h
LoggerCpp/include/LoggerCpp/OutputFile.h fl/LoggerCpp/OutputFile.h
LoggerCpp/include/LoggerCpp/shared_ptr.hpp fl/LoggerCpp/shared_ptr.hpp
LoggerCpp/include/LoggerCpp/Utils.h fl/LoggerCpp/Utils.h
LoggerCpp/src/Config.cpp src/LoggerCpp/Config.cpp
LoggerCpp/src/DateTime.cpp src/LoggerCpp/DateTime.cpp
LoggerCpp/src/Log.cpp src/LoggerCpp/Log.cpp
LoggerCpp/src/Logger.cpp src/LoggerCpp/Logger.cpp
LoggerCpp/src/Manager.cpp src/LoggerCpp/Manager.cpp
LoggerCpp/src/OutputConsole.cpp src/LoggerCpp/OutputConsole.cpp
LoggerCpp/src/OutputDebug.cpp src/LoggerCpp/OutputDebug.cpp
LoggerCpp/src/OutputFile.cpp src/LoggerCpp/OutputFile.cpp
) )
#set_target_properties(LoggerCpp PROPERTIES COMPILE_FLAGS -fvisibility=hidden) #set_target_properties(LoggerCpp PROPERTIES COMPILE_FLAGS -fvisibility=hidden)
@ -144,7 +144,7 @@ install(TARGETS fl-bin fl-shared
) )
install(DIRECTORY fl/ DESTINATION include/fl) install(DIRECTORY fl/ DESTINATION include/fl)
install(DIRECTORY LoggerCpp/include/LoggerCpp DESTINATION include) #install(DIRECTORY DESTINATION include)
#if(WIN32) #if(WIN32)
# set(fl-suffix) # set(fl-suffix)

27
LoggerCpp/.gitignore vendored
View file

@ -1,27 +0,0 @@
Debug
Release
build
lib
doc
CMakeCache.txt
CMakeFiles
*.cmake
*.dir
*.sln
*.vcproj*
*.vcxproj*
*.ncb
*.suo
*.user
*sdf
*ipch
*.make
Makefile
.settings
*~
log*.txt
core

View file

@ -1,106 +0,0 @@
# 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)
cmake_minimum_required(VERSION 2.6)
project(LoggerCpp)
# Define useful variables to handle OS/Compiler differences
if (MSVC)
set(CPPLINT_ARG_OUTPUT "--output=vs7")
set(CPPCHECK_ARG_TEMPLATE "--template=vs")
set(DEV_NULL "NUL")
set(SYSTEM_LIBRARIES "")
add_definitions (/D_CRT_SECURE_NO_WARNINGS)
else()
set(CPPLINT_ARG_OUTPUT "--output=eclipse")
set(CPPCHECK_ARG_TEMPLATE "--template=gcc")
set(DEV_NULL "/dev/null")
set(SYSTEM_LIBRARIES "rt")
add_definitions (-std=c++0x) # -std=c++11
endif()
set(CPPLINT_ARG_VERBOSE "--verbose=3")
set(CPPLINT_ARG_LINELENGTH "--linelength=120")
# All includes are relative to the "include" directory
include_directories ("${PROJECT_SOURCE_DIR}/include")
# add sources of the logger library as a "LoggerCpp" library
add_library (LoggerCpp
include/LoggerCpp/Channel.h
include/LoggerCpp/Config.h
include/LoggerCpp/DateTime.h
include/LoggerCpp/Exception.h
include/LoggerCpp/Formatter.h
include/LoggerCpp/Log.h
include/LoggerCpp/Logger.h
include/LoggerCpp/LoggerCpp.h
include/LoggerCpp/Manager.h
include/LoggerCpp/Output.h
include/LoggerCpp/OutputConsole.h
include/LoggerCpp/OutputDebug.h
include/LoggerCpp/OutputFile.h
include/LoggerCpp/shared_ptr.hpp
include/LoggerCpp/Utils.h
src/Config.cpp
src/DateTime.cpp
src/Log.cpp
src/Logger.cpp
src/Manager.cpp
src/OutputConsole.cpp
src/OutputDebug.cpp
src/OutputFile.cpp
)
# Optional additional targets:
option(LOGGERCPP_BUILD_EXAMPLE "Build the example of LoggerCpp." ON)
if (LOGGERCPP_BUILD_EXAMPLE)
# add the example executable, linked with the LoggerCpp library
add_executable(LoggerCpp_Example examples/Main.cpp)
target_link_libraries (LoggerCpp_Example LoggerCpp ${SYSTEM_LIBRARIES})
endif ()
option(LOGGERCPP_RUN_CPPLINT "Run cpplint.py tool for Google C++ StyleGuide." ON)
if (LOGGERCPP_RUN_CPPLINT)
# List all sources/headers files for cpplint:
# adding a file still require explicittly modifing the CMakeLists.txt
# so that CMake know that it should rebuild the project (it is best practice)
file(GLOB all_source_files
"${PROJECT_SOURCE_DIR}/include/LoggerCpp/*.h"
"${PROJECT_SOURCE_DIR}/src/*.cpp"
)
# add a cpplint target to the "all" target
add_custom_target(LoggerCpp_cpplint
ALL
COMMAND python cpplint.py ${CPPLINT_ARG_OUTPUT} ${CPPLINT_ARG_VERBOSE} ${all_source_files}
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
)
endif()
option(LOGGERCPP_RUN_CPPCHECK "Run cppcheck C++ static analysis tool." ON)
if (LOGGERCPP_RUN_CPPCHECK)
# add a cppcheck target to the "all" target
add_custom_target(LoggerCpp_cppcheck
ALL
COMMAND cppcheck -j 4 cppcheck --enable=style --quiet ${CPPCHECK_ARG_TEMPLATE} ${PROJECT_SOURCE_DIR}/src
)
endif()
if (NOT DEFINED ENV{TRAVIS})
option(LOGGERCPP_RUN_DOXYGEN "Run Doxygen C++ documentation tool." ON)
if (LOGGERCPP_RUN_DOXYGEN)
# add a Doxygen target to the "all" target
add_custom_target(LoggerCpp_doxygen
ALL
COMMAND doxygen Doxyfile > ${DEV_NULL}
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
)
endif()
else()
# but no Doxygen under Travis CI: too costly and no real benefit
message("no Doxygen target when TRAVIS is defined")
endif()

File diff suppressed because it is too large Load diff

View file

@ -1,21 +0,0 @@
Update shared_ptr to tag v1.0
test
Github Pages
Release
Manager: configure channels
Add a basic thread-safety security (throw if multiple threads create Loggers)
- Add a static Thread::getCurrentId()
Searching for a more compact or standard output format
- XML
- HTML
- json
- db3
- no SQL
- google protocol buffer
- message pack

View file

@ -1,147 +0,0 @@
/**
* @file Main.cpp
* @brief Example program for the simple LoggerC++ system
*
* 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/LoggerCpp.h"
#include <iostream>
/**
* @brief Simple test class
*/
class Tester {
public:
Tester() :
mLogger("main.Tester")
{
}
void constTest (void) const {
mLogger.debug() << "log within a const method";
}
private:
Log::Logger mLogger; ///< A named logger to produce log
};
/**
* @brief Simple example program
*/
int main ()
{
// Configure the default severity Level of new Channel objects
#ifndef NDEBUG
Log::Manager::setDefaultLevel(Log::Log::eDebug);
#else
Log::Manager::setDefaultLevel(Log::Log::eNotice);
#endif
int val;
if (false)
{
val = 2;
}
if (true)
{
// TODO SRombauts : testing
int* p = new int(2);
}
// Configure 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, "filename_old", "log.old.txt");
Log::Config::setOption(configList, "max_startup_size", "0");
Log::Config::setOption(configList, "max_size", "10000");
#ifdef WIN32
Log::Config::addOutput(configList, "OutputDebug");
#endif
// Create a Logger object, using a "Main.Example" Channel
Log::Logger logger("Main.Example");
logger.warning() << "NO logs before configure()";
try
{
// Configure the Log Manager (create the Output objects)
//Log::Manager::configure(configList);
std::cout << "Configure" << std::endl;
}
catch (std::exception& e)
{
std::cerr << e.what();
}
// 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";
logger.debug() << "sizeof(logger)=" << sizeof(logger);
// 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);
// Create other loggers, sharing the "Main.Example" Channel, and creating a new one
Log::Logger logger2("Main.Example");
Log::Logger logger3("Main.Other");
logger.debug() << "First logger to the Channel";
logger2.debug() << "Second logger to the Channel";
logger3.debug() << "Third logger, other Channel";
// Modify the Level of the "Main.example" channel by its name
Log::Manager::get("Main.Example")->setLevel(Log::Log::eInfo);
logger.debug() << "first logger inhibited"; // NO more debug logs for this logger
logger2.debug() << "second logger also disabled"; // NO more debug logs (sharing the same underlying channel)
logger3.debug() << "third logger still active";
// Reset the Level of the "Main.example" channel by its name
Log::Manager::get("Main.Example")->setLevel(Log::Log::eDebug);
logger.debug() << "first logger re-activated";
logger2.debug() << "second logger also re-activated";
logger3.debug() << "third logger always active";
// Create an object using a Logger as member variable
Tester tester;
tester.constTest();
// Show how to get the current Channel configuration (to save it to a file, for instance)
Log::Manager::get("Main.OtherChannel")->setLevel(Log::Log::eNotice);
Log::Config::Ptr ChannelConfigPtr = Log::Manager::getChannelConfig();
// Show how to set the current Channel configuration (restored from a file, for instance)
Log::Manager::setChannelConfig(ChannelConfigPtr);
// Terminate the Log Manager (destroy the Output objects)
Log::Manager::terminate();
logger.warning() << "NO more logs after terminate()";
return 0;
}

View file

@ -1,87 +0,0 @@
/**
* @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 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

View file

@ -1,123 +0,0 @@
/**
* @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 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

@ -1,48 +0,0 @@
/**
* @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 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

View file

@ -1,67 +0,0 @@
/**
* @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 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

View file

@ -1,134 +0,0 @@
/**
* @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 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

View file

@ -1,91 +0,0 @@
/**
* @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>
/**
* @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

@ -1,102 +0,0 @@
/**
* @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 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

View file

@ -1,62 +0,0 @@
/**
* @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 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

@ -1,42 +0,0 @@
/**
* @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 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

@ -1,84 +0,0 @@
/**
* @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 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

View file

@ -1,305 +0,0 @@
/**
* @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 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 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 Log {
using std::tr1::shared_ptr;
} // namespace Log
#elif defined(__clang__) && __has_feature(cxx_nullptr)
// Clang 2.9 and above ?
#include <memory>
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 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 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 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

@ -1,65 +0,0 @@
/**
* @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 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

View file

@ -1,69 +0,0 @@
/**
* @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 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

View file

@ -1,75 +0,0 @@
/**
* @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 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

View file

@ -1,61 +0,0 @@
/**
* @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 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

View file

@ -1,140 +0,0 @@
/**
* @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 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

View file

@ -1,94 +0,0 @@
/**
* @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 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

@ -1,49 +0,0 @@
/**
* @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 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

@ -1,101 +0,0 @@
/**
* @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 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

89
fl/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 fl {
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

125
fl/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 fl {
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

50
fl/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 fl {
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

View file

@ -29,38 +29,40 @@
#pragma warning(disable:4290) #pragma warning(disable:4290)
#endif #endif
namespace fl {
namespace Log { namespace Log {
/** /**
* @brief Encapsulation of an error message based on std::runtime_error. * @brief Encapsulation of an error message based on std::runtime_error.
* @ingroup LoggerCpp * @ingroup LoggerCpp
*/ */
class Exception : public std::runtime_error { class Exception : public std::runtime_error {
public: public:
/** /**
* @brief Encapsulation of an error message based on std::runtime_error. * @brief Encapsulation of an error message based on std::runtime_error.
* *
* @param[in] aErrorMessage The string message describing the error * @param[in] aErrorMessage The string message describing the error
*/ */
explicit Exception(const std::string& aErrorMessage) : explicit Exception(const std::string& aErrorMessage) :
std::runtime_error(aErrorMessage) std::runtime_error(aErrorMessage)
{} {}
}; };
/// @brief Stringify 1/2 : convert an integer to a string (using the following macro) /// @brief Stringify 1/2 : convert an integer to a string (using the following macro)
#define TOSTRING(x) _XSTRING(x) #define TOSTRING(x) _XSTRING(x)
/// @brief Stringify 2/2 : convert an integer to a string (inner macro) /// @brief Stringify 2/2 : convert an integer to a string (inner macro)
#define _XSTRING(x) #x #define _XSTRING(x) #x
#ifdef __FUNCTION__ #ifdef __FUNCTION__
/// @brief Define __func__ under Windows, to use the same name as with GCC /// @brief Define __func__ under Windows, to use the same name as with GCC
#define __func__ __FUNCTION__ #define __func__ __FUNCTION__
#endif #endif
/// @brief Helper macro to throw an Exception with file/line/function information, using the string stream Formatter /// @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) #define LOGGER_THROW(x) throw Exception(Formatter() << __FILE__ << ":" << TOSTRING(__LINE__) << ": " << __func__ << "(): " << x)
}
} // namespace Log } // namespace Log

69
fl/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 fl {
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

135
fl/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 fl {
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

93
fl/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 fl {
/**
* @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

104
fl/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 fl {
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

View file

@ -21,41 +21,41 @@
// and imports the "shared_ptr" symbol inside the Log namespace (ie. Log::shared_ptr) // and imports the "shared_ptr" symbol inside the Log namespace (ie. Log::shared_ptr)
#include "LoggerCpp/shared_ptr.hpp" #include "LoggerCpp/shared_ptr.hpp"
namespace fl {
namespace Log { namespace Log {
// Forward declaration // Forward declaration
class Log; class Log;
/** /**
* @brief Interface of an Output * @brief Interface of an Output
* @ingroup LoggerCpp * @ingroup LoggerCpp
*/ */
class Output { class Output {
public: public:
/// @brief Virtual destructor /// @brief Virtual destructor
virtual ~Output() {} virtual ~Output() {}
public: public:
/// @brief Shared Pointer to an Output /// @brief Shared Pointer to an Output
typedef shared_ptr<Output> Ptr; typedef shared_ptr<Output> Ptr;
/// @brief List of Output objects /// @brief List of Output objects
typedef std::vector<Ptr> Vector; typedef std::vector<Ptr> Vector;
/** /**
* @brief Output the Log * @brief Output the Log
* *
* @param[in] aChannelPtr The underlying Channel of the Log * @param[in] aChannelPtr The underlying Channel of the Log
* @param[in] aLog The Log to output * @param[in] aLog The Log to output
*/ */
virtual void output(const Channel::Ptr& aChannelPtr, const Log& aLog) const = 0; 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();
}
};
/// @brief Return the type name of the Output object
inline const char* name() const {
return typeid(this).name();
}
};
}
} // namespace Log } // 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 fl {
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,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 fl {
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

84
fl/LoggerCpp/OutputFile.h Normal file
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 fl {
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

317
fl/LoggerCpp/shared_ptr.hpp Normal file
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 fl {
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

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 fl {
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

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 fl {
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

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 fl {
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

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 fl {
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

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 fl {
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

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 fl {
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,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 fl {
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,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 fl {
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