2022-06-21 22:23:55 +02:00
|
|
|
use crate::{attribute, event};
|
|
|
|
use console_api::resources::resource;
|
|
|
|
use tracing::{field, span};
|
|
|
|
use tracing_core::field::Visit;
|
|
|
|
|
|
|
|
const LOCATION_FILE: &str = "loc.file";
|
|
|
|
const LOCATION_LINE: &str = "loc.line";
|
|
|
|
const LOCATION_COLUMN: &str = "loc.col";
|
|
|
|
const INHERIT_FIELD_NAME: &str = "inherits_child_attrs";
|
|
|
|
|
|
|
|
/// Used to extract the fields needed to construct
|
|
|
|
/// an Event::Resource from the metadata of a tracing span
|
|
|
|
/// that has the following shape:
|
|
|
|
///
|
|
|
|
/// tracing::trace_span!(
|
|
|
|
/// "runtime.resource",
|
|
|
|
/// concrete_type = "Sleep",
|
|
|
|
/// kind = "timer",
|
|
|
|
/// is_internal = true,
|
|
|
|
/// inherits_child_attrs = true,
|
|
|
|
/// );
|
|
|
|
///
|
|
|
|
/// Fields:
|
|
|
|
/// concrete_type - indicates the concrete rust type for this resource
|
|
|
|
/// kind - indicates the type of resource (i.e. timer, sync, io )
|
|
|
|
/// is_internal - whether this is a resource type that is not exposed publicly (i.e. BatchSemaphore)
|
|
|
|
/// inherits_child_attrs - whether this resource should inherit the state attributes of its children
|
|
|
|
#[derive(Default)]
|
|
|
|
pub(crate) struct ResourceVisitor {
|
|
|
|
concrete_type: Option<String>,
|
|
|
|
kind: Option<resource::Kind>,
|
|
|
|
is_internal: bool,
|
|
|
|
inherit_child_attrs: bool,
|
|
|
|
line: Option<u32>,
|
|
|
|
file: Option<String>,
|
|
|
|
column: Option<u32>,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) struct ResourceVisitorResult {
|
|
|
|
pub(crate) concrete_type: String,
|
|
|
|
pub(crate) kind: resource::Kind,
|
|
|
|
pub(crate) location: Option<console_api::Location>,
|
|
|
|
pub(crate) is_internal: bool,
|
|
|
|
pub(crate) inherit_child_attrs: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Used to extract all fields from the metadata
|
|
|
|
/// of a tracing span
|
|
|
|
pub(crate) struct FieldVisitor {
|
|
|
|
fields: Vec<console_api::Field>,
|
|
|
|
meta_id: console_api::MetaId,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Used to extract the fields needed to construct
|
|
|
|
/// an `Event::Spawn` from the metadata of a tracing span
|
|
|
|
/// that has the following shape:
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// tracing::trace_span!(
|
|
|
|
/// target: "tokio::task",
|
|
|
|
/// "runtime.spawn",
|
|
|
|
/// kind = "local",
|
|
|
|
/// task.name = "some_name",
|
|
|
|
/// loc.file = "some_file.rs",
|
|
|
|
/// loc.line = 555,
|
|
|
|
/// loc.col = 5,
|
|
|
|
/// );
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// # Fields
|
|
|
|
///
|
|
|
|
/// This visitor has special behavior for `loc.line`, `loc.file`, and `loc.col`
|
|
|
|
/// fields, which are interpreted as a Rust source code location where the task
|
|
|
|
/// was spawned, if they are present. Other fields are recorded as arbitrary
|
|
|
|
/// key-value pairs.
|
|
|
|
pub(crate) struct TaskVisitor {
|
|
|
|
field_visitor: FieldVisitor,
|
|
|
|
line: Option<u32>,
|
|
|
|
file: Option<String>,
|
|
|
|
column: Option<u32>,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Used to extract the fields needed to construct
|
|
|
|
/// an Event::AsyncOp from the metadata of a tracing span
|
|
|
|
/// that has the following shape:
|
|
|
|
///
|
|
|
|
/// tracing::trace_span!(
|
|
|
|
/// "runtime.resource.async_op",
|
|
|
|
/// source = "Sleep::new_timeout",
|
|
|
|
/// );
|
|
|
|
///
|
|
|
|
/// Fields:
|
|
|
|
/// source - the method which has created an instance of this async operation
|
|
|
|
#[derive(Default)]
|
|
|
|
pub(crate) struct AsyncOpVisitor {
|
|
|
|
source: Option<String>,
|
|
|
|
inherit_child_attrs: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Used to extract the fields needed to construct
|
|
|
|
/// an Event::Waker from the metadata of a tracing span
|
|
|
|
/// that has the following shape:
|
|
|
|
///
|
|
|
|
/// tracing::trace!(
|
|
|
|
/// target: "tokio::task::waker",
|
|
|
|
/// op = "waker.clone",
|
|
|
|
/// task.id = id.into_u64(),
|
|
|
|
/// );
|
|
|
|
///
|
|
|
|
/// Fields:
|
|
|
|
/// task.id - the id of the task this waker will wake
|
|
|
|
/// op - the operation associated with this waker event
|
|
|
|
#[derive(Default)]
|
|
|
|
pub(crate) struct WakerVisitor {
|
|
|
|
id: Option<span::Id>,
|
|
|
|
op: Option<event::WakeOp>,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Used to extract the fields needed to construct
|
|
|
|
/// an Event::PollOp from the metadata of a tracing event
|
|
|
|
/// that has the following shape:
|
|
|
|
///
|
|
|
|
/// tracing::trace!(
|
|
|
|
/// target: "runtime::resource::poll_op",
|
|
|
|
/// op_name = "poll_elapsed",
|
|
|
|
/// readiness = "pending"
|
|
|
|
/// );
|
|
|
|
///
|
|
|
|
/// Fields:
|
|
|
|
/// op_name - the name of this resource poll operation
|
|
|
|
/// readiness - the result of invoking this poll op, describing its readiness
|
|
|
|
#[derive(Default)]
|
|
|
|
pub(crate) struct PollOpVisitor {
|
|
|
|
op_name: Option<String>,
|
|
|
|
is_ready: Option<bool>,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Used to extract the fields needed to construct
|
|
|
|
/// an Event::StateUpdate from the metadata of a tracing event
|
|
|
|
/// that has the following shape:
|
|
|
|
///
|
|
|
|
/// tracing::trace!(
|
|
|
|
/// target: "runtime::resource::state_update",
|
|
|
|
/// duration = duration,
|
|
|
|
/// duration.unit = "ms",
|
|
|
|
/// duration.op = "override",
|
|
|
|
/// );
|
|
|
|
///
|
|
|
|
/// Fields:
|
|
|
|
/// attribute_name - a field value for a field that has the name of the resource attribute being updated
|
|
|
|
/// value - the value for this update
|
|
|
|
/// unit - the unit for the value being updated (e.g. ms, s, bytes)
|
|
|
|
/// op - the operation that this update performs to the value of the resource attribute (one of: ovr, sub, add)
|
|
|
|
pub(crate) struct StateUpdateVisitor {
|
|
|
|
meta_id: console_api::MetaId,
|
|
|
|
field: Option<console_api::Field>,
|
|
|
|
unit: Option<String>,
|
|
|
|
op: Option<attribute::UpdateOp>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ResourceVisitor {
|
|
|
|
pub(crate) const RES_SPAN_NAME: &'static str = "runtime.resource";
|
|
|
|
const RES_CONCRETE_TYPE_FIELD_NAME: &'static str = "concrete_type";
|
|
|
|
const RES_VIZ_FIELD_NAME: &'static str = "is_internal";
|
|
|
|
const RES_KIND_FIELD_NAME: &'static str = "kind";
|
|
|
|
const RES_KIND_TIMER: &'static str = "timer";
|
|
|
|
|
|
|
|
pub(crate) fn result(self) -> Option<ResourceVisitorResult> {
|
|
|
|
let concrete_type = self.concrete_type?;
|
|
|
|
let kind = self.kind?;
|
|
|
|
|
|
|
|
let location = if self.file.is_some() && self.line.is_some() && self.column.is_some() {
|
|
|
|
Some(console_api::Location {
|
|
|
|
file: self.file,
|
|
|
|
line: self.line,
|
|
|
|
column: self.column,
|
|
|
|
..Default::default()
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
|
|
|
|
Some(ResourceVisitorResult {
|
|
|
|
concrete_type,
|
|
|
|
kind,
|
|
|
|
location,
|
|
|
|
is_internal: self.is_internal,
|
|
|
|
inherit_child_attrs: self.inherit_child_attrs,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Visit for ResourceVisitor {
|
|
|
|
fn record_debug(&mut self, _: &field::Field, _: &dyn std::fmt::Debug) {}
|
|
|
|
|
|
|
|
fn record_str(&mut self, field: &tracing_core::Field, value: &str) {
|
|
|
|
match field.name() {
|
|
|
|
Self::RES_CONCRETE_TYPE_FIELD_NAME => self.concrete_type = Some(value.to_string()),
|
|
|
|
Self::RES_KIND_FIELD_NAME => {
|
|
|
|
let kind = Some(match value {
|
|
|
|
Self::RES_KIND_TIMER => {
|
|
|
|
resource::kind::Kind::Known(resource::kind::Known::Timer as i32)
|
|
|
|
}
|
|
|
|
other => resource::kind::Kind::Other(other.to_string()),
|
|
|
|
});
|
|
|
|
self.kind = Some(resource::Kind { kind });
|
|
|
|
}
|
|
|
|
LOCATION_FILE => self.file = Some(value.to_string()),
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn record_bool(&mut self, field: &tracing_core::Field, value: bool) {
|
|
|
|
match field.name() {
|
|
|
|
Self::RES_VIZ_FIELD_NAME => self.is_internal = value,
|
|
|
|
INHERIT_FIELD_NAME => self.inherit_child_attrs = value,
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn record_u64(&mut self, field: &tracing_core::Field, value: u64) {
|
|
|
|
match field.name() {
|
|
|
|
LOCATION_LINE => self.line = Some(value as u32),
|
|
|
|
LOCATION_COLUMN => self.column = Some(value as u32),
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl FieldVisitor {
|
|
|
|
pub(crate) fn new(meta_id: console_api::MetaId) -> Self {
|
|
|
|
FieldVisitor {
|
|
|
|
fields: Vec::default(),
|
|
|
|
meta_id,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pub(crate) fn result(self) -> Vec<console_api::Field> {
|
|
|
|
self.fields
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TaskVisitor {
|
2022-06-22 14:43:09 +02:00
|
|
|
pub(crate) const SPAWN_TARGET: &'static str = "executor::task";
|
|
|
|
pub(crate) const SPAWN_NAME: &'static str = "runtime.spawn";
|
|
|
|
|
2022-06-21 22:23:55 +02:00
|
|
|
pub(crate) fn new(meta_id: console_api::MetaId) -> Self {
|
|
|
|
TaskVisitor {
|
|
|
|
field_visitor: FieldVisitor::new(meta_id),
|
|
|
|
line: None,
|
|
|
|
file: None,
|
|
|
|
column: None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn result(self) -> (Vec<console_api::Field>, Option<console_api::Location>) {
|
|
|
|
let fields = self.field_visitor.result();
|
|
|
|
let location = if self.file.is_some() && self.line.is_some() && self.column.is_some() {
|
|
|
|
Some(console_api::Location {
|
|
|
|
file: self.file,
|
|
|
|
line: self.line,
|
|
|
|
column: self.column,
|
|
|
|
..Default::default()
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
|
|
|
|
(fields, location)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Visit for TaskVisitor {
|
|
|
|
fn record_debug(&mut self, field: &field::Field, value: &dyn std::fmt::Debug) {
|
|
|
|
self.field_visitor.record_debug(field, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn record_i64(&mut self, field: &tracing_core::Field, value: i64) {
|
|
|
|
self.field_visitor.record_i64(field, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn record_u64(&mut self, field: &tracing_core::Field, value: u64) {
|
|
|
|
match field.name() {
|
|
|
|
LOCATION_LINE => self.line = Some(value as u32),
|
|
|
|
LOCATION_COLUMN => self.column = Some(value as u32),
|
|
|
|
_ => self.field_visitor.record_u64(field, value),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn record_bool(&mut self, field: &tracing_core::Field, value: bool) {
|
|
|
|
self.field_visitor.record_bool(field, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn record_str(&mut self, field: &tracing_core::Field, value: &str) {
|
|
|
|
if field.name() == LOCATION_FILE {
|
|
|
|
self.file = Some(value.to_string());
|
|
|
|
} else {
|
|
|
|
self.field_visitor.record_str(field, value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Visit for FieldVisitor {
|
|
|
|
fn record_debug(&mut self, field: &field::Field, value: &dyn std::fmt::Debug) {
|
|
|
|
self.fields.push(console_api::Field {
|
|
|
|
name: Some(field.name().into()),
|
|
|
|
value: Some(value.into()),
|
|
|
|
metadata_id: Some(self.meta_id.clone()),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
fn record_i64(&mut self, field: &tracing_core::Field, value: i64) {
|
|
|
|
self.fields.push(console_api::Field {
|
|
|
|
name: Some(field.name().into()),
|
|
|
|
value: Some(value.into()),
|
|
|
|
metadata_id: Some(self.meta_id.clone()),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
fn record_u64(&mut self, field: &tracing_core::Field, value: u64) {
|
|
|
|
self.fields.push(console_api::Field {
|
|
|
|
name: Some(field.name().into()),
|
|
|
|
value: Some(value.into()),
|
|
|
|
metadata_id: Some(self.meta_id.clone()),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
fn record_bool(&mut self, field: &tracing_core::Field, value: bool) {
|
|
|
|
self.fields.push(console_api::Field {
|
|
|
|
name: Some(field.name().into()),
|
|
|
|
value: Some(value.into()),
|
|
|
|
metadata_id: Some(self.meta_id.clone()),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
fn record_str(&mut self, field: &tracing_core::Field, value: &str) {
|
|
|
|
self.fields.push(console_api::Field {
|
|
|
|
name: Some(field.name().into()),
|
|
|
|
value: Some(value.into()),
|
|
|
|
metadata_id: Some(self.meta_id.clone()),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl AsyncOpVisitor {
|
|
|
|
pub(crate) const ASYNC_OP_SPAN_NAME: &'static str = "runtime.resource.async_op";
|
2022-06-22 14:43:09 +02:00
|
|
|
pub(crate) const ASYNC_OP_POLL_NAME: &'static str = "runtime.resource.async_op.poll";
|
2022-06-21 22:23:55 +02:00
|
|
|
const ASYNC_OP_SRC_FIELD_NAME: &'static str = "source";
|
|
|
|
|
|
|
|
pub(crate) fn result(self) -> Option<(String, bool)> {
|
|
|
|
let inherit = self.inherit_child_attrs;
|
|
|
|
self.source.map(|s| (s, inherit))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Visit for AsyncOpVisitor {
|
|
|
|
fn record_debug(&mut self, _: &field::Field, _: &dyn std::fmt::Debug) {}
|
|
|
|
|
|
|
|
fn record_str(&mut self, field: &tracing_core::Field, value: &str) {
|
|
|
|
if field.name() == Self::ASYNC_OP_SRC_FIELD_NAME {
|
|
|
|
self.source = Some(value.to_string());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn record_bool(&mut self, field: &tracing_core::Field, value: bool) {
|
|
|
|
if field.name() == INHERIT_FIELD_NAME {
|
|
|
|
self.inherit_child_attrs = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl WakerVisitor {
|
2022-06-22 14:43:09 +02:00
|
|
|
pub(crate) const WAKE_TARGET: &'static str = "executor::waker";
|
|
|
|
|
2022-06-21 22:23:55 +02:00
|
|
|
const WAKE: &'static str = "waker.wake";
|
|
|
|
const WAKE_BY_REF: &'static str = "waker.wake_by_ref";
|
|
|
|
const CLONE: &'static str = "waker.clone";
|
|
|
|
const DROP: &'static str = "waker.drop";
|
|
|
|
const TASK_ID_FIELD_NAME: &'static str = "task.id";
|
|
|
|
|
|
|
|
pub(crate) fn result(self) -> Option<(span::Id, event::WakeOp)> {
|
|
|
|
self.id.zip(self.op)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Visit for WakerVisitor {
|
|
|
|
fn record_debug(&mut self, _: &field::Field, _: &dyn std::fmt::Debug) {
|
|
|
|
// don't care (yet?)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn record_u64(&mut self, field: &tracing_core::Field, value: u64) {
|
|
|
|
if field.name() == Self::TASK_ID_FIELD_NAME {
|
|
|
|
self.id = Some(span::Id::from_u64(value));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn record_str(&mut self, field: &tracing_core::Field, value: &str) {
|
|
|
|
use crate::event::WakeOp;
|
|
|
|
if field.name() == "op" {
|
|
|
|
self.op = Some(match value {
|
|
|
|
Self::WAKE => WakeOp::Wake { self_wake: false },
|
|
|
|
Self::WAKE_BY_REF => WakeOp::WakeByRef { self_wake: false },
|
|
|
|
Self::CLONE => WakeOp::Clone,
|
|
|
|
Self::DROP => WakeOp::Drop,
|
|
|
|
_ => return,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PollOpVisitor {
|
|
|
|
pub(crate) const POLL_OP_EVENT_TARGET: &'static str = "runtime::resource::poll_op";
|
|
|
|
const OP_NAME_FIELD_NAME: &'static str = "op_name";
|
|
|
|
const OP_READINESS_FIELD_NAME: &'static str = "is_ready";
|
|
|
|
|
|
|
|
pub(crate) fn result(self) -> Option<(String, bool)> {
|
|
|
|
let op_name = self.op_name?;
|
|
|
|
let is_ready = self.is_ready?;
|
|
|
|
Some((op_name, is_ready))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Visit for PollOpVisitor {
|
|
|
|
fn record_debug(&mut self, _: &field::Field, _: &dyn std::fmt::Debug) {}
|
|
|
|
|
|
|
|
fn record_bool(&mut self, field: &tracing_core::Field, value: bool) {
|
|
|
|
if field.name() == Self::OP_READINESS_FIELD_NAME {
|
|
|
|
self.is_ready = Some(value)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn record_str(&mut self, field: &tracing_core::Field, value: &str) {
|
|
|
|
if field.name() == Self::OP_NAME_FIELD_NAME {
|
|
|
|
self.op_name = Some(value.to_string());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl StateUpdateVisitor {
|
|
|
|
pub(crate) const RE_STATE_UPDATE_EVENT_TARGET: &'static str = "runtime::resource::state_update";
|
|
|
|
pub(crate) const AO_STATE_UPDATE_EVENT_TARGET: &'static str =
|
|
|
|
"runtime::resource::async_op::state_update";
|
|
|
|
|
|
|
|
const STATE_OP_SUFFIX: &'static str = ".op";
|
|
|
|
const STATE_UNIT_SUFFIX: &'static str = ".unit";
|
|
|
|
|
|
|
|
const OP_ADD: &'static str = "add";
|
|
|
|
const OP_SUB: &'static str = "sub";
|
|
|
|
const OP_OVERRIDE: &'static str = "override";
|
|
|
|
|
|
|
|
pub(crate) fn new(meta_id: console_api::MetaId) -> Self {
|
|
|
|
StateUpdateVisitor {
|
|
|
|
meta_id,
|
|
|
|
field: None,
|
|
|
|
unit: None,
|
|
|
|
op: None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn result(self) -> Option<attribute::Update> {
|
|
|
|
Some(attribute::Update {
|
|
|
|
field: self.field?,
|
|
|
|
op: self.op,
|
|
|
|
unit: self.unit,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Visit for StateUpdateVisitor {
|
|
|
|
fn record_debug(&mut self, field: &field::Field, value: &dyn std::fmt::Debug) {
|
|
|
|
if !field.name().ends_with(Self::STATE_OP_SUFFIX)
|
|
|
|
&& !field.name().ends_with(Self::STATE_UNIT_SUFFIX)
|
|
|
|
{
|
|
|
|
self.field = Some(console_api::Field {
|
|
|
|
name: Some(field.name().into()),
|
|
|
|
value: Some(value.into()),
|
|
|
|
metadata_id: Some(self.meta_id.clone()),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn record_i64(&mut self, field: &field::Field, value: i64) {
|
|
|
|
if !field.name().ends_with(Self::STATE_OP_SUFFIX)
|
|
|
|
&& !field.name().ends_with(Self::STATE_UNIT_SUFFIX)
|
|
|
|
{
|
|
|
|
self.field = Some(console_api::Field {
|
|
|
|
name: Some(field.name().into()),
|
|
|
|
value: Some(value.into()),
|
|
|
|
metadata_id: Some(self.meta_id.clone()),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn record_u64(&mut self, field: &field::Field, value: u64) {
|
|
|
|
if !field.name().ends_with(Self::STATE_OP_SUFFIX)
|
|
|
|
&& !field.name().ends_with(Self::STATE_UNIT_SUFFIX)
|
|
|
|
{
|
|
|
|
self.field = Some(console_api::Field {
|
|
|
|
name: Some(field.name().into()),
|
|
|
|
value: Some(value.into()),
|
|
|
|
metadata_id: Some(self.meta_id.clone()),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn record_bool(&mut self, field: &field::Field, value: bool) {
|
|
|
|
if !field.name().ends_with(Self::STATE_OP_SUFFIX)
|
|
|
|
&& !field.name().ends_with(Self::STATE_UNIT_SUFFIX)
|
|
|
|
{
|
|
|
|
self.field = Some(console_api::Field {
|
|
|
|
name: Some(field.name().into()),
|
|
|
|
value: Some(value.into()),
|
|
|
|
metadata_id: Some(self.meta_id.clone()),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn record_str(&mut self, field: &field::Field, value: &str) {
|
|
|
|
if field.name().ends_with(Self::STATE_OP_SUFFIX) {
|
|
|
|
match value {
|
|
|
|
Self::OP_ADD => self.op = Some(attribute::UpdateOp::Add),
|
|
|
|
Self::OP_SUB => self.op = Some(attribute::UpdateOp::Sub),
|
|
|
|
Self::OP_OVERRIDE => self.op = Some(attribute::UpdateOp::Override),
|
|
|
|
_ => {}
|
|
|
|
};
|
|
|
|
} else if field.name().ends_with(Self::STATE_UNIT_SUFFIX) {
|
|
|
|
self.unit = Some(value.to_string());
|
|
|
|
} else {
|
|
|
|
self.field = Some(console_api::Field {
|
|
|
|
name: Some(field.name().into()),
|
|
|
|
value: Some(value.into()),
|
|
|
|
metadata_id: Some(self.meta_id.clone()),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|