use crate::{
error::EtwError,
native::{CommonSchemaOutput, NormalOutput, OutputMode},
statics::GLOBAL_ACTIVITY_SEED,
values::{event_values::*, *},
};
use eventheader::*;
use eventheader_dynamic::EventBuilder;
use std::{
cell::RefCell,
marker::PhantomData,
ops::DerefMut,
pin::Pin,
sync::Arc,
time::SystemTime,
};
use tracing_subscriber::registry::{LookupSpan, SpanRef};
pub(crate) type ProviderGroupType = std::borrow::Cow<'static, str>;
unsafe extern "C" {
#[link_name = "__start__etw_kw"]
pub(crate) static _start__etw_kw: usize;
#[link_name = "__stop__etw_kw"]
pub(crate) static _stop__etw_kw: usize;
}
#[unsafe(link_section = "_etw_kw")]
#[used]
static mut ETW_META_PTR: *const crate::_details::EventMetadata = core::ptr::null();
thread_local! {static EBW: std::cell::RefCell<EventBuilder> = RefCell::new(EventBuilder::new());}
impl AddFieldAndValue for &'_ mut eventheader_dynamic::EventBuilder {
fn add_field_value(&mut self, fv: &FieldAndValue) {
match fv.value {
ValueTypes::None => (),
ValueTypes::v_u64(u) => {
self.add_value(fv.field_name, *u, FieldFormat::Default, 0);
}
ValueTypes::v_i64(i) => {
self.add_value(fv.field_name, *i, FieldFormat::SignedInt, 0);
}
ValueTypes::v_u128(u) => {
self.add_value(fv.field_name, u.to_le_bytes(), FieldFormat::Default, 0);
}
ValueTypes::v_i128(i) => {
self.add_value(fv.field_name, i.to_le_bytes(), FieldFormat::Default, 0);
}
ValueTypes::v_f64(f) => {
self.add_value(fv.field_name, *f, FieldFormat::Float, 0);
}
ValueTypes::v_bool(b) => {
self.add_value(fv.field_name, *b, FieldFormat::Boolean, 0);
}
ValueTypes::v_str(s) => {
self.add_str(fv.field_name, s.as_ref(), FieldFormat::Default, 0);
}
ValueTypes::v_char(c) => {
self.add_value(fv.field_name, *c, FieldFormat::StringUtf, 0);
}
}
}
}
#[doc(hidden)]
pub struct Provider<OutMode: OutputMode> {
provider: std::sync::RwLock<eventheader_dynamic::Provider>,
_m: PhantomData<OutMode>,
}
impl<OutMode: OutputMode> crate::native::ProviderTraits for Provider<OutMode> {
#[inline(always)]
fn supports_enable_callback() -> bool {
false
}
fn is_valid_provider(provider_name: &str) -> Result<(), EtwError> {
if provider_name.contains(|f: char| !f.is_ascii_alphanumeric() && f != '_') {
Err(EtwError::InvalidProviderNameCharacters(
provider_name.to_string(),
))
} else {
Ok(())
}
}
fn is_valid_group(provider_name: &str, value: &ProviderGroupType) -> Result<(), EtwError> {
if !eventheader_dynamic::ProviderOptions::is_valid_option_value(value) {
Err(EtwError::InvalidProviderGroupCharacters(
value.clone().into(),
))
} else if provider_name.len() + value.len() >= 234 {
Err(EtwError::TooManyCharacters(
provider_name.len() + value.len(),
))
} else {
Ok(())
}
}
#[inline]
fn enabled(&self, level: &tracing_core::Level, keyword: u64) -> bool {
let es = self
.provider
.read()
.unwrap()
.find_set(Self::map_level(level), keyword);
if let Some(s) = es {
s.enabled()
} else {
false
}
}
fn new<G>(
provider_name: &str,
_: &G,
provider_group: &Option<ProviderGroupType>,
default_keyword: u64,
) -> Pin<Arc<Self>>
where
for<'a> &'a G: Into<crate::native::GuidWrapper>,
{
let mut options = eventheader_dynamic::Provider::new_options();
if let Some(name) = provider_group {
options = *options.group_name(name);
}
let mut provider = eventheader_dynamic::Provider::new(provider_name, &options);
for event in crate::statics::event_metadata() {
provider.register_set(Self::map_level(&tracing::Level::ERROR), event.kw);
provider.register_set(Self::map_level(&tracing::Level::WARN), event.kw);
provider.register_set(Self::map_level(&tracing::Level::INFO), event.kw);
provider.register_set(Self::map_level(&tracing::Level::DEBUG), event.kw);
provider.register_set(Self::map_level(&tracing::Level::TRACE), event.kw);
}
provider.register_set(Self::map_level(&tracing::Level::ERROR), default_keyword);
provider.register_set(Self::map_level(&tracing::Level::WARN), default_keyword);
provider.register_set(Self::map_level(&tracing::Level::INFO), default_keyword);
provider.register_set(Self::map_level(&tracing::Level::DEBUG), default_keyword);
provider.register_set(Self::map_level(&tracing::Level::TRACE), default_keyword);
Arc::pin(Self {
provider: std::sync::RwLock::new(provider),
_m: PhantomData,
})
}
}
impl<OutMode: OutputMode> Provider<OutMode> {
fn find_set(
self: Pin<&Self>,
level: eventheader_dynamic::Level,
keyword: u64,
) -> Option<Arc<eventheader_dynamic::EventSet>> {
self.get_provider().read().unwrap().find_set(level, keyword)
}
fn register_set(
self: Pin<&Self>,
level: eventheader_dynamic::Level,
keyword: u64,
) -> Arc<eventheader_dynamic::EventSet> {
self.get_provider()
.write()
.unwrap()
.register_set(level, keyword)
}
fn get_provider(self: Pin<&Self>) -> Pin<&std::sync::RwLock<eventheader_dynamic::Provider>> {
unsafe { self.map_unchecked(|s| &s.provider) }
}
#[inline]
const fn map_level(level: &tracing_core::Level) -> eventheader_dynamic::Level {
match *level {
tracing_core::Level::ERROR => eventheader_dynamic::Level::Error,
tracing_core::Level::WARN => eventheader_dynamic::Level::Warning,
tracing_core::Level::INFO => eventheader_dynamic::Level::Informational,
tracing_core::Level::DEBUG => eventheader_dynamic::Level::Verbose,
tracing_core::Level::TRACE => eventheader_dynamic::Level::from_int(
eventheader_dynamic::Level::Verbose.as_int() + 1,
),
}
}
}
impl<Mode: OutputMode> super::EventWriter<NormalOutput> for Provider<Mode> {
fn span_start<'a, 'b, R>(
self: Pin<&Self>,
span: &'b SpanRef<'a, R>,
timestamp: SystemTime,
activity_id: &[u8; 16],
related_activity_id: &[u8; 16],
fields: &'b [crate::values::span_values::FieldValueIndex],
level: &tracing_core::Level,
keyword: u64,
event_tag: u32,
) where
R: LookupSpan<'a>,
{
let span_name = span.name();
let es = if let Some(es) = self.find_set(Self::map_level(level), keyword) {
es
} else {
self.register_set(Self::map_level(level), keyword)
};
EBW.with(|eb| {
let mut eb = eb.borrow_mut();
eb.reset(span_name, event_tag as u16);
eb.opcode(Opcode::ActivityStart);
eb.add_value(
"start time",
timestamp
.duration_since(std::time::SystemTime::UNIX_EPOCH)
.unwrap()
.as_secs(),
FieldFormat::Time,
0,
);
for f in fields {
<&mut EventBuilder as AddFieldAndValue>::add_field_value(
&mut eb.deref_mut(),
&FieldAndValue {
field_name: f.field,
value: &f.value,
},
);
}
let _ = eb.write(
&es,
if activity_id[0] != 0 {
Some(activity_id)
} else {
None
},
if related_activity_id[0] != 0 {
Some(related_activity_id)
} else {
None
},
);
});
}
fn span_stop<'a, 'b, R>(
self: Pin<&Self>,
span: &'b SpanRef<'a, R>,
start_stop_times: (std::time::SystemTime, std::time::SystemTime),
activity_id: &[u8; 16],
related_activity_id: &[u8; 16],
fields: &'b [crate::values::span_values::FieldValueIndex],
level: &tracing_core::Level,
keyword: u64,
event_tag: u32,
) where
R: LookupSpan<'a>,
{
let span_name = span.name();
let es = if let Some(es) = self.find_set(Self::map_level(level), keyword) {
es
} else {
self.register_set(Self::map_level(level), keyword)
};
EBW.with(|eb| {
let mut eb = eb.borrow_mut();
eb.reset(span_name, event_tag as u16);
eb.opcode(Opcode::ActivityStop);
eb.add_value(
"stop time",
start_stop_times
.1
.duration_since(std::time::SystemTime::UNIX_EPOCH)
.unwrap()
.as_secs(),
FieldFormat::Time,
0,
);
for f in fields {
<&mut EventBuilder as AddFieldAndValue>::add_field_value(
&mut eb.deref_mut(),
&FieldAndValue {
field_name: f.field,
value: &f.value,
},
);
}
let _ = eb.write(
&es,
if activity_id[0] != 0 {
Some(activity_id)
} else {
None
},
if related_activity_id[0] != 0 {
Some(related_activity_id)
} else {
None
},
);
});
}
fn write_record(
self: Pin<&Self>,
timestamp: SystemTime,
current_span: u64,
parent_span: u64,
event_name: &str,
level: &tracing_core::Level,
keyword: u64,
event_tag: u32,
event: &tracing::Event<'_>,
_otel_context: Option<([u8; 32], [u8; 16])>,
) {
let es = if let Some(es) = self.find_set(Self::map_level(level), keyword) {
es
} else {
self.register_set(Self::map_level(level), keyword)
};
let mut activity_id: [u8; 16] = *GLOBAL_ACTIVITY_SEED;
activity_id[0] = if current_span != 0 {
let (_, half) = activity_id.split_at_mut(8);
half.copy_from_slice(¤t_span.to_le_bytes());
1
} else {
0
};
let mut related_activity_id: [u8; 16] = *GLOBAL_ACTIVITY_SEED;
related_activity_id[0] = if parent_span != 0 {
let (_, half) = related_activity_id.split_at_mut(8);
half.copy_from_slice(&parent_span.to_le_bytes());
1
} else {
0
};
EBW.with(|eb| {
let mut eb = eb.borrow_mut();
eb.reset(event_name, event_tag as u16);
eb.opcode(Opcode::Info);
eb.add_value(
"time",
timestamp
.duration_since(std::time::SystemTime::UNIX_EPOCH)
.unwrap()
.as_secs(),
FieldFormat::Time,
0,
);
let mut visitor = EventBuilderVisitorWrapper::from(eb.deref_mut());
event.record(&mut visitor);
let _ = eb.write(
&es,
if activity_id[0] != 0 {
Some(&activity_id)
} else {
None
},
if related_activity_id[0] != 0 {
Some(&related_activity_id)
} else {
None
},
);
});
}
}
struct CommonSchemaPartCBuilder<'a> {
eb: &'a mut EventBuilder,
}
impl<'a> CommonSchemaPartCBuilder<'a> {
fn make_visitor(
eb: &'a mut EventBuilder,
) -> EventBuilderVisitorWrapper<CommonSchemaPartCBuilder<'a>> {
EventBuilderVisitorWrapper::from(CommonSchemaPartCBuilder { eb })
}
}
impl AddFieldAndValue for CommonSchemaPartCBuilder<'_> {
fn add_field_value(&mut self, fv: &FieldAndValue) {
let mut field_name: &'static str = fv.field_name;
if field_name == "message" {
field_name = "Body";
assert!(matches!(fv.value, ValueTypes::v_str(_)));
}
<&mut EventBuilder as AddFieldAndValue>::add_field_value(
&mut self.eb,
&FieldAndValue {
field_name,
value: fv.value,
},
);
}
}
impl<Mode: OutputMode> super::EventWriter<CommonSchemaOutput> for Provider<Mode> {
fn span_start<'a, 'b, R>(
self: Pin<&Self>,
_span: &'b SpanRef<'a, R>,
_timestamp: SystemTime,
_activity_id: &[u8; 16],
_related_activity_id: &[u8; 16],
_fields: &'b [crate::values::span_values::FieldValueIndex],
_level: &tracing_core::Level,
_keyword: u64,
_event_tag: u32,
) where
R: LookupSpan<'a>,
{
}
fn span_stop<'a, 'b, R>(
self: Pin<&Self>,
span: &'b SpanRef<'a, R>,
start_stop_times: (std::time::SystemTime, std::time::SystemTime),
_activity_id: &[u8; 16],
_related_activity_id: &[u8; 16],
fields: &'b [crate::values::span_values::FieldValueIndex],
level: &tracing_core::Level,
keyword: u64,
event_tag: u32,
) where
R: LookupSpan<'a>,
{
let span_name = span.name();
#[cfg(feature = "opentelemetry")]
let (trace_id, span_id) = {
let otel_ctx = crate::otel::extract_otel_context(span);
if otel_ctx.is_valid {
(otel_ctx.trace_id, otel_ctx.span_id)
} else {
let mut span_id_buf = [0u8; 16];
let mut trace_id_buf = [0u8; 32];
let _ = std::io::Write::write_fmt(
&mut span_id_buf.as_mut_slice(),
format_args!("{:016x}", span.id().into_u64()),
);
(trace_id_buf, span_id_buf)
}
};
#[cfg(not(feature = "opentelemetry"))]
let (trace_id, span_id) = {
let mut span_id_buf = [0u8; 16];
let trace_id_buf = [0u8; 32];
let _ = std::io::Write::write_fmt(
&mut span_id_buf.as_mut_slice(),
format_args!("{:016x}", span.id().into_u64()),
);
(trace_id_buf, span_id_buf)
};
let es = if let Some(es) = self.find_set(Self::map_level(level), keyword) {
es
} else {
self.register_set(Self::map_level(level), keyword)
};
EBW.with(|eb| {
let mut eb = eb.borrow_mut();
eb.reset(span_name, event_tag as u16);
eb.opcode(Opcode::Info);
eb.add_value("__csver__", 0x0401, FieldFormat::SignedInt, 0);
eb.add_struct("PartA", 2 , 0);
{
let time: String = chrono::DateTime::to_rfc3339(
&chrono::DateTime::<chrono::Utc>::from(start_stop_times.1),
);
eb.add_str("time", time, FieldFormat::Default, 0);
eb.add_struct("ext_dt", 2, 0);
{
eb.add_str("traceId", trace_id, FieldFormat::Default, 0);
eb.add_str("spanId", span_id, FieldFormat::Default, 0);
}
}
let span_parent = span.parent();
let partb_field_count = 3 + if span_parent.is_some() { 1 } else { 0 };
eb.add_struct("PartB", partb_field_count, 0);
{
eb.add_str("_typeName", "Span", FieldFormat::Default, 0);
if let Some(parent) = span_parent {
#[cfg(feature = "opentelemetry")]
let parent_span_id = {
let otel_ctx = crate::otel::extract_otel_context(&parent);
if otel_ctx.is_valid {
otel_ctx.span_id
} else {
let mut buf = [0u8; 16];
let _ = std::io::Write::write_fmt(
&mut buf.as_mut_slice(),
format_args!("{:016x}", parent.id().into_u64()),
);
buf
}
};
#[cfg(not(feature = "opentelemetry"))]
let parent_span_id = {
let mut buf = [0u8; 16];
let _ = std::io::Write::write_fmt(
&mut buf.as_mut_slice(),
format_args!("{:016x}", parent.id().into_u64()),
);
buf
};
eb.add_str("parentId", parent_span_id, FieldFormat::Default, 0);
}
eb.add_str("name", span_name, FieldFormat::Default, 0);
eb.add_str(
"startTime",
&chrono::DateTime::to_rfc3339(&chrono::DateTime::<chrono::Utc>::from(
start_stop_times.0,
)),
FieldFormat::Default,
0,
);
}
let partc_field_count = span.fields().len() as u8;
eb.add_struct("PartC", partc_field_count, 0);
{
let mut pfv = CommonSchemaPartCBuilder { eb: eb.deref_mut() };
for f in fields {
<CommonSchemaPartCBuilder<'_> as AddFieldAndValue>::add_field_value(
&mut pfv,
&FieldAndValue {
field_name: f.field,
value: &f.value,
},
);
}
}
let _ = eb.write(&es, None, None);
});
}
fn write_record(
self: Pin<&Self>,
timestamp: SystemTime,
current_span: u64,
_parent_span: u64,
event_name: &str,
level: &tracing_core::Level,
keyword: u64,
event_tag: u32,
event: &tracing::Event<'_>,
otel_context: Option<([u8; 32], [u8; 16])>,
) {
let es = if let Some(es) = self.find_set(Self::map_level(level), keyword) {
es
} else {
self.register_set(Self::map_level(level), keyword)
};
EBW.with(|eb| {
let mut eb = eb.borrow_mut();
eb.reset(event_name, event_tag as u16);
eb.opcode(Opcode::Info);
eb.add_value("__csver__", 0x0401, FieldFormat::SignedInt, 0);
eb.add_struct(
"PartA",
1 + if current_span != 0 || otel_context.is_some() { 1 } else { 0 },
0,
);
{
let time: String =
chrono::DateTime::to_rfc3339(&chrono::DateTime::<chrono::Utc>::from(timestamp));
eb.add_str("time", time, FieldFormat::Default, 0);
if let Some((trace_id, span_id)) = otel_context {
eb.add_struct("ext_dt", 2, 0);
{
eb.add_str("traceId", trace_id, FieldFormat::Default, 0);
eb.add_str("spanId", span_id, FieldFormat::Default, 0);
}
} else if current_span != 0 {
eb.add_struct("ext_dt", 2, 0);
{
let mut span_id_buf = [0u8; 16];
let _ = std::io::Write::write_fmt(
&mut span_id_buf.as_mut_slice(),
format_args!("{:016x}", current_span),
);
eb.add_str("traceId", [0u8; 32], FieldFormat::Default, 0);
eb.add_str("spanId", span_id_buf, FieldFormat::Default, 0);
}
}
}
eb.add_struct("PartB", 3, 0);
{
eb.add_str("_typeName", "Log", FieldFormat::Default, 0);
eb.add_str("name", event_name, FieldFormat::Default, 0);
eb.add_str(
"eventTime",
&chrono::DateTime::to_rfc3339(&chrono::DateTime::<chrono::Utc>::from(
timestamp,
)),
FieldFormat::Default,
0,
);
}
let partc_field_count = event.fields().count() as u8;
eb.add_struct("PartC", partc_field_count, 0);
{
let mut visitor = CommonSchemaPartCBuilder::make_visitor(eb.deref_mut());
event.record(&mut visitor);
}
let _ = eb.write(&es, None, None);
});
}
}