mirror of
https://github.com/Fishwaldo/Fuzzylite.git
synced 2025-03-15 11:21:36 +00:00
build LoggerCpp into FL Sources
This commit is contained in:
parent
9b11338dce
commit
ee1a7fee77
50 changed files with 1903 additions and 4049 deletions
|
@ -77,7 +77,7 @@ if(NOT FL_BACKTRACE)
|
|||
endif()
|
||||
|
||||
include_directories(.)
|
||||
include_directories ("${PROJECT_SOURCE_DIR}/LoggerCpp/include/")
|
||||
include_directories ("${PROJECT_SOURCE_DIR}/fl/")
|
||||
add_definitions (-std=c++0x) # -std=c++11
|
||||
|
||||
file(STRINGS FL_HEADERS fl-headers)
|
||||
|
@ -91,29 +91,29 @@ message("${exepath}")
|
|||
|
||||
# add sources of the logger library as a "LoggerCpp" library
|
||||
add_library (LoggerCpp STATIC
|
||||
LoggerCpp/include/LoggerCpp/Channel.h
|
||||
LoggerCpp/include/LoggerCpp/Config.h
|
||||
LoggerCpp/include/LoggerCpp/DateTime.h
|
||||
LoggerCpp/include/LoggerCpp/Exception.h
|
||||
LoggerCpp/include/LoggerCpp/Formatter.h
|
||||
LoggerCpp/include/LoggerCpp/Log.h
|
||||
LoggerCpp/include/LoggerCpp/Logger.h
|
||||
LoggerCpp/include/LoggerCpp/LoggerCpp.h
|
||||
LoggerCpp/include/LoggerCpp/Manager.h
|
||||
LoggerCpp/include/LoggerCpp/Output.h
|
||||
LoggerCpp/include/LoggerCpp/OutputConsole.h
|
||||
LoggerCpp/include/LoggerCpp/OutputDebug.h
|
||||
LoggerCpp/include/LoggerCpp/OutputFile.h
|
||||
LoggerCpp/include/LoggerCpp/shared_ptr.hpp
|
||||
LoggerCpp/include/LoggerCpp/Utils.h
|
||||
LoggerCpp/src/Config.cpp
|
||||
LoggerCpp/src/DateTime.cpp
|
||||
LoggerCpp/src/Log.cpp
|
||||
LoggerCpp/src/Logger.cpp
|
||||
LoggerCpp/src/Manager.cpp
|
||||
LoggerCpp/src/OutputConsole.cpp
|
||||
LoggerCpp/src/OutputDebug.cpp
|
||||
LoggerCpp/src/OutputFile.cpp
|
||||
fl/LoggerCpp/Channel.h
|
||||
fl/LoggerCpp/Config.h
|
||||
fl/LoggerCpp/DateTime.h
|
||||
fl/LoggerCpp/Exception.h
|
||||
fl/LoggerCpp/Formatter.h
|
||||
fl/LoggerCpp/Log.h
|
||||
fl/LoggerCpp/Logger.h
|
||||
fl/LoggerCpp/LoggerCpp.h
|
||||
fl/LoggerCpp/Manager.h
|
||||
fl/LoggerCpp/Output.h
|
||||
fl/LoggerCpp/OutputConsole.h
|
||||
fl/LoggerCpp/OutputDebug.h
|
||||
fl/LoggerCpp/OutputFile.h
|
||||
fl/LoggerCpp/shared_ptr.hpp
|
||||
fl/LoggerCpp/Utils.h
|
||||
src/LoggerCpp/Config.cpp
|
||||
src/LoggerCpp/DateTime.cpp
|
||||
src/LoggerCpp/Log.cpp
|
||||
src/LoggerCpp/Logger.cpp
|
||||
src/LoggerCpp/Manager.cpp
|
||||
src/LoggerCpp/OutputConsole.cpp
|
||||
src/LoggerCpp/OutputDebug.cpp
|
||||
src/LoggerCpp/OutputFile.cpp
|
||||
)
|
||||
#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 LoggerCpp/include/LoggerCpp DESTINATION include)
|
||||
#install(DIRECTORY DESTINATION include)
|
||||
|
||||
#if(WIN32)
|
||||
# set(fl-suffix)
|
||||
|
|
27
LoggerCpp/.gitignore
vendored
27
LoggerCpp/.gitignore
vendored
|
@ -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
|
|
@ -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()
|
1874
LoggerCpp/Doxyfile
1874
LoggerCpp/Doxyfile
File diff suppressed because it is too large
Load diff
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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
89
fl/LoggerCpp/Channel.h
Normal file
|
@ -0,0 +1,89 @@
|
|||
/**
|
||||
* @file Channel.h
|
||||
* @ingroup LoggerCpp
|
||||
* @brief The named channel shared by Logger objects using the same name
|
||||
*
|
||||
* Copyright (c) 2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "LoggerCpp/Log.h"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
// The following includes "boost/shared_ptr.hpp" if LOGGER_USE_BOOST_SHARED_PTR is defined,
|
||||
// or <memory> (or <tr1/memory>) when C++11 (or experimental C++0x) is available,
|
||||
// or a custom minimal shared_ptr implementation,
|
||||
// and imports the "shared_ptr" symbol inside the Log namespace (ie. Log::shared_ptr)
|
||||
#include "LoggerCpp/shared_ptr.hpp"
|
||||
|
||||
namespace 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
125
fl/LoggerCpp/Config.h
Normal file
|
@ -0,0 +1,125 @@
|
|||
/**
|
||||
* @file Config.h
|
||||
* @ingroup LoggerCpp
|
||||
* @brief Configuration for an Output object
|
||||
*
|
||||
* Copyright (c) 2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
// The following includes "boost/shared_ptr.hpp" if LOGGER_USE_BOOST_SHARED_PTR is defined,
|
||||
// or <memory> (or <tr1/memory>) when C++11 (or experimental C++0x) is available,
|
||||
// or a custom minimal shared_ptr implementation,
|
||||
// and imports the "shared_ptr" symbol inside the Log namespace (ie. Log::shared_ptr)
|
||||
#include "LoggerCpp/shared_ptr.hpp"
|
||||
|
||||
namespace 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
50
fl/LoggerCpp/DateTime.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
/**
|
||||
* @file DateTime.h
|
||||
* @ingroup LoggerCpp
|
||||
* @brief Current time precise to the millisecond.
|
||||
*
|
||||
* Copyright (c) 2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
namespace 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
|
|
@ -29,38 +29,40 @@
|
|||
#pragma warning(disable:4290)
|
||||
#endif
|
||||
|
||||
namespace fl {
|
||||
|
||||
namespace Log {
|
||||
namespace Log {
|
||||
|
||||
/**
|
||||
* @brief Encapsulation of an error message based on std::runtime_error.
|
||||
* @ingroup LoggerCpp
|
||||
*/
|
||||
class Exception : public std::runtime_error {
|
||||
public:
|
||||
/**
|
||||
* @brief Encapsulation of an error message based on std::runtime_error.
|
||||
*
|
||||
* @param[in] aErrorMessage The string message describing the error
|
||||
*/
|
||||
explicit Exception(const std::string& aErrorMessage) :
|
||||
std::runtime_error(aErrorMessage)
|
||||
{}
|
||||
};
|
||||
/**
|
||||
* @brief Encapsulation of an error message based on std::runtime_error.
|
||||
* @ingroup LoggerCpp
|
||||
*/
|
||||
class Exception : public std::runtime_error {
|
||||
public:
|
||||
/**
|
||||
* @brief Encapsulation of an error message based on std::runtime_error.
|
||||
*
|
||||
* @param[in] aErrorMessage The string message describing the error
|
||||
*/
|
||||
explicit Exception(const std::string& aErrorMessage) :
|
||||
std::runtime_error(aErrorMessage)
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
/// @brief Stringify 1/2 : convert an integer to a string (using the following macro)
|
||||
/// @brief Stringify 1/2 : convert an integer to a string (using the following macro)
|
||||
#define TOSTRING(x) _XSTRING(x)
|
||||
/// @brief Stringify 2/2 : convert an integer to a string (inner macro)
|
||||
/// @brief Stringify 2/2 : convert an integer to a string (inner macro)
|
||||
#define _XSTRING(x) #x
|
||||
|
||||
#ifdef __FUNCTION__
|
||||
/// @brief Define __func__ under Windows, to use the same name as with GCC
|
||||
/// @brief Define __func__ under Windows, to use the same name as with GCC
|
||||
#define __func__ __FUNCTION__
|
||||
#endif
|
||||
|
||||
/// @brief Helper macro to throw an Exception with file/line/function information, using the string stream Formatter
|
||||
/// @brief Helper macro to throw an Exception with file/line/function information, using the string stream Formatter
|
||||
#define LOGGER_THROW(x) throw Exception(Formatter() << __FILE__ << ":" << TOSTRING(__LINE__) << ": " << __func__ << "(): " << x)
|
||||
|
||||
}
|
||||
|
||||
} // namespace Log
|
69
fl/LoggerCpp/Formatter.h
Normal file
69
fl/LoggerCpp/Formatter.h
Normal file
|
@ -0,0 +1,69 @@
|
|||
/**
|
||||
* @file Formatter.h
|
||||
* @ingroup LoggerCpp
|
||||
* @brief A standard string stream formatter with implicit string conversion
|
||||
*
|
||||
* Copyright (c) 2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
namespace 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
135
fl/LoggerCpp/Log.h
Normal file
|
@ -0,0 +1,135 @@
|
|||
/**
|
||||
* @file Log.h
|
||||
* @ingroup LoggerCpp
|
||||
* @brief A RAII (private) log object constructed by the Logger class
|
||||
*
|
||||
* Copyright (c) 2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "LoggerCpp/DateTime.h"
|
||||
#include "LoggerCpp/Utils.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <iomanip> // For easy use of parametric manipulators (setfill, setprecision) by client code
|
||||
|
||||
namespace 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
93
fl/LoggerCpp/Logger.h
Normal file
|
@ -0,0 +1,93 @@
|
|||
/**
|
||||
* @file Logger.h
|
||||
* @ingroup LoggerCpp
|
||||
* @brief A simple thread-safe Logger class
|
||||
*
|
||||
* Copyright (c) 2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "LoggerCpp/Log.h"
|
||||
#include "LoggerCpp/Channel.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace 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
104
fl/LoggerCpp/Manager.h
Normal file
|
@ -0,0 +1,104 @@
|
|||
/**
|
||||
* @file Manager.h
|
||||
* @ingroup LoggerCpp
|
||||
* @brief The static class that manage the registered Channel and Output objects
|
||||
*
|
||||
* Copyright (c) 2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "LoggerCpp/Log.h"
|
||||
#include "LoggerCpp/Channel.h"
|
||||
#include "LoggerCpp/Output.h"
|
||||
#include "LoggerCpp/Config.h"
|
||||
|
||||
namespace 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
|
|
@ -21,41 +21,41 @@
|
|||
// and imports the "shared_ptr" symbol inside the Log namespace (ie. Log::shared_ptr)
|
||||
#include "LoggerCpp/shared_ptr.hpp"
|
||||
|
||||
|
||||
namespace Log {
|
||||
namespace fl {
|
||||
namespace Log {
|
||||
|
||||
|
||||
// Forward declaration
|
||||
class Log;
|
||||
// Forward declaration
|
||||
class Log;
|
||||
|
||||
/**
|
||||
* @brief Interface of an Output
|
||||
* @ingroup LoggerCpp
|
||||
*/
|
||||
class Output {
|
||||
public:
|
||||
/// @brief Virtual destructor
|
||||
virtual ~Output() {}
|
||||
/**
|
||||
* @brief Interface of an Output
|
||||
* @ingroup LoggerCpp
|
||||
*/
|
||||
class Output {
|
||||
public:
|
||||
/// @brief Virtual destructor
|
||||
virtual ~Output() {}
|
||||
|
||||
public:
|
||||
/// @brief Shared Pointer to an Output
|
||||
typedef shared_ptr<Output> Ptr;
|
||||
/// @brief List of Output objects
|
||||
typedef std::vector<Ptr> Vector;
|
||||
public:
|
||||
/// @brief Shared Pointer to an Output
|
||||
typedef shared_ptr<Output> Ptr;
|
||||
/// @brief List of Output objects
|
||||
typedef std::vector<Ptr> Vector;
|
||||
|
||||
/**
|
||||
* @brief Output the Log
|
||||
*
|
||||
* @param[in] aChannelPtr The underlying Channel of the Log
|
||||
* @param[in] aLog The Log to output
|
||||
*/
|
||||
virtual void output(const Channel::Ptr& aChannelPtr, const Log& aLog) const = 0;
|
||||
|
||||
/// @brief Return the type name of the Output object
|
||||
inline const char* name() const {
|
||||
return typeid(this).name();
|
||||
}
|
||||
};
|
||||
/**
|
||||
* @brief Output the Log
|
||||
*
|
||||
* @param[in] aChannelPtr The underlying Channel of the Log
|
||||
* @param[in] aLog The Log to output
|
||||
*/
|
||||
virtual void output(const Channel::Ptr& aChannelPtr, const Log& aLog) const = 0;
|
||||
|
||||
/// @brief Return the type name of the Output object
|
||||
inline const char* name() const {
|
||||
return typeid(this).name();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace Log
|
62
fl/LoggerCpp/OutputConsole.h
Normal file
62
fl/LoggerCpp/OutputConsole.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
/**
|
||||
* @file OutputConsole.h
|
||||
* @ingroup LoggerCpp
|
||||
* @brief Output to the standard console using fprintf() with stdout
|
||||
*
|
||||
* Copyright (c) 2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "LoggerCpp/Output.h"
|
||||
#include "LoggerCpp/Config.h"
|
||||
|
||||
namespace 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
|
43
fl/LoggerCpp/OutputDebug.h
Normal file
43
fl/LoggerCpp/OutputDebug.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
/**
|
||||
* @file OutputDebug.h
|
||||
* @ingroup LoggerCpp
|
||||
* @brief Output to the Visual Studio debugger using OutputDebugString()
|
||||
*
|
||||
* Copyright (c) 2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "LoggerCpp/Output.h"
|
||||
#include "LoggerCpp/Config.h"
|
||||
|
||||
namespace 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
84
fl/LoggerCpp/OutputFile.h
Normal file
|
@ -0,0 +1,84 @@
|
|||
/**
|
||||
* @file OutputFile.h
|
||||
* @ingroup LoggerCpp
|
||||
* @brief Output to the a file using fprintf
|
||||
*
|
||||
* Copyright (c) 2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "LoggerCpp/Output.h"
|
||||
#include "LoggerCpp/Config.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace 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
317
fl/LoggerCpp/shared_ptr.hpp
Normal file
|
@ -0,0 +1,317 @@
|
|||
/**
|
||||
* @file shared_ptr.hpp
|
||||
* @brief shared_ptr is a minimal implementation of smart pointer, a subset of the C++11 std::shared_ptr or boost::shared_ptr.
|
||||
*
|
||||
* This file includes "boost/shared_ptr.hpp" if LOGGER_USE_BOOST_SHARED_PTR is defined,
|
||||
* or <memory> (or <tr1/memory>) when C++11 (or experimental C++0x) is available,
|
||||
* and imports the symbol "shared_ptr" inside the current namespace (ie. Log::shared_ptr).
|
||||
* If no std::shared_ptr is available, it defines a minimal shared_ptr implementation.
|
||||
*
|
||||
* Copyright (c) 2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
||||
/// Compatibility with non-clang compilers.
|
||||
#ifndef __has_feature
|
||||
#define __has_feature(x) 0
|
||||
#endif
|
||||
|
||||
//
|
||||
// Try to detect the better shared_ptr to use, and then imports the symbol in the current namespace
|
||||
// => if you include this "shared_ptr.hpp" file inside your own namespace you will
|
||||
// get a kind of universal easy to use "shared_ptr" type
|
||||
//
|
||||
#ifdef LOGGER_USE_BOOST_SHARED_PTR
|
||||
// Use Boost only if explicitly told
|
||||
#include <boost/shared_ptr.hpp>
|
||||
namespace fl {
|
||||
namespace Log {
|
||||
using boost::shared_ptr;
|
||||
} // namespace Log
|
||||
}
|
||||
// Detect whether the compiler supports C++11 shared_ptr or its TR1 pre-version.
|
||||
#elif (defined(__GNUC__) && \
|
||||
(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2)) && \
|
||||
defined(__GXX_EXPERIMENTAL_CXX0X__))
|
||||
// GCC 4.3 and following have std::shared_ptr support when called with -std=c++0x (or -std=c++11 starting with GCC 4.7)
|
||||
#include <memory>
|
||||
namespace 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
65
src/LoggerCpp/Config.cpp
Normal file
|
@ -0,0 +1,65 @@
|
|||
/**
|
||||
* @file Config.cpp
|
||||
* @ingroup LoggerCpp
|
||||
* @brief Configuration for an Output object
|
||||
*
|
||||
* Copyright (c) 2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
|
||||
#include "LoggerCpp/Config.h"
|
||||
#include "LoggerCpp/Exception.h"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
namespace 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
|
70
src/LoggerCpp/DateTime.cpp
Normal file
70
src/LoggerCpp/DateTime.cpp
Normal file
|
@ -0,0 +1,70 @@
|
|||
/**
|
||||
* @file DateTime.cpp
|
||||
* @ingroup LoggerCpp
|
||||
* @brief Current time precise to the millisecond.
|
||||
*
|
||||
* Copyright (c) 2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
|
||||
#include "LoggerCpp/DateTime.h"
|
||||
#include "LoggerCpp/Utils.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
namespace 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
75
src/LoggerCpp/Log.cpp
Normal file
|
@ -0,0 +1,75 @@
|
|||
/**
|
||||
* @file Log.cpp
|
||||
* @ingroup LoggerCpp
|
||||
* @brief A RAII (private) log object constructed by the Logger class
|
||||
*
|
||||
* Copyright (c) 2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
|
||||
#include "LoggerCpp/Log.h"
|
||||
#include "LoggerCpp/Logger.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace 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
61
src/LoggerCpp/Logger.cpp
Normal file
|
@ -0,0 +1,61 @@
|
|||
/**
|
||||
* @file Logger.cpp
|
||||
* @ingroup LoggerCpp
|
||||
* @brief A simple thread-safe Logger class
|
||||
*
|
||||
* Copyright (c) 2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
|
||||
#include "LoggerCpp/Logger.h"
|
||||
#include "LoggerCpp/Manager.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace 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
140
src/LoggerCpp/Manager.cpp
Normal file
|
@ -0,0 +1,140 @@
|
|||
/**
|
||||
* @file Manager.cpp
|
||||
* @ingroup LoggerCpp
|
||||
* @brief The static class that manage the registered channels and outputs
|
||||
*
|
||||
* Copyright (c) 2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
|
||||
#include "LoggerCpp/Manager.h"
|
||||
#include "LoggerCpp/Exception.h"
|
||||
|
||||
#include "LoggerCpp/OutputConsole.h"
|
||||
#include "LoggerCpp/OutputFile.h"
|
||||
#ifdef WIN32
|
||||
#include "LoggerCpp/OutputDebug.h"
|
||||
#endif
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
namespace 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
|
||||
|
94
src/LoggerCpp/OutputConsole.cpp
Normal file
94
src/LoggerCpp/OutputConsole.cpp
Normal file
|
@ -0,0 +1,94 @@
|
|||
/**
|
||||
* @file OutputConsole.cpp
|
||||
* @ingroup LoggerCpp
|
||||
* @brief Output to the standard console using fprintf() with stdout
|
||||
*
|
||||
* Copyright (c) 2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
|
||||
#include "LoggerCpp/OutputConsole.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
namespace 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
|
49
src/LoggerCpp/OutputDebug.cpp
Normal file
49
src/LoggerCpp/OutputDebug.cpp
Normal file
|
@ -0,0 +1,49 @@
|
|||
/**
|
||||
* @file OutputDebug.cpp
|
||||
* @ingroup LoggerCpp
|
||||
* @brief Output to the Visual Studio debugger using OutputDebugString()
|
||||
*
|
||||
* Copyright (c) 2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
#include "LoggerCpp/OutputDebug.h"
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
namespace 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
|
101
src/LoggerCpp/OutputFile.cpp
Normal file
101
src/LoggerCpp/OutputFile.cpp
Normal file
|
@ -0,0 +1,101 @@
|
|||
/**
|
||||
* @file OutputFile.cpp
|
||||
* @ingroup LoggerCpp
|
||||
* @brief Output to the standard console using printf
|
||||
*
|
||||
* Copyright (c) 2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
|
||||
*
|
||||
* Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
|
||||
* or copy at http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
|
||||
#include "LoggerCpp/OutputFile.h"
|
||||
#include "LoggerCpp/Exception.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
namespace 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
|
Loading…
Add table
Reference in a new issue