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
6 changes: 3 additions & 3 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ enum Command {
#[arg(long)]
until: Option<String>,

/// JSON array of metric names to include
/// JSON array or comma-separated list of metric names to include
///
/// Available metrics: requests, requests_per_minute, bytes_received,
/// bytes_sent, client_errors, server_errors, error_rate,
Expand All @@ -161,7 +161,7 @@ enum Command {
#[arg(long)]
interval: Option<String>,

/// JSON array of field names to group by (in addition to time interval)
/// JSON array or comma-separated list of field names to group by (in addition to time interval)
///
/// Available fields: env, consumer_id, method, path, status_code.
#[arg(long)]
Expand Down Expand Up @@ -213,7 +213,7 @@ enum Command {
#[arg(long)]
until: Option<String>,

/// JSON array of field names to include
/// JSON array or comma-separated list of field names to include
///
/// Available fields: timestamp, request_uuid, env, method, path,
/// url, consumer_id, request_headers, request_size_bytes, request_body_json,
Expand Down
9 changes: 3 additions & 6 deletions src/metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use duckdb::arrow::ipc::reader::StreamReader;
use duckdb::vtab::arrow::{ArrowVTab, arrow_recordbatch_to_query_params};

use crate::auth::{resolve_api_base_url, resolve_api_key};
use crate::utils::{api_post, input_err, open_db, resolve_relative_datetime};
use crate::utils::{api_post, input_err, open_db, parse_string_list, resolve_relative_datetime};

pub(crate) fn ensure_metrics_table(conn: &duckdb::Connection) -> Result<()> {
conn.execute_batch(
Expand Down Expand Up @@ -55,13 +55,11 @@ pub fn run(
let since = resolve_relative_datetime(since);
let until = until.map(resolve_relative_datetime);

let metrics_value: serde_json::Value = serde_json::from_str(metrics)
.map_err(|e| input_err(format!("invalid JSON for --metrics: {e}")))?;
let format = if db.is_some() { "arrow" } else { "ndjson" };
let mut body = serde_json::json!({
"format": format,
"since": since,
"metrics": metrics_value,
"metrics": parse_string_list(metrics).map_err(|e| input_err(format!("invalid JSON for --metrics: {e}")))?,
});
if let Some(ref until) = until {
body["until"] = serde_json::json!(until);
Expand All @@ -70,9 +68,8 @@ pub fn run(
body["interval"] = serde_json::json!(interval);
}
if let Some(group_by) = group_by {
let group_by_value: serde_json::Value = serde_json::from_str(group_by)
body["group_by"] = parse_string_list(group_by)
.map_err(|e| input_err(format!("invalid JSON for --group-by: {e}")))?;
body["group_by"] = group_by_value;
}
if let Some(filters) = filters {
let filters_value: serde_json::Value = serde_json::from_str(filters)
Expand Down
5 changes: 2 additions & 3 deletions src/request_logs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use duckdb::arrow::ipc::reader::StreamReader;
use duckdb::vtab::arrow::{ArrowVTab, arrow_recordbatch_to_query_params};

use crate::auth::{resolve_api_base_url, resolve_api_key};
use crate::utils::{api_post, input_err, open_db, resolve_relative_datetime};
use crate::utils::{api_post, input_err, open_db, parse_string_list, resolve_relative_datetime};

pub(crate) fn ensure_request_logs_table(conn: &duckdb::Connection) -> Result<()> {
conn.execute_batch(
Expand Down Expand Up @@ -69,9 +69,8 @@ pub fn run(
body["until"] = serde_json::json!(until);
}
if let Some(fields) = fields {
let fields_value: serde_json::Value = serde_json::from_str(fields)
body["fields"] = parse_string_list(fields)
.map_err(|e| input_err(format!("invalid JSON for --fields: {e}")))?;
body["fields"] = fields_value;
}
if let Some(filters) = filters {
let filters_value: serde_json::Value = serde_json::from_str(filters)
Expand Down
39 changes: 39 additions & 0 deletions src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,20 @@ pub fn resolve_relative_datetime(s: &str) -> String {
dt.to_rfc3339()
}

/// Parses a string as either a JSON array or a comma-separated list of strings.
pub fn parse_string_list(s: &str) -> Result<serde_json::Value> {
let s = s.trim_start();
if s.starts_with('[') {
Comment thread
itssimon marked this conversation as resolved.
return serde_json::from_str::<serde_json::Value>(s).map_err(Into::into);
}
let items: Vec<&str> = s
.split(',')
.map(|item| item.trim())
.filter(|item| !item.is_empty())
.collect();
Ok(serde_json::json!(items))
}

pub fn api_get(url: &str, api_key: &str, query: &[(&str, &str)]) -> Result<Response<Body>> {
let mut req = ureq::get(url)
.header("Api-Key", api_key)
Expand Down Expand Up @@ -185,6 +199,31 @@ mod tests {
assert_approximately_now_minus(&resolve_relative_datetime("1w"), 604_800);
}

#[test]
fn test_parse_string_list() {
assert_eq!(
parse_string_list(r#"["requests","error_rate"]"#).unwrap(),
serde_json::json!(["requests", "error_rate"])
);
assert_eq!(
parse_string_list("requests,error_rate").unwrap(),
serde_json::json!(["requests", "error_rate"])
);
assert_eq!(
parse_string_list("requests").unwrap(),
serde_json::json!(["requests"])
);
assert_eq!(
parse_string_list("requests , error_rate").unwrap(),
serde_json::json!(["requests", "error_rate"])
);
assert_eq!(
parse_string_list("requests,,error_rate").unwrap(),
serde_json::json!(["requests", "error_rate"])
);
assert!(parse_string_list("[foo]").is_err());
}

#[test]
fn test_check_response() {
assert!(check_response(&mut resp(200)).is_ok());
Expand Down
Loading