Skip to main content

drasi_reaction_profiler/
lib.rs

1#![allow(unexpected_cfgs)]
2// Copyright 2025 The Drasi Authors.
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//     http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16//! Profiler reaction plugin for Drasi
17//!
18//! This plugin implements Profiler reactions for Drasi.
19//!
20//! # Example
21//!
22//! ```rust,ignore
23//! use drasi_reaction_profiler::ProfilerReaction;
24//!
25//! let reaction = ProfilerReaction::builder("my-profiler")
26//!     .with_queries(vec!["query1".to_string()])
27//!     .with_window_size(2000)
28//!     .with_report_interval_secs(30)
29//!     .build()?;
30//! ```
31
32pub mod config;
33pub mod descriptor;
34pub mod profiler;
35
36pub use config::ProfilerReactionConfig;
37pub use profiler::ProfilerReaction;
38
39/// Builder for Profiler reaction
40pub struct ProfilerReactionBuilder {
41    id: String,
42    queries: Vec<String>,
43    window_size: usize,
44    report_interval_secs: u64,
45    priority_queue_capacity: Option<usize>,
46    auto_start: bool,
47}
48
49impl ProfilerReactionBuilder {
50    /// Create a new Profiler reaction builder with the given ID
51    pub fn new(id: impl Into<String>) -> Self {
52        Self {
53            id: id.into(),
54            queries: Vec::new(),
55            window_size: 1000,
56            report_interval_secs: 60,
57            priority_queue_capacity: None,
58            auto_start: true,
59        }
60    }
61
62    /// Set the query IDs to subscribe to
63    pub fn with_queries(mut self, queries: Vec<String>) -> Self {
64        self.queries = queries;
65        self
66    }
67
68    /// Add a query ID to subscribe to
69    pub fn with_query(mut self, query_id: impl Into<String>) -> Self {
70        self.queries.push(query_id.into());
71        self
72    }
73
74    /// Set the window size for profiling statistics
75    pub fn with_window_size(mut self, size: usize) -> Self {
76        self.window_size = size;
77        self
78    }
79
80    /// Set the report interval in seconds
81    pub fn with_report_interval_secs(mut self, secs: u64) -> Self {
82        self.report_interval_secs = secs;
83        self
84    }
85
86    /// Set the priority queue capacity
87    pub fn with_priority_queue_capacity(mut self, capacity: usize) -> Self {
88        self.priority_queue_capacity = Some(capacity);
89        self
90    }
91
92    /// Set whether the reaction should auto-start
93    pub fn with_auto_start(mut self, auto_start: bool) -> Self {
94        self.auto_start = auto_start;
95        self
96    }
97
98    /// Set the full configuration at once
99    pub fn with_config(mut self, config: ProfilerReactionConfig) -> Self {
100        self.window_size = config.window_size;
101        self.report_interval_secs = config.report_interval_secs;
102        self
103    }
104
105    /// Build the Profiler reaction
106    pub fn build(self) -> anyhow::Result<ProfilerReaction> {
107        let config = ProfilerReactionConfig {
108            window_size: self.window_size,
109            report_interval_secs: self.report_interval_secs,
110        };
111
112        Ok(ProfilerReaction::from_builder(
113            self.id,
114            self.queries,
115            config,
116            self.priority_queue_capacity,
117            self.auto_start,
118        ))
119    }
120}
121
122#[cfg(test)]
123mod tests {
124    use super::*;
125    use drasi_lib::Reaction;
126
127    #[test]
128    fn test_profiler_builder_defaults() {
129        let reaction = ProfilerReactionBuilder::new("test-reaction")
130            .build()
131            .unwrap();
132        assert_eq!(reaction.id(), "test-reaction");
133    }
134
135    #[test]
136    fn test_profiler_builder_custom() {
137        let reaction = ProfilerReaction::builder("test-reaction")
138            .with_window_size(2000)
139            .with_report_interval_secs(30)
140            .with_queries(vec!["query1".to_string()])
141            .build()
142            .unwrap();
143
144        assert_eq!(reaction.id(), "test-reaction");
145        assert_eq!(reaction.query_ids(), vec!["query1".to_string()]);
146    }
147
148    #[test]
149    fn test_profiler_new_constructor() {
150        let config = ProfilerReactionConfig::default();
151        let reaction = ProfilerReaction::new("test-reaction", vec!["query1".to_string()], config);
152        assert_eq!(reaction.id(), "test-reaction");
153    }
154}
155
156/// Dynamic plugin entry point.
157///
158/// Dynamic plugin entry point.
159#[cfg(feature = "dynamic-plugin")]
160drasi_plugin_sdk::export_plugin!(
161    plugin_id = "profiler-reaction",
162    core_version = env!("CARGO_PKG_VERSION"),
163    lib_version = env!("CARGO_PKG_VERSION"),
164    plugin_version = env!("CARGO_PKG_VERSION"),
165    source_descriptors = [],
166    reaction_descriptors = [descriptor::ProfilerReactionDescriptor],
167    bootstrap_descriptors = [],
168);