use crate::{
common::system_time::{TimePeriod, fetch_time},
proto::v3::{
JsonLog, KeyStringValuePair, LogData, LogDataBody, LogTags, TextLog, TraceContext, YamlLog,
log_data_body::Content,
},
trace::{
span::{HandleSpanObject, Span},
trace_context::TracingContext,
},
};
use std::time::{SystemTime, UNIX_EPOCH};
pub enum RecordType {
Text,
Json,
Yaml,
}
impl Default for RecordType {
fn default() -> Self {
Self::Text
}
}
#[derive(Default)]
pub struct LogRecord {
time: Option<SystemTime>,
is_ignore_time: bool,
endpoint: String,
tags: Vec<(String, String)>,
trace_id: Option<String>,
trace_segment_id: Option<String>,
span_id: Option<i32>,
record_type: RecordType,
content: String,
}
impl LogRecord {
#[inline]
pub fn new() -> Self {
Default::default()
}
#[inline]
pub fn custom_time(mut self, time: SystemTime) -> Self {
self.time = Some(time);
self
}
#[inline]
pub fn ignore_time(mut self) -> Self {
self.is_ignore_time = true;
self
}
#[inline]
pub fn endpoint(mut self, endpoint: impl Into<String>) -> Self {
self.endpoint = endpoint.into();
self
}
pub fn add_tag(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
self.tags.push((key.into(), value.into()));
self
}
pub fn add_tags<K, V, I>(mut self, tags: I) -> Self
where
K: Into<String>,
V: Into<String>,
I: IntoIterator<Item = (K, V)>,
{
self.tags
.extend(tags.into_iter().map(|(k, v)| (k.into(), v.into())));
self
}
pub fn with_tracing_context(mut self, tracing_context: &TracingContext) -> Self {
self.trace_id = Some(tracing_context.trace_id().to_owned());
self.trace_segment_id = Some(tracing_context.trace_segment_id().to_owned());
self
}
pub fn with_span(mut self, span: &Span) -> Self {
self.span_id = Some(span.span_id());
self
}
pub fn record_type(mut self, record_type: RecordType) -> Self {
self.record_type = record_type;
self
}
pub fn content(mut self, content: impl Into<String>) -> Self {
self.content = content.into();
self
}
pub(crate) fn convert_to_log_data(
self,
service_name: String,
instance_name: String,
) -> LogData {
let timestamp = if self.is_ignore_time {
0
} else {
match self.time {
Some(time) => time
.duration_since(UNIX_EPOCH)
.map(|dur| dur.as_millis() as i64)
.unwrap_or_default(),
None => fetch_time(TimePeriod::Log),
}
};
let trace_context = match (self.trace_id, self.trace_segment_id, self.span_id) {
(Some(trace_id), Some(trace_segment_id), Some(span_id)) => Some(TraceContext {
trace_id,
trace_segment_id,
span_id,
}),
_ => None,
};
let tags = if self.tags.is_empty() {
None
} else {
let data = self
.tags
.into_iter()
.map(|(key, value)| KeyStringValuePair { key, value })
.collect();
Some(LogTags { data })
};
LogData {
timestamp,
service: service_name,
service_instance: instance_name,
endpoint: self.endpoint,
body: Some(LogDataBody {
r#type: "".to_owned(),
content: match self.record_type {
RecordType::Text => Some(Content::Text(TextLog { text: self.content })),
RecordType::Json => Some(Content::Json(JsonLog { json: self.content })),
RecordType::Yaml => Some(Content::Yaml(YamlLog { yaml: self.content })),
},
}),
trace_context,
tags,
layer: Default::default(),
}
}
}