11use std:: {
22 collections:: HashMap ,
3+ marker:: PhantomData ,
34 sync:: {
45 mpsc:: { self , Sender } ,
56 Arc , Condvar , Mutex ,
@@ -152,7 +153,7 @@ impl PyroscopeAgentBuilder {
152153 }
153154
154155 /// Initialize the backend, timer and return a PyroscopeAgent object.
155- pub fn build ( self ) -> Result < PyroscopeAgent > {
156+ pub fn build ( self ) -> Result < PyroscopeAgent < PyroscopeAgentReady > > {
156157 // Get the backend
157158 //let backend = Arc::clone(&self.backend);
158159
@@ -191,13 +192,22 @@ impl PyroscopeAgentBuilder {
191192 tx : None ,
192193 handle : None ,
193194 running : Arc :: new ( ( Mutex :: new ( false ) , Condvar :: new ( ) ) ) ,
195+ _state : PhantomData ,
194196 } )
195197 }
196198}
197199
200+ pub trait PyroscopeAgentState { }
201+ pub struct PyroscopeAgentBare ;
202+ pub struct PyroscopeAgentReady ;
203+ pub struct PyroscopeAgentRunning ;
204+ impl PyroscopeAgentState for PyroscopeAgentBare { }
205+ impl PyroscopeAgentState for PyroscopeAgentReady { }
206+ impl PyroscopeAgentState for PyroscopeAgentRunning { }
207+
198208/// PyroscopeAgent is the main object of the library. It is used to start and stop the profiler, schedule the timer, and send the profiler data to the server.
199209#[ derive( Debug ) ]
200- pub struct PyroscopeAgent {
210+ pub struct PyroscopeAgent < S : PyroscopeAgentState > {
201211 timer : Timer ,
202212 session_manager : SessionManager ,
203213 tx : Option < Sender < TimerSignal > > ,
@@ -208,12 +218,13 @@ pub struct PyroscopeAgent {
208218 pub backend : BackendImpl < BackendReady > ,
209219 /// Configuration Object
210220 pub config : PyroscopeConfig ,
221+ _state : PhantomData < S > ,
211222}
212223
213224/// Gracefully stop the profiler.
214- impl Drop for PyroscopeAgent {
225+ impl < S : PyroscopeAgentState > PyroscopeAgent < S > {
215226 /// Properly shutdown the agent.
216- fn drop ( & mut self ) {
227+ pub fn shutdown ( mut self ) {
217228 log:: debug!( target: LOG_TAG , "PyroscopeAgent::drop()" ) ;
218229
219230 // Drop Timer listeners
@@ -258,7 +269,7 @@ impl Drop for PyroscopeAgent {
258269 }
259270}
260271
261- impl PyroscopeAgent {
272+ impl PyroscopeAgent < PyroscopeAgentBare > {
262273 /// Short-hand for PyroscopeAgentBuilder::build(). This is a convenience method.
263274 ///
264275 /// # Example
@@ -269,14 +280,16 @@ impl PyroscopeAgent {
269280 // Build PyroscopeAgent
270281 PyroscopeAgentBuilder :: new ( url, application_name)
271282 }
283+ }
272284
285+ impl PyroscopeAgent < PyroscopeAgentReady > {
273286 /// Start profiling and sending data. The agent will keep running until stopped. The agent will send data to the server every 10s secondy.
274287 /// # Example
275288 /// ```ignore
276289 /// let agent = PyroscopeAgent::builder("http://localhost:8080", "my-app").build()?;
277290 /// agent.start()?;
278291 /// ```
279- pub fn start ( & mut self ) -> Result < ( ) > {
292+ pub fn start ( mut self ) -> Result < PyroscopeAgent < PyroscopeAgentRunning > > {
280293 log:: debug!( target: LOG_TAG , "Starting" ) ;
281294
282295 // Create a clone of Backend
@@ -331,9 +344,21 @@ impl PyroscopeAgent {
331344 Ok ( ( ) )
332345 } ) ) ;
333346
334- Ok ( ( ) )
347+ let agent_running = PyroscopeAgent {
348+ timer : self . timer ,
349+ session_manager : self . session_manager ,
350+ tx : self . tx ,
351+ handle : self . handle ,
352+ running : self . running ,
353+ backend : self . backend ,
354+ config : self . config ,
355+ _state : PhantomData ,
356+ } ;
357+
358+ Ok ( agent_running)
335359 }
336-
360+ }
361+ impl PyroscopeAgent < PyroscopeAgentRunning > {
337362 /// Stop the agent. The agent will stop profiling and send a last report to the server.
338363 /// # Example
339364 /// ```ignore
@@ -342,7 +367,7 @@ impl PyroscopeAgent {
342367 /// // Expensive operation
343368 /// agent.stop();
344369 /// ```
345- pub fn stop ( & mut self ) -> Result < ( ) > {
370+ pub fn stop ( mut self ) -> Result < PyroscopeAgent < PyroscopeAgentReady > > {
346371 log:: debug!( target: LOG_TAG , "Stopping" ) ;
347372 // get tx and send termination signal
348373 if let Some ( sender) = self . tx . take ( ) {
@@ -361,43 +386,18 @@ impl PyroscopeAgent {
361386 // Create a clone of Backend
362387 //let backend = Arc::clone(&self.backend);
363388
364- Ok ( ( ) )
365- }
366-
367- /// Add tags. This will restart the agent.
368- /// # Example
369- /// ```ignore
370- /// let agent = PyroscopeAgent::builder("http://localhost:8080", "my-app").build()?;
371- /// agent.start()?;
372- /// // Expensive operation
373- /// agent.add_tags(vec!["tag", "value"])?;
374- /// // Tagged operation
375- /// agent.stop()?;
376- /// ```
377- pub fn add_tags ( & mut self , tags : & [ ( & str , & str ) ] ) -> Result < ( ) > {
378- log:: debug!( target: LOG_TAG , "Adding tags" ) ;
379- // Check that tags are not empty
380- if tags. is_empty ( ) {
381- return Ok ( ( ) ) ;
382- }
383-
384- // Stop Agent
385- self . stop ( ) ?;
386-
387- // Convert &[(&str, &str)] to HashMap(String, String)
388- let tags_hashmap: HashMap < String , String > = tags
389- . to_owned ( )
390- . iter ( )
391- . cloned ( )
392- . map ( |( a, b) | ( a. to_owned ( ) , b. to_owned ( ) ) )
393- . collect ( ) ;
394-
395- self . config . tags . extend ( tags_hashmap) ;
396-
397- // Restart Agent
398- self . start ( ) ?;
399-
400- Ok ( ( ) )
389+ let agent_running = PyroscopeAgent {
390+ timer : self . timer ,
391+ session_manager : self . session_manager ,
392+ tx : self . tx ,
393+ handle : self . handle ,
394+ running : self . running ,
395+ backend : self . backend ,
396+ config : self . config ,
397+ _state : PhantomData ,
398+ } ;
399+
400+ Ok ( agent_running)
401401 }
402402
403403 pub fn tag_wrapper (
@@ -429,6 +429,7 @@ impl PyroscopeAgent {
429429 )
430430 }
431431
432+ // TODO: change &mut self to &self
432433 pub fn add_global_tag ( & mut self , tag : Tag ) -> Result < ( ) > {
433434 let rule = Rule :: GlobalTag ( tag) ;
434435 self . backend . add_rule ( rule) ?;
@@ -456,44 +457,4 @@ impl PyroscopeAgent {
456457
457458 Ok ( ( ) )
458459 }
459-
460- /// Remove tags. This will restart the agent.
461- /// # Example
462- /// ```ignore
463- /// # use pyroscope::*;
464- /// # use std::result;
465- /// # fn main() -> result::Result<(), error::PyroscopeError> {
466- /// let agent = PyroscopeAgent::builder("http://localhost:8080", "my-app")
467- /// .tags(vec![("tag", "value")])
468- /// .build()?;
469- /// agent.start()?;
470- /// // Expensive operation
471- /// agent.remove_tags(vec!["tag"])?;
472- /// // Un-Tagged operation
473- /// agent.stop()?;
474- /// # Ok(())
475- /// # }
476- /// ```
477- pub fn remove_tags ( & mut self , tags : & [ & str ] ) -> Result < ( ) > {
478- log:: debug!( target: LOG_TAG , "Removing tags" ) ;
479-
480- // Check that tags are not empty
481- if tags. is_empty ( ) {
482- return Ok ( ( ) ) ;
483- }
484-
485- // Stop Agent
486- self . stop ( ) ?;
487-
488- // Iterate through every tag
489- tags. iter ( ) . for_each ( |key| {
490- // Remove tag
491- self . config . tags . remove ( key. to_owned ( ) ) ;
492- } ) ;
493-
494- // Restart Agent
495- self . start ( ) ?;
496-
497- Ok ( ( ) )
498- }
499460}
0 commit comments