Better JSON serialization in metrics

This commit is contained in:
Aleksey Kladov 2020-08-01 04:09:52 +02:00
parent 2346a28c63
commit a015714def
3 changed files with 22 additions and 118 deletions

7
Cargo.lock generated
View file

@ -1831,6 +1831,12 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "write-json"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b3f9a784c809a99e38d2e825907617cb03bd880d5421153bc4548e9317f59d0"
[[package]] [[package]]
name = "ws2_32-sys" name = "ws2_32-sys"
version = "0.2.1" version = "0.2.1"
@ -1852,4 +1858,5 @@ dependencies = [
"quote", "quote",
"ungrammar", "ungrammar",
"walkdir", "walkdir",
"write-json",
] ]

View file

@ -17,3 +17,4 @@ proc-macro2 = "1.0.8"
quote = "1.0.2" quote = "1.0.2"
ungrammar = "0.1.0" ungrammar = "0.1.0"
walkdir = "2.3.1" walkdir = "2.3.1"
write-json = "0.1.0"

View file

@ -1,7 +1,6 @@
use std::{ use std::{
collections::BTreeMap, collections::BTreeMap,
env, env,
fmt::{self, Write as _},
io::Write as _, io::Write as _,
path::Path, path::Path,
time::{Instant, SystemTime, UNIX_EPOCH}, time::{Instant, SystemTime, UNIX_EPOCH},
@ -127,40 +126,21 @@ impl Metrics {
self.metrics.insert(name.into(), (value, unit)); self.metrics.insert(name.into(), (value, unit));
} }
fn json(&self) -> Json { fn json(&self) -> String {
let mut json = Json::default(); let mut buf = String::new();
self.to_json(&mut json); self.to_json(write_json::object(&mut buf));
json buf
} }
fn to_json(&self, json: &mut Json) {
json.begin_object();
{
json.field("host");
self.host.to_json(json);
json.field("timestamp"); fn to_json(&self, mut obj: write_json::Object<'_>) {
let timestamp = self.timestamp.duration_since(UNIX_EPOCH).unwrap(); self.host.to_json(obj.object("host"));
json.number(timestamp.as_secs() as f64); let timestamp = self.timestamp.duration_since(UNIX_EPOCH).unwrap();
obj.number("timestamp", timestamp.as_secs() as f64);
json.field("revision"); obj.string("revision", &self.revision);
json.string(&self.revision); let mut metrics = obj.object("metrics");
for (k, (value, unit)) in &self.metrics {
json.field("metrics"); metrics.array(k).number(*value as f64).string(unit);
json.begin_object();
{
for (k, (value, unit)) in &self.metrics {
json.field(k);
json.begin_array();
{
json.number(*value as f64);
json.string(unit);
}
json.end_array();
}
}
json.end_object()
} }
json.end_object();
} }
} }
@ -189,91 +169,7 @@ impl Host {
Ok(line[field.len()..].trim().to_string()) Ok(line[field.len()..].trim().to_string())
} }
} }
fn to_json(&self, json: &mut Json) { fn to_json(&self, mut obj: write_json::Object<'_>) {
json.begin_object(); obj.string("os", &self.os).string("cpu", &self.cpu).string("mem", &self.mem);
{
json.field("os");
json.string(&self.os);
json.field("cpu");
json.string(&self.cpu);
json.field("mem");
json.string(&self.mem);
}
json.end_object();
}
}
struct State {
obj: bool,
first: bool,
}
#[derive(Default)]
struct Json {
stack: Vec<State>,
buf: String,
}
impl Json {
fn begin_object(&mut self) {
self.stack.push(State { obj: true, first: true });
self.buf.push('{');
}
fn end_object(&mut self) {
self.stack.pop();
self.buf.push('}')
}
fn begin_array(&mut self) {
self.stack.push(State { obj: false, first: true });
self.buf.push('[');
}
fn end_array(&mut self) {
self.stack.pop();
self.buf.push(']')
}
fn field(&mut self, name: &str) {
self.object_comma();
self.string_token(name);
self.buf.push(':');
}
fn string(&mut self, value: &str) {
self.array_comma();
self.string_token(value);
}
fn string_token(&mut self, value: &str) {
self.buf.push('"');
self.buf.extend(value.escape_default());
self.buf.push('"');
}
fn number(&mut self, value: f64) {
self.array_comma();
write!(self.buf, "{}", value).unwrap();
}
fn array_comma(&mut self) {
let state = self.stack.last_mut().unwrap();
if state.obj {
return;
}
if !state.first {
self.buf.push(',');
}
state.first = false;
}
fn object_comma(&mut self) {
let state = self.stack.last_mut().unwrap();
if !state.first {
self.buf.push(',');
}
state.first = false;
}
}
impl fmt::Display for Json {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.buf)
} }
} }