简体   繁体   English

Java/Rust 日志桥

[英]Java/Rust logging bridge

I have a Java program that uses JNI to call a Rust library.我有一个 Java 程序,它使用 JNI 调用 Rust 库。 In the rust code, I have calls to info!在 rust 代码中,我有电话咨询info! which do not appear in the output.没有出现在 output 中。 I am 99% positive this is because I am not initializing the Rust logging system.我 99% 肯定这是因为我没有初始化 Rust 日志系统。

When I had a similar problem in Python code calling Rust code, there was a module that I added which did the work to connect the Rust logging system to the python logger. When I had a similar problem in Python code calling Rust code, there was a module that I added which did the work to connect the Rust logging system to the python logger.

Is there a similar bridge for Rust and Java? Rust 和 Java 是否有类似的桥接?

I am using slf4j in Java and log::info in Rust.我在 Java 中使用slf4j ,在 Rust 中使用log::info

I searched for an bridge but the closest I found was how to call Rust from Java.我搜索了一座桥,但我找到的最接近的是如何从 Java 调用 Rust。

The log library provides only a mechanism for passing log messages to a global hook. log库仅提供一种将日志消息传递到全局挂钩的机制。 Something must call log::set_logger() with a function that does something with the messages.必须使用 function 调用log::set_logger()来处理消息。 There are a variety of libraries you can use for this purpose ;多种库可以用于此目的 if you want to hook up your log logging to slf4j you will need to find or write code that does that combination specifically.如果您想将log记录连接到slf4j ,您将需要查找或编写专门执行该组合的代码。 (I don't know much of anything about JNI+Rust so I can't say whether one exists already.) (我对 JNI+Rust 知之甚少,所以我不能说是否已经存在。)

  1. Create your own logger (don't use env_logger or others):创建自己的记录器(不要使用 env_logger 或其他):
use std::sync::Arc;
use log::{LevelFilter, Level};
pub type LogCallbackType = Arc<dyn Fn(Level, String) + Send + Sync>;
pub struct SimpleLogger {
  callback: LogCallbackType,
  level: LevelFilter,
}
  1. Provide a function to bind a callback to your logger提供 function 以将回调绑定到您的记录器
impl SimpleLogger {
  pub fn init(level: LevelFilter, callback: LogCallbackType) {
    let message = std::format!("Initialize logging to {}", &level);
    callback(Level::Debug, message);

    log::set_boxed_logger(Box::new(SimpleLogger { callback, level }))
      .map(|()| log::set_max_level(level));
  }
  1. Externalize your function to other languages将您的 function 外化为其他语言
use std::os::raw::c_char;
pub type NativeString = *const c_char;
pub type ExternLogCallbackType = Option<extern "C" fn(u32, NativeString)>;

#[no_mangle]
pub extern fn init_logging(level: u32, callback: ExternLogCallbackType) {
  if !callback.is_none() {
    let callback = callback.unwrap();
    let level_filter = SimpleLogger::u32_to_level_filter(level);
    SimpleLogger::init(level_filter, Arc::new(move |level, msg| {
      callback(level as u32, msg.as_ptr());
    }))
  }
}
  1. Prepare the JNA stuff准备 JNA 的东西
public static class LogCallback implements Callback {
  public static final Logger LOGGER = LoggerFactory.getLogger("myrustliblog");

  public void callback(int level, String message) {
    switch (level) {
      case 0:
        break;
      case 1:
        LOGGER.error(message);
        break;
      case 2:
        LOGGER.warn(message);
        break;
      case 3:
        LOGGER.info(message);
        break;
      case 4:
        LOGGER.debug(message);
        break;
      case 5:
        LOGGER.trace(message);
        break;
      default:
        LOGGER.trace(message);
        break;
    }
  }
}

public interface MyNativeInterface extends Library {
   //...other stuff ...

   String init_logging(int level, LogCallback callback);
   //...
}
  1. Finally Initialize logging from Java:最后从 Java 初始化日志记录:
static final LogCallback LOG_CALLBACK = new LogCallback();

public static void initLogging(org.slf4j.event.Level level) {
    int iLevel = 0;
    switch (level) {
      case ERROR:
        iLevel = 1;
        break;
      case WARN:
        iLevel = 2;
        break;
      case INFO:
        iLevel = 3;
        break;
      case DEBUG:
        iLevel = 4;
        break;
      case TRACE:
        iLevel = 5;
        break;
    }
    _myInterfaceJnaInstance.init_logging(iLevel, LOG_CALLBACK);
  }

Notes:笔记:

  1. I omitted result handling in Rust.我省略了 Rust 中的结果处理。 You should be able to do it你应该能够做到
  2. This is from my running code, it works.这是来自我的运行代码,它有效。 But you might need to do a few tweaks for memory leaks (ie deallocate the strings after being logged).但是您可能需要对 memory 泄漏进行一些调整(即在记录后释放字符串)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM