Knowledge Base/CPP/log4cxx
Contents |
Why Apache log4cxx?
Let us consider the alternatives. If you look for C++ logging libraries, you will probably discover
Alternatives
log4cplus
The stated purpose of this project is "to port the excellent Log for Java (log4j) logging library to C++" (just like Apache log4cxx). And "this project is now in Production status". The last release was performed on 28th March, 2009 (log4cplus V1.0.3), the next release is planned for October, 2009. Currently there is log4cplus V1.0.4. Looks like this project is activer and work is being done on it.
Whereas Log for Java was created by the Software Foundation, this project doesn't seem to be formally affiliated with Apache.
log4cpp
According to its creators, "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".
One problem with this project is that the newest files on its SourceForge.net page were submitted on 3rd September, 2007 (log4cpp-1.0.tar.gz). Looks like no new releases have appeared since then.
"Boost Log"
We put "Boost Log" in quotes because it is not really Boost Log. At least, you won't find it here. The library was submitted to Boost by John Torjo but was rejected on 13th February, 2008: "February 13 - Logging Library Rejected - Awaiting resubmission for new review, John Torjo has already resubmitted and Gennadiy Rozental has again volunteered to manage the review". It is unclear whether the aforementioned new review has taken place; the library is not part of the standard Boost distribution. However, John has written "Boost Logging Library v2" which presumably will be reviewed and is maintained separately from Boost libraries. However, it looks like he is maintaining it single-handedly, at least at this stage.
Conclusion
We have also looked for other people's views on the subject of logging frameworks.
A very sensible question was submitted by Matthieu Labour to comp.lang.c++ (although ages ago, on 4th September, 2003): which of these logging frameworks is "best"? (Whatever "best" means, of course.) However, Kevin Goodsell and Alf P. Steinbach seized the occasion to indulge in a charming but pointless (as far as we are concerned!) discussion of what's off-topic and what isn't off-topic and the discussion quickly reduced to tedium and bureaucracy. So we stopped reading. (To be fair, perhaps Matthieu could have phrased his question better (avoiding the word "best"), and perhaps comp.lang.c++ is a wrong place to ask the question. However, no-one ever pointed out the right place and it looks like Kevin and Alf managed to deprive Matthieu of his enthusiasm — the question never surfaced elsewhere.)
Much later Andrew Cencini posted log4cxx / log4cplus and visual studio where he ultimately "moves to log4cxx as many seem to do". That was on 11th December, 2008.
Our own subjective conclusion is that log4cxx has several advantages over the other frameworks:
- Like most other frameworks, it is modelled on Apache log4j. Its interface is very well thought out.
- Unlike the rest, however, it is offered by Apache themselves, who seem to be in the best position to port log4j to C++ as they are the authors of log4j.
- For the same reason a large number of people appear to be involved in this project.
- The last check-in to http://svn.apache.org/viewvc/logging/log4cxx/trunk/ took place only two days ago (as of 26th August, 2009).
- The feature set is rich. "Appenders exist for the console, files, GUI components, remote socket servers, NT Event Loggers, and remote UNIX Syslog daemons. It is also possible to log asynchronously" (as mentioned [http://logging.apache.org/log4cxx/index.html here).
- It appears that other users (see above) have favoured log4cxx over other frameworks. Of course, our googling hasn't been exhaustive, and this statement is hardly scientific.
Therefore, we concluded, we should give log4cxx a go.
Building log4cxx on Windows
First, a few comments.
Why did we write this?
We found building log4cxx on Windows a bit of a nightmare.
One of the reasons is the proliferation of obsolete and/or incomplete build process documentation.
INSTALL
Consider, for example, the file INSTALL included in apache-log4cxx-0.10.0.zip. It tells us to use
Apache Ant 1.6.1 or later http://ant.apache.org
and
The following files placed in the lib directory:
apr-1.2.2.tar.gz
apr-util-1.2.2.tar.gz
If you try using (ant -v) this combination you will get the very unpleasant
--- Nested Exception ---
class net.sf.antcontrib.cpptasks.ide.ProjectDef doesn't support the nested "comment" element.
at org.apache.tools.ant.IntrospectionHelper.throwNotSupported(IntrospectionHelper.java:447)
at org.apache.tools.ant.UnknownElement.handleChildren(UnknownElement.java:349)
at org.apache.tools.ant.UnknownElement.handleChild(UnknownElement.java:569)
at org.apache.tools.ant.UnknownElement.handleChildren(UnknownElement.java:346)
at org.apache.tools.ant.UnknownElement.configure(UnknownElement.java:198)
at org.apache.tools.ant.UnknownElement.maybeConfigure(UnknownElement.java:160)
at org.apache.tools.ant.Task.perform(Task.java:347)
at org.apache.tools.ant.Target.execute(Target.java:357)
at org.apache.tools.ant.Target.performTasks(Target.java:385)
at org.apache.tools.ant.Project.executeSortedTargets(Project.java:1337)
at org.apache.tools.ant.helper.SingleCheckExecutor.executeTargets(SingleCheckExecutor.java:38)
at org.apache.tools.ant.Project.executeTargets(Project.java:1189)
at org.apache.tools.ant.taskdefs.Ant.execute(Ant.java:416)
at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:288)
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:106)
at org.apache.tools.ant.Task.perform(Task.java:348)
at org.apache.tools.ant.Target.execute(Target.java:357)
at org.apache.tools.ant.Target.performTasks(Target.java:385)
at org.apache.tools.ant.Project.executeSortedTargets(Project.java:1337)
at org.apache.tools.ant.Project.executeTarget(Project.java:1306)
at org.apache.tools.ant.helper.DefaultExecutor.executeTargets(DefaultExecutor.java:41)
at org.apache.tools.ant.Project.executeTargets(Project.java:1189)
at org.apache.tools.ant.Main.runBuild(Main.java:758)
at org.apache.tools.ant.Main.startAnt(Main.java:217)
at org.apache.tools.ant.launch.Launcher.run(Launcher.java:257)
at org.apache.tools.ant.launch.Launcher.main(Launcher.java:104)
No good.
Online documentation
So one should ignore INSTALL and look at http://logging.apache.org/log4cxx/building/vstudio.html instead.
Currently (26th August, 2009), we are told to perform the following initial steps:
unzip apr-1.2.11-win32-src.zip rename apr-1.2.11 apr unzip apr-util-1.2.10-win32-src.zip rename apr-util-1.2.10 apr-util cd apache-log4cxx-0.10.0 configure configure-aprutil
One of the requirements for building log4cxx is Microsoft Windows SDK. We used the latest version, Microsoft Windows SDK for Windows Server 2008 and .NET Framework V3.5 obtainable here. Despite the awkward naming, this framework supports Windows Server 2003, Windows Server 2008, Windows Vista, Windows XP; Visual Studio 2005 and Visual Studio 2008.
What happens if we use apr-1.2.11-win32-src.zip and apr-util-1.2.10-win32-src.zip with this version of the Microsoft Windows SDK?
If we follow the steps in http://logging.apache.org/log4cxx/building/vstudio.html and attempt to build the project apr from Visual Studio 2005 we first get
multicast.c I:\dev\apr\network_io\unix\multicast.c(137) : error C2079: 'mip' uses undefined struct 'group_source_req' I:\dev\apr\network_io\unix\multicast.c(168) : error C2224: left of '.gsr_interface' must have struct/union type I:\dev\apr\network_io\unix\multicast.c(168) : warning C4013: 'find_if_index' undefined; assuming extern returning int I:\dev\apr\network_io\unix\multicast.c(169) : error C2224: left of '.gsr_group' must have struct/union type I:\dev\apr\network_io\unix\multicast.c(169) : error C2224: left of '.gsr_group' must have struct/union type I:\dev\apr\network_io\unix\multicast.c(169) : error C2198: 'memcpy' : too few arguments for call I:\dev\apr\network_io\unix\multicast.c(170) : error C2224: left of '.gsr_source' must have struct/union type I:\dev\apr\network_io\unix\multicast.c(170) : error C2224: left of '.gsr_source' must have struct/union type I:\dev\apr\network_io\unix\multicast.c(170) : error C2198: 'memcpy' : too few arguments for call
Other people have experienced this. There is even a fix:
Index: include/apr.hw
===================================================================
--- include/apr.hw (revision 606596)
+++ include/apr.hw (working copy)
@@ -78,7 +78,10 @@
/* Restrict the server to a subset of Windows 2000 header files by default
*/
-#define _WIN32_WINNT 0x0500
+ *
+ * In order to use the MCAST API - 0x0501 is required!
+ */
+#define _WIN32_WINNT 0x0501 /* _WIN32_WINNT_WINXP */
#endif
#ifndef NOUSER
#define NOUSER
@@ -217,7 +220,7 @@
#define APR_HAVE_IN_ADDR 1
#define APR_HAVE_INET_ADDR 1
#define APR_HAVE_INET_NETWORK 0
-#define APR_HAVE_IPV6 0
+#define APR_HAVE_IPV6 1
#define APR_HAVE_MEMMOVE 1
#define APR_HAVE_SETRLIMIT 0
#define APR_HAVE_SIGACTION 0
Index: network_io/unix/multicast.c
===================================================================
--- network_io/unix/multicast.c (revision 606596)
+++ network_io/unix/multicast.c (working copy)
@@ -117,13 +117,13 @@
#if APR_HAVE_IPV6
struct ipv6_mreq mip6;
#endif
-#if MCAST_JOIN_SOURCE_GROUP
+#ifdef GROUP_FILTER_SIZE
struct group_source_req mip;
int ip_proto;
#endif
if (source != NULL) {
-#if MCAST_JOIN_SOURCE_GROUP
+#ifdef GROUP_FILTER_SIZE
if (sock_is_ipv4(sock)) {
ip_proto = IPPROTO_IP;
}
(But in our case the original line looks like
#define _WIN32_WINNT 0x0400
which means that we are looking at an even older version of apr.)
Having applied this fix we get a huge number of errors like the following:
nteventlogappender.cpp
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2def.h(91) : warning C4005: 'AF_IPX' : macro
redefinition
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(460) : see previous definition of
'AF_IPX'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2def.h(127) : warning C4005: 'AF_MAX' : macro
redefinition
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(479) : see previous definition of
'AF_MAX'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2def.h(163) : warning C4005: 'SO_DONTLINGER' : macro
redefinition
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(402) : see previous definition of
'SO_DONTLINGER'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2def.h(207) : error C2011: 'sockaddr' : 'struct' type
redefinition
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(485) : see declaration of 'sockaddr'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2def.h(385) : error C2143: syntax error : missing '}'
before 'constant'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2def.h(385) : error C2143: syntax error : missing ';'
before 'constant'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2def.h(385) : error C2059: syntax error : 'constant'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2def.h(438) : error C2143: syntax error : missing ';'
before '}'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2def.h(438) : error C4430: missing type specifier -
int assumed. Note: C++ does not support default-int
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2def.h(438) : error C4430: missing type specifier -
int assumed. Note: C++ does not support default-int
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2def.h(519) : warning C4005: 'IN_CLASSA' : macro
redefinition
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(287) : see previous definition of
'IN_CLASSA'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2def.h(525) : warning C4005: 'IN_CLASSB' : macro
redefinition
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(293) : see previous definition of
'IN_CLASSB'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2def.h(531) : warning C4005: 'IN_CLASSC' : macro
redefinition
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(299) : see previous definition of
'IN_CLASSC'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2def.h(542) : warning C4005: 'INADDR_ANY' : macro
redefinition
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(304) : see previous definition of
'INADDR_ANY'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2def.h(544) : warning C4005: 'INADDR_BROADCAST' :
macro redefinition
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(306) : see previous definition of
'INADDR_BROADCAST'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2def.h(578) : error C2011: 'sockaddr_in' : 'struct'
type redefinition
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(312) : see declaration of
'sockaddr_in'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(132) : error C2011: 'fd_set' : 'struct' type
redefinition
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(68) : see declaration of 'fd_set'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(167) : warning C4005: 'FD_SET' : macro
redefinition
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(102) : see previous definition of
'FD_SET'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(176) : error C2011: 'timeval' : 'struct'
type redefinition
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(111) : see declaration of 'timeval'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(232) : error C2011: 'hostent' : 'struct'
type redefinition
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(167) : see declaration of 'hostent'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(245) : error C2011: 'netent' : 'struct' type
redefinition
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(180) : see declaration of 'netent'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(252) : error C2011: 'servent' : 'struct'
type redefinition
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(187) : see declaration of 'servent'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(264) : error C2011: 'protoent' : 'struct'
type redefinition
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(199) : see declaration of 'protoent'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(360) : error C2011: 'WSAData' : 'struct'
type redefinition
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(322) : see declaration of 'WSAData'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(458) : error C2011: 'sockproto' : 'struct'
type redefinition
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(494) : see declaration of 'sockproto'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(500) : error C2011: 'linger' : 'struct' type
redefinition
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(531) : see declaration of 'linger'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(513) : warning C4005: 'SOMAXCONN' : macro
redefinition
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(544) : see previous definition of
'SOMAXCONN'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(542) : warning C4005: 'FD_READ' : macro
redefinition
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(562) : see previous definition of
'FD_READ'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(545) : warning C4005: 'FD_WRITE' : macro
redefinition
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(563) : see previous definition of
'FD_WRITE'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(548) : warning C4005: 'FD_OOB' : macro
redefinition
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(564) : see previous definition of
'FD_OOB'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(551) : warning C4005: 'FD_ACCEPT' : macro
redefinition
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(565) : see previous definition of
'FD_ACCEPT'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(554) : warning C4005: 'FD_CONNECT' : macro
redefinition
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(566) : see previous definition of
'FD_CONNECT'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(557) : warning C4005: 'FD_CLOSE' : macro
redefinition
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(567) : see previous definition of
'FD_CLOSE'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(1527) : error C2375: 'accept' :
redefinition; different linkage
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(735) : see declaration of 'accept'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(1548) : error C2375: 'bind' : redefinition;
different linkage
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(740) : see declaration of 'bind'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(1567) : error C2375: 'closesocket' :
redefinition; different linkage
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(745) : see declaration of
'closesocket'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(1586) : error C2375: 'connect' :
redefinition; different linkage
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(747) : see declaration of 'connect'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(1607) : error C2375: 'ioctlsocket' :
redefinition; different linkage
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(752) : see declaration of
'ioctlsocket'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(1628) : error C2375: 'getpeername' :
redefinition; different linkage
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(757) : see declaration of
'getpeername'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(1649) : error C2375: 'getsockname' :
redefinition; different linkage
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(762) : see declaration of
'getsockname'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(1672) : error C2375: 'getsockopt' :
redefinition; different linkage
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(767) : see declaration of
'getsockopt'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(1693) : error C2375: 'htonl' : redefinition;
different linkage
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(774) : see declaration of 'htonl'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(1710) : error C2375: 'htons' : redefinition;
different linkage
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(776) : see declaration of 'htons'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(1728) : error C2375: 'inet_addr' :
redefinition; different linkage
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(778) : see declaration of 'inet_addr'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(1745) : error C2375: 'inet_ntoa' :
redefinition; different linkage
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(780) : see declaration of 'inet_ntoa'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(1763) : error C2375: 'listen' :
redefinition; different linkage
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(782) : see declaration of 'listen'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(1781) : error C2375: 'ntohl' : redefinition;
different linkage
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(786) : see declaration of 'ntohl'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(1798) : error C2375: 'ntohs' : redefinition;
different linkage
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(788) : see declaration of 'ntohs'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(1818) : error C2375: 'recv' : redefinition;
different linkage
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(790) : see declaration of 'recv'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(1843) : error C2375: 'recvfrom' :
redefinition; different linkage
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(796) : see declaration of 'recvfrom'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(1869) : error C2375: 'select' :
redefinition; different linkage
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(804) : see declaration of 'select'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(1893) : error C2375: 'send' : redefinition;
different linkage
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(811) : see declaration of 'send'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(1918) : error C2375: 'sendto' :
redefinition; different linkage
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(817) : see declaration of 'sendto'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(1944) : error C2375: 'setsockopt' :
redefinition; different linkage
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(825) : see declaration of
'setsockopt'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(1966) : error C2375: 'shutdown' :
redefinition; different linkage
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(832) : see declaration of 'shutdown'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(1986) : error C2375: 'socket' :
redefinition; different linkage
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(836) : see declaration of 'socket'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(2009) : error C2375: 'gethostbyaddr' :
redefinition; different linkage
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(843) : see declaration of
'gethostbyaddr'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(2029) : error C2375: 'gethostbyname' :
redefinition; different linkage
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(848) : see declaration of
'gethostbyname'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(2047) : error C2375: 'gethostname' :
redefinition; different linkage
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(850) : see declaration of
'gethostname'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(2067) : error C2375: 'getservbyport' :
redefinition; different linkage
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(854) : see declaration of
'getservbyport'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(2087) : error C2375: 'getservbyname' :
redefinition; different linkage
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(858) : see declaration of
'getservbyname'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(2106) : error C2375: 'getprotobynumber' :
redefinition; different linkage
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(862) : see declaration of
'getprotobynumber'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(2124) : error C2375: 'getprotobyname' :
redefinition; different linkage
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(864) : see declaration of
'getprotobyname'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(2145) : error C2375: 'WSAStartup' :
redefinition; different linkage
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(868) : see declaration of
'WSAStartup'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(2163) : error C2375: 'WSACleanup' :
redefinition; different linkage
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(872) : see declaration of
'WSACleanup'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(2180) : error C2375: 'WSASetLastError' :
redefinition; different linkage
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(874) : see declaration of
'WSASetLastError'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(2197) : error C2375: 'WSAGetLastError' :
redefinition; different linkage
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(876) : see declaration of
'WSAGetLastError'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(2214) : error C2375: 'WSAIsBlocking' :
redefinition; different linkage
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(878) : see declaration of
'WSAIsBlocking'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(2231) : error C2375: 'WSAUnhookBlockingHook'
: redefinition; different linkage
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(880) : see declaration of
'WSAUnhookBlockingHook'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(2248) : error C2375: 'WSASetBlockingHook' :
redefinition; different linkage
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(882) : see declaration of
'WSASetBlockingHook'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(2265) : error C2375: 'WSACancelBlockingCall'
: redefinition; different linkage
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(884) : see declaration of
'WSACancelBlockingCall'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(2287) : error C2375: 'WSAAsyncGetServByName'
: redefinition; different linkage
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(886) : see declaration of
'WSAAsyncGetServByName'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(2314) : error C2375: 'WSAAsyncGetServByPort'
: redefinition; different linkage
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(894) : see declaration of
'WSAAsyncGetServByPort'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(2340) : error C2375:
'WSAAsyncGetProtoByName' : redefinition; different linkage
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(902) : see declaration of
'WSAAsyncGetProtoByName'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(2365) : error C2375:
'WSAAsyncGetProtoByNumber' : redefinition; different linkage
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(909) : see declaration of
'WSAAsyncGetProtoByNumber'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(2390) : error C2375: 'WSAAsyncGetHostByName'
: redefinition; different linkage
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(916) : see declaration of
'WSAAsyncGetHostByName'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(2417) : error C2375: 'WSAAsyncGetHostByAddr'
: redefinition; different linkage
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(923) : see declaration of
'WSAAsyncGetHostByAddr'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(2440) : error C2375: 'WSACancelAsyncRequest'
: redefinition; different linkage
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(932) : see declaration of
'WSACancelAsyncRequest'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(2461) : error C2375: 'WSAAsyncSelect' :
redefinition; different linkage
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(934) : see declaration of
'WSAAsyncSelect'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(3910) : error C2059: syntax error : '}'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(3910) : error C2143: syntax error : missing
';' before '}'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock2.h(3910) : error C2059: syntax error : '}'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2ipdef.h(39) : error C2143: syntax error : missing
';' before '{'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2ipdef.h(39) : error C2447: '{' : missing function
header (old-style formal list?)
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2ipdef.h(119) : warning C4005: 'IP_TOS' : macro
redefinition
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(352) : see previous definition of
'IP_TOS'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2ipdef.h(120) : warning C4005: 'IP_TTL' : macro
redefinition
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(351) : see previous definition of
'IP_TTL'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2ipdef.h(121) : warning C4005: 'IP_MULTICAST_IF' :
macro redefinition
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(346) : see previous definition of
'IP_MULTICAST_IF'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2ipdef.h(122) : warning C4005: 'IP_MULTICAST_TTL' :
macro redefinition
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(347) : see previous definition of
'IP_MULTICAST_TTL'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2ipdef.h(123) : warning C4005: 'IP_MULTICAST_LOOP' :
macro redefinition
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(348) : see previous definition of
'IP_MULTICAST_LOOP'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2ipdef.h(124) : warning C4005: 'IP_ADD_MEMBERSHIP' :
macro redefinition
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(349) : see previous definition of
'IP_ADD_MEMBERSHIP'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2ipdef.h(125) : warning C4005: 'IP_DROP_MEMBERSHIP' :
macro redefinition
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(350) : see previous definition of
'IP_DROP_MEMBERSHIP'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2ipdef.h(126) : warning C4005: 'IP_DONTFRAGMENT' :
macro redefinition
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\winsock.h(353) : see previous definition of
'IP_DONTFRAGMENT'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2tcpip.h(750) : error C2061: syntax error :
identifier 'MULTICAST_MODE_TYPE'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2tcpip.h(757) : error C2065: 'PIP_MSFILTER' :
undeclared identifier
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2tcpip.h(757) : error C2146: syntax error : missing
';' before identifier 'Filter'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2tcpip.h(757) : error C2065: 'Filter' : undeclared
identifier
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2tcpip.h(759) : error C2065: 'SourceCount' :
undeclared identifier
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2tcpip.h(760) : error C2070: ''unknown-type'':
illegal sizeof operand
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2tcpip.h(760) : error C2065: 'SourceList' :
undeclared identifier
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2tcpip.h(760) : error C2070: ''unknown-type'':
illegal sizeof operand
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2tcpip.h(761) : error C3861: 'WSASetLastError':
identifier not found
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2tcpip.h(765) : error C2065: 'IP_MSFILTER' :
undeclared identifier
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2tcpip.h(765) : error C2070: ''unknown-type'':
illegal sizeof operand
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2tcpip.h(766) : error C2146: syntax error : missing
';' before identifier 'HeapAlloc'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2tcpip.h(768) : error C3861: 'WSASetLastError':
identifier not found
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2tcpip.h(772) : error C2227: left of
'->imsf_multiaddr' must point to class/struct/union/generic type
type is ''unknown-type''
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2tcpip.h(773) : error C2227: left of
'->imsf_interface' must point to class/struct/union/generic type
type is ''unknown-type''
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2tcpip.h(774) : error C2227: left of '->imsf_fmode'
must point to class/struct/union/generic type
type is ''unknown-type''
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2tcpip.h(774) : error C2065: 'FilterMode' :
undeclared identifier
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2tcpip.h(775) : error C2227: left of '->imsf_numsrc'
must point to class/struct/union/generic type
type is ''unknown-type''
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2tcpip.h(778) : error C2227: left of '->imsf_slist'
must point to class/struct/union/generic type
type is ''unknown-type''
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2tcpip.h(778) : error C2070: ''unknown-type'':
illegal sizeof operand
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2tcpip.h(795) : error C2061: syntax error :
identifier 'MULTICAST_MODE_TYPE'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2tcpip.h(802) : error C2146: syntax error : missing
';' before identifier 'Filter'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2tcpip.h(805) : error C2070: ''unknown-type'':
illegal sizeof operand
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2tcpip.h(805) : error C2070: ''unknown-type'':
illegal sizeof operand
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2tcpip.h(806) : error C3861: 'WSASetLastError':
identifier not found
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2tcpip.h(810) : error C2070: ''unknown-type'':
illegal sizeof operand
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2tcpip.h(811) : error C2146: syntax error : missing
';' before identifier 'HeapAlloc'
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2tcpip.h(813) : error C3861: 'WSASetLastError':
identifier not found
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2tcpip.h(817) : error C2227: left of
'->imsf_multiaddr' must point to class/struct/union/generic type
type is ''unknown-type''
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2tcpip.h(818) : error C2227: left of
'->imsf_interface' must point to class/struct/union/generic type
type is ''unknown-type''
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2tcpip.h(819) : error C2227: left of '->imsf_numsrc'
must point to class/struct/union/generic type
type is ''unknown-type''
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2tcpip.h(827) : error C2227: left of '->imsf_slist'
must point to class/struct/union/generic type
type is ''unknown-type''
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2tcpip.h(827) : error C2070: ''unknown-type'':
illegal sizeof operand
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2tcpip.h(828) : error C2227: left of '->imsf_numsrc'
must point to class/struct/union/generic type
type is ''unknown-type''
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2tcpip.h(830) : error C2227: left of '->imsf_fmode'
must point to class/struct/union/generic type
C:\Program Files\Microsoft SDKs\Windows\v6.1\Include\ws2tcpip.h(830) : fatal error C1003: error count
exceeds 100; stopping compilation
All this means that winsock.h and winsock2.h are both being included and there can be only one!
The correct instructions
Building log4cxx
Rather than patching apr or Microsoft Windows SDK we attempt to use the latest versions of apr and apr-util where these problems have been fixed. (Spoiler: it works!)
(Is it obvious that we should be using the latest versions, you may ask? In our opinion, not at all!)
Thus the correct instructions (as of 26th August, 2009) are as follows.
Prerequisites
GnuWin32
We will need sed and some other *nix tools — their Windows ports. We use GnuWin32 which we have under
- C:\Programs\Win32\GnuWin32\
which you can download using GetGnuWin32.
This has sed, among other things.
Important: You should add
- C:\Programs\Win32\GnuWin32\bin\
(or wherever sed.exe lives) to your PATH environment variable.
Windows SDK
Windows SDK is a prerequisite. We are using Windows SDK for Windows Server 2008 and .NET Framework 3.5, obtainable from
Once you have installed the SDK using setup.exe, you will see its files (typically) under
- "C:\Program Files\Microsoft SDKs\Windows\v6.1\"
Important: In order to make the header files visible to the C++ compiler, you should add
- /I"C:\Program Files\Microsoft SDKs\Windows\v6.1\Include" /I"C:\Program Files\Microsoft Visual Studio 8\VC\include"
to your CL environment variable.
APR
"The mission of the Apache Portable Runtime (APR) project is to create and maintain software libraries that provide a predictable and consistent interface to underlying platform-specific implementations" (http://apr.apache.org/). In each case, both APR and APR-UTIL are required.
Choose a directory (we chose I:\dev\apache-log4cxx-0.10.0\) and download
to this directory.
Preparation
Then, from this directory:
unzip apr-1.3.8-win32-src.zip rename apr-1.3.8 apr unzip apr-util-1.3.9-win32-src.zip rename apr-util-1.3.9 apr-util cd apache-log4cxx-0.10.0 configure configure-aprutil
configure.bat copies the prefabricated log4cxx.hw and private/log4cxx_private.hw over to log4cxx.h and private/log4cxx_private.h.
configure-aprutil.bat uses sed to modify apu.hw and apr_ldap.hw to disable APR-Iconv and LDAP which are not necessary for log4cxx and problematic to build. If sed is not available, the modifications would be trivial to do in any text editor.
Use the Win32 source zips for APR and APR-Util to preserve the required line endings for the project files. Directories need to be renamed to "apr" and "apr-util" respectively.
Building log4cxx.dll
Open I:/dev/apache-log4cxx-0.10.0/projects/log4cxx.dsw with Microsoft Visual Studio 2005. You will be asked to convert the *.dsw Microsoft Visual Studio 6 project files to the *.sln and *.vcproj Microsoft Visual Studio 2005 project files. Agree to this, and continue.
Select "Debug" from the configuration drop-down list. Then Build > Build Solution. This should produce
- I:\dev\apache-log4cxx-0.10.0\projects\Debug\log4cxx.dll
Select "Release" from the configuration drop-down list. Then Build > Build Solution. This should produce
- I:\dev\apache-log4cxx-0.10.0\projects\Release\log4cxx.dll
Building log4cxx test suite
Prerequisites
Environment Variables
We are about to change the environment variables. For changes to take effect, close Visual Studio 2005.
Go to Control Panel > System > Advanced > Environment Variables and set the system variables
TOTO=wonderful key1=value1 key2=value2
*nix tools
You need gzip, zip and sed to run the tests. They must be on your PATH.
But if you have installed GnuWin32 as we advised you will find all of these under
- C:\Programs\Win32\GnuWin32\bin\
Building the test suite
Open I:\dev\apache-log4cxx-0.10.0\projects\testsuite.dsw. You will be asked to convert the project to Visual Studio 2005. Confirm this in the dialog boxes.
Select "Debug" from the configuration drop-down list. Then Build > Build Solution. This should produce
- I:\dev\apache-log4cxx-0.10.0\projects\Debug\testsuite.exe
Select "Release" from the configuration drop-down list. Then Build > Build Solution. This should produce
- I:\dev\apache-log4cxx-0.10.0\projects\Release\testsuite.exe
Running the test suite
Right-click on the testsuite project in Solution Explorer. Click on "Set as StartUp Project".
Right-click on the testsuite project (again). Click on "Properties". Select Congfiguration: "All Configurations". Under Configuration Properties > Debugging set Working Directory to ../src/test/resources. Click OK.
From the menu, Debug > Start Without Debugging.
Building log4cxx on Linux
We found it easier to build log4cxx on Linux. Maybe this is because we learned some lessons from the Windoes build. In each case we decided to document the procedure.
The original document by Apache can be found here:
Note that there are some differences between our procedure and theirs. We didn't have to sudo make install anything in order to get this to work. This may be useful, particularly if you are not a sudoer or do not have root access.
Prerequisites
System
We have built log4cxx on
- Linux V2.4.21
using
- gcc V3.2.3
- GNU Make V3.79.1
gcc must be on the PATH.
APR
We downloaded
to
- /home/paul/dev
Building APR
The following steps should build APR:
cd /home/paul/dev gzip -d apr-1.3.8.tar.gz tar xvf apr-1.3.8.tar cd apr-1.3.8 ./configure make make check
The last command should show something like
... testsockopt : SUCCESS teststr : SUCCESS teststrnatcmp : SUCCESS testtable : SUCCESS testtemp : SUCCESS testthread : SUCCESS testtime : SUCCESS testud : SUCCESS testuser : SUCCESS testvsn : SUCCESS All tests passed. ia32make[1]: Leaving directory `/home/paul/dev/apr-1.3.8/test'
This should have produced
- /home/paul/dev/apr-1.3.8/.libs/libapr-1.a
Building APR Util
We used the following sequence:
cd .. gzip -d apr-util-1.3.9.tar.gz tar xvf apr-util-1.3.9.tar cd apr-util-1.3.9 ./configure --with-apr=../apr-1.3.8 make make check
The last command should produce something like
... testmd5 : SUCCESS testdbd : SUCCESS testdate : SUCCESS testmemcache : SUCCESS testxml : SUCCESS testxlate : SUCCESS testrmm : SUCCESS testdbm : SUCCESS testqueue : SUCCESS testreslist : SUCCESS All tests passed.
This should have produced
- /home/paul/dev/apr-util-1.3.9/.libs/libaprutil-1.a
Building log4cxx
Finally,
cd .. unzip apache-log4cxx-0.10.0.zip cd apache-log4cxx-0.10.0 ./configure --with-apr=../apr-1.3.8 --with-apr-util=../apr-util-1.3.9 make make check
The last command should produce
testcase3 : SUCCESS All tests passed. ../cpp/testsuite -v testcase4 LC_CTYPE: C testcase4 : SUCCESS All tests passed. ia32make[3]: Leaving directory `/home/paul/dev/apache-log4cxx-0.10.0/src/test/resources' ia32make[3]: Entering directory `/home/paul/dev/apache-log4cxx-0.10.0/src/test' ia32make[3]: Nothing to be done for `check-am'. ia32make[3]: Leaving directory `/home/paul/dev/apache-log4cxx-0.10.0/src/test' ia32make[2]: Leaving directory `/home/paul/dev/apache-log4cxx-0.10.0/src/test' ia32make[2]: Entering directory `/home/paul/dev/apache-log4cxx-0.10.0/src' ia32make[2]: Nothing to be done for `check-am'. ia32make[2]: Leaving directory `/home/paul/dev/apache-log4cxx-0.10.0/src' ia32make[1]: Leaving directory `/home/paul/dev/apache-log4cxx-0.10.0/src' ia32make[1]: Entering directory `/home/paul/dev/apache-log4cxx-0.10.0' ia32make[1]: Nothing to be done for `check-am'. ia32make[1]: Leaving directory `/home/paul/dev/apache-log4cxx-0.10.0'
if we succeeded.
This should have produced
- /home/paul/dev/apache-log4cxx-0.10.0/src/main/cpp/.libs/liblog4cxx.a
Using Apache log4cxx
Here are some basic examples.
Don't worry if you see log4j in these examples. We are still on the C++ territory; the authors decided to stay faithful to the original log4j implementation, hence the names.
BasicConfigurator
#include <log4cxx/logger.h> #include <log4cxx/basicconfigurator.h> #include <tchar.h> using namespace log4cxx; LoggerPtr logger(Logger::getRootLogger()); int _tmain(int argc, _TCHAR* argv[]) { BasicConfigurator::configure(); LOG4CXX_DEBUG(logger, _T("This is a debug message")); LOG4CXX_INFO(logger, _T("This is an info message")); LOG4CXX_WARN(logger, _T("This is a warn message")); LOG4CXX_ERROR(logger, _T("This is an error message")); LOG4CXX_FATAL(logger, _T("This is a fatal message")); return 0; }
This produced the output
0 [0x00000dd4] DEBUG root null - This is a debug message 0 [0x00000dd4] INFO root null - This is an info message 0 [0x00000dd4] WARN root null - This is a warn message 0 [0x00000dd4] ERROR root null - This is an error message 0 [0x00000dd4] FATAL root null - This is a fatal message
Modifying BasicConfigurator configuration
It is possible to tweak the configuration produced by BasicConfigurator::configure. Here is an example.
#include <log4cxx/logger.h> #include <log4cxx/basicconfigurator.h> #include <log4cxx/patternlayout.h> #include <tchar.h> using namespace log4cxx; LoggerPtr logger(Logger::getRootLogger()); int _tmain(int argc, _TCHAR* argv[]) { BasicConfigurator::configure(); LoggerPtr logger(Logger::getRootLogger()); logger->setLevel(Level::getInfo()); AppenderList appenders(logger->getAllAppenders()); appenders[0]->setLayout(new PatternLayout(LOG4CXX_STR("%d{yyyy-MM-dd HH:mm:ss,SSS} %r %-5p [%t] (%F:%L) - %m%n"))); LOG4CXX_DEBUG(logger, _T("This is a debug message")); // The above line should have no effect as we have done // logger->setLevel(Level::getInfo()); LOG4CXX_INFO(logger, _T("This is an info message")); LOG4CXX_WARN(logger, _T("This is a warn message")); LOG4CXX_ERROR(logger, _T("This is an error message")); LOG4CXX_FATAL(logger, _T("This is a fatal message")); return 0; }
DOMConfigurator
The source file:
#include <log4cxx/logger.h> #include <log4cxx/xml/domconfigurator.h> #include <tchar.h> using namespace log4cxx; using namespace log4cxx::xml; LoggerPtr logger(Logger::getRootLogger()); int _tmain(int argc, _TCHAR* argv[]) { DOMConfigurator::configure("DevLogConfig.xml"); LOG4CXX_DEBUG(logger, _T("This is a debug message")); LOG4CXX_INFO(logger, _T("This is an info message")); LOG4CXX_WARN(logger, _T("This is a warn message")); LOG4CXX_ERROR(logger, _T("This is an error message")); LOG4CXX_FATAL(logger, _T("This is a fatal message")); return 0; }
The configuration file, DevLogConfig.xml:
<?xml version="1.0" encoding="UTF-8" ?> <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"> <root> <priority value="all" /> <appender-ref ref="ConsoleAppender" /> </root> <appender name="ConsoleAppender" class="org.apache.log4j.ConsoleAppender"> <param name="Target" value="System.out" /> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%5p [%t] (%F:%L) - %m%n" /> </layout> </appender> </log4j:configuration>
The output:
DEBUG [0x000012a4] (.\proto-log4cxx.cpp:15) - This is a debug message INFO [0x000012a4] (.\proto-log4cxx.cpp:16) - This is an info message WARN [0x000012a4] (.\proto-log4cxx.cpp:17) - This is a warn message ERROR [0x000012a4] (.\proto-log4cxx.cpp:18) - This is an error message FATAL [0x000012a4] (.\proto-log4cxx.cpp:19) - This is a fatal message
Note that we have chosen to call our appender ConsoleAppender by specifying
<appender name="ConsoleAppender" ...
Of course, we could have called it something else. (But the class tells us what implements the appender, so it has to be org.apache.log4j.ConsoleAppender.)
FileAppender
Of course, more often than not, we need to log to a file. We don't need to change any code. Just update DevLogConfig.xml in the example above to
<?xml version="1.0" encoding="UTF-8" ?> <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"> <root> <priority value="all" /> <appender-ref ref="ConsoleAppender" /> <appender-ref ref="FileAppender" /> </root> <appender name="ConsoleAppender" class="org.apache.log4j.ConsoleAppender"> <param name="Target" value="System.out" /> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%5p [%t] (%F:%L) - %m%n" /> </layout> </appender> <appender name="FileAppender" class="org.apache.log4j.FileAppender"> <param name="File" value="C:/MyApp.log" /> <param name="Append" value="true" /> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%5p [%t] (%F:%L) - %m%n" /> </layout> </appender> </log4j:configuration>
This will produce the output
DEBUG [0x00000990] (.\proto-log4cxx.cpp:15) - This is a debug message INFO [0x00000990] (.\proto-log4cxx.cpp:16) - This is an info message WARN [0x00000990] (.\proto-log4cxx.cpp:17) - This is a warn message ERROR [0x00000990] (.\proto-log4cxx.cpp:18) - This is an error message FATAL [0x00000990] (.\proto-log4cxx.cpp:19) - This is a fatal message
both on the console and in C:/MyApp.log. Of course, it's the same in both cases only because we are using identical ConversionPattern in the two appenders.
ConversionPattern
This is a good time to discuss the ConversionPattern. We were using
%5p [%t] (%F:%L) - %m%n
to get:
%5p %t (%F :%L) - %m %n INFO [0x00000990] (.\proto-log4cxx.cpp:16) - This is an info message
But we could try something fancier, such as
%d{yyyy-MM-dd HH:mm:ss,SSS} %r %-5p [%t] (%F:%L) - %m%n
which would give us
2009-08-27 14:00:50,259 31 INFO [0x00000b28] (.\proto-log4cxx.cpp:16) - This is an info message
Here is this line along with the conversion pattern, side by side:
%d{yyyy-MM-dd HH:mm:ss,SSS} %r %-5p [%t ] (%F :%L) - %m %n
2009-08-27 14:00:50,259 31 INFO [0x00000b28] (.\proto-log4cxx.cpp:16) - This is an info message
We could use a brief conversion pattern in our ConsoleAppender and a more comprehensive one in our FileAppender:
<?xml version="1.0" encoding="UTF-8" ?> <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"> <root> <priority value="all" /> <appender-ref ref="ConsoleAppender" /> <appender-ref ref="FileAppender" /> </root> <appender name="ConsoleAppender" class="org.apache.log4j.ConsoleAppender"> <param name="Target" value="System.out" /> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%r %-5p - %m%n" /> </layout> </appender> <appender name="FileAppender" class="org.apache.log4j.FileAppender"> <param name="File" value="C:/MyApp.log" /> <param name="Append" value="true" /> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss,SSS} %r %-5p [%t] (%F:%L) - %m%n" /> </layout> </appender> </log4j:configuration>
On the screen, we'll see
46 DEBUG - This is a debug message 46 INFO - This is an info message 46 WARN - This is a warn message 46 ERROR - This is an error message 62 FATAL - This is a fatal message
But in C:/MyApp.log we'll have more information:
2009-08-27 14:04:44,618 46 DEBUG [0x00001584] (.\proto-log4cxx.cpp:15) - This is a debug message 2009-08-27 14:04:44,618 46 INFO [0x00001584] (.\proto-log4cxx.cpp:16) - This is an info message 2009-08-27 14:04:44,618 46 WARN [0x00001584] (.\proto-log4cxx.cpp:17) - This is a warn message 2009-08-27 14:04:44,618 46 ERROR [0x00001584] (.\proto-log4cxx.cpp:18) - This is an error message 2009-08-27 14:04:44,634 62 FATAL [0x00001584] (.\proto-log4cxx.cpp:19) - This is a fatal message
The conversion characters, like "%r" (which is, by the way, the number of milliseconds elapsed since the start of the application until the creation of the logging event) are documented here.
Reconfiguring log4cxx dynamically
Is it possible to reconfigure log4cxx on the fly after it has already been configured? Apparently it is.
Code:
#include <log4cxx/logger.h> #include <log4cxx/basicconfigurator.h> #include <log4cxx/xml/domconfigurator.h> #include <tchar.h> using namespace log4cxx; using namespace log4cxx::xml; LoggerPtr logger(Logger::getRootLogger()); int _tmain(int argc, _TCHAR* argv[]) { // First, use BasicConfigurator BasicConfigurator::configure(); LOG4CXX_DEBUG(logger, _T("This is a debug message")); LOG4CXX_INFO(logger, _T("This is an info message")); LOG4CXX_WARN(logger, _T("This is a warn message")); LOG4CXX_ERROR(logger, _T("This is an error message")); LOG4CXX_FATAL(logger, _T("This is a fatal message")); // Now, reconfigured using DOMConfigurator DOMConfigurator::configure("DevLogConfig.xml"); LOG4CXX_DEBUG(logger, _T("This is a debug message")); LOG4CXX_INFO(logger, _T("This is an info message")); LOG4CXX_WARN(logger, _T("This is a warn message")); LOG4CXX_ERROR(logger, _T("This is an error message")); LOG4CXX_FATAL(logger, _T("This is a fatal message")); return 0; }
Output:
0 [0x00001110] DEBUG root null - This is a debug message 0 [0x00001110] INFO root null - This is an info message 0 [0x00001110] WARN root null - This is a warn message 0 [0x00001110] ERROR root null - This is an error message 0 [0x00001110] FATAL root null - This is a fatal message 31 DEBUG - This is a debug message 31 INFO - This is an info message 31 WARN - This is a warn message 31 ERROR - This is an error message 31 FATAL - This is a fatal message
Detecting user name and directory; system properties
In production, the process may not have the permission to access C:/MyApp.log. It is more sensible to place it under the user's home directory:
"C:\Documents and Settings\paul\MyApp.log"
But how do we know, in our DevLogConfig.xml where it is at runtime?
Also, it may be useful to output the username as part of our message, particularly in multi-user systems.
We can use the properties ${user.home} and ${user.name}:
<?xml version="1.0" encoding="UTF-8" ?> <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"> <root> <priority value="all" /> <appender-ref ref="ConsoleAppender" /> <appender-ref ref="FileAppender" /> </root> <appender name="ConsoleAppender" class="org.apache.log4j.ConsoleAppender"> <param name="Target" value="System.out" /> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%r %-5p - %m%n" /> </layout> </appender> <appender name="FileAppender" class="org.apache.log4j.FileAppender"> <param name="File" value="${user.home}/MyApp.log" /> <param name="Append" value="true" /> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss,SSS} %r %-5p ${user.name} [%t] (%F:%L) - %m%n" /> </layout> </appender> </log4j:configuration>
In summary, the Logsystem properties that <tt>log4cxx supports are:
- java.io.tmpdir — the temporary directory, something like C:/Documents and Settings/paul/Local Settings/Temp
- user.dir — the user's current directory (not home directory!)
- user.home — the user's home directory, something like C:/Documents and Settings/paul/Local Settings/Temp
- user.name — the username, something like paul
Logging to Windows NT/XP/etc. Event Log
Simply add a org.apache.log4j.nt.NTEventLogAppender log appender to DevLogConfig.xml which we use in the above examples:
<?xml version="1.0" encoding="UTF-8" ?> <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"> <root> <priority value="all" /> <appender-ref ref="ConsoleAppender" /> <appender-ref ref="FileAppender" /> <appender-ref ref="NTEventLogAppender" /> </root> <appender name="ConsoleAppender" class="org.apache.log4j.ConsoleAppender"> <param name="Target" value="System.out" /> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%r %-5p - %m%n" /> </layout> </appender> <appender name="FileAppender" class="org.apache.log4j.FileAppender"> <param name="File" value="${user.home}/MyApp.log" /> <param name="Append" value="true" /> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss,SSS} %r %-5p ${user.name} [%t] (%F:%L) - %m%n" /> </layout> </appender> <appender name="NTEventLogAppender" class="org.apache.log4j.nt.NTEventLogAppender"> <param name="Source" value="MyApp" /> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%r %-5p [%t] (%F:%L) - %m%n" /> </layout> </appender> </log4j:configuration>
You should now be able to view the logged events in Event Viewer (Control Panel > Administrative Tools > Event Viewer), under the Event Viewer (Local) > Application log.
We can add a threshold to the NTEventLogAppender definition so only the WARN, ERROR, and FATAL level events get logged. In order to do this, we amend the corresponding appender section as follows:
... <appender name="NTEventLogAppender" class="org.apache.log4j.nt.NTEventLogAppender"> <param name="Threshold" value="WARN" /> <param name="Source" value="MyApp" /> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%r %-5p [%t] (%F:%L) - %m%n" /> </layout> </appender> ...
Rolling file appenders
Here is an example size-based rolling file appender:
... <appender name="SizeBasedRollingFileAppender" class="org.apache.log4j.rolling.RollingFileAppender"> <triggeringPolicy class="org.apache.log4j.rolling.SizeBasedTriggeringPolicy"> <param name="MaxFileSize" value="100KB" /> </triggeringPolicy> <rollingPolicy class="org.apache.log4j.rolling.FixedWindowRollingPolicy"> <param name="FileNamePattern" value="${user.home}/MyApp-%i.log" /> <param name="MaxIndex" value="10" /> </rollingPolicy> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss,SSS} %r %-5p ${user.name} [%t] (%F:%L) - %m%n" /> </layout> </appender> ...
and a time-based rolling file appender:
... <appender name="TimeBasedRollingFileAppender" class="org.apache.log4j.rolling.RollingFileAppender"> <rollingPolicy class="org.apache.log4j.rolling.TimeBasedRollingPolicy"> <param name="FileNamePattern" value="${user.home}/MyApp-%d{yyyy-MM-dd_HH_mm}.log" /> </rollingPolicy> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss,SSS} %r %-5p ${user.name} [%t] (%F:%L) - %m%n" /> </layout> </appender> ...
A new log file will be created every minute. If you want it created every hour, simply replace the line
<param name="FileNamePattern" value="${user.home}/MyApp-%d{yyyy-MM-dd_HH_mm}.log" />with
<param name="FileNamePattern" value="${user.home}/MyApp-%d{yyyy-MM-dd_HH}.log" />The rest is pretty self-explanatory.
A Summary So Far
We have mentioned quite a few different appenders and techniques, so it's probably a good idea to examine a configuration file that includes all/most of them. Here it is:
<?xml version="1.0" encoding="UTF-8" ?> <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"> <root> <priority value="all" /> <appender-ref ref="ConsoleAppender" /> <appender-ref ref="FileAppender" /> <appender-ref ref="SizeBasedRollingFileAppender" /> <appender-ref ref="TimeBasedRollingFileAppender" /> <appender-ref ref="NTEventLogAppender" /> </root> <appender name="ConsoleAppender" class="org.apache.log4j.ConsoleAppender"> <param name="Target" value="System.out" /> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%r %-5p - %m%n" /> </layout> </appender> <appender name="FileAppender" class="org.apache.log4j.FileAppender"> <param name="File" value="${user.home}/MyApp.log" /> <param name="Append" value="true" /> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss,SSS} %r %-5p ${user.name} [%t] (%F:%L) - %m%n" /> </layout> </appender> <appender name="SizeBasedRollingFileAppender" class="org.apache.log4j.rolling.RollingFileAppender"> <triggeringPolicy class="org.apache.log4j.rolling.SizeBasedTriggeringPolicy"> <param name="MaxFileSize" value="100KB" /> </triggeringPolicy> <rollingPolicy class="org.apache.log4j.rolling.FixedWindowRollingPolicy"> <param name="FileNamePattern" value="${user.home}/MyApp-%i.log"/> <param name="MaxIndex" value="10"/> </rollingPolicy> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss,SSS} %r %-5p ${user.name} [%t] (%F:%L) - %m%n" /> </layout> </appender> <appender name="TimeBasedRollingFileAppender" class="org.apache.log4j.rolling.RollingFileAppender"> <rollingPolicy class="org.apache.log4j.rolling.TimeBasedRollingPolicy"> <param name="FileNamePattern" value="${user.home}/MyApp-%d{yyyy-MM-dd_HH_mm}.log"/> </rollingPolicy> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss,SSS} %r %-5p ${user.name} [%t] (%F:%L) - %m%n" /> </layout> </appender> <appender name="NTEventLogAppender" class="org.apache.log4j.nt.NTEventLogAppender"> <param name="Threshold" value="WARN" /> <param name="Source" value="MyApp" /> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%r %-5p [%t] (%F:%L) - %m%n" /> </layout> </appender> </log4j:configuration>