Skip to content

Commit

Permalink
#209 Set Log callback. Add Paho C logging to Rust logs
Browse files Browse the repository at this point in the history
  • Loading branch information
fpagliughi committed Sep 11, 2023
1 parent 45740e8 commit 4159335
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 1 deletion.
52 changes: 51 additions & 1 deletion src/async_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ use std::{
ptr, slice, str,
sync::{
atomic::{AtomicU32, Ordering},
Arc, Mutex,
Arc, Mutex, Once,
},
time::Duration,
};
Expand Down Expand Up @@ -135,6 +135,9 @@ struct CallbackContext {
on_message_arrived: Option<Box<MessageArrivedCallback>>,
}

// Runs code to initialize the underlying C library
static C_LIB_INIT: Once = Once::new();

impl AsyncClient {
/// Creates a new MQTT client which can connect to an MQTT broker.
///
Expand All @@ -146,6 +149,18 @@ impl AsyncClient {
where
T: Into<CreateOptions>,
{
// Do any initialization of the C lib
C_LIB_INIT.call_once(|| {
if let Some(lvl) = crate::paho_c_trace_level() {
debug!("Setting Paho C log level to {}", lvl);
unsafe {
ffi::MQTTAsync_setTraceCallback(Some(Self::on_trace));
ffi::MQTTAsync_setTraceLevel(lvl);
}
}
});

// Create the client
let mut opts = opts.into();
debug!("Create options: {:?}", opts);

Expand Down Expand Up @@ -230,6 +245,41 @@ impl AsyncClient {
self.inner.handle
}

// Low-level callback from the C library for log/trace messages.
// We send the
unsafe extern "C" fn on_trace(lvl: ffi::MQTTASYNC_TRACE_LEVELS, msg: *mut c_char) {
if msg.is_null() {
return;
}

let cmsg = CStr::from_ptr(msg);
let msg = match cmsg.to_str() {
Ok(s) => s,
Err(_) => return,
};

let lvl = match lvl {
ffi::MQTTASYNC_TRACE_LEVELS_MQTTASYNC_TRACE_FATAL |
ffi::MQTTASYNC_TRACE_LEVELS_MQTTASYNC_TRACE_SEVERE =>
log::Level::Error,

ffi::MQTTASYNC_TRACE_LEVELS_MQTTASYNC_TRACE_ERROR =>
log::Level::Warn,

ffi::MQTTASYNC_TRACE_LEVELS_MQTTASYNC_TRACE_PROTOCOL =>
log::Level::Info,

ffi::MQTTASYNC_TRACE_LEVELS_MQTTASYNC_TRACE_MINIMUM |
ffi::MQTTASYNC_TRACE_LEVELS_MQTTASYNC_TRACE_MEDIUM =>
log::Level::Debug,

ffi::MQTTASYNC_TRACE_LEVELS_MQTTASYNC_TRACE_MAXIMUM | _ =>
log::Level::Trace,
};

log!(target: "paho_mqtt_c", lvl, "{}", msg);
}

// Low-level callback from the C library when the client is connected.
// We just pass the call on to the handler registered with the client, if any.
unsafe extern "C" fn on_connected(context: *mut c_void, _cause: *mut c_char) {
Expand Down
62 changes: 62 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,68 @@ pub fn from_c_bool(on: c_int) -> bool {
on != 0
}

/// The log target (module) for the Paho C trace logs
const PAHO_C_LOG_TARGET: &str = "paho_mqtt_c";

/// Converts a Paho C trace level into a Rust log level.
pub fn from_c_trace_level(level: ffi::MQTTASYNC_TRACE_LEVELS) -> log::Level {
match level {
ffi::MQTTASYNC_TRACE_LEVELS_MQTTASYNC_TRACE_FATAL |
ffi::MQTTASYNC_TRACE_LEVELS_MQTTASYNC_TRACE_SEVERE =>
log::Level::Error,

ffi::MQTTASYNC_TRACE_LEVELS_MQTTASYNC_TRACE_ERROR =>
log::Level::Warn,

ffi::MQTTASYNC_TRACE_LEVELS_MQTTASYNC_TRACE_PROTOCOL =>
log::Level::Info,

ffi::MQTTASYNC_TRACE_LEVELS_MQTTASYNC_TRACE_MINIMUM |
ffi::MQTTASYNC_TRACE_LEVELS_MQTTASYNC_TRACE_MEDIUM =>
log::Level::Debug,

ffi::MQTTASYNC_TRACE_LEVELS_MQTTASYNC_TRACE_MAXIMUM | _ =>
log::Level::Trace,
}
}

/// Converts a Rust log level filer into a Paho C trace level.
/// This gives the most verbose C trace level for the log level.
pub fn log_into_c_trace_level(level: log::LevelFilter) -> Option<ffi::MQTTASYNC_TRACE_LEVELS> {
use log::LevelFilter::*;
match level {
Off => None,
Error => Some(ffi::MQTTASYNC_TRACE_LEVELS_MQTTASYNC_TRACE_SEVERE),
Warn => Some(ffi::MQTTASYNC_TRACE_LEVELS_MQTTASYNC_TRACE_ERROR),
Info => Some(ffi::MQTTASYNC_TRACE_LEVELS_MQTTASYNC_TRACE_PROTOCOL),
Debug => Some(ffi::MQTTASYNC_TRACE_LEVELS_MQTTASYNC_TRACE_MEDIUM),
Trace => Some(ffi::MQTTASYNC_TRACE_LEVELS_MQTTASYNC_TRACE_MAXIMUM),
}
}

/// Gets the trace level, if any, to set the Paho C library
pub fn paho_c_trace_level() -> Option<ffi::MQTTASYNC_TRACE_LEVELS> {
use log::Level::*;
if log_enabled!(target: PAHO_C_LOG_TARGET, Trace) {
Some(ffi::MQTTASYNC_TRACE_LEVELS_MQTTASYNC_TRACE_MAXIMUM)
}
else if log_enabled!(target: PAHO_C_LOG_TARGET, Debug) {
Some(ffi::MQTTASYNC_TRACE_LEVELS_MQTTASYNC_TRACE_MEDIUM)
}
else if log_enabled!(target: PAHO_C_LOG_TARGET, Info) {
Some(ffi::MQTTASYNC_TRACE_LEVELS_MQTTASYNC_TRACE_PROTOCOL)
}
else if log_enabled!(target: PAHO_C_LOG_TARGET, Warn) {
Some(ffi::MQTTASYNC_TRACE_LEVELS_MQTTASYNC_TRACE_ERROR)
}
else if log_enabled!(target: PAHO_C_LOG_TARGET, Error) {
Some(ffi::MQTTASYNC_TRACE_LEVELS_MQTTASYNC_TRACE_SEVERE)
}
else {
None
}
}

/////////////////////////////////////////////////////////////////////////////
// Unit Tests
/////////////////////////////////////////////////////////////////////////////
Expand Down

0 comments on commit 4159335

Please sign in to comment.