use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use crate::error::WyrdError;
use crate::vala::ids::{SpanId, TraceId};
use crate::vala::trace::{InstrumentationScope, Resource};
pub const MAX_LOG_BODY_BYTES: usize = 256 * 1024; pub const MAX_LOG_ATTRIBUTES_BYTES: usize = 64 * 1024;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct LogRecord {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub time: Option<DateTime<Utc>>,
pub observed_time: DateTime<Utc>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub severity_number: Option<u8>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub severity_text: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub event_name: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub body: Option<serde_json::Value>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub trace_id: Option<TraceId>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub span_id: Option<SpanId>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub trace_flags: Option<u8>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub resource: Option<Resource>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub scope: Option<InstrumentationScope>,
#[serde(default)]
pub attributes: serde_json::Map<String, serde_json::Value>,
#[serde(default)]
pub dropped_attributes_count: u32,
}
impl LogRecord {
pub fn validate(&self) -> Result<(), WyrdError> {
let err = |msg: &str| {
Err(WyrdError::Validation {
message: msg.to_string(),
details: serde_json::Value::Null,
})
};
if let Some(sev) = self.severity_number
&& sev > 24
{
return err("severity_number must be in [0, 24]");
}
if self.span_id.is_some() && self.trace_id.is_none() {
return err("span_id requires trace_id");
}
if let Some(body) = &self.body {
let bytes = serde_json::to_vec(body).unwrap_or_default();
if bytes.len() > MAX_LOG_BODY_BYTES {
return err("log body exceeds MAX_LOG_BODY_BYTES");
}
}
let attr_bytes = serde_json::to_vec(&self.attributes).unwrap_or_default();
if attr_bytes.len() > MAX_LOG_ATTRIBUTES_BYTES {
return err("log attributes exceed MAX_LOG_ATTRIBUTES_BYTES");
}
Ok(())
}
}