below_render/
default_configs.rs

1// Copyright (c) Facebook, Inc. and its affiliates.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use model::ProcessModelFieldId;
16use model::SingleCgroupModelFieldId;
17use model::SingleProcessModelFieldId;
18use RenderFormat::Duration;
19use RenderFormat::MaxOrDuration;
20use RenderFormat::MaxOrReadableSize;
21use RenderFormat::PageReadableSize;
22use RenderFormat::Precision;
23use RenderFormat::ReadableSize;
24use RenderFormat::SectorReadableSize;
25
26use super::*;
27
28impl HasRenderConfig for model::Model {
29    fn get_render_config_builder(field_id: &Self::FieldId) -> RenderConfigBuilder {
30        use model::ModelFieldId::*;
31        let rc = RenderConfigBuilder::new();
32        match field_id {
33            System(field_id) => model::SystemModel::get_render_config_builder(field_id),
34            Cgroup(field_id) => {
35                model::SingleCgroupModel::get_render_config_builder(&field_id.subquery_id.0)
36            }
37            Process(ProcessModelFieldId::Processes(field_id)) => {
38                model::SingleProcessModel::get_render_config_builder(&field_id.subquery_id.0)
39            }
40            Network(field_id) => model::NetworkModel::get_render_config_builder(field_id),
41            Gpu(_) => rc,
42            Resctrl(_) => rc,
43            Tc(_) => rc,
44        }
45    }
46}
47
48impl HasRenderConfig for model::SingleCgroupModel {
49    fn get_render_config_builder(field_id: &Self::FieldId) -> RenderConfigBuilder {
50        use model::SingleCgroupModelFieldId::*;
51        let rc = RenderConfigBuilder::new();
52        match field_id {
53            Name => rc.title("Name").width(50),
54            FullPath => rc.title("Full Path").width(50),
55            InodeNumber => rc.title("Inode Number"),
56            Cpu(field_id) => model::CgroupCpuModel::get_render_config_builder(field_id),
57            Io(field_id) => model::CgroupIoModel::get_render_config_builder(field_id),
58            IoDetails(field_id) => {
59                model::CgroupIoModel::get_render_config_builder(&field_id.subquery_id.0)
60            }
61            Mem(field_id) => model::CgroupMemoryModel::get_render_config_builder(field_id),
62            Pressure(field_id) => model::CgroupPressureModel::get_render_config_builder(field_id),
63            CgroupStat(field_id) => model::CgroupStatModel::get_render_config_builder(field_id),
64            MemNuma(field_id) => {
65                model::CgroupMemoryNumaModel::get_render_config_builder(&field_id.subquery_id.0)
66            }
67            Props(field_id) => model::CgroupProperties::get_render_config_builder(field_id),
68            Pids(field_id) => model::CgroupPidsModel::get_render_config_builder(field_id),
69        }
70    }
71}
72
73impl HasRenderConfigForDump for model::SingleCgroupModel {
74    fn get_render_config_for_dump(field_id: &SingleCgroupModelFieldId) -> RenderConfig {
75        use common::util::get_prefix;
76        use model::CgroupCpuModelFieldId::ThrottledPct;
77        use model::CgroupIoModelFieldId::CostIndebtPct;
78        use model::CgroupIoModelFieldId::CostIndelayPct;
79        use model::CgroupIoModelFieldId::CostUsagePct;
80        use model::CgroupIoModelFieldId::CostWaitPct;
81        use model::CgroupIoModelFieldId::DbytesPerSec;
82        use model::CgroupIoModelFieldId::DiosPerSec;
83        use model::CgroupIoModelFieldId::RbytesPerSec;
84        use model::CgroupIoModelFieldId::RiosPerSec;
85        use model::CgroupIoModelFieldId::RwbytesPerSec;
86        use model::CgroupIoModelFieldId::WbytesPerSec;
87        use model::CgroupIoModelFieldId::WiosPerSec;
88        use model::CgroupMemoryModelFieldId::Anon;
89        use model::CgroupMemoryModelFieldId::File;
90        use model::CgroupMemoryModelFieldId::Pgactivate;
91        use model::CgroupMemoryModelFieldId::Pgdeactivate;
92        use model::CgroupMemoryModelFieldId::Pgfault;
93        use model::CgroupMemoryModelFieldId::Pglazyfree;
94        use model::CgroupMemoryModelFieldId::Pglazyfreed;
95        use model::CgroupMemoryModelFieldId::Pgmajfault;
96        use model::CgroupMemoryModelFieldId::Pgrefill;
97        use model::CgroupMemoryModelFieldId::Pgscan;
98        use model::CgroupMemoryModelFieldId::Pgsteal;
99        use model::CgroupMemoryModelFieldId::Shmem;
100        use model::CgroupMemoryModelFieldId::Slab;
101        use model::CgroupMemoryModelFieldId::Sock;
102        use model::CgroupMemoryModelFieldId::Swap;
103        use model::CgroupMemoryModelFieldId::ThpCollapseAlloc;
104        use model::CgroupMemoryModelFieldId::ThpFaultAlloc;
105        use model::CgroupMemoryModelFieldId::Total;
106        use model::CgroupMemoryModelFieldId::WorkingsetActivateAnon;
107        use model::CgroupMemoryModelFieldId::WorkingsetActivateFile;
108        use model::CgroupMemoryModelFieldId::WorkingsetNodereclaim;
109        use model::CgroupMemoryModelFieldId::WorkingsetRefaultAnon;
110        use model::CgroupMemoryModelFieldId::WorkingsetRefaultFile;
111        use model::CgroupMemoryModelFieldId::WorkingsetRestoreAnon;
112        use model::CgroupMemoryModelFieldId::WorkingsetRestoreFile;
113        use model::CgroupMemoryModelFieldId::Zswap;
114        use model::CgroupMemoryModelFieldId::Zswapped;
115        use model::CgroupPressureModelFieldId::MemoryFullPct;
116        use model::CgroupPressureModelFieldId::MemorySomePct;
117        use model::SingleCgroupModelFieldId::Cpu;
118        use model::SingleCgroupModelFieldId::Io;
119        use model::SingleCgroupModelFieldId::Mem;
120        use model::SingleCgroupModelFieldId::Name;
121        use model::SingleCgroupModelFieldId::Pressure;
122
123        let rc = model::SingleCgroupModel::get_render_config_builder(field_id);
124        match field_id {
125            Name => rc.indented_prefix(get_prefix(false)),
126            Cpu(ThrottledPct) => rc.title("Throttled Pct"),
127            Io(RbytesPerSec) => rc.title("RBytes"),
128            Io(WbytesPerSec) => rc.title("WBytes"),
129            Io(DbytesPerSec) => rc.title("DBytes"),
130            Io(RiosPerSec) => rc.title("R I/O"),
131            Io(WiosPerSec) => rc.title("W I/O"),
132            Io(DiosPerSec) => rc.title("D I/O"),
133            Io(RwbytesPerSec) => rc.title("RW Total"),
134            Io(CostUsagePct) => rc.title("Cost Usage"),
135            Io(CostWaitPct) => rc.title("Cost Wait"),
136            Io(CostIndebtPct) => rc.title("Cost Indebt"),
137            Io(CostIndelayPct) => rc.title("Cost Indelay"),
138            Mem(Total) => rc.title("Mem Total"),
139            Mem(Swap) => rc.title("Mem Swap"),
140            Mem(Anon) => rc.title("Mem Anon"),
141            Mem(File) => rc.title("Mem File"),
142            Mem(Slab) => rc.title("Mem Slab"),
143            Mem(Sock) => rc.title("Mem Sock"),
144            Mem(Shmem) => rc.title("Mem Shmem"),
145            Mem(Zswap) => rc.title("Mem Zswap"),
146            Mem(Zswapped) => rc.title("Mem Zswapped"),
147            Mem(Pgfault) => rc.title("Pgfault"),
148            Mem(Pgmajfault) => rc.title("Pgmajfault"),
149            Mem(WorkingsetRefaultAnon) => rc.title("Workingset Refault Anon"),
150            Mem(WorkingsetRefaultFile) => rc.title("Workingset Refault File"),
151            Mem(WorkingsetActivateAnon) => rc.title("Workingset Activate Anon"),
152            Mem(WorkingsetActivateFile) => rc.title("Workingset Activate File"),
153            Mem(WorkingsetRestoreAnon) => rc.title("Workingset Restore Anon"),
154            Mem(WorkingsetRestoreFile) => rc.title("Workingset Restore File"),
155            Mem(WorkingsetNodereclaim) => rc.title("Workingset Nodereclaim"),
156            Mem(Pgrefill) => rc.title("Pgrefill"),
157            Mem(Pgscan) => rc.title("Pgscan"),
158            Mem(Pgsteal) => rc.title("Pgsteal"),
159            Mem(Pgactivate) => rc.title("Pgactivate"),
160            Mem(Pgdeactivate) => rc.title("Pgdeactivate"),
161            Mem(Pglazyfree) => rc.title("Pglazyfree"),
162            Mem(Pglazyfreed) => rc.title("Pglazyfreed"),
163            Mem(ThpFaultAlloc) => rc.title("THP Fault Alloc"),
164            Mem(ThpCollapseAlloc) => rc.title("THP Collapse Alloc"),
165            Pressure(MemorySomePct) => rc.title("Mem Some Pressure"),
166            Pressure(MemoryFullPct) => rc.title("Mem Pressure"),
167            _ => rc,
168        }
169        .get()
170    }
171
172    fn get_openmetrics_config_for_dump(
173        &self,
174        field_id: &Self::FieldId,
175    ) -> Option<RenderOpenMetricsConfigBuilder> {
176        use model::CgroupCpuModelFieldId::*;
177        use model::CgroupIoModelFieldId::*;
178        use model::CgroupMemoryModelFieldId::*;
179        use model::CgroupPidsModelFieldId::*;
180        use model::CgroupPressureModelFieldId::*;
181        use model::CgroupStatModelFieldId::*;
182        use model::SingleCgroupModelFieldId::*;
183
184        let counter = counter().label("cgroup", &self.full_path);
185        let gauge = gauge().label("cgroup", &self.full_path);
186        match field_id {
187            // We only use full path for the label to avoid ambiguity
188            Name => None,
189            // We will label each metric with the full path
190            FullPath => None,
191            // Not sure what to do with static fields like inode number so leave out for now
192            InodeNumber => None,
193            Cpu(field_id) => match field_id {
194                UsagePct => Some(gauge.unit("percent")),
195                UserPct => Some(gauge.unit("percent")),
196                SystemPct => Some(gauge.unit("percent")),
197                NrPeriodsPerSec => Some(gauge),
198                NrThrottledPerSec => Some(gauge),
199                ThrottledPct => Some(gauge.unit("percent")),
200            },
201            Pids(field_id) => match field_id {
202                TidsCurrent => Some(counter.unit("count")),
203            },
204            Io(field_id) => match field_id {
205                RbytesPerSec => Some(gauge.unit("bytes_per_second")),
206                WbytesPerSec => Some(gauge.unit("bytes_per_second")),
207                RiosPerSec => Some(gauge),
208                WiosPerSec => Some(gauge),
209                DbytesPerSec => Some(gauge.unit("bytes_per_second")),
210                DiosPerSec => Some(gauge),
211                RwbytesPerSec => Some(gauge.unit("bytes_per_second")),
212                CostUsagePct => Some(gauge.unit("percent")),
213                CostWaitPct => Some(gauge.unit("percent")),
214                CostIndebtPct => Some(gauge.unit("percent")),
215                CostIndelayPct => Some(gauge.unit("percent")),
216            },
217            Mem(field_id) => match field_id {
218                Total => Some(counter.unit("bytes")),
219                Swap => Some(counter.unit("bytes")),
220                // Not sure what to do about min/low/high/max values b/c they're neither
221                // counters nor gauges. So leave out for now.
222                EventsLow => None,
223                EventsHigh => None,
224                EventsMax => None,
225                EventsOom => Some(counter),
226                EventsOomKill => Some(counter),
227                EventsLocalLow => None,
228                EventsLocalHigh => None,
229                EventsLocalMax => None,
230                EventsLocalOom => Some(counter),
231                EventsLocalOomKill => Some(counter),
232                Anon => Some(gauge.unit("bytes")),
233                File => Some(gauge.unit("bytes")),
234                Kernel => Some(gauge.unit("bytes")),
235                KernelStack => Some(gauge.unit("bytes")),
236                Slab => Some(gauge.unit("bytes")),
237                Sock => Some(gauge.unit("bytes")),
238                Shmem => Some(gauge.unit("bytes")),
239                Zswap => Some(counter.unit("bytes")),
240                Zswapped => Some(gauge.unit("bytes")),
241                FileMapped => Some(gauge.unit("bytes")),
242                FileDirty => Some(gauge.unit("bytes")),
243                FileWriteback => Some(gauge.unit("bytes")),
244                AnonThp => Some(gauge.unit("bytes")),
245                InactiveAnon => Some(gauge.unit("bytes")),
246                ActiveAnon => Some(gauge.unit("bytes")),
247                InactiveFile => Some(gauge.unit("bytes")),
248                ActiveFile => Some(gauge.unit("bytes")),
249                Unevictable => Some(gauge.unit("bytes")),
250                SlabReclaimable => Some(gauge.unit("bytes")),
251                SlabUnreclaimable => Some(gauge.unit("bytes")),
252                Pgfault => Some(gauge.help("Page faults per second")),
253                Pgmajfault => Some(gauge.help("Major page faults per second")),
254                WorkingsetRefaultAnon => Some(gauge.help("Workingset refault anon per second")),
255                WorkingsetRefaultFile => Some(gauge.help("Workingset refault file per second")),
256                WorkingsetActivateAnon => Some(gauge.help("Workingset activate anon per second")),
257                WorkingsetActivateFile => Some(gauge.help("Workingset activate file per second")),
258                WorkingsetRestoreAnon => Some(gauge.help("Workingset restore anon per second")),
259                WorkingsetRestoreFile => Some(gauge.help("Workingset restore file per second")),
260                WorkingsetNodereclaim => Some(gauge.help("Workingset nodereclaim per second")),
261                Pgrefill => Some(gauge.help("Pgrefill per second")),
262                Pgscan => Some(gauge.help("Pgscan per second")),
263                Pgsteal => Some(gauge.help("Pgsteal per second")),
264                Pgactivate => Some(gauge.help("Pgactivate per second")),
265                Pgdeactivate => Some(gauge.help("Pgdeactivate per second")),
266                Pglazyfree => Some(gauge.help("Pglazyfree per second")),
267                Pglazyfreed => Some(gauge.help("Pglazyfreed per second")),
268                ThpFaultAlloc => Some(gauge.help("THP Fault Alloc per second")),
269                ThpCollapseAlloc => Some(gauge.help("THP Collapse Alloc per second")),
270            },
271            Pressure(field_id) => match field_id {
272                CpuSomePct => Some(gauge.unit("percent")),
273                CpuFullPct => Some(gauge.unit("percent")),
274                IoSomePct => Some(gauge.unit("percent")),
275                IoFullPct => Some(gauge.unit("percent")),
276                MemorySomePct => Some(gauge.unit("percent")),
277                MemoryFullPct => Some(gauge.unit("percent")),
278            },
279            CgroupStat(field_id) => match field_id {
280                NrDescendants => Some(counter),
281                NrDyingDescendants => Some(counter),
282            },
283            // Unclear how to represent numa nodes. Doesn't seem super useful so leave out for now.
284            MemNuma(_) => None,
285            // These are all settings rather than counters/gauges, so not sure how to represent
286            // these. Leave out for now.
287            Props(_) => None,
288            // Looks like these represent child IO data. Not sure it's necessary to report this
289            // as dump does not even pretend to form a hierarchy.
290            IoDetails(_) => None,
291        }
292    }
293}
294
295impl HasRenderConfig for model::CgroupCpuModel {
296    fn get_render_config_builder(field_id: &Self::FieldId) -> RenderConfigBuilder {
297        use model::CgroupCpuModelFieldId::*;
298        let rc = RenderConfigBuilder::new();
299        match field_id {
300            UsagePct => rc.title("CPU Usage").suffix("%").format(Precision(2)),
301            UserPct => rc.title("CPU User").suffix("%").format(Precision(2)),
302            SystemPct => rc.title("CPU Sys").suffix("%").format(Precision(2)),
303            NrPeriodsPerSec => rc.title("Nr Period").suffix("/s").format(Precision(2)),
304            NrThrottledPerSec => rc.title("Nr Throttled").suffix("/s").format(Precision(2)),
305            ThrottledPct => rc.title("Throttled").suffix("%").format(Precision(2)),
306        }
307    }
308}
309
310impl HasRenderConfig for model::CgroupPidsModel {
311    fn get_render_config_builder(field_id: &Self::FieldId) -> RenderConfigBuilder {
312        use model::CgroupPidsModelFieldId::*;
313        let rc = RenderConfigBuilder::new();
314        match field_id {
315            TidsCurrent => rc.title("Tids Current").format(Precision(1)),
316        }
317    }
318}
319
320impl HasRenderConfig for model::CgroupIoModel {
321    fn get_render_config_builder(field_id: &Self::FieldId) -> RenderConfigBuilder {
322        use model::CgroupIoModelFieldId::*;
323        let rc = RenderConfigBuilder::new();
324        match field_id {
325            RbytesPerSec => rc.title("Reads").suffix("/s").format(ReadableSize),
326            WbytesPerSec => rc.title("Writes").suffix("/s").format(ReadableSize),
327            RiosPerSec => rc.title("Read IOPS").format(Precision(1)),
328            WiosPerSec => rc.title("Write IOPS").format(Precision(1)),
329            DbytesPerSec => rc.title("Discards").suffix("/s").format(ReadableSize),
330            DiosPerSec => rc.title("Discard IOPS").format(Precision(1)),
331            RwbytesPerSec => rc.title("RW Total").suffix("/s").format(ReadableSize),
332            CostUsagePct => rc.title("Cost Usage").suffix("%").format(Precision(2)),
333            CostWaitPct => rc.title("Cost Wait").suffix("%").format(Precision(2)),
334            CostIndebtPct => rc.title("Cost Indebt").suffix("%").format(Precision(2)),
335            CostIndelayPct => rc.title("Cost Indelay").suffix("%").format(Precision(2)),
336        }
337    }
338}
339
340impl HasRenderConfig for model::CgroupMemoryModel {
341    fn get_render_config_builder(field_id: &Self::FieldId) -> RenderConfigBuilder {
342        use model::CgroupMemoryModelFieldId::*;
343        let rc = RenderConfigBuilder::new();
344        match field_id {
345            Total => rc.title("Mem").format(ReadableSize),
346            Swap => rc.title("Mem Swap").format(ReadableSize),
347            EventsLow => rc.title("Events Low/s"),
348            EventsHigh => rc.title("Events High/s"),
349            EventsMax => rc.title("Events Max/s"),
350            EventsOom => rc.title("Events OOM/s"),
351            EventsOomKill => rc.title("Events Kill/s"),
352            EventsLocalLow => rc.title("Events Local Low/s"),
353            EventsLocalHigh => rc.title("Events Local High/s"),
354            EventsLocalMax => rc.title("Events Local Max/s"),
355            EventsLocalOom => rc.title("Events Local OOM/s"),
356            EventsLocalOomKill => rc.title("Events Local Kill/s"),
357            Anon => rc.title("Anon").format(ReadableSize),
358            File => rc.title("File").format(ReadableSize),
359            Kernel => rc.title("Kernel").format(ReadableSize),
360            KernelStack => rc.title("Kernel Stack").format(ReadableSize),
361            Slab => rc.title("Slab").format(ReadableSize),
362            Sock => rc.title("Sock").format(ReadableSize),
363            Shmem => rc.title("Shmem").format(ReadableSize),
364            Zswap => rc.title("Zswap").format(ReadableSize),
365            Zswapped => rc.title("Zswapped").format(ReadableSize),
366            FileMapped => rc.title("File Mapped").format(ReadableSize),
367            FileDirty => rc.title("File Dirty").format(ReadableSize),
368            FileWriteback => rc.title("File WB").format(ReadableSize),
369            AnonThp => rc.title("Anon THP").format(ReadableSize),
370            InactiveAnon => rc.title("Inactive Anon").format(ReadableSize),
371            ActiveAnon => rc.title("Active Anon").format(ReadableSize),
372            InactiveFile => rc.title("Inactive File").format(ReadableSize),
373            ActiveFile => rc.title("Active File").format(ReadableSize),
374            Unevictable => rc.title("Unevictable").format(ReadableSize),
375            SlabReclaimable => rc.title("Slab Reclaimable").format(ReadableSize),
376            SlabUnreclaimable => rc.title("Slab Unreclaimable").format(ReadableSize),
377            Pgfault => rc.title("Pgfault/s"),
378            Pgmajfault => rc.title("Pgmajfault/s"),
379            WorkingsetRefaultAnon => rc.title("WS Rflt Anon/s"),
380            WorkingsetRefaultFile => rc.title("WS Rflt File/s"),
381            WorkingsetActivateAnon => rc.title("WS Actv Anon/s"),
382            WorkingsetActivateFile => rc.title("WS Actv File/s"),
383            WorkingsetRestoreAnon => rc.title("WS Rstr Anon/s"),
384            WorkingsetRestoreFile => rc.title("WS Rstr File/s"),
385            WorkingsetNodereclaim => rc.title("WS Nodereclaim/s"),
386            Pgrefill => rc.title("Pgrefill/s"),
387            Pgscan => rc.title("Pgscan/s"),
388            Pgsteal => rc.title("Pgsteal/s"),
389            Pgactivate => rc.title("Pgactivate/s"),
390            Pgdeactivate => rc.title("Pgdeactivate/s"),
391            Pglazyfree => rc.title("Pglazyfree/s"),
392            Pglazyfreed => rc.title("Pglazyfreed/s"),
393            ThpFaultAlloc => rc.title("THP Fault Alloc/s"),
394            ThpCollapseAlloc => rc.title("THP Collapse Alloc/s"),
395        }
396    }
397}
398
399impl HasRenderConfig for model::CgroupPressureModel {
400    fn get_render_config_builder(field_id: &Self::FieldId) -> RenderConfigBuilder {
401        use model::CgroupPressureModelFieldId::*;
402        let rc = RenderConfigBuilder::new();
403        match field_id {
404            CpuSomePct => rc
405                .title("CPU Some Pressure")
406                .suffix("%")
407                .format(Precision(2)),
408            CpuFullPct => rc.title("CPU Pressure").suffix("%").format(Precision(2)),
409            IoSomePct => rc
410                .title("I/O Some Pressure")
411                .suffix("%")
412                .format(Precision(2)),
413            IoFullPct => rc.title("I/O Pressure").suffix("%").format(Precision(2)),
414            MemorySomePct => rc
415                .title("Mem Some Pressure")
416                .suffix("%")
417                .format(Precision(2)),
418            MemoryFullPct => rc.title("Mem Pressure").suffix("%").format(Precision(2)),
419        }
420    }
421}
422
423impl HasRenderConfig for model::NetworkModel {
424    fn get_render_config_builder(field_id: &Self::FieldId) -> RenderConfigBuilder {
425        use model::NetworkModelFieldId::*;
426        match field_id {
427            Interfaces(field_id) => {
428                model::SingleNetModel::get_render_config_builder(&field_id.subquery_id.0)
429            }
430            Tcp(field_id) => model::TcpModel::get_render_config_builder(field_id),
431            Ip(field_id) => model::IpModel::get_render_config_builder(field_id),
432            Ip6(field_id) => model::Ip6Model::get_render_config_builder(field_id),
433            Icmp(field_id) => model::IcmpModel::get_render_config_builder(field_id),
434            Icmp6(field_id) => model::Icmp6Model::get_render_config_builder(field_id),
435            Udp(field_id) => model::UdpModel::get_render_config_builder(field_id),
436            Udp6(field_id) => model::Udp6Model::get_render_config_builder(field_id),
437        }
438    }
439}
440
441impl HasRenderConfigForDump for model::NetworkModel {
442    fn get_openmetrics_config_for_dump(
443        &self,
444        field_id: &Self::FieldId,
445    ) -> Option<RenderOpenMetricsConfigBuilder> {
446        use model::NetworkModelFieldId::*;
447        match field_id {
448            // Do not dump interfaces from network model b/c there is already the `iface` category.
449            // It is also hard to figure out exactly which interface is being queried from here.
450            // Meaning we cannot label the metric with the proper interface.
451            Interfaces(_) => None,
452            Tcp(field_id) => self.tcp.get_openmetrics_config_for_dump(field_id),
453            Ip(field_id) => self.ip.get_openmetrics_config_for_dump(field_id),
454            Ip6(field_id) => self.ip6.get_openmetrics_config_for_dump(field_id),
455            Icmp(field_id) => self.icmp.get_openmetrics_config_for_dump(field_id),
456            Icmp6(field_id) => self.icmp6.get_openmetrics_config_for_dump(field_id),
457            Udp(field_id) => self.udp.get_openmetrics_config_for_dump(field_id),
458            Udp6(field_id) => self.udp6.get_openmetrics_config_for_dump(field_id),
459        }
460    }
461}
462
463impl HasRenderConfig for model::TcpModel {
464    fn get_render_config_builder(field_id: &Self::FieldId) -> RenderConfigBuilder {
465        use model::TcpModelFieldId::*;
466        let rc = RenderConfigBuilder::new();
467        match field_id {
468            ActiveOpensPerSec => rc.title("TcpActiveOpens/s"),
469            PassiveOpensPerSec => rc.title("TcpPassiveOpens/s"),
470            AttemptFailsPerSec => rc.title("TcpAttemptFails/s"),
471            EstabResetsPerSec => rc.title("TcpEstabResets/s"),
472            CurrEstabConn => rc.title("CurEstabConn"),
473            InSegsPerSec => rc.title("TcpInSegs/s").suffix(" segs"),
474            OutSegsPerSec => rc.title("TcpOutSegs/s").suffix(" segs"),
475            RetransSegsPerSec => rc.title("TcpRetransSegs/s").suffix(" segs"),
476            RetransSegs => rc.title("TcpRetransSegs").suffix(" segs"),
477            InErrs => rc.title("TcpInErrors"),
478            OutRstsPerSec => rc.title("TcpOutRsts/s"),
479            InCsumErrors => rc.title("TcpInCsumErrors"),
480        }
481    }
482}
483
484impl HasRenderConfigForDump for model::TcpModel {
485    fn get_openmetrics_config_for_dump(
486        &self,
487        field_id: &Self::FieldId,
488    ) -> Option<RenderOpenMetricsConfigBuilder> {
489        use model::TcpModelFieldId::*;
490        match field_id {
491            ActiveOpensPerSec => Some(gauge().help("Active opens per second")),
492            PassiveOpensPerSec => Some(gauge().help("Passive opens per second")),
493            AttemptFailsPerSec => Some(gauge().help("Failed attempts per second")),
494            EstabResetsPerSec => Some(gauge()),
495            CurrEstabConn => Some(gauge().help("Current established connections")),
496            InSegsPerSec => Some(gauge()),
497            OutSegsPerSec => Some(gauge()),
498            RetransSegsPerSec => Some(gauge()),
499            RetransSegs => Some(gauge()),
500            InErrs => Some(counter()),
501            OutRstsPerSec => Some(gauge()),
502            InCsumErrors => Some(counter().help("Ingress checksum errors")),
503        }
504    }
505}
506
507impl HasRenderConfig for model::IpModel {
508    fn get_render_config_builder(field_id: &Self::FieldId) -> RenderConfigBuilder {
509        use model::IpModelFieldId::*;
510        let rc = RenderConfigBuilder::new();
511        match field_id {
512            ForwardingPktsPerSec => rc.title("IpForwPkts/s").suffix(" pkts"),
513            InReceivesPktsPerSec => rc.title("IpInPkts/s").suffix(" pkts"),
514            ForwDatagramsPerSec => rc.title("IpForwDatagrams/s"),
515            InDiscardsPktsPerSec => rc.title("IpInDiscardPkts/s").suffix(" pkts"),
516            InDeliversPktsPerSec => rc.title("IpInDeliversPkts/s").suffix(" pkts"),
517            OutRequestsPerSec => rc.title("IpOutReqs/s").suffix(" reqs"),
518            OutDiscardsPktsPerSec => rc.title("IpOutDiscardPkts/s").suffix(" pkts"),
519            OutNoRoutesPktsPerSec => rc.title("IpOutNoRoutesPkts/s").suffix(" pkts"),
520            // IpExt
521            InMcastPktsPerSec => rc.title("IpInMcastPkts/s").suffix(" pkts"),
522            OutMcastPktsPerSec => rc.title("IpOutMcastPkts/s").suffix(" pkts"),
523            InBcastPktsPerSec => rc.title("IpInBcastPkts/s").suffix(" pkts"),
524            OutBcastPktsPerSec => rc.title("IpOutBcastPkts/s").suffix(" pkts"),
525            InOctetsPerSec => rc.title("IpInOctets/s").suffix(" octets"),
526            OutOctetsPerSec => rc.title("IpOutOctets/s").suffix(" octets"),
527            InMcastOctetsPerSec => rc.title("IpInMcastOctets/s").suffix(" octets"),
528            OutMcastOctetsPerSec => rc.title("IpOutMcastOctets/s").suffix(" octets"),
529            InBcastOctetsPerSec => rc.title("IpInBcastOctets/s").suffix(" octets"),
530            OutBcastOctetsPerSec => rc.title("IpOutBcastOctets/s").suffix(" octets"),
531            InNoEctPktsPerSec => rc.title("IpInNoEctPkts/s").suffix(" pkts"),
532        }
533    }
534}
535
536impl HasRenderConfigForDump for model::IpModel {
537    fn get_openmetrics_config_for_dump(
538        &self,
539        field_id: &Self::FieldId,
540    ) -> Option<RenderOpenMetricsConfigBuilder> {
541        use model::IpModelFieldId::*;
542        match field_id {
543            ForwardingPktsPerSec => Some(gauge().help("Forwarded packets per second")),
544            InReceivesPktsPerSec => Some(gauge()),
545            ForwDatagramsPerSec => Some(gauge().help("Forwarded datagrams per second")),
546            InDiscardsPktsPerSec => Some(gauge()),
547            InDeliversPktsPerSec => Some(gauge().help("Locally delivered packets per second")),
548            OutRequestsPerSec => Some(gauge()),
549            OutDiscardsPktsPerSec => Some(gauge()),
550            OutNoRoutesPktsPerSec => Some(gauge()),
551            InMcastPktsPerSec => Some(gauge()),
552            OutMcastPktsPerSec => Some(gauge()),
553            InBcastPktsPerSec => Some(gauge()),
554            OutBcastPktsPerSec => Some(gauge()),
555            InOctetsPerSec => Some(gauge()),
556            OutOctetsPerSec => Some(gauge()),
557            InMcastOctetsPerSec => Some(gauge()),
558            OutMcastOctetsPerSec => Some(gauge()),
559            InBcastOctetsPerSec => Some(gauge()),
560            OutBcastOctetsPerSec => Some(gauge()),
561            InNoEctPktsPerSec => Some(gauge()),
562        }
563    }
564}
565
566impl HasRenderConfig for model::Ip6Model {
567    fn get_render_config_builder(field_id: &Self::FieldId) -> RenderConfigBuilder {
568        use model::Ip6ModelFieldId::*;
569        let rc = RenderConfigBuilder::new();
570        match field_id {
571            InReceivesPktsPerSec => rc.title("Ip6InPkts/s").suffix(" pkts"),
572            InHdrErrors => rc.title("Ip6InHdrErrs"),
573            InNoRoutesPktsPerSec => rc.title("Ip6InNoRoutesPkts/s").suffix(" pkts"),
574            InAddrErrors => rc.title("Ip6InAddrErrs"),
575            InDiscardsPktsPerSec => rc.title("Ip6InDiscardsPkts/s").suffix(" pkts"),
576            InDeliversPktsPerSec => rc.title("Ip6InDeliversPkts/s").suffix(" pkts"),
577            OutForwDatagramsPerSec => rc.title("Ip6ForwDatagrams/s"),
578            OutRequestsPerSec => rc.title("Ip6OutReqs/s").suffix(" reqs"),
579            OutNoRoutesPktsPerSec => rc.title("Ip6OutNoRoutesPkts/s").suffix(" pkts"),
580            InMcastPktsPerSec => rc.title("Ip6InMcastPkts/s").suffix(" pkts"),
581            OutMcastPktsPerSec => rc.title("Ip6OutMcastPkts/s").suffix(" pkts"),
582            InOctetsPerSec => rc.title("Ip6InOctets/s").suffix(" octets"),
583            OutOctetsPerSec => rc.title("Ip6OutOctets/s").suffix(" octets"),
584            InMcastOctetsPerSec => rc.title("Ip6InMcastOctets/s").suffix(" octets"),
585            OutMcastOctetsPerSec => rc.title("Ip6OutMcastOctets/s").suffix(" octets"),
586            InBcastOctetsPerSec => rc.title("Ip6InBcastOctets/s").suffix(" octets"),
587            OutBcastOctetsPerSec => rc.title("Ip6OutBcastOctets/s").suffix(" octets"),
588        }
589    }
590}
591
592impl HasRenderConfigForDump for model::Ip6Model {
593    fn get_openmetrics_config_for_dump(
594        &self,
595        field_id: &Self::FieldId,
596    ) -> Option<RenderOpenMetricsConfigBuilder> {
597        use model::Ip6ModelFieldId::*;
598        match field_id {
599            InReceivesPktsPerSec => Some(gauge()),
600            InHdrErrors => Some(counter()),
601            InNoRoutesPktsPerSec => Some(gauge()),
602            InAddrErrors => Some(counter()),
603            InDiscardsPktsPerSec => Some(gauge()),
604            InDeliversPktsPerSec => Some(gauge()),
605            OutForwDatagramsPerSec => Some(gauge()),
606            OutRequestsPerSec => Some(gauge()),
607            OutNoRoutesPktsPerSec => Some(gauge()),
608            InMcastPktsPerSec => Some(gauge()),
609            OutMcastPktsPerSec => Some(gauge()),
610            InOctetsPerSec => Some(gauge()),
611            OutOctetsPerSec => Some(gauge()),
612            InMcastOctetsPerSec => Some(gauge()),
613            OutMcastOctetsPerSec => Some(gauge()),
614            InBcastOctetsPerSec => Some(gauge()),
615            OutBcastOctetsPerSec => Some(gauge()),
616        }
617    }
618}
619
620impl HasRenderConfig for model::IcmpModel {
621    fn get_render_config_builder(field_id: &Self::FieldId) -> RenderConfigBuilder {
622        use model::IcmpModelFieldId::*;
623        let rc = RenderConfigBuilder::new();
624        match field_id {
625            InMsgsPerSec => rc.title("IcmpInMsg/s").suffix(" msgs"),
626            InErrors => rc.title("IcmpInErrs"),
627            InDestUnreachs => rc.title("IcmpInDestUnreachs"),
628            OutMsgsPerSec => rc.title("IcmpOutMsg/s").suffix(" msgs"),
629            OutErrors => rc.title("IcmpOutErrs"),
630            OutDestUnreachs => rc.title("IcmpOutDestUnreachs"),
631        }
632    }
633}
634
635impl HasRenderConfigForDump for model::IcmpModel {
636    fn get_openmetrics_config_for_dump(
637        &self,
638        field_id: &Self::FieldId,
639    ) -> Option<RenderOpenMetricsConfigBuilder> {
640        use model::IcmpModelFieldId::*;
641        match field_id {
642            InMsgsPerSec => Some(gauge()),
643            InErrors => Some(counter()),
644            InDestUnreachs => Some(counter()),
645            OutMsgsPerSec => Some(gauge()),
646            OutErrors => Some(counter()),
647            OutDestUnreachs => Some(counter()),
648        }
649    }
650}
651
652impl HasRenderConfig for model::Icmp6Model {
653    fn get_render_config_builder(field_id: &Self::FieldId) -> RenderConfigBuilder {
654        use model::Icmp6ModelFieldId::*;
655        let rc = RenderConfigBuilder::new();
656        match field_id {
657            InMsgsPerSec => rc.title("Icmp6InMsg/s").suffix(" msgs"),
658            InErrors => rc.title("Icmp6InErrs"),
659            InDestUnreachs => rc.title("Icmp6InDestUnreachs"),
660            OutMsgsPerSec => rc.title("Icmp6OutMsg/s").suffix(" msgs"),
661            OutErrors => rc.title("Icmp6OutErrs"),
662            OutDestUnreachs => rc.title("Icmp6OutDestUnreachs"),
663        }
664    }
665}
666
667impl HasRenderConfigForDump for model::Icmp6Model {
668    fn get_openmetrics_config_for_dump(
669        &self,
670        field_id: &Self::FieldId,
671    ) -> Option<RenderOpenMetricsConfigBuilder> {
672        use model::Icmp6ModelFieldId::*;
673        match field_id {
674            InMsgsPerSec => Some(gauge()),
675            InErrors => Some(counter()),
676            InDestUnreachs => Some(counter()),
677            OutMsgsPerSec => Some(gauge()),
678            OutErrors => Some(counter()),
679            OutDestUnreachs => Some(counter()),
680        }
681    }
682}
683
684impl HasRenderConfig for model::UdpModel {
685    fn get_render_config_builder(field_id: &Self::FieldId) -> RenderConfigBuilder {
686        use model::UdpModelFieldId::*;
687        let rc = RenderConfigBuilder::new();
688        match field_id {
689            InDatagramsPktsPerSec => rc.title("UdpInPkts/s").suffix(" pkts"),
690            NoPorts => rc.title("UdpNoPorts"),
691            InErrors => rc.title("UdpInErrs"),
692            OutDatagramsPktsPerSec => rc.title("UdpOutPkts/s").suffix(" pkts"),
693            RcvbufErrors => rc.title("UdpRcvbufErrs"),
694            SndbufErrors => rc.title("UdpSndBufErrs"),
695            IgnoredMulti => rc.title("UdpIgnoredMulti"),
696        }
697    }
698}
699
700impl HasRenderConfigForDump for model::UdpModel {
701    fn get_openmetrics_config_for_dump(
702        &self,
703        field_id: &Self::FieldId,
704    ) -> Option<RenderOpenMetricsConfigBuilder> {
705        use model::UdpModelFieldId::*;
706        match field_id {
707            InDatagramsPktsPerSec => Some(gauge()),
708            NoPorts => Some(counter()),
709            InErrors => Some(counter()),
710            OutDatagramsPktsPerSec => Some(gauge()),
711            RcvbufErrors => Some(counter()),
712            SndbufErrors => Some(counter()),
713            IgnoredMulti => Some(counter()),
714        }
715    }
716}
717
718impl HasRenderConfig for model::Udp6Model {
719    fn get_render_config_builder(field_id: &Self::FieldId) -> RenderConfigBuilder {
720        use model::Udp6ModelFieldId::*;
721        let rc = RenderConfigBuilder::new();
722        match field_id {
723            InDatagramsPktsPerSec => rc.title("Udp6InPkts/s").suffix(" pkts"),
724            NoPorts => rc.title("Udp6NoPorts"),
725            InErrors => rc.title("Udp6InErrs"),
726            OutDatagramsPktsPerSec => rc.title("Udp6OutPkts/s").suffix(" pkts"),
727            RcvbufErrors => rc.title("Udp6RcvbufErrs"),
728            SndbufErrors => rc.title("Udp6SndBufErrs"),
729            InCsumErrors => rc.title("Udp6InCsumErrs"),
730            IgnoredMulti => rc.title("Udp6IgnoredMulti"),
731        }
732    }
733}
734
735impl HasRenderConfigForDump for model::Udp6Model {
736    fn get_openmetrics_config_for_dump(
737        &self,
738        field_id: &Self::FieldId,
739    ) -> Option<RenderOpenMetricsConfigBuilder> {
740        use model::Udp6ModelFieldId::*;
741        match field_id {
742            InDatagramsPktsPerSec => Some(gauge()),
743            NoPorts => Some(counter()),
744            InErrors => Some(counter()),
745            OutDatagramsPktsPerSec => Some(gauge()),
746            RcvbufErrors => Some(counter()),
747            SndbufErrors => Some(counter()),
748            InCsumErrors => Some(counter()),
749            IgnoredMulti => Some(counter()),
750        }
751    }
752}
753
754impl HasRenderConfig for model::SingleNetModel {
755    fn get_render_config_builder(field_id: &Self::FieldId) -> RenderConfigBuilder {
756        use model::SingleNetModelFieldId::*;
757        let rc = RenderConfigBuilder::new();
758        match field_id {
759            Interface => rc.title("Interface"),
760            RxBytesPerSec => rc.title("RX Bytes/s").format(ReadableSize),
761            TxBytesPerSec => rc.title("TX Bytes/s").format(ReadableSize),
762            ThroughputPerSec => rc.title("I/O Bytes/s").format(ReadableSize),
763            RxPacketsPerSec => rc.title("RX Pkts/s"),
764            TxPacketsPerSec => rc.title("TX Pkts/s"),
765            Collisions => rc.title("Collisions"),
766            Multicast => rc.title("Multicast"),
767            RxBytes => rc.title("RX Bytes"),
768            RxCompressed => rc.title("RX Compressed"),
769            RxCrcErrors => rc.title("RX CRC Errors"),
770            RxDropped => rc.title("RX Dropped"),
771            RxErrors => rc.title("RX Errors"),
772            RxFifoErrors => rc.title("RX Fifo Errors"),
773            RxFrameErrors => rc.title("RX Frame Errors"),
774            RxLengthErrors => rc.title("RX Length Errors"),
775            RxMissedErrors => rc.title("RX Missed Errors"),
776            RxNohandler => rc.title("RX Nohandler"),
777            RxOverErrors => rc.title("RX Over Errors"),
778            RxPackets => rc.title("RX Packets"),
779            TxAbortedErrors => rc.title("TX Aborted Errors"),
780            TxBytes => rc.title("TX Bytes"),
781            TxCarrierErrors => rc.title("TX Carrier Errors"),
782            TxCompressed => rc.title("TX Compressed"),
783            TxDropped => rc.title("TX Dropped"),
784            TxErrors => rc.title("TX Errors"),
785            TxFifoErrors => rc.title("TX Fifo Errors"),
786            TxHeartbeatErrors => rc.title("TX Heartbeat Errors"),
787            TxPackets => rc.title("TX Packets"),
788            TxWindowErrors => rc.title("TX Window Errors"),
789            TxTimeoutPerSec => rc.title("TX Timeout").suffix("/s"),
790            RawStats => rc.title("Raw Stats"),
791            Queues(field_id) => Vec::<model::SingleQueueModel>::get_render_config_builder(field_id),
792        }
793    }
794}
795
796impl HasRenderConfigForDump for model::SingleNetModel {
797    fn get_openmetrics_config_for_dump(
798        &self,
799        field_id: &Self::FieldId,
800    ) -> Option<RenderOpenMetricsConfigBuilder> {
801        use model::SingleNetModelFieldId::*;
802        let counter = counter().label("interface", &self.interface);
803        let gauge = gauge().label("interface", &self.interface);
804        match field_id {
805            // We label all the other metrics with the interface name
806            Interface => None,
807            RxBytesPerSec => Some(gauge),
808            TxBytesPerSec => Some(gauge),
809            ThroughputPerSec => Some(gauge),
810            RxPacketsPerSec => Some(gauge),
811            TxPacketsPerSec => Some(gauge),
812            Collisions => Some(counter),
813            Multicast => Some(counter),
814            RxBytes => Some(counter),
815            RxCompressed => Some(counter),
816            RxCrcErrors => Some(counter),
817            RxDropped => Some(counter),
818            RxErrors => Some(counter),
819            RxFifoErrors => Some(counter),
820            RxFrameErrors => Some(counter),
821            RxLengthErrors => Some(counter),
822            RxMissedErrors => Some(counter),
823            RxNohandler => Some(counter),
824            RxOverErrors => Some(counter),
825            RxPackets => Some(counter),
826            TxAbortedErrors => Some(counter),
827            TxBytes => Some(counter),
828            TxCarrierErrors => Some(counter),
829            TxCompressed => Some(counter),
830            TxDropped => Some(counter),
831            TxErrors => Some(counter),
832            TxFifoErrors => Some(counter),
833            TxHeartbeatErrors => Some(counter),
834            TxPackets => Some(counter),
835            TxWindowErrors => Some(counter),
836            TxTimeoutPerSec => Some(gauge),
837            RawStats => Some(counter),
838            Queues(field_id) => self.queues.get_openmetrics_config_for_dump(field_id),
839        }
840    }
841}
842
843impl HasRenderConfig for Vec<model::SingleQueueModel> {
844    fn get_render_config_builder(field_id: &Self::FieldId) -> RenderConfigBuilder {
845        let mut rc =
846            model::SingleQueueModel::get_render_config_builder(&field_id.subquery_id.0).get();
847        rc.title = rc.title.map(|title| title.to_string());
848        rc.into()
849    }
850}
851
852impl HasRenderConfigForDump for Vec<model::SingleQueueModel> {
853    fn get_openmetrics_config_for_dump(
854        &self,
855        field_id: &Self::FieldId,
856    ) -> Option<RenderOpenMetricsConfigBuilder> {
857        let idx = field_id
858            .idx
859            .expect("VecFieldId without index should not have render config");
860        self.get(idx)
861            .map(|queue| queue.get_openmetrics_config_for_dump(&field_id.subquery_id.0))?
862    }
863}
864
865impl HasRenderConfig for model::SingleQueueModel {
866    fn get_render_config_builder(field_id: &Self::FieldId) -> RenderConfigBuilder {
867        use model::SingleQueueModelFieldId::*;
868        let rc = RenderConfigBuilder::new();
869        match field_id {
870            Interface => rc.title("Interface"),
871            QueueId => rc.title("Queue"),
872            RxBytesPerSec => rc.title("RxBytes").suffix("/s").format(ReadableSize),
873            TxBytesPerSec => rc.title("TxBytes").suffix("/s").format(ReadableSize),
874            RxCountPerSec => rc.title("RxCount").suffix("/s"),
875            TxCountPerSec => rc.title("TxCount").suffix("/s"),
876            TxMissedTx => rc.title("TxMissedTx"),
877            TxUnmaskInterrupt => rc.title("TxUnmaskInterrupt"),
878            RawStats => rc.title("RawStats"),
879        }
880    }
881}
882
883impl HasRenderConfigForDump for model::SingleQueueModel {
884    fn get_openmetrics_config_for_dump(
885        &self,
886        field_id: &Self::FieldId,
887    ) -> Option<RenderOpenMetricsConfigBuilder> {
888        use model::SingleQueueModelFieldId::*;
889        let counter = counter()
890            .label("interface", &self.interface)
891            .label("queue", &self.queue_id.to_string());
892        let gauge = gauge()
893            .label("interface", &self.interface)
894            .label("queue", &self.queue_id.to_string());
895
896        match field_id {
897            Interface => None,
898            QueueId => None,
899            RxBytesPerSec => Some(gauge.unit("bytes_per_second")),
900            TxBytesPerSec => Some(gauge.unit("bytes_per_second")),
901            RxCountPerSec => Some(gauge),
902            TxCountPerSec => Some(gauge),
903            TxMissedTx => Some(counter),
904            TxUnmaskInterrupt => Some(counter),
905            RawStats => Some(counter),
906        }
907    }
908}
909
910impl HasRenderConfig for model::SingleProcessModel {
911    fn get_render_config_builder(field_id: &Self::FieldId) -> RenderConfigBuilder {
912        use model::SingleProcessModelFieldId::*;
913        let rc = RenderConfigBuilder::new();
914        match field_id {
915            Pid => rc.title("Pid"),
916            Ppid => rc.title("Ppid"),
917            NsTgid => rc.title("NStgid").width(12),
918            Comm => rc.title("Comm").width(30),
919            State => rc.title("State"),
920            UptimeSecs => rc.title("Uptime(sec)"),
921            Cgroup => rc.title("Cgroup").width(50).fold(FoldOption::Name),
922            Io(field_id) => model::ProcessIoModel::get_render_config_builder(field_id),
923            Mem(field_id) => model::ProcessMemoryModel::get_render_config_builder(field_id),
924            Cpu(field_id) => model::ProcessCpuModel::get_render_config_builder(field_id),
925            Cmdline => rc.title("Cmdline").width(50),
926            ExePath => rc.title("Exe Path"),
927        }
928    }
929}
930
931impl HasRenderConfigForDump for model::SingleProcessModel {
932    fn get_render_config_for_dump(field_id: &SingleProcessModelFieldId) -> RenderConfig {
933        use model::ProcessCpuModelFieldId::SystemPct;
934        use model::ProcessCpuModelFieldId::UserPct;
935        use model::ProcessIoModelFieldId::RwbytesPerSec;
936        use model::SingleProcessModelFieldId::Cpu;
937        use model::SingleProcessModelFieldId::Io;
938
939        let rc = model::SingleProcessModel::get_render_config_builder(field_id);
940        match field_id {
941            Cpu(UserPct) => rc.title("User CPU"),
942            Cpu(SystemPct) => rc.title("Sys CPU"),
943            Io(RwbytesPerSec) => rc.title("RW"),
944            _ => rc,
945        }
946        .get()
947    }
948
949    fn get_openmetrics_config_for_dump(
950        &self,
951        field_id: &Self::FieldId,
952    ) -> Option<RenderOpenMetricsConfigBuilder> {
953        use model::ProcessCpuModelFieldId::*;
954        use model::ProcessIoModelFieldId::*;
955        use model::ProcessMemoryModelFieldId::*;
956        use model::SingleProcessModelFieldId::*;
957        let mut counter = counter();
958        let mut gauge = gauge();
959        if let Some(pid) = &self.pid {
960            counter = counter.label("pid", &pid.to_string());
961            gauge = gauge.label("pid", &pid.to_string());
962        }
963        if let Some(comm) = &self.comm {
964            counter = counter.label("comm", comm);
965            gauge = gauge.label("comm", comm);
966        }
967        match field_id {
968            // We will label all the other metrics with the pid
969            Pid => None,
970            // Not sure what to do about static values like ppid. Omitting for now.
971            Ppid => None,
972            // Same as ppid
973            NsTgid => None,
974            // OpenMetrics does not support strings
975            Comm => None,
976            // OpenMetrics does not support strings
977            State => None,
978            UptimeSecs => Some(counter),
979            // OpenMetrics does not support strings
980            Cgroup => None,
981            Io(field_id) => match field_id {
982                RbytesPerSec => Some(gauge),
983                WbytesPerSec => Some(gauge),
984                RwbytesPerSec => Some(gauge),
985            },
986            Mem(field_id) => match field_id {
987                MinorfaultsPerSec => Some(gauge),
988                MajorfaultsPerSec => Some(gauge),
989                RssBytes => Some(gauge.unit("bytes")),
990                VmSize => Some(gauge.unit("bytes")),
991                Lock => Some(gauge.unit("bytes")),
992                Pin => Some(gauge.unit("bytes")),
993                Anon => Some(gauge.unit("bytes")),
994                File => Some(gauge.unit("bytes")),
995                Shmem => Some(gauge.unit("bytes")),
996                Pte => Some(gauge.unit("bytes")),
997                Swap => Some(gauge.unit("bytes")),
998                HugeTlb => Some(gauge.unit("bytes")),
999            },
1000            Cpu(field_id) => match field_id {
1001                UsagePct => Some(gauge.unit("percent")),
1002                UserPct => Some(gauge.unit("percent")),
1003                SystemPct => Some(gauge.unit("percent")),
1004                NumThreads => Some(counter),
1005            },
1006            // OpenMetrics does not support strings
1007            Cmdline => None,
1008            // OpenMetrics does not support strings
1009            ExePath => None,
1010        }
1011    }
1012}
1013
1014impl HasRenderConfig for model::ProcessIoModel {
1015    fn get_render_config_builder(field_id: &Self::FieldId) -> RenderConfigBuilder {
1016        use model::ProcessIoModelFieldId::*;
1017        let rc = RenderConfigBuilder::new();
1018        match field_id {
1019            RbytesPerSec => rc.title("Reads").suffix("/s").format(ReadableSize),
1020            WbytesPerSec => rc.title("Writes").suffix("/s").format(ReadableSize),
1021            RwbytesPerSec => rc.title("RW Total").suffix("/s").format(ReadableSize),
1022        }
1023    }
1024}
1025
1026impl HasRenderConfig for model::ProcessMemoryModel {
1027    fn get_render_config_builder(field_id: &Self::FieldId) -> RenderConfigBuilder {
1028        use model::ProcessMemoryModelFieldId::*;
1029        let rc = RenderConfigBuilder::new();
1030        match field_id {
1031            MinorfaultsPerSec => rc.title("Minflt").format(Precision(2)).suffix("/s"),
1032            MajorfaultsPerSec => rc.title("Majflt").format(Precision(2)).suffix("/s"),
1033            RssBytes => rc.title("RSS").format(ReadableSize),
1034            VmSize => rc.title("VM Size").format(ReadableSize),
1035            Lock => rc.title("Lock").format(ReadableSize),
1036            Pin => rc.title("Pin").format(ReadableSize),
1037            Anon => rc.title("Anon").format(ReadableSize),
1038            File => rc.title("File").format(ReadableSize),
1039            Shmem => rc.title("Shmem").format(ReadableSize),
1040            Pte => rc.title("PTE").format(ReadableSize),
1041            Swap => rc.title("Swap").format(ReadableSize),
1042            HugeTlb => rc.title("Huge TLB").format(ReadableSize),
1043        }
1044    }
1045}
1046
1047impl HasRenderConfig for model::ProcessCpuModel {
1048    fn get_render_config_builder(field_id: &Self::FieldId) -> RenderConfigBuilder {
1049        use model::ProcessCpuModelFieldId::*;
1050        let rc = RenderConfigBuilder::new();
1051        match field_id {
1052            UsagePct => rc.title("CPU").format(Precision(2)).suffix("%"),
1053            UserPct => rc.title("CPU User").format(Precision(2)).suffix("%"),
1054            SystemPct => rc.title("CPU System").format(Precision(2)).suffix("%"),
1055            NumThreads => rc.title("Threads"),
1056        }
1057    }
1058}
1059
1060impl HasRenderConfig for model::SystemModel {
1061    fn get_render_config_builder(field_id: &Self::FieldId) -> RenderConfigBuilder {
1062        use model::SystemModelFieldId::*;
1063        let rc = RenderConfigBuilder::new();
1064        match field_id {
1065            Hostname => rc.title("Hostname").width(20),
1066            KernelVersion => rc.title("Kernel Version").width(50),
1067            OsRelease => rc.title("OS Release").width(50),
1068            Stat(field_id) => model::ProcStatModel::get_render_config_builder(field_id),
1069            Cpu(field_id) => model::SingleCpuModel::get_render_config_builder(field_id),
1070            Cpus(field_id) => {
1071                BTreeMap::<u32, model::SingleCpuModel>::get_render_config_builder(field_id)
1072            }
1073            Mem(field_id) => model::MemoryModel::get_render_config_builder(field_id),
1074            Vm(field_id) => model::VmModel::get_render_config_builder(field_id),
1075            Slab(field_id) => {
1076                model::SingleSlabModel::get_render_config_builder(&field_id.subquery_id.0)
1077            }
1078            Ksm(field_id) => model::KsmModel::get_render_config_builder(field_id),
1079            Disks(field_id) => {
1080                model::SingleDiskModel::get_render_config_builder(&field_id.subquery_id.0)
1081            }
1082            Btrfs(field_id) => {
1083                model::BtrfsModel::get_render_config_builder(&field_id.subquery_id.0)
1084            }
1085        }
1086    }
1087}
1088
1089impl HasRenderConfigForDump for model::SystemModel {
1090    fn get_openmetrics_config_for_dump(
1091        &self,
1092        field_id: &Self::FieldId,
1093    ) -> Option<RenderOpenMetricsConfigBuilder> {
1094        use model::SystemModelFieldId::*;
1095        match field_id {
1096            // We tag all metrics with the hostname already
1097            Hostname => None,
1098            // OpenMetrics does not support strings
1099            KernelVersion => None,
1100            // OpenMetrics does not support strings
1101            OsRelease => None,
1102            Stat(field_id) => self.stat.get_openmetrics_config_for_dump(field_id),
1103            Cpu(field_id) => self.total_cpu.get_openmetrics_config_for_dump(field_id),
1104            Cpus(field_id) => self.cpus.get_openmetrics_config_for_dump(field_id),
1105            Mem(field_id) => self.mem.get_openmetrics_config_for_dump(field_id),
1106            Vm(field_id) => self.vm.get_openmetrics_config_for_dump(field_id),
1107            Slab(_) => None,
1108            Ksm(_) => None,
1109            // Same as with NetworkModel, we leave disk dumping to `disk` category
1110            Disks(_) => None,
1111            // Same as with above, we leave btrfs dumping to `btrfs` category
1112            Btrfs(_) => None,
1113        }
1114    }
1115}
1116
1117impl HasRenderConfig for model::ProcStatModel {
1118    fn get_render_config_builder(field_id: &Self::FieldId) -> RenderConfigBuilder {
1119        use model::ProcStatModelFieldId::*;
1120        let rc = RenderConfigBuilder::new();
1121        match field_id {
1122            TotalInterruptCt => rc.title("Total Interrupts"),
1123            ContextSwitches => rc.title("Context Switches"),
1124            BootTimeEpochSecs => rc.title("Boot Time Epoch"),
1125            TotalProcesses => rc.title("Total Procs"),
1126            RunningProcesses => rc.title("Running Procs"),
1127            BlockedProcesses => rc.title("Blocked Procs"),
1128        }
1129    }
1130}
1131
1132impl HasRenderConfigForDump for model::ProcStatModel {
1133    fn get_openmetrics_config_for_dump(
1134        &self,
1135        field_id: &Self::FieldId,
1136    ) -> Option<RenderOpenMetricsConfigBuilder> {
1137        use model::ProcStatModelFieldId::*;
1138        match field_id {
1139            TotalInterruptCt => Some(counter()),
1140            ContextSwitches => Some(counter()),
1141            BootTimeEpochSecs => Some(counter()),
1142            TotalProcesses => Some(gauge()),
1143            RunningProcesses => Some(gauge()),
1144            BlockedProcesses => Some(gauge()),
1145        }
1146    }
1147}
1148
1149impl HasRenderConfig for model::SingleCpuModel {
1150    fn get_render_config_builder(field_id: &Self::FieldId) -> RenderConfigBuilder {
1151        use model::SingleCpuModelFieldId::*;
1152        let rc = RenderConfigBuilder::new();
1153        match field_id {
1154            Idx => rc.title("Idx"),
1155            UsagePct => rc.title("Usage").suffix("%").format(Precision(2)),
1156            UserPct => rc.title("User").suffix("%").format(Precision(2)),
1157            IdlePct => rc.title("Idle").suffix("%").format(Precision(2)),
1158            SystemPct => rc.title("System").suffix("%").format(Precision(2)),
1159            NicePct => rc.title("Nice").suffix("%").format(Precision(2)),
1160            IowaitPct => rc.title("IOWait").suffix("%").format(Precision(2)),
1161            IrqPct => rc.title("Irq").suffix("%").format(Precision(2)),
1162            SoftirqPct => rc.title("SoftIrq").suffix("%").format(Precision(2)),
1163            StolenPct => rc.title("Stolen").suffix("%").format(Precision(2)),
1164            GuestPct => rc.title("Guest").suffix("%").format(Precision(2)),
1165            GuestNicePct => rc.title("Guest Nice").suffix("%").format(Precision(2)),
1166        }
1167    }
1168}
1169
1170impl HasRenderConfigForDump for model::SingleCpuModel {
1171    fn get_openmetrics_config_for_dump(
1172        &self,
1173        field_id: &Self::FieldId,
1174    ) -> Option<RenderOpenMetricsConfigBuilder> {
1175        use model::SingleCpuModelFieldId::*;
1176        let gauge = gauge().label("cpu", &self.idx.to_string());
1177        match field_id {
1178            // We label each metric with the CPU index
1179            Idx => None,
1180            UsagePct => Some(gauge),
1181            UserPct => Some(gauge),
1182            IdlePct => Some(gauge),
1183            SystemPct => Some(gauge),
1184            NicePct => Some(gauge),
1185            IowaitPct => Some(gauge),
1186            IrqPct => Some(gauge),
1187            SoftirqPct => Some(gauge),
1188            StolenPct => Some(gauge),
1189            GuestPct => Some(gauge),
1190            GuestNicePct => Some(gauge),
1191        }
1192    }
1193}
1194
1195impl HasRenderConfig for BTreeMap<u32, model::SingleCpuModel> {
1196    fn get_render_config_builder(field_id: &Self::FieldId) -> RenderConfigBuilder {
1197        let mut rc =
1198            model::SingleCpuModel::get_render_config_builder(&field_id.subquery_id.0).get();
1199        rc.title = rc.title.map(|title| {
1200            format!(
1201                "CPU {} {}",
1202                field_id
1203                    .idx
1204                    .expect("BTreeMapFieldId without key should not have render config"),
1205                title
1206            )
1207        });
1208        rc.into()
1209    }
1210}
1211
1212impl HasRenderConfigForDump for BTreeMap<u32, model::SingleCpuModel> {
1213    fn get_openmetrics_config_for_dump(
1214        &self,
1215        field_id: &Self::FieldId,
1216    ) -> Option<RenderOpenMetricsConfigBuilder> {
1217        let key = field_id
1218            .idx
1219            .expect("BTreeMapFieldId without key should not have render config");
1220        self.get(&key)
1221            .map(|cpu| cpu.get_openmetrics_config_for_dump(&field_id.subquery_id.0))?
1222    }
1223}
1224
1225impl HasRenderConfig for model::MemoryModel {
1226    fn get_render_config_builder(field_id: &Self::FieldId) -> RenderConfigBuilder {
1227        use model::MemoryModelFieldId::*;
1228        let rc = RenderConfigBuilder::new();
1229        match field_id {
1230            Total => rc.title("Total").format(ReadableSize),
1231            Free => rc.title("Free").format(ReadableSize),
1232            Available => rc.title("Available").format(ReadableSize),
1233            Buffers => rc.title("Buffers").format(ReadableSize),
1234            Cached => rc.title("Cached").format(ReadableSize),
1235            SwapCached => rc.title("Swap Cached").format(ReadableSize),
1236            Active => rc.title("Active").format(ReadableSize),
1237            Inactive => rc.title("Inactive").format(ReadableSize),
1238            Anon => rc.title("Anon").format(ReadableSize),
1239            File => rc.title("File").format(ReadableSize),
1240            Unevictable => rc.title("Unevictable").format(ReadableSize),
1241            Mlocked => rc.title("Mlocked").format(ReadableSize),
1242            SwapTotal => rc.title("Swap Total").format(ReadableSize),
1243            SwapFree => rc.title("Swap Free").format(ReadableSize),
1244            Dirty => rc.title("Dirty").format(ReadableSize),
1245            Writeback => rc.title("Writeback").format(ReadableSize),
1246            AnonPages => rc.title("Anon Pages").format(ReadableSize),
1247            Mapped => rc.title("Mapped").format(ReadableSize),
1248            Shmem => rc.title("Shmem").format(ReadableSize),
1249            Kreclaimable => rc.title("Kreclaimable").format(ReadableSize),
1250            Slab => rc.title("Slab").format(ReadableSize),
1251            SlabReclaimable => rc.title("Slab Reclaimable").format(ReadableSize),
1252            SlabUnreclaimable => rc.title("Slab Unreclaimable").format(ReadableSize),
1253            KernelStack => rc.title("Kernel Stack").format(ReadableSize),
1254            PageTables => rc.title("Page Tables").format(ReadableSize),
1255            AnonHugePagesBytes => rc.title("Anon Huge Pages").format(ReadableSize),
1256            ShmemHugePagesBytes => rc.title("Shmem Huge Pages").format(ReadableSize),
1257            FileHugePagesBytes => rc.title("File Huge Pages").format(ReadableSize),
1258            Hugetlb => rc.title("Hugetlb").format(ReadableSize),
1259            CmaTotal => rc.title("Cma Total").format(ReadableSize),
1260            CmaFree => rc.title("Cma Free").format(ReadableSize),
1261            VmallocTotal => rc.title("Vmalloc Total").format(ReadableSize),
1262            VmallocUsed => rc.title("Vmalloc Used").format(ReadableSize),
1263            VmallocChunk => rc.title("Vmalloc Chunk").format(ReadableSize),
1264            DirectMap4k => rc.title("Direct Map 4K").format(ReadableSize),
1265            DirectMap2m => rc.title("Direct Map 2M").format(ReadableSize),
1266            DirectMap1g => rc.title("Direct Map 1G").format(ReadableSize),
1267        }
1268    }
1269}
1270
1271impl HasRenderConfigForDump for model::MemoryModel {
1272    fn get_openmetrics_config_for_dump(
1273        &self,
1274        field_id: &Self::FieldId,
1275    ) -> Option<RenderOpenMetricsConfigBuilder> {
1276        use model::MemoryModelFieldId::*;
1277        match field_id {
1278            Total => Some(gauge().unit("bytes")),
1279            Free => Some(gauge().unit("bytes")),
1280            Available => Some(gauge().unit("bytes")),
1281            Buffers => Some(gauge().unit("bytes")),
1282            Cached => Some(gauge().unit("bytes")),
1283            SwapCached => Some(gauge().unit("bytes")),
1284            Active => Some(gauge().unit("bytes")),
1285            Inactive => Some(gauge().unit("bytes")),
1286            Anon => Some(gauge().unit("bytes")),
1287            File => Some(gauge().unit("bytes")),
1288            Unevictable => Some(gauge().unit("bytes")),
1289            Mlocked => Some(gauge().unit("bytes")),
1290            SwapTotal => Some(gauge().unit("bytes")),
1291            SwapFree => Some(gauge().unit("bytes")),
1292            Dirty => Some(gauge().unit("bytes")),
1293            Writeback => Some(gauge().unit("bytes")),
1294            AnonPages => Some(gauge().unit("bytes")),
1295            Mapped => Some(gauge().unit("bytes")),
1296            Shmem => Some(gauge().unit("bytes")),
1297            Kreclaimable => Some(gauge().unit("bytes")),
1298            Slab => Some(gauge().unit("bytes")),
1299            SlabReclaimable => Some(gauge().unit("bytes")),
1300            SlabUnreclaimable => Some(gauge().unit("bytes")),
1301            KernelStack => Some(gauge().unit("bytes")),
1302            PageTables => Some(gauge().unit("bytes")),
1303            AnonHugePagesBytes => Some(gauge().unit("bytes")),
1304            ShmemHugePagesBytes => Some(gauge().unit("bytes")),
1305            FileHugePagesBytes => Some(gauge().unit("bytes")),
1306            Hugetlb => Some(gauge().unit("bytes")),
1307            CmaTotal => Some(gauge().unit("bytes")),
1308            CmaFree => Some(gauge().unit("bytes")),
1309            VmallocTotal => Some(gauge().unit("bytes")),
1310            VmallocUsed => Some(gauge().unit("bytes")),
1311            VmallocChunk => Some(gauge().unit("bytes")),
1312            DirectMap4k => Some(gauge().unit("bytes")),
1313            DirectMap2m => Some(gauge().unit("bytes")),
1314            DirectMap1g => Some(gauge().unit("bytes")),
1315        }
1316    }
1317}
1318
1319impl HasRenderConfig for model::VmModel {
1320    fn get_render_config_builder(field_id: &Self::FieldId) -> RenderConfigBuilder {
1321        use model::VmModelFieldId::*;
1322        let rc = RenderConfigBuilder::new();
1323        match field_id {
1324            PgpginPerSec => rc.title("Page In").format(SectorReadableSize).suffix("/s"),
1325            PgpgoutPerSec => rc.title("Page Out").format(SectorReadableSize).suffix("/s"),
1326            PswpinPerSec => rc.title("Swap In").format(PageReadableSize).suffix("/s"),
1327            PswpoutPerSec => rc.title("Swap Out").format(PageReadableSize).suffix("/s"),
1328            PgstealKswapd => rc.title("Pgsteal Kswapd").suffix(" pages/s"),
1329            PgstealDirect => rc.title("Pgsteal Direct").suffix(" pages/s"),
1330            PgscanKswapd => rc.title("Pgscan Kswapd").suffix(" pages/s"),
1331            PgscanDirect => rc.title("Pgscan Direct").suffix(" pages/s"),
1332            OomKill => rc.title("OOM Kills"),
1333        }
1334    }
1335}
1336
1337impl HasRenderConfigForDump for model::VmModel {
1338    fn get_openmetrics_config_for_dump(
1339        &self,
1340        field_id: &Self::FieldId,
1341    ) -> Option<RenderOpenMetricsConfigBuilder> {
1342        use model::VmModelFieldId::*;
1343        match field_id {
1344            PgpginPerSec => Some(gauge()),
1345            PgpgoutPerSec => Some(gauge()),
1346            PswpinPerSec => Some(gauge()),
1347            PswpoutPerSec => Some(gauge()),
1348            PgstealKswapd => Some(counter()),
1349            PgstealDirect => Some(counter()),
1350            PgscanKswapd => Some(counter()),
1351            PgscanDirect => Some(counter()),
1352            OomKill => Some(counter()),
1353        }
1354    }
1355}
1356
1357impl HasRenderConfig for model::SingleSlabModel {
1358    fn get_render_config_builder(field_id: &Self::FieldId) -> RenderConfigBuilder {
1359        use model::SingleSlabModelFieldId::*;
1360        let rc = RenderConfigBuilder::new();
1361        match field_id {
1362            Name => rc.title("Name").width(25),
1363            ActiveObjs => rc.title("ActiveObjs"),
1364            NumObjs => rc.title("TotalObjs"),
1365            ObjSize => rc.title("ObjSize").format(ReadableSize),
1366            ObjPerSlab => rc.title("Obj/Slab"),
1367            NumSlabs => rc.title("Slabs"),
1368            ActiveCaches => rc.title("ActiveCaches"),
1369            NumCaches => rc.title("TotalCaches"),
1370            ActiveSize => rc.title("ActiveSize").format(ReadableSize),
1371            TotalSize => rc.title("TotalSize").format(ReadableSize),
1372        }
1373    }
1374}
1375
1376impl HasRenderConfigForDump for model::SingleSlabModel {
1377    fn get_openmetrics_config_for_dump(
1378        &self,
1379        field_id: &Self::FieldId,
1380    ) -> Option<RenderOpenMetricsConfigBuilder> {
1381        use model::SingleSlabModelFieldId::*;
1382        match field_id {
1383            Name => None,
1384            ActiveObjs => Some(counter()),
1385            NumObjs => Some(counter()),
1386            ObjSize => Some(counter()),
1387            ObjPerSlab => Some(counter()),
1388            NumSlabs => Some(counter()),
1389            ActiveCaches => Some(counter()),
1390            NumCaches => Some(counter()),
1391            ActiveSize => Some(counter()),
1392            TotalSize => Some(counter()),
1393        }
1394    }
1395}
1396
1397impl HasRenderConfig for model::KsmModel {
1398    fn get_render_config_builder(field_id: &Self::FieldId) -> RenderConfigBuilder {
1399        use model::KsmModelFieldId::*;
1400        let rc = RenderConfigBuilder::new();
1401        match field_id {
1402            AdvisorMaxCpu => rc.title("AdvisorMaxCpu"),
1403            AdvisorMaxPagesToScan => rc.title("AdvisorMaxPagesToScan"),
1404            AdvisorMinPagesToScan => rc.title("AdvisorMinPagesToScan"),
1405            AdvisorMode => rc.title("AdvisorMode"),
1406            AdvisorTargetScanTime => rc.title("AdvisorTargetScanTime"),
1407            FullScans => rc.title("FullScans"),
1408            GeneralProfit => rc.title("GeneralProfit"),
1409            KsmZeroPages => rc.title("KsmZeroPages"),
1410            MaxPageSharing => rc.title("MaxPageSharing"),
1411            MergeAcrossNodes => rc.title("MergeAcrossNodes"),
1412            PagesScanned => rc.title("PagesScanned"),
1413            PagesShared => rc.title("PagesShared"),
1414            PagesSharing => rc.title("PagesSharing"),
1415            PagesSkipped => rc.title("PagesSkipped"),
1416            PagesToScan => rc.title("PagesToScan"),
1417            PagesUnshared => rc.title("PagesUnshared"),
1418            PagesVolatile => rc.title("PagesVolatile"),
1419            Run => rc.title("Run"),
1420            SleepMillisecs => rc.title("SleepMillisecs"),
1421            SmartScan => rc.title("SmartScan"),
1422            StableNodeChains => rc.title("StableNodeChains"),
1423            StableNodeChainsPruneMillisecs => rc.title("StableNodeChainsPruneMillisecs"),
1424            StableNodeDups => rc.title("StableNodeDups"),
1425            UseZeroPages => rc.title("UseZeroPages"),
1426        }
1427    }
1428}
1429
1430impl HasRenderConfigForDump for model::KsmModel {
1431    fn get_openmetrics_config_for_dump(
1432        &self,
1433        field_id: &Self::FieldId,
1434    ) -> Option<RenderOpenMetricsConfigBuilder> {
1435        use model::KsmModelFieldId::*;
1436        match field_id {
1437            AdvisorMaxCpu => Some(counter()),
1438            AdvisorMaxPagesToScan => Some(counter()),
1439            AdvisorMinPagesToScan => Some(counter()),
1440            AdvisorMode => Some(counter()),
1441            AdvisorTargetScanTime => Some(counter()),
1442            FullScans => Some(counter()),
1443            GeneralProfit => Some(counter()),
1444            KsmZeroPages => Some(counter()),
1445            MaxPageSharing => Some(counter()),
1446            MergeAcrossNodes => Some(counter()),
1447            PagesScanned => Some(counter()),
1448            PagesShared => Some(counter()),
1449            PagesSharing => Some(counter()),
1450            PagesSkipped => Some(counter()),
1451            PagesToScan => Some(counter()),
1452            PagesUnshared => Some(counter()),
1453            PagesVolatile => Some(counter()),
1454            Run => Some(counter()),
1455            SleepMillisecs => Some(counter()),
1456            SmartScan => Some(counter()),
1457            StableNodeChains => Some(counter()),
1458            StableNodeChainsPruneMillisecs => Some(counter()),
1459            StableNodeDups => Some(counter()),
1460            UseZeroPages => Some(counter()),
1461        }
1462    }
1463}
1464
1465impl HasRenderConfig for model::SingleDiskModel {
1466    fn get_render_config_builder(field_id: &Self::FieldId) -> RenderConfigBuilder {
1467        use model::SingleDiskModelFieldId::*;
1468        let rc = RenderConfigBuilder::new();
1469        match field_id {
1470            Name => rc.title("Name").width(15),
1471            ReadBytesPerSec => rc.title("Read").format(ReadableSize).suffix("/s"),
1472            WriteBytesPerSec => rc.title("Write").format(ReadableSize).suffix("/s"),
1473            DiscardBytesPerSec => rc.title("Discard").format(ReadableSize).suffix("/s"),
1474            DiskTotalBytesPerSec => rc.title("Disk").format(ReadableSize).suffix("/s"),
1475            ReadCompleted => rc.title("Read Completed"),
1476            ReadMerged => rc.title("Read Merged"),
1477            ReadSectors => rc.title("Read Sectors"),
1478            TimeSpendReadMs => rc.title("Time Spend Read").suffix(" ms"),
1479            WriteCompleted => rc.title("Write Completed"),
1480            WriteMerged => rc.title("Write Merged"),
1481            WriteSectors => rc.title("Write Sectors"),
1482            TimeSpendWriteMs => rc.title("Time Spend Write").suffix(" ms"),
1483            DiscardCompleted => rc.title("Discard Completed"),
1484            DiscardMerged => rc.title("Discard Merged"),
1485            DiscardSectors => rc.title("Discard Sectors"),
1486            TimeSpendDiscardMs => rc.title("Time Spend Discard").suffix(" ms"),
1487            Major => rc.title("Major").width(7),
1488            Minor => rc.title("Minor").width(7),
1489            DiskUsage => rc.title("Disk Usage").suffix("%").format(Precision(2)),
1490            PartitionSize => rc.title("Partition Size").format(ReadableSize),
1491            FilesystemType => rc.title("Filesystem Type"),
1492        }
1493    }
1494}
1495
1496impl HasRenderConfigForDump for model::SingleDiskModel {
1497    fn get_openmetrics_config_for_dump(
1498        &self,
1499        field_id: &Self::FieldId,
1500    ) -> Option<RenderOpenMetricsConfigBuilder> {
1501        use model::SingleDiskModelFieldId::*;
1502        let counter = if let Some(name) = &self.name {
1503            counter().label("disk", name)
1504        } else {
1505            counter()
1506        };
1507        let gauge = if let Some(name) = &self.name {
1508            gauge().label("disk", name)
1509        } else {
1510            gauge()
1511        };
1512        match field_id {
1513            // We label the other metrics with the disk name
1514            Name => None,
1515            ReadBytesPerSec => Some(gauge.unit("bytes_per_second")),
1516            WriteBytesPerSec => Some(gauge.unit("bytes_per_second")),
1517            DiscardBytesPerSec => Some(gauge.unit("bytes_per_second")),
1518            DiskTotalBytesPerSec => Some(gauge.unit("bytes_per_second")),
1519            ReadCompleted => Some(counter),
1520            ReadMerged => Some(counter),
1521            ReadSectors => Some(counter),
1522            TimeSpendReadMs => Some(counter.unit("milliseconds")),
1523            WriteCompleted => Some(counter),
1524            WriteMerged => Some(counter),
1525            WriteSectors => Some(counter),
1526            TimeSpendWriteMs => Some(counter.unit("milliseconds")),
1527            DiscardCompleted => Some(counter),
1528            DiscardMerged => Some(counter),
1529            DiscardSectors => Some(counter),
1530            TimeSpendDiscardMs => Some(counter.unit("milliseconds")),
1531            // Not sure what to do about static values like major/minor so leave them out for now
1532            Major => None,
1533            Minor => None,
1534            DiskUsage => Some(gauge.unit("percent")),
1535            PartitionSize => Some(gauge.unit("bytes")),
1536            FilesystemType => None,
1537        }
1538    }
1539}
1540
1541impl HasRenderConfig for model::BtrfsModel {
1542    fn get_render_config_builder(field_id: &Self::FieldId) -> RenderConfigBuilder {
1543        use model::BtrfsModelFieldId::*;
1544        let rc = RenderConfigBuilder::new();
1545        match field_id {
1546            Name => rc.title("Name").width(100).fold(FoldOption::Path),
1547            DiskFraction => rc
1548                .title("Approx Disk Usage")
1549                .format(Precision(1))
1550                .suffix("%"),
1551            DiskBytes => rc.title("Approx Disk Bytes").format(ReadableSize),
1552        }
1553    }
1554}
1555
1556impl HasRenderConfigForDump for model::BtrfsModel {
1557    fn get_openmetrics_config_for_dump(
1558        &self,
1559        _field_id: &Self::FieldId,
1560    ) -> Option<RenderOpenMetricsConfigBuilder> {
1561        // Btrfs not supported in open source
1562        None
1563    }
1564}
1565
1566impl HasRenderConfig for model::CgroupStatModel {
1567    fn get_render_config_builder(field_id: &Self::FieldId) -> RenderConfigBuilder {
1568        use model::CgroupStatModelFieldId::*;
1569        let rc = RenderConfigBuilder::new();
1570        match field_id {
1571            NrDescendants => rc.title("Nr Descendants"),
1572            NrDyingDescendants => rc.title("Nr Dying Descendants"),
1573        }
1574    }
1575}
1576
1577impl HasRenderConfig for model::CgroupMemoryNumaModel {
1578    fn get_render_config_builder(field_id: &Self::FieldId) -> RenderConfigBuilder {
1579        use model::CgroupMemoryNumaModelFieldId::*;
1580        let rc = RenderConfigBuilder::new();
1581        match field_id {
1582            Total => rc.title("Total").format(ReadableSize),
1583            Anon => rc.title("Anon").format(ReadableSize),
1584            File => rc.title("File").format(ReadableSize),
1585            KernelStack => rc.title("KernelStack").format(ReadableSize),
1586            Pagetables => rc.title("Pagetables").format(ReadableSize),
1587            Shmem => rc.title("Shmem").format(ReadableSize),
1588            FileMapped => rc.title("FileMapped").format(ReadableSize),
1589            FileDirty => rc.title("FileDirty").format(ReadableSize),
1590            FileWriteback => rc.title("FileWriteback").format(ReadableSize),
1591            Swapcached => rc.title("Swapcached").format(ReadableSize),
1592            AnonThp => rc.title("AnonThp").format(ReadableSize),
1593            FileThp => rc.title("FileThp").format(ReadableSize),
1594            ShmemThp => rc.title("ShmemThp").format(ReadableSize),
1595            InactiveAnon => rc.title("InactiveAnon").format(ReadableSize),
1596            ActiveAnon => rc.title("ActiveAnon").format(ReadableSize),
1597            InactiveFile => rc.title("InactiveFile").format(ReadableSize),
1598            ActiveFile => rc.title("ActiveFile").format(ReadableSize),
1599            Unevictable => rc.title("Unevictable").format(ReadableSize),
1600            SlabReclaimable => rc.title("SlabReclaimable").format(ReadableSize),
1601            SlabUnreclaimable => rc.title("SlabUnreclaimable").format(ReadableSize),
1602            WorkingsetRefaultAnon => rc
1603                .title("Workingset Refaults Anon")
1604                .suffix("/s")
1605                .format(Precision(1)),
1606            WorkingsetRefaultFile => rc
1607                .title("Workingset Refaults File")
1608                .suffix("/s")
1609                .format(Precision(1)),
1610            WorkingsetActivateAnon => rc
1611                .title("Workingset Activates Anon")
1612                .suffix("/s")
1613                .format(Precision(1)),
1614            WorkingsetActivateFile => rc
1615                .title("Workingset Activates File")
1616                .suffix("/s")
1617                .format(Precision(1)),
1618            WorkingsetRestoreAnon => rc
1619                .title("Workingset Restores Anon")
1620                .suffix("/s")
1621                .format(Precision(1)),
1622            WorkingsetRestoreFile => rc
1623                .title("Workingset Restores File")
1624                .suffix("/s")
1625                .format(Precision(1)),
1626            WorkingsetNodereclaim => rc
1627                .title("Workingset Nodereclaims")
1628                .suffix("/s")
1629                .format(Precision(1)),
1630        }
1631    }
1632}
1633
1634impl HasRenderConfig for model::CgroupProperties {
1635    fn get_render_config_builder(field_id: &Self::FieldId) -> RenderConfigBuilder {
1636        use model::CgroupPropertiesFieldId::*;
1637        let rc = RenderConfigBuilder::new();
1638        match field_id {
1639            // "cpu cpuset hugetlb io memory pids" is 33 chars
1640            CgroupControllers => rc.title("Controllers").width(35),
1641            CgroupSubtreeControl => rc.title("SubtreeControl").width(35),
1642            TidsMax => rc.title("Tids Max").format(MaxOrReadableSize),
1643            MemoryMin => rc.title("Mem Min").format(MaxOrReadableSize),
1644            MemoryLow => rc.title("Mem Low").format(MaxOrReadableSize),
1645            MemoryHigh => rc.title("Mem High").format(MaxOrReadableSize),
1646            MemoryMax => rc.title("Mem Max").format(MaxOrReadableSize),
1647            MemorySwapMax => rc.title("Swap Max").format(MaxOrReadableSize),
1648            MemoryZswapMax => rc.title("Zswap Max").format(MaxOrReadableSize),
1649            CpuWeight => rc.title("CPU Weight"),
1650            CpusetCpus => rc.title("Allowed CPUs"),
1651            CpusetCpusEffective => rc.title("Effective CPUs"),
1652            CpusetMems => rc.title("Allowed Mem Nodes"),
1653            CpusetMemsEffective => rc.title("Effective Mem Nodes"),
1654            CpuMaxUsec => rc.title("CPU Max").format(MaxOrDuration),
1655            CpuMaxPeriodUsec => rc.title("CPU Max Period").format(Duration),
1656        }
1657    }
1658}
1659
1660impl HasRenderConfig for model::SingleTcModel {
1661    fn get_render_config_builder(field_id: &Self::FieldId) -> RenderConfigBuilder {
1662        use model::SingleTcModelFieldId::*;
1663        let rc = RenderConfigBuilder::new();
1664        match field_id {
1665            Interface => rc.title("Interface"),
1666            Kind => rc.title("Kind"),
1667            Qlen => rc.title("Queue Length"),
1668            Bps => rc.title("Bps").format(ReadableSize).suffix("/s"),
1669            Pps => rc.title("Pps").suffix("/s"),
1670            BytesPerSec => rc.title("Bytes").format(ReadableSize).suffix("/s"),
1671            PacketsPerSec => rc.title("Packets").suffix("/s"),
1672            BacklogPerSec => rc.title("Backlog").suffix("/s"),
1673            DropsPerSec => rc.title("Drops").suffix("/s"),
1674            RequeuesPerSec => rc.title("Requeues").suffix("/s"),
1675            OverlimitsPerSec => rc.title("Overlimits").suffix("/s"),
1676            Qdisc(field_id) => model::QDiscModel::get_render_config_builder(field_id),
1677            Xstats(field_id) => model::XStatsModel::get_render_config_builder(field_id),
1678        }
1679    }
1680}
1681
1682impl HasRenderConfigForDump for model::SingleTcModel {
1683    fn get_openmetrics_config_for_dump(
1684        &self,
1685        field_id: &Self::FieldId,
1686    ) -> Option<RenderOpenMetricsConfigBuilder> {
1687        use model::SingleTcModelFieldId::*;
1688        let gauge = gauge()
1689            .label("interface", &self.interface)
1690            .label("qdisc", &self.kind);
1691        match field_id {
1692            Interface => None,
1693            Kind => None,
1694            Qlen => Some(gauge),
1695            Bps => Some(gauge.unit("bytes_per_second")),
1696            Pps => Some(gauge.unit("packets_per_second")),
1697            BytesPerSec => Some(gauge.unit("bytes_per_second")),
1698            PacketsPerSec => Some(gauge.unit("packets_per_second")),
1699            BacklogPerSec => Some(gauge.unit("packets_per_second")),
1700            DropsPerSec => Some(gauge.unit("packets_per_second")),
1701            RequeuesPerSec => Some(gauge.unit("packets_per_second")),
1702            OverlimitsPerSec => Some(gauge.unit("packets_per_second")),
1703            Qdisc(field_id) => self
1704                .qdisc
1705                .as_ref()
1706                .and_then(|qdisc| qdisc.get_openmetrics_config_for_dump(field_id)),
1707            Xstats(field_id) => self
1708                .xstats
1709                .as_ref()
1710                .and_then(|xstats| xstats.get_openmetrics_config_for_dump(field_id)),
1711        }
1712    }
1713}
1714
1715impl HasRenderConfig for model::QDiscModel {
1716    fn get_render_config_builder(field_id: &Self::FieldId) -> RenderConfigBuilder {
1717        use model::QDiscModelFieldId::*;
1718        match field_id {
1719            FqCodel(field_id) => model::FqCodelQDiscModel::get_render_config_builder(field_id),
1720        }
1721    }
1722}
1723
1724impl HasRenderConfigForDump for model::QDiscModel {
1725    fn get_openmetrics_config_for_dump(
1726        &self,
1727        field_id: &Self::FieldId,
1728    ) -> Option<RenderOpenMetricsConfigBuilder> {
1729        use model::QDiscModelFieldId::*;
1730        match field_id {
1731            FqCodel(field_id) => self
1732                .fq_codel
1733                .as_ref()
1734                .and_then(|fq_codel| fq_codel.get_openmetrics_config_for_dump(field_id)),
1735        }
1736    }
1737}
1738
1739impl HasRenderConfig for model::FqCodelQDiscModel {
1740    fn get_render_config_builder(field_id: &Self::FieldId) -> RenderConfigBuilder {
1741        use model::FqCodelQDiscModelFieldId::*;
1742        let rc = RenderConfigBuilder::new();
1743        match field_id {
1744            Target => rc.title("Target"),
1745            Limit => rc.title("Limit"),
1746            Interval => rc.title("Interval"),
1747            Ecn => rc.title("Ecn"),
1748            Quantum => rc.title("Quantum"),
1749            CeThreshold => rc.title("CeThreshold"),
1750            DropBatchSize => rc.title("DropBatchSize"),
1751            MemoryLimit => rc.title("MemoryLimit"),
1752            Flows => rc.title("Flows"),
1753        }
1754    }
1755}
1756
1757impl HasRenderConfig for model::XStatsModel {
1758    fn get_render_config_builder(field_id: &Self::FieldId) -> RenderConfigBuilder {
1759        use model::XStatsModelFieldId::*;
1760        match field_id {
1761            FqCodel(field_id) => model::FqCodelXStatsModel::get_render_config_builder(field_id),
1762        }
1763    }
1764}
1765
1766impl HasRenderConfigForDump for model::XStatsModel {
1767    fn get_openmetrics_config_for_dump(
1768        &self,
1769        field_id: &Self::FieldId,
1770    ) -> Option<RenderOpenMetricsConfigBuilder> {
1771        use model::XStatsModelFieldId::*;
1772        match field_id {
1773            FqCodel(field_id) => self
1774                .fq_codel
1775                .as_ref()
1776                .and_then(|fq_codel| fq_codel.get_openmetrics_config_for_dump(field_id)),
1777        }
1778    }
1779}
1780
1781impl HasRenderConfigForDump for model::FqCodelQDiscModel {
1782    fn get_openmetrics_config_for_dump(
1783        &self,
1784        field_id: &Self::FieldId,
1785    ) -> Option<RenderOpenMetricsConfigBuilder> {
1786        use model::FqCodelQDiscModelFieldId::*;
1787        match field_id {
1788            Target => Some(gauge()),
1789            Limit => Some(gauge()),
1790            Interval => Some(gauge()),
1791            Ecn => Some(gauge()),
1792            Quantum => Some(gauge()),
1793            CeThreshold => Some(gauge()),
1794            DropBatchSize => Some(gauge()),
1795            MemoryLimit => Some(gauge()),
1796            Flows => Some(gauge()),
1797        }
1798    }
1799}
1800
1801impl HasRenderConfig for model::FqCodelXStatsModel {
1802    fn get_render_config_builder(field_id: &Self::FieldId) -> RenderConfigBuilder {
1803        use model::FqCodelXStatsModelFieldId::*;
1804        let rc = RenderConfigBuilder::new();
1805        match field_id {
1806            Maxpacket => rc.title("MaxPacket"),
1807            EcnMark => rc.title("EcnMark"),
1808            NewFlowsLen => rc.title("NewFlowsLen"),
1809            OldFlowsLen => rc.title("OldFlowsLen"),
1810            CeMark => rc.title("CeMark"),
1811            DropOverlimitPerSec => rc.title("DropOverlimit").suffix("/s"),
1812            NewFlowCountPerSec => rc.title("NewFlowCount").suffix("/s"),
1813            MemoryUsagePerSec => rc.title("MemoryUsage").suffix("/s"),
1814            DropOvermemoryPerSec => rc.title("DropOvermemory").suffix("/s"),
1815        }
1816    }
1817}
1818
1819impl HasRenderConfigForDump for model::FqCodelXStatsModel {
1820    fn get_openmetrics_config_for_dump(
1821        &self,
1822        field_id: &Self::FieldId,
1823    ) -> Option<RenderOpenMetricsConfigBuilder> {
1824        use model::FqCodelXStatsModelFieldId::*;
1825        let gauge = gauge();
1826        match field_id {
1827            Maxpacket => Some(gauge),
1828            EcnMark => Some(gauge),
1829            NewFlowsLen => Some(gauge),
1830            OldFlowsLen => Some(gauge),
1831            CeMark => Some(gauge),
1832            DropOverlimitPerSec => Some(gauge),
1833            NewFlowCountPerSec => Some(gauge),
1834            MemoryUsagePerSec => Some(gauge),
1835            DropOvermemoryPerSec => Some(gauge),
1836        }
1837    }
1838}