Skip to content

Commit 38f9458

Browse files
committed
added logging
1 parent c7f5d14 commit 38f9458

File tree

7 files changed

+232
-15
lines changed

7 files changed

+232
-15
lines changed

rustecal-core/src/core.rs

Lines changed: 69 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,29 @@
11
//! Core lifecycle control for the eCAL runtime.
22
//!
33
//! This module provides safe Rust wrappers around initializing and finalizing
4-
//! the eCAL communication system, as well as querying its state.
4+
//! the eCAL communication system, as well as querying its state and version.
55
//!
66
//! The main entry point is the [`Ecal`] struct which provides:
77
//! - [`Ecal::initialize`] to start the middleware
88
//! - [`Ecal::finalize`] to shut it down
99
//! - [`Ecal::ok`] to query if eCAL is currently running
10+
//! - [`Ecal::is_initialized`] and [`Ecal::is_component_initialized`] for introspection
11+
//! - [`Ecal::version_string`], [`Ecal::version_date_string`] and [`Ecal::version_struct`] for version info
1012
//!
1113
//! Typically, you will call [`Ecal::initialize`] once at the beginning of your
1214
//! application and [`Ecal::finalize`] at shutdown.
1315
14-
use std::ffi::CString;
16+
use std::ffi::{CStr, CString};
1517
use crate::components::EcalComponents;
16-
use rustecal_sys;
18+
use crate::types::Version;
1719

18-
/// Provides access to the core initialization and finalization functions of eCAL.
20+
/// Provides access to the core initialization, shutdown, and state-checking functions of eCAL.
1921
pub struct Ecal;
2022

