Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions examples/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright 2021 Developers of Pyroscope.

// Licensed under the Apache License, Version 2.0 <LICENSE or
// https://www.apache.org/licenses/LICENSE-2.0>. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate pyroscope;

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();

// This example should fail and return an error.
println!("This example should fail and return an error.");
println!("Run this with: RUST_BACKTRACE=1 cargo run --example error");

let mut agent = PyroscopeAgent::builder("http://invalid_url", "example.error")
.build()?;
// Start Agent
agent.start()?;

let _result = fibonacci(47);

// Stop Agent
agent.stop()?;

drop(agent);

Ok(())
}
21 changes: 8 additions & 13 deletions src/backends/pprof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use pprof::{ProfilerGuard, ProfilerGuardBuilder, Report};

use crate::backends::Backend;
use crate::backends::State;
use crate::PyroscopeError;
use crate::Result;

#[derive(Default)]
Expand All @@ -31,9 +32,7 @@ impl Backend for Pprof<'_> {
fn initialize(&mut self, sample_rate: i32) -> Result<()> {
// Check if Backend is Uninitialized
if self.state != State::Uninitialized {
return Err(crate::error::PyroscopeError {
msg: String::from("Pprof Backend is already Initialized"),
});
return Err(PyroscopeError::new("Pprof Backend is already Initialized"));
}

// Construct a ProfilerGuardBuilder
Expand All @@ -50,9 +49,7 @@ impl Backend for Pprof<'_> {
fn start(&mut self) -> Result<()> {
// Check if Backend is Ready
if self.state != State::Ready {
return Err(crate::error::PyroscopeError {
msg: String::from("Pprof Backend is not Ready"),
});
return Err(PyroscopeError::new("Pprof Backend is not Ready"));
}

self.guard = Some(self.inner_builder.as_ref().unwrap().clone().build()?);
Expand All @@ -66,9 +63,7 @@ impl Backend for Pprof<'_> {
fn stop(&mut self) -> Result<()> {
// Check if Backend is Running
if self.state != State::Running {
return Err(crate::error::PyroscopeError {
msg: String::from("Pprof Backend is not Running"),
});
return Err(PyroscopeError::new("Pprof Backend is not Running"));
}

// drop the guard
Expand All @@ -83,9 +78,7 @@ impl Backend for Pprof<'_> {
fn report(&mut self) -> Result<Vec<u8>> {
// Check if Backend is Running
if self.state != State::Running {
return Err(crate::error::PyroscopeError {
msg: String::from("Pprof Backend is not Running"),
});
return Err(PyroscopeError::new("Pprof Backend is not Running"));
}

let mut buffer = Vec::new();
Expand All @@ -102,7 +95,9 @@ impl Backend for Pprof<'_> {

// Copyright: https://github.com/YangKeao
fn fold<W>(report: &Report, with_thread_name: bool, mut writer: W) -> Result<()>
where W: std::io::Write {
where
W: std::io::Write,
{
for (key, value) in report.data.iter() {
if with_thread_name {
if !key.thread_name.is_empty() {
Expand Down
52 changes: 43 additions & 9 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ use thiserror::Error;
pub type Result<T> = std::result::Result<T, PyroscopeError>;

/// Error type of Pyroscope
#[derive(Error, Debug, PartialEq)]
#[derive(Error, Debug)]
pub struct PyroscopeError {
pub msg: String,
source: Option<Box<dyn std::error::Error + Send + Sync>>,
}

impl fmt::Display for PyroscopeError {
Expand All @@ -22,50 +23,83 @@ impl fmt::Display for PyroscopeError {
}
}

impl Default for PyroscopeError {
fn default() -> Self {
PyroscopeError {
msg: "".to_string(),
source: None,
}
}
}

impl PyroscopeError {
/// Create a new instance of PyroscopeError
pub fn new(msg: &str) -> Self {
PyroscopeError {
msg: msg.to_string(),
source: None,
}
}

/// Create a new instance of PyroscopeError with source
pub fn new_with_source(msg: &str, source: Box<dyn std::error::Error + Send + Sync>) -> Self {
PyroscopeError {
msg: msg.to_string(),
source: Some(source),
}
}
}

impl From<reqwest::Error> for PyroscopeError {
fn from(_err: reqwest::Error) -> Self {
fn from(err: reqwest::Error) -> Self {
PyroscopeError {
msg: String::from("reqwest Error"),
source: Some(Box::new(err)),
}
}
}

impl From<pprof::Error> for PyroscopeError {
fn from(_err: pprof::Error) -> Self {
fn from(err: pprof::Error) -> Self {
PyroscopeError {
msg: String::from("pprof Error"),
source: Some(Box::new(err)),
}
}
}

impl From<std::time::SystemTimeError> for PyroscopeError {
fn from(_err: std::time::SystemTimeError) -> Self {
fn from(err: std::time::SystemTimeError) -> Self {
PyroscopeError {
msg: String::from("SystemTime Error"),
source: Some(Box::new(err)),
}
}
}

impl From<std::io::Error> for PyroscopeError {
fn from(_err: std::io::Error) -> Self {
fn from(err: std::io::Error) -> Self {
PyroscopeError {
msg: String::from("IO Error"),
source: Some(Box::new(err)),
}
}
}

impl<T> From<std::sync::PoisonError<T>> for PyroscopeError {
fn from(_err: std::sync::PoisonError<T>) -> Self {
PyroscopeError {
msg: String::from("Poison/Mutex Error"),
msg: String::from("Poison Error"),
source: None,
}
}
}

impl<T> From<std::sync::mpsc::SendError<T>> for PyroscopeError {
fn from(_err: std::sync::mpsc::SendError<T>) -> Self {
impl<T: 'static + Send + Sync> From<std::sync::mpsc::SendError<T>> for PyroscopeError {
fn from(err: std::sync::mpsc::SendError<T>) -> Self {
PyroscopeError {
msg: String::from("mpsc Send Error"),
msg: String::from("SendError Error"),
source: Some(Box::new(err)),
}
}
}
67 changes: 33 additions & 34 deletions src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ impl SessionManager {
}
SessionSignal::Kill => {
// Kill the session manager
return Ok(());
log::trace!("SessionManager - Kill signal received");
return Ok(());
}
}
}
Expand Down Expand Up @@ -89,7 +89,7 @@ pub struct Session {

impl Session {
/// Create a new Session
/// # Example
/// # Example
/// ```ignore
/// let config = PyroscopeConfig::new("https://localhost:8080", "my-app");
/// let report = vec![1, 2, 3];
Expand Down Expand Up @@ -131,39 +131,38 @@ impl Session {
pub fn send(self) -> Result<()> {
log::info!("Session - Sending Session");

let _handle: JoinHandle<Result<()>> = thread::spawn(move || {
if self.report.is_empty() {
return Ok(());
}

let client = reqwest::blocking::Client::new();
// TODO: handle the error of this request

// Clone URL
let url = self.config.url.clone();

// Merge application name with Tags
let application_name = merge_tags_with_app_name(
self.config.application_name.clone(),
self.config.tags.clone(),
)?;

client
.post(format!("{}/ingest", url))
.header("Content-Type", "binary/octet-stream")
.query(&[
("name", application_name.as_str()),
("from", &format!("{}", self.from)),
("until", &format!("{}", self.until)),
("format", "folded"),
("sampleRate", &format!("{}", self.config.sample_rate)),
("spyName", "pprof-rs"),
])
.body(self.report)
.send()?;

// Check if the report is empty
if self.report.is_empty() {
return Ok(());
});
}

// Create a new client
let client = reqwest::blocking::Client::new();

// Clone URL
let url = self.config.url.clone();

// Merge application name with Tags
let application_name = merge_tags_with_app_name(
self.config.application_name.clone(),
self.config.tags.clone(),
)?;

// Create and send the request
client
.post(format!("{}/ingest", url))
.header("Content-Type", "binary/octet-stream")
.query(&[
("name", application_name.as_str()),
("from", &format!("{}", self.from)),
("until", &format!("{}", self.until)),
("format", "folded"),
("sampleRate", &format!("{}", self.config.sample_rate)),
("spyName", "pyroscope-rs"),
])
.body(self.report)
.timeout(std::time::Duration::from_secs(10))
.send()?;

Ok(())
}
Expand Down