Initial import

This commit is contained in:
gab 2014-01-25 11:09:04 +02:00
commit 681e40ce46
26 changed files with 1287 additions and 0 deletions

37
ReadMe.txt Normal file
View File

@ -0,0 +1,37 @@
========================================================================
STATIC LIBRARY : c11log Project Overview
========================================================================
AppWizard has created this c11log library project for you.
This file contains a summary of what you will find in each of the files that
make up your c11log application.
c11log.vcxproj
This is the main project file for VC++ projects generated using an Application Wizard.
It contains information about the version of Visual C++ that generated the file, and
information about the platforms, configurations, and project features selected with the
Application Wizard.
c11log.vcxproj.filters
This is the filters file for VC++ projects generated using an Application Wizard.
It contains information about the association between the files in your project
and the filters. This association is used in the IDE to show grouping of files with
similar extensions under a specific node (for e.g. ".cpp" files are associated with the
"Source Files" filter).
/////////////////////////////////////////////////////////////////////////////
StdAfx.h, StdAfx.cpp
These files are used to build a precompiled header (PCH) file
named c11log.pch and a precompiled types file named StdAfx.obj.
/////////////////////////////////////////////////////////////////////////////
Other notes:
AppWizard uses "TODO:" comments to indicate parts of the source code you
should add to or customize.
/////////////////////////////////////////////////////////////////////////////

115
c11log.vcxproj Normal file
View File

@ -0,0 +1,115 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{BBFA8622-1945-4EB0-BAF4-473BE753ED24}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>c11log</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>$(ProjectDir)build\</OutDir>
<TargetName>$(ProjectName)-debug</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>$(ProjectDir)build\</OutDir>
<TargetName>$(ProjectName)</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(ProjectDir);$(ProjectDir)\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>Use</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(ProjectDir);$(ProjectDir)\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<Text Include="ReadMe.txt" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="include\c11log\details\blocking_queue.h" />
<ClInclude Include="include\c11log\details\factory.h" />
<ClInclude Include="include\c11log\details\line_logger.h" />
<ClInclude Include="include\c11log\details\message.h" />
<ClInclude Include="include\c11log\details\null_mutex.h" />
<ClInclude Include="include\c11log\details\os.h" />
<ClInclude Include="include\c11log\details\fast_oss.h" />
<ClInclude Include="include\c11log\formatters\formatters.h" />
<ClInclude Include="include\c11log\level.h" />
<ClInclude Include="include\c11log\logger.h" />
<ClInclude Include="include\c11log\log_exception.h" />
<ClInclude Include="include\c11log\sinks\async_sink.h" />
<ClInclude Include="include\c11log\sinks\base_sink.h" />
<ClInclude Include="include\c11log\sinks\file_sinks.h" />
<ClInclude Include="include\c11log\sinks\stdout_sinks.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="targetver.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\factory.cpp" />
<ClCompile Include="src\formatters.cpp" />
<ClCompile Include="src\line_logger.cpp" />
<ClCompile Include="src\os.cpp" />
<ClCompile Include="stdafx.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

102
c11log.vcxproj.filters Normal file
View File

