Add logging library
This commit is contained in:
parent
8037f5a2f6
commit
24613010c8
5 changed files with 160 additions and 1 deletions
8
libs/log/CMakeLists.txt
Normal file
8
libs/log/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
find_package(Threads)
|
||||
|
||||
file(GLOB_RECURSE PSEMEK_LOG_HEADERS RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "include/*.hpp")
|
||||
file(GLOB_RECURSE PSEMEK_LOG_SOURCES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "source/*.cpp")
|
||||
|
||||
add_library(log ${PSEMEK_LOG_HEADERS} ${PSEMEK_LOG_SOURCES})
|
||||
target_include_directories(log PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include")
|
||||
target_link_libraries(log PUBLIC ${CMAKE_THREAD_LIBS_INIT})
|
||||
27
libs/log/include/psemek/log/level.hpp
Normal file
27
libs/log/include/psemek/log/level.hpp
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
#pragma once
|
||||
|
||||
namespace psemek::log
|
||||
{
|
||||
|
||||
enum class level
|
||||
{
|
||||
debug,
|
||||
info,
|
||||
warning,
|
||||
error,
|
||||
};
|
||||
|
||||
template <typename Stream>
|
||||
Stream & operator << (Stream & s, level l)
|
||||
{
|
||||
switch (l)
|
||||
{
|
||||
case level::debug: return s << "debug";
|
||||
case level::info: return s << "info";
|
||||
case level::warning: return s << "warning";
|
||||
case level::error: return s << "error";
|
||||
default: return s << "(unknown)";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
47
libs/log/include/psemek/log/log.hpp
Normal file
47
libs/log/include/psemek/log/log.hpp
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
#pragma once
|
||||
|
||||
#include <psemek/log/level.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <sstream>
|
||||
|
||||
namespace psemek::log
|
||||
{
|
||||
|
||||
void set_max_thread_name_length(int length);
|
||||
|
||||
void register_thread(std::string name);
|
||||
void register_thread(std::thread::id id, std::string name);
|
||||
|
||||
void put_message(level l, std::string const & message);
|
||||
|
||||
struct log_stream
|
||||
{
|
||||
log_stream(level l)
|
||||
: l_(l)
|
||||
{}
|
||||
|
||||
~log_stream()
|
||||
{
|
||||
put_message(l_, os_.str());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
log_stream & operator << (T const & x)
|
||||
{
|
||||
os_ << x;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
level l_;
|
||||
std::ostringstream os_;
|
||||
};
|
||||
|
||||
inline log_stream debug() { return {level::debug}; }
|
||||
inline log_stream info() { return {level::info}; }
|
||||
inline log_stream warning() { return {level::warning}; }
|
||||
inline log_stream error() { return {level::error}; }
|
||||
|
||||
}
|
||||
78
libs/log/source/log.cpp
Normal file
78
libs/log/source/log.cpp
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
#include <psemek/log/log.hpp>
|
||||
|
||||
#include <chrono>
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
#include <thread>
|
||||
|
||||
namespace psemek::log
|
||||
{
|
||||
|
||||
static int max_thread_name_length = 5;
|
||||
|
||||
void set_max_thread_name_length(int length)
|
||||
{
|
||||
max_thread_name_length = length;
|
||||
}
|
||||
|
||||
static std::unordered_map<std::thread::id, std::string> thread_names;
|
||||
|
||||
void register_thread(std::string name)
|
||||
{
|
||||
register_thread(std::this_thread::get_id(), std::move(name));
|
||||
}
|
||||
|
||||
void register_thread(std::thread::id id, std::string name)
|
||||
{
|
||||
auto it = thread_names.find(id);
|
||||
if (it != thread_names.end())
|
||||
throw std::runtime_error("Thread \"" + name + "\" already registered!");
|
||||
|
||||
if (name.size() > max_thread_name_length)
|
||||
throw std::runtime_error("Thread \"" + name + "\" name is too long");
|
||||
|
||||
thread_names[id] = name;
|
||||
|
||||
put_message(level::info, "Thread \"" + name + "\" registered");
|
||||
}
|
||||
|
||||
static ::tm safe_localtime(std::time_t const & time)
|
||||
{
|
||||
static std::mutex mutex;
|
||||
std::lock_guard lock{mutex};
|
||||
return *std::localtime(&time);
|
||||
}
|
||||
|
||||
void put_message(level l, std::string const & message)
|
||||
{
|
||||
static std::string unknown_thread_name = "???";
|
||||
|
||||
using clock = std::chrono::system_clock;
|
||||
|
||||
auto const time = clock::to_time_t(clock::now());
|
||||
auto const tm = safe_localtime(time);
|
||||
|
||||
auto const millis = std::chrono::duration_cast<std::chrono::milliseconds>(clock::now().time_since_epoch()).count() % 1000;
|
||||
|
||||
auto const id = std::this_thread::get_id();
|
||||
auto const it = thread_names.find(id);
|
||||
|
||||
auto const & thread_name = (it == thread_names.end()) ? unknown_thread_name : it->second;
|
||||
|
||||
std::ostringstream os;
|
||||
os
|
||||
<< '[' << std::put_time(&tm, "%Y %b %d %H:%M:%S.") << std::setw(3) << std::setfill('0') << millis << ']'
|
||||
<< '[' << std::setw(max_thread_name_length) << std::setfill(' ') << thread_name << ']'
|
||||
<< '[' << std::setw(7) << l << ']'
|
||||
<< ' ' << message;
|
||||
|
||||
static std::mutex cout_mutex;
|
||||
std::lock_guard lock{cout_mutex};
|
||||
std::cout << os.str() << std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
1
todo.md
1
todo.md
|
|
@ -4,5 +4,4 @@
|
|||
* Implement pixmap font rendering
|
||||
* Create a simple generic primive painter
|
||||
* Design resources system
|
||||
* Design logging system
|
||||
* Design ui system
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue