mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
- Implemented the new logging API(not used currently) - Added lock typedefs to Global.h - Some layout updates to Global.h
This commit is contained in:
parent
f39ad093b9
commit
0baa261dfc
198
Global.h
198
Global.h
@ -1,14 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
// Standard include file
|
||||
// Contents:
|
||||
// Includes C/C++ libraries, STL libraries, IOStream and String libraries
|
||||
// Includes the most important boost headers
|
||||
// Defines the import + export, override and exception handling macros
|
||||
// Defines the vstd library
|
||||
// Includes the logger
|
||||
|
||||
// This file shouldn't be changed, except if there is a important header file missing which is shared among several projects.
|
||||
|
||||
/*
|
||||
* Global.h, part of VCMI engine
|
||||
@ -20,11 +9,59 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
/* Compiler detection */
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
// Fixed width bool data type is important for serialization
|
||||
static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size.");
|
||||
|
||||
#if defined _M_X64 && defined _WIN32 //Win64 -> cannot load 32-bit DLLs for video handling
|
||||
#define DISABLE_VIDEO
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__ * 10 + __GNUC_PATCHLEVEL__)
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && (GCC_VERSION == 470 || GCC_VERSION == 471)
|
||||
#error This GCC version has buggy std::array::at version and should not be used. Please update to 4.7.2 or use 4.6.x.
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
/* Guarantee compiler features */
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
//defining available c++11 features
|
||||
|
||||
//initialization lists - only gcc-4.4 or later
|
||||
#if defined(__clang__) || (defined(__GNUC__) && (GCC_VERSION >= 440))
|
||||
#define CPP11_USE_INITIALIZERS_LIST
|
||||
#endif
|
||||
|
||||
//nullptr - only msvc and gcc-4.6 or later, othervice define it as NULL
|
||||
#if !defined(_MSC_VER) && !(defined(__GNUC__) && (GCC_VERSION >= 460))
|
||||
#define nullptr NULL
|
||||
#endif
|
||||
|
||||
//override keyword - only msvc and gcc-4.7 or later.
|
||||
#if !defined(_MSC_VER) && !(defined(__GNUC__) && (GCC_VERSION >= 470))
|
||||
#define override
|
||||
#endif
|
||||
|
||||
//workaround to support existing code
|
||||
#define OVERRIDE override
|
||||
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
/* Suppress some compiler warnings */
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (disable : 4800 ) /* disable conversion to bool warning -- I think it's intended in all places */
|
||||
#endif //_MSC_VER
|
||||
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
/* Commonly used C++, Boost headers */
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||
#include <cstdio>
|
||||
#include <stdio.h>
|
||||
@ -50,7 +87,6 @@
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
//#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
@ -70,6 +106,7 @@
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time_io.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/format.hpp>
|
||||
@ -90,6 +127,17 @@
|
||||
#include <android/log.h>
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
/* Usings */
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
using std::shared_ptr;
|
||||
using std::unique_ptr;
|
||||
using std::make_shared;
|
||||
namespace range = boost::range;
|
||||
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
/* Typedefs */
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
// Integral data types
|
||||
typedef boost::uint64_t ui64; //unsigned int 64 bits (8 bytes)
|
||||
typedef boost::uint32_t ui32; //unsigned int 32 bits (4 bytes)
|
||||
@ -100,21 +148,14 @@ typedef boost::int32_t si32; //signed int 32 bits (4 bytes)
|
||||
typedef boost::int16_t si16; //signed int 16 bits (2 bytes)
|
||||
typedef boost::int8_t si8; //signed int 8 bits (1 byte)
|
||||
|
||||
// Fixed width bool data type is important for serialization
|
||||
static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size.");
|
||||
|
||||
#if defined _M_X64 && defined _WIN32 //Win64 -> cannot load 32-bit DLLs for video handling
|
||||
#define DISABLE_VIDEO
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__ * 10 + __GNUC_PATCHLEVEL__)
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && (GCC_VERSION == 470 || GCC_VERSION == 471)
|
||||
#error This GCC version has buggy std::array::at version and should not be used. Please update to 4.7.2 or use 4.6.x.
|
||||
#endif
|
||||
// Lock typedefs
|
||||
typedef boost::unique_lock<boost::shared_mutex> TWriteLock;
|
||||
typedef boost::shared_lock<boost::shared_mutex> TReadLock;
|
||||
typedef boost::lock_guard<boost::mutex> TLockGuard;
|
||||
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
/* Macros */
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
// Import + Export macro declarations
|
||||
#ifdef _WIN32
|
||||
#ifdef __GNUC__
|
||||
@ -150,26 +191,46 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size.");
|
||||
#define DLL_LINKAGE DLL_IMPORT
|
||||
#endif
|
||||
|
||||
//defining available c++11 features
|
||||
#define THROW_FORMAT(message, formatting_elems) throw std::runtime_error(boost::str(boost::format(message) % formatting_elems))
|
||||
|
||||
//initialization lists - only gcc-4.4 or later
|
||||
#if defined(__clang__) || (defined(__GNUC__) && (GCC_VERSION >= 440))
|
||||
#define CPP11_USE_INITIALIZERS_LIST
|
||||
#endif
|
||||
#define ASSERT_IF_CALLED_WITH_PLAYER if(!player) {tlog1 << __FUNCTION__ << "\n"; assert(0);}
|
||||
|
||||
//nullptr - only msvc and gcc-4.6 or later, othervice define it as NULL
|
||||
#if !defined(_MSC_VER) && !(defined(__GNUC__) && (GCC_VERSION >= 460))
|
||||
#define nullptr NULL
|
||||
#endif
|
||||
//XXX pls dont - 'debug macros' are usually more trouble than it's worth
|
||||
#define HANDLE_EXCEPTION \
|
||||
catch (const std::exception& e) { \
|
||||
tlog1 << e.what() << std::endl; \
|
||||
throw; \
|
||||
} \
|
||||
catch (const std::exception * e) \
|
||||
{ \
|
||||
tlog1 << e->what()<< std::endl; \
|
||||
throw; \
|
||||
} \
|
||||
catch (const std::string& e) { \
|
||||
tlog1 << e << std::endl; \
|
||||
throw; \
|
||||
}
|
||||
|
||||
//override keyword - only msvc and gcc-4.7 or later.
|
||||
#if !defined(_MSC_VER) && !(defined(__GNUC__) && (GCC_VERSION >= 470))
|
||||
#define override
|
||||
#endif
|
||||
#define HANDLE_EXCEPTIONC(COMMAND) \
|
||||
catch (const std::exception& e) { \
|
||||
COMMAND; \
|
||||
tlog1 << e.what() << std::endl; \
|
||||
throw; \
|
||||
} \
|
||||
catch (const std::string &e) \
|
||||
{ \
|
||||
COMMAND; \
|
||||
tlog1 << e << std::endl; \
|
||||
throw; \
|
||||
}
|
||||
|
||||
//workaround to support existing code
|
||||
#define OVERRIDE override
|
||||
// can be used for counting arrays
|
||||
template<typename T, size_t N> char (&_ArrayCountObj(const T (&)[N]))[N];
|
||||
#define ARRAY_COUNT(arr) (sizeof(_ArrayCountObj(arr)))
|
||||
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
/* VCMI standard library */
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
//a normal std::map with a const operator[] for sanity
|
||||
template<typename KeyT, typename ValT>
|
||||
class bmap : public std::map<KeyT, ValT>
|
||||
@ -508,53 +569,10 @@ namespace vstd
|
||||
obj = (T)(((int)obj) + change);
|
||||
}
|
||||
}
|
||||
|
||||
using std::shared_ptr;
|
||||
using std::unique_ptr;
|
||||
using std::make_shared;
|
||||
using vstd::operator-=;
|
||||
using vstd::make_unique;
|
||||
|
||||
using vstd::operator-=;
|
||||
|
||||
namespace range = boost::range;
|
||||
|
||||
// can be used for counting arrays
|
||||
template<typename T, size_t N> char (&_ArrayCountObj(const T (&)[N]))[N];
|
||||
#define ARRAY_COUNT(arr) (sizeof(_ArrayCountObj(arr)))
|
||||
|
||||
|
||||
#define THROW_FORMAT(message, formatting_elems) throw std::runtime_error(boost::str(boost::format(message) % formatting_elems))
|
||||
|
||||
#define ASSERT_IF_CALLED_WITH_PLAYER if(!player) {tlog1 << __FUNCTION__ << "\n"; assert(0);}
|
||||
|
||||
//XXX pls dont - 'debug macros' are usually more trouble than it's worth
|
||||
#define HANDLE_EXCEPTION \
|
||||
catch (const std::exception& e) { \
|
||||
tlog1 << e.what() << std::endl; \
|
||||
throw; \
|
||||
} \
|
||||
catch (const std::exception * e) \
|
||||
{ \
|
||||
tlog1 << e->what()<< std::endl; \
|
||||
throw; \
|
||||
} \
|
||||
catch (const std::string& e) { \
|
||||
tlog1 << e << std::endl; \
|
||||
throw; \
|
||||
}
|
||||
|
||||
#define HANDLE_EXCEPTIONC(COMMAND) \
|
||||
catch (const std::exception& e) { \
|
||||
COMMAND; \
|
||||
tlog1 << e.what() << std::endl; \
|
||||
throw; \
|
||||
} \
|
||||
catch (const std::string &e) \
|
||||
{ \
|
||||
COMMAND; \
|
||||
tlog1 << e << std::endl; \
|
||||
throw; \
|
||||
}
|
||||
|
||||
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
/* VCMI headers */
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
#include "lib/CLogger.h"
|
||||
|
@ -3,7 +3,7 @@
|
||||
{
|
||||
"type" : "object",
|
||||
"$schema": "http://json-schema.org/draft-04/schema",
|
||||
"required" : [ "general", "video", "adventure", "battle", "server" ],
|
||||
"required" : [ "general", "video", "adventure", "battle", "server", "logging" ],
|
||||
"properties":
|
||||
{
|
||||
"general" : {
|
||||
@ -133,6 +133,72 @@
|
||||
"default" : "StupidAI"
|
||||
}
|
||||
}
|
||||
},
|
||||
"logging" : {
|
||||
"type" : "object",
|
||||
"default" : {},
|
||||
"properties" : {
|
||||
"console" : {
|
||||
"type" : "object",
|
||||
"properties" : {
|
||||
"format" : {
|
||||
"type" : "string",
|
||||
"default" : "%l %n [%t] - %m"
|
||||
},
|
||||
"threshold" : {
|
||||
"type" : "string",
|
||||
"default" : "info",
|
||||
"enum" : [ "trace", "debug", "info", "warn", "error" ]
|
||||
},
|
||||
"coloredOutputEnabled" : {
|
||||
"type" : "boolean",
|
||||
"default" : true
|
||||
},
|
||||
"colorMapping" : {
|
||||
"type" : "array",
|
||||
"default" : [
|
||||
{ "domain" : "global", "level" : "trace", "color" : "gray"},
|
||||
{ "domain" : "global", "level" : "debug", "color" : "white"},
|
||||
{ "domain" : "global", "level" : "info", "color" : "green"},
|
||||
{ "domain" : "global", "level" : "warn", "color" : "yellow"},
|
||||
{ "domain" : "global", "level" : "error", "color" : "red"}
|
||||
],
|
||||
"items" : {
|
||||
"type" : "object",
|
||||
"required" : [ "domain", "level", "color" ],
|
||||
"properties" : {
|
||||
"domain" : { "type" : "string" },
|
||||
"level" : { "type" : "string", "enum" : [ "trace", "debug", "info", "warn", "error" ] },
|
||||
"color" : { "type" : "string", "enum" : [ "default", "green", "red", "magenta", "yellow", "white", "gray", "teal" ] }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"file" : {
|
||||
"type" : "object",
|
||||
"properties" : {
|
||||
"format" : {
|
||||
"type" : "string",
|
||||
"default" : "%d %l %n [%t] - %m"
|
||||
}
|
||||
}
|
||||
},
|
||||
"loggers" : {
|
||||
"type" : "object",
|
||||
"additionalProperties" : {
|
||||
"type":"object",
|
||||
"required" : [ "level" ],
|
||||
"properties" : {
|
||||
"level" : {
|
||||
"type" : "string",
|
||||
"enum" : [ "trace", "debug", "info", "warn", "error" ]
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -141,43 +141,43 @@ LONG WINAPI onUnhandledException(EXCEPTION_POINTERS* exception)
|
||||
#endif
|
||||
|
||||
|
||||
void CConsoleHandler::setColor(int level)
|
||||
void CConsoleHandler::setColor(EConsoleTextColor::EConsoleTextColor color)
|
||||
{
|
||||
TColor color;
|
||||
switch(level)
|
||||
TColor colorCode;
|
||||
switch(color)
|
||||
{
|
||||
case -1:
|
||||
color = defColor;
|
||||
case EConsoleTextColor::DEFAULT:
|
||||
colorCode = defColor;
|
||||
break;
|
||||
case 0:
|
||||
color = CONSOLE_GREEN;
|
||||
case EConsoleTextColor::GREEN:
|
||||
colorCode = CONSOLE_GREEN;
|
||||
break;
|
||||
case 1:
|
||||
color = CONSOLE_RED;
|
||||
case EConsoleTextColor::RED:
|
||||
colorCode = CONSOLE_RED;
|
||||
break;
|
||||
case 2:
|
||||
color = CONSOLE_MAGENTA;
|
||||
case EConsoleTextColor::MAGENTA:
|
||||
colorCode = CONSOLE_MAGENTA;
|
||||
break;
|
||||
case 3:
|
||||
color = CONSOLE_YELLOW;
|
||||
case EConsoleTextColor::YELLOW:
|
||||
colorCode = CONSOLE_YELLOW;
|
||||
break;
|
||||
case 4:
|
||||
color = CONSOLE_WHITE;
|
||||
case EConsoleTextColor::WHITE:
|
||||
colorCode = CONSOLE_WHITE;
|
||||
break;
|
||||
case 5:
|
||||
color = CONSOLE_GRAY;
|
||||
case EConsoleTextColor::GRAY:
|
||||
colorCode = CONSOLE_GRAY;
|
||||
break;
|
||||
case -2:
|
||||
color = CONSOLE_TEAL;
|
||||
case EConsoleTextColor::TEAL:
|
||||
colorCode = CONSOLE_TEAL;
|
||||
break;
|
||||
default:
|
||||
color = defColor;
|
||||
colorCode = defColor;
|
||||
break;
|
||||
}
|
||||
#ifdef _WIN32
|
||||
SetConsoleTextAttribute(handleOut,color);
|
||||
SetConsoleTextAttribute(handleOut, colorCode);
|
||||
#else
|
||||
std::cout << color;
|
||||
std::cout << colorCode;
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -210,7 +210,7 @@ int CConsoleHandler::run()
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
CConsoleHandler::CConsoleHandler()
|
||||
CConsoleHandler::CConsoleHandler() : thread(nullptr)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
handleIn = GetStdHandle(STD_INPUT_HANDLE);
|
||||
@ -225,7 +225,6 @@ CConsoleHandler::CConsoleHandler()
|
||||
defColor = "\x1b[0m";
|
||||
#endif
|
||||
cb = new boost::function<void(const std::string &)>;
|
||||
thread = NULL;
|
||||
}
|
||||
CConsoleHandler::~CConsoleHandler()
|
||||
{
|
||||
|
@ -10,36 +10,64 @@
|
||||
*
|
||||
*/
|
||||
|
||||
namespace EConsoleTextColor
|
||||
{
|
||||
/** The color enum is used for colored text console output. */
|
||||
enum EConsoleTextColor
|
||||
{
|
||||
DEFAULT = -1,
|
||||
GREEN,
|
||||
RED,
|
||||
MAGENTA,
|
||||
YELLOW,
|
||||
WHITE,
|
||||
GRAY,
|
||||
TEAL = -2
|
||||
};
|
||||
}
|
||||
|
||||
/// Class which wraps the native console. It can print text based on
|
||||
/// the chosen color
|
||||
class DLL_LINKAGE CConsoleHandler
|
||||
{
|
||||
public:
|
||||
boost::function<void(const std::string &)> *cb; //function to be called when message is received
|
||||
int curLvl; //logging level
|
||||
boost::thread *thread;
|
||||
|
||||
int run();
|
||||
void setColor(int level); //sets color of text appropriate for given logging level
|
||||
|
||||
CConsoleHandler(); //c-tor
|
||||
~CConsoleHandler(); //d-tor
|
||||
void start(); //starts listening thread
|
||||
void end(); //kills listening thread
|
||||
|
||||
template<typename T> void print(const T &data, int lvl)
|
||||
template<typename T> void print(const T &data, EConsoleTextColor::EConsoleTextColor color = EConsoleTextColor::DEFAULT, bool printToStdErr = false)
|
||||
{
|
||||
TLockGuard _(mx);
|
||||
#ifndef _WIN32
|
||||
// with love from ffmpeg - library is trying to print some warnings from separate thread
|
||||
// this results in broken console on Linux. Lock stdout to print all our data at once
|
||||
flockfile(stdout);
|
||||
#endif
|
||||
setColor(lvl);
|
||||
if(color != EConsoleTextColor::DEFAULT) setColor(color);
|
||||
if(printToStdErr)
|
||||
{
|
||||
std::cerr << data << std::flush;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << data << std::flush;
|
||||
setColor(-1);
|
||||
}
|
||||
if(color != EConsoleTextColor::DEFAULT) setColor(EConsoleTextColor::DEFAULT);
|
||||
#ifndef _WIN32
|
||||
funlockfile(stdout);
|
||||
#endif
|
||||
}
|
||||
|
||||
boost::function<void(const std::string &)> *cb; //function to be called when message is received
|
||||
|
||||
private:
|
||||
int run();
|
||||
|
||||
void end(); //kills listening thread
|
||||
|
||||
void setColor(EConsoleTextColor::EConsoleTextColor color); //sets color of text appropriate for given logging level
|
||||
|
||||
mutable boost::mutex mx;
|
||||
|
||||
boost::thread * thread;
|
||||
};
|
||||
|
@ -41,7 +41,7 @@ public:
|
||||
if(lvl < CLogger::CONSOLE_LOGGING_LEVEL)
|
||||
{
|
||||
if(console)
|
||||
console->print(data, lvl);
|
||||
console->print(data, static_cast<EConsoleTextColor::EConsoleTextColor>(lvl));
|
||||
else
|
||||
std::cout << data << std::flush;
|
||||
}
|
||||
|
@ -13,6 +13,12 @@ set(lib_SRCS
|
||||
Filesystem/CResourceLoader.cpp
|
||||
Filesystem/CFileInputStream.cpp
|
||||
Filesystem/CCompressedStream.cpp
|
||||
Logging/CBasicLogConfigurator.cpp
|
||||
Logging/CLogConsoleTarget.cpp
|
||||
Logging/CLogFileTarget.cpp
|
||||
Logging/CLogFormatter.cpp
|
||||
Logging/CLogger.cpp
|
||||
Logging/CLogManager.cpp
|
||||
Mapping/CCampaignHandler.cpp
|
||||
Mapping/CMap.cpp
|
||||
Mapping/CMapEditManager.cpp
|
||||
@ -59,6 +65,14 @@ set(lib_SRCS
|
||||
set(lib_HEADERS
|
||||
Filesystem/CInputStream.h
|
||||
Filesystem/ISimpleResourceLoader.h
|
||||
Logging/CBasicLogConfigurator.h
|
||||
Logging/CLogConsoleTarget.h
|
||||
Logging/CLogFileTarget.h
|
||||
Logging/CLogFormatter.h
|
||||
Logging/CLogger.h
|
||||
Logging/CLogManager.h
|
||||
Logging/ILogTarget.h
|
||||
Logging/LogRecord.h
|
||||
Mapping/CCampaignHandler.h
|
||||
Mapping/CMap.h
|
||||
Mapping/CMapEditManager.h
|
||||
|
113
lib/Logging/CBasicLogConfigurator.cpp
Normal file
113
lib/Logging/CBasicLogConfigurator.cpp
Normal file
@ -0,0 +1,113 @@
|
||||
#include "StdInc.h"
|
||||
#include "CBasicLogConfigurator.h"
|
||||
|
||||
#include "../CConfigHandler.h"
|
||||
#include "CLogConsoleTarget.h"
|
||||
#include "CLogFileTarget.h"
|
||||
|
||||
CBasicLogConfigurator::CBasicLogConfigurator(const std::string & filePath, CConsoleHandler * console)
|
||||
{
|
||||
const JsonNode & logging = settings["logging"];
|
||||
|
||||
// Configure loggers
|
||||
const JsonNode & loggers = logging["loggers"];
|
||||
if(!loggers.isNull())
|
||||
{
|
||||
BOOST_FOREACH(auto & loggerPair, loggers.Struct())
|
||||
{
|
||||
// Get logger
|
||||
std::string name = loggerPair.first;
|
||||
CGLogger * logger = CGLogger::getLogger(name);
|
||||
|
||||
// Set log level
|
||||
const JsonNode & loggerNode = loggerPair.second;
|
||||
const JsonNode & levelNode = loggerNode["level"];
|
||||
if(!levelNode.isNull())
|
||||
{
|
||||
logger->setLevel(getLogLevel(levelNode.String()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add console target
|
||||
CLogConsoleTarget * consoleTarget = new CLogConsoleTarget(console);
|
||||
const JsonNode & consoleNode = logging["console"];
|
||||
if(!consoleNode.isNull())
|
||||
{
|
||||
const JsonNode & consoleFormatNode = consoleNode["format"];
|
||||
if(!consoleFormatNode.isNull()) consoleTarget->setFormatter(CLogFormatter(consoleFormatNode.String()));
|
||||
const JsonNode & consoleThresholdNode = consoleNode["threshold"];
|
||||
if(!consoleThresholdNode.isNull()) consoleTarget->setThreshold(getLogLevel(consoleThresholdNode.String()));
|
||||
const JsonNode & coloredConsoleEnabledNode = consoleNode["coloredOutputEnabled"];
|
||||
consoleTarget->setColoredOutputEnabled(coloredConsoleEnabledNode.Bool());
|
||||
|
||||
CColorMapping colorMapping;
|
||||
const JsonNode & colorMappingNode = consoleNode["colorMapping"];
|
||||
if(!colorMappingNode.isNull())
|
||||
{
|
||||
BOOST_FOREACH(const JsonNode & mappingNode, colorMappingNode.Vector())
|
||||
{
|
||||
std::string domain = mappingNode["domain"].String();
|
||||
std::string level = mappingNode["level"].String();
|
||||
std::string color = mappingNode["color"].String();
|
||||
colorMapping.setColorFor(domain, getLogLevel(level), getConsoleColor(color));
|
||||
}
|
||||
}
|
||||
consoleTarget->setColorMapping(colorMapping);
|
||||
}
|
||||
CGLogger::getGlobalLogger()->addTarget(consoleTarget);
|
||||
|
||||
// Add file target
|
||||
CLogFileTarget * fileTarget = new CLogFileTarget(filePath);
|
||||
const JsonNode & fileNode = logging["file"];
|
||||
if(!fileNode.isNull())
|
||||
{
|
||||
const JsonNode & fileFormatNode = fileNode["format"];
|
||||
if(!fileFormatNode.isNull()) fileTarget->setFormatter(CLogFormatter(fileFormatNode.String()));
|
||||
}
|
||||
|
||||
// Add targets to the root logger by default
|
||||
CGLogger::getGlobalLogger()->addTarget(consoleTarget);
|
||||
CGLogger::getGlobalLogger()->addTarget(fileTarget);
|
||||
}
|
||||
|
||||
ELogLevel::ELogLevel CBasicLogConfigurator::getLogLevel(const std::string & level) const
|
||||
{
|
||||
static const std::map<std::string, ELogLevel::ELogLevel> levelMap = boost::assign::map_list_of
|
||||
("trace", ELogLevel::TRACE)
|
||||
("debug", ELogLevel::DEBUG)
|
||||
("info", ELogLevel::INFO)
|
||||
("warn", ELogLevel::WARN)
|
||||
("error", ELogLevel::ERROR);
|
||||
const auto & levelPair = levelMap.find(level);
|
||||
if(levelPair != levelMap.end())
|
||||
{
|
||||
return levelPair->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error("Log level " + level + " unknown.");
|
||||
}
|
||||
}
|
||||
|
||||
EConsoleTextColor::EConsoleTextColor CBasicLogConfigurator::getConsoleColor(const std::string & colorName) const
|
||||
{
|
||||
static const std::map<std::string, EConsoleTextColor::EConsoleTextColor> colorMap = boost::assign::map_list_of
|
||||
("default", EConsoleTextColor::DEFAULT)
|
||||
("green", EConsoleTextColor::GREEN)
|
||||
("red", EConsoleTextColor::RED)
|
||||
("magenta", EConsoleTextColor::MAGENTA)
|
||||
("yellow", EConsoleTextColor::YELLOW)
|
||||
("white", EConsoleTextColor::WHITE)
|
||||
("gray", EConsoleTextColor::GRAY)
|
||||
("teal", EConsoleTextColor::TEAL);
|
||||
const auto & colorPair = colorMap.find(colorName);
|
||||
if(colorPair != colorMap.end())
|
||||
{
|
||||
return colorPair->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error("Color " + colorName + " unknown.");
|
||||
}
|
||||
}
|
55
lib/Logging/CBasicLogConfigurator.h
Normal file
55
lib/Logging/CBasicLogConfigurator.h
Normal file
@ -0,0 +1,55 @@
|
||||
|
||||
/*
|
||||
* CBasicLogConfigurator.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CLogger.h"
|
||||
|
||||
class CConsoleHandler;
|
||||
|
||||
/**
|
||||
* The basic log configurator reads log properties from the settings.json and
|
||||
* sets up the logging system. The file path of the log file can be specified
|
||||
* via the constructor.
|
||||
*/
|
||||
class DLL_LINKAGE CBasicLogConfigurator
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param fileName The file path of the log file.
|
||||
*
|
||||
* @throws std::runtime_error if the configuration has errors
|
||||
*/
|
||||
CBasicLogConfigurator(const std::string & filePath, CConsoleHandler * console);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Gets the log level enum from a string.
|
||||
*
|
||||
* @param level The log level string to parse.
|
||||
* @return the corresponding log level enum value
|
||||
*
|
||||
* @throws std::runtime_error if the log level is unknown
|
||||
*/
|
||||
ELogLevel::ELogLevel getLogLevel(const std::string & level) const;
|
||||
|
||||
/**
|
||||
* Gets the console text color enum from a string.
|
||||
*
|
||||
* @param colorName The color string to parse.
|
||||
* @return the corresponding console text color enum value
|
||||
*
|
||||
* @throws std::runtime_error if the log level is unknown
|
||||
*/
|
||||
EConsoleTextColor::EConsoleTextColor getConsoleColor(const std::string & colorName) const;
|
||||
};
|
126
lib/Logging/CLogConsoleTarget.cpp
Normal file
126
lib/Logging/CLogConsoleTarget.cpp
Normal file
@ -0,0 +1,126 @@
|
||||
#include "StdInc.h"
|
||||
#include "CLogConsoleTarget.h"
|
||||
|
||||
#include "LogRecord.h"
|
||||
|
||||
CColorMapping::CColorMapping()
|
||||
{
|
||||
// Set default mappings
|
||||
auto & levelMap = map[""];
|
||||
levelMap[ELogLevel::TRACE] = EConsoleTextColor::GRAY;
|
||||
levelMap[ELogLevel::DEBUG] = EConsoleTextColor::WHITE;
|
||||
levelMap[ELogLevel::INFO] = EConsoleTextColor::GREEN;
|
||||
levelMap[ELogLevel::WARN] = EConsoleTextColor::YELLOW;
|
||||
levelMap[ELogLevel::ERROR] = EConsoleTextColor::RED;
|
||||
}
|
||||
|
||||
void CColorMapping::setColorFor(const CLoggerDomain & domain, ELogLevel::ELogLevel level, EConsoleTextColor::EConsoleTextColor color)
|
||||
{
|
||||
if(level == ELogLevel::NOT_SET) throw std::runtime_error("Log level NOT_SET not allowed for configuring the color mapping.");
|
||||
map[domain.getName()][level] = color;
|
||||
}
|
||||
|
||||
EConsoleTextColor::EConsoleTextColor CColorMapping::getColorFor(const CLoggerDomain & domain, ELogLevel::ELogLevel level) const
|
||||
{
|
||||
std::string name = domain.getName();
|
||||
while(true)
|
||||
{
|
||||
const auto & loggerPair = map.find(name);
|
||||
if(loggerPair != map.end())
|
||||
{
|
||||
const auto & levelMap = loggerPair->second;
|
||||
const auto & levelPair = levelMap.find(level);
|
||||
if(levelPair != levelMap.end())
|
||||
{
|
||||
return levelPair->second;
|
||||
}
|
||||
}
|
||||
|
||||
CLoggerDomain currentDomain(name);
|
||||
if(!currentDomain.isGlobalDomain())
|
||||
{
|
||||
name = currentDomain.getParent().getName();
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
throw std::runtime_error("No color mapping found. Should not happen.");
|
||||
}
|
||||
|
||||
CLogConsoleTarget::CLogConsoleTarget(CConsoleHandler * console) : console(console), threshold(ELogLevel::INFO), coloredOutputEnabled(true)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void CLogConsoleTarget::write(const LogRecord & record)
|
||||
{
|
||||
if(threshold > record.level) return;
|
||||
|
||||
std::string message = formatter.format(record);
|
||||
bool printToStdErr = record.level >= ELogLevel::WARN;
|
||||
if(console)
|
||||
{
|
||||
if(coloredOutputEnabled)
|
||||
{
|
||||
console->print(message, colorMapping.getColorFor(record.domain, record.level));
|
||||
}
|
||||
else
|
||||
{
|
||||
console->print(message, EConsoleTextColor::DEFAULT, printToStdErr);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TLockGuard _(mx);
|
||||
if(printToStdErr)
|
||||
{
|
||||
std::cerr << message << std::flush;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << message << std::flush;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CLogConsoleTarget::isColoredOutputEnabled() const
|
||||
{
|
||||
return coloredOutputEnabled;
|
||||
}
|
||||
|
||||
void CLogConsoleTarget::setColoredOutputEnabled(bool coloredOutputEnabled)
|
||||
{
|
||||
this->coloredOutputEnabled = coloredOutputEnabled;
|
||||
}
|
||||
|
||||
ELogLevel::ELogLevel CLogConsoleTarget::getThreshold() const
|
||||
{
|
||||
return threshold;
|
||||
}
|
||||
|
||||
void CLogConsoleTarget::setThreshold(ELogLevel::ELogLevel threshold)
|
||||
{
|
||||
this->threshold = threshold;
|
||||
}
|
||||
|
||||
const CLogFormatter & CLogConsoleTarget::getFormatter() const
|
||||
{
|
||||
return formatter;
|
||||
}
|
||||
|
||||
void CLogConsoleTarget::setFormatter(const CLogFormatter & formatter)
|
||||
{
|
||||
this->formatter = formatter;
|
||||
}
|
||||
|
||||
const CColorMapping & CLogConsoleTarget::getColorMapping() const
|
||||
{
|
||||
return colorMapping;
|
||||
}
|
||||
|
||||
void CLogConsoleTarget::setColorMapping(const CColorMapping & colorMapping)
|
||||
{
|
||||
this->colorMapping = colorMapping;
|
||||
}
|
147
lib/Logging/CLogConsoleTarget.h
Normal file
147
lib/Logging/CLogConsoleTarget.h
Normal file
@ -0,0 +1,147 @@
|
||||
|
||||
/*
|
||||
* CLogConsoleTarget.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ILogTarget.h"
|
||||
#include "CLogger.h"
|
||||
#include "CLogFormatter.h"
|
||||
#include "CConsoleHandler.h"
|
||||
|
||||
class LogRecord;
|
||||
|
||||
/**
|
||||
* The color mapping maps a logger name and a level to a specific color.
|
||||
*/
|
||||
class DLL_LINKAGE CColorMapping
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor. There are default color mappings for the root logger, which child loggers inherit if not overriden.
|
||||
*/
|
||||
CColorMapping();
|
||||
|
||||
/**
|
||||
* Sets a console text color for a logger name and a level.
|
||||
*
|
||||
* @param domain The domain of the logger.
|
||||
* @param level The logger level.
|
||||
* @param color The console text color to use as the mapping.
|
||||
*/
|
||||
void setColorFor(const CLoggerDomain & domain, ELogLevel::ELogLevel level, EConsoleTextColor::EConsoleTextColor color);
|
||||
|
||||
/**
|
||||
* Gets a console text color for a logger name and a level.
|
||||
*
|
||||
* @param domain The domain of the logger.
|
||||
* @param level The logger level.
|
||||
* @return the console text color which has been applied for the mapping
|
||||
*/
|
||||
EConsoleTextColor::EConsoleTextColor getColorFor(const CLoggerDomain & domain, ELogLevel::ELogLevel level) const;
|
||||
|
||||
private:
|
||||
/** The color mapping, 1. Key: Logger domain, 2. Key: Level, Value: Color. */
|
||||
std::map<std::string, std::map<ELogLevel::ELogLevel, EConsoleTextColor::EConsoleTextColor> > map;
|
||||
};
|
||||
|
||||
/**
|
||||
* The console target is a logging target which writes message to the console.
|
||||
*/
|
||||
class DLL_LINKAGE CLogConsoleTarget : public ILogTarget
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param console Optional. The console handler which is used to output messages to the console.
|
||||
*/
|
||||
explicit CLogConsoleTarget(CConsoleHandler * console);
|
||||
|
||||
/**
|
||||
* Writes a log record.
|
||||
*
|
||||
* @param record The log record to write.
|
||||
*/
|
||||
void write(const LogRecord & record);
|
||||
|
||||
/**
|
||||
* True if colored output is enabled.
|
||||
*
|
||||
* @return true if colored output is enabled, false if not
|
||||
*/
|
||||
bool isColoredOutputEnabled() const;
|
||||
|
||||
/**
|
||||
* Sets the colored output flag.
|
||||
*
|
||||
* @param coloredOutput True if the log target should write colored messages to the console, false if not.
|
||||
*/
|
||||
void setColoredOutputEnabled(bool coloredOutputEnabled);
|
||||
|
||||
/**
|
||||
* Gets the threshold log level.
|
||||
*
|
||||
* @return the threshold log level
|
||||
*/
|
||||
ELogLevel::ELogLevel getThreshold() const;
|
||||
|
||||
/**
|
||||
* Sets the threshold log level.
|
||||
*
|
||||
* @param threshold The threshold log level.
|
||||
*/
|
||||
void setThreshold(ELogLevel::ELogLevel threshold);
|
||||
|
||||
/**
|
||||
* Gets the log formatter.
|
||||
*
|
||||
* @return The log formatter.
|
||||
*/
|
||||
const CLogFormatter & getFormatter() const;
|
||||
|
||||
/**
|
||||
* Sets the log formatter.
|
||||
*
|
||||
* @param formatter The log formatter.
|
||||
*/
|
||||
void setFormatter(const CLogFormatter & formatter);
|
||||
|
||||
/**
|
||||
* Gets the color mapping.
|
||||
*/
|
||||
const CColorMapping & getColorMapping() const;
|
||||
|
||||
/**
|
||||
* Sets the color mapping.
|
||||
*
|
||||
* @param colorMapping The color mapping.
|
||||
*/
|
||||
void setColorMapping(const CColorMapping & colorMapping);
|
||||
|
||||
private:
|
||||
/** The console handler which is used to output messages to the console. */
|
||||
CConsoleHandler * console;
|
||||
|
||||
/** The threshold log level. */
|
||||
ELogLevel::ELogLevel threshold;
|
||||
|
||||
/** Flag whether colored console output is enabled. */
|
||||
bool coloredOutputEnabled;
|
||||
|
||||
/** The log formatter to log messages. */
|
||||
CLogFormatter formatter;
|
||||
|
||||
/** The color mapping which maps a logger and a log level to a color. */
|
||||
CColorMapping colorMapping;
|
||||
|
||||
/** The shared mutex for providing synchronous thread-safe access to the log console target. */
|
||||
mutable boost::mutex mx;
|
||||
};
|
28
lib/Logging/CLogFileTarget.cpp
Normal file
28
lib/Logging/CLogFileTarget.cpp
Normal file
@ -0,0 +1,28 @@
|
||||
#include "StdInc.h"
|
||||
#include "CLogFileTarget.h"
|
||||
|
||||
CLogFileTarget::CLogFileTarget(const std::string & filePath) : file(filePath)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CLogFileTarget::~CLogFileTarget()
|
||||
{
|
||||
file.close();
|
||||
}
|
||||
|
||||
void CLogFileTarget::write(const LogRecord & record)
|
||||
{
|
||||
TLockGuard _(mx);
|
||||
file << formatter.format(record) << std::endl;
|
||||
}
|
||||
|
||||
const CLogFormatter & CLogFileTarget::getFormatter() const
|
||||
{
|
||||
return formatter;
|
||||
}
|
||||
|
||||
void CLogFileTarget::setFormatter(const CLogFormatter & formatter)
|
||||
{
|
||||
this->formatter = formatter;
|
||||
}
|
66
lib/Logging/CLogFileTarget.h
Normal file
66
lib/Logging/CLogFileTarget.h
Normal file
@ -0,0 +1,66 @@
|
||||
|
||||
/*
|
||||
* CLogFileTarget.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ILogTarget.h"
|
||||
#include "CLogFormatter.h"
|
||||
|
||||
/**
|
||||
* The log file target is a logging target which writes messages to a log file.
|
||||
*/
|
||||
class DLL_LINKAGE CLogFileTarget : public ILogTarget
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param filePath The file path of the log file.
|
||||
*/
|
||||
explicit CLogFileTarget(const std::string & filePath);
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~CLogFileTarget();
|
||||
|
||||
/**
|
||||
* Writes a log record.
|
||||
*
|
||||
* @param record The log record to write.
|
||||
*/
|
||||
void write(const LogRecord & record);
|
||||
|
||||
/**
|
||||
* Gets the log formatter.
|
||||
*
|
||||
* @return The log formatter.
|
||||
*/
|
||||
const CLogFormatter & getFormatter() const;
|
||||
|
||||
/**
|
||||
* Sets the log formatter.
|
||||
*
|
||||
* @param formatter The log formatter.
|
||||
*/
|
||||
void setFormatter(const CLogFormatter & formatter);
|
||||
|
||||
private:
|
||||
/** The output file stream. */
|
||||
std::ofstream file;
|
||||
|
||||
/** The log formatter to log messages. */
|
||||
CLogFormatter formatter;
|
||||
|
||||
/** The shared mutex for providing synchronous thread-safe access to the log file target. */
|
||||
mutable boost::mutex mx;
|
||||
};
|
||||
|
65
lib/Logging/CLogFormatter.cpp
Normal file
65
lib/Logging/CLogFormatter.cpp
Normal file
@ -0,0 +1,65 @@
|
||||
#include "StdInc.h"
|
||||
#include "CLogFormatter.h"
|
||||
|
||||
#include "LogRecord.h"
|
||||
|
||||
CLogFormatter::CLogFormatter() : pattern("%m")
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CLogFormatter::CLogFormatter(const std::string & pattern) : pattern(pattern)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::string CLogFormatter::format(const LogRecord & record) const
|
||||
{
|
||||
std::string message = pattern;
|
||||
|
||||
// Format date
|
||||
std::stringstream dateStream;
|
||||
boost::posix_time::time_facet * facet = new boost::posix_time::time_facet("%d-%b-%Y %H:%M:%S");
|
||||
dateStream.imbue(std::locale(dateStream.getloc(), facet));
|
||||
dateStream << record.timeStamp;
|
||||
boost::algorithm::replace_all(message, "%d", dateStream.str());
|
||||
|
||||
// Format log level
|
||||
std::string level;
|
||||
switch(record.level)
|
||||
{
|
||||
case ELogLevel::TRACE:
|
||||
level = "TRACE";
|
||||
break;
|
||||
case ELogLevel::DEBUG:
|
||||
level = "DEBUG";
|
||||
break;
|
||||
case ELogLevel::INFO:
|
||||
level = "INFO";
|
||||
break;
|
||||
case ELogLevel::WARN:
|
||||
level = "WARN";
|
||||
break;
|
||||
case ELogLevel::ERROR:
|
||||
level = "ERROR";
|
||||
break;
|
||||
}
|
||||
boost::algorithm::replace_all(message, "%l", level);
|
||||
|
||||
// Format name, thread id and message
|
||||
boost::algorithm::replace_all(message, "%n", record.domain.getName());
|
||||
boost::algorithm::replace_all(message, "%t", boost::lexical_cast<std::string>(record.threadId));
|
||||
boost::algorithm::replace_all(message, "%m", record.message);
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
void CLogFormatter::setPattern(const std::string & pattern)
|
||||
{
|
||||
this->pattern = pattern;
|
||||
}
|
||||
|
||||
const std::string & CLogFormatter::getPattern() const
|
||||
{
|
||||
return pattern;
|
||||
}
|
66
lib/Logging/CLogFormatter.h
Normal file
66
lib/Logging/CLogFormatter.h
Normal file
@ -0,0 +1,66 @@
|
||||
|
||||
/*
|
||||
* CLogFormatter.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
class LogRecord;
|
||||
|
||||
/**
|
||||
* The log formatter formats log records.
|
||||
*
|
||||
* There are several pattern characters which can be used to format a log record:
|
||||
* %d = Date/Time
|
||||
* %l = Log level
|
||||
* %n = Logger name
|
||||
* %t = Thread ID
|
||||
* %m = Message
|
||||
*/
|
||||
class DLL_LINKAGE CLogFormatter
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
CLogFormatter();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param pattern The pattern to format the log record with.
|
||||
*/
|
||||
CLogFormatter(const std::string & pattern);
|
||||
|
||||
/**
|
||||
* Formats a log record.
|
||||
*
|
||||
* @param record The log record to format.
|
||||
* @return the formatted log record as a string
|
||||
*/
|
||||
std::string format(const LogRecord & record) const;
|
||||
|
||||
/**
|
||||
* Sets the pattern.
|
||||
*
|
||||
* @param pattern The pattern string which describes how to format the log record.
|
||||
*/
|
||||
void setPattern(const std::string & pattern);
|
||||
|
||||
/**
|
||||
* Gets the pattern.
|
||||
*
|
||||
* @return the pattern string which describes how to format the log record
|
||||
*/
|
||||
const std::string & getPattern() const;
|
||||
|
||||
private:
|
||||
/** The pattern string which describes how to format the log record. */
|
||||
std::string pattern;
|
||||
};
|
51
lib/Logging/CLogManager.cpp
Normal file
51
lib/Logging/CLogManager.cpp
Normal file
@ -0,0 +1,51 @@
|
||||
#include "StdInc.h"
|
||||
#include "CLogManager.h"
|
||||
|
||||
#include "CLogger.h"
|
||||
|
||||
CLogManager * CLogManager::instance = nullptr;
|
||||
|
||||
boost::mutex CLogManager::smx;
|
||||
|
||||
CLogManager * CLogManager::get()
|
||||
{
|
||||
TLockGuard _(smx);
|
||||
if(!instance)
|
||||
{
|
||||
instance = new CLogManager();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
CLogManager::CLogManager()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CLogManager::~CLogManager()
|
||||
{
|
||||
BOOST_FOREACH(auto & i, loggers)
|
||||
{
|
||||
delete i.second;
|
||||
}
|
||||
}
|
||||
|
||||
void CLogManager::addLogger(CGLogger * logger)
|
||||
{
|
||||
TWriteLock _(mx);
|
||||
loggers[logger->getDomain().getName()] = logger;
|
||||
}
|
||||
|
||||
CGLogger * CLogManager::getLogger(const CLoggerDomain & domain)
|
||||
{
|
||||
TReadLock _(mx);
|
||||
auto it = loggers.find(domain.getName());
|
||||
if(it != loggers.end())
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
67
lib/Logging/CLogManager.h
Normal file
67
lib/Logging/CLogManager.h
Normal file
@ -0,0 +1,67 @@
|
||||
|
||||
/*
|
||||
* CLogManager.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
class CGLogger;
|
||||
class CLoggerDomain;
|
||||
|
||||
/**
|
||||
* The log manager is a global storage of all logger objects.
|
||||
*/
|
||||
class DLL_LINKAGE CLogManager : public boost::noncopyable
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Gets an instance of the log manager.
|
||||
*
|
||||
* @return an instance of the log manager
|
||||
*/
|
||||
static CLogManager * get();
|
||||
|
||||
/**
|
||||
* Adds a logger. The log manager holds strong ownership of the logger object.
|
||||
*
|
||||
* @param logger The logger to add.
|
||||
*/
|
||||
void addLogger(CGLogger * logger);
|
||||
|
||||
/**
|
||||
* Gets a logger by domain.
|
||||
*
|
||||
* @param domain The domain of the logger.
|
||||
* @return a logger by domain or nullptr if the logger was not found
|
||||
*/
|
||||
CGLogger * getLogger(const CLoggerDomain & domain);
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~CLogManager();
|
||||
|
||||
private:
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
CLogManager();
|
||||
|
||||
/** The instance of the log manager. */
|
||||
static CLogManager * instance;
|
||||
|
||||
/** The loggers map where the key is the logger name and the value the corresponding logger. */
|
||||
std::map<std::string, CGLogger *> loggers;
|
||||
|
||||
/** The shared mutex for providing synchronous thread-safe access to the log manager. */
|
||||
mutable boost::shared_mutex mx;
|
||||
|
||||
/** The unique mutex for providing thread-safe singleton access. */
|
||||
static boost::mutex smx;
|
||||
};
|
165
lib/Logging/CLogger.cpp
Normal file
165
lib/Logging/CLogger.cpp
Normal file
@ -0,0 +1,165 @@
|
||||
#include "StdInc.h"
|
||||
#include "CLogger.h"
|
||||
#include "LogRecord.h"
|
||||
#include "ILogTarget.h"
|
||||
#include "CLogManager.h"
|
||||
|
||||
boost::mutex CGLogger::smx;
|
||||
|
||||
const std::string CLoggerDomain::DOMAIN_GLOBAL = "global";
|
||||
|
||||
CLoggerDomain::CLoggerDomain(const std::string & name) : name(name)
|
||||
{
|
||||
if(name.empty()) throw std::runtime_error("Logger domain cannot be empty.");
|
||||
}
|
||||
|
||||
CLoggerDomain CLoggerDomain::getParent() const
|
||||
{
|
||||
if(isGlobalDomain()) return *this;
|
||||
|
||||
size_t pos = name.find_last_of(".");
|
||||
if(pos != std::string::npos)
|
||||
{
|
||||
return CLoggerDomain(name.substr(0, pos));
|
||||
}
|
||||
else
|
||||
{
|
||||
return CLoggerDomain(DOMAIN_GLOBAL);
|
||||
}
|
||||
}
|
||||
|
||||
bool CLoggerDomain::isGlobalDomain() const
|
||||
{
|
||||
return name == DOMAIN_GLOBAL;
|
||||
}
|
||||
|
||||
std::string CLoggerDomain::getName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
CGLogger * CGLogger::getLogger(const CLoggerDomain & domain)
|
||||
{
|
||||
TLockGuard _(smx);
|
||||
CGLogger * logger = CLogManager::get()->getLogger(domain);
|
||||
if(logger)
|
||||
{
|
||||
return logger;
|
||||
}
|
||||
else
|
||||
{
|
||||
logger = new CGLogger(domain);
|
||||
if(domain.isGlobalDomain())
|
||||
{
|
||||
logger->setLevel(ELogLevel::INFO);
|
||||
}
|
||||
CLogManager::get()->addLogger(logger);
|
||||
return logger;
|
||||
}
|
||||
}
|
||||
|
||||
CGLogger * CGLogger::getGlobalLogger()
|
||||
{
|
||||
return getLogger(CLoggerDomain::DOMAIN_GLOBAL);
|
||||
}
|
||||
|
||||
CGLogger::CGLogger(const CLoggerDomain & domain) : domain(domain), level(ELogLevel::INFO)
|
||||
{
|
||||
if(!domain.isGlobalDomain())
|
||||
{
|
||||
parent = getLogger(domain.getParent());
|
||||
}
|
||||
}
|
||||
|
||||
CGLogger::~CGLogger()
|
||||
{
|
||||
BOOST_FOREACH(ILogTarget * target, targets)
|
||||
{
|
||||
delete target;
|
||||
}
|
||||
}
|
||||
|
||||
void CGLogger::trace(const std::string & message) const
|
||||
{
|
||||
log(ELogLevel::TRACE, message);
|
||||
}
|
||||
|
||||
void CGLogger::debug(const std::string & message) const
|
||||
{
|
||||
log(ELogLevel::DEBUG, message);
|
||||
}
|
||||
|
||||
void CGLogger::info(const std::string & message) const
|
||||
{
|
||||
log(ELogLevel::INFO, message);
|
||||
}
|
||||
|
||||
void CGLogger::warn(const std::string & message) const
|
||||
{
|
||||
log(ELogLevel::WARN, message);
|
||||
}
|
||||
|
||||
void CGLogger::error(const std::string & message) const
|
||||
{
|
||||
log(ELogLevel::ERROR, message);
|
||||
}
|
||||
|
||||
void CGLogger::log(ELogLevel::ELogLevel level, const std::string & message) const
|
||||
{
|
||||
if(getEffectiveLevel() <= level)
|
||||
{
|
||||
callTargets(LogRecord(domain, level, message));
|
||||
}
|
||||
}
|
||||
|
||||
ELogLevel::ELogLevel CGLogger::getLevel() const
|
||||
{
|
||||
TReadLock _(mx);
|
||||
return level;
|
||||
}
|
||||
|
||||
void CGLogger::setLevel(ELogLevel::ELogLevel level)
|
||||
{
|
||||
TWriteLock _(mx);
|
||||
if(domain.isGlobalDomain() && level == ELogLevel::NOT_SET) return;
|
||||
this->level = level;
|
||||
}
|
||||
|
||||
const CLoggerDomain & CGLogger::getDomain() const
|
||||
{
|
||||
return domain;
|
||||
}
|
||||
|
||||
void CGLogger::addTarget(ILogTarget * target)
|
||||
{
|
||||
TWriteLock _(mx);
|
||||
targets.push_back(target);
|
||||
}
|
||||
|
||||
std::list<ILogTarget *> CGLogger::getTargets() const
|
||||
{
|
||||
TReadLock _(mx);
|
||||
return targets;
|
||||
}
|
||||
|
||||
ELogLevel::ELogLevel CGLogger::getEffectiveLevel() const
|
||||
{
|
||||
for(const CGLogger * logger = this; logger != nullptr; logger = logger->parent)
|
||||
{
|
||||
if(logger->getLevel() != ELogLevel::NOT_SET) return logger->getLevel();
|
||||
}
|
||||
|
||||
// This shouldn't be reached, as the root logger must have set a log level
|
||||
return ELogLevel::INFO;
|
||||
}
|
||||
|
||||
void CGLogger::callTargets(const LogRecord & record) const
|
||||
{
|
||||
for(const CGLogger * logger = this; logger != nullptr; logger = logger->parent)
|
||||
{
|
||||
BOOST_FOREACH(ILogTarget * target, logger->getTargets())
|
||||
{
|
||||
target->write(record);
|
||||
}
|
||||
}
|
||||
}
|
230
lib/Logging/CLogger.h
Normal file
230
lib/Logging/CLogger.h
Normal file
@ -0,0 +1,230 @@
|
||||
|
||||
/*
|
||||
* CLogger.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
class CGLogger;
|
||||
class LogRecord;
|
||||
class ILogTarget;
|
||||
|
||||
namespace ELogLevel
|
||||
{
|
||||
/**
|
||||
* The log level enum holds various log level definitions.
|
||||
*/
|
||||
enum ELogLevel
|
||||
{
|
||||
NOT_SET = 0,
|
||||
TRACE,
|
||||
DEBUG,
|
||||
INFO,
|
||||
WARN,
|
||||
ERROR
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* The logger domain provides convenient access to super domains from a sub domain.
|
||||
*/
|
||||
class DLL_LINKAGE CLoggerDomain
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param domain The domain name. Sub-domains can be specified by separating domains by a dot, e.g. "ai.battle". The global domain is named "global".
|
||||
*/
|
||||
CLoggerDomain(const std::string & name);
|
||||
|
||||
/**
|
||||
* Gets the parent logger domain.
|
||||
*
|
||||
* @return the parent logger domain or the same domain logger if this method has been called on the global domain
|
||||
*/
|
||||
CLoggerDomain getParent() const;
|
||||
|
||||
/**
|
||||
* Returns true if this domain is the global domain.
|
||||
*
|
||||
* @return true if this is the global domain or false if not
|
||||
*/
|
||||
bool isGlobalDomain() const;
|
||||
|
||||
/**
|
||||
* Gets the name of the domain.
|
||||
*
|
||||
* @return the name of the domain
|
||||
*/
|
||||
std::string getName() const;
|
||||
|
||||
/** Constant to the global domain name. */
|
||||
static const std::string DOMAIN_GLOBAL;
|
||||
|
||||
private:
|
||||
/** The domain name. */
|
||||
std::string name;
|
||||
};
|
||||
|
||||
/**
|
||||
* The logger is used to log messages to certain targets of a specific domain/name. Temporary name is
|
||||
* CGLogger, should be renamed to CLogger after refactoring.
|
||||
*/
|
||||
class DLL_LINKAGE CGLogger : public boost::noncopyable
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Gets a logger by domain.
|
||||
*
|
||||
* @param domain The logger domain.
|
||||
* @return the logger object
|
||||
*/
|
||||
static CGLogger * getLogger(const CLoggerDomain & domain);
|
||||
|
||||
/**
|
||||
* Gets the global logger which is the parent of all domain-specific loggers.
|
||||
*
|
||||
* @return the global logger object
|
||||
*/
|
||||
static CGLogger * getGlobalLogger();
|
||||
|
||||
/**
|
||||
* Logs a message with the trace level.
|
||||
*
|
||||
* @param message The message to log.
|
||||
*/
|
||||
void trace(const std::string & message) const;
|
||||
|
||||
/**
|
||||
* Logs a message with the debug level.
|
||||
*
|
||||
* @param message The message to log.
|
||||
*/
|
||||
void debug(const std::string & message) const;
|
||||
|
||||
/**
|
||||
* Logs a message with the info level.
|
||||
*
|
||||
* @param message The message to log.
|
||||
*/
|
||||
void info(const std::string & message) const;
|
||||
|
||||
/**
|
||||
* Logs a message with the warn level.
|
||||
*
|
||||
* @param message The message to log.
|
||||
*/
|
||||
void warn(const std::string & message) const;
|
||||
|
||||
/**
|
||||
* Logs a message with the error level.
|
||||
*
|
||||
* @param message The message to log.
|
||||
*/
|
||||
void error(const std::string & message) const;
|
||||
|
||||
/**
|
||||
* Gets the log level applied for this logger. The default level for the root logger is INFO.
|
||||
*
|
||||
* @return the log level
|
||||
*/
|
||||
inline ELogLevel::ELogLevel getLevel() const;
|
||||
|
||||
/**
|
||||
* Sets the log level.
|
||||
*
|
||||
* @param level The log level.
|
||||
*/
|
||||
void setLevel(ELogLevel::ELogLevel level);
|
||||
|
||||
/**
|
||||
* Gets the logger domain.
|
||||
*
|
||||
* @return the domain of the logger
|
||||
*/
|
||||
const CLoggerDomain & getDomain() const;
|
||||
|
||||
/**
|
||||
* Adds a target to this logger and indirectly to all loggers which derive from this logger.
|
||||
* The logger holds strong-ownership of the target object.
|
||||
*
|
||||
* @param target The log target to add.
|
||||
*/
|
||||
void addTarget(ILogTarget * target);
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~CGLogger();
|
||||
|
||||
private:
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param domain The domain of the logger.
|
||||
*/
|
||||
explicit CGLogger(const CLoggerDomain & domain);
|
||||
|
||||
/**
|
||||
* Gets the parent logger.
|
||||
*
|
||||
* @return the parent logger or nullptr if this is the root logger
|
||||
*/
|
||||
CGLogger * getParent() const;
|
||||
|
||||
/**
|
||||
* Logs a message of the given log level.
|
||||
*
|
||||
* @param level The log level of the message to log.
|
||||
* @param message The message to log.
|
||||
*/
|
||||
inline void log(ELogLevel::ELogLevel level, const std::string & message) const;
|
||||
|
||||
/**
|
||||
* Gets the effective log level.
|
||||
*
|
||||
* @return the effective log level with respect to parent log levels
|
||||
*/
|
||||
inline ELogLevel::ELogLevel getEffectiveLevel() const;
|
||||
|
||||
/**
|
||||
* Calls all targets in the hierarchy to write the message.
|
||||
*
|
||||
* @param record The log record to write.
|
||||
*/
|
||||
inline void callTargets(const LogRecord & record) const;
|
||||
|
||||
/**
|
||||
* Gets all log targets attached to this logger.
|
||||
*
|
||||
* @return all log targets as a list
|
||||
*/
|
||||
inline std::list<ILogTarget *> getTargets() const;
|
||||
|
||||
/** The domain of the logger. */
|
||||
CLoggerDomain domain;
|
||||
|
||||
/** A reference to the parent logger. */
|
||||
CGLogger * parent;
|
||||
|
||||
/** The log level of the logger. */
|
||||
ELogLevel::ELogLevel level;
|
||||
|
||||
/** A list of log targets. */
|
||||
std::list<ILogTarget *> targets;
|
||||
|
||||
/** The shared mutex for providing synchronous thread-safe access to the logger. */
|
||||
mutable boost::shared_mutex mx;
|
||||
|
||||
/** The unique mutex for providing thread-safe get logger access. */
|
||||
static boost::mutex smx;
|
||||
};
|
||||
|
||||
//extern CLogger * logGlobal;
|
31
lib/Logging/ILogTarget.h
Normal file
31
lib/Logging/ILogTarget.h
Normal file
@ -0,0 +1,31 @@
|
||||
|
||||
/*
|
||||
* LogRecord.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
class LogRecord;
|
||||
|
||||
/**
|
||||
* The interface log target is used by all log target implementations. It holds
|
||||
* the abstract method write which sub-classes should implement.
|
||||
*/
|
||||
class DLL_LINKAGE ILogTarget : public boost::noncopyable
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Writes a log record.
|
||||
*
|
||||
* @param record The log record to write.
|
||||
*/
|
||||
virtual void write(const LogRecord & record) = 0;
|
||||
|
||||
virtual ~ILogTarget() { };
|
||||
};
|
44
lib/Logging/LogRecord.h
Normal file
44
lib/Logging/LogRecord.h
Normal file
@ -0,0 +1,44 @@
|
||||
|
||||
/*
|
||||
* LogRecord.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CLogger.h"
|
||||
|
||||
/**
|
||||
* The log records holds the log message and additional logging information.
|
||||
*/
|
||||
struct DLL_LINKAGE LogRecord
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
LogRecord(const CLoggerDomain & domain, ELogLevel::ELogLevel level, const std::string & message)
|
||||
: domain(domain), level(level), message(message), timeStamp(boost::posix_time::second_clock::local_time()), threadId(boost::this_thread::get_id())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/** The logger domain. */
|
||||
CLoggerDomain domain;
|
||||
|
||||
/** The log level. */
|
||||
ELogLevel::ELogLevel level;
|
||||
|
||||
/** The message. */
|
||||
std::string message;
|
||||
|
||||
/** The time when the message was created. */
|
||||
boost::posix_time::ptime timeStamp;
|
||||
|
||||
/** The thread id. */
|
||||
boost::thread::id threadId;
|
||||
};
|
Loading…
Reference in New Issue
Block a user