next_web_ai/observation/
simple_observation.rs

1use std::collections::VecDeque;
2
3use next_web_core::{autoconfigure::context, convert::into_box::IntoBox};
4
5use crate::{
6    chat::observation::observation_convention::ObservationConvention,
7    observation::observation_documentation::BoxObservationConvention,
8};
9
10use super::{
11    observation::{Context, Observation},
12    observation_filter::ObservationFilter,
13    observation_handler::ObservationHandler,
14    observation_registry::ObservationRegistry,
15};
16
17pub struct SimpleObservation {
18    pub(crate) context: Box<dyn Context>,
19    pub(crate) registry: Box<dyn ObservationRegistry>,
20    pub(crate) convention: Option<BoxObservationConvention>,
21    pub(crate) handlers: VecDeque<Box<dyn ObservationHandler>>,
22    pub(crate) filters: Vec<Box<dyn ObservationFilter>>,
23}
24
25impl SimpleObservation {
26    pub fn new(
27        name: impl AsRef<str>,
28        registry: Box<dyn ObservationRegistry>,
29        mut context: impl Context + 'static,
30    ) -> Self {
31        context.set_name(name.as_ref());
32        let filters = registry
33            .observation_config()
34            .observation_filters
35            .data
36            .blocking_read()
37            .clone();
38        Self {
39            convention: Self::get_convention_from_config(&registry, &context),
40            handlers: Self::get_handlers_from_config(&registry, &context),
41            context: Box::new(context),
42            filters,
43            registry,
44        }
45    }
46
47    fn get_convention_from_config(
48        registry: &Box<dyn ObservationRegistry>,
49        context: &dyn Context,
50    ) -> Option<BoxObservationConvention> {
51        for convention in registry
52            .observation_config()
53            .observation_conventions
54            .data
55            .blocking_read()
56            .iter()
57        {
58            if convention.supports_context(context) {
59                return Some(convention.clone());
60            }
61        }
62        return None;
63    }
64
65    fn get_handlers_from_config(
66        registry: &Box<dyn ObservationRegistry>,
67        context: &dyn Context,
68    ) -> VecDeque<Box<dyn ObservationHandler>> {
69        let mut handlers = VecDeque::new();
70        for handler in registry
71            .observation_config()
72            .observation_handlers
73            .data
74            .blocking_read()
75            .iter()
76        {
77            if handler.supports_context(context) {
78                handlers.push_back(handler.clone());
79            }
80        }
81        handlers
82    }
83}
84
85impl SimpleObservation {
86    fn notify_on_observation_started(&mut self) {
87        for handler in self.handlers.iter_mut() {
88            handler.on_start(self.context.as_ref());
89        }
90    }
91
92    fn notify_on_observation_stopped(&mut self, context: &dyn Context) {
93        self.handlers
94            .iter_mut()
95            .rev()
96            .for_each(|handler| handler.on_stop(context));
97    }
98}
99impl Observation for SimpleObservation {
100    fn start(&mut self) {
101        if let Some(convention) = self.convention.as_ref() {
102            let low = convention.low_cardinality_key_values(self.context.as_ref());
103            let high = convention.high_cardinality_key_values(self.context.as_ref());
104
105            self.context.add_low_cardinality_key_values(low);
106            self.context.add_low_cardinality_key_values(high);
107
108            let new_name = convention.name();
109            if let Some(name) = new_name {
110                self.context.set_name(name);
111            }
112        }
113        self.notify_on_observation_started();
114    }
115
116    fn stop(&mut self) {
117        if let Some(convention) = self.convention.as_ref() {
118            let low = convention.low_cardinality_key_values(self.context.as_ref());
119            let high = convention.high_cardinality_key_values(self.context.as_ref());
120
121            self.context.add_low_cardinality_key_values(low);
122            self.context.add_low_cardinality_key_values(high);
123
124            let new_name = convention.contextual_name(self.context.as_ref());
125            if let Some(name) = new_name {
126                self.context.set_contextual_name(name);
127            }
128        }
129
130        let mut modified_context = self.context.clone();
131        for filter in self.filters.iter_mut() {
132            modified_context = filter.map(modified_context);
133        }
134
135        self.notify_on_observation_stopped(modified_context.as_ref());
136    }
137
138    fn context(&mut self) -> &mut dyn super::observation::Context {
139        self.context.as_mut()
140    }
141
142    fn contextual_name(&mut self, contextual_name: &str) {
143        self.context.set_contextual_name(contextual_name);
144    }
145
146    fn parent_observation(&mut self, parent_observation: Box<dyn Observation>) {
147        todo!()
148    }
149
150    fn low_cardinality_key_value(&mut self, key_value: Box<dyn crate::util::key_value::KeyValue>) {
151        todo!()
152    }
153
154    fn high_cardinality_key_value(&mut self, key_value: Box<dyn crate::util::key_value::KeyValue>) {
155        todo!()
156    }
157
158    fn observation_convention(&mut self, observation_convention: BoxObservationConvention) {
159        todo!()
160    }
161
162    fn error(&mut self, error: &next_web_core::error::BoxError) {
163        todo!()
164    }
165
166    fn event(&mut self, event: Box<dyn super::observation::Event>) {
167        todo!()
168    }
169
170    fn open_scope(&self) -> Box<dyn super::observation::Scope> {
171        todo!()
172    }
173}