@@ -14,13 +14,15 @@ use crate::{
1414 session:: { Session , SessionManager , SessionSignal } ,
1515 timer:: { Timer , TimerSignal } ,
1616 utils:: get_time_range,
17+ PyroscopeError ,
1718} ;
1819
1920use crate :: backend:: BackendImpl ;
2021
2122const LOG_TAG : & str = "Pyroscope::Agent" ;
2223
2324/// Pyroscope Agent Configuration. This is the configuration that is passed to the agent.
25+ ///
2426/// # Example
2527/// ```
2628/// use pyroscope::pyroscope::PyroscopeConfig;
@@ -43,6 +45,7 @@ pub struct PyroscopeConfig {
4345impl PyroscopeConfig {
4446 /// Create a new PyroscopeConfig object. url and application_name are required.
4547 /// tags and sample_rate are optional. If sample_rate is not specified, it will default to 100.
48+ ///
4649 /// # Example
4750 /// ```ignore
4851 /// let config = PyroscopeConfig::new("http://localhost:8080", "my-app");
@@ -70,7 +73,8 @@ impl PyroscopeConfig {
7073 Self { spy_name, ..self }
7174 }
7275
73- /// Set the tags
76+ /// Set the tags.
77+ ///
7478 /// # Example
7579 /// ```ignore
7680 /// use pyroscope::pyroscope::PyroscopeConfig;
@@ -126,11 +130,12 @@ impl PyroscopeAgentBuilder {
126130 }
127131 }
128132
129- /// Set the agent backend. Default is pprof.
133+ /// Set the agent backend. Default is void-backend.
134+ ///
130135 /// # Example
131136 /// ```ignore
132137 /// let builder = PyroscopeAgentBuilder::new("http://localhost:8080", "my-app")
133- /// .backend(Pprof::default( ))
138+ /// .backend(PprofConfig::new().sample_rate(100 ))
134139 /// .build()
135140 /// ?;
136141 /// ```
@@ -139,6 +144,7 @@ impl PyroscopeAgentBuilder {
139144 }
140145
141146 /// Set tags. Default is empty.
147+ ///
142148 /// # Example
143149 /// ```ignore
144150 /// let builder = PyroscopeAgentBuilder::new("http://localhost:8080", "my-app")
@@ -152,30 +158,28 @@ impl PyroscopeAgentBuilder {
152158 }
153159 }
154160
155- /// Initialize the backend, timer and return a PyroscopeAgent object.
161+ /// Initialize the backend, timer and return a PyroscopeAgent with Ready
162+ /// state. While you can call this method, you should call it through the
163+ /// `PyroscopeAgent.build()` method.
156164 pub fn build ( self ) -> Result < PyroscopeAgent < PyroscopeAgentReady > > {
157- // Get the backend
158- //let backend = Arc::clone(&self.backend);
159-
160165 // Set Spy Name and Sample Rate from the Backend
161166 let config = self . config . sample_rate ( self . backend . sample_rate ( ) ?) ;
162167 let config = config. spy_name ( self . backend . spy_name ( ) ?) ;
163168
164169 // Set Global Tags
165- for ( k , v ) in config. tags . iter ( ) {
170+ for ( key , value ) in config. tags . iter ( ) {
166171 self . backend
167172 . add_rule ( crate :: backend:: Rule :: GlobalTag ( Tag :: new (
168- k . to_owned ( ) ,
169- v . to_owned ( ) ,
173+ key . to_owned ( ) ,
174+ value . to_owned ( ) ,
170175 ) ) ) ?;
171176 }
172177
173- // Initialize the backend
178+ // Initialize the Backend
174179 let backend_ready = self . backend . initialize ( ) ?;
175-
176180 log:: trace!( target: LOG_TAG , "Backend initialized" ) ;
177181
178- // Start Timer
182+ // Start the Timer
179183 let timer = Timer :: initialize ( std:: time:: Duration :: from_secs ( 10 ) ) ?;
180184 log:: trace!( target: LOG_TAG , "Timer initialized" ) ;
181185
@@ -201,9 +205,13 @@ impl PyroscopeAgentBuilder {
201205 }
202206}
203207
208+ /// This trait is used to encode the state of the agent.
204209pub trait PyroscopeAgentState { }
210+ /// Marker struct for an Uninitialized state.
205211pub struct PyroscopeAgentBare ;
212+ /// Marker struct for a Ready state.
206213pub struct PyroscopeAgentReady ;
214+ /// Marker struct for a Running state.
207215pub struct PyroscopeAgentRunning ;
208216impl PyroscopeAgentState for PyroscopeAgentBare { }
209217impl PyroscopeAgentState for PyroscopeAgentReady { }
@@ -307,11 +315,12 @@ impl PyroscopeAgent<PyroscopeAgentBare> {
307315}
308316
309317impl PyroscopeAgent < PyroscopeAgentReady > {
310- /// Start profiling and sending data. The agent will keep running until stopped. The agent will send data to the server every 10s secondy.
318+ /// Start profiling and sending data. The agent will keep running until stopped. The agent will send data to the server every 10s seconds.
319+ ///
311320 /// # Example
312321 /// ```ignore
313322 /// let agent = PyroscopeAgent::builder("http://localhost:8080", "my-app").build()?;
314- /// agent.start()?;
323+ /// let agent_running = agent.start()?;
315324 /// ```
316325 pub fn start ( mut self ) -> Result < PyroscopeAgent < PyroscopeAgentRunning > > {
317326 log:: debug!( target: LOG_TAG , "Starting" ) ;
@@ -327,12 +336,14 @@ impl PyroscopeAgent<PyroscopeAgentReady> {
327336 * running = true ;
328337 drop ( running) ;
329338
339+ // Create a channel to listen for timer signals
330340 let ( tx, rx) = mpsc:: channel ( ) ;
331341 self . timer . attach_listener ( tx. clone ( ) ) ?;
332342 self . tx = Some ( tx) ;
333343
334344 let config = self . config . clone ( ) ;
335345
346+ // Clone SessionManager Sender
336347 let stx = self . session_manager . tx . clone ( ) ;
337348
338349 self . handle = Some ( std:: thread:: spawn ( move || {
@@ -344,7 +355,15 @@ impl PyroscopeAgent<PyroscopeAgentReady> {
344355 log:: trace!( target: LOG_TAG , "Sending session {}" , until) ;
345356
346357 // Generate report from backend
347- let report = backend. lock ( ) ?. as_mut ( ) . unwrap ( ) . report ( ) ?;
358+ let report = backend
359+ . lock ( ) ?
360+ . as_mut ( )
361+ . ok_or_else ( || {
362+ PyroscopeError :: AdHoc (
363+ "PyroscopeAgent - Failed to unwrap backend" . to_string ( ) ,
364+ )
365+ } ) ?
366+ . report ( ) ?;
348367
349368 // Send new Session to SessionManager
350369 stx. send ( SessionSignal :: Session ( Session :: new (
@@ -356,40 +375,32 @@ impl PyroscopeAgent<PyroscopeAgentReady> {
356375 TimerSignal :: Terminate => {
357376 log:: trace!( target: LOG_TAG , "Session Killed" ) ;
358377
378+ // Notify the Stop function
359379 let ( lock, cvar) = & * pair;
360380 let mut running = lock. lock ( ) ?;
361381 * running = false ;
362382 cvar. notify_one ( ) ;
363383
384+ // Kill the internal thread
364385 return Ok ( ( ) ) ;
365386 }
366387 }
367388 }
368389 Ok ( ( ) )
369390 } ) ) ;
370391
371- //let agent_running = PyroscopeAgent {
372- //timer: self.timer,
373- //session_manager: self.session_manager,
374- //tx: self.tx,
375- //handle: self.handle,
376- //running: self.running,
377- //backend: self.backend,
378- //config: self.config,
379- //_state: PhantomData,
380- //};
381-
382392 Ok ( self . transition ( ) )
383393 }
384394}
385395impl PyroscopeAgent < PyroscopeAgentRunning > {
386396 /// Stop the agent. The agent will stop profiling and send a last report to the server.
397+ ///
387398 /// # Example
388399 /// ```ignore
389400 /// let agent = PyroscopeAgent::builder("http://localhost:8080", "my-app").build()?;
390- /// agent.start()?;
401+ /// let agent_running = agent.start()?;
391402 /// // Expensive operation
392- /// agent .stop();
403+ /// let agent_ready = agent_running .stop();
393404 /// ```
394405 pub fn stop ( mut self ) -> Result < PyroscopeAgent < PyroscopeAgentReady > > {
395406 log:: debug!( target: LOG_TAG , "Stopping" ) ;
@@ -411,6 +422,24 @@ impl PyroscopeAgent<PyroscopeAgentRunning> {
411422 Ok ( self . transition ( ) )
412423 }
413424
425+ /// Return a tuple of functions to add and remove tags to the agent across
426+ /// thread boundaries. This function can be called multiple times.
427+ ///
428+ /// # Example
429+ /// ```ignore
430+ /// let agent = PyroscopeAgent::builder("http://localhost:8080", "my-app").build()?;
431+ /// let agent_running = agent.start()?;
432+ /// let (add_tag, remove_tag) = agent_running.tag_wrapper();
433+ /// ```
434+ ///
435+ /// The functions can be later called from any thread.
436+ ///
437+ /// # Example
438+ /// ```ignore
439+ /// add_tag("key".to_string(), "value".to_string());
440+ /// // some computation
441+ /// remove_tag("key".to_string(), "value".to_string());
442+ /// ```
414443 pub fn tag_wrapper (
415444 & self ,
416445 ) -> (
@@ -425,42 +454,64 @@ impl PyroscopeAgent<PyroscopeAgentRunning> {
425454 let thread_id = crate :: utils:: pthread_self ( ) ?;
426455 let rule = Rule :: ThreadTag ( thread_id, Tag :: new ( key, value) ) ;
427456 let backend = backend_add. lock ( ) ?;
428- backend. as_ref ( ) . unwrap ( ) . add_rule ( rule) ?;
457+ backend
458+ . as_ref ( )
459+ . ok_or_else ( || {
460+ PyroscopeError :: AdHoc (
461+ "PyroscopeAgent - Failed to unwrap backend" . to_string ( ) ,
462+ )
463+ } ) ?
464+ . add_rule ( rule) ?;
429465
430466 Ok ( ( ) )
431467 } ,
432468 move |key, value| {
433469 let thread_id = crate :: utils:: pthread_self ( ) ?;
434470 let rule = Rule :: ThreadTag ( thread_id, Tag :: new ( key, value) ) ;
435471 let backend = backend_remove. lock ( ) ?;
436- backend. as_ref ( ) . unwrap ( ) . remove_rule ( rule) ?;
472+ backend
473+ . as_ref ( )
474+ . ok_or_else ( || {
475+ PyroscopeError :: AdHoc (
476+ "PyroscopeAgent - Failed to unwrap backend" . to_string ( ) ,
477+ )
478+ } ) ?
479+ . remove_rule ( rule) ?;
437480
438481 Ok ( ( ) )
439482 } ,
440483 )
441484 }
442485
486+ /// Add a global Tag rule to the backend Ruleset. For tagging, it's
487+ /// recommended to use the `tag_wrapper` function.
443488 pub fn add_global_tag ( & self , tag : Tag ) -> Result < ( ) > {
444489 let rule = Rule :: GlobalTag ( tag) ;
445490 self . backend . add_rule ( rule) ?;
446491
447492 Ok ( ( ) )
448493 }
449494
495+ /// Remove a global Tag rule from the backend Ruleset. For tagging, it's
496+ /// recommended to use the `tag_wrapper` function.
450497 pub fn remove_global_tag ( & self , tag : Tag ) -> Result < ( ) > {
451498 let rule = Rule :: GlobalTag ( tag) ;
452499 self . backend . remove_rule ( rule) ?;
453500
454501 Ok ( ( ) )
455502 }
456503
504+ /// Add a thread Tag rule to the backend Ruleset. For tagging, it's
505+ /// recommended to use the `tag_wrapper` function.
457506 pub fn add_thread_tag ( & self , thread_id : u64 , tag : Tag ) -> Result < ( ) > {
458507 let rule = Rule :: ThreadTag ( thread_id, tag) ;
459508 self . backend . add_rule ( rule) ?;
460509
461510 Ok ( ( ) )
462511 }
463512
513+ /// Remove a thread Tag rule from the backend Ruleset. For tagging, it's
514+ /// recommended to use the `tag_wrapper` function.
464515 pub fn remove_thread_tag ( & self , thread_id : u64 , tag : Tag ) -> Result < ( ) > {
465516 let rule = Rule :: ThreadTag ( thread_id, tag) ;
466517 self . backend . remove_rule ( rule) ?;
0 commit comments