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 12, 2023
1 parent ce18462 commit 25f9dcd
Show file tree
Hide file tree
Showing 3 changed files with 172 additions and 1 deletion.
17 changes: 16 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::c_trace_level() {
debug!("Setting Paho C log level to {}", lvl);
unsafe {
ffi::MQTTAsync_setTraceCallback(Some(crate::on_c_trace));
ffi::MQTTAsync_setTraceLevel(lvl);
}
}
});

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

Expand Down
102 changes: 102 additions & 0 deletions src/c_trace.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// c_trace.rs
//
// This file is part of the Eclipse Paho MQTT Rust Client library.
//

/*******************************************************************************
* Copyright (c) 2023 Frank Pagliughi <fpagliughi@mindspring.com>
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Frank Pagliughi - initial implementation and documentation
*******************************************************************************/

//! Module for passing Paho C trace statements to the Rust log facility.
//!

use crate::ffi;
use std::{ffi::CStr, os::raw::c_char};

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

// Low-level callback from the C library for log/trace messages.
// We send the traces to the Rust logger, approximating the log level from
// the C library, which has more levels than the Rust logger.
// This should be installed by the client once when the first one is
// created.
pub(crate) unsafe extern "C" fn on_c_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 = log_from_c_trace_level(lvl);
log!(target: PAHO_C_LOG_TARGET, lvl, "{}", msg);
}

/// Converts a Paho C trace level into a Rust log level.
pub fn log_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 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::Level) -> ffi::MQTTASYNC_TRACE_LEVELS {
use log::Level::*;
match level {
Error => ffi::MQTTASYNC_TRACE_LEVELS_MQTTASYNC_TRACE_SEVERE,
Warn => ffi::MQTTASYNC_TRACE_LEVELS_MQTTASYNC_TRACE_ERROR,
Info => ffi::MQTTASYNC_TRACE_LEVELS_MQTTASYNC_TRACE_PROTOCOL,
Debug => ffi::MQTTASYNC_TRACE_LEVELS_MQTTASYNC_TRACE_MEDIUM,
Trace => ffi::MQTTASYNC_TRACE_LEVELS_MQTTASYNC_TRACE_MAXIMUM,
}
}

/// Gets the trace level, if any, to set the Paho C library
pub fn c_trace_level() -> Option<ffi::MQTTASYNC_TRACE_LEVELS> {
use log::Level::*;
if log_enabled!(target: PAHO_C_LOG_TARGET, Trace) {
Some(log_into_c_trace_level(Trace))
}
else if log_enabled!(target: PAHO_C_LOG_TARGET, Debug) {
Some(log_into_c_trace_level(Debug))
}
else if log_enabled!(target: PAHO_C_LOG_TARGET, Info) {
Some(log_into_c_trace_level(Info))
}
else if log_enabled!(target: PAHO_C_LOG_TARGET, Warn) {
Some(log_into_c_trace_level(Warn))
}
else if log_enabled!(target: PAHO_C_LOG_TARGET, Error) {
Some(log_into_c_trace_level(Error))
}
else {
None
}
}
54 changes: 54 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,56 @@

//! This is the Eclipse Paho MQTT client library for the Rust language.
//!
//! # Crate Features
//!
//! ### Default
//!
//! * **bundled**
//! Builds the Paho C library for the target and automatically links it.
//!
//! * **ssl**
//! Builds the library with OpenSSL support. This allow secure SSL/TLS
//! connections to a broker along with secure websockets. This requires
//! OpenSSL to be installed for the target or using the `vendored-ssl`
//! feature to build it.
//!
//! ### Non-default
//!
//! * **build_bindgen**
//! Build the bindings to the Paho C library for the target. The library
//! ships with a number of pre-built bindings for common targets. For
//! other targets it might be helpful to build the bindings for the
//! specific target platform, especially if the library segfauls due to
//! an improper API.
//!
//! * **vendored-ssl**
//! Download an build OpenSSL for the target.
//!
//! # Logging
//!
//! The library uses the standard Rust log facility with the target/module
//! "paho_mqtt".
//!
//! In addition, the traces from the underlying Paho C library are captured
//! and redirected to the Rust log facility. Since the C library is a bit
//! cryptic and verbose, the output is controlled separately using a
//! "paho_mqtt_c" target/module. The levels for the C library are
//! approximated to suit the Rust filter level selected for it.
//!
//! The example applications use the simple
//! [environment logger](https://crates.io/crates/env_logger) which can be
//! controlled by the `RUST_LOG` environment variable. To set the logging
//! for the two modules, you can do something like:
//!
//! ```text
//! $ RUST_LOG="pago_mqtt=info,paho_mqtt_c=debug" ./target/debug/examples/async_subscribe
//! Connecting to the MQTT server at 'mqtt://localhost:1883'...
//! [2023-09-11T13:26:18Z DEBUG paho_mqtt::async_client] =========================================================
//! [2023-09-11T13:26:18Z DEBUG paho_mqtt::async_client] Trace Output
//! [2023-09-11T13:26:18Z DEBUG paho_mqtt::async_client] Product name: Eclipse Paho Asynchronous MQTT C Client Library
//! [2023-09-11T13:26:18Z DEBUG paho_mqtt::async_client] Version: 1.3.11
//! ...
//! ```

#![deny(missing_docs)]
#![allow(non_upper_case_globals)]
Expand Down Expand Up @@ -125,6 +175,10 @@ pub mod string_collection;
/// (to pass to the C library).
pub mod name_value;

// C log tracing pass-through
mod c_trace;
use c_trace::{c_trace_level, on_c_trace};

// --------------------------------------------------------------------------

/// Generic type for arbitrary user-supplied data.
Expand Down

0 comments on commit 25f9dcd

Please sign in to comment.