tags:

views:

352

answers:

2

My java app uses JNI to invoke a library written in C. This native library logs errors to stderr but I would like to redirect the error stream through my log4j logger somehow. Is this possible?

The C library is external - I don't have the source, so cannot change it.

Thanks

A: 

My C is a little rusty, but it may be possible, since you can invoke the PrinStream methods from within a C via JNI. But you'll have to find a way to hook into when the stream gets written to.

Update: This might help you with hooking into stdout from within C:

http://www.gnu.org/software/hello/manual/libc/Hook-Functions.html

Kristopher Ives
Thanks, but unfortunately I can't change the C library as it's not mine.
dogbane
+2  A: 

Note: I have not tried this answer; YMMV.

The POSIX method freopen will change the underlying file associated with a stream. As the manpage states: "The primary use of the freopen() function is to change the file associated with a standard text stream (stderr, stdin, or stdout)".

So, you could create your own JNI library that simply redirects the stream into a file. However, there are several serious roadblocks to making this work:

  1. You'll need to ensure that your Java program doesn't itself use standard streams, because they'll be redirected too. A workaround for this is to change System.out et al to something else when your program starts up.
  2. It's possible that the third-party library bypasses the standard text streams, and writes directly to the underlying file descriptor. It's unlikely but possible. I can't remember whether freopen() just changes the file descriptor used by the buffered stream, or actually re-opens the underlying fd.
  3. You'll still have the problem of connecting changes to the "file" to a logger.

That last point is by far the biggest: stdio writes to an OS-level file descriptor. You would have to create some Java-level code to read that descriptor and write to a log. My first thought is that you'd have to use a named pipe, and then spin up a new Java thread to read that pipe. But that won't be portable to different operating systems, and will that you manage the pipe name in your program's configuration.

Assuming that this is a server program, and does not itself process the standard IO streams, I think your best solution will be to configure Log4J with a console logger, and simply redirect all console output to a file.

Or talk to the people who wrote the library, to get them to add configurable logging.

kdgregory