use alloc::string::String;
use alloc::vec::Vec;
use super::{Gradus, SpatiumId, VestigiumId};
#[derive(Debug, Clone)]
pub struct EventusVestigium {
id: EventusId,
trace_id: VestigiumId,
parent_span_id: Option<SpatiumId>,
span_id: SpatiumId,
effect_id: u64,
effect_name: String,
operation: String,
timestamp_ns: u64,
duration_ns: Option<u64>,
level: Gradus,
kind: EventusKind,
attributes: Vec<Attributum>,
}
impl EventusVestigium {
pub fn new(
trace_id: VestigiumId,
span_id: SpatiumId,
effect_id: u64,
effect_name: impl Into<String>,
operation: impl Into<String>,
) -> Self {
EventusVestigium {
id: EventusId::generate(),
trace_id,
parent_span_id: None,
span_id,
effect_id,
effect_name: effect_name.into(),
operation: operation.into(),
timestamp_ns: 0,
duration_ns: None,
level: Gradus::Info,
kind: EventusKind::OperationStart,
attributes: Vec::new(),
}
}
#[inline]
pub fn with_parent(mut self, parent: SpatiumId) -> Self {
self.parent_span_id = Some(parent);
self
}
#[inline]
pub fn with_timestamp(mut self, timestamp_ns: u64) -> Self {
self.timestamp_ns = timestamp_ns;
self
}
#[inline]
pub fn with_duration(mut self, duration_ns: u64) -> Self {
self.duration_ns = Some(duration_ns);
self
}
#[inline]
pub fn with_level(mut self, level: Gradus) -> Self {
self.level = level;
self
}
#[inline]
pub fn with_kind(mut self, kind: EventusKind) -> Self {
self.kind = kind;
self
}
pub fn with_attribute(
mut self,
key: impl Into<String>,
value: impl Into<AttributumValue>,
) -> Self {
self.attributes.push(Attributum {
key: key.into(),
value: value.into(),
});
self
}
#[inline]
pub fn id(&self) -> EventusId {
self.id
}
#[inline]
pub fn trace_id(&self) -> VestigiumId {
self.trace_id
}
#[inline]
pub fn parent_span_id(&self) -> Option<SpatiumId> {
self.parent_span_id
}
#[inline]
pub fn span_id(&self) -> SpatiumId {
self.span_id
}
#[inline]
pub fn effect_id(&self) -> u64 {
self.effect_id
}
#[inline]
pub fn effect_name(&self) -> &str {
&self.effect_name
}
#[inline]
pub fn operation(&self) -> &str {
&self.operation
}
#[inline]
pub fn timestamp_ns(&self) -> u64 {
self.timestamp_ns
}
#[inline]
pub fn duration_ns(&self) -> Option<u64> {
self.duration_ns
}
#[inline]
pub fn level(&self) -> Gradus {
self.level
}
#[inline]
pub fn kind(&self) -> EventusKind {
self.kind
}
#[inline]
pub fn attributes(&self) -> &[Attributum] {
&self.attributes
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct EventusId(u64);
impl EventusId {
#[inline]
pub fn new(id: u64) -> Self {
EventusId(id)
}
#[inline]
pub fn generate() -> Self {
use core::sync::atomic::{AtomicU64, Ordering};
static COUNTER: AtomicU64 = AtomicU64::new(1);
EventusId(COUNTER.fetch_add(1, Ordering::Relaxed))
}
#[inline]
pub fn value(&self) -> u64 {
self.0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EventusKind {
OperationStart,
OperationEnd,
OperationError,
EffectPerform,
EffectHandle,
EffectResume,
FibraSpawn,
FibraComplete,
FibraCancel,
Custom,
}
impl EventusKind {
#[inline]
pub fn name(&self) -> &'static str {
match self {
EventusKind::OperationStart => "operation.start",
EventusKind::OperationEnd => "operation.end",
EventusKind::OperationError => "operation.error",
EventusKind::EffectPerform => "effect.perform",
EventusKind::EffectHandle => "effect.handle",
EventusKind::EffectResume => "effect.resume",
EventusKind::FibraSpawn => "fibra.spawn",
EventusKind::FibraComplete => "fibra.complete",
EventusKind::FibraCancel => "fibra.cancel",
EventusKind::Custom => "custom",
}
}
#[inline]
pub fn is_start(&self) -> bool {
matches!(self, EventusKind::OperationStart | EventusKind::FibraSpawn)
}
#[inline]
pub fn is_end(&self) -> bool {
matches!(self, EventusKind::OperationEnd | EventusKind::FibraComplete)
}
#[inline]
pub fn is_error(&self) -> bool {
matches!(self, EventusKind::OperationError)
}
}
#[derive(Debug, Clone)]
pub struct Attributum {
pub key: String,
pub value: AttributumValue,
}
#[derive(Debug, Clone)]
pub enum AttributumValue {
String(String),
Int(i64),
UInt(u64),
Float(f64),
Bool(bool),
}
impl From<String> for AttributumValue {
fn from(s: String) -> Self {
AttributumValue::String(s)
}
}
impl From<&str> for AttributumValue {
fn from(s: &str) -> Self {
AttributumValue::String(s.into())
}
}
impl From<i64> for AttributumValue {
fn from(v: i64) -> Self {
AttributumValue::Int(v)
}
}
impl From<i32> for AttributumValue {
fn from(v: i32) -> Self {
AttributumValue::Int(i64::from(v))
}
}
impl From<u64> for AttributumValue {
fn from(v: u64) -> Self {
AttributumValue::UInt(v)
}
}
impl From<u32> for AttributumValue {
fn from(v: u32) -> Self {
AttributumValue::UInt(u64::from(v))
}
}
impl From<f64> for AttributumValue {
fn from(v: f64) -> Self {
AttributumValue::Float(v)
}
}
impl From<bool> for AttributumValue {
fn from(v: bool) -> Self {
AttributumValue::Bool(v)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_event_creation() {
let event = EventusVestigium::new(
VestigiumId::generate(),
SpatiumId::generate(),
1,
"StateEffect",
"get",
);
assert_eq!(event.effect_name(), "StateEffect");
assert_eq!(event.operation(), "get");
}
#[test]
fn test_event_with_attributes() {
let event = EventusVestigium::new(
VestigiumId::generate(),
SpatiumId::generate(),
1,
"IO",
"read",
)
.with_attribute("path", "/tmp/file.txt")
.with_attribute("size", 1024u64);
assert_eq!(event.attributes().len(), 2);
}
#[test]
fn test_eventus_kind() {
assert!(EventusKind::OperationStart.is_start());
assert!(EventusKind::OperationEnd.is_end());
assert!(EventusKind::OperationError.is_error());
}
}