中文版 | English Version | User Guide | Developer Guide
log4cpp is a C++ logging library inspired by log4j.
Features:
- Configurable via JSON files, no code modification required
- Supports logging to STDOUT and STDERR
- Supports logging to specified files
- Supports size/time/startup rolling for file logs, with count and history retention
- Supports logging to log server (TCP/UDP)
- Singleton pattern
- Thread-safe
- Hot configuration reload, changes take effect without restarting the process(Linux only)
- C++ compiler supporting C++20 or later
- CMake 3.10 or later (for CMake builds)
- Meson 1.1.0 or later (for Meson builds)
Create the following project:
log4cpp-demo/
├── CMakeLists.txt
├── meson.build
├── subprojects/
│ └── log4cpp.wrap
├── demo.cpp
└── log4cpp.json (optional)
The same demo.cpp and optional log4cpp.json are used by both build systems. Keep either build definition, or both
if the project should support CMake and Meson.
Using FetchContent:
cmake_minimum_required(VERSION 3.11)
project(log4cpp-demo LANGUAGES CXX)
add_executable(demo demo.cpp)
include(FetchContent)
FetchContent_Declare(
log4cpp
GIT_REPOSITORY https://github.com/lwhttpdorg/log4cpp.git
GIT_TAG v5.0.0
)
FetchContent_MakeAvailable(log4cpp)
target_link_libraries(demo PRIVATE log4cpp)
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/log4cpp.json")
configure_file(log4cpp.json log4cpp.json COPYONLY)
endif()Or using pkg-config (the log4cpp deb/rpm package has already been installed):
cmake_minimum_required(VERSION 3.11)
project(log4cpp-demo LANGUAGES CXX)
add_executable(demo demo.cpp)
find_package(PkgConfig REQUIRED)
pkg_check_modules(LOG4CPP REQUIRED IMPORTED_TARGET log4cpp)
target_link_libraries(demo PRIVATE PkgConfig::LOG4CPP)
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/log4cpp.json")
configure_file(log4cpp.json log4cpp.json COPYONLY)
endif()Save the following as meson.build:
project(
'log4cpp-demo',
'cpp',
default_options: ['cpp_std=c++20'],
meson_version: '>=1.1.0',
)
log4cpp_dep = dependency(
'log4cpp',
fallback: ['log4cpp', 'log4cpp_dep'],
)
executable('demo', 'demo.cpp', dependencies: log4cpp_dep)
fs = import('fs')
if fs.exists('log4cpp.json')
configure_file(input: 'log4cpp.json', output: 'log4cpp.json', copy: true)
endifIf log4cpp is not installed, create subprojects/log4cpp.wrap so Meson can fetch it automatically:
[wrap-git]
directory = log4cpp
url = https://github.com/lwhttpdorg/log4cpp.git
revision = v5.0.0
depth = 1Header file:
#include <log4cpp/log4cpp.hpp>Configuration can be loaded in two ways:
- If
log4cpp.jsonexists in the current path, it will be loaded automatically - If the configuration file is not in the current path, or has a different name, you need to load it manually
Notes: If log4cpp.json does not exist and is not loaded manually, the built-in default configuration will be used.
const std::string config_file = "demo.json";
auto &log_mgr = log4cpp::supervisor::get_logger_manager();
log_mgr.load_config(config_file);Get the configured logger by name:
std::shared_ptr<log4cpp::logger> log = log4cpp::logger_manager::get_logger(const std::string &name = "root");You can specify a unique string, which can be output to the log (the length of the output can be specified via
${<n>NM} in "log-pattern")
hello : 2025-11-13 23:32:02:475 [main ] [ERROR] -- this is an errorAfter getting the logger, you can use the following methods to output the log:
void trace(std::string_view msg);
void debug(std::string_view msg);
void info(std::string_view msg);
void warn(std::string_view msg);
void error(std::string_view msg);
void fatal(std::string_view msg);
template <class... Args> void trace(std::format_string<Args...> fmt, Args &&...args);
template <class... Args> void debug(std::format_string<Args...> fmt, Args &&...args);
template <class... Args> void info(std::format_string<Args...> fmt, Args &&...args);
template <class... Args> void warn(std::format_string<Args...> fmt, Args &&...args);
template <class... Args> void error(std::format_string<Args...> fmt, Args &&...args);
template <class... Args> void fatal(std::format_string<Args...> fmt, Args &&...args);Or directly:
void log(log_level level, std::string_view msg);
template <class... Args> void log(log_level level, std::format_string<Args...> fmt, Args &&...args);Formatted log messages use C++20 std::format syntax:
logger->info("user={}, cost={}ms", user_name, cost_ms);Use at() when a log message should include the source file and line number:
logger->at().info("user={}, cost={}ms", user_name, cost_ms);The log level log_level is defined as follows:
namespace log4cpp {
enum class log_level { FATAL, ERROR, WARN, INFO, DEBUG, TRACE };
}Description:
FATAL: Fatal errorERROR: ErrorWARN: WarningINFO: InformationDEBUG: DebuggingTRACE: Tracing
The logger object can also be used as a class member variable (or static member variable). Since it is a
std::shared_ptr, all instances of the class will use the same logger
class demo {
public:
demo() {
logger = log4cpp::logger_manager::get_logger("demo");
logger->info("constructor");
}
~demo() {
logger->info("destructor");
}
void func(const std::string &name) const {
logger->info("func({})", name);
}
private:
std::shared_ptr<log4cpp::logger> logger;
};You will get the following log:
demo: 2025-11-29 20:06:47:652 [main ] [INFO ] -- constructor
demo: 2025-11-29 20:06:47:652 [main ] [INFO ] -- func(hello)
demo: 2025-11-29 20:06:47:652 [main ] [INFO ] -- destructor#include <memory>
#include <string>
#include <thread>
#include <log4cpp/log4cpp.hpp>
class demo {
public:
demo() {
logger = log4cpp::logger_manager::get_logger("demo");
logger->info("constructor");
}
~demo() {
logger->info("destructor");
}
void func(const std::string &name) const {
logger->info("func({})", name);
}
private:
std::shared_ptr<log4cpp::logger> logger;
};
void thread_routine() {
log4cpp::set_thread_name("child");
const auto log = log4cpp::logger_manager::get_logger("aaa");
for (int i = 0; i < 10; ++i) {
log->trace("this is a trace");
log->debug("this is a debug");
log->info("this is an info");
log->warn("this is a warning");
log->error("this is an error");
log->fatal("this is a fatal");
}
}
int main() {
#ifndef _WIN32
log4cpp::supervisor::enable_config_hot_loading();
#endif
std::thread child(thread_routine);
log4cpp::set_thread_name("main");
const auto log = log4cpp::logger_manager::get_logger("hello");
log->at().info("this log includes source file and line number");
for (int i = 0; i < 10; ++i) {
log->trace("this is a trace");
log->debug("this is a debug");
log->info("this is an info");
log->warn("this is a warning");
log->error("this is an error");
log->fatal("this is a fatal");
}
child.join();
demo app;
app.func("hello");
return 0;
}Example log output when using the optional configuration below:
root : 2025-11-13 23:32:02:475 [child ] [ERROR] -- this is an error
hello : 2025-11-13 23:32:02:475 [main ] [ERROR] -- this is an error
root : 2025-11-13 23:32:02:475 [child ] [FATAL] -- this is a fatal
hello : 2025-11-13 23:32:02:475 [main ] [FATAL] -- this is a fatal
root : 2025-11-13 23:32:02:475 [child ] [INFO ] -- this is info
hello : 2025-11-13 23:32:02:475 [main ] [INFO ] -- this is info
root : 2025-11-13 23:32:02:475 [child ] [WARN ] -- this is a warning
hello : 2025-11-13 23:32:02:475 [main ] [WARN ] -- this is a warning
root : 2025-11-13 23:32:02:475 [child ] [ERROR] -- this is an error
hello : 2025-11-13 23:32:02:475 [main ] [ERROR] -- this is an error
root : 2025-11-13 23:32:02:475 [child ] [FATAL] -- this is a fatalThe configuration file is optional. Without one, log4cpp uses its built-in log pattern, writes to stdout, and uses a
WARN-level root logger.
To customize the defaults, save the following as log4cpp.json. log4cpp loads this filename automatically from the
current working directory; it configures console and file output, a log pattern, and named loggers:
{
"log-pattern": "${NM}: ${yyyy}-${MM}-${dd} ${HH}:${mm}:${ss}:${ms} [${8TN}] [${L}] -- ${msg}",
"appenders": {
"console": {
"out-stream": "stdout"
},
"file": {
"file-path": "log/log4cpp.log"
}
},
"loggers": [
{
"name": "root",
"level": "INFO",
"appenders": [
"console",
"file"
]
},
{
"name": "hello",
"level": "INFO",
"appenders": [
"console",
"file"
]
}
]
}The repository contains a more complete demo configuration, including a socket appender.
CMake:
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build
cd build
./demoMeson:
meson setup build-meson --buildtype=release
meson compile -C build-meson
cd build-meson
./demoOn Windows, run the generated demo.exe. When using a multi-configuration CMake generator, build with
--config Release and run Release\demo.exe from the build directory.
For configuration patterns, appenders, rolling policies, logger inheritance, and hot configuration reload, see the User Guide.
This project is licensed under LGPLv3