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 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 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 }
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 }
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.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 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}