console_subscriber/
attribute.rs
1use console_api as proto;
2use std::collections::HashMap;
3use tracing::span::Id;
4
5#[derive(Debug, Default)]
6pub(crate) struct Attributes {
7 attributes: HashMap<FieldKey, proto::Attribute>,
8}
9
10#[derive(Debug, Clone)]
11pub(crate) struct Update {
12 pub(crate) field: proto::Field,
13 pub(crate) op: Option<UpdateOp>,
14 pub(crate) unit: Option<String>,
15}
16
17#[derive(Debug, Clone)]
18pub(crate) enum UpdateOp {
19 Add,
20 Override,
21 Sub,
22}
23
24#[derive(Debug, Hash, PartialEq, Eq)]
28struct FieldKey {
29 update_id: Id,
30 field_name: proto::field::Name,
31}
32
33impl Attributes {
36 pub(crate) fn values(&self) -> impl Iterator<Item = &proto::Attribute> {
37 self.attributes.values()
38 }
39
40 pub(crate) fn update(&mut self, id: &Id, update: &Update) {
41 let field_name = match update.field.name.as_ref() {
42 Some(name) => name.clone(),
43 None => {
44 tracing::warn!(?update.field, "field missing name, skipping...");
45 return;
46 }
47 };
48 let update_id = id.clone();
49 let key = FieldKey {
50 update_id,
51 field_name,
52 };
53
54 self.attributes
55 .entry(key)
56 .and_modify(|attr| update_attribute(attr, update))
57 .or_insert_with(|| update.clone().into());
58 }
59}
60
61fn update_attribute(attribute: &mut proto::Attribute, update: &Update) {
62 use proto::field::Value::*;
63 let attribute_val = attribute.field.as_mut().and_then(|a| a.value.as_mut());
64 let update_val = update.field.value.clone();
65 let update_name = update.field.name.clone();
66 match (attribute_val, update_val) {
67 (Some(BoolVal(v)), Some(BoolVal(upd))) => *v = upd,
68
69 (Some(StrVal(v)), Some(StrVal(upd))) => *v = upd,
70
71 (Some(DebugVal(v)), Some(DebugVal(upd))) => *v = upd,
72
73 (Some(U64Val(v)), Some(U64Val(upd))) => match update.op {
74 Some(UpdateOp::Add) => *v = v.saturating_add(upd),
75
76 Some(UpdateOp::Sub) => *v = v.saturating_sub(upd),
77
78 Some(UpdateOp::Override) => *v = upd,
79
80 None => tracing::warn!(
81 "numeric attribute update {:?} needs to have an op field",
82 update_name
83 ),
84 },
85
86 (Some(I64Val(v)), Some(I64Val(upd))) => match update.op {
87 Some(UpdateOp::Add) => *v = v.saturating_add(upd),
88
89 Some(UpdateOp::Sub) => *v = v.saturating_sub(upd),
90
91 Some(UpdateOp::Override) => *v = upd,
92
93 None => tracing::warn!(
94 "numeric attribute update {:?} needs to have an op field",
95 update_name
96 ),
97 },
98
99 (val, update) => {
100 tracing::warn!(
101 "attribute {:?} cannot be updated by update {:?}",
102 val,
103 update
104 );
105 }
106 }
107}
108
109impl From<Update> for proto::Attribute {
110 fn from(upd: Update) -> Self {
111 proto::Attribute {
112 field: Some(upd.field),
113 unit: upd.unit,
114 }
115 }
116}