2123
impl Ecal {
2224
/// Initializes the eCAL runtime system.
2325
///
24-
/// This function must be called before using any publisher or subscriber functionality.
26+
/// This function must be called before using any publisher, subscriber, or service functionality.
2527
///
2628
/// # Arguments
2729
///
@@ -48,7 +50,7 @@ impl Ecal {
4850

4951
/// Finalizes and shuts down the eCAL runtime system.
5052
///
51-
/// After calling this function, all publishers and subscribers are invalidated.
53+
/// After calling this function, all publishers, subscribers, and services are invalidated.
5254
pub fn finalize() {
5355
unsafe {
5456
rustecal_sys::eCAL_Finalize();
@@ -65,4 +67,65 @@ impl Ecal {
6567
pub fn ok() -> bool {
6668
unsafe { rustecal_sys::eCAL_Ok() != 0 }
6769
}
70+
71+
/// Checks if the eCAL system has been initialized.
72+
///
73+
/// This function checks whether any components of the middleware have been initialized.
74+
///
75+
/// # Returns
76+
///
77+
/// `true` if initialization has occurred, `false` otherwise.
78+
pub fn is_initialized() -> bool {
79+
unsafe { rustecal_sys::eCAL_IsInitialized() != 0 }
80+
}
81+
82+
/// Checks if specific components of eCAL are initialized.
83+
///
84+
/// This allows querying the status of individual middleware components like pub/sub, monitoring, etc.
85+
///
86+
/// # Arguments
87+
///
88+
/// * `components` - Bitmask of components to check.
89+
///
90+
/// # Returns
91+
///
92+
/// `true` if the given components are initialized, `false` otherwise.
93+
pub fn is_component_initialized(components: EcalComponents) -> bool {
94+
unsafe { rustecal_sys::eCAL_IsComponentInitialized(components.bits()) != 0 }
95+
}
96+
97+
/// Returns the version string of the eCAL runtime.
98+
///
99+
/// # Returns
100+
///
101+
/// A static string slice with the full version string, e.g. `"5.11.0"`.
102+
pub fn version_string() -> &'static str {
103+
unsafe {
104+
CStr::from_ptr(rustecal_sys::eCAL_GetVersionString())
105+
.to_str()
106+
.unwrap_or("unknown")
107+
}
108+
}
109+
110+
/// Returns the build date string of the eCAL runtime.
111+
///
112+
/// # Returns
113+
///
114+
/// A static string slice with the build date string, e.g. `"Apr 2025"`.
115+
pub fn version_date_string() -> &'static str {
116+
unsafe {
117+
CStr::from_ptr(rustecal_sys::eCAL_GetVersionDateString())
118+
.to_str()
119+
.unwrap_or("unknown")
120+
}
121+
}
122+
123+
/// Returns the version of the eCAL runtime as structured integers.
124+
///
125+
/// # Returns
126+
///
127+
/// A [`Version`] struct with fields `major`, `minor`, and `patch`.
128+
pub fn version_struct() -> Version {
129+
unsafe { rustecal_sys::eCAL_GetVersion().into() }
130+
}
68131
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//! Rust-safe wrapper for `eCAL_Logging_SLogMessage`.
2+
//!
3+
//! This type represents individual log entries emitted by eCAL.
4+
5+
use crate::log_level::LogLevel;
6+
use std::ffi::CStr;
7+
use std::os::raw::c_char;
8+
9+
/// Represents a single log message emitted by eCAL.
10+
#[derive(Debug, Clone)]
11+
pub struct LogMessage {
12+
pub level: LogLevel,
13+
pub timestamp: i64,
14+
pub host_name: String,
15+
pub process_name: String,
16+
pub process_id: i32,
17+
pub thread_name: String,
18+
pub content: String,
19+
}
20+
21+
impl From<rustecal_sys::eCAL_Logging_SLogMessage> for LogMessage {
22+
fn from(raw: rustecal_sys::eCAL_Logging_SLogMessage) -> Self {
23+
Self {
24+
level: LogLevel::from(raw.level),
25+
timestamp: raw.time,
26+
host_name: cstr_to_string(raw.host_name),
27+
process_name: cstr_to_string(raw.process_name),
28+
process_id: raw.process_id,
29+
thread_name: cstr_to_string(raw.unit_name), // or rename field to unit_name
30+
content: cstr_to_string(raw.content),
31+
}
32+
}
33+
}
34+
35+
/// Converts a C string pointer to a Rust `String`.
36+
fn cstr_to_string(ptr: *const c_char) -> String {
37+
if ptr.is_null() {
38+
String::new()
39+
} else {
40+
unsafe { CStr::from_ptr(ptr).to_string_lossy().into_owned() }
41+
}
42+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
//! Common eCAL types shared across pubsub and service layers.
2+
3+
pub mod logging;

rustecal-core/src/lib.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,18 @@
1-
//! rustecal-core: eCAL initialization & shared types
1+
//! rustecal-core: eCAL initialization, shared components, logging, and core types.
2+
//!
3+
//! This crate provides safe Rust wrappers for the core system of eCAL,
4+
//! including runtime lifecycle management, logging, and reusable data structures.
25
36
pub mod core;
47
pub mod components;
58
pub mod types;
9+
pub mod log;
10+
pub mod log_level;
11+
pub mod core_types;
612

713
// Re‑exports for ergonomic access:
814
pub use core::Ecal;
915
pub use components::EcalComponents;
16+
pub use log::Log;
17+
pub use log_level::LogLevel;
18+
pub use core_types::logging::LogMessage;

rustecal-core/src/log.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
//! Core logging functions for emitting messages through eCAL.
2+
//!
3+
//! This module wraps the C API from `ecal_c/log.h` and provides access to
4+
//! logging at various severity levels, as well as retrieval of current log entries.
5+
6+
use crate::core_types::logging::LogMessage;
7+
use crate::log_level::LogLevel;
8+
9+
use std::ffi::CString;
10+
use std::ptr;
11+
use std::slice;
12+
13+
/// Provides logging functions to emit and retrieve messages via the eCAL runtime.
14+
pub struct Log;
15+
16+
impl Log {
17+
/// Emits a message to the eCAL logging system with a specified severity.
18+
///
19+
/// # Arguments
20+
///
21+
/// * `level` - Log severity (e.g., [`LogLevel::Info`], [`LogLevel::Error`])
22+
/// * `message` - The log content to emit
23+
pub fn log(level: LogLevel, message: &str) {
24+
let cstr = CString::new(message)
25+
.unwrap_or_else(|_| CString::new("<invalid UTF-8>").unwrap());
26+
27+
unsafe {
28+
rustecal_sys::eCAL_Logging_Log(level.into(), cstr.as_ptr());
29+
}
30+
}
31+
32+
/// Fetches all current log messages stored in the eCAL runtime.
33+
///
34+
/// This function uses the C API `eCAL_Logging_GetLogging` to retrieve
35+
/// structured log messages and ensures the memory is released with `eCAL_Free`.
36+
///
37+
/// # Returns
38+
///
39+
/// A vector of [`LogMessage`] entries, or an empty vector if retrieval failed.
40+
pub fn get_logging() -> Vec<LogMessage> {
41+
let mut raw_ptr: *mut rustecal_sys::eCAL_Logging_SLogging = ptr::null_mut();
42+
43+
let success = unsafe { rustecal_sys::eCAL_Logging_GetLogging(&mut raw_ptr) };
44+
45+
if success != 0 || raw_ptr.is_null() {
46+
return vec![];
47+
}
48+
49+
let logging = unsafe { &*raw_ptr };
50+
let raw_messages = logging.log_messages;
51+
let len = logging.log_messages_length;
52+
53+
let logs = unsafe {
54+
slice::from_raw_parts(raw_messages, len)
55+
.iter()
56+
.map(|msg| LogMessage::from(*msg))
57+
.collect()
58+
};
59+
60+
unsafe {
61+
rustecal_sys::eCAL_Free(raw_ptr as *mut _);
62+
}
63+
64+
logs
65+
}
66+
}

rustecal-core/src/log_level.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//! eCAL logging severity levels.
2+
//!
3+
//! This mirrors the C enum `eCAL_Logging_eLogLevel` and is used in logging APIs.
4+
5+
#[repr(i32)]
6+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7+
pub enum LogLevel {
8+
None = 0,
9+
Fatal = 1,
10+
Error = 2,
11+
Warning = 3,
12+
Info = 4,
13+
Debug = 5,
14+
Verbose = 6,
15+
}
16+
17+
impl From<i32> for LogLevel {
18+
fn from(value: i32) -> Self {
19+
match value {
20+
1 => LogLevel::Fatal,
21+
2 => LogLevel::Error,
22+
3 => LogLevel::Warning,
23+
4 => LogLevel::Info,
24+
5 => LogLevel::Debug,
25+
6 => LogLevel::Verbose,
26+
_ => LogLevel::None,
27+
}
28+
}
29+
}
30+
31+
impl From<LogLevel> for i32 {
32+
fn from(level: LogLevel) -> Self {
33+
level as i32
34+
}
35+
}

rustecal-core/src/types.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
//! Common eCAL types shared across pubsub and service layers.
22
3-
use rustecal_sys::*;
4-
use std::ffi::{CStr};
3+
use std::ffi::CStr;
54
use std::os::raw::c_char;
65

76
/// Represents a globally unique entity in eCAL.
@@ -12,8 +11,8 @@ pub struct EntityId {
1211
pub host_name: String,
1312
}
1413

15-
impl From<eCAL_SEntityId> for EntityId {
16-
fn from(raw: eCAL_SEntityId) -> Self {
14+
impl From<rustecal_sys::eCAL_SEntityId> for EntityId {
15+
fn from(raw: rustecal_sys::eCAL_SEntityId) -> Self {
1716
Self {
1817
entity_id: raw.entity_id,
1918
process_id: raw.process_id,
@@ -30,8 +29,8 @@ pub struct DataTypeInfo {
3029
pub descriptor: Vec<u8>,
3130
}
3231

33-
impl From<eCAL_SDataTypeInformation> for DataTypeInfo {
34-
fn from(info: eCAL_SDataTypeInformation) -> Self {
32+
impl From<rustecal_sys::eCAL_SDataTypeInformation> for DataTypeInfo {
33+
fn from(info: rustecal_sys::eCAL_SDataTypeInformation) -> Self {
3534
let type_name = cstr_to_string(info.name);
3635
let encoding = cstr_to_string(info.encoding);
3736
let descriptor = if info.descriptor.is_null() || info.descriptor_length == 0 {
@@ -59,8 +58,8 @@ pub struct Version {
5958
pub patch: i32,
6059
}
6160

62-
impl From<eCAL_SVersion> for Version {
63-
fn from(raw: eCAL_SVersion) -> Self {
61+
impl From<rustecal_sys::eCAL_SVersion> for Version {
62+
fn from(raw: rustecal_sys::eCAL_SVersion) -> Self {
6463
Self {
6564
major: raw.major,
6665
minor: raw.minor,

0 commit comments

Comments
 (0)