Skip to content

Commit 41e564e

Browse files
authored
Skip unnecessary log formatting, include log category (#261)
This adds the log category to log messages and skips log formatting altogether when the target log level is not activated.
1 parent 29da728 commit 41e564e

2 files changed

Lines changed: 63 additions & 24 deletions

File tree

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

88
## [Unreleased]
99

10+
### Changed
11+
12+
- Include category ("network", "channel", ..., "discovery") in log messages.
13+
- Skip overhead of formatting log message when corresponding log level has been disabled.
14+
1015
## [0.9.3] - 2025-08-27
1116

1217
### Added

src/ua/logger/rust_log.rs

Lines changed: 58 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,57 @@
11
use std::{
2+
borrow::Cow,
23
ffi::{c_char, c_void, CStr},
34
ptr,
45
};
56

7+
use log::Level;
68
use open62541_sys::{vsnprintf_va_copy, vsnprintf_va_end, UA_LogCategory, UA_LogLevel, UA_Logger};
79

810
use crate::ua;
911

12+
// This matches the crate name.
1013
const LOG_TARGET: &str = "open62541_sys";
1114

1215
/// Creates logger that forwards to the `log` crate.
1316
///
14-
/// We can use this to prevent `open62541` from installing its own default logger (which outputs any
17+
/// We can use this to prevent `open62541` from installing its own default logger (which outputs all
1518
/// logs to stdout/stderr directly).
1619
pub(crate) fn logger() -> ua::Logger {
1720
unsafe extern "C" fn log_c(
1821
_log_context: *mut c_void,
1922
level: UA_LogLevel,
20-
_category: UA_LogCategory,
23+
category: UA_LogCategory,
2124
msg: *const c_char,
2225
args: open62541_sys::va_list_,
2326
) {
24-
let Some(msg) = format_message(msg, args) else {
25-
log::error!(target: LOG_TARGET, "Unknown log message");
27+
let level = match level {
28+
// Without fatal level in `log`, fall back to error.
29+
UA_LogLevel::UA_LOGLEVEL_FATAL | UA_LogLevel::UA_LOGLEVEL_ERROR => Level::Error,
30+
UA_LogLevel::UA_LOGLEVEL_WARNING => Level::Warn,
31+
UA_LogLevel::UA_LOGLEVEL_INFO => Level::Info,
32+
UA_LogLevel::UA_LOGLEVEL_DEBUG => Level::Debug,
33+
UA_LogLevel::UA_LOGLEVEL_TRACE => Level::Trace,
34+
// Handle unexpected level by escalating to error.
35+
#[expect(clippy::match_same_arms, reason = "distinction of cases")]
36+
_ => Level::Error,
37+
};
38+
39+
if !log::log_enabled!(target: LOG_TARGET, level) {
40+
// Bail out early to skip formatting message.
2641
return;
42+
}
43+
44+
let msg = format_message(msg, args);
45+
let msg = match msg {
46+
Some(ref msg) => CStr::from_bytes_with_nul(msg)
47+
.unwrap_or(c"Invalid log message")
48+
.to_string_lossy(),
49+
None => Cow::Borrowed("Unknown log message"),
2750
};
2851

29-
let msg = CStr::from_bytes_with_nul(&msg)
30-
.unwrap_or(c"Invalid log message")
31-
.to_string_lossy();
52+
let category = log_category(&category);
3253

33-
if level == UA_LogLevel::UA_LOGLEVEL_FATAL {
34-
// Without fatal level in `log`, fall back to error.
35-
log::error!(target: LOG_TARGET, "{msg}");
36-
} else if level == UA_LogLevel::UA_LOGLEVEL_ERROR {
37-
log::error!(target: LOG_TARGET, "{msg}");
38-
} else if level == UA_LogLevel::UA_LOGLEVEL_WARNING {
39-
log::warn!(target: LOG_TARGET, "{msg}");
40-
} else if level == UA_LogLevel::UA_LOGLEVEL_INFO {
41-
log::info!(target: LOG_TARGET, "{msg}");
42-
} else if level == UA_LogLevel::UA_LOGLEVEL_DEBUG {
43-
log::debug!(target: LOG_TARGET, "{msg}");
44-
} else if level == UA_LogLevel::UA_LOGLEVEL_TRACE {
45-
log::trace!(target: LOG_TARGET, "{msg}");
46-
} else {
47-
// Handle unexpected level by escalating to error.
48-
log::error!(target: LOG_TARGET, "{msg}");
49-
}
54+
log::log!(target: LOG_TARGET, level, "({category}) {msg}");
5055
}
5156

5257
unsafe extern "C" fn clear_c(logger: *mut UA_Logger) {
@@ -156,3 +161,32 @@ fn format_message(msg: *const c_char, args: open62541_sys::va_list_) -> Option<V
156161

157162
Some(msg_buffer)
158163
}
164+
165+
// These match the category names from `ua_log_stdout.c` and `ua_log_syslog.c`.
166+
const LOG_CATEGORY_NETWORK: &str = "network";
167+
const LOG_CATEGORY_SECURECHANNEL: &str = "channel";
168+
const LOG_CATEGORY_SESSION: &str = "session";
169+
const LOG_CATEGORY_SERVER: &str = "server";
170+
const LOG_CATEGORY_CLIENT: &str = "client";
171+
const LOG_CATEGORY_USERLAND: &str = "userland";
172+
const LOG_CATEGORY_SECURITYPOLICY: &str = "security";
173+
const LOG_CATEGORY_EVENTLOOP: &str = "eventloop";
174+
const LOG_CATEGORY_PUBSUB: &str = "pubsub";
175+
const LOG_CATEGORY_DISCOVERY: &str = "discovery";
176+
const LOG_CATEGORY_UNKNOWN: &str = "unknown";
177+
178+
const fn log_category(category: &UA_LogCategory) -> &'static str {
179+
match *category {
180+
UA_LogCategory::UA_LOGCATEGORY_NETWORK => LOG_CATEGORY_NETWORK,
181+
UA_LogCategory::UA_LOGCATEGORY_SECURECHANNEL => LOG_CATEGORY_SECURECHANNEL,
182+
UA_LogCategory::UA_LOGCATEGORY_SESSION => LOG_CATEGORY_SESSION,
183+
UA_LogCategory::UA_LOGCATEGORY_SERVER => LOG_CATEGORY_SERVER,
184+
UA_LogCategory::UA_LOGCATEGORY_CLIENT => LOG_CATEGORY_CLIENT,
185+
UA_LogCategory::UA_LOGCATEGORY_USERLAND => LOG_CATEGORY_USERLAND,
186+
UA_LogCategory::UA_LOGCATEGORY_SECURITYPOLICY => LOG_CATEGORY_SECURITYPOLICY,
187+
UA_LogCategory::UA_LOGCATEGORY_EVENTLOOP => LOG_CATEGORY_EVENTLOOP,
188+
UA_LogCategory::UA_LOGCATEGORY_PUBSUB => LOG_CATEGORY_PUBSUB,
189+
UA_LogCategory::UA_LOGCATEGORY_DISCOVERY => LOG_CATEGORY_DISCOVERY,
190+
_ => LOG_CATEGORY_UNKNOWN,
191+
}
192+
}

0 commit comments

Comments
 (0)