@ -0,0 +1,102 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
<Filter Include="Header Files\c11log">
<UniqueIdentifier>{3f3d8a51-d799-43e2-bd6e-3638f1cd4f54}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\c11log\sinks">
<UniqueIdentifier>{d087c87d-8703-46a1-aa23-4509cf253e87}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\c11log\details">
<UniqueIdentifier>{5af50a0f-d174-41cd-833c-ead8ba06199a}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\c11log\formatters">
<UniqueIdentifier>{64fe6898-a191-4d60-9363-25ecfd196f30}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<Text Include="ReadMe.txt" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="stdafx.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="targetver.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\c11log\level.h">
<Filter>Header Files\c11log</Filter>
</ClInclude>
<ClInclude Include="include\c11log\logger.h">
<Filter>Header Files\c11log</Filter>
</ClInclude>
<ClInclude Include="include\c11log\details\line_logger.h">
<Filter>Header Files\c11log\details</Filter>
</ClInclude>
<ClInclude Include="include\c11log\formatters\formatters.h">
<Filter>Header Files\c11log\formatters</Filter>
</ClInclude>
<ClInclude Include="include\c11log\sinks\base_sink.h">
<Filter>Header Files\c11log\sinks</Filter>
</ClInclude>
<ClInclude Include="include\c11log\sinks\stdout_sinks.h">
<Filter>Header Files\c11log\sinks</Filter>
</ClInclude>
<ClInclude Include="include\c11log\sinks\file_sinks.h">
<Filter>Header Files\c11log\sinks</Filter>
</ClInclude>
<ClInclude Include="include\c11log\log_exception.h">
<Filter>Header Files\c11log</Filter>
</ClInclude>
<ClInclude Include="include\c11log\details\os.h">
<Filter>Header Files\c11log\details</Filter>
</ClInclude>
<ClInclude Include="include\c11log\details\factory.h">
<Filter>Header Files\c11log\details</Filter>
</ClInclude>
<ClInclude Include="include\c11log\details\null_mutex.h">
<Filter>Header Files\c11log\details</Filter>
</ClInclude>
<ClInclude Include="include\c11log\details\fast_oss.h">
<Filter>Header Files\c11log\details</Filter>
</ClInclude>
<ClInclude Include="include\c11log\details\message.h">
<Filter>Header Files\c11log\details</Filter>
</ClInclude>
<ClInclude Include="include\c11log\sinks\async_sink.h">
<Filter>Header Files\c11log\sinks</Filter>
</ClInclude>
<ClInclude Include="include\c11log\details\blocking_queue.h">
<Filter>Header Files\c11log\details</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\factory.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\formatters.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\os.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\line_logger.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -0,0 +1,64 @@
#pragma once
#include <cstddef>
#include <chrono>
#include <memory>
#include <queue>
#include <mutex>
#include <condition_variable>
namespace c11log {
namespace details {
template<typename T>
class blocking_queue {
public:
explicit blocking_queue(std::size_t max_size) :_max_size(max_size), _q()
{}
blocking_queue(const blocking_queue&) = delete;
blocking_queue& operator=(const blocking_queue&) = delete;
~blocking_queue() = default;
std::size_t size()
{
std::lock_guard<std::mutex> lock(_mutex);
return _q.size();
}
bool push(const T& item, const std::chrono::milliseconds& timeout)
{
std::unique_lock<std::mutex> ul(_mutex);
if (_q.size() >= _max_size) {
if (_item_popped_cond.wait_for(ul, timeout) == std::cv_status::timeout || _q.size() >= _max_size)
return false;
}
_q.push(item);
if (_q.size() <= 1)
_item_pushed_cond.notify_all();
return true;
}
bool pop(T& item, const std::chrono::milliseconds& timeout)
{
std::unique_lock<std::mutex> ul(_mutex);
if (_q.empty()) {
if (_item_pushed_cond.wait_for(ul, timeout) == std::cv_status::timeout || _q.empty())
return false;
}
item = _q.front();
_q.pop();
if (_q.size() >= _max_size - 1)
_item_popped_cond.notify_all();
return true;
}
private:
std::size_t _max_size;
std::queue<T> _q;
std::mutex _mutex;
std::condition_variable _item_pushed_cond;
std::condition_variable _item_popped_cond;
};
}
}

View File

@ -0,0 +1,22 @@
#pragma once
#include <unordered_map>
#include <string>
#include <memory>
#include <mutex>
namespace c11log {
class logger;
namespace details {
class factory {
public:
typedef std::shared_ptr<c11log::logger> logger_ptr;
typedef std::unordered_map<std::string, logger_ptr> logger_map;
logger_ptr get_logger(const std::string &name);
static c11log::details::factory& instance();
private:
logger_map _loggers;
std::mutex _loggers_mutex;
};
}
}

View File

@ -0,0 +1,76 @@
#pragma once
#include<streambuf>
#include<string>
namespace c11log {
namespace details {
class str_devicebuf:public std::streambuf {
public:
str_devicebuf()
{
_str.reserve(128);
}
const std::string& str_ref()
{
return _str;
}
void clear()
{
_str.clear();
}
protected:
virtual int sync() override
{
return 0;
}
virtual std::streamsize xsputn(const char_type* s, std::streamsize count) override
{
_str.append(s, static_cast<unsigned int>(count));
return count;
}
virtual int_type overflow(int_type ch) override
{
if (ch != traits_type::eof())
_str.append((char*)&ch, 1);
return 1;
}
private:
std::string _str;
};
class fast_oss:public std::ostream {
public:
fast_oss():std::ostream(&_dev)
{}
~fast_oss()
{}
const std::string& str_ref() const
{
auto mydevice = static_cast<str_devicebuf*>(rdbuf());
return mydevice->str_ref();
}
const std::string str() const
{
auto mydevice = static_cast<str_devicebuf*>(rdbuf());
return mydevice->str_ref();
}
void clear()
{
auto mydevice = static_cast<str_devicebuf*>(rdbuf());
mydevice->clear();
}
private:
str_devicebuf _dev;
};
}
}

