rsiot/components/cmp_logger/
mod.rs

1//! Компонент для логгирования сообщений
2
3use async_trait::async_trait;
4pub use tracing::Level;
5use tracing::{debug, error, info, trace, warn};
6
7use crate::{
8    executor::{CmpInOut, Component, ComponentError, IComponentProcess},
9    message::{AuthPermissions, Message, MsgDataBound},
10};
11
12/// Настройки компонента логгирования
13#[derive(Clone, Debug)]
14pub struct Config<TMsg> {
15    /// Уровень логгирования
16    pub level: Level,
17
18    /// Функция преобразования входящих сообщений в записи.
19    ///
20    /// Можно реализовать фильтрацию сообщений.
21    ///
22    /// **Примеры**
23    ///
24    /// - Логгирование всех сообщений
25    ///
26    /// ```rust
27    /// fn_input: |msg| Ok(Some(msg.serialize()?)),
28    /// ```
29    ///
30    /// - Логгирование всех сообщений с заголовком
31    ///
32    /// ```rust
33    /// fn_input: |msg| {
34    ///     let text = msg.serialize()?;
35    ///     let text = format!("Header: {text}");
36    ///     Ok(Some(text))
37    /// },
38    /// ```
39    pub fn_input: fn(Message<TMsg>) -> anyhow::Result<Option<String>>,
40}
41
42#[cfg_attr(not(feature = "single-thread"), async_trait)]
43#[cfg_attr(feature = "single-thread", async_trait(?Send))]
44impl<TMsg> IComponentProcess<Config<TMsg>, TMsg> for Component<Config<TMsg>, TMsg>
45where
46    TMsg: MsgDataBound,
47{
48    async fn process(
49        &self,
50        config: Config<TMsg>,
51        in_out: CmpInOut<TMsg>,
52    ) -> Result<(), ComponentError> {
53        process(
54            config,
55            in_out.clone_with_new_id("cmp_logger", AuthPermissions::FullAccess),
56        )
57        .await
58    }
59}
60
61async fn process<TMsg>(
62    config: Config<TMsg>,
63    mut in_out: CmpInOut<TMsg>,
64) -> Result<(), ComponentError>
65where
66    TMsg: MsgDataBound,
67{
68    while let Ok(msg) = in_out.recv_input().await {
69        let text = (config.fn_input)(msg);
70        // ошибка сериализации
71        let Ok(text) = text else {
72            warn!("Logger Error: {:?}", text);
73            continue;
74        };
75        // фильтрация
76        let Some(text) = text else { continue };
77        match config.level {
78            Level::TRACE => trace!("{text}"),
79            Level::DEBUG => debug!("{text}"),
80            Level::INFO => info!("{text}"),
81            Level::WARN => warn!("{text}"),
82            Level::ERROR => error!("{text}"),
83        }
84    }
85    Ok(())
86}
87
88/// Компонент cmp_logger
89pub type Cmp<TMsg> = Component<Config<TMsg>, TMsg>;