Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
submodules: true
- run: git submodule update --init --recursive
- name: Configure
run: cmake -S . -B build -DLOG_IT_CPP_BUILD_TESTS=ON -DCMAKE_CXX_STANDARD=${{ matrix.std }}
run: cmake -S . -B build -DLOG_IT_CPP_BUILD_TESTS=ON -DCMAKE_CXX_STANDARD=${{ matrix.std }} -DLOGIT_WITH_SYSLOG=ON -DLOGIT_WITH_WIN_EVENT_LOG=OFF
- name: Build
run: cmake --build build
- name: Install
Expand All @@ -41,7 +41,7 @@ jobs:
submodules: true
- run: git submodule update --init --recursive
- name: Configure
run: cmake -S . -B build -DLOG_IT_CPP_BUILD_TESTS=ON -DCMAKE_CXX_STANDARD=${{ matrix.std }}
run: cmake -S . -B build -DLOG_IT_CPP_BUILD_TESTS=ON -DCMAKE_CXX_STANDARD=${{ matrix.std }} -DLOGIT_WITH_SYSLOG=OFF -DLOGIT_WITH_WIN_EVENT_LOG=ON
- name: Build
run: cmake --build build --config Release
- name: Install
Expand All @@ -64,7 +64,7 @@ jobs:
submodules: true
- run: git submodule update --init --recursive
- name: Configure
run: cmake -S . -B build -DLOG_IT_CPP_BUILD_TESTS=ON -DCMAKE_CXX_STANDARD=${{ matrix.std }}
run: cmake -S . -B build -DLOG_IT_CPP_BUILD_TESTS=ON -DCMAKE_CXX_STANDARD=${{ matrix.std }} -DLOGIT_WITH_SYSLOG=ON -DLOGIT_WITH_WIN_EVENT_LOG=OFF
- name: Build
run: cmake --build build
- name: Install
Expand Down
11 changes: 11 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ option(LOG_IT_CPP_BUILD_EXAMPLES "Build log-it-cpp examples" OFF)
option(LOGIT_WITH_GZIP "Enable gzip via zlib" OFF)
option(LOGIT_WITH_ZSTD "Enable zstd" OFF)
option(LOGIT_USE_SUBMODULES "Allow bundled third_party fallback" OFF)
option(LOGIT_WITH_SYSLOG "Enable POSIX syslog backend" ON)
option(LOGIT_WITH_WIN_EVENT_LOG "Enable Windows Event Log backend" ON)