View File

@ -0,0 +1,30 @@
#pragma once
#include "../level.h"
#include "fast_oss.h"
namespace c11log {
class logger;
namespace details {
class line_logger {
public:
c11log::details::line_logger::line_logger(logger* callback_logger, level::level_enum msg_level);
c11log::details::line_logger::line_logger(logger* callback_logger):_callback_logger(nullptr) {};
~line_logger();
template<typename T>
line_logger& operator<<(const T& msg)
{
if (_callback_logger)
_oss << msg;
return *this;
}
private:
logger* _callback_logger;
details::fast_oss _oss;
};
} //Namespace details
} // Namespace c11log

View File

@ -0,0 +1,31 @@
#pragma once
#include <chrono>
#include <string>
#include "../level.h"
namespace c11log {
namespace details {
struct message {
message(const std::string& logger_name,
level::level_enum log_level,
const std::chrono::system_clock::time_point time_p
, const std::string& msg) :
logger_name(logger_name),
log_level(log_level),
time_p(time_p),
msg(msg) {}
~message() = default;
message(const message& other) = default;
message& operator=(const message& rhs) = default;
std::string logger_name;
level::level_enum log_level;
std::chrono::system_clock::time_point time_p;
std::string msg;
};
}
}

View File

@ -0,0 +1,17 @@
#pragma once
namespace c11log{
namespace details{
struct null_mutex
{
void lock()
{}
void unlock()
{}
bool try_lock()
{
return true;
}
};
}
}

View File

@ -0,0 +1,17 @@
#pragma once
#include<string>
#include<cstdio>
#include<ctime>
namespace c11log
{
namespace details
{
namespace os
{
std::tm localtime(const std::time_t &time_t);
std::tm localtime();
}
}
}

View File

@ -0,0 +1,38 @@
#pragma once
#include<string>
#include<chrono>
#include<functional>
#include <sstream>
#include "../level.h"
#include "../details/os.h"
namespace c11log {
namespace formatters {
typedef std::chrono::system_clock::time_point timepoint;
typedef std::function<std::string(const std::string& logger_name, const std::string&, level::level_enum, const timepoint&)> format_fn;
void format_time(const timepoint& tp, std::ostream &dest);
void format_time(std::ostream &dest);
std::string to_hex(const unsigned char* buf, std::size_t size);
class formatter {
public:
formatter() {}
virtual ~formatter() {}
virtual void format_header(const std::string& logger_name, level::level_enum level, const timepoint& tp, std::ostream& dest) = 0;
};
class default_formatter: public formatter {
public:
// Format: [2013-12-29 01:04:42.900] [logger_name:Info] Message body
void format_header(const std::string& logger_name, level::level_enum level, const timepoint& tp, std::ostream& dest) override
{
format_time(tp, dest);
dest << " [" << logger_name << ":" << c11log::level::to_str(level) << "] ";
}
};
} //namespace formatter
} //namespace c11log

24
include/c11log/level.h Normal file
View File

@ -0,0 +1,24 @@
#pragma once
namespace c11log
{
namespace level
{
typedef enum
{
DEBUG,
INFO,
WARNING,
ERROR,
FATAL,
NONE = 99
} level_enum;
const char* to_str(level_enum l);
}
}
static const char* level_names[] { "Debug", "Info", "Warning", "Error", "Fatal" };
inline const char* c11log::level::to_str(c11log::level::level_enum l)
{
return level_names[l];
}

View File

