1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

#![no_std]
#![warn(missing_docs)]
#![allow(clippy::needless_return)]

//! # Dynamic EventHeader-encoded Linux Tracepoints
//!
//! `eventheader_dynamic` provides a flexible way to log `EventHeader`-encoded
//! events to [Linux user_events](https://docs.kernel.org/trace/user_events.html).
//! The events can be generated and collected on Linux 6.4 or later (requires the
//! `user_events` kernel feature to be enabled, the `tracefs` or `debugfs`
//! filesystem to be mounted, and appropriate permissions configured for the
//! `/sys/kernel/.../tracing/user_events_data` file).
//!
//! This "dynamic" implementation is more flexible than the implementation in the
//! [`eventheader`] crate. For example, it supports runtime-defined schema and can
//! easily log arrays of strings. However, it is harder to use, it has higher runtime
//! costs, and it depends on the `alloc` crate. This dynamic implementation is intended
//!  for use only when the set of events cannot be determined at compile-time. For
//! example, `eventheader_dynamic` might be used to implement a middle-layer library
//! providing tracing support to a scripting language like JavaScript or
//! Python. In other cases, use the [`eventheader`] crate instead of this crate.
//!
//! # Overview
//!
//! - Create a [Provider] object with the name of the provider to be used.
//! - Use the provider to register an [EventSet] for each level/keyword combination
//!   needed.
//! - Use [EventSet::enabled] to determine whether the event set is enabled.
//! - If the event set is enabled, use an [EventBuilder] to build the event
//!   (setting event properties and adding event fields) then write the event
//!   to the [EventSet].
//! - The provider will automatically unregister when it is dropped. You can manually
//!   call [Provider::unregister] if you want to unregister sooner or if the provider
//!   is stored within a static variable.
//!
//! # Example
//!
//! ```
//! use eventheader_dynamic as ehd;
//!
//! // Create a provider to use for all "MyCompany_MyComponent" events.
//! let mut provider = ehd::Provider::new("MyCompany_MyComponent", &ehd::Provider::new_options());
//!
//! // Create an event_set to use for all "MyCompany_MyComponent" events with severity
//! // level Verbose and event category bits 0x1f.
//! let event_l5k1f = provider.register_set(ehd::Level::Verbose, 0x1f);
//!
//! // If nobody is listening for events from this event set, the write method will do nothing.
//! // It is more efficient to only build and write the event if the event set is enabled.
//! if event_l5k1f.enabled() {
//!     let field1_value = "FieldValue";
//!     let field2_value = b'A';
//!
//!     // Build and write an event with two fields:
//!     ehd::EventBuilder::new()
//!         // Most events specify 0 for event tag.
//!         .reset("MyEventName", 0)
//!         // Most fields use 0 for field tag.
//!         .add_str("FieldName1", field1_value, ehd::FieldFormat::Default, 0)
//!         .add_value("FieldName2", field2_value, ehd::FieldFormat::String8, 0)
//!         // activity_id is None indicating event is not part of an activity.
//!         // related_id is None indicating event does not specify a parent activity.
//!         .write(&event_l5k1f, None, None);
//! }
//! ```
//!
//! # Notes
//!
//! The [EventBuilder] object is reusable. You may get a small performance benefit by
//! reusing an EventBuilder object for multiple events rather than using a new
//! EventBuilder for each event.
//!
//! Events are limited in size (event size = headers + metadata + data). The kernel will
//! ignore any event that is larger than 64KB.
//!
//! All event sets registered with a provider will become unregistered when the provider
//! is dropped or when you call `provider.unregister()`.
//!
//! Each event set maps to one tracepoint name, e.g. if the provider name is
//! "MyCompany_MyComponent", level is Verbose, and category bits are 0x1f, the event set
//! will correspond to a tracepoint named "MyCompany_MyComponent_L5K1f".
//!
//! Collect events to a file using a tool such as `perf`, e.g.
//! `perf record -e user_events:MyCompany_MyComponent_L5K1f`.
//!
//! Decode events using a tool such as `decode-perf`.

// Re-exports from eventheader:
pub use eventheader::FieldEncoding;
pub use eventheader::FieldFormat;
pub use eventheader::Level;
pub use eventheader::NativeImplementation;
pub use eventheader::Opcode;
pub use eventheader::NATIVE_IMPLEMENTATION;

// Exports from eventheader_dynamic:
pub use builder::EventBuilder;
pub use provider::EventSet;
pub use provider::Provider;
pub use provider::ProviderOptions;

pub mod changelog;

/// Converts a
/// [`std::time::SystemTime`](https://doc.rust-lang.org/std/time/struct.SystemTime.html)
/// into a [`time_t`](https://en.wikipedia.org/wiki/Unix_time) `i64` value.
///
/// This macro will convert the provided `SystemTime` value into a signed 64-bit
/// integer storing the number of seconds since 1970, saturating if the value is
/// out of the range that a 64-bit integer can represent.
///
/// The returned `i64` value can be used with [`EventBuilder::add_value`] and
/// [`EventBuilder::add_value_sequence`].
///
/// Note: `time_from_systemtime` is implemented as a macro because this crate is
/// `[no_std]`. Implementing this via a function would require this crate to reference
/// `std::time::SystemTimeError`.
#[macro_export]
macro_rules! time_from_systemtime {
    // Keep in sync with eventheader::time_from_systemtime.
    // The implementation is duplicated to allow for different doc comments.
    ($time:expr) => {
        match $time.duration_since(::std::time::SystemTime::UNIX_EPOCH) {
            Ok(dur) => ::tracelogging::_internal::time_from_duration_after_1970(dur),
            Err(err) => ::tracelogging::_internal::time_from_duration_before_1970(err.duration()),
        }
    };
}

extern crate alloc;
mod builder;
mod provider;