Skip to content

Commit 895770a

Browse files
danobifacebook-github-bot
authored andcommitted
Add support for dumping in OpenMetrics format (facebookincubator#8186)
Summary: As promised, here is support for dumping in OpenMetrics format. I did my best to structure the commits so it's more easily reviewed, but here are some salient points: * I opted not to use a 3rd party library for generating openmetrics b/c it's really quite trivial to do ourselves. It also frees us from any constraints the library puts on us. There are quite a few contraints from the popular ones b/c they probably didn't envision this use case. They're mostly designed for applications to report metrics about themselves. * It's much easier to review this PR if you go commit-by-commit. There aren't actually that many changes. Most of the diff is the model registration in the final ~6 commits. Pull Request resolved: facebookincubator#8186 Reviewed By: dschatzberg Differential Revision: D45213671 Pulled By: brianc118 fbshipit-source-id: 5c79dde163871a2474c1d85cfbe1acc936a7b4b6
1 parent a759dca commit 895770a

File tree

21 files changed

+1524
-305
lines changed

21 files changed

+1524
-305
lines changed

Cargo.lock

Lines changed: 279 additions & 139 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

below/dump/src/btrfs.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ use model::BtrfsModelFieldId;
1616

1717
use super::*;
1818

19-
impl HasRenderConfigForDump for model::BtrfsModel {}
20-
2119
pub struct Btrfs {
2220
opts: GeneralOpt,
2321
select: Option<BtrfsModelFieldId>,
@@ -80,7 +78,6 @@ impl Dumper for Btrfs {
8078
btrfs_items.truncate(self.opts.top as usize);
8179
}
8280
}
83-
let json = self.opts.output_format == Some(OutputFormat::Json);
8481
let mut json_output = json!([]);
8582

8683
btrfs_items
@@ -133,15 +130,21 @@ impl Dumper for Btrfs {
133130
self.opts.raw
134131
)
135132
)?,
133+
Some(OutputFormat::OpenMetrics) => write!(
134+
output,
135+
"{}",
136+
print::dump_openmetrics(&self.fields, ctx, model)
137+
)?,
136138
}
137139
*round += 1;
138140
Ok(())
139141
})
140142
.collect::<Result<Vec<_>>>()?;
141143

