问题描述
我的java应用程序使用JNI来调用用C编写的库。这个本机库将错误记录到stderr,但我想以某种方式通过我的log4j记录器重定向错误流。这可能吗?
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?
C库是外部的 - 我没有源代码,因此无法更改它。
The C library is external - I don't have the source, so cannot change it.
谢谢
推荐答案
注意:我没有尝试过这个答案; YMMV。
Note: I have not tried this answer; YMMV.
POSIX方法 freopen
将更改与流关联的基础文件。正如联机帮助页所述:freopen()函数的主要用途是更改与标准文本流(stderr,stdin或stdout)关联的文件。
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)".
因此,您可以创建自己的JNI库,只需将流重定向到文件中。 然而,使这项工作有几个严重的障碍:
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:
- 你需要确保你的Java
程序本身不使用标准的
流,因为它们也将被重定向
。
的解决方法是在程序启动时将System.out
等
更改为其他内容。 - 第二方库的
可能会绕过标准的
文本流,并直接写入底层文件描述符
。不太可能,但可能是
。我不能
记住freopen()只是
更改缓冲流
使用的文件描述符,或者实际
重新打开底层fd。 - 您还需要
将
更改连接到文件到记录器。
- You'll need to ensure that your Javaprogram doesn't itself use standardstreams, because they'll beredirected too. A workaround forthis is to change
System.out
et alto something else when your program starts up. - It's possible thatthe third-party library bypasses the standardtext streams, and writes directly tothe underlying file descriptor. It'sunlikely but possible. I can'tremember whether freopen() justchanges the file descriptor used bythe buffered stream, or actuallyre-opens the underlying fd.
- You'llstill have the problem of connectingchanges to the "file" to a logger.
最后一点是迄今为止最大的:stdio写入操作系统级文件描述符。您必须创建一些Java级代码来读取该描述符并写入日志。我的第一个想法是你必须使用命名管道,然后启动一个新的Java线程来读取该管道。但是这不能移植到不同的操作系统,并且你将在程序的配置中管理管道名称。
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.
假设这是一个服务器程序,并且不是自己处理标准IO流,我认为你最好的解决方案是用控制台记录器配置Log4J,并简单地将所有控制台输出重定向到一个文件。
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.
这篇关于通过log4j发送JNI C stderr / stdout的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!