Skip to content

Commit

Permalink
ref(api): Send events using EnvelopesApi instead of sentry-core (#2083)
Browse files Browse the repository at this point in the history
Use sentry-cli's envelopes client, EnvelopesApi, instead of the sentry-core Client's capture_event method. This change enables debug logging and non-zero exit codes for transmission failures, like the other commands.

Fixes GH-2060
  • Loading branch information
elramen authored Jun 7, 2024
1 parent 787a388 commit 0a42b4c
Show file tree
Hide file tree
Showing 10 changed files with 60 additions and 82 deletions.
38 changes: 14 additions & 24 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,11 @@ regex = "1.7.3"
runas = "1.0.0"
rust-ini = "0.18.0"
semver = "1.0.16"
sentry = { version = "0.33.0", default-features = false, features = [
sentry = { version = "0.34.0", default-features = false, features = [
"anyhow",
"curl",
"contexts",
"UNSTABLE_metrics",
"metrics",
] }
serde = { version = "1.0.152", features = ["derive"] }
serde_json = "1.0.93"
Expand Down
3 changes: 2 additions & 1 deletion src/api/envelopes_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ impl EnvelopesApi {
.map_err(|_| ApiErrorKind::DsnMissing.into())
}

pub fn send_envelope(&self, envelope: Envelope) -> ApiResult<ApiResponse> {
pub fn send_envelope(&self, envelope: impl Into<Envelope>) -> ApiResult<ApiResponse> {
let mut body = vec![];
envelope
.into()
.to_writer(&mut body)
.map_err(|e| ApiError::with_source(ApiErrorKind::CannotSerializeEnvelope, e))?;
let url = self.dsn.envelope_api_url();
Expand Down
5 changes: 3 additions & 2 deletions src/commands/bash_hook.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ use sentry::protocol::{Event, Exception, Frame, Stacktrace, User, Value};
use username::get_user_name;
use uuid::Uuid;

use crate::commands::send_event;
use crate::config::Config;
use crate::utils::event::{attach_logfile, get_sdk_info, with_sentry_client};
use crate::utils::event::{attach_logfile, get_sdk_info};
use crate::utils::releases::detect_release_name;

const BASH_SCRIPT: &str = include_str!("../bashsupport.sh");
Expand Down Expand Up @@ -198,7 +199,7 @@ fn send_event(
..Default::default()
});

let id = with_sentry_client(config.get_dsn()?, |c| c.capture_event(event, None));
let id = send_event::send_raw_event(event)?;
println!("{id}");

Ok(())
Expand Down
4 changes: 2 additions & 2 deletions src/commands/monitors/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ fn execute_checkin(
};

let envelopes_api = EnvelopesApi::try_new()?;
envelopes_api.send_envelope(open_checkin.into())?;
envelopes_api.send_envelope(open_checkin)?;

let (success, code, elapsed) = run_program(args, monitor_slug);

Expand All @@ -161,7 +161,7 @@ fn execute_checkin(
monitor_config: None,
};

envelopes_api.send_envelope(close_checkin.into())?;
envelopes_api.send_envelope(close_checkin)?;
Ok((success, code))
}

Expand Down
34 changes: 20 additions & 14 deletions src/commands/send_event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,22 @@ use std::env;
use std::path::PathBuf;
use std::time::SystemTime;

use anyhow::{format_err, Result};
use anyhow::{anyhow, format_err, Result};
use chrono::{DateTime, Utc};
use clap::{Arg, ArgAction, ArgMatches, Command};
use glob::{glob_with, MatchOptions};
use itertools::Itertools;
use log::{debug, warn};
use log::warn;
use sentry::protocol::{Event, Level, LogEntry, User};
use sentry::types::{Dsn, Uuid};
use sentry::Envelope;
use sentry::types::Uuid;
use sentry::{apply_defaults, Client, ClientOptions, Envelope};
use serde_json::Value;
use username::get_user_name;

use crate::api::envelopes_api::EnvelopesApi;
use crate::config::Config;
use crate::constants::USER_AGENT;
use crate::utils::args::{get_timestamp, validate_distribution};
use crate::utils::event::{attach_logfile, get_sdk_info, with_sentry_client};
use crate::utils::event::{attach_logfile, get_sdk_info};
use crate::utils::releases::detect_release_name;

pub fn make_command(command: Command) -> Command {
Expand Down Expand Up @@ -159,14 +159,20 @@ pub fn make_command(command: Command) -> Command {
)
}

fn send_raw_event(event: Event<'static>, dsn: Dsn) -> Uuid {
debug!("{:?}", event);
with_sentry_client(dsn, |c| c.capture_event(event, None))
pub(super) fn send_raw_event(event: Event<'static>) -> Result<Uuid> {
let client = Client::from_config(apply_defaults(ClientOptions {
user_agent: USER_AGENT.into(),
..Default::default()
}));
let event = client
.prepare_event(event, None)
.ok_or(anyhow!("Event dropped during preparation"))?;
let event_id = event.event_id;
EnvelopesApi::try_new()?.send_envelope(event)?;
Ok(event_id)
}

pub fn execute(matches: &ArgMatches) -> Result<()> {
let config = Config::current();
let dsn = config.get_dsn()?;
let raw = matches.get_flag("raw");

if let Some(path) = matches.get_one::<String>("path") {
Expand Down Expand Up @@ -204,7 +210,7 @@ pub fn execute(matches: &ArgMatches) -> Result<()> {
id
} else {
let event: Event = serde_json::from_slice(&raw_event)?;
send_raw_event(event, dsn.clone())
send_raw_event(event)?
};

println!("Event from file {} dispatched: {}", path.display(), id);
Expand Down Expand Up @@ -319,8 +325,8 @@ pub fn execute(matches: &ArgMatches) -> Result<()> {
attach_logfile(&mut event, logfile, matches.get_flag("with_categories"))?;
}

let id = send_raw_event(event, dsn);
println!("Event dispatched: {id}");
let id = send_raw_event(event)?;
println!("Event dispatched.\nEvent id: {id}");

Ok(())
}
29 changes: 0 additions & 29 deletions src/utils/event.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
use std::borrow::Cow;
use std::fs;
use std::io::{BufRead, BufReader};
use std::time::Duration;

use anyhow::{Context, Result};
use chrono::Utc;
use lazy_static::lazy_static;
use regex::Regex;
use sentry::protocol::{Breadcrumb, ClientSdkInfo, Event};
use sentry::types::Dsn;
use sentry::{apply_defaults, Client, ClientOptions};

use crate::constants::USER_AGENT;

lazy_static! {
static ref COMPONENT_RE: Regex = Regex::new(r#"^([^:]+): (.*)$"#).unwrap();
Expand Down Expand Up @@ -68,27 +63,3 @@ pub fn get_sdk_info() -> Cow<'static, ClientSdkInfo> {
packages: Vec::new(),
})
}

/// Executes the callback with an isolate sentry client on an empty isolate scope.
///
/// Use the client's API to capture exceptions or manual events. The client will automatically drop
/// after the callback has finished and drain its queue with a timeout of 2 seconds. The return
/// value of the callback is passed through to the caller.
pub fn with_sentry_client<F, R>(dsn: Dsn, callback: F) -> R
where
F: FnOnce(&Client) -> R,
{
let client = Client::from_config((
dsn,
apply_defaults(ClientOptions {
// TODO: do we want to eventually set `debug` based on the CLI log-level?
// debug: true,
user_agent: USER_AGENT.into(),
..Default::default()
}),
));

let rv = callback(&client);
client.close(Some(Duration::from_secs(2)));
rv
}
9 changes: 7 additions & 2 deletions tests/integration/_cases/send_event/send_event-raw.trycmd
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,12 @@ $ sentry-cli send-event --log-level=debug
INFO [..] Loaded config from [CWD]/.sentryclirc
DEBUG [..] sentry-cli version: [VERSION], platform: [..], architecture: [..]
INFO [..] sentry-cli was invoked with the following command line: "[CWD]/target/debug/sentry-cli[EXE]" "send-event" "--log-level=debug" "--level" "debug" "--timestamp" "1649335000929" "--release" "my-release" "--dist" "my-dist" "--env" "production" "--message" "hello" "--platform" "prod" "--tag" "hello:there" "--extra" "hello:there" "--user" "id:42" "--fingerprint" "custom-fingerprint" "--no-environ"
DEBUG [..] Event { event_id: [..], level: Debug, fingerprint: ["custom-fingerprint"], culprit: None, transaction: None, message: None, logentry: Some(LogEntry { message: "hello", params: [] }), logger: None, modules: {}, platform: "prod", timestamp: SystemTime { tv_sec: 1649335000929, tv_nsec: 0 }, server_name: None, release: Some("my-release"), dist: Some("my-dist"), environment: Some("production"), user: Some(User { id: Some("42"), email: None, ip_address: Some(Auto), username: None, other: {} }), request: None, contexts: {}, breadcrumbs: Values { values: [] }, exception: Values { values: [] }, stacktrace: None, template: None, threads: Values { values: [] }, tags: {"hello": "there"}, extra: {"hello": String("there")}, debug_meta: DebugMeta { sdk_info: None, images: [] }, sdk: Some(ClientSdkInfo { name: "sentry-cli", version: "[VERSION]", integrations: [], packages: [] }) }
Event dispatched: [..]
DEBUG [..] Sending envelope:
{"event_id":"[..]"}
{"type":"event","length":[..]}
{"event_id":"[..]","level":"debug","fingerprint":["custom-fingerprint"],"logentry":{"message":"hello"},"platform":"prod","timestamp":1649335000929,"server_name":"[..]","release":"my-release","dist":"my-dist","environment":"production","user":{"id":"42","ip_address":"{{auto}}"},"contexts":{"device":{"type":"device"[..]"arch":"[..]"},"os":{"type":"os","name":[..],"version":[..]},"rust":{"type":"runtime","name":"rustc","version":[..],"channel":"stable"}},"tags":{"hello":"there"},"extra":{"hello":"there"},"sdk":{"name":"sentry-cli","version":"[VERSION]"}}
...
Event dispatched.
Event id: [..]

```
2 changes: 1 addition & 1 deletion tests/integration/_fixtures/event.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@
"dist": "my-dist",
"environment": "production",
"message": "hello there"
}
}
14 changes: 9 additions & 5 deletions tests/integration/send_event.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::integration::register_test;
use crate::integration::{self, EndpointOptions};

#[test]
fn command_send_event_help() {
register_test("send_event/send_event-help.trycmd");
integration::register_test("send_event/send_event-help.trycmd");
}

// I have no idea why this is timing out on Windows.
Expand All @@ -11,15 +11,19 @@ fn command_send_event_help() {
#[cfg(not(windows))]
#[test]
fn command_send_event_raw() {
register_test("send_event/send_event-raw.trycmd");
let _server =
integration::mock_endpoint(EndpointOptions::new("POST", "/api/1337/envelope/", 200));
integration::register_test("send_event/send_event-raw.trycmd");
}

#[test]
fn command_send_event_file() {
register_test("send_event/send_event-file.trycmd");
let _server =
integration::mock_endpoint(EndpointOptions::new("POST", "/api/1337/envelope/", 200));
integration::register_test("send_event/send_event-file.trycmd");
}

#[test]
fn command_send_event_raw_fail() {
register_test("send_event/send_event-raw-fail.trycmd");
integration::register_test("send_event/send_event-raw-fail.trycmd");
}

0 comments on commit 0a42b4c

Please sign in to comment.