Skip to content

Commit 8118a42

Browse files
feat: add option to output structured json
1 parent 80f3e3d commit 8118a42

5 files changed

Lines changed: 52 additions & 7 deletions

File tree

src/local_logger.rs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use log::Log;
1212
use simplelog::{CombinedLogger, SharedLogger};
1313
use std::io::Write;
1414

15-
use crate::logger::{get_group_event, GroupEvent};
15+
use crate::logger::{get_group_event, get_json_event, GroupEvent, JsonEvent};
1616

1717
pub const CODSPEED_U8_COLOR_CODE: u8 = 208; // #FF8700
1818

@@ -66,7 +66,7 @@ impl Log for LocalLogger {
6666
if let Some(group_event) = get_group_event(record) {
6767
match group_event {
6868
GroupEvent::Start(name) | GroupEvent::StartOpened(name) => {
69-
println!(
69+
eprintln!(
7070
"\n{}",
7171
style(format!("►►► {} ", name))
7272
.bold()
@@ -89,7 +89,7 @@ impl Log for LocalLogger {
8989
spinner.enable_steady_tick(Duration::from_millis(100));
9090
SPINNER.lock().unwrap().replace(spinner);
9191
} else {
92-
println!("{}...", name);
92+
eprintln!("{}...", name);
9393
}
9494
}
9595
GroupEvent::End => {
@@ -105,6 +105,11 @@ impl Log for LocalLogger {
105105
return;
106106
}
107107

108+
if let Some(JsonEvent(json_string)) = get_json_event(record) {
109+
println!("{json_string}");
110+
return;
111+
}
112+
108113
suspend_progress_bar(|| print_record(record));
109114
}
110115

@@ -124,12 +129,12 @@ fn print_record(record: &log::Record) {
124129
match record.level() {
125130
log::Level::Error => eprintln!("{}", error_style.apply_to(record.args())),
126131
log::Level::Warn => eprintln!("{}", warn_style.apply_to(record.args())),
127-
log::Level::Info => println!("{}", info_style.apply_to(record.args())),
128-
log::Level::Debug => println!(
132+
log::Level::Info => eprintln!("{}", info_style.apply_to(record.args())),
133+
log::Level::Debug => eprintln!(
129134
"{}",
130135
debug_style.apply_to(format!("[DEBUG::{}] {}", record.target(), record.args())),
131136
),
132-
log::Level::Trace => println!(
137+
log::Level::Trace => eprintln!(
133138
"{}",
134139
trace_style.apply_to(format!("[TRACE::{}] {}", record.target(), record.args()))
135140
),

src/logger.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,23 @@ pub(super) fn get_group_event(record: &log::Record) -> Option<GroupEvent> {
7171
_ => None,
7272
}
7373
}
74+
75+
#[macro_export]
76+
/// Log a structured JSON output
77+
macro_rules! log_json {
78+
($value:expr) => {
79+
log::log!(target: $crate::logger::JSON_TARGET, log::Level::Info, "{}", $value);
80+
};
81+
}
82+
83+
pub struct JsonEvent(pub String);
84+
85+
pub const JSON_TARGET: &str = "codspeed::json";
86+
87+
pub(super) fn get_json_event(record: &log::Record) -> Option<JsonEvent> {
88+
if record.target() != JSON_TARGET {
89+
return None;
90+
}
91+
92+
Some(JsonEvent(record.args().to_string()))
93+
}

src/prelude.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
pub use crate::{end_group, start_group, start_opened_group};
1+
pub use crate::{end_group, log_json, start_group, start_opened_group};
22
#[allow(unused_imports)]
33
pub use anyhow::{anyhow, bail, ensure, Context, Error, Result};
44
pub use itertools::Itertools;

src/run/config.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ mod tests {
112112
mode: RunnerMode::Instrumentation,
113113
instruments: vec![],
114114
mongo_uri_env_name: None,
115+
message_format: None,
115116
skip_upload: false,
116117
skip_setup: false,
117118
command: vec!["cargo".into(), "codspeed".into(), "bench".into()],
@@ -138,6 +139,7 @@ mod tests {
138139
mode: RunnerMode::Instrumentation,
139140
instruments: vec!["mongodb".into()],
140141
mongo_uri_env_name: Some("MONGODB_URI".into()),
142+
message_format: Some("json".into()),
141143
skip_upload: true,
142144
skip_setup: true,
143145
command: vec!["cargo".into(), "codspeed".into(), "bench".into()],

src/run/mod.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ pub struct RunArgs {
8787
#[arg(long)]
8888
pub mongo_uri_env_name: Option<String>,
8989

90+
#[arg(long)]
91+
pub message_format: Option<String>,
92+
9093
/// Only for debugging purposes, skips the upload of the results
9194
#[arg(
9295
long,
@@ -117,6 +120,7 @@ impl RunArgs {
117120
mode: RunnerMode::Instrumentation,
118121
instruments: vec![],
119122
mongo_uri_env_name: None,
123+
message_format: None,
120124
skip_upload: false,
121125
skip_setup: false,
122126
command: vec![],
@@ -125,6 +129,12 @@ impl RunArgs {
125129
}
126130

127131
pub async fn run(args: RunArgs, api_client: &CodSpeedAPIClient) -> Result<()> {
132+
let output_json = args
133+
.message_format
134+
.as_ref()
135+
.map(|format| format == "json")
136+
.unwrap_or(false);
137+
128138
let mut config = Config::try_from(args)?;
129139
let provider = run_environment::get_provider(&config)?;
130140
let codspeed_config = CodSpeedConfig::load()?;
@@ -194,7 +204,15 @@ pub async fn run(args: RunArgs, api_client: &CodSpeedAPIClient) -> Result<()> {
194204

195205
if provider.get_run_environment() == RunEnvironment::Local {
196206
start_group!("Fetching the results");
207+
let run_id = upload_result.run_id.clone();
197208
poll_results::poll_results(api_client, &provider, upload_result.run_id).await?;
209+
if output_json {
210+
// TODO: Refactor `log_json` to accept a serde_json::Value arguemnt
211+
log_json!(format!(
212+
"{{\"event\": \"run_finished\", \"run_id\": \"{}\"}}",
213+
run_id
214+
));
215+
}
198216
end_group!();
199217
}
200218
}

0 commit comments

Comments
 (0)