@ -0,0 +1,46 @@
#pragma once
#include <sstream>
#include <iostream>
namespace c11log
{
class log_exception :public std::exception
{
public:
log_exception() : _oss(), _msg()
{}
virtual ~log_exception()
{}
explicit log_exception(const std::string& msg) :_oss(msg, std::ostringstream::ate), _msg(msg)
{}
log_exception(const log_exception &other) :_oss(other._oss.str()), _msg(other._msg)
{}
log_exception& operator=(const log_exception& other)
{
_oss.str(other._oss.str());
_msg = other._msg;
return *this;
}
virtual const char* what() const throw () override
{
return _msg.c_str();
}
template<typename T>
log_exception& operator<<(const T& what)
{
_oss << what;
_msg = _oss.str();
return *this;
}
private:
std::ostringstream _oss;
std::string _msg;
};
}

161
include/c11log/logger.h Normal file
View File

@ -0,0 +1,161 @@
#pragma once
#include<vector>
#include<memory>
#include<mutex>
#include<atomic>
#include <algorithm>
#include "level.h"
#include "sinks/base_sink.h"
#include "details/line_logger.h"
#include "details/factory.h"
namespace c11log {
class logger {
public:
typedef std::shared_ptr<sinks::base_sink> sink_ptr_t;
typedef std::vector<sink_ptr_t> sinks_vector_t;
explicit logger(const std::string& name) : _logger_name(name),
_formatter(std::make_unique<formatters::default_formatter>())
{
_atomic_level.store(level::INFO);
}
~logger()
{
};
logger(const logger&) = delete;
logger& operator=(const logger&) = delete;
void set_name(const std::string& name);
const std::string& get_name();
void add_sink(sink_ptr_t sink_ptr);
void remove_sink(sink_ptr_t sink_ptr);
void set_formatter(std::unique_ptr<formatters::formatter> formatter);
void set_level(c11log::level::level_enum level);
c11log::level::level_enum get_level() const;
bool should_log(c11log::level::level_enum level) const;
details::line_logger log(level::level_enum level);
details::line_logger debug();
details::line_logger info();
details::line_logger warn();
details::line_logger error();
details::line_logger fatal();
private:
friend details::line_logger;
std::string _logger_name = "";
std::unique_ptr<c11log::formatters::formatter> _formatter;
sinks_vector_t _sinks;
std::mutex _mutex;
std::atomic_int _atomic_level;
void _log_it(const std::string& msg);
};
logger& get_logger(const std::string& name);
}
/*
Logger inline impl
*/
inline c11log::details::line_logger c11log::logger::log(c11log::level::level_enum msg_level)
{
if (msg_level >= _atomic_level.load()) {
std::lock_guard<std::mutex> lock(_mutex);
return details::line_logger(this, msg_level);
} else {
return details::line_logger(nullptr);
}
}
inline c11log::details::line_logger c11log::logger::debug()
{
return log(c11log::level::DEBUG);
}
inline c11log::details::line_logger c11log::logger::info()
{
return log(c11log::level::INFO);
}
inline c11log::details::line_logger c11log::logger::warn()
{
return log(c11log::level::WARNING);
}
inline c11log::details::line_logger c11log::logger::error()
{
return log(level::ERROR);
}
inline c11log::details::line_logger c11log::logger::fatal()
{
return log(c11log::level::FATAL);
}
inline void c11log::logger::set_name(const std::string& name)
{
std::lock_guard<std::mutex> lock(_mutex);
_logger_name = name;
}
inline const std::string& c11log::logger::get_name()
{
std::lock_guard<std::mutex> lock(_mutex);
return _logger_name;
}
inline void c11log::logger::add_sink(sink_ptr_t sink_ptr)
{
std::lock_guard<std::mutex> lock(_mutex);
_sinks.push_back(sink_ptr);
}
inline void c11log::logger::remove_sink(sink_ptr_t sink_ptr)
{
std::lock_guard<std::mutex> lock(_mutex);
_sinks.erase(std::remove(_sinks.begin(), _sinks.end(), sink_ptr), _sinks.end());
}
inline void c11log::logger::set_formatter(std::unique_ptr<formatters::formatter> formatter)
{
std::lock_guard<std::mutex> lock(_mutex);
_formatter = std::move(formatter);
}
inline void c11log::logger::set_level(c11log::level::level_enum level)
{
_atomic_level.store(level);
}
inline c11log::level::level_enum c11log::logger::get_level() const
{
return static_cast<c11log::level::level_enum>(_atomic_level.load());
}
inline bool c11log::logger::should_log(c11log::level::level_enum level) const
{
return level >= _atomic_level.load();
}
inline void c11log::logger::_log_it(const std::string& msg)
{
level::level_enum level = static_cast<level::level_enum>(_atomic_level.load());
std::lock_guard<std::mutex> lock(_mutex);
for (auto &sink : _sinks)
sink->log(msg, level);
}
inline c11log::logger& c11log::get_logger(const std::string& name)
{
return *(c11log::details::factory::instance().get_logger(name));
}

