cosmic_space/
log.rs

1use core::str::FromStr;
2use std::collections::HashMap;
3use std::ops::Deref;
4use std::process::Output;
5use std::sync::Arc;
6
7use crate::{Agent, ANONYMOUS, ToSubstance};
8use regex::Regex;
9use serde;
10use serde::{Deserialize, Serialize};
11use serde_json::Value;
12
13use crate::command::common::StateSrc::Substance;
14use crate::err::SpaceErr;
15use crate::loc::{Layer, ToPoint, ToSurface, Uuid};
16use crate::parse::{CamelCase, to_string};
17use crate::point::Point;
18use crate::selector::Selector;
19use crate::substance::LogSubstance;
20use crate::util::{timestamp, uuid};
21use crate::wasm::Timestamp;
22use crate::wave::core::cmd::CmdMethod;
23use crate::wave::exchange::synch::{ProtoTransmitter, ProtoTransmitterBuilder};
24use crate::wave::exchange::SetStrategy;
25use crate::wave::{
26    DirectedProto, Handling, HandlingKind, Priority, Retries, ToRecipients, WaitTime,
27};
28
29#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, strum_macros::Display)]
30pub enum Level {
31    Trace,
32    Debug,
33    Info,
34    Warn,
35    Error,
36}
37
38impl Default for Level {
39    fn default() -> Self {
40        Level::Info
41    }
42}
43
44#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
45pub struct Log {
46    pub point: Point,
47    pub mark: Point,
48    pub action: Option<CamelCase>,
49    pub source: LogSource,
50    pub span: Option<Uuid>,
51    pub timestamp: i64,
52    pub payload: LogPayload,
53    pub level: Level,
54}
55
56impl ToString for Log {
57    fn to_string(&self) -> String {
58        format!(
59            "{} {} {}",
60            self.point.to_string(),
61            self.level.to_string(),
62            self.payload.to_string()
63        )
64    }
65}
66
67#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, strum_macros::Display)]
68pub enum LogSource {
69    Shell,
70    Core,
71}
72#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
73pub enum LogSpanEventKind {
74    Entry,
75    Exit,
76}
77
78#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
79pub struct LogSpanEvent {
80    pub point: Point,
81    pub span: Uuid,
82    pub kind: LogSpanEventKind,
83    pub attributes: HashMap<String, String>,
84    pub timestamp: Timestamp,
85}
86
87impl LogSpanEvent {
88    pub fn new(
89        span: &LogSpan,
90        point: &Point,
91        kind: LogSpanEventKind,
92        attributes: HashMap<String, String>,
93    ) -> LogSpanEvent {
94        LogSpanEvent {
95            span: span.id.clone(),
96            point: point.clone(),
97            kind,
98            attributes,
99            timestamp: timestamp(),
100        }
101    }
102}
103
104pub type TrailSpanId = Uuid;
105
106#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
107pub struct LogSpan {
108    pub id: TrailSpanId,
109    pub point: Point,
110    pub mark: Point,
111    pub action: Option<CamelCase>,
112    pub parent: Option<Uuid>,
113    pub attributes: HashMap<String, String>,
114    pub entry_timestamp: Timestamp,
115}
116
117impl LogSpan {
118    pub fn new(point: Point) -> Self {
119        Self {
120            id: uuid(),
121            point,
122            mark: Point::root(),
123            action: None,
124            parent: None,
125            attributes: Default::default(),
126            entry_timestamp: timestamp(),
127        }
128    }
129
130    pub fn parent(point: Point, parent: Uuid) -> Self {
131        Self {
132            id: uuid(),
133            point,
134            mark: Point::root(),
135            action: None,
136            parent: Some(parent),
137            attributes: Default::default(),
138            entry_timestamp: timestamp(),
139        }
140    }
141
142    pub fn opt(point: Point, span: Option<Self>) -> Self {
143        let mut span = span.unwrap_or(Self {
144            id: uuid(),
145            point: point.clone(),
146            mark: Point::root(),
147            action: None,
148            parent: None,
149            attributes: Default::default(),
150            entry_timestamp: timestamp(),
151        });
152        span.point = point;
153        span
154    }
155}
156
157#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
158pub struct PointlessLog {
159    timestamp: Timestamp,
160    message: String,
161    level: Level,
162}
163
164#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
165pub enum LogPayload {
166    Message(String),
167    Json(Value),
168    Both { message: String, json: Value },
169}
170
171impl ToString for LogPayload {
172    fn to_string(&self) -> String {
173        match self {
174            LogPayload::Message(message) => message.clone(),
175            LogPayload::Json(json) => json.to_string(),
176            LogPayload::Both { json, message } => {
177                format!("{} {}", json.to_string(), message.clone())
178            }
179        }
180    }
181}
182
183pub struct RootLogBuilder {
184    pub point: Option<Point>,
185    pub span: Option<Uuid>,
186    pub logger: RootLogger,
187    pub level: Level,
188    pub message: Option<String>,
189    pub json: Option<Value>,
190    msg_overrides: Vec<String>,
191}
192
193impl RootLogBuilder {
194    pub fn new(logger: RootLogger, span: Option<Uuid>) -> Self {
195        RootLogBuilder {
196            logger,
197            span,
198            point: None,
199            level: Level::default(),
200            message: None,
201            json: None,
202            msg_overrides: vec![],
203        }
204    }
205
206    pub fn level(mut self, level: Level) -> Self {
207        self.level = level;
208        self
209    }
210
211    pub fn trace(mut self) -> Self {
212        self.level = Level::Trace;
213        self
214    }
215    pub fn debug(mut self) -> Self {
216        self.level = Level::Debug;
217        self
218    }
219    pub fn info(mut self) -> Self {
220        self.level = Level::Info;
221        self
222    }
223    pub fn warn(mut self) -> Self {
224        self.level = Level::Warn;
225        self
226    }
227    pub fn error(mut self) -> Self {
228        self.level = Level::Error;
229        self
230    }
231
232    pub fn point(mut self, p: Point) -> Self {
233        self.point = Some(p);
234        self
235    }
236
237    pub fn msg<M>(mut self, m: M) -> Self
238    where
239        M: ToString,
240    {
241        self.message = Some(m.to_string());
242        self
243    }
244
245    pub fn json<'a, J>(mut self, json: J) -> Self
246    where
247        J: Into<&'a str>,
248    {
249        match serde_json::from_str(json.into()) {
250            Ok(json) => {
251                self.json = Some(json);
252            }
253            Err(err) => {
254                self.msg_overrides
255                    .push(format!("error parsing log json: {}", err.to_string()));
256            }
257        }
258        self
259    }
260
261    pub fn json_value(mut self, json: Value) -> Self {
262        self.json = Some(json);
263        self
264    }
265
266    pub fn commit(mut self) {
267        if self.message.is_none() && self.json.is_none() {
268            self.msg_overrides
269                .push("Log must have either a message or json or both".to_string())
270        }
271
272        if self.point.is_none() {
273            self.msg_overrides
274                .push("Particle Point must be set for a Log".to_string())
275        }
276
277        let message = if self.msg_overrides.is_empty() {
278            self.message
279        } else {
280            let mut rtn = String::new();
281            rtn.push_str("LOG ERROR OVERRIDES: this means there was an error int he logging process itself.\n");
282            for over in self.msg_overrides {
283                rtn.push_str(over.as_str());
284            }
285            match self.message {
286                None => {}
287                Some(message) => {
288                    rtn.push_str(format!("original message: {}", message).as_str());
289                }
290            }
291            Some(rtn)
292        };
293
294        if self.point.is_none() {
295            let log = PointlessLog {
296                timestamp: timestamp(),
297                message: message.expect("message"),
298                level: Level::Error,
299            };
300            self.logger.pointless(log);
301            return;
302        }
303
304        let content = if message.is_some() && self.json.is_none() {
305            LogPayload::Message(message.expect("message"))
306        } else if message.is_none() && self.json.is_some() {
307            LogPayload::Json(self.json.expect("message"))
308        } else if message.is_some() && self.json.is_some() {
309            LogPayload::Both {
310                message: message.expect("message"),
311                json: self.json.expect("json"),
312            }
313        } else {
314            panic!("LogBuilder: must set Logger before LogBuilder.send() can be called")
315        };
316
317        let point = self.point.expect("point");
318        let log = Log {
319            point,
320            mark: Point::root(),
321            action: None,
322            level: self.level,
323            timestamp: timestamp().timestamp_millis(),
324            payload: content,
325            source: self.logger.source(),
326            span: self.span,
327        };
328        self.logger.log(log);
329    }
330}
331
332pub trait LogAppender: Send + Sync {
333    fn log(&self, log: Log);
334
335    fn audit(&self, log: AuditLog);
336
337    fn span_event(&self, log: LogSpanEvent);
338
339    /// PointlessLog is used for error diagnosis of the logging system itself, particularly
340    /// where there is parsing error due to a bad point
341    fn pointless(&self, log: PointlessLog);
342}
343
344#[derive(Clone)]
345pub struct RootLogger {
346    source: LogSource,
347    appender: Arc<dyn LogAppender>,
348}
349
350impl Default for RootLogger {
351    fn default() -> Self {
352        RootLogger::new(LogSource::Core, Arc::new(StdOutAppender::new()))
353    }
354}
355
356impl RootLogger {
357    pub fn new(source: LogSource, appender: Arc<dyn LogAppender>) -> Self {
358        Self { source, appender }
359    }
360
361    pub fn stdout(source: LogSource) -> Self {
362        Self {
363            source,
364            ..RootLogger::default()
365        }
366    }
367
368    fn source(&self) -> LogSource {
369        self.source.clone()
370    }
371
372    fn log(&self, log: Log) {
373        self.appender.log(log);
374    }
375
376    fn audit(&self, log: AuditLog) {
377        self.appender.audit(log);
378    }
379
380    fn span_event(&self, log: LogSpanEvent) {
381        self.appender.span_event(log);
382    }
383
384    /// PointlessLog is used for error diagnosis of the logging system itself, particularly
385    /// where there is parsing error due to a bad point
386    fn pointless(&self, log: PointlessLog) {
387        self.appender.pointless(log);
388    }
389
390    pub fn point<P: ToPoint>(&self, point: P) -> PointLogger {
391        PointLogger {
392            logger: self.clone(),
393            point: point.to_point(),
394            mark: Point::root(),
395            action: None,
396        }
397    }
398}
399pub struct NoAppender {}
400
401impl NoAppender {
402    pub fn new() -> Self {
403        NoAppender {}
404    }
405}
406
407impl LogAppender for NoAppender {
408    fn log(&self, log: Log) {}
409
410    fn audit(&self, log: AuditLog) {}
411
412    fn span_event(&self, log: LogSpanEvent) {}
413
414    fn pointless(&self, log: PointlessLog) {}
415}
416
417pub struct StdOutAppender();
418
419impl StdOutAppender {
420    pub fn new() -> Self {
421        StdOutAppender()
422    }
423}
424
425impl LogAppender for StdOutAppender {
426    fn log(&self, log: Log) {
427        let action = match log.action {
428            None => "None".to_string(),
429            Some(action) => action.to_string(),
430        };
431        println!("{} | {}", log.point.to_string(), log.payload.to_string())
432    }
433
434    fn audit(&self, log: AuditLog) {
435        println!("audit log...")
436    }
437
438    fn span_event(&self, log: LogSpanEvent) {
439        /*         println!(
440                   "{} | Span({})",
441                   log.point.to_string(),
442                   log.span.to_string(),
443               )
444
445        */
446    }
447
448    fn pointless(&self, log: PointlessLog) {
449        println!("{}", log.message);
450    }
451}
452
453pub struct SynchTransmittingLogAppender {
454    transmitter: ProtoTransmitter,
455}
456
457impl SynchTransmittingLogAppender {
458    pub fn new(mut transmitter: ProtoTransmitterBuilder) -> Self {
459        transmitter.method = SetStrategy::Override(CmdMethod::Log.into());
460        transmitter.to = SetStrategy::Override(
461            Point::global_logger()
462                .to_surface()
463                .with_layer(Layer::Core)
464                .to_recipients(),
465        );
466        transmitter.handling = SetStrategy::Fill(Handling {
467            kind: HandlingKind::Durable,
468            priority: Priority::Low,
469            retries: Retries::Medium,
470            wait: WaitTime::High,
471        });
472        let transmitter = transmitter.build();
473        Self { transmitter }
474    }
475}
476
477impl LogAppender for SynchTransmittingLogAppender {
478    fn log(&self, log: Log) {
479        let mut directed = DirectedProto::signal();
480        directed.from(log.point.to_surface());
481        directed.agent(Agent::Point(log.point.clone()));
482        directed.body(LogSubstance::Log(log).into());
483        self.transmitter.signal(directed);
484    }
485
486    fn audit(&self, log: AuditLog) {
487        let mut directed = DirectedProto::signal();
488        directed.from(log.point.to_surface());
489        directed.agent(Agent::Point(log.point.clone()));
490        directed.body(LogSubstance::Audit(log).into());
491        self.transmitter.signal(directed);
492    }
493
494    fn span_event(&self, log: LogSpanEvent) {
495        let mut directed = DirectedProto::signal();
496        directed.from(log.point.to_surface());
497        directed.agent(Agent::Point(log.point.clone()));
498        directed.body(LogSubstance::Event(log).into());
499        self.transmitter.signal(directed);
500    }
501
502    fn pointless(&self, log: PointlessLog) {
503        let mut directed = DirectedProto::signal();
504        directed.from(Point::anonymous());
505        directed.agent(Agent::Anonymous);
506        directed.body(LogSubstance::Pointless(log).into());
507        self.transmitter.signal(directed);
508    }
509}
510
511#[derive(Clone)]
512pub struct PointLogger {
513    pub logger: RootLogger,
514    pub point: Point,
515    pub mark: Point,
516    pub action: Option<CamelCase>,
517}
518
519impl Default for PointLogger {
520    fn default() -> Self {
521        Self {
522            logger: Default::default(),
523            point: Point::root(),
524            mark: Point::root(),
525            action: None,
526        }
527    }
528}
529
530impl PointLogger {
531    pub fn source(&self) -> LogSource {
532        self.logger.source()
533    }
534
535    pub fn opt_span(&self, span: Option<LogSpan>) -> SpanLogger {
536        let new = span.is_none();
537        let span = LogSpan::opt(self.point.clone(), span);
538        let logger = SpanLogger {
539            root_logger: self.logger.clone(),
540            span: span.clone(),
541            commit_on_drop: true,
542        };
543
544        if new {
545            self.logger.span_event(LogSpanEvent::new(
546                &span,
547                &self.point,
548                LogSpanEventKind::Entry,
549                Default::default(),
550            ));
551        }
552
553        logger
554    }
555
556    pub fn for_span_async(&self, span: LogSpan) -> SpanLogger {
557        let mut span = self.for_span(span);
558        span.commit_on_drop = false;
559        span
560    }
561
562    pub fn for_span(&self, span: LogSpan) -> SpanLogger {
563        let mut span = SpanLogger {
564            root_logger: self.logger.clone(),
565            span,
566            commit_on_drop: true,
567        };
568        span
569    }
570
571    pub fn span(&self) -> SpanLogger {
572        let span = LogSpan::new(self.point.clone());
573        let logger = SpanLogger {
574            root_logger: self.logger.clone(),
575            span: span.clone(),
576            commit_on_drop: true,
577        };
578
579        self.logger.span_event(LogSpanEvent::new(
580            &span,
581            &self.point,
582            LogSpanEventKind::Entry,
583            Default::default(),
584        ));
585
586        logger
587    }
588
589    pub fn span_async(&self) -> SpanLogger {
590        let mut span = self.span();
591        span.commit_on_drop = false;
592        span
593    }
594
595    pub fn spanner<S>(&self, spannable: &S) -> SpanLogger
596    where
597        S: Spannable,
598    {
599        let logger = self.span();
600        let mut attrs = HashMap::new();
601        attrs.insert("type".to_string(), spannable.span_type().to_string());
602        attrs.insert("id".to_string(), spannable.span_id().to_string());
603        logger.span_attr(attrs);
604        logger
605    }
606
607    pub fn point(&self, point: Point) -> PointLogger {
608        PointLogger {
609            logger: self.logger.clone(),
610            point,
611            mark: Point::root(),
612            action: None,
613        }
614    }
615
616    pub fn push_point<S: ToString>(&self, segs: S) -> Result<PointLogger, SpaceErr> {
617        Ok(PointLogger {
618            logger: self.logger.clone(),
619            point: self.point.push(segs)?,
620            mark: Point::root(),
621            action: None,
622        })
623    }
624
625    pub fn pop_mark(&self) -> PointLogger {
626        PointLogger {
627            logger: self.logger.clone(),
628            point: self.point.clone(),
629            mark: self.mark.pop(),
630            action: self.action.clone(),
631        }
632    }
633
634    pub fn push_mark<S: ToString>(&self, segs: S) -> Result<PointLogger, SpaceErr> {
635        Ok(PointLogger {
636            logger: self.logger.clone(),
637            point: self.point.clone(),
638            mark: self.mark.push(segs)?,
639            action: None,
640        })
641    }
642
643    pub fn push_action<A: ToString>(&self, action: A) -> Result<PointLogger, SpaceErr> {
644        Ok(PointLogger {
645            logger: self.logger.clone(),
646            point: self.point.clone(),
647            mark: self.mark.clone(),
648            action: Some(CamelCase::from_str(action.to_string().as_str())?),
649        })
650    }
651
652    pub fn msg<M>(&self, level: Level, message: M)
653    where
654        M: ToString,
655    {
656        self.logger.log(Log {
657            point: self.point.clone(),
658            mark: self.mark.clone(),
659            action: self.action.clone(),
660            level,
661            timestamp: timestamp().timestamp_millis(),
662            payload: LogPayload::Message(message.to_string()),
663            span: None,
664            source: self.logger.source(),
665        })
666    }
667
668    pub fn handle(&self, log: LogSubstance) {
669        match log {
670            LogSubstance::Log(log) => {
671                self.logger.log(log);
672            }
673            LogSubstance::Span(span) => {
674                println!("start log span...");
675                // not sure how to handle this
676            }
677            LogSubstance::Event(event) => {
678                self.logger.span_event(event);
679            }
680            LogSubstance::Audit(audit) => {
681                self.logger.audit(audit);
682            }
683            LogSubstance::Pointless(pointless) => {
684                self.logger.pointless(pointless);
685            }
686        }
687    }
688
689    pub fn trace<M>(&self, message: M)
690    where
691        M: ToString,
692    {
693        self.msg(Level::Trace, message);
694    }
695
696    pub fn debug<M>(&self, message: M)
697    where
698        M: ToString,
699    {
700        self.msg(Level::Trace, message);
701    }
702
703    pub fn info<M>(&self, message: M)
704    where
705        M: ToString,
706    {
707        self.msg(Level::Trace, message);
708    }
709
710    pub fn warn<M>(&self, message: M)
711    where
712        M: ToString,
713    {
714        self.msg(Level::Warn, message);
715    }
716
717    pub fn error<M>(&self, message: M)
718    where
719        M: ToString,
720    {
721        self.msg(Level::Error, message);
722    }
723
724    pub fn result<R, E>(&self, result: Result<R, E>) -> Result<R, E>
725    where
726        E: ToString,
727    {
728        match &result {
729            Ok(_) => {}
730            Err(err) => {
731                //self.error(err.to_string());
732                self.msg(Level::Error, err.to_string());
733            }
734        }
735        result
736    }
737
738    pub fn eat<R, E>(&self, result: Result<R, E>)
739    where
740        E: ToString,
741    {
742        match &result {
743            Ok(_) => {}
744            Err(err) => {
745                self.error(err.to_string());
746            }
747        }
748    }
749
750    pub fn result_ctx<R, E>(&self, ctx: &str, result: Result<R, E>) -> Result<R, E>
751    where
752        E: ToString,
753    {
754        match &result {
755            Ok(_) => {}
756            Err(err) => {
757                self.msg(Level::Error, err.to_string());
758            }
759        }
760        result
761    }
762
763    pub fn eat_ctx<R, E>(&self, ctx: &str, result: Result<R, E>)
764    where
765        E: ToString,
766    {
767        match &result {
768            Ok(_) => {}
769            Err(err) => {
770                self.error(format!("{} {}", ctx, err.to_string()));
771            }
772        }
773    }
774
775    pub fn track<T, F>(&self, trackable: &T, f: F)
776    where
777        T: Trackable,
778        F: FnOnce() -> Tracker,
779    {
780        if trackable.track() {
781            let tracker = f();
782            self.msg(tracker.level.clone(), trackable.track_fmt(&tracker));
783        }
784    }
785
786    pub fn track_msg<T, F, M, S>(&self, trackable: &T, f: F, m: M)
787    where
788        T: Trackable,
789        F: FnOnce() -> Tracker,
790        M: FnOnce() -> S,
791        S: ToString,
792    {
793        if trackable.track() {
794            let tracker = f();
795            let message = m().to_string();
796            self.msg(
797                tracker.level.clone(),
798                format!("{} {}", trackable.track_fmt(&tracker), message),
799            );
800        }
801    }
802}
803
804pub struct SpanLogBuilder {
805    pub entry_timestamp: Timestamp,
806    pub attributes: HashMap<String, String>,
807}
808
809impl SpanLogBuilder {
810    pub fn new() -> Self {
811        Self {
812            entry_timestamp: timestamp(),
813            attributes: HashMap::new(),
814        }
815    }
816}
817
818#[derive(Clone)]
819pub struct SpanLogger {
820    root_logger: RootLogger,
821    span: LogSpan,
822    commit_on_drop: bool,
823}
824
825impl SpanLogger {
826    pub fn span_uuid(&self) -> Uuid {
827        self.span.id.clone()
828    }
829
830    pub fn point(&self) -> &Point {
831        &self.span.point
832    }
833
834    pub fn span(&self) -> SpanLogger {
835        let span = LogSpan::new(self.point().clone());
836        SpanLogger {
837            root_logger: self.root_logger.clone(),
838            span,
839            commit_on_drop: true,
840        }
841    }
842
843    pub fn spanner<S>(&self, spannable: &S) -> SpanLogger
844    where
845        S: Spannable,
846    {
847        let logger = self.span();
848        let mut attrs = HashMap::new();
849        attrs.insert("type".to_string(), spannable.span_type().to_string());
850        attrs.insert("id".to_string(), spannable.span_id().to_string());
851        logger.span_attr(attrs);
852        logger
853    }
854
855    pub fn span_attr(&self, attr: HashMap<String, String>) -> SpanLogger {
856        let mut span = LogSpan::new(self.point().clone());
857        span.attributes = attr;
858        SpanLogger {
859            root_logger: self.root_logger.clone(),
860            span,
861            commit_on_drop: true,
862        }
863    }
864
865    pub fn span_async(&self) -> SpanLogger {
866        let mut span = self.span();
867        span.commit_on_drop = false;
868        span
869    }
870
871    pub fn current_span(&self) -> &LogSpan {
872        &self.span
873    }
874
875    pub fn entry_timestamp(&self) -> Timestamp {
876        self.span.entry_timestamp.clone()
877    }
878
879    pub fn set_span_attr<K, V>(&mut self, key: K, value: V)
880    where
881        K: ToString,
882        V: ToString,
883    {
884        self.span
885            .attributes
886            .insert(key.to_string(), value.to_string());
887    }
888
889    pub fn get_span_attr<K>(&self, key: K) -> Option<String>
890    where
891        K: ToString,
892    {
893        self.span.attributes.get(&key.to_string()).cloned()
894    }
895
896    pub fn msg<M>(&self, level: Level, message: M)
897    where
898        M: ToString,
899    {
900        self.root_logger.log(Log {
901            point: self.point().clone(),
902            mark: self.span.mark.clone(),
903            action: self.span.action.clone(),
904            level,
905            timestamp: timestamp().timestamp_millis(),
906            payload: LogPayload::Message(message.to_string()),
907            span: Some(self.span_uuid()),
908            source: self.root_logger.source(),
909        })
910    }
911
912    pub fn trace<M>(&self, message: M)
913    where
914        M: ToString,
915    {
916        self.msg(Level::Trace, message);
917    }
918
919    pub fn debug<M>(&self, message: M)
920    where
921        M: ToString,
922    {
923        self.msg(Level::Trace, message);
924    }
925
926    pub fn info<M>(&self, message: M)
927    where
928        M: ToString,
929    {
930        self.msg(Level::Trace, message);
931    }
932
933    pub fn warn<M>(&self, message: M)
934    where
935        M: ToString,
936    {
937        self.msg(Level::Warn, message);
938    }
939
940    pub fn error<M>(&self, message: M)
941    where
942        M: ToString,
943    {
944        self.msg(Level::Error, message);
945    }
946
947    pub fn audit(&self) -> AuditLogBuilder {
948        AuditLogBuilder {
949            logger: self.root_logger.clone(),
950            point: self.point().clone(),
951            span: self.span.id.clone(),
952            attributes: HashMap::new(),
953        }
954    }
955
956    pub fn builder(&self) -> LogBuilder {
957        let builder = RootLogBuilder::new(self.root_logger.clone(), None);
958        let builder = LogBuilder::new(self.root_logger.clone(), builder);
959        builder
960    }
961
962    pub fn log_audit(&self, log: AuditLog) {
963        self.root_logger.audit(log);
964    }
965
966    pub fn result<R, E>(&self, result: Result<R, E>) -> Result<R, E>
967    where
968        E: ToString,
969    {
970        match &result {
971            Ok(_) => {}
972            Err(err) => {
973                self.error(err.to_string());
974            }
975        }
976        result
977    }
978
979    pub fn result_ctx<R, E>(&self, ctx: &str, result: Result<R, E>) -> Result<R, E>
980    where
981        E: ToString,
982    {
983        match &result {
984            Ok(_) => {}
985            Err(err) => {
986                self.error(format!("{} {}", ctx, err.to_string()));
987            }
988        }
989        result
990    }
991}
992
993impl Drop for SpanLogger {
994    fn drop(&mut self) {
995        if self.commit_on_drop {
996            let log = LogSpanEvent::new(
997                &self.span,
998                self.point(),
999                LogSpanEventKind::Exit,
1000                self.span.attributes.clone(),
1001            );
1002            self.root_logger.span_event(log)
1003        }
1004    }
1005}
1006
1007pub struct LogBuilder {
1008    logger: RootLogger,
1009    builder: RootLogBuilder,
1010}
1011
1012impl LogBuilder {
1013    pub fn new(logger: RootLogger, builder: RootLogBuilder) -> Self {
1014        LogBuilder { logger, builder }
1015    }
1016
1017    pub fn trace(mut self) -> Self {
1018        self.builder = self.builder.trace();
1019        self
1020    }
1021    pub fn debug(mut self) -> Self {
1022        self.builder = self.builder.debug();
1023        self
1024    }
1025    pub fn info(mut self) -> Self {
1026        self.builder = self.builder.info();
1027        self
1028    }
1029    pub fn warn(mut self) -> Self {
1030        self.builder = self.builder.warn();
1031        self
1032    }
1033    pub fn error(mut self) -> Self {
1034        self.builder = self.builder.error();
1035        self
1036    }
1037
1038    pub fn msg<M>(mut self, m: M) -> Self
1039    where
1040        M: ToString,
1041    {
1042        self.builder = self.builder.msg(m);
1043        self
1044    }
1045
1046    pub fn json<'a, J>(mut self, json: J) -> Self
1047    where
1048        J: Into<&'a str>,
1049    {
1050        self.builder = self.builder.json(json);
1051        self
1052    }
1053
1054    pub fn json_value(mut self, json: Value) -> Self {
1055        self.builder = self.builder.json_value(json);
1056        self
1057    }
1058
1059    pub fn commit(mut self) {
1060        self.builder.commit();
1061    }
1062}
1063
1064pub struct AuditLogBuilder {
1065    logger: RootLogger,
1066    point: Point,
1067    span: Uuid,
1068    attributes: HashMap<String, String>,
1069}
1070
1071impl AuditLogBuilder {
1072    pub fn new(logger: RootLogger, point: Point, span: Uuid) -> Self {
1073        AuditLogBuilder {
1074            logger,
1075            point,
1076            attributes: HashMap::new(),
1077            span,
1078        }
1079    }
1080
1081    // make nice appended call:
1082    // logger.audit().append("hello","kitty").commit();
1083    pub fn append<K: ToString, V: ToString>(mut self, key: K, value: V) -> Self {
1084        self.attributes.insert(key.to_string(), value.to_string());
1085        self
1086    }
1087
1088    pub fn add<K: ToString, V: ToString>(&mut self, key: K, value: V) {
1089        self.attributes.insert(key.to_string(), value.to_string());
1090    }
1091
1092    pub fn kind<K>(mut self, kind: K) -> Self
1093    where
1094        K: ToString,
1095    {
1096        self.attributes.insert("kind".to_string(), kind.to_string());
1097        self
1098    }
1099
1100    pub fn commit(mut self) {
1101        let log = AuditLog {
1102            point: self.point,
1103            timestamp: timestamp(),
1104            metrics: self.attributes,
1105        };
1106        self.logger.audit(log)
1107    }
1108}
1109
1110#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
1111pub struct AuditLog {
1112    pub point: Point,
1113    pub timestamp: Timestamp,
1114    pub metrics: HashMap<String, String>,
1115}
1116
1117pub trait Spannable {
1118    fn span_id(&self) -> String;
1119    fn span_type(&self) -> &'static str;
1120}
1121
1122pub trait Trackable {
1123    fn track_id(&self) -> String;
1124    fn track_method(&self) -> String;
1125    fn track_payload(&self) -> String;
1126    fn track_from(&self) -> String;
1127    fn track_to(&self) -> String;
1128    fn track(&self) -> bool;
1129
1130    fn track_payload_fmt(&self) -> String {
1131        self.track_payload()
1132    }
1133
1134    fn track_key_fmt(&self) -> String {
1135        format!(
1136            "{}::<{}>::[{}]",
1137            self.track_id(),
1138            self.track_method(),
1139            self.track_payload_fmt()
1140        )
1141    }
1142
1143    fn track_fmt(&self, tracker: &Tracker) -> String {
1144        format!(
1145            "{}<{}> : {} : ({} -> {})",
1146            tracker.parsec,
1147            tracker.action,
1148            self.track_key_fmt(),
1149            self.track_from(),
1150            self.track_to()
1151        )
1152    }
1153}
1154
1155pub struct Tracker {
1156    pub parsec: String,
1157    pub action: String,
1158    pub level: Level,
1159}
1160
1161impl Tracker {
1162    pub fn new<P: ToString, A: ToString>(parsec: P, action: A) -> Self {
1163        Self {
1164            parsec: parsec.to_string(),
1165            action: action.to_string(),
1166            level: Level::Info,
1167        }
1168    }
1169}
1170
1171pub type Track = TrackDef<String>;
1172pub type TrackRegex = TrackDef<Regex>;
1173
1174#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Hash)]
1175pub struct TrackDef<R> {
1176    selector: Selector,
1177    stop: R,
1178    action: R,
1179}
1180
1181impl TrackRegex {
1182    pub fn new<S: ToString>(selector: S, stop: S, action: S) -> Result<Self, SpaceErr> {
1183        let selector = Selector::from_str(selector.to_string().as_str())?;
1184        let stop = Regex::from_str(stop.to_string().as_str())?;
1185        let action = Regex::from_str(action.to_string().as_str())?;
1186
1187        Ok(Self {
1188            selector,
1189            stop,
1190            action,
1191        })
1192    }
1193}
1194
1195impl TrackDef<String> {
1196    pub fn new<S: ToString>(selector: S, stop: S, action: S) -> Result<Self, SpaceErr> {
1197        let selector = Selector::from_str(selector.to_string().as_str())?;
1198        Regex::from_str(stop.to_string().as_str())?;
1199        Regex::from_str(action.to_string().as_str())?;
1200
1201        let stop = stop.to_string();
1202        let action = action.to_string();
1203
1204        Ok(Self {
1205            selector,
1206            stop,
1207            action,
1208        })
1209    }
1210
1211    pub fn to_regex(&self) -> Result<TrackRegex, SpaceErr> {
1212        Ok(TrackRegex {
1213            selector: self.selector.clone(),
1214            stop: Regex::from_str(self.stop.as_str())?,
1215            action: Regex::from_str(self.action.as_str())?,
1216        })
1217    }
1218}