11use std:: {
22 collections:: HashMap ,
33 sync:: {
4- mpsc:: { channel , Receiver , Sender } ,
4+ mpsc:: { self , Sender } ,
55 Arc , Condvar , Mutex ,
66 } ,
77 thread:: JoinHandle ,
@@ -16,6 +16,28 @@ use crate::{
1616
1717const LOG_TAG : & str = "Pyroscope::Agent" ;
1818
19+
20+ /// A signal sent from the agent to the timer.
21+ ///
22+ /// Either schedules another wake-up, or asks
23+ /// the timer thread to terminate.
24+ #[ derive( Debug , Clone , Copy ) ]
25+ pub enum AgentSignal {
26+ // Thread termination was requested.
27+ Terminate ,
28+ // When to take the next snapshot using the `Backend`.
29+ NextSnapshot ( u64 ) ,
30+ }
31+
32+ impl std:: fmt:: Display for AgentSignal {
33+ fn fmt ( & self , f : & mut std:: fmt:: Formatter ) -> std:: fmt:: Result {
34+ match self {
35+ Self :: Terminate => write ! ( f, "Terminate" ) ,
36+ Self :: NextSnapshot ( when) => write ! ( f, "NextSnapshot({})" , when) ,
37+ }
38+ }
39+ }
40+
1941/// Pyroscope Agent Configuration. This is the configuration that is passed to the agent.
2042/// # Example
2143/// ```
@@ -32,6 +54,8 @@ pub struct PyroscopeConfig {
3254 pub tags : HashMap < String , String > ,
3355 /// Sample rate used in Hz
3456 pub sample_rate : i32 ,
57+ /// How long to accumulate data for before sending it upstream
58+ pub accumulation_cycle : std:: time:: Duration ,
3559 // TODO
3660 // log_level
3761 // auth_token
@@ -52,6 +76,7 @@ impl PyroscopeConfig {
5276 application_name : application_name. as_ref ( ) . to_owned ( ) ,
5377 tags : HashMap :: new ( ) ,
5478 sample_rate : 100i32 ,
79+ accumulation_cycle : std:: time:: Duration :: from_secs ( 10 ) ,
5580 }
5681 }
5782
@@ -69,6 +94,26 @@ impl PyroscopeConfig {
6994 }
7095 }
7196
97+ /// Override the accumulation cycle.
98+ ///
99+ /// # Example
100+ ///
101+ /// ```
102+ /// # fn main() -> Result<(), PyroscopeError> {
103+ /// use std::time::Duration;
104+ /// use pyroscope::pyroscope::PyroscopeConfig;
105+ /// let config = PyroscopeConfig::new("http://localhost:8080", "my-app")
106+ /// .accumulation_cycle(Duration::from_millis(4587))?;
107+ /// # Ok(())
108+ /// # }
109+ /// ```
110+ pub fn accumulation_cycle ( self , accumulation_cycle : std:: time:: Duration ) -> Self {
111+ Self {
112+ accumulation_cycle,
113+ ..self
114+ }
115+ }
116+
72117 /// Set the tags
73118 /// # Example
74119 /// ```ignore
@@ -134,7 +179,9 @@ impl PyroscopeAgentBuilder {
134179 /// ?;
135180 /// ```
136181 pub fn backend < T > ( self , backend : T ) -> Self
137- where T : ' static + Backend {
182+ where
183+ T : ' static + Backend ,
184+ {
138185 Self {
139186 backend : Arc :: new ( Mutex :: new ( backend) ) ,
140187 ..self
@@ -145,7 +192,7 @@ impl PyroscopeAgentBuilder {
145192 /// # Example
146193 /// ```ignore
147194 /// let builder = PyroscopeAgentBuilder::new("http://localhost:8080", "my-app")
148- /// .sample_rate(99 )
195+ /// .sample_rate(113 )
149196 /// .build()
150197 /// ?;
151198 /// ```
@@ -156,6 +203,28 @@ impl PyroscopeAgentBuilder {
156203 }
157204 }
158205
206+ /// Set the accumulation cycle. Default value is 10 seconds.
207+ ///
208+ /// # Example
209+ ///
210+ /// ```
211+ /// # fn main() -> Result<(), PyroscopeError> {
212+ /// use std::time::Duration;
213+ ///
214+ /// let builder = PyroscopeAgentBuilder::new("http://localhost:8080", "my-app")
215+ /// .accumulation_cycle(Duration::from_secs(3))
216+ /// .build()
217+ /// ?;
218+ /// # Ok(())
219+ /// # }
220+ /// ```
221+ pub fn accumulation_cycle ( self , acc_cycle : impl Into < std:: time:: Duration > ) -> Self {
222+ Self {
223+ config : self . config . accumulation_cycle ( acc_cycle. into ( ) ) ,
224+ ..self
225+ }
226+ }
227+
159228 /// Set tags. Default is empty.
160229 /// # Example
161230 /// ```ignore
@@ -179,7 +248,7 @@ impl PyroscopeAgentBuilder {
179248 log:: trace!( target: LOG_TAG , "Backend initialized" ) ;
180249
181250 // Start Timer
182- let timer = Timer :: default ( ) . initialize ( ) ?;
251+ let timer = Timer :: initialize ( self . config . accumulation_cycle . clone ( ) ) ?;
183252 log:: trace!( target: LOG_TAG , "Timer initialized" ) ;
184253
185254 // Start the SessionManager
@@ -204,7 +273,7 @@ impl PyroscopeAgentBuilder {
204273pub struct PyroscopeAgent {
205274 timer : Timer ,
206275 session_manager : SessionManager ,
207- tx : Option < Sender < u64 > > ,
276+ tx : Option < Sender < AgentSignal > > ,
208277 handle : Option < JoinHandle < Result < ( ) > > > ,
209278 running : Arc < ( Mutex < bool > , Condvar ) > ,
210279
@@ -287,7 +356,7 @@ impl PyroscopeAgent {
287356 * running = true ;
288357 drop ( running) ;
289358
290- let ( tx, rx) : ( Sender < u64 > , Receiver < u64 > ) = channel ( ) ;
359+ let ( tx, rx) = mpsc :: channel ( ) ;
291360 self . timer . attach_listener ( tx. clone ( ) ) ?;
292361 self . tx = Some ( tx) ;
293362
@@ -298,28 +367,31 @@ impl PyroscopeAgent {
298367 self . handle = Some ( std:: thread:: spawn ( move || {
299368 log:: trace!( target: LOG_TAG , "Main Thread started" ) ;
300369
301- while let Ok ( until) = rx. recv ( ) {
302- log:: trace!( target: LOG_TAG , "Sending session {}" , until) ;
303-
304- // Generate report from backend
305- let report = backend. lock ( ) ?. report ( ) ?;
306-
307- // Send new Session to SessionManager
308- stx. send ( SessionSignal :: Session ( Session :: new (
309- until,
310- config. clone ( ) ,
311- report,
312- ) ?) ) ?;
313-
314- if until == 0 {
315- log:: trace!( target: LOG_TAG , "Session Killed" ) ;
316-
317- let ( lock, cvar) = & * pair;
318- let mut running = lock. lock ( ) ?;
319- * running = false ;
320- cvar. notify_one ( ) ;
321-
322- return Ok ( ( ) ) ;
370+ while let Ok ( signal) = rx. recv ( ) {
371+ match signal {
372+ AgentSignal :: NextSnapshot ( until) => {
373+ log:: trace!( target: LOG_TAG , "Sending session {}" , until) ;
374+
375+ // Generate report from backend
376+ let report = backend. lock ( ) ?. report ( ) ?;
377+
378+ // Send new Session to SessionManager
379+ stx. send ( SessionSignal :: Session ( Session :: new (
380+ until,
381+ config. clone ( ) ,
382+ report,
383+ ) ?) ) ?
384+ }
385+ AgentSignal :: Terminate => {
386+ log:: trace!( target: LOG_TAG , "Session Killed" ) ;
387+
388+ let ( lock, cvar) = & * pair;
389+ let mut running = lock. lock ( ) ?;
390+ * running = false ;
391+ cvar. notify_one ( ) ;
392+
393+ return Ok ( ( ) ) ;
394+ }
323395 }
324396 }
325397 Ok ( ( ) )
@@ -345,7 +417,9 @@ impl PyroscopeAgent {
345417 log:: debug!( target: LOG_TAG , "Stopping" ) ;
346418 // get tx and send termination signal
347419 if let Some ( sender) = self . tx . take ( ) {
348- sender. send ( 0 ) ?;
420+ // best effort
421+ let _ = sender. send ( AgentSignal :: NextSnapshot ( 0 ) ) ;
422+ sender. send ( AgentSignal :: Terminate ) ?;
349423 } else {
350424 log:: error!( "PyroscopeAgent - Missing sender" )
351425 }
0 commit comments