View File

@ -0,0 +1,55 @@
#pragma once
#include <mutex>
#include <queue>
#include <thread>
#include <iostream>
#include "../logger.h"
#include "base_sink.h"
namespace c11log {
namespace sinks {
class async_sink : base_sink {
enum class fullq_policy {
BLOCK=0,
DROP_MSG
};
public:
async_sink(std::size_t max_queue_size, fullq_policy q_policy) :_fullq_policy(q_policy), _back_thread(&_thread_loop)
{
}
protected:
void _sink_it(const std::string& msg) override
{
_msgs_mutex.unlock();
_msgs.push(msg);
}
void _thread_loop()
{
while (_active) {
_msgs_mutex.lock();
std::string &msg = _msgs.front();
_msgs.pop();
_msgs_mutex.unlock();
std::cout << "Popped: " << msg << std::endl;
}
}
private:
c11log::logger::sinks_vector_t _sinks;
fullq_policy _fullq_policy;
std::queue<std::string> _msgs;
std::thread _back_thread;
bool _active = true;
std::mutex _msgs_mutex;
};
}
}
void c11log::sinks::async_sink::_sink_it(const std::string& msg)
{
}

View File

@ -0,0 +1,50 @@
#pragma once
#include<string>
#include<memory>
#include<mutex>
#include "../formatters/formatters.h"
#include "../level.h"
namespace c11log {
namespace sinks {
class base_sink {
public:
base_sink()
{}
base_sink(level::level_enum l):_level(l)
{};
virtual ~base_sink()
{};
base_sink(const base_sink&) = delete;
base_sink& operator=(const base_sink&) = delete;
void log(const std::string &msg, level::level_enum level)
{
if (level >= _level) {
std::lock_guard<std::mutex> lock(_mutex);
if (level >= _level)
_sink_it(msg);
}
};
void set_level(level::level_enum level)
{
std::lock_guard<std::mutex> lock(_mutex);
_level = level;
}
protected:
virtual void _sink_it(const std::string& msg) = 0;
level::level_enum _level = level::INFO;
std::mutex _mutex;
};
class null_sink:public base_sink {
protected:
void _sink_it(const std::string& msg) override
{}
};
}
}

View File

