1use model::Field;
16use model::FieldId;
17use model::Nameable;
18use model::Queriable;
19use model::Recursive;
20use render::RenderConfig;
21use render::RenderOpenMetricsConfigBuilder;
22
23use super::*;
24
25impl CommonField {
26 pub fn get_render_config(&self) -> RenderConfig {
28 let rc = render::RenderConfigBuilder::new();
29 match self {
30 Self::Timestamp => rc.title("Timestamp").width(10),
31 Self::Datetime => rc.title("Datetime").width(19),
32 }
33 .get()
34 }
35}
36
37impl<F> DumpField<F>
38where
39 F: FieldId,
40 <<F as FieldId>::Queriable as Queriable>::FieldId: ToString,
41{
42 fn get_field_id_str(&self) -> String {
43 match self {
44 Self::Common(common) => common.to_string(),
45 Self::FieldId(field_id) => field_id.to_string(),
46 }
47 }
48}
49
50impl<F> DumpField<F>
51where
52 F: FieldId,
53 F::Queriable: HasRenderConfigForDump,
54{
55 pub fn get_render_config(&self) -> RenderConfig {
56 match self {
57 Self::Common(common) => common.get_render_config(),
58 Self::FieldId(field_id) => F::Queriable::get_render_config_for_dump(field_id),
59 }
60 }
61
62 pub fn get_openmetrics_render_config(
63 &self,
64 model: &F::Queriable,
65 ) -> Option<RenderOpenMetricsConfigBuilder> {
66 match self {
67 Self::Common(_) => None,
69 Self::FieldId(field_id) => model.get_openmetrics_config_for_dump(field_id),
70 }
71 }
72
73 pub fn get_field(&self, ctx: &CommonFieldContext, model: &F::Queriable) -> Option<Field> {
74 match self {
75 Self::Common(common) => common.get_field(ctx),
76 Self::FieldId(field_id) => model.query(field_id),
77 }
78 }
79
80 pub fn dump_field(
81 &self,
82 ctx: &CommonFieldContext,
83 model: &F::Queriable,
84 raw: bool,
85 fixed_width: bool,
86 ) -> String {
87 let mut config = self.get_render_config();
88 if raw {
89 config.format = None;
90 config.suffix = None;
91 }
92 config.render(self.get_field(ctx, model), fixed_width)
93 }
94
95 pub fn dump_field_openmetrics(
96 &self,
97 key: &str,
98 ctx: &CommonFieldContext,
99 model: &F::Queriable,
100 ) -> Option<String> {
101 match self.get_field(ctx, model) {
102 Some(f) => self.get_openmetrics_render_config(model).map(|b| {
103 b.label("hostname", &ctx.hostname)
104 .build()
105 .render(key, f, ctx.timestamp)
106 }),
107 None => None,
108 }
109 }
110}
111
112impl<F> DumpField<F>
113where
114 F: FieldId,
115 F::Queriable: HasRenderConfigForDump + Recursive,
116{
117 pub fn dump_field_indented(
118 &self,
119 ctx: &CommonFieldContext,
120 model: &F::Queriable,
121 raw: bool,
122 fixed_width: bool,
123 ) -> String {
124 let mut config = self.get_render_config();
125 if raw {
126 config.format = None;
127 config.suffix = None;
128 }
129 config.render_indented(self.get_field(ctx, model), fixed_width, model.get_depth())
130 }
131}
132
133pub fn dump_kv<T: HasRenderConfigForDump>(
134 fields: &[DumpField<T::FieldId>],
135 ctx: &CommonFieldContext,
136 model: &T,
137 raw: bool,
138) -> String {
139 let mut res = String::new();
140 for field in fields {
141 let config = field.get_render_config();
142 res.push_str(&format!(
143 "{}: {}\n",
144 config.render_title(false),
145 field.dump_field(ctx, model, raw, false),
146 ));
147 }
148 res.push('\n');
149 res
150}
151
152pub fn dump_json<T: HasRenderConfigForDump>(
153 fields: &[DumpField<T::FieldId>],
154 ctx: &CommonFieldContext,
155 model: &T,
156 raw: bool,
157) -> Value {
158 let mut res = json!({});
159 for field in fields {
160 let config = field.get_render_config();
161 res[config.render_title(false)] = json!(field.dump_field(ctx, model, raw, false));
162 }
163 res
164}
165
166fn dump_title_line<F>(fields: &[DumpField<F>], sep: &'static str, fixed_width: bool) -> String
167where
168 F: FieldId,
169 F::Queriable: HasRenderConfigForDump,
170{
171 let mut line = String::new();
172 for field in fields {
173 line.push_str(&field.get_render_config().render_title(fixed_width));
174 line.push_str(sep);
175 }
176 line.push('\n');
177 line
178}
179
180pub fn dump_raw<T: HasRenderConfigForDump>(
181 fields: &[DumpField<T::FieldId>],
182 ctx: &CommonFieldContext,
183 model: &T,
184 round: usize,
185 repeat_title: Option<usize>,
186 disable_title: bool,
187 raw: bool,
188) -> String {
189 let mut res = String::new();
190 let repeat = repeat_title.unwrap_or(0);
191 if !disable_title && (round == 0 || (repeat != 0 && round % repeat == 0)) {
192 res.push_str(&dump_title_line(fields, " ", true));
193 }
194 for field in fields {
195 res.push_str(&field.dump_field(ctx, model, raw, true));
196 res.push(' ');
197 }
198 res.push('\n');
199 res
200}
201
202pub fn dump_raw_indented<T: HasRenderConfigForDump + Recursive>(
203 fields: &[DumpField<T::FieldId>],
204 ctx: &CommonFieldContext,
205 model: &T,
206 round: usize,
207 repeat_title: Option<usize>,
208 disable_title: bool,
209 raw: bool,
210) -> String {
211 let mut res = String::new();
212 let repeat = repeat_title.unwrap_or(0);
213 if !disable_title && (round == 0 || (repeat != 0 && round % repeat == 0)) {
214 res.push_str(&dump_title_line(fields, " ", true));
215 }
216 for field in fields {
217 res.push_str(&field.dump_field_indented(ctx, model, raw, true));
218 res.push(' ');
219 }
220 res.push('\n');
221 res
222}
223
224pub fn dump_csv<T: HasRenderConfigForDump>(
225 fields: &[DumpField<T::FieldId>],
226 ctx: &CommonFieldContext,
227 model: &T,
228 round: usize,
229 disable_title: bool,
230 raw: bool,
231) -> String {
232 let mut res = String::new();
233 if !disable_title && round == 0 {
234 res.push_str(&dump_title_line(fields, ",", false));
235 }
236 for field in fields {
237 res.push_str(&field.dump_field(ctx, model, raw, false));
238 res.push(',');
239 }
240 res.push('\n');
241 res
242}
243
244pub fn dump_tsv<T: HasRenderConfigForDump>(
245 fields: &[DumpField<T::FieldId>],
246 ctx: &CommonFieldContext,
247 model: &T,
248 round: usize,
249 disable_title: bool,
250 raw: bool,
251) -> String {
252 let mut res = String::new();
253 if !disable_title && round == 0 {
254 res.push_str(&dump_title_line(fields, "\t", false));
255 }
256 for field in fields {
257 res.push_str(&field.dump_field(ctx, model, raw, false));
258 res.push('\t');
259 }
260 res.push('\n');
261 res
262}
263
264pub fn dump_openmetrics<T>(
265 fields: &[DumpField<T::FieldId>],
266 ctx: &CommonFieldContext,
267 model: &T,
268) -> String
269where
270 T: HasRenderConfigForDump,
271 T: Nameable,
272 T::FieldId: ToString,
273{
274 fields
275 .iter()
276 .filter_map(|field| {
277 let key = format!(
279 "{}_{}",
280 T::name(),
281 field.get_field_id_str().replace('.', "_")
282 );
283 field.dump_field_openmetrics(&key, ctx, model)
284 })
285 .flat_map(|s| s.chars().collect::<Vec<_>>().into_iter())
286 .collect::<String>()
287}