imsub_log_crate/
lib.rs

1mod message;
2mod rabbitmq;
3mod error;
4
5use std::collections::HashMap;
6
7use tracing::{Subscriber};
8use tracing_subscriber::Layer;
9
10pub use rabbitmq::RabbitMqClient;
11use error::Error;
12
13#[derive(Default, Debug)]
14struct FieldsHandler {
15    telegram_id: Option<String>,
16    target: String,
17    name: String,
18    method_name: Option<String>,
19    message: Option<String>,
20    details: HashMap<String, String>,
21}
22
23impl tracing::field::Visit for FieldsHandler {
24    fn record_f64(&mut self, field: &tracing::field::Field, value: f64) {
25        self.dispatch_field_value(field.name(), value.to_string())
26    }
27
28    fn record_i64(&mut self, field: &tracing::field::Field, value: i64) {
29        self.dispatch_field_value(field.name(), value.to_string())
30    }
31
32    fn record_u64(&mut self, field: &tracing::field::Field, value: u64) {
33        self.dispatch_field_value(field.name(), value.to_string())
34    }
35
36    fn record_bool(&mut self, field: &tracing::field::Field, value: bool) {
37        self.dispatch_field_value(field.name(), value.to_string())
38    }
39
40    fn record_str(&mut self, field: &tracing::field::Field, value: &str) {
41        self.dispatch_field_value(field.name(), value.to_string())
42    }
43
44    fn record_error(
45        &mut self,
46        field: &tracing::field::Field,
47        value: &(dyn std::error::Error + 'static),
48    ) {
49        self.dispatch_field_value(field.name(), value.to_string());
50    }
51
52    fn record_debug(&mut self, field: &tracing::field::Field, value: &dyn std::fmt::Debug) {
53        self.dispatch_field_value(field.name(), format!("{:#?}", value));
54    }
55}
56
57impl FieldsHandler {
58    pub fn new(target: &str, name: &str) -> Self {
59        Self {
60            target: target.to_string(),
61            name: name.to_string(),
62            ..Default::default()
63        }
64    }
65
66    fn dispatch_field_value(&mut self, field_name: &str, field_value: String) {
67        match field_name {
68            "telegram_id" => self.telegram_id = Some(field_value),
69            "message" => self.message = Some(field_value),
70            "fn_path" => self.set_fn_path(field_value),
71            field_name => {
72                self.details.insert(field_name.to_string(), field_value);
73            }
74        };
75    }
76
77    pub fn get_details_to_string(&self) -> String {
78        self.details.iter().fold("".to_string(), |acc, (k, v)| {
79            format!("{}{} = {}\n", acc, k, v)
80        })
81    }
82
83    pub fn set_fn_path(&mut self, fn_path: String) {
84        let fn_path = format!("{}::{}", self.target, fn_path);
85        self.method_name = Some(fn_path);
86    }
87
88    pub fn get_method_name(&self) -> String {
89        match &self.method_name {
90            None => self.name.clone(),
91            Some(value) => value.to_string(),
92        }
93    }
94}
95
96pub struct RabbitLayer {
97    rabbit_client: RabbitMqClient,
98}
99
100impl RabbitLayer {
101    pub async fn new(rabbit_url: String, service_name: String) -> Result<Self, Error> {
102        let rabbit_client = RabbitMqClient::new(rabbit_url, service_name).await?;
103        Ok(Self { rabbit_client })
104    }
105}
106
107impl<S: Subscriber> Layer<S> for RabbitLayer {
108    fn on_event(
109        &self,
110        event: &tracing::Event<'_>,
111        _ctx: tracing_subscriber::layer::Context<'_, S>,
112    ) {
113        let mut visitor = FieldsHandler::new(event.metadata().target(), event.metadata().name());
114        event.record(&mut visitor);
115
116        self.rabbit_client.send_log(
117            event.metadata().level(),
118            visitor.telegram_id.clone(),
119            Some(visitor.get_method_name()),
120            visitor.message.clone(),
121            Some(visitor.get_details_to_string()),
122        );
123    }
124}