@ -0,0 +1,174 @@
#pragma once
#include <fstream>
#include <iomanip>
#include "../logger.h"
#include "../log_exception.h"
#include "../details/os.h"
#include "base_sink.h"
namespace c11log {
namespace sinks {
/*
* Trivial file sink with single file as target
*/
class simple_file_sink:base_sink {
public:
simple_file_sink(const std::string &filename, const std::string& extension = "txt")
{
std::ostringstream oss;
oss << filename << "." << extension;
_ofstream.open(oss.str(), std::ofstream::app);
}
protected:
void _sink_it(const std::string& msg) override
{
_ofstream << msg;
_ofstream.flush();
}
std::ofstream _ofstream;
};
/*
* Rotating file sinks. Close and open new file at some point
*/
namespace details {
class rotating_file_sink_base:public base_sink {
public:
rotating_file_sink_base()
{}
virtual ~rotating_file_sink_base()
{}
protected:
virtual void _sink_it(const std::string& msg) override
{
if (_should_rotate())
_rotate();
_ofstream << msg;
_ofstream.flush();
}
virtual bool _should_rotate() const = 0;
virtual void _rotate() = 0;
std::ofstream _ofstream;
};
}
class rotating_file_sink:public details::rotating_file_sink_base {
public:
rotating_file_sink(const std::string &base_filename, const std::string &extension, size_t max_size, size_t max_files):
_base_filename(base_filename),
_extension(extension),
_max_size(max_size),
_max_files(max_files),
_current_size(0),
_index(0)
{
_ofstream.open(_calc_filename(_base_filename, 0, _extension));
}
protected:
virtual void _sink_it(const std::string& msg) override
{
_current_size += msg.length();
rotating_file_sink_base::_sink_it(msg);
}
bool _should_rotate() const override
{
return _current_size >= _max_size;
}
// Rotate old files:
// log.n-1.txt -> log.n.txt
// log n-2.txt -> log.n-1.txt
// ...
// log.txt -> log.1.txt
void _rotate() override
{
_ofstream.close();
_current_size = 0;
//Remove oldest file
for (auto i = _max_files; i > 0; --i) {
auto src = _calc_filename(_base_filename, i - 1, _extension);
auto target = _calc_filename(_base_filename, i, _extension);
if (i == _max_files)
std::remove(target.c_str());
std::rename(src.c_str(), target.c_str());
}
_ofstream.open(_calc_filename(_base_filename, 0, _extension));
}
private:
static std::string _calc_filename(const std::string& filename, std::size_t index, const std::string& extension)
{
std::ostringstream oss;
if (index)
oss << filename << "." << index << "." << extension;
else
oss << filename << "." << extension;
return oss.str();
}
std::string _base_filename;
std::string _extension;
std::size_t _max_size;
std::size_t _max_files;
std::size_t _current_size;
std::size_t _index;
};
/*
* File sink that closes the log file at midnight and opens new one
*/
class midnight_file_sink:public details::rotating_file_sink_base {
public:
midnight_file_sink(const std::string& base_filename, const std::string& extension):
_base_filename(base_filename),
_extension(extension),
_midnight_tp { _calc_midnight_tp() }
{
_ofstream.open(_calc_filename(_base_filename, _extension));
}
protected:
bool _should_rotate() const override
{
return std::chrono::system_clock::now() >= _midnight_tp;
}
void _rotate() override
{
_midnight_tp = _calc_midnight_tp();
_ofstream.close();
_ofstream.open(_calc_filename(_base_filename, _extension));
}
private:
// Return next midnight's time_point
static std::chrono::system_clock::time_point _calc_midnight_tp()
{
using namespace std::chrono;
auto now = system_clock::now();
time_t tnow = std::chrono::system_clock::to_time_t(now);
tm date = c11log::details::os::localtime(tnow);
date.tm_hour = date.tm_min = date.tm_sec = 0;
auto midnight = std::chrono::system_clock::from_time_t(std::mktime(&date));
return system_clock::time_point(midnight + hours(24));
}
static std::string _calc_filename(const std::string& basename, const std::string& extension)
{
std::ostringstream oss;
std::tm now_tm = c11log::details::os::localtime();
oss << basename << std::put_time(&now_tm, ".%Y-%m-%d.") << extension;
return oss.str();
}
std::string _base_filename;
std::string _extension;
std::chrono::system_clock::time_point _midnight_tp;
};
}
}

View File

@ -0,0 +1,41 @@
#include <iostream>
#include "base_sink.h"
namespace c11log
{
namespace sinks
{
class ostream_sink:public base_sink
{
public:
ostream_sink(std::ostream& os):_ostream(os)
{}
virtual ~ostream_sink()
{}
protected:
virtual void _sink_it(const std::string& msg)
{
_ostream << msg;
}
std::ostream& _ostream;
};
class stdout_sink:public ostream_sink
{
public:
stdout_sink():ostream_sink(std::cout)
{}
};
class stderr_sink:public ostream_sink
{
public:
stderr_sink():ostream_sink(std::cerr)
{}
};
}
}

23
src/factory.cpp Normal file
View File

@ -0,0 +1,23 @@
#include "stdafx.h"
#include "c11log/details/factory.h"
#include "c11log/logger.h"
c11log::details::factory::logger_ptr c11log::details::factory::get_logger(const std::string &name)
{
std::lock_guard<std::mutex> lock(_loggers_mutex);
auto found = _loggers.find(name);
if (found == _loggers.end()) {
auto new_logger_ptr = std::make_shared<c11log::logger>(name);
_loggers.insert(std::make_pair(name, new_logger_ptr));
return new_logger_ptr;
}
else {
return found->second;
}
}
c11log::details::factory & c11log::details::factory::instance()
{
static c11log::details::factory instance;
return instance;
}

36
src/formatters.cpp Normal file
View File

