redgold_schema/observability/
errors.rs

1use crate::helpers::easy_json::EasyJson;
2use crate::structs::{ErrorDetails, ErrorInfo, ResponseMetadata};
3use crate::message::Response;
4use crate::{structs, HashClear, RgResult};
5use log::{error, Level};
6use tracing::field::FieldSet;
7use tracing::{event, Event, Metadata};
8
9pub fn convert_log_level(level: String) -> log::Level {
10    match level.to_lowercase().as_str() {
11        "trace" => log::Level::Trace,
12        "debug" => log::Level::Debug,
13        "info" => log::Level::Info,
14        "warn" => log::Level::Warn,
15        "error" => log::Level::Error,
16        _ => log::Level::Error,
17    }
18}
19
20pub fn convert_trace_log_level(level: String) -> tracing::Level {
21    match level.to_lowercase().as_str() {
22        "trace" => tracing::Level::TRACE,
23        "debug" => tracing::Level::DEBUG,
24        "info" => tracing::Level::INFO,
25        "warn" => tracing::Level::WARN,
26        "error" => tracing::Level::ERROR,
27        _ => tracing::Level::ERROR,
28    }
29}
30
31pub trait Loggable<T> {
32    fn log_error(&self) -> RgResult<T>;
33}
34
35impl<T> Loggable<T> for RgResult<T> where T: Clone {
36    // TODO: Better here to do a map_err and then return self to avoid the clone?
37    fn log_error(&self) -> RgResult<T> {
38        self.as_ref()
39            .map_err(|e| {
40                let e2 = e.clone();
41                if !e2.skip_logging {
42                    let ser = e2.json_or();
43                    if let Some(l) = e2.internal_log_level.as_ref(){
44                        let _level = convert_trace_log_level(l.clone());
45                        // TODO: Finish this
46                        // let metadata = Metadata::new("log_error", "?", level, None, None, None, FieldSet::new(&[],), &[], &[]);
47                        // let event = Event::new(&metadata, &ser);
48                        // tracing::dispatcher::get_default(|dispatcher| {
49                        //     dispatcher.event(&event);
50                        // });
51                        // event!(level, "{}", ser);
52                    } else {
53                        error!("{}", ser);
54                    }
55                }
56                e.clone()
57            }).map(|t| t.clone())
58    }
59}
60
61impl ErrorInfo {
62    pub fn error_info<S: Into<String>>(message: S) -> ErrorInfo {
63        crate::error_info(message)
64    }
65    pub fn new(message: impl Into<String>) -> ErrorInfo {
66        crate::error_info(message.into())
67    }
68
69    pub fn response_metadata(self) -> ResponseMetadata {
70        ResponseMetadata {
71            success: false,
72            error_info: Some(self),
73            task_local_details: vec![],
74            request_id: None,
75            trace_id: None,
76        }
77    }
78    pub fn enhance(self, message: impl Into<String>) -> ErrorInfo {
79        let mut e = self;
80        e.message = format!("{} {} ", e.message, message.into());
81        e
82    }
83    pub fn with_detail(&mut self, k: impl Into<String>, v: impl Into<String>) {
84        let mut ed = ErrorDetails::default();
85        ed.detail = v.into();
86        ed.detail_name = k.into();
87        self.details.push(ed);
88    }
89    pub fn with_code(&mut self, v: structs::ErrorCode) {
90        self.code = v as i32;
91    }
92
93}
94
95impl HashClear for ErrorInfo {
96    fn hash_clear(&mut self) {
97
98    }
99}
100
101pub trait EnhanceErrorInfo<T> {
102    fn add(self, message: impl Into<String>) -> RgResult<T>;
103    fn mark_abort(self) -> RgResult<T>;
104    fn bubble_abort(self) -> RgResult<RgResult<T>>;
105    fn with_code(self, v: structs::ErrorCode) -> RgResult<T>;
106    fn with_detail(self, k: impl Into<String>, v: impl Into<String>) -> RgResult<T>;
107    fn with_detail_fn<F>(self, k: impl Into<String>, v: impl Fn() -> F) -> RgResult<T>
108    where F: Into<String> + Sized;
109    fn mark_skip_log(self) -> RgResult<T>;
110    fn level(self, l: Level) -> RgResult<T>;
111}
112
113impl<T> EnhanceErrorInfo<T> for RgResult<T> {
114    fn add(self, message: impl Into<String>) -> RgResult<T> {
115        self.map_err(|e| e.enhance(message))
116    }
117    fn mark_abort(self) -> RgResult<T> {
118        self.map_err(|mut e| {
119            e.abort = true;
120            e
121        })
122    }
123    fn bubble_abort(self) -> RgResult<RgResult<T>> {
124        match self {
125            Ok(r) => {Ok(Ok(r))}
126            Err(e) => {
127                if !e.abort {
128                    Ok(Err(e))
129                } else {
130                    Err(e)
131                }
132            }
133        }
134    }
135    fn with_code(self, v: structs::ErrorCode) -> RgResult<T> {
136        self.map_err(|mut e| {
137            e.with_code(v);
138            e
139        })
140    }
141    fn with_detail(self, k: impl Into<String>, v: impl Into<String>) -> RgResult<T> {
142        self.map_err(|mut e| {
143            e.with_detail(k, v);
144            e
145        })
146    }
147
148
149    fn with_detail_fn<F>(self, k: impl Into<String>, v: impl Fn() -> F) -> RgResult<T>
150    where F: Into<String> + Sized{
151        self.map_err(|mut e| {
152            let v = v().into();
153            e.with_detail(k, v);
154            e
155        })
156    }
157
158    fn mark_skip_log(self) -> RgResult<T> {
159        self.map_err(|mut e| {
160            e.skip_logging = true;
161            e
162        })
163    }
164
165    fn level(self, l: Level) -> RgResult<T> {
166        self.map_err(|mut e| {
167            e.internal_log_level = Some(l.to_string());
168            e
169        })
170    }
171
172}