Using pantheios to log from a C++ JNI DLL

I originally published this post on my old blog in 2009. I’ve edited it a little for readability but left the contents unchanged, so it may be out of date and not reflect the current state of the pantheios library. I also haven’t been using pantheios for logging since about 2010, and have been using Boost.Log instead.

I recently had to come up with a logging solution for C++ code a JNI DLL/shared library that is providing the data translation layer between Java and underlying native C and C++ libraries. As usual, some logging was required to aid fault-finding in a production environment, if necessary. A quick survey of the state of C++ logging showed that not a lot had changed since I last looked at logging libraries. In fact, a lot of them seem to have survived unchanged for several years. I’m not sure if that is a good thing and a sign of maturity or a sign of “making do” and the low priority most projects assign to a performant logging library. Eventually I settled on pantheios as it offered several features that were crucial for this application. The major one was that pantheios it is extremely modular and will only link in the parts you really need. I consider this a major advantage over the more monolithic libraries that pull in all their functionality all the time, especially when you link them in as a static library (yes, log4cxx, I’m looking at you). Linking in the logging library as a static library was necessary to avoid conflicts with other libraries that are being used in the same process.

Initial tests in a simple command line program suggested that worked well and matched the requirements. Unfortunately I couldn’t get it to log at all inside the JNI DLL, so I ended up trawling Google’s search results for quite a while and experimented quite a lot of different settings until I ended up with a working combination.

First, pantheios initialises itself automatically if you use it inside a regular executable. For various reasons, it can’t do that inside a Windows DLL, so you have to do that explicitly. Fortunately, Matthew Wilson, the author of pantheios, had explained on a mailing list how to do this. Typically, I can’t find the post anymore so here’s the code that I’m using to initialise the library, which is more or less a verbatim copy of Matthew’s code minus a couple of lines that weren’t required:

#include <iostream>

#include <pantheios/pantheios.hpp>
#include <pantheios/inserters.hpp> 
#include <pantheios/frontends/stock.h>

const char PANTHEIOS_FE_PROCESS_IDENTITY[] = "JNITestDll.1";

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  dwReason,
                       LPVOID lpReserved
                                         )
{
  if (dwReason == DLL_PROCESS_ATTACH)
  {
    if (pantheios::pantheios_init() < 0)
    {
      std::cout << "Failed to initialise the Pantheios logging libraries!n" << std::endl;
      return FALSE;
    }
    else
    {
      pantheios::log_INFORMATIONAL("Logger enabled!");
    }
  }
  else if (dwReason == DLL_PROCESS_DETACH)
  {
    pantheios::log_INFORMATIONAL("Logger disabled!");
    pantheios::pantheios_uninit();
  }
  return TRUE;  // ok
}

This seemed to initialise the library correctly. I wasn’t getting any error messages to prove otherwise but unfortunately I still wasn’t getting any output either. Yes, I could see that pantheios_init() returned a value that indicated successful initialisation, the logging functions were called and the output went straight into the bit bucket somewhere.

It took me a little while to work out what happened but in the end I tracked it down to something that I filed under “JNI oddity”. Pantheios supports implicit linking for both its frontends (the part that you interact with) and its backends which are responsible for sending the output somewhere. Being the usual lazy so-and-so programmer, I had borrowed one of the implicit link files from the samples. Which should have worked OK as it was for a command line executable, but didn’t.

After some poking and prodding I realised that the issue was that by default, in this particular implicit link file pantheios would use the Windows Console logger when the code was built Windows. This didn’t work (probably because this was in a DLL and there wasn’t a console associated with it. Switching to the fprintf backend fixed this issue and I was finally seeing logging output from the JNI DLL. Here is the code for the implicit linking:

/* Pantheios Header Files */
#include <pantheios/implicit_link/core.h>
#include <pantheios/implicit_link/fe.simple.h>
#include <platformstl/platformstl.h>
#include <pantheios/implicit_link/be.fprintf.h>

#if (   defined(UNIX) || 
        defined(unix))&& 
    (   defined(_WIN32) || 
        defined(_WIN64))
# include <unixem/implicit_link.h>
#endif /* _WIN32 || _WIN64 */

All in all I’m happy with Pantheios as a logging solution. If you’re looking for a versatile C++ logger, I’d recommend you look at it.

Note from 2014: In a project that is not using or cannot use Boost, I would still look at pantheios first before looking at other libraries.

Boost.Log, preventing the’unhandled exception’in Windows 7 when attempting to log to the event log

I recently ran into a requirements for retrofitting a logging library to an existing project. My first instinct was to throw Pantheios at it as I’ve used it before and It Just Worked. Unfortunately in this case, we needed the ability to log to more than two event sinks and it looked like this was getting a little awkward with Pantheios, which prompted me to look at Boost.Log.

After some digging through the documentation and the samples, I managed to get the logging going to the three event sinks we needed. So far, so good, but every time I started up the program it reported an unhandled exception on Windows 7 when it was trying to initialise the simple_event_log backend and the software wasn’t run as administrator. Curiously enough, the log messages still did appear in the event log, just with lots of unnecessary decoration.

The reason for this problem was that the registry key in HKEY_LOCAL_MACHINESystemCurrentControlSetServicesEventLog that the application needs access to both has to be present (if you’re not administrator, you don’t have the privileges to create it) and the user who runs the application also needs to be able to both read and write to it. Normally you’d need the installer to create the key as it tends to run with administrator privileges; the installer also needs to set the permissions on the created key to ‘Full Control’. Once both the key and the permissions are set correctly, the backend will register OK without any unhandled exceptions.

Unfortunately, if the event log backend can’t create the event log registry entry by itself during its initalisation phase, it is also necessary to point the event log at the file that contains the event messages. In order to do this, the installer also needs to create a string value in the newly added application-specific key that has the name “EventMessageFile” and that points at the correct boost_log dll.

Once the above entries are in the registry, logging to the event log using the simple_event_log backend Just Works, too.