Log4cpp is library of C++ classes for flexible logging to files, syslog, IDSA and other destinations. It is modeled after the Log4j Java library, staying as close to their API as is reasonable.
Sources are available from SourceForges download
page.
We do not supply binaries, because of the numerous incompatible ABIs
(e.g. g++ 2.95 vs 2.96 vs 3.0 vs 3.2) and different package
formats.
rpm -ta log4cpp-x.y.z.tar.gz^
The project uses GNU Autotools as primary build system. CMake is secondary option.
If file ./configure is absent in project directory (as when the code is checked out from
repository), run the following:
./autogen.shThis will create
./configure and the necessary Makefile.in's. Then:
./configure
make
make check
make install
This will build and install log4cpp under /usr/local. To install in
another location specify option --prefix=<location> when
running configure.
./configure options like --prefix a few others are
available:
Browse into the source code catalog (log4cpp) and run the following for Release
build:
cmake -S . -B build_release -DCMAKE_BUILD_TYPE=ReleaseThis will create
cmake --build build_release
./build_release, compile and build libraries into it.
Optionally, run tests (expected result is 100% tests passed):
cd build_release/tests
ctest
Debug build is analogous:
cmake -S . -B build_debug -DCMAKE_BUILD_TYPE=Debug
cmake --build build_debug
Run tests for debug build:
cd build_debug/tests^
ctest
MS Visual Studio 2022 can open
log4cppdirectly as a CMake project.
- Use
File → Open → CMake...menu items to chooselog4cpp/CMakeLists.txtfile and start CMake generation.- After CMake generation is finished, choose
Build → Build Allto buildlog4cpplibs.- Optionally, run set of tests from
Test → Run CTests
Note: Native project files intended for older MSVC versions (msvc10, msvc7, msvc6) are archived since log4cpp 1.1.6 intoprojectsdirectory.
Embarcadero RAD Studio 12 can build
log4cppproject using its bundled version of CMake, provided via the RAD Package Manager.
Make sure that Embarcadero's CMake (and not another installation) is used for command line. Ninja generator will be used as build system, you can getninja-win.zipat Ninja site and extract the executable into catalog included into PATH environment variable.
Open RAD Studio Command Prompt and run commands to buildlog4cpplibs:Release:
cmake.exe -G Ninja -S . -B build_release -DCMAKE_SYSTEM_NAME=Windows -DCMAKE_SYSTEM_PROCESSOR=x86_64 -DCMAKE_CROSSCOMPILING=OFF -DCMAKE_BUILD_TYPE=Release -DCMAKE_ASM_COMPILER=bcc64x -DCMAKE_C_COMPILER=bcc64x -DCMAKE_CXX_COMPILER=bcc64x
cmake.exe --build build_release --config Release -vDebug:
cmake.exe -G Ninja -S . -B build_debug -DCMAKE_SYSTEM_NAME=Windows -DCMAKE_SYSTEM_PROCESSOR=x86_64 -DCMAKE_CROSSCOMPILING=OFF -DCMAKE_BUILD_TYPE=Debug -DCMAKE_ASM_COMPILER=bcc64x -DCMAKE_C_COMPILER=bcc64x -DCMAKE_CXX_COMPILER=bcc64x
cmake.exe --build build_debug --config Debug -v
Works since log4cpp 1.1.5.
^CC=CC CXX=CC LD="CC -KPIC" ./configure --disable-static
msvc10.
You may need to adjust include/log4cpp/config-win32.h and the project
files to your particular needs. Since log4cpp 1.1.6, directory with project
files is kept as archive in directory projects. Extract it into project's root to
use.
msvc6.
You may need to adjust include/log4cpp/config-win32.h and the project
files to your particular needs. Since log4cpp 1.1.6, directory with project
files is kept as archive in directory projects. Extract it into project's root to
use.
bcb5. Since log4cpp 1.1.6, directory
with project
files is kept as archive in directory projects. Extract it into project's root to
use.
./configure; make; make installinclude/log4cpp/config-openvms.h if you need
different settings.cxx /include=("/a1\$dkb0/user/tony/project/log4cpp/include") /define=(__USE_STD_IOSTREAM,__OPENVMS__) /repository=a1$dkb0:[user.tony.project.log4cpp.repository] APPENDER.CPP
cxx /include=("/a1\$dkb0/user/tony/project/log4cpp/include") /define=(__USE_STD_IOSTREAM,__OPENVMS__) /repository=a1$dkb0:[user.tony.project.log4cpp.repository] APPENDERSKELETON.CPP
...etclib/create log4cpp
lib/insert log4cpp appender...etc
lib/insert log4cpp appenderskeleton
cxx /include=("/a1\$dkb0/user/tony/project/log4cpp/include") /define=(__USE_STD_IOSTREAM,__OPENVMS__) testlog4cpp.cxx
cxxlink /repository=a1$dkb0:[user.tony.project.log4cpp.repository] testlog4cpp,log4cpp/library
This library is licensed under the Lesser General Public License version 2.1 (LGPL 2.1) as of version 0.2.1, instead of the General Public License (GPL). No further license changes are planned. :-)
Log for C++ (short name: log4cpp), a C++ library for flexible logging.^
Copyright (C) 2000-2002 LifeLine Networks bv
Copyright (C) 2000-2002 Bastiaan Bakker
Portions Copyright others, see file THANKS and source code.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see https://www.gnu.org/licenses/.
The Solaris Developer Connection features an article by Mo Budlon on using log4cpp 0.2.x, called 'Logging and Tracing in C++ Simplified'. Recommended reading if you trying to figure out how to use log4cpp!
^tests subdirectory.examples/cmake_usages
subdirectory.
log4cpp::Categoryobject (a logger) can be used simultaneously from multiple threads without explicit synchronization.
%%- a single percent sign
%c- the category
%d- the date\n Date format: The date format character may be followed by a date format specifier enclosed between braces. For example,
%d{%H:%M:%S,%l} or %d{%d %m %Y %H:%M:%S,%l}
.
If no date format specifier is given then the following format is used:
"Wed Jan 02 02:03:55 1980". The date format specifier admits the same syntax as the ANSI C function strftime, with 1 addition. The addition is the specifier
%lfor milliseconds, padded with zeros to make 3 digits.
%m- the message
%n- the platform specific line separator
%p- the priority
%r- milliseconds since this layout was created.
%R- seconds since Jan 1, 1970
%u- clock ticks since process start
%x- the NDC
%t- thread name
"%m%n".
Log4cpp provides the following log levels (priorities), ordered from lowest to highest severity:
TRACE- very fine-grained diagnostic information. Usage: Function entry/exit, loop iterations, variable changes, or high-frequency internal events during deep debugging.
DEBUG- detailed diagnostic information. Usage: Debugging program logic, inspecting important state, or understanding code flow during development.
INFO- general informational messages. Usage: Normal application behavior such as startup, shutdown, configuration loading, or key workflow steps.
NOTICE- normal but significant conditions. Usage: Important events that are not errors but worth highlighting (e.g., configuration changes, feature toggles).
WARN- warning conditions. Usage: Unexpected situations that are recoverable (e.g., missing optional data, retries, deprecated API usage).
ERROR- error conditions. Usage: Failures that affect a specific operation but do not stop the entire application (e.g., failed request, file read error).
CRIT- critical conditions. Usage: Serious failures impacting major components (e.g., subsystem unavailable, database connection lost).
ALERT- action must be taken immediately. Usage: Conditions requiring immediate intervention (e.g., data corruption risk, critical resource exhaustion).
FATAL- severe errors causing program termination. Usage: Unrecoverable errors leading to shutdown (e.g., inability to initialize core components).
There are following ways to log a message:
Category's method corresponding to the log level and pass parameters.
log4cpp::Category& logger = log4cpp::Category::getRoot();
logger.debug("Debug message");
logger.info("Info message # %d", 2);
logger.debugStream() << "Render " << loginpage << " address"; logger << log4cpp::Priority::INFO << "Server " << servername << " started up";
LOG4CPP_DEBUG(logger, "Items left in stock: %d remaining", calcRemainder()); LOG4CPP_INFO_S(logger, "Temperature in warehouse: " << readTemperature());
Building complex log messages can introduce runtime overhead. You can reduce this overhead in several ways:
LOG4CPP_DEBUG,
LOG4CPP_INFO_S) will compare message's priority to the logger’s level before
evaluating arguments, preventing unnecessary computations when a message is not logged due to
its lower priority.
LOG4CPP_ACTIVE_LEVEL
are removed at compile time, resulting in zero runtime overhead. For example, to remove all logs
below
INFO level in current compilation unit:
#define LOG4CPP_ACTIVE_LEVEL LOG4CPP_PRIORITY_INFO #include <log4cpp/LogMacros.hh>
Of course the proper solution would be if the offending party would use one of the above methods, but we could have to wait some time for this to actually happen. As an alternative log4cpp can workaround these #defines. The workaround code is enabled by doing #define LOG4CPP_FIX_ERROR_COLLISION 1 before #including any log4cpp header files and after #including all platform headers. For Win32 platforms this #define has already been included in log4cpp/config-win32.h.
Once log4cpp has been updated to the log4j 1.2 API we can get rid of this problem by adopting the new names for log levels.
export LD="CC -Kpic" && ./configure --disable-static
Sample main.cpp file that logs onto console and into file program.log. Loggers and appenders are created and configured manually. Example makes use of both function-style logging and stream-style logging.
// main.cpp
#include "log4cpp/Category.hh"
#include "log4cpp/Appender.hh"
#include "log4cpp/FileAppender.hh"
#include "log4cpp/OstreamAppender.hh"
#include "log4cpp/Layout.hh"
#include "log4cpp/BasicLayout.hh"
#include "log4cpp/Priority.hh"
int main(int argc, char** argv) {
log4cpp::Appender *appender1 = new log4cpp::OstreamAppender("console", &std::cout);
appender1->setLayout(new log4cpp::BasicLayout());
log4cpp::Appender *appender2 = new log4cpp::FileAppender("default", "program.log");
appender2->setLayout(new log4cpp::BasicLayout());
log4cpp::Category& root = log4cpp::Category::getRoot();
root.setPriority(log4cpp::Priority::WARN);
root.addAppender(appender1);
log4cpp::Category& sub1 = log4cpp::Category::getInstance(std::string("sub1"));
sub1.addAppender(appender2);
// use of functions for logging messages
root.error("root error");
root.info("root info");
sub1.error("sub1 error");
sub1.warn("sub1 warn");
// printf-style for logging variables
root.warn("%d + %d == %s ?", 1, 1, "two");
// use of streams for logging messages
root << log4cpp::Priority::ERROR << "Streamed root error";
root << log4cpp::Priority::INFO << "Streamed root info";
sub1 << log4cpp::Priority::ERROR << "Streamed sub1 error";
sub1 << log4cpp::Priority::WARN << "Streamed sub1 warn";
// or this way:
root.errorStream() << "Another streamed error";
return 0;
}
Console output for that example
1352973121 ERROR : root error 1352973121 ERROR sub1 : sub1 error 1352973121 WARN sub1 : sub1 warn 1352973121 WARN : 1 + 1 == two ? 1352973121 ERROR : Streamed root error 1352973121 ERROR sub1 : Streamed sub1 error 1352973121 WARN sub1 : Streamed sub1 warn 1352973121 ERROR : Another streamed error^
Sample main.cpp file that makes use of logging configuration file log4cpp.properties
// main.cpp
#include <log4cpp/Category.hh>
#include <log4cpp/PropertyConfigurator.hh>
int main(int argc, char* argv[])
{
std::string initFileName = "log4cpp.properties";
log4cpp::PropertyConfigurator::configure(initFileName);
log4cpp::Category& root = log4cpp::Category::getRoot();
log4cpp::Category& sub1 =
log4cpp::Category::getInstance(std::string("sub1"));
log4cpp::Category& sub2 =
log4cpp::Category::getInstance(std::string("sub1.sub2"));
root.warn("Storm is coming");
sub1.debug("Received storm warning");
sub1.info("Closing all hatches");
sub2.debug("Hiding solar panels");
sub2.error("Solar panels are blocked");
sub2.debug("Applying protective shield");
sub2.warn("Unfolding protective shield");
sub2.info("Solar panels are shielded");
sub1.info("All hatches closed");
root.info("Ready for storm.");
log4cpp::Category::shutdown();
return 0;
}
Configuration file for use with that code
# log4cpp.properties log4cpp.rootCategory=DEBUG, rootAppender log4cpp.category.sub1=DEBUG, A1, A2 log4cpp.category.sub1.sub2=DEBUG, A3 log4cpp.appender.rootAppender=ConsoleAppender log4cpp.appender.rootAppender.layout=PatternLayout log4cpp.appender.rootAppender.layout.ConversionPattern=%d [%p] %m%n log4cpp.appender.A1=FileAppender log4cpp.appender.A1.fileName=A1.log log4cpp.appender.A1.layout=BasicLayout log4cpp.appender.A2=FileAppender log4cpp.appender.A2.threshold=WARN log4cpp.appender.A2.fileName=A2.log log4cpp.appender.A2.layout=PatternLayout log4cpp.appender.A2.layout.ConversionPattern=%d [%p] %m%n log4cpp.appender.A3=RollingFileAppender log4cpp.appender.A3.fileName=A3.log log4cpp.appender.A3.maxFileSize=200 log4cpp.appender.A3.maxBackupIndex=1 log4cpp.appender.A3.layout=PatternLayout log4cpp.appender.A3.layout.ConversionPattern=%d [%p] %m%nConsole output for that example
2012-11-14 18:44:58,163 [WARN] Storm is coming 2012-11-14 18:44:58,166 [DEBUG] Received storm warning 2012-11-14 18:44:58,170 [INFO] Closing all hatches 2012-11-14 18:44:58,172 [DEBUG] Hiding solar panels 2012-11-14 18:44:58,175 [ERROR] Solar panels are blocked A3.log.1 2012-11-14 18:44:58,179 [DEBUG] Applying protective shield 2012-11-14 18:44:58,183 [WARN] Unfolding protective shield 2012-11-14 18:44:58,186 [INFO] Solar panels are shielded 2012-11-14 18:44:58,190 [INFO] All hatches closed 2012-11-14 18:44:58,192 [INFO] Ready for storm.
There are three loggers (including root) and three appenders. Root logger redirects all its own input and input of its descendant onto console. Descendant sub1 writes into two files, filtering output by message priority for second of them. Descendant sub1.sub2 writes also into rolling file. Log file A3.log is rolled over as soon as it reaches limit of 200 bytes, 1 backup log file is kept.
^Log4cpp is hosted in a Git repository on SourceForge since version 1.1.1.
A mirror of the Git repository is also available on GitHub: https://github.com/log4cpp/log4cpp
To start working with a freshly checked out log4cpp repository, run ./autogen.sh
first.
This will generate the ./configure script and the required Makefile.in
files.
You will need at least autoconf 2.50, automake 1.6.0, and libtool 1.4 (the GNU Autotools build system).
Older versions of log4cpp (prior to 1.1.1) are available via CVS. See the SourceForge CVS page for instructions. The CVS repository is no longer maintained.
^Each release will receive a tag named REL_x_y_z or prefixed with REL_x.y.z
printf format checking to Category logging methods.
Enhance class log4cpp::Category to enable compile-time checking of
printf-style format strings and arguments using compiler attributes.
Fixes bug #155 reported by Adrien Destugues.
TRACE with priority value 800 for fine-grained
diagnostic logging, trace-level methods and macros.
LOG4CPP_BUILD_EXAMPLES
option.
CMake usage examples are provided for both scenarios: importing a CMake-installed log4cpp
library and using
log4cpp as a CMake subproject.
include/log4cpp/config.h
from Autotools-style
config.h.inThe latest stable release is 1.1.6
log4cpp is moved to git since version 1.1.1, cvs is stale since then
Note for cvs: As of version 0.3.0 log4cpp had a separate 'stable' and 'development' branches. Releases x.y.z where y is even are considered stable and those where y is odd are experimental (which means that some or all features may be broken).
^Coding on Log4cpp was initiated by me (Bastiaan Bakker) late 2000. Since then other people have joined the project or contributed code:
| Cedric Le Goater <cedric(at)legoater.com> | autoconf setup, various improvements |
| Marc Welz <marc(at)jade.cs.uct.ac.za> | IdsaAppender |
| Lynn Owen <opl(at)agoby.com> | MSVC++ support |
| Steve Ostlind <s.ostlind(at)pentasafe.com> | MSVC++ support, various fixes |
| Marcel Harkema <marcel(at)debian.org> | Debian packaging |
| Uwe Jäger <jaeger(at)varial.de> | Borland C++ Builder support |
| Walter Stroebel <walter.stroebel(at)lifeline.nl> | RemoteSyslogAppender |
| Glen Scott <glen_s(at)yahoo.com> | PatternLayout, SimpleConfigurator |
| Tony Cheung <dragonman(at)asiayeah.com> | OpenVMS support |
| Alex Tapaccos <ATapaccos(at)redfig.com> | RollingFileAppender |
| Brendan B. Boerner <bboerner(at)texas.net> | Multiple Appender support for Categories |
| Paulo Pizarro <paulo.pizarro(at)digitro.com.br> | RollingFileAppender |
| David Resnick <dresnick(at)mobilespear.com> | NTEventAppender, integration work |
| Aaron Ingram <ai8(at)yahoo.com> | MSThreads support |
| Alan Anderson <alan(at)rushmore.com> | Win32DebugAppender, PropertyConfigurator |
| Emiliano Martin <emilianomc(at)terra.es> | PThreads support |
| Alexander Perepelkin <sanchouss_(at)users.sf.net> | DailyRollingFileAppender. Project maintenance, improvements, fixes |
Log4cpp is one of many ports/implementations of the Log4j API. Here's an incomplete list:
| log4c | An implementation in C by Cedric Legoater |
| log4cplus | An indepent C++ implementation by Tad Smith. Worth checking out if you don't like Log4cpp for some reason. |