【问题标题】:Send JNI C stderr/stdout through log4j通过 log4j 发送 JNI C stderr/stdout
【发布时间】:2009-12-30 22:44:05
【问题描述】:

我的 java 应用程序使用 JNI 调用用 C 编写的库。这个本机库将错误记录到 stderr,但我想以某种方式通过我的 log4j 记录器重定向错误流。这可能吗?

C 库是外部的 - 我没有源代码,所以无法更改。

谢谢

【问题讨论】:

  • JNI 层是您的应用程序的一部分还是外部工具包的一部分?
  • 这也是外部工具包的一部分。
  • 以什么粒度调用外部代码,来回传递多少数据?换句话说,您可以将工作作为子进程生成吗?重定向您无法控制的 C 代码的 stdout 或 stderr 非常困难。我以为我以前做过,但自从我编写那种 C 代码以来至少已经有 10 年了,我在网上只能找到关于将它重定向到文件的信息。

标签: java logging java-native-interface


【解决方案1】:

注意:我没有尝试过这个答案; YMMV。

POSIX 方法freopen 将更改与流关联的基础文件。正如手册页所述:“freopen() 函数的主要用途是更改与标准文本流(stderr、stdin 或 stdout)关联的文件”。

因此,您可以创建自己的 JNI 库,该库只需将流重定向到文件中。 但是,要完成这项工作有几个严重的障碍:

  1. 您需要确保您的 Java 程序本身不使用标准 流,因为它们会 也重定向了。一种解决方法 这是为了改变System.out et al 当你的程序启动时,其他的东西。
  2. 有可能 第三方库绕过标准 文本流,并直接写入 底层文件描述符。它是 不太可能但可能。我不能 记住是否 freopen() 只是 更改使用的文件描述符 缓冲的流,或者实际上 重新打开底层 fd。
  3. 你会 还是有连接问题 将“文件”更改为记录器。

最后一点是迄今为止最大的一点:stdio 写入操作系统级别的文件描述符。您必须创建一些 Java 级别的代码来读取该描述符并写入日志。我的第一个想法是您必须使用命名管道,然后启动一个新的 Java 线程来读取该管道。但这不能移植到不同的操作系统,并且您可以在程序的配置中管理管道名称。

假设这是一个服务器程序,并且本身不处理标准 IO 流,我认为您最好的解决方案是使用控制台记录器配置 Log4J,并将所有控制台输出重定向到一个文件。

或者与编写库的人交谈,让他们添加可配置的日志记录。

【讨论】:

    【解决方案2】:

    我的 C 有点生疏,但有可能,因为您可以通过 JNI 从 C 中调用 PrinStream 方法。但是您必须找到一种方法来挂钩何时写入流。

    更新:这可能会帮助您从 C 中连接到标准输出:

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

    【讨论】:

    • 谢谢,但很遗憾我无法更改 C 库,因为它不是我的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-03-29
    • 2012-07-22
    • 1970-01-01
    • 1970-01-01
    • 2019-01-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多