if(NOT DEFINED CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 11)
Expand Down Expand Up @@ -33,6 +35,15 @@ target_include_directories(log-it-cpp INTERFACE

target_link_libraries(log-it-cpp INTERFACE time_shield::time_shield)

if(LOGIT_WITH_SYSLOG AND (UNIX OR APPLE) AND NOT EMSCRIPTEN)
target_compile_definitions(log-it-cpp INTERFACE LOGIT_HAS_SYSLOG=1)
endif()

if(LOGIT_WITH_WIN_EVENT_LOG AND WIN32)
target_compile_definitions(log-it-cpp INTERFACE LOGIT_HAS_WIN_EVENT_LOG=1)
target_link_libraries(log-it-cpp INTERFACE advapi32)
endif()

# ---------- GZIP (zlib) ----------
if(LOGIT_WITH_GZIP)
if(NOT TARGET ZLIB::ZLIB)
Expand Down
30 changes: 29 additions & 1 deletion README-RU.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,11 @@ LOGIT_ADD_FILE_LOGGER_DEFAULT();
LOGIT_ADD_UNIQUE_FILE_LOGGER_DEFAULT_SINGLE_MODE();
```

- **Асинхронное логирование**:
- **Системные бэкенды**:

Использование системных журналов: `SyslogLogger` для POSIX `syslog` и `EventLogLogger` для Windows Event Log.

- **Асинхронное логирование**:

Улучшите производительность приложения с помощью асинхронного логирования. Все логгеры по умолчанию обрабатывают сообщения в отдельном потоке.

Expand Down Expand Up @@ -486,6 +490,30 @@ LogIt++ поддерживает библиотеку *fmt* для продви
#define LOGIT_USE_FMT_LIB
```

## Системные бэкенды

LogIt++ может отправлять сообщения в системные журналы.

### Syslog (Unix)

Доступен при `LOGIT_WITH_SYSLOG=ON` на Unix-подобных системах. Соответствие уровней: TRACE/DEBUG → `LOG_DEBUG`, INFO → `LOG_INFO`, WARN → `LOG_WARNING`, ERROR/FATAL → `LOG_ERR`/`LOG_CRIT`.

```cpp
LOGIT_ADD_SYSLOG_DEFAULT();
LOGIT_INFO("Syslog работает");
```

### Windows Event Log

Работает при `LOGIT_WITH_WIN_EVENT_LOG=ON` в Windows. Уровни: TRACE/DEBUG/INFO → `INFORMATION`, WARN → `WARNING`, ERROR/FATAL → `ERROR`.

```cpp
LOGIT_ADD_EVENT_LOG_DEFAULT();
LOGIT_ERROR("Что-то пошло не так");
```

На неподдерживаемых платформах оба логгера компилируются в заглушки.

### Emscripten

При сборке с Emscripten библиотека работает в однопоточном режиме. ConsoleLogger
Expand Down
30 changes: 29 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,11 @@ LOGIT_ADD_FILE_LOGGER_DEFAULT();
LOGIT_ADD_UNIQUE_FILE_LOGGER_DEFAULT_SINGLE_MODE();
```

- **Asynchronous Logging**:
- **System Backends**:

Use the host OS logging facility. `SyslogLogger` works with POSIX `syslog`, while `EventLogLogger` writes to the Windows Event Log.

- **Asynchronous Logging**:

Improve application performance with asynchronous logging. All loggers handle messages in a separate thread by default.

Expand Down Expand Up @@ -498,6 +502,30 @@ LogIt++ supports the *fmt* library for advanced string formatting, which is also
#define LOGIT_USE_FMT_LIB
```

## System Backends

LogIt++ can forward messages to system logging facilities.

### Syslog (Unix)

Available when `LOGIT_WITH_SYSLOG=ON` on Unix-like systems. Log levels are mapped as follows: TRACE/DEBUG → `LOG_DEBUG`, INFO → `LOG_INFO`, WARN → `LOG_WARNING`, ERROR/FATAL → `LOG_ERR`/`LOG_CRIT`.

```cpp
LOGIT_ADD_SYSLOG_DEFAULT();
LOGIT_INFO("Syslog is alive");
```

### Windows Event Log

Enabled with `LOGIT_WITH_WIN_EVENT_LOG=ON` on Windows. Levels map TRACE/DEBUG/INFO → `INFORMATION`, WARN → `WARNING`, ERROR/FATAL → `ERROR`.

```cpp
LOGIT_ADD_EVENT_LOG_DEFAULT();
LOGIT_ERROR("Something went wrong");
```

Both loggers compile to no-ops on unsupported platforms.

### Emscripten

When building with Emscripten the library runs without threads. Console logging
Expand Down
52 changes: 52 additions & 0 deletions include/logit_cpp/logit/LogMacros.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -994,6 +994,30 @@ static_assert(LOGIT_LEVEL_FATAL == static_cast<int>(logit::LogLevel::LOG_LVL_FAT
std::make_unique<logit::SimpleLogFormatter>(LOGIT_UNIQUE_FILE_LOGGER_PATTERN), \
true)

#define LOGIT_ADD_SYSLOG(ident, facility, async) \
logit::Logger::get_instance().add_logger( \
std::make_unique<logit::SyslogLogger>(ident, facility, async), \
std::make_unique<logit::SimpleLogFormatter>(LOGIT_CONSOLE_PATTERN), false)

#define LOGIT_ADD_SYSLOG_SINGLE_MODE(ident, facility, async) \
logit::Logger::get_instance().add_logger( \
std::make_unique<logit::SyslogLogger>(ident, facility, async), \
std::make_unique<logit::SimpleLogFormatter>(LOGIT_CONSOLE_PATTERN), true)

#define LOGIT_ADD_SYSLOG_DEFAULT() LOGIT_ADD_SYSLOG("log-it", LOG_USER, true)

#define LOGIT_ADD_EVENT_LOG(source_wide, async) \
logit::Logger::get_instance().add_logger( \
std::make_unique<logit::EventLogLogger>(source_wide, async), \
std::make_unique<logit::SimpleLogFormatter>(LOGIT_CONSOLE_PATTERN), false)

#define LOGIT_ADD_EVENT_LOG_SINGLE_MODE(source_wide, async) \
logit::Logger::get_instance().add_logger( \
std::make_unique<logit::EventLogLogger>(source_wide, async), \
std::make_unique<logit::SimpleLogFormatter>(LOGIT_CONSOLE_PATTERN), true)

#define LOGIT_ADD_EVENT_LOG_DEFAULT() LOGIT_ADD_EVENT_LOG(L"LogIt", true)

#else // C++11 fallback

/// \brief Macro for adding a logger with a specific formatter.
Expand Down Expand Up @@ -1185,6 +1209,34 @@ static_assert(LOGIT_LEVEL_FATAL == static_cast<int>(logit::LogLevel::LOG_LVL_FAT
std::unique_ptr<logit::SimpleLogFormatter>(new logit::SimpleLogFormatter(LOGIT_UNIQUE_FILE_LOGGER_PATTERN)), \
true)

#define LOGIT_ADD_SYSLOG(ident, facility, async) \
logit::Logger::get_instance().add_logger( \
std::unique_ptr<logit::SyslogLogger>(new logit::SyslogLogger(ident, facility, async)), \
std::unique_ptr<logit::SimpleLogFormatter>(new logit::SimpleLogFormatter(LOGIT_CONSOLE_PATTERN)), \
false)

#define LOGIT_ADD_SYSLOG_SINGLE_MODE(ident, facility, async) \
logit::Logger::get_instance().add_logger( \
std::unique_ptr<logit::SyslogLogger>(new logit::SyslogLogger(ident, facility, async)), \
std::unique_ptr<logit::SimpleLogFormatter>(new logit::SimpleLogFormatter(LOGIT_CONSOLE_PATTERN)), \
true)

#define LOGIT_ADD_SYSLOG_DEFAULT() LOGIT_ADD_SYSLOG("log-it", LOG_USER, true)

#define LOGIT_ADD_EVENT_LOG(source_wide, async) \
logit::Logger::get_instance().add_logger( \
std::unique_ptr<logit::EventLogLogger>(new logit::EventLogLogger(source_wide, async)), \
std::unique_ptr<logit::SimpleLogFormatter>(new logit::SimpleLogFormatter(LOGIT_CONSOLE_PATTERN)), \
false)

#define LOGIT_ADD_EVENT_LOG_SINGLE_MODE(source_wide, async) \
logit::Logger::get_instance().add_logger( \
std::unique_ptr<logit::EventLogLogger>(new logit::EventLogLogger(source_wide, async)), \
std::unique_ptr<logit::SimpleLogFormatter>(new logit::SimpleLogFormatter(LOGIT_CONSOLE_PATTERN)), \
true)

#define LOGIT_ADD_EVENT_LOG_DEFAULT() LOGIT_ADD_EVENT_LOG(L"LogIt", true)

#endif // C++ version check

/// \name Logger Management
Expand Down
3 changes: 3 additions & 0 deletions include/logit_cpp/logit/loggers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,8 @@
#include "loggers/ConsoleLogger.hpp"
#include "loggers/FileLogger.hpp"
#include "loggers/UniqueFileLogger.hpp"
#include "loggers/SyslogLogger.hpp"
#include "loggers/EventLogLogger.hpp"
#include "loggers/SystemLogger.hpp"

#endif // _LOGIT_LOGGERS_HPP_INCLUDED
99 changes: 99 additions & 0 deletions include/logit_cpp/logit/loggers/EventLogLogger.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
#pragma once
#ifndef LOGIT_EVENT_LOG_LOGGER_HPP_INCLUDED
#define LOGIT_EVENT_LOG_LOGGER_HPP_INCLUDED

#include "ILogger.hpp"
#include <atomic>
#include <string>

#if defined(_WIN32) && defined(LOGIT_HAS_WIN_EVENT_LOG)
#include <windows.h>
#define LOGIT_WIN_EVENT_ENABLED 1
#else
#define LOGIT_WIN_EVENT_ENABLED 0
#endif

namespace logit {

#if LOGIT_WIN_EVENT_ENABLED

class EventLogLogger : public ILogger {
public:
struct Config {
const wchar_t* source;
bool async;
Config(const wchar_t* s = L"LogIt", bool a = true) : source(s), async(a) {}
};
EventLogLogger() : EventLogLogger(Config()) {}
explicit EventLogLogger(const Config& c) : cfg(c) {
hsrc = RegisterEventSourceW(nullptr, cfg.source);
}
EventLogLogger(const wchar_t* source, bool async) : EventLogLogger(Config(source, async)) {}
~EventLogLogger() override { if (hsrc) DeregisterEventSource(hsrc); }

void log(const LogRecord& rec, const std::string& msg) override {
LogLevel lvl = rec.log_level;
std::string s = msg;
auto task = [this, lvl, s]() {
if ((int)lvl < level.load()) return;
if (!hsrc) return;
WORD type = map(lvl);
int n = MultiByteToWideChar(CP_UTF8, 0, s.c_str(), (int)s.size(), nullptr, 0);
std::wstring wmsg; wmsg.resize(n);
MultiByteToWideChar(CP_UTF8, 0, s.c_str(), (int)s.size(), &wmsg[0], n);
LPCWSTR arr[1] = { wmsg.c_str() };
ReportEventW(hsrc, type, 0, 0, nullptr, 1, 0, arr, nullptr);
};
if (cfg.async) { detail::TaskExecutor::get_instance().add_task(task); }
else { task(); }
last_ts.store(rec.timestamp_ms);
}

std::string get_string_param(const LoggerParam&) const override { return {}; }
int64_t get_int_param(const LoggerParam&) const override { return 0; }
double get_float_param(const LoggerParam&) const override { return 0.0; }
void set_log_level(LogLevel l) override { level.store((int)l); }
LogLevel get_log_level() const override { return (LogLevel)level.load(); }
void wait() override { if (cfg.async) detail::TaskExecutor::get_instance().wait(); }

private:
static WORD map(LogLevel l) {
switch (l) {
case LogLevel::LOG_LVL_TRACE:
case LogLevel::LOG_LVL_DEBUG:
case LogLevel::LOG_LVL_INFO: return EVENTLOG_INFORMATION_TYPE;
case LogLevel::LOG_LVL_WARN: return EVENTLOG_WARNING_TYPE;
case LogLevel::LOG_LVL_ERROR: return EVENTLOG_ERROR_TYPE;
case LogLevel::LOG_LVL_FATAL: return EVENTLOG_ERROR_TYPE;
} return EVENTLOG_INFORMATION_TYPE;
}
Config cfg{};
HANDLE hsrc = nullptr;
std::atomic<int> level{(int)LogLevel::LOG_LVL_TRACE};
std::atomic<int64_t> last_ts{0};
};

#else // stub
class EventLogLogger : public ILogger {
public:
struct Config {
const wchar_t* source;
bool async;
Config(const wchar_t* s = L"", bool a = false) : source(s), async(a) {}
};
EventLogLogger() {}
explicit EventLogLogger(const Config&) {}
EventLogLogger(const wchar_t*, bool) {}
void log(const LogRecord&, const std::string&) override {}
std::string get_string_param(const LoggerParam&) const override { return {}; }
int64_t get_int_param(const LoggerParam&) const override { return 0; }
double get_float_param(const LoggerParam&) const override { return 0.0; }
void set_log_level(LogLevel) override {}
LogLevel get_log_level() const override { return LogLevel::LOG_LVL_TRACE; }
void wait() override {}
};
#endif

} // namespace logit
#endif

Loading
Loading