Skip to main content

ferroui_splat/application_performance_monitoring/
default_feature_usage_tracking.rs

1//! `DefaultFeatureUsageTrackingSession`, `FuncFeatureUsageTrackingManager` and
2//! `DefaultFeatureUsageTrackingManager`.
3
4use super::{Guid, IFeatureUsageTrackingManager, IFeatureUsageTrackingSession, IFeatureUsageTrackingSessionOf};
5use crate::logging::IEnableLogger;
6use ferroui_system::IDisposable;
7use std::rc::Rc;
8
9/// The session of [`DefaultFeatureUsageTrackingManager`] (`DefaultFeatureUsageTrackingSession`):
10/// it logs the start and the end of the feature, and its failures, at the level `Info`.
11pub struct DefaultFeatureUsageTrackingSession {
12    parent_reference: Guid,
13    feature_reference: Guid,
14    feature_name: String,
15}
16
17impl DefaultFeatureUsageTrackingSession {
18    /// A session for the feature `feature_name`, without a parent.
19    ///
20    /// Panics when the name is empty or white space (`ArgumentException`).
21    pub fn new(feature_name: &str) -> Self {
22        Self::with_parent(feature_name, Guid::EMPTY)
23    }
24
25    /// A session for the feature `feature_name` under the session `parent_reference`.
26    pub(crate) fn with_parent(feature_name: &str, parent_reference: Guid) -> Self {
27        assert!(!feature_name.trim().is_empty(), "The value cannot be an empty string or composed entirely of whitespace. (Parameter 'featureName')");
28        let session = Self {
29            parent_reference,
30            feature_reference: Guid::new_guid(),
31            feature_name: feature_name.to_owned(),
32        };
33        session.log().info_fn(&|| session.session_start_log_message());
34        session
35    }
36
37    fn session_start_log_message(&self) -> String {
38        let mut message = format!("Feature Start. Reference={}", self.feature_reference);
39        if self.parent_reference != Guid::EMPTY {
40            message += &format!(", Parent Reference={}", self.parent_reference);
41        }
42        message
43    }
44}
45
46impl IEnableLogger for DefaultFeatureUsageTrackingSession {}
47
48impl IFeatureUsageTrackingSession for DefaultFeatureUsageTrackingSession {
49    fn feature_name(&self) -> &str {
50        &self.feature_name
51    }
52
53    fn sub_feature(&self, description: &str) -> Rc<dyn IFeatureUsageTrackingSession> {
54        Rc::new(Self::with_parent(description, self.feature_reference))
55    }
56
57    fn on_exception(&self, exception: &dyn std::error::Error) {
58        self.log().info_exception_fn(exception, &|| "Feature Usage Tracking Exception".to_owned());
59    }
60}
61
62impl IFeatureUsageTrackingSessionOf<Guid> for DefaultFeatureUsageTrackingSession {
63    fn feature_reference(&self) -> Guid {
64        self.feature_reference
65    }
66
67    fn parent_reference(&self) -> Guid {
68        self.parent_reference
69    }
70}
71
72impl IDisposable for DefaultFeatureUsageTrackingSession {
73    fn dispose(&self) {
74        self.log().info_fn(&|| format!("Feature Finish: {}", self.feature_reference));
75    }
76}
77
78/// A manager over a function that starts the sessions (`FuncFeatureUsageTrackingManager`).
79pub struct FuncFeatureUsageTrackingManager {
80    feature_usage_tracking_session_func: Box<dyn Fn(&str) -> Rc<dyn IFeatureUsageTrackingSession>>,
81}
82
83impl FuncFeatureUsageTrackingManager {
84    /// A manager whose sessions `feature_usage_tracking_session_func` starts.
85    pub fn new(
86        feature_usage_tracking_session_func: impl Fn(&str) -> Rc<dyn IFeatureUsageTrackingSession> + 'static,
87    ) -> Self {
88        Self { feature_usage_tracking_session_func: Box::new(feature_usage_tracking_session_func) }
89    }
90}
91
92impl IFeatureUsageTrackingManager for FuncFeatureUsageTrackingManager {
93    fn get_feature_usage_tracking_session(&self, feature_name: &str) -> Rc<dyn IFeatureUsageTrackingSession> {
94        (self.feature_usage_tracking_session_func)(feature_name)
95    }
96}
97
98/// The manager Splat registers (`DefaultFeatureUsageTrackingManager`): its sessions are
99/// [`DefaultFeatureUsageTrackingSession`]s, which log.
100pub struct DefaultFeatureUsageTrackingManager {
101    inner: FuncFeatureUsageTrackingManager,
102}
103
104impl Default for DefaultFeatureUsageTrackingManager {
105    fn default() -> Self {
106        Self::new()
107    }
108}
109
110impl DefaultFeatureUsageTrackingManager {
111    /// The manager.
112    pub fn new() -> Self {
113        Self {
114            inner: FuncFeatureUsageTrackingManager::new(|feature_name| {
115                Rc::new(DefaultFeatureUsageTrackingSession::new(feature_name)) as Rc<dyn IFeatureUsageTrackingSession>
116            }),
117        }
118    }
119}
120
121impl IFeatureUsageTrackingManager for DefaultFeatureUsageTrackingManager {
122    fn get_feature_usage_tracking_session(&self, feature_name: &str) -> Rc<dyn IFeatureUsageTrackingSession> {
123        self.inner.get_feature_usage_tracking_session(feature_name)
124    }
125}