From d4d0dfe9822d16f28c7289163d6cc83ab8965328 Mon Sep 17 00:00:00 2001 From: Abid Omar Date: Wed, 19 Jan 2022 19:54:40 +0100 Subject: [PATCH 1/6] refactor(example): update basic example --- examples/basic.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/examples/basic.rs b/examples/basic.rs index ca685565..1c4c8349 100644 --- a/examples/basic.rs +++ b/examples/basic.rs @@ -20,13 +20,34 @@ fn main() -> Result<()> { .tags(&[("TagA", "ValueA"), ("TagB", "ValueB")]) .build()?; + // Show start time + let start = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap() + .as_secs(); + println!("Start Time: {}", start); + // Start Agent agent.start()?; let _result = fibonacci(47); + // Show stop time + let stop = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap() + .as_secs(); + println!("Stop Time: {}", stop); + // Stop Agent agent.stop()?; + // Show program exit time + let exit = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap() + .as_secs(); + println!("Exit Time: {}", exit); + Ok(()) } From 3572000ac6acb3f76fe20ee5a12d6544aae72676 Mon Sep 17 00:00:00 2001 From: Abid Omar Date: Wed, 19 Jan 2022 19:57:30 +0100 Subject: [PATCH 2/6] refactor(example): update basic example --- examples/basic.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/basic.rs b/examples/basic.rs index 1c4c8349..b11db348 100644 --- a/examples/basic.rs +++ b/examples/basic.rs @@ -42,6 +42,8 @@ fn main() -> Result<()> { // Stop Agent agent.stop()?; + drop(agent); + // Show program exit time let exit = std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) From 6dfe69858650502eea77b2fbd6e92d13553e51a0 Mon Sep 17 00:00:00 2001 From: Abid Omar Date: Thu, 20 Jan 2022 19:43:14 +0100 Subject: [PATCH 3/6] imp(session): implementation for SessionManager --- src/pyroscope.rs | 26 +++++++++++++++++++++++--- src/session.rs | 37 ++++++++++++++++++++++++++++++++++++- 2 files changed, 59 insertions(+), 4 deletions(-) diff --git a/src/pyroscope.rs b/src/pyroscope.rs index 8538d85d..49bd0886 100644 --- a/src/pyroscope.rs +++ b/src/pyroscope.rs @@ -15,6 +15,7 @@ use crate::backends::pprof::Pprof; use crate::backends::Backend; use crate::error::Result; use crate::session::Session; +use crate::session::SessionManager; use crate::timer::Timer; /// Represent PyroscopeAgent Configuration @@ -93,7 +94,9 @@ impl PyroscopeAgentBuilder { /// Set the agent backend. Default is pprof. pub fn backend(self, backend: T) -> Self - where T: Backend { + where + T: Backend, + { Self { backend: Arc::new(Mutex::new(backend)), ..self @@ -125,11 +128,15 @@ impl PyroscopeAgentBuilder { // Start Timer let timer = Timer::default().initialize()?; + // Start the SessionManager + let session_manager = SessionManager::new()?; + // Return PyroscopeAgent Ok(PyroscopeAgent { backend: self.backend, config: self.config, timer, + session_manager, tx: None, handle: None, running: Arc::new((Mutex::new(false), Condvar::new())), @@ -142,6 +149,7 @@ impl PyroscopeAgentBuilder { pub struct PyroscopeAgent { pub backend: Arc>, timer: Timer, + session_manager: SessionManager, tx: Option>, handle: Option>>, running: Arc<(Mutex, Condvar)>, @@ -156,6 +164,16 @@ impl Drop for PyroscopeAgent { // Stop Timer self.timer.drop_listeners().unwrap(); // Drop listeners self.timer.handle.take().unwrap().join().unwrap().unwrap(); // Wait for the Timer thread to finish + + // Wait for main thread to finish + self.handle.take().unwrap().join().unwrap().unwrap(); + self.session_manager + .handle + .take() + .unwrap() + .join() + .unwrap() + .unwrap(); } } @@ -188,11 +206,13 @@ impl PyroscopeAgent { let config = self.config.clone(); + let stx = self.session_manager.tx.clone(); + self.handle = Some(std::thread::spawn(move || { while let Ok(time) = rx.recv() { let report = backend.lock()?.report()?; - // start a new session - Session::new(time, config.clone(), report)?.send()?; + // Send new Session to SessionManager + stx.send(Session::new(time, config.clone(), report)?)?; if time == 0 { let (lock, cvar) = &*pair; diff --git a/src/session.rs b/src/session.rs index 231d59ae..2bc72601 100644 --- a/src/session.rs +++ b/src/session.rs @@ -4,12 +4,47 @@ // https://www.apache.org/licenses/LICENSE-2.0>. This file may not be copied, modified, or distributed // except according to those terms. -use std::{thread, thread::JoinHandle}; +use std::{ + sync::mpsc::{sync_channel, Receiver, SyncSender}, + thread, + thread::JoinHandle, +}; use crate::pyroscope::PyroscopeConfig; use crate::utils::merge_tags_with_app_name; use crate::Result; +/// SessionManager +#[derive(Debug)] +pub struct SessionManager { + pub handle: Option>>, + pub tx: SyncSender, +} + +impl SessionManager { + /// Create a new SessionManager + pub fn new() -> Result { + // Create a channel for sending and receiving sessions + let (tx, rx): (SyncSender, Receiver) = sync_channel(10); + + // Create a thread for the SessionManager + let handle = Some(thread::spawn(move || { + while let Ok(session) = rx.recv() { + session.send()?; + } + Ok(()) + })); + + Ok(SessionManager { handle, tx }) + } + + /// Push a new session into the SessionManager + pub fn push(&self, session: Session) -> Result<()> { + self.tx.send(session)?; + Ok(()) + } +} + /// Pyroscope Session #[derive(Clone, Debug)] pub struct Session { From 11111154afeba31a7b831d846a36d938b864cdde Mon Sep 17 00:00:00 2001 From: Abid Omar Date: Thu, 20 Jan 2022 20:04:08 +0100 Subject: [PATCH 4/6] imp(session): kill SessionManager on Agent drop --- src/pyroscope.rs | 14 +++++++++++--- src/session.rs | 26 +++++++++++++++++++++----- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/pyroscope.rs b/src/pyroscope.rs index 49bd0886..c1756a20 100644 --- a/src/pyroscope.rs +++ b/src/pyroscope.rs @@ -16,6 +16,7 @@ use crate::backends::Backend; use crate::error::Result; use crate::session::Session; use crate::session::SessionManager; +use crate::session::SessionSignal; use crate::timer::Timer; /// Represent PyroscopeAgent Configuration @@ -165,8 +166,8 @@ impl Drop for PyroscopeAgent { self.timer.drop_listeners().unwrap(); // Drop listeners self.timer.handle.take().unwrap().join().unwrap().unwrap(); // Wait for the Timer thread to finish - // Wait for main thread to finish - self.handle.take().unwrap().join().unwrap().unwrap(); + // Stop the SessionManager + self.session_manager.push(SessionSignal::Kill).unwrap(); self.session_manager .handle .take() @@ -174,6 +175,9 @@ impl Drop for PyroscopeAgent { .join() .unwrap() .unwrap(); + + // Wait for main thread to finish + self.handle.take().unwrap().join().unwrap().unwrap(); } } @@ -212,7 +216,11 @@ impl PyroscopeAgent { while let Ok(time) = rx.recv() { let report = backend.lock()?.report()?; // Send new Session to SessionManager - stx.send(Session::new(time, config.clone(), report)?)?; + stx.send(SessionSignal::Session(Session::new( + time, + config.clone(), + report, + )?))?; if time == 0 { let (lock, cvar) = &*pair; diff --git a/src/session.rs b/src/session.rs index 2bc72601..783fc39e 100644 --- a/src/session.rs +++ b/src/session.rs @@ -14,23 +14,39 @@ use crate::pyroscope::PyroscopeConfig; use crate::utils::merge_tags_with_app_name; use crate::Result; +/// Session Signal +#[derive(Debug)] +pub enum SessionSignal { + Session(Session), + Kill, +} + /// SessionManager #[derive(Debug)] pub struct SessionManager { pub handle: Option>>, - pub tx: SyncSender, + pub tx: SyncSender, } impl SessionManager { /// Create a new SessionManager pub fn new() -> Result { // Create a channel for sending and receiving sessions - let (tx, rx): (SyncSender, Receiver) = sync_channel(10); + let (tx, rx): (SyncSender, Receiver) = sync_channel(10); // Create a thread for the SessionManager let handle = Some(thread::spawn(move || { - while let Ok(session) = rx.recv() { - session.send()?; + while let Ok(signal) = rx.recv() { + match signal { + SessionSignal::Session(session) => { + // Send the session + session.send()?; + } + SessionSignal::Kill => { + // Kill the session manager + return Ok(()); + } + } } Ok(()) })); @@ -39,7 +55,7 @@ impl SessionManager { } /// Push a new session into the SessionManager - pub fn push(&self, session: Session) -> Result<()> { + pub fn push(&self, session: SessionSignal) -> Result<()> { self.tx.send(session)?; Ok(()) } From 47385f37a257bb91d2cdf07a562ccfba75751902 Mon Sep 17 00:00:00 2001 From: Abid Omar Date: Thu, 20 Jan 2022 21:24:05 +0100 Subject: [PATCH 5/6] imp(logging): initial logging implementation --- Cargo.toml | 2 ++ src/pyroscope.rs | 23 +++++++++++++++++++++++ src/session.rs | 12 ++++++++++++ 3 files changed, 37 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index da2db602..4285108b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,12 +15,14 @@ readme = "README.md" [dependencies] thiserror ="1.0" +log = "0.4" reqwest = {version = "0.11", features = ["blocking"]} pprof = { version="0.6.2"} libc = "^0.2.66" [dev-dependencies] tokio = { version = "1.13", features = ["full"] } +pretty_env_logger = "0.4.0" [profile.dev] opt-level=0 diff --git a/src/pyroscope.rs b/src/pyroscope.rs index c1756a20..06b6bb9d 100644 --- a/src/pyroscope.rs +++ b/src/pyroscope.rs @@ -125,12 +125,15 @@ impl PyroscopeAgentBuilder { // Initiliaze the backend let backend = Arc::clone(&self.backend); backend.lock()?.initialize(self.config.sample_rate)?; + log::trace!("PyroscopeAgent - Backend initialized"); // Start Timer let timer = Timer::default().initialize()?; + log::trace!("PyroscopeAgent - Timer initialized"); // Start the SessionManager let session_manager = SessionManager::new()?; + log::trace!("PyroscopeAgent - SessionManager initialized"); // Return PyroscopeAgent Ok(PyroscopeAgent { @@ -162,12 +165,17 @@ pub struct PyroscopeAgent { impl Drop for PyroscopeAgent { /// Properly shutdown the agent. fn drop(&mut self) { + log::debug!("PyroscopeAgent::drop()"); + // Stop Timer self.timer.drop_listeners().unwrap(); // Drop listeners + log::trace!("PyroscopeAgent - Dropped timer listeners"); self.timer.handle.take().unwrap().join().unwrap().unwrap(); // Wait for the Timer thread to finish + log::trace!("PyroscopeAgent - Dropped timer thread"); // Stop the SessionManager self.session_manager.push(SessionSignal::Kill).unwrap(); + log::trace!("PyroscopeAgent - Sent kill signal to SessionManager"); self.session_manager .handle .take() @@ -175,9 +183,11 @@ impl Drop for PyroscopeAgent { .join() .unwrap() .unwrap(); + log::trace!("PyroscopeAgent - Dropped SessionManager thread"); // Wait for main thread to finish self.handle.take().unwrap().join().unwrap().unwrap(); + log::trace!("PyroscopeAgent - Dropped main thread"); } } @@ -190,6 +200,8 @@ impl PyroscopeAgent { /// Start profiling and sending data. The agent will keep running until stopped. pub fn start(&mut self) -> Result<()> { + log::debug!("PyroscopeAgent - Starting"); + // Create a clone of Backend let backend = Arc::clone(&self.backend); // Call start() @@ -213,8 +225,14 @@ impl PyroscopeAgent { let stx = self.session_manager.tx.clone(); self.handle = Some(std::thread::spawn(move || { + log::trace!("PyroscopeAgent - Main Thread started"); + while let Ok(time) = rx.recv() { + log::trace!("PyroscopeAgent - Sending session {}", time); + + // Generate report from backend let report = backend.lock()?.report()?; + // Send new Session to SessionManager stx.send(SessionSignal::Session(Session::new( time, @@ -223,6 +241,8 @@ impl PyroscopeAgent { )?))?; if time == 0 { + log::trace!("PyroscopeAgent - Session Killed"); + let (lock, cvar) = &*pair; let mut running = lock.lock()?; *running = false; @@ -240,6 +260,7 @@ impl PyroscopeAgent { /// Stop the agent. pub fn stop(&mut self) -> Result<()> { + log::debug!("PyroscopeAgent - Stopping"); // get tx and send termination signal self.tx.take().unwrap().send(0)?; @@ -258,6 +279,7 @@ impl PyroscopeAgent { /// Add tags. This will restart the agent. pub fn add_tags(&mut self, tags: &[(&str, &str)]) -> Result<()> { + log::debug!("PyroscopeAgent - Adding tags"); // Stop Agent self.stop()?; @@ -279,6 +301,7 @@ impl PyroscopeAgent { /// Remove tags. This will restart the agent. pub fn remove_tags(&mut self, tags: &[&str]) -> Result<()> { + log::debug!("PyroscopeAgent - Removing tags"); // Stop Agent self.stop()?; diff --git a/src/session.rs b/src/session.rs index 783fc39e..a4f8caa2 100644 --- a/src/session.rs +++ b/src/session.rs @@ -31,20 +31,25 @@ pub struct SessionManager { impl SessionManager { /// Create a new SessionManager pub fn new() -> Result { + log::info!("SessionManager - Creating SessionManager"); + // Create a channel for sending and receiving sessions let (tx, rx): (SyncSender, Receiver) = sync_channel(10); // Create a thread for the SessionManager let handle = Some(thread::spawn(move || { + log::trace!("SessionManager - SessionManager thread started"); while let Ok(signal) = rx.recv() { match signal { SessionSignal::Session(session) => { // Send the session session.send()?; + log::trace!("SessionManager - Session sent"); } SessionSignal::Kill => { // Kill the session manager return Ok(()); + log::trace!("SessionManager - Kill signal received"); } } } @@ -56,7 +61,11 @@ impl SessionManager { /// Push a new session into the SessionManager pub fn push(&self, session: SessionSignal) -> Result<()> { + // Push the session into the SessionManager self.tx.send(session)?; + + log::trace!("SessionManager - SessionSignal pushed"); + Ok(()) } } @@ -72,6 +81,7 @@ pub struct Session { impl Session { pub fn new(mut until: u64, config: PyroscopeConfig, report: Vec) -> Result { + log::info!("Session - Creating Session"); // Session interrupted (0 signal), determine the time if until == 0 { let now = std::time::SystemTime::now() @@ -94,6 +104,8 @@ impl Session { } pub fn send(self) -> Result<()> { + log::info!("Session - Sending Session"); + let _handle: JoinHandle> = thread::spawn(move || { if self.report.is_empty() { return Ok(()); From c9d7438e5d4c0c3a4b96f4bf6c05e5b267e40f34 Mon Sep 17 00:00:00 2001 From: Abid Omar Date: Thu, 20 Jan 2022 21:30:03 +0100 Subject: [PATCH 6/6] imp(examples): add with-logger example --- examples/with-logger.rs | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 examples/with-logger.rs diff --git a/examples/with-logger.rs b/examples/with-logger.rs new file mode 100644 index 00000000..a5406fc8 --- /dev/null +++ b/examples/with-logger.rs @@ -0,0 +1,41 @@ +// Copyright 2021 Developers of Pyroscope. + +// Licensed under the Apache License, Version 2.0 . This file may not be copied, modified, or distributed +// except according to those terms. + +extern crate pyroscope; + +use log::{debug, error, info, trace, warn}; + +use pyroscope::{PyroscopeAgent, Result}; + +fn fibonacci(n: u64) -> u64 { + match n { + 0 | 1 => 1, + n => fibonacci(n - 1) + fibonacci(n - 2), + } +} + +fn main() -> Result<()> { + // Force rustc to display the log messages in the console. + std::env::set_var("RUST_LOG", "trace"); + + // Initialize the logger. + pretty_env_logger::init_timed(); + + info!("With Logger example"); + + // Create a new agent. + let mut agent = PyroscopeAgent::builder("http://localhost:4040", "example.logger").build()?; + + // Start Agent + agent.start()?; + + let _result = fibonacci(47); + + // Stop Agent + agent.stop()?; + + Ok(()) +}