@ -0,0 +1,36 @@
#include "stdafx.h"
#include "c11log/formatters/formatters.h"
#include "c11log/level.h"
void c11log::formatters::format_time(const c11log::formatters::timepoint& tp, std::ostream &dest)
{
std::tm tm = details::os::localtime(std::chrono::system_clock::to_time_t(tp));
//get ms
auto duration = tp.time_since_epoch();
int millis = static_cast<int>(std::chrono::duration_cast<std::chrono::milliseconds>(duration).count() % 1000);
//std::put_time(&tm, "[ %Y-%m-%d %H:%M:%S ]") - seems too slow
char buf[64];
sprintf(buf, "[%d-%02d-%02d %02d:%02d:%02d.%03d]",
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec, millis);
dest << buf;
}
void c11log::formatters::format_time(std::ostream& dest)
{
return format_time(std::chrono::system_clock::now(), dest);
}
static const char _hex_chars[17] = "0123456789ABCDEF";
std::string c11log::formatters::to_hex(const unsigned char* buf, std::size_t size)
{
std::ostringstream oss;
for (std::size_t i = 0; i < size; i++) {
oss << _hex_chars[buf[i] >> 4];
oss << _hex_chars[buf[i] & 0x0F];
}
return oss.str();
}

21
src/line_logger.cpp Normal file
View File

@ -0,0 +1,21 @@
#include "stdafx.h"
#include "c11log/logger.h"
c11log::details::line_logger::line_logger(logger* callback_logger, level::level_enum msg_level) :
_callback_logger(callback_logger)
{
if (callback_logger) {
callback_logger->_formatter->format_header(callback_logger->_logger_name,
msg_level,
c11log::formatters::timepoint::clock::now(),
_oss);
}
}
c11log::details::line_logger::~line_logger()
{
if (_callback_logger) {
_oss << '\n';
_callback_logger->_log_it(_oss.str_ref());
}
}

51
src/logger.cpp Normal file
View File

@ -0,0 +1,51 @@
#include "stdafx.h"
#include <algorithm>
#include "c11log/logger.h"
void c11log::logger::set_name(const std::string& name)
{
std::lock_guard<std::mutex> lock(_mutex);
_logger_name = name;
}
const std::string& c11log::logger::get_name()
{
std::lock_guard<std::mutex> lock(_mutex);
return _logger_name;
}
void c11log::logger::add_sink(sink_ptr_t sink_ptr)
{
std::lock_guard<std::mutex> lock(_mutex);
_sinks.push_back(sink_ptr);
}
void c11log::logger::remove_sink(sink_ptr_t sink_ptr)
{
std::lock_guard<std::mutex> lock(_mutex);
_sinks.erase(std::remove(_sinks.begin(), _sinks.end(), sink_ptr), _sinks.end());
}
void c11log::logger::set_formatter(std::unique_ptr<formatters::formatter> formatter)
{
std::lock_guard<std::mutex> lock(_mutex);
_formatter = std::move(formatter);
}
void c11log::logger::set_level(c11log::level::level_enum level)
{
std::lock_guard<std::mutex> lock(_mutex);
_level = level;
}
bool c11log::logger::should_log(c11log::level::level_enum level)
{
std::lock_guard<std::mutex> lock(_mutex);
return level >= _level;
}
c11log::logger& c11log::get_logger(const std::string& name)
{
return *(c11log::details::factory::instance().get_logger(name));
}

24
src/os.cpp Normal file
View File

@ -0,0 +1,24 @@
#include "stdafx.h"
#include "c11log/details/os.h"
namespace c11log {
namespace details {
namespace os {
std::tm localtime(const std::time_t &time_t)
{
#ifdef _MSC_VER
std::tm tm;
localtime_s(&tm, &time_t);
return tm;
#endif
}
std::tm localtime()
{
std::time_t now_t = time(0);
return localtime(now_t);
}
}
}
}

8
stdafx.cpp Normal file
View File

@ -0,0 +1,8 @@
// stdafx.cpp : source file that includes just the standard includes
// c11log.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information
#include "stdafx.h"
// TODO: reference any additional headers you need in STDAFX.H
// and not in this file

16
stdafx.h Normal file
View File

@ -0,0 +1,16 @@
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#pragma once
#include "targetver.h"
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#include <string>
#include <chrono>
#include <ctime>
#include <memory>
#include <iostream>

8
targetver.h Normal file
View File

@ -0,0 +1,8 @@
#pragma once
// Including SDKDDKVer.h defines the highest available Windows platform.
// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
#include <SDKDDKVer.h>