android_logd_logger/
events.rs

1//! Android event logging support.
2//!
3//! This module provides functionality for writing structured binary events to Android's
4//! event log buffer. Events consist of a tag (numeric identifier) and a value that can
5//! be a primitive type, string, or list of values.
6
7use bytes::{BufMut, Bytes, BytesMut};
8use std::{iter::FromIterator, time::SystemTime};
9
10use crate::{Buffer, Error, LOGGER_ENTRY_MAX_LEN};
11
12/// Event tag identifier.
13///
14/// A numeric identifier used to categorize events. Event tags are typically
15/// defined in Android's event-log-tags files.
16pub type EventTag = u32;
17
18/// An event log entry.
19///
20/// Events are structured log entries that consist of a timestamp, a numeric tag,
21/// and a value. They are written to Android's event log buffer and can be viewed
22/// with `logcat -b events`.
23#[derive(Debug, Clone, PartialEq)]
24pub struct Event {
25    /// Timestamp
26    pub timestamp: SystemTime,
27    /// Tag
28    pub tag: EventTag,
29    /// Value
30    pub value: EventValue,
31}
32
33/// The value payload of an event.
34///
35/// Event values can be primitives (int, long, float), strings, or lists of values.
36/// This allows for structured logging of complex data.
37///
38/// # Examples
39///
40/// ```
41/// use android_logd_logger::EventValue;
42///
43/// // Simple values
44/// let int_val: EventValue = 42.into();
45/// let str_val: EventValue = "hello".into();
46/// let float_val: EventValue = 3.14.into();
47///
48/// // List of values
49/// let list_val: EventValue = vec![
50///     EventValue::Int(1),
51///     EventValue::String("test".to_string()),
52///     EventValue::Float(2.5)
53/// ].into();
54/// ```
55#[derive(Debug, PartialEq, Clone)]
56pub enum EventValue {
57    /// Void value
58    Void,
59    /// Int value
60    Int(i32),
61    /// Long value
62    Long(i64),
63    /// Float value
64    Float(f32),
65    /// String value
66    String(String),
67    /// List of values
68    List(Vec<EventValue>),
69}
70
71impl EventValue {
72    /// Returns the serialized size of this value in bytes.
73    ///
74    /// This includes the type tag and the value data.
75    pub fn serialized_size(&self) -> usize {
76        match self {
77            &EventValue::Void => 0,
78            EventValue::Int(_) | EventValue::Float(_) => 1 + 4,
79            EventValue::Long(_) => 1 + 8,
80            EventValue::String(s) => 1 + 4 + s.len(),
81            EventValue::List(l) => 1 + 1 + l.iter().map(EventValue::serialized_size).sum::<usize>(),
82        }
83    }
84
85    /// Serializes the event value into bytes.
86    ///
87    /// The serialization format follows Android's event log binary format,
88    /// with a type tag followed by the value data.
89    pub fn as_bytes(&self) -> Bytes {
90        const EVENT_TYPE_INT: u8 = 0;
91        const EVENT_TYPE_LONG: u8 = 1;
92        const EVENT_TYPE_STRING: u8 = 2;
93        const EVENT_TYPE_LIST: u8 = 3;
94        const EVENT_TYPE_FLOAT: u8 = 4;
95
96        let mut buffer = BytesMut::with_capacity(self.serialized_size());
97        match self {
98            EventValue::Void => (),
99            EventValue::Int(num) => {
100                buffer.put_u8(EVENT_TYPE_INT);
101                buffer.put_i32_le(*num);
102            }
103            EventValue::Long(num) => {
104                buffer.put_u8(EVENT_TYPE_LONG);
105                buffer.put_i64_le(*num);
106            }
107            EventValue::Float(num) => {
108                buffer.put_u8(EVENT_TYPE_FLOAT);
109                buffer.put_f32_le(*num);
110            }
111            EventValue::String(string) => {
112                buffer.put_u8(EVENT_TYPE_STRING);
113                buffer.put_u32_le(string.len() as u32);
114                buffer.put(string.as_bytes());
115            }
116            EventValue::List(values) => {
117                buffer.put_u8(EVENT_TYPE_LIST);
118                buffer.put_u8(values.len() as u8);
119                values.iter().for_each(|value| buffer.put(value.as_bytes()));
120            }
121        };
122        buffer.freeze()
123    }
124}
125
126impl From<()> for EventValue {
127    fn from(_: ()) -> Self {
128        EventValue::Void
129    }
130}
131
132impl From<i32> for EventValue {
133    fn from(v: i32) -> Self {
134        EventValue::Int(v)
135    }
136}
137
138impl From<i64> for EventValue {
139    fn from(v: i64) -> Self {
140        EventValue::Long(v)
141    }
142}
143
144impl From<f32> for EventValue {
145    fn from(v: f32) -> Self {
146        EventValue::Float(v)
147    }
148}
149
150impl From<&str> for EventValue {
151    fn from(v: &str) -> Self {
152        EventValue::String(v.to_string())
153    }
154}
155
156impl<T> FromIterator<T> for EventValue
157where
158    T: Into<EventValue>,
159{
160    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
161        EventValue::List(iter.into_iter().map(Into::into).collect())
162    }
163}
164
165impl<T> From<Vec<T>> for EventValue
166where
167    T: Into<EventValue>,
168{
169    fn from(mut v: Vec<T>) -> Self {
170        EventValue::List(v.drain(..).map(|e| e.into()).collect())
171    }
172}
173
174impl<T, U> From<(T, U)> for EventValue
175where
176    T: Into<EventValue>,
177    U: Into<EventValue>,
178{
179    fn from(value: (T, U)) -> Self {
180        EventValue::List(vec![value.0.into(), value.1.into()])
181    }
182}
183
184impl<T, U, V> From<(T, U, V)> for EventValue
185where
186    T: Into<EventValue>,
187    U: Into<EventValue>,
188    V: Into<EventValue>,
189{
190    fn from(value: (T, U, V)) -> Self {
191        EventValue::List(vec![value.0.into(), value.1.into(), value.2.into()])
192    }
193}
194
195impl<T, U, V, X> From<(T, U, V, X)> for EventValue
196where
197    T: Into<EventValue>,
198    U: Into<EventValue>,
199    V: Into<EventValue>,
200    X: Into<EventValue>,
201{
202    fn from(value: (T, U, V, X)) -> Self {
203        EventValue::List(vec![value.0.into(), value.1.into(), value.2.into(), value.3.into()])
204    }
205}
206
207impl<T, U, V, X, Y> From<(T, U, V, X, Y)> for EventValue
208where
209    T: Into<EventValue>,
210    U: Into<EventValue>,
211    V: Into<EventValue>,
212    X: Into<EventValue>,
213    Y: Into<EventValue>,
214{
215    fn from(value: (T, U, V, X, Y)) -> Self {
216        EventValue::List(vec![
217            value.0.into(),
218            value.1.into(),
219            value.2.into(),
220            value.3.into(),
221            value.4.into(),
222        ])
223    }
224}
225
226/// Writes an event with the current timestamp to the events buffer.
227///
228/// This is a convenience function that creates an event with the current system
229/// time and writes it to `Buffer::Events`.
230///
231/// # Parameters
232///
233/// - `tag`: The event tag identifier
234/// - `value`: The event value (can be any type that converts to `EventValue`)
235///
236/// # Errors
237///
238/// Returns an error if the event data exceeds the maximum size.
239///
240/// # Examples
241///
242/// ```
243/// use android_logd_logger::{write_event, write_event_now, Error, Event, EventValue};
244/// android_logd_logger::builder().init();
245///
246/// write_event_now(1, "test").unwrap();
247///
248/// let value: Vec<EventValue> = vec![1.into(), "one".into(), 123.3.into()].into();
249/// write_event_now(2, value).unwrap();
250/// ```
251pub fn write_event_now<T: Into<EventValue>>(tag: EventTag, value: T) -> Result<(), Error> {
252    write_event(&Event {
253        timestamp: SystemTime::now(),
254        tag,
255        value: value.into(),
256    })
257}
258
259/// Writes an event with the current timestamp to a specific buffer.
260///
261/// This is a convenience function that creates an event with the current system
262/// time and writes it to the specified buffer.
263///
264/// # Parameters
265///
266/// - `log_buffer`: The target log buffer
267/// - `tag`: The event tag identifier
268/// - `value`: The event value (can be any type that converts to `EventValue`)
269///
270/// # Errors
271///
272/// Returns an error if the event data exceeds the maximum size.
273///
274/// # Examples
275///
276/// ```
277/// use android_logd_logger::{write_event_buffer_now, Buffer, Error, Event, EventValue};
278/// android_logd_logger::builder().init();
279///
280/// write_event_buffer_now(Buffer::Stats, 1, "test").unwrap();
281///
282/// let value: Vec<EventValue> = vec![1.into(), "one".into(), 123.3.into()].into();
283/// write_event_buffer_now(Buffer::Stats, 2, value).unwrap();
284/// ```
285pub fn write_event_buffer_now<T: Into<EventValue>>(log_buffer: Buffer, tag: EventTag, value: T) -> Result<(), Error> {
286    write_event_buffer(
287        log_buffer,
288        &Event {
289            timestamp: SystemTime::now(),
290            tag,
291            value: value.into(),
292        },
293    )
294}
295
296/// Writes an event to the events buffer.
297///
298/// # Parameters
299///
300/// - `event`: The event to write
301///
302/// # Errors
303///
304/// Returns an error if the event data exceeds the maximum size.
305///
306/// # Examples
307///
308/// ```
309/// use android_logd_logger::{write_event, Error, Event, EventValue};
310/// android_logd_logger::builder().init();
311///
312/// write_event(&Event {
313///     timestamp: std::time::SystemTime::now(),
314///     tag: 1,
315///     value: "blah".into(),
316/// }).unwrap();
317/// ```
318pub fn write_event(event: &Event) -> Result<(), Error> {
319    write_event_buffer(Buffer::Events, event)
320}
321
322/// Writes an event to a specific buffer.
323///
324/// # Parameters
325///
326/// - `log_buffer`: The target log buffer
327/// - `event`: The event to write
328///
329/// # Errors
330///
331/// Returns an error if the event data exceeds the maximum size.
332///
333/// # Examples
334///
335/// ```
336/// use android_logd_logger::{write_event_buffer, Buffer, Error, Event, EventValue};
337/// android_logd_logger::builder().init();
338///
339/// write_event_buffer(Buffer::Stats, &Event {
340///     timestamp: std::time::SystemTime::now(),
341///     tag: 1,
342///     value: "blah".into(),
343/// }).unwrap();
344/// ```
345pub fn write_event_buffer(log_buffer: Buffer, event: &Event) -> Result<(), Error> {
346    if event.value.serialized_size() > (LOGGER_ENTRY_MAX_LEN - 1 - 2 - 4 - 4 - 4) {
347        return Err(Error::EventSize);
348    }
349
350    #[cfg(target_os = "android")]
351    crate::logd::write_event(log_buffer, event);
352
353    #[cfg(not(target_os = "android"))]
354    println!("buffer: {:?}, event: {:?}", log_buffer, event);
355
356    Ok(())
357}