Skip to content

Commit

Permalink
feat(commands): add send-metric command
Browse files Browse the repository at this point in the history
Add CLI command that can emit metrics.

Fixes GH-2001
  • Loading branch information
Elias Ram committed Apr 29, 2024
1 parent 64d20b0 commit 5a72389
Show file tree
Hide file tree
Showing 65 changed files with 1,191 additions and 34 deletions.
97 changes: 66 additions & 31 deletions Cargo.lock

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

6 changes: 4 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,15 @@ prettytable-rs = "0.10.0"
proguard = { version = "5.0.0", features = ["uuid"] }
r2d2 = "0.8.10"
rayon = "1.6.1"
regex = "1.7.3"
regex = "1.10.4"
runas = "1.0.0"
rust-ini = "0.18.0"
semver = "1.0.16"
sentry = { version = "0.32.2", default-features = false, features = [
sentry = { version = "0.32.3", default-features = false, features = [
"anyhow",
"curl",
"contexts",
"UNSTABLE_metrics",
] }
serde = { version = "1.0.152", features = ["derive"] }
serde_json = "1.0.93"
Expand All @@ -79,6 +80,7 @@ zip = "0.6.4"
data-encoding = "2.3.3"
magic_string = "0.3.4"
chrono-tz = "0.8.4"
crc32fast = "1.4.0"

[dev-dependencies]
insta = { version = "1.26.0", features = ["redactions", "yaml"] }
Expand Down
6 changes: 5 additions & 1 deletion src/commands/derive_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ use crate::utils::auth_token::AuthToken;
use crate::utils::value_parsers::kv_parser;
use clap::{command, value_parser, ArgAction::SetTrue, Parser, Subcommand};

use super::send_metric::SendMetricArgs;

#[derive(Parser)]
pub(super) struct SentryCLI {
#[command(subcommand)]
Expand Down Expand Up @@ -29,4 +31,6 @@ pub(super) struct SentryCLI {
}

#[derive(Subcommand)]
pub(super) enum SentryCLICommand {}
pub enum SentryCLICommand {
SendMetric(SendMetricArgs),
}
2 changes: 2 additions & 0 deletions src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ macro_rules! each_subcommand {
$mac!(repos);
$mac!(send_event);
$mac!(send_envelope);
$mac!(send_metric);
$mac!(sourcemaps);
#[cfg(not(feature = "managed"))]
$mac!(uninstall);
Expand Down Expand Up @@ -77,6 +78,7 @@ const UPDATE_NAGGER_CMDS: &[&str] = &[
"projects",
"releases",
"repos",
"send-metric",
"sourcemaps",
];

Expand Down
38 changes: 38 additions & 0 deletions src/commands/send_metric/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
use super::derive_parser::{SentryCLI, SentryCLICommand};
use crate::config::Config;
use crate::utils::event;
use crate::utils::metrics::payload::MetricsPayload;
use anyhow::Context;
use anyhow::Result;
use clap::{command, Args, Subcommand};
use clap::{ArgMatches, Command, Parser};
use log::debug;
use sentry::protocol::EnvelopeItem;
use sentry::Envelope;
use subcommands::SendMetricSubcommand;

pub mod subcommands;

#[derive(Args)]
pub(super) struct SendMetricArgs {
#[command(subcommand)]
pub(super) subcommand: SendMetricSubcommand,
}

pub(super) fn make_command(command: Command) -> Command {
SendMetricSubcommand::augment_subcommands(command)
}

pub(super) fn execute(_: &ArgMatches) -> Result<()> {
let SentryCLICommand::SendMetric(SendMetricArgs { subcommand }) = SentryCLI::parse().command;
let payload = MetricsPayload::from_subcommand(subcommand)?;
let mut envelope = Envelope::new();
envelope.add_item(EnvelopeItem::Statsd(payload.to_bytes()));
let dsn = Config::current().get_dsn().ok().context(
"DSN not found. \
See: https://docs.sentry.io/product/crons/getting-started/cli/#configuration",
)?;
event::with_sentry_client(dsn, |c| c.send_envelope(envelope));
debug!("Metric payload sent: {}", (payload.to_string()?));
Ok(())
}
63 changes: 63 additions & 0 deletions src/commands/send_metric/subcommands.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
use clap::Args;
use clap::{command, Subcommand};

use crate::utils::value_parsers;

#[derive(Subcommand)]
#[command(about = "Send a metric to Sentry.")]
#[command(long_about = "Send a metric event to Sentry.{n}{n}\
This command will validate input parameters and attempt to send a metric to \
Sentry. Due to network errors and rate limits, the metric is not guaranteed to \
arrive.")]
pub enum SendMetricSubcommand {
#[command(about = "Send an increment to a counter metric")]
Increment(IncrementArgs),
#[command(about = "Send a value to a distribution metric")]
Distribution(FloatValueMetricArgs),
#[command(about = "Send a value to a gauge metric")]
Gauge(FloatValueMetricArgs),
#[command(about = "Send a value to a set metric")]
Set(SetArgs),
}

#[derive(Args)]
pub struct FloatValueMetricArgs {
#[command(flatten)]
pub common: CommonMetricArgs,

#[arg(short, long, help = "Metric value")]
pub value: f64,
}

#[derive(Args)]
pub struct IncrementArgs {
#[command(flatten)]
pub common: CommonMetricArgs,

#[arg(short, long, help = "Metric value", default_value = "1")]
pub value: f64,
}

#[derive(Args)]
pub struct SetArgs {
#[command(flatten)]
pub common: CommonMetricArgs,

#[arg(short, long, value_parser=value_parsers::set_value_parser)]
#[arg(help = "Metric value: strings and integers are supported, floats are floored")]
pub value: f64,
}

#[derive(Args)]
pub struct CommonMetricArgs {
#[arg(short, long, help = "Metric key/name")]
#[arg(visible_alias = "name", visible_short_alias = 'n')]
pub key: String,

#[arg(short, long, help = "Metric unit")]
pub unit: Option<String>,

#[arg(short, long, value_delimiter=',', value_name = "KEY:VALUE", num_args = 1..)]
#[arg(value_parser=value_parsers::kv_parser, help = "Metric tags as key:value pairs")]
pub tags: Vec<(String, String)>,
}
3 changes: 3 additions & 0 deletions src/utils/metrics/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub mod payload;
mod subcommand_impl;
mod tags;
Loading

0 comments on commit 5a72389

Please sign in to comment.