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}