142-
match (json, comma_flag) {
143-
(true, true) => write!(output, ",{}", json_output)?,
144-
(true, false) => write!(output, "{}", json_output)?,
144+
match (self.opts.output_format, comma_flag) {
145+
(Some(OutputFormat::Json), true) => write!(output, ",{}", json_output)?,
146+
(Some(OutputFormat::Json), false) => write!(output, "{}", json_output)?,
147+
(Some(OutputFormat::OpenMetrics), _) => (),
145148
_ => write!(output, "\n")?,
146149
};
147150

below/dump/src/cgroup.rs

Lines changed: 5 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -13,109 +13,9 @@
1313
// limitations under the License.
1414

1515
use model::SingleCgroupModelFieldId;
16-
use render::RenderConfig;
1716

1817
use super::*;
1918

20-
impl HasRenderConfigForDump for model::SingleCgroupModel {
21-
fn get_render_config_for_dump(field_id: &SingleCgroupModelFieldId) -> RenderConfig {
22-
use common::util::get_prefix;
23-
use model::CgroupCpuModelFieldId::ThrottledPct;
24-
use model::CgroupIoModelFieldId::CostIndebtPct;
25-
use model::CgroupIoModelFieldId::CostIndelayPct;
26-
use model::CgroupIoModelFieldId::CostUsagePct;
27-
use model::CgroupIoModelFieldId::CostWaitPct;
28-
use model::CgroupIoModelFieldId::DbytesPerSec;
29-
use model::CgroupIoModelFieldId::DiosPerSec;
30-
use model::CgroupIoModelFieldId::RbytesPerSec;
31-
use model::CgroupIoModelFieldId::RiosPerSec;
32-
use model::CgroupIoModelFieldId::RwbytesPerSec;
33-
use model::CgroupIoModelFieldId::WbytesPerSec;
34-
use model::CgroupIoModelFieldId::WiosPerSec;
35-
use model::CgroupMemoryModelFieldId::Anon;
36-
use model::CgroupMemoryModelFieldId::File;
37-
use model::CgroupMemoryModelFieldId::Pgactivate;
38-
use model::CgroupMemoryModelFieldId::Pgdeactivate;
39-
use model::CgroupMemoryModelFieldId::Pgfault;
40-
use model::CgroupMemoryModelFieldId::Pglazyfree;
41-
use model::CgroupMemoryModelFieldId::Pglazyfreed;
42-
use model::CgroupMemoryModelFieldId::Pgmajfault;
43-
use model::CgroupMemoryModelFieldId::Pgrefill;
44-
use model::CgroupMemoryModelFieldId::Pgscan;
45-
use model::CgroupMemoryModelFieldId::Pgsteal;
46-
use model::CgroupMemoryModelFieldId::Shmem;
47-
use model::CgroupMemoryModelFieldId::Slab;
48-
use model::CgroupMemoryModelFieldId::Sock;
49-
use model::CgroupMemoryModelFieldId::Swap;
50-
use model::CgroupMemoryModelFieldId::ThpCollapseAlloc;
51-
use model::CgroupMemoryModelFieldId::ThpFaultAlloc;
52-
use model::CgroupMemoryModelFieldId::Total;
53-
use model::CgroupMemoryModelFieldId::WorkingsetActivateAnon;
54-
use model::CgroupMemoryModelFieldId::WorkingsetActivateFile;
55-
use model::CgroupMemoryModelFieldId::WorkingsetNodereclaim;
56-
use model::CgroupMemoryModelFieldId::WorkingsetRefaultAnon;
57-
use model::CgroupMemoryModelFieldId::WorkingsetRefaultFile;
58-
use model::CgroupMemoryModelFieldId::WorkingsetRestoreAnon;
59-
use model::CgroupMemoryModelFieldId::WorkingsetRestoreFile;
60-
use model::CgroupMemoryModelFieldId::Zswap;
61-
use model::CgroupPressureModelFieldId::MemoryFullPct;
62-
use model::CgroupPressureModelFieldId::MemorySomePct;
63-
use model::SingleCgroupModelFieldId::Cpu;
64-
use model::SingleCgroupModelFieldId::Io;
65-
use model::SingleCgroupModelFieldId::Mem;
66-
use model::SingleCgroupModelFieldId::Name;
67-
use model::SingleCgroupModelFieldId::Pressure;
68-
use render::HasRenderConfig;
69-
70-
let rc = model::SingleCgroupModel::get_render_config_builder(field_id);
71-
match field_id {
72-
Name => rc.indented_prefix(get_prefix(false)),
73-
Cpu(ThrottledPct) => rc.title("Throttled Pct"),
74-
Io(RbytesPerSec) => rc.title("RBytes"),
75-
Io(WbytesPerSec) => rc.title("WBytes"),
76-
Io(DbytesPerSec) => rc.title("DBytes"),
77-
Io(RiosPerSec) => rc.title("R I/O"),
78-
Io(WiosPerSec) => rc.title("W I/O"),
79-
Io(DiosPerSec) => rc.title("D I/O"),
80-
Io(RwbytesPerSec) => rc.title("RW Total"),
81-
Io(CostUsagePct) => rc.title("Cost Usage"),
82-
Io(CostWaitPct) => rc.title("Cost Wait"),
83-
Io(CostIndebtPct) => rc.title("Cost Indebt"),
84-
Io(CostIndelayPct) => rc.title("Cost Indelay"),
85-
Mem(Total) => rc.title("Mem Total"),
86-
Mem(Swap) => rc.title("Mem Swap"),
87-
Mem(Zswap) => rc.title("Mem Zswap"),
88-
Mem(Anon) => rc.title("Mem Anon"),
89-
Mem(File) => rc.title("Mem File"),
90-
Mem(Slab) => rc.title("Mem Slab"),
91-
Mem(Sock) => rc.title("Mem Sock"),
92-
Mem(Shmem) => rc.title("Mem Shmem"),
93-
Mem(Pgfault) => rc.title("Pgfault"),
94-
Mem(Pgmajfault) => rc.title("Pgmajfault"),
95-
Mem(WorkingsetRefaultAnon) => rc.title("Workingset Refault Anon"),
96-
Mem(WorkingsetRefaultFile) => rc.title("Workingset Refault File"),
97-
Mem(WorkingsetActivateAnon) => rc.title("Workingset Activate Anon"),
98-
Mem(WorkingsetActivateFile) => rc.title("Workingset Activate File"),
99-
Mem(WorkingsetRestoreAnon) => rc.title("Workingset Restore Anon"),
100-
Mem(WorkingsetRestoreFile) => rc.title("Workingset Restore File"),
101-
Mem(WorkingsetNodereclaim) => rc.title("Workingset Nodereclaim"),
102-
Mem(Pgrefill) => rc.title("Pgrefill"),
103-
Mem(Pgscan) => rc.title("Pgscan"),
104-
Mem(Pgsteal) => rc.title("Pgsteal"),
105-
Mem(Pgactivate) => rc.title("Pgactivate"),
106-
Mem(Pgdeactivate) => rc.title("Pgdeactivate"),
107-
Mem(Pglazyfree) => rc.title("Pglazyfree"),
108-
Mem(Pglazyfreed) => rc.title("Pglazyfreed"),
109-
Mem(ThpFaultAlloc) => rc.title("THP Fault Alloc"),
110-
Mem(ThpCollapseAlloc) => rc.title("THP Collapse Alloc"),
111-
Pressure(MemorySomePct) => rc.title("Mem Some Pressure"),
112-
Pressure(MemoryFullPct) => rc.title("Mem Pressure"),
113-
_ => rc,
114-
}
115-
.get()
116-
}
117-
}
118-
11919
pub struct Cgroup {
12020
opts: GeneralOpt,
12121
select: Option<SingleCgroupModelFieldId>,
@@ -213,6 +113,11 @@ impl Dumper for Cgroup {
213113
*jval = print::dump_json(&handle.fields, ctx, cgroup, handle.opts.raw);
214114
jval["children"] = json!([]);
215115
}
116+
Some(OutputFormat::OpenMetrics) => write!(
117+
output,
118+
"{}",
119+
print::dump_openmetrics(&handle.fields, ctx, cgroup)
120+
)?,
216121
};
217122
*round += 1;
218123
}

below/dump/src/command.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -979,6 +979,7 @@ make_option! (OutputFormat {
979979
"tsv": Tsv,
980980
"json": Json,
981981
"kv": KeyVal,
982+
"openmetrics": OpenMetrics,
982983
});
983984

984985
#[derive(Debug, Parser, Default, Clone)]
@@ -1019,7 +1020,7 @@ pub struct GeneralOpt {
10191020
/// Repeat title, for each N line, it will render a line of title. Only for raw output format.
10201021
#[clap(long = "repeat-title")]
10211022
pub repeat_title: Option<usize>,
1022-
/// Output format. Choose from raw, csv, tsv, kv, json. Default to raw
1023+
/// Output format. Choose from raw, csv, tsv, kv, json, openmetrics. Default to raw
10231024
#[clap(long, short = 'O')]
10241025
pub output_format: Option<OutputFormat>,
10251026
/// Output destination, default to stdout.

below/dump/src/disk.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ use model::SingleDiskModelFieldId;
1616

1717
use super::*;
1818

19-
impl HasRenderConfigForDump for model::SingleDiskModel {}
20-
2119
pub struct Disk {
2220
opts: GeneralOpt,
2321
select: Option<SingleDiskModelFieldId>,
@@ -80,7 +78,6 @@ impl Dumper for Disk {
8078
disks.truncate(self.opts.top as usize);
8179
}
8280
}
83-
let json = self.opts.output_format == Some(OutputFormat::Json);
8481
let mut json_output = json!([]);
8582

8683
disks
@@ -133,15 +130,21 @@ impl Dumper for Disk {
133130
let par = print::dump_json(&self.fields, ctx, model, self.opts.raw);
134131
json_output.as_array_mut().unwrap().push(par);
135132
}
133+
Some(OutputFormat::OpenMetrics) => write!(
134+
output,
135+
"{}",
136+
print::dump_openmetrics(&self.fields, ctx, model)
137+
)?,
136138
}
137139
*round += 1;
138140
Ok(())
139141
})
140142
.collect::<Result<Vec<_>>>()?;
141143

142-
match (json, comma_flag) {
143-
(true, true) => write!(output, ",{}", json_output)?,
144-
(true, false) => write!(output, "{}", json_output)?,
144+
match (self.opts.output_format, comma_flag) {
145+
(Some(OutputFormat::Json), true) => write!(output, ",{}", json_output)?,
146+
(Some(OutputFormat::Json), false) => write!(output, "{}", json_output)?,
147+
(Some(OutputFormat::OpenMetrics), _) => (),
145148
_ => write!(output, "\n")?,
146149
};
147150

below/dump/src/iface.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ use model::SingleNetModelFieldId;
1616

1717
use super::*;
1818

19-
impl HasRenderConfigForDump for model::SingleNetModel {}
20-
2119
pub struct Iface {
2220
opts: GeneralOpt,
2321
select: Option<SingleNetModelFieldId>,
@@ -47,7 +45,6 @@ impl Dumper for Iface {
4745
round: &mut usize,
4846
comma_flag: bool,
4947
) -> Result<IterExecResult> {
50-
let json = self.opts.output_format == Some(OutputFormat::Json);
5148
let mut json_output = json!([]);
5249

5350
model
@@ -116,15 +113,21 @@ impl Dumper for Iface {
116113
let par = print::dump_json(&self.fields, ctx, model, self.opts.raw);
117114
json_output.as_array_mut().unwrap().push(par);
118115
}
116+
Some(OutputFormat::OpenMetrics) => write!(
117+
output,
118+
"{}",
119+
print::dump_openmetrics(&self.fields, ctx, model)
120+
)?,
119121
}
120122
*round += 1;
121123
Ok(())
122124
})
123125
.collect::<Result<Vec<_>>>()?;
124126

125-
match (json, comma_flag) {
126-
(true, true) => write!(output, ",{}", json_output)?,
127-
(true, false) => write!(output, "{}", json_output)?,
127+
match (self.opts.output_format, comma_flag) {
128+
(Some(OutputFormat::Json), true) => write!(output, ",{}", json_output)?,
129+
(Some(OutputFormat::Json), false) => write!(output, "{}", json_output)?,
130+
(Some(OutputFormat::OpenMetrics), _) => (),
128131
_ => write!(output, "\n")?,
129132
};
130133

below/dump/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ use command::expand_fields;
6262
pub use command::DumpCommand;
6363
use command::GeneralOpt;
6464
use command::OutputFormat;
65-
use print::HasRenderConfigForDump;
65+
use render::HasRenderConfigForDump;
6666
use tmain::dump_timeseries;
6767
use tmain::Dumper;
6868
use tmain::IterExecResult;
@@ -85,6 +85,7 @@ pub enum CommonField {
8585
/// Context for initializing CommonFields.
8686
pub struct CommonFieldContext {
8787
pub timestamp: i64,
88+
pub hostname: String,
8889
}
8990

9091
impl CommonField {

below/dump/src/network.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@
1414

1515
use super::*;
1616

17-
impl HasRenderConfigForDump for model::NetworkModel {}
18-
1917
pub struct Network {
2018
opts: GeneralOpt,
2119
fields: Vec<NetworkField>,
@@ -91,12 +89,19 @@ impl Dumper for Network {
9189
write!(output, "{}", json_output)?;
9290
}
9391
}
92+
Some(OutputFormat::OpenMetrics) => write!(
93+
output,
94+
"{}",
95+
print::dump_openmetrics(&self.fields, ctx, &model.network)
96+
)?,
9497
};
9598
*round += 1;
9699

97-
if self.opts.output_format != Some(OutputFormat::Json) {
98-
write!(output, "\n")?;
100+
match &self.opts.output_format {
101+
Some(OutputFormat::Json) | Some(OutputFormat::OpenMetrics) => (),
102+
_ => write!(output, "\n")?,
99103
}
104+
100105
Ok(IterExecResult::Success)
101106
}
102107
}

0 commit comments

Comments
 (0)