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}