Coverage Report

Created: 2024-11-20 10:13

/build/source/nativelink-metric-collector/src/metrics_visitors.rs
Line
Count
Source (jump to first uncovered line)
1
// Copyright 2024 The NativeLink Authors. All rights reserved.
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
15
use std::borrow::Cow;
16
use std::fmt::Debug;
17
18
use nativelink_metric::MetricKind;
19
use serde::Serialize;
20
use tracing::field::{Field, Visit};
21
22
use crate::metrics_collection::{CollectedMetricPrimitive, CollectedMetricPrimitiveValue};
23
24
/// The type of the collected primitive metric.
25
#[derive(Default, Debug, Serialize)]
26
pub enum CollectionKind {
27
    #[default]
28
    Counter = 0,
29
    String = 1,
30
}
31
32
impl From<MetricKind> for CollectionKind {
33
16
    fn from(kind: MetricKind) -> Self {
34
16
        match kind {
35
8
            MetricKind::Counter => CollectionKind::Counter,
36
            MetricKind::Default | MetricKind::String | MetricKind::Component => {
37
8
                CollectionKind::String
38
            }
39
        }
40
16
    }
41
}
42
43
/// The final-metric primitive value and type that was collected.
44
#[derive(Debug)]
45
enum ValueWithPrimitiveType {
46
    String(String),
47
    U64(u64),
48
}
49
50
impl Default for ValueWithPrimitiveType {
51
16
    fn default() -> Self {
52
16
        ValueWithPrimitiveType::U64(0)
53
16
    }
54
}
55
56
/// An intermediate structed that will have it's contents populated
57
/// by the `tracing` layer for a given field.
58
/// This is done by implementing the `Visit` trait and asking the
59
/// `tracing` library to visit the fields of the captured event
60
/// and populate this struct.
61
#[derive(Default, Debug)]
62
pub struct MetricDataVisitor {
63
    pub name: String,
64
    value: ValueWithPrimitiveType,
65
    help: String,
66
    value_type: Option<CollectionKind>,
67
}
68
69
impl From<MetricDataVisitor> for CollectedMetricPrimitive {
70
16
    fn from(visitor: MetricDataVisitor) -> Self {
71
16
        let (value, derived_type) = match visitor.value {
72
8
            ValueWithPrimitiveType::String(s) => (
73
8
                CollectedMetricPrimitiveValue::String(Cow::Owned(s)),
74
8
                CollectionKind::String,
75
8
            ),
76
8
            ValueWithPrimitiveType::U64(u) => (
77
8
                CollectedMetricPrimitiveValue::Counter(u),
78
8
                CollectionKind::Counter,
79
8
            ),
80
        };
81
16
        CollectedMetricPrimitive {
82
16
            value: Some(value),
83
16
            help: visitor.help,
84
16
            value_type: visitor.value_type.unwrap_or(derived_type),
85
16
        }
86
16
    }
87
}
88
89
impl Visit for MetricDataVisitor {
90
0
    fn record_debug(&mut self, _field: &Field, _value: &dyn Debug) {}
91
92
0
    fn record_f64(&mut self, field: &Field, value: f64) {
93
0
        if field.name() == "__value" {
  Branch (93:12): [True: 0, False: 0]
  Branch (93:12): [Folded - Ignored]
94
0
            self.value = ValueWithPrimitiveType::String(value.to_string());
95
0
        }
96
0
    }
97
0
    fn record_i64(&mut self, field: &Field, value: i64) {
98
0
        if field.name() == "__value" {
  Branch (98:12): [True: 0, False: 0]
  Branch (98:12): [Folded - Ignored]
99
0
            match u64::try_from(value) {
100
0
                Ok(v) => self.value = ValueWithPrimitiveType::U64(v),
101
0
                Err(_) => self.value = ValueWithPrimitiveType::String(value.to_string()),
102
            }
103
0
        }
104
0
    }
105
24
    fn record_u64(&mut self, field: &Field, value: u64) {
106
24
        match field.name() {
107
24
            "__value" => 
self.value = ValueWithPrimitiveType::U64(value)8
,
108
16
            "__type" => self.value_type = Some(MetricKind::from(value).into()),
109
0
            "__help" => self.help = value.to_string(),
110
0
            "__name" => self.name = value.to_string(),
111
0
            field => panic!("UNKNOWN FIELD {field}"),
112
        }
113
24
    }
114
0
    fn record_i128(&mut self, field: &Field, value: i128) {
115
0
        if field.name() == "__value" {
  Branch (115:12): [True: 0, False: 0]
  Branch (115:12): [Folded - Ignored]
116
0
            match u64::try_from(value) {
117
0
                Ok(v) => self.value = ValueWithPrimitiveType::U64(v),
118
0
                Err(_) => self.value = ValueWithPrimitiveType::String(value.to_string()),
119
            }
120
0
        }
121
0
    }
122
0
    fn record_u128(&mut self, field: &Field, value: u128) {
123
0
        if field.name() == "__value" {
  Branch (123:12): [True: 0, False: 0]
  Branch (123:12): [Folded - Ignored]
124
0
            match u64::try_from(value) {
125
0
                Ok(v) => self.value = ValueWithPrimitiveType::U64(v),
126
0
                Err(_) => self.value = ValueWithPrimitiveType::String(value.to_string()),
127
            }
128
0
        }
129
0
    }
130
0
    fn record_bool(&mut self, field: &Field, value: bool) {
131
0
        if field.name() == "__value" {
  Branch (131:12): [True: 0, False: 0]
  Branch (131:12): [Folded - Ignored]
132
0
            self.value = ValueWithPrimitiveType::U64(u64::from(value));
133
0
        }
134
0
    }
135
40
    fn record_str(&mut self, field: &Field, value: &str) {
136
40
        match field.name() {
137
40
            "__value" => 
self.value = ValueWithPrimitiveType::String(value.to_string())8
,
138
32
            "__help" => 
self.help = value.to_string()16
,
139
16
            "__name" => self.name = value.to_string(),
140
0
            field => panic!("UNKNOWN FIELD {field}"),
141
        }
142
40
    }
143
0
    fn record_error(&mut self, _field: &Field, _value: &(dyn std::error::Error + 'static)) {}
144
}
145
146
/// An intermediate structed that will have it's contents populated
147
/// by the `tracing` layer for a given field.
148
/// This is the same as `MetricDataVisitor` but only captures info
149
/// about a given span on span creation.
150
pub struct SpanFields {
151
    pub name: Cow<'static, str>,
152
}
153
154
impl Visit for SpanFields {
155
0
    fn record_debug(&mut self, _field: &Field, _value: &dyn Debug) {}
156
157
4
    fn record_str(&mut self, field: &Field, value: &str) {
158
4
        if field.name() == "__name" {
  Branch (158:12): [True: 4, False: 0]
  Branch (158:12): [Folded - Ignored]
159
4
            self.name = Cow::Owned(value.to_string());
160
4
        }
0
161
4
    }
162
}