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
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[workspace]
resolver = "2"
members = ["runtime_tracing", "runtime_tracing_cli"]
members = ["runtime_tracing", "runtime_tracing_cli", "trace_formatter"]

[workspace.dependencies]
runtime_tracing = { path = "runtime_tracing/" }
trace_formatter = { path = "trace_formatter/"}
3 changes: 3 additions & 0 deletions runtime_tracing_cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,6 @@ edition = "2021"
[dependencies]
clap = { version = "4.5.40", features = ["derive"] }
runtime_tracing.workspace = true
trace_formatter.workspace = true
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
24 changes: 24 additions & 0 deletions runtime_tracing_cli/src/fmt_trace_cmd.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
use clap::Args;
use serde_json::Value;
use trace_formatter::{
prettify::{correct_path, prettify_value},
read_write_json::{save_to_file, serialize_file},
};

#[derive(Debug, Clone, Args)]
pub(crate) struct FmtTraceCommand {
/// Trace file which we want to format
source_file: String,

/// Path where the formatted trace will be saved
target_file: String,
}

pub(crate) fn run(args: FmtTraceCommand) {
let ser_json: Value = serialize_file(args.source_file);

let prettified_json: String = prettify_value(ser_json, "", false);
let final_pretty_json: String = correct_path(&prettified_json);

save_to_file(args.target_file, final_pretty_json);
}
8 changes: 8 additions & 0 deletions runtime_tracing_cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ use std::path::Path;
use clap::{Args, Parser, Subcommand};
use runtime_tracing::{TraceEventsFileFormat, Tracer};

use crate::fmt_trace_cmd::FmtTraceCommand;
mod fmt_trace_cmd;

#[derive(Debug, Clone, Args)]
struct ConvertCommand {
input_file: String,
Expand All @@ -14,6 +17,8 @@ struct ConvertCommand {
enum RuntimeTracingCliCommand {
/// Convert from one trace file format to another
Convert(ConvertCommand),
/// Format a trace which is in JSON file format
FormatTrace(FmtTraceCommand),
}

#[derive(Parser, Debug)]
Expand Down Expand Up @@ -43,6 +48,9 @@ fn main() {
let mut trace = Tracer::new("", &[]);
trace.load_trace_events(Path::new(&convert_command.input_file), input_file_format).unwrap();
trace.store_trace_events(Path::new(&convert_command.output_file), output_file_format).unwrap();
},
RuntimeTracingCliCommand::FormatTrace(fmt_trace_cmd) => {
fmt_trace_cmd::run(fmt_trace_cmd);
}
}
}
13 changes: 13 additions & 0 deletions trace_formatter/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[package]
name = "trace_formatter"
version = "0.1.0"
edition = "2021"

[dependencies]
serde = "1.0"
serde_json = { version = "1.0", features = ["preserve_order"] }
regex = "1.10.5"

[lib]
name = "trace_formatter"
path = "src/lib.rs"
26 changes: 26 additions & 0 deletions trace_formatter/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Format-trace-tool
## Overview
This tool is used for formatting json files, especially ones that are generated from the command:
```bash
nargo trace
```
## Usage
You need to provide two arguments, first being the source file containing the json, second is the destination file name.
Example:
```bash
cargo run src.json des.json
```
This will generate a file in the current directory named "des.json" containing the output of our program.
### Trace formatting example
Input:
```json
[{"a":1},{"b":"bbb"},{"c":{"f1":3,"f2":"0"}}]
```
Output:
```json
[
{ "a": 1 },
{ "b": "bbb" },
{ "c": { "f1": 3, "f2": "0" } }
]
```
99 changes: 99 additions & 0 deletions trace_formatter/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
pub mod prettify;
pub mod read_write_json;

#[cfg(test)]
mod tests {
use crate::prettify::correct_path;

use super::*;
fn generate_pretty_json(input_json: &str) -> String {
let ser_json = serde_json::from_str(input_json).expect("Failed to parse the json input");
let prettified_json: String = prettify::prettify_value(ser_json, "", false);
let mut final_pretty_json: String = correct_path(&prettified_json);
final_pretty_json.push('\n'); //this is done automatically when saving the json to a file
final_pretty_json
}

#[test]
fn test_single_json_object() {
let input_json = r#"[{"Key":"val"}]"#;
let expected = r#"[
{ "Key": "val" }
]
"#;
let final_pretty_json = generate_pretty_json(input_json);
assert_eq!(final_pretty_json, expected);
}

#[test]
fn test_non_absolute_path_json() {
let input_json = r#"[{"Path":"?"},{"Path":"src/dir/main.nr"}]"#;
let expected = r#"[
{ "Path": "?" },
{ "Path": "src/dir/main.nr" }
]
"#;
let final_pretty_json = generate_pretty_json(input_json);
assert_eq!(final_pretty_json, expected);
}

#[test]
fn test_absolute_path_json() {
let input_json = r#"[{"Path":"?"},{"Path":"some/absolute/path/src/dir/main.nr"}]"#;
let expected = r#"[
{ "Path": "?" },
{ "Path": "<relative-to-this>/src/dir/main.nr" }
]
"#;
let final_pretty_json = generate_pretty_json(input_json);
assert_eq!(final_pretty_json, expected);
}

#[test]
fn test_basic_nested_array_json() {
let input_json = r#"[{"arr":[{"nested_arr":[{"key":"val"}]}]}]"#;
let expected = r#"[
{ "arr": [
{ "nested_arr": [
{ "key": "val" }
] }
] }
]
"#;
let final_pretty_json = generate_pretty_json(input_json);
assert_eq!(final_pretty_json, expected);
}

#[test]
fn test_basic_nested_json_objects() {
let input_json = r#"[{"key":{"inner_key1":"inner_value1","inner_key2":"inner_value2"}}]"#;
let expected = r#"[
{ "key": { "inner_key1": "inner_value1", "inner_key2": "inner_value2" } }
]
"#;
let final_pretty_json = generate_pretty_json(input_json);
assert_eq!(final_pretty_json, expected);
}

#[test]
fn test_arrays_nested_objects_full_json() {
let input_json = r#"[{"a":"111"},{"b":[]},{"c":[{"arr":"arr1", "abb" : 1},"#.to_string()
+ r#"{"arr":"arr2","abb" : 2},{"arr":"arr3","abb" : 3}]},{"long":"a1","along1":"a2"},"#
+ r#"{ "Value": { "variable_id": 0, "value": { "kind": "Int", "i": 4, "type_id": 1 } } }]"#;

let expected = r#"[
{ "a": "111" },
{ "b": [] },
{ "c": [
{ "arr": "arr1", "abb": 1 },
{ "arr": "arr2", "abb": 2 },
{ "arr": "arr3", "abb": 3 }
] },
{ "long": "a1", "along1": "a2" },
{ "Value": { "variable_id": 0, "value": { "kind": "Int", "i": 4, "type_id": 1 } } }
]
"#;
let final_pretty_json = generate_pretty_json(&input_json);
assert_eq!(final_pretty_json, expected);
}
}
46 changes: 46 additions & 0 deletions trace_formatter/src/prettify.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
use regex::Regex;
use serde_json::Value;

pub fn prettify_value(root_value: Value, indent: &str, is_in_array: bool) -> String {
let content = match root_value {
Value::Array(elements) => {
let new_indent = indent.to_string() + " ";
let parts: Vec<String> = elements
.into_iter()
.map(|el| prettify_value(el, new_indent.as_str(), true))
.collect::<Vec<String>>();
if parts.is_empty() {
"[]".to_string()
} else {
let lines = parts.join(",\n");
format!("[\n{lines}\n{indent}]")
}
}
Value::Object(map) => {
let parts: Vec<String> = map
.into_iter()
.map(|(k, v)| {
let head = format!("\"{k}\"");
let rest = prettify_value(v, indent, false);
format!("{head}: {rest}")
})
.collect();
let json_object_string = parts.join(", ");
format!("{{ {json_object_string} }}")
}
_ => root_value.to_string(),
};
let indent = if is_in_array { indent } else { "" };
format!("{indent}{content}")
}

/// Replaces all absolute paths in the trace with relative paths
pub fn correct_path(pretty_json: &str) -> String {
let re = Regex::new(r#" \{ "Path": (?<abs_path>.*)(?<rel_path>/src/.*)"#);
let result = re.map(|regex| {
regex.replace_all(pretty_json, |caps: &regex::Captures| {
format!(" {{ \"Path\": \"<relative-to-this>{}", &caps["rel_path"])
})
});
result.map(|result_string| result_string.into_owned()).unwrap_or(pretty_json.to_string())
}
19 changes: 19 additions & 0 deletions trace_formatter/src/read_write_json.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
use serde_json::Value;
use std::fs;

pub fn serialize_file(src_filename: String) -> Value {
let file_content = fs::read_to_string(src_filename).expect("Failed to read the file");

serde_json::from_str(&file_content)
.expect("Failed to parse the json file that was given as a source")
}

pub fn save_to_file(dest_filename: String, json_string: String) {
let mut json_string_copy = json_string.clone();
if !json_string_copy.ends_with('\n') {
json_string_copy.push('\n');
}
fs::write(&dest_filename, json_string_copy).unwrap_or_else(|_| {
panic!("Unable to write to destination file: {}", dest_filename.as_str())
});
}