Skip to main content

tell_encoding/
lib.rs

1//! FlatBuffer encoders for the Tell wire protocol.
2//!
3//! Hand-written, allocation-light encoders for events, logs, metrics, and the
4//! batch envelope. No I/O and no dependencies. Buffers can be reused across
5//! calls via the `*_into` variants.
6
7mod batch;
8mod event;
9mod helpers;
10mod log;
11mod metric;
12
13#[cfg(test)]
14mod batch_test;
15#[cfg(test)]
16mod event_test;
17#[cfg(test)]
18mod log_test;
19#[cfg(test)]
20mod metric_test;
21
22pub use batch::{encode_batch, encode_batch_into};
23pub use event::{encode_event, encode_event_data, encode_event_data_into};
24pub use log::{encode_log_data, encode_log_data_into, encode_log_entry};
25pub use metric::{encode_metric_data, encode_metric_data_into, encode_metric_entry};
26
27/// API key length in bytes (16 bytes = 32 hex chars).
28pub const API_KEY_LENGTH: usize = 16;
29
30/// UUID length in bytes.
31pub const UUID_LENGTH: usize = 16;
32
33/// IPv6 address length in bytes.
34pub const IPV6_LENGTH: usize = 16;
35
36/// Default protocol version (v1.0 = 100).
37pub const DEFAULT_VERSION: u8 = 100;
38
39/// Schema type for routing batches.
40#[derive(Debug, Clone, Copy, PartialEq, Eq)]
41#[repr(u8)]
42pub enum SchemaType {
43    Unknown = 0,
44    Event = 1,
45    Log = 2,
46    Metric = 3,
47}
48
49impl SchemaType {
50    #[inline]
51    pub const fn as_u8(self) -> u8 {
52        self as u8
53    }
54}
55
56/// Event type for analytics events.
57#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
58#[repr(u8)]
59pub enum EventType {
60    #[default]
61    Unknown = 0,
62    Track = 1,
63    Identify = 2,
64    Group = 3,
65    Alias = 4,
66    Enrich = 5,
67    Context = 6,
68}
69
70impl EventType {
71    #[inline]
72    pub const fn as_u8(self) -> u8 {
73        self as u8
74    }
75}
76
77/// Log event type.
78#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
79#[repr(u8)]
80pub enum LogEventType {
81    Unknown = 0,
82    #[default]
83    Log = 1,
84    Enrich = 2,
85}
86
87impl LogEventType {
88    #[inline]
89    pub const fn as_u8(self) -> u8 {
90        self as u8
91    }
92}
93
94/// Log severity levels following RFC 5424 + trace.
95#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
96#[repr(u8)]
97pub enum LogLevel {
98    Emergency = 0,
99    Alert = 1,
100    Critical = 2,
101    Error = 3,
102    Warning = 4,
103    Notice = 5,
104    #[default]
105    Info = 6,
106    Debug = 7,
107    Trace = 8,
108}
109
110impl LogLevel {
111    #[inline]
112    pub const fn as_u8(self) -> u8 {
113        self as u8
114    }
115}
116
117/// Metric type — determines how to interpret the value.
118#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
119#[repr(u8)]
120pub enum MetricType {
121    #[default]
122    Unknown = 0,
123    /// Point-in-time value (cpu %, memory bytes, temperature).
124    Gauge = 1,
125    /// Cumulative or delta count (requests_total, bytes_sent).
126    Counter = 2,
127    /// Distribution with buckets (latency, request size).
128    Histogram = 3,
129}
130
131impl MetricType {
132    #[inline]
133    pub const fn as_u8(self) -> u8 {
134        self as u8
135    }
136}
137
138/// Aggregation temporality — how counter/histogram values relate to time.
139#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
140#[repr(u8)]
141pub enum Temporality {
142    #[default]
143    Unspecified = 0,
144    /// Total since process start (Prometheus-style).
145    Cumulative = 1,
146    /// Change since last report (StatsD-style).
147    Delta = 2,
148}
149
150impl Temporality {
151    #[inline]
152    pub const fn as_u8(self) -> u8 {
153        self as u8
154    }
155}
156
157/// Parameters for encoding a single event.
158pub struct EventParams<'a> {
159    pub event_type: EventType,
160    pub timestamp: u64,
161    pub service: Option<&'a str>,
162    pub device_id: Option<&'a [u8; UUID_LENGTH]>,
163    pub session_id: Option<&'a [u8; UUID_LENGTH]>,
164    pub event_name: Option<&'a str>,
165    pub payload: Option<&'a [u8]>,
166}
167
168/// Parameters for encoding a single log entry.
169pub struct LogEntryParams<'a> {
170    pub event_type: LogEventType,
171    pub session_id: Option<&'a [u8; UUID_LENGTH]>,
172    pub level: LogLevel,
173    pub timestamp: u64,
174    pub source: Option<&'a str>,
175    pub service: Option<&'a str>,
176    pub payload: Option<&'a [u8]>,
177}
178
179/// Parameters for encoding a single metric entry.
180pub struct MetricEntryParams<'a> {
181    pub metric_type: MetricType,
182    pub timestamp: u64,
183    pub name: &'a str,
184    pub value: f64,
185    pub source: Option<&'a str>,
186    pub service: Option<&'a str>,
187    pub labels: &'a [LabelParam<'a>],
188    pub temporality: Temporality,
189    pub histogram: Option<&'a HistogramParams>,
190    pub session_id: Option<&'a [u8; UUID_LENGTH]>,
191}
192
193/// A string key-value label for metric dimensions.
194pub struct LabelParam<'a> {
195    pub key: &'a str,
196    pub value: &'a str,
197}
198
199/// Histogram data for encoding.
200#[derive(Debug, Clone)]
201pub struct HistogramParams {
202    pub count: u64,
203    pub sum: f64,
204    pub min: f64,
205    pub max: f64,
206    /// Bucket boundaries and cumulative counts, sorted by `upper_bound`.
207    /// Use `f64::INFINITY` for the final catch-all bucket.
208    pub buckets: Vec<(f64, u64)>,
209}
210
211/// Parameters for encoding a batch.
212pub struct BatchParams<'a> {
213    pub api_key: &'a [u8; API_KEY_LENGTH],
214    pub schema_type: SchemaType,
215    pub version: u8,
216    pub batch_id: u64,
217    pub data: &'a [u8],
218}