blob: 9e641b8e78dd43e3dcc57e3299e5114d949a6a5a [file] [log] [blame]
Markus Vill9b308492023-11-23 13:25:57 +01001// Copyright 2024, The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! # Structed Logger API for Android
16
Markus Vill81bacf92024-01-31 15:49:32 +010017use log_event_list::__private_api::{LogContext, LogContextError};
Markus Vill9b308492023-11-23 13:25:57 +010018
19/// Add functionality to a type to log to a LogContext
20pub trait Value {
21 /// Apend value to provided context
22 fn add_to_context(&self, ctx: LogContext) -> Result<LogContext, LogContextError>;
23}
24
25impl Value for f32 {
26 fn add_to_context(&self, ctx: LogContext) -> Result<LogContext, LogContextError> {
27 ctx.append_f32(*self)
28 }
29}
30
31impl Value for i32 {
32 fn add_to_context(&self, ctx: LogContext) -> Result<LogContext, LogContextError> {
33 ctx.append_i32(*self)
34 }
35}
36
37impl Value for i64 {
38 fn add_to_context(&self, ctx: LogContext) -> Result<LogContext, LogContextError> {
39 ctx.append_i64(*self)
40 }
41}
42
43impl Value for &str {
44 fn add_to_context(&self, ctx: LogContext) -> Result<LogContext, LogContextError> {
45 ctx.append_str(self)
46 }
47}
48
49impl Value for String {
50 fn add_to_context(&self, ctx: LogContext) -> Result<LogContext, LogContextError> {
51 ctx.append_str(self.as_str())
52 }
53}
54
55/// Enum provides values to control sections.
56#[derive(PartialEq)]
57pub enum StructuredLogSection {
58 /// Start a new section
59 SubsectionStart,
60 /// End a section
61 SubsectionEnd,
62}
63
64impl Value for StructuredLogSection {
65 fn add_to_context(&self, ctx: LogContext) -> Result<LogContext, LogContextError> {
66 match *self {
67 StructuredLogSection::SubsectionStart => ctx.begin_list(),
68 StructuredLogSection::SubsectionEnd => ctx.end_list(),
69 }
70 }
71}
72
73// The following uses global crate names to make the usage of the macro
74// as simple as possible as the using code does not need to use the
75// dependencies explicitly.
76// Using imported crate names would require using code to import all our
77// internal dependencies without using them manually.
78
79/// Events log buffer.
80/// C++ implementation always logs to events, and used by default for consistent behavior between Rust and C++.
81pub const LOG_ID_EVENTS: u32 = log_event_list_bindgen::log_id_LOG_ID_EVENTS;
82/// Security log buffer.
83pub const LOG_ID_SECURITY: u32 = log_event_list_bindgen::log_id_LOG_ID_SECURITY;
84/// Statistics log buffer.
85pub const LOG_ID_STATS: u32 = log_event_list_bindgen::log_id_LOG_ID_STATS;
86
87/// Add a structured log entry to buffer $log_id.
88/// Should not be used directly, but the macros below.
Markus Vill81bacf92024-01-31 15:49:32 +010089/// Warning: Since this macro is internal, it may change any time.
Markus Vill9b308492023-11-23 13:25:57 +010090/// Usage: __structured_log_internal!(LOG_ID, TAG, value1, value2, ...)
91/// Returns Result:
92/// Ok if entry was written successfully
93/// Err(str) with an error description
94#[doc(hidden)]
95#[macro_export]
96macro_rules! __structured_log_internal {
97 ($log_id:expr, $tag:expr, $($entry:expr),+) => (
98 {
99 let mut ctx =
Markus Vill81bacf92024-01-31 15:49:32 +0100100 log_event_list::__private_api::LogContext::new($log_id, $tag)
101 .ok_or(log_event_list::__private_api::LogContextError).map_err(|_|
Markus Vill9b308492023-11-23 13:25:57 +0100102 "Unable to create a log context");
103 $(ctx = ctx.and_then(|c| $crate::Value::add_to_context(&$entry, c)
104 .map_err(|_| "unable to log value"));)+;
105 ctx.and_then(|c| c.write()
106 .map_err(|_| "unable to write log message"))
107 }
108 )
109}
110
111/// Add a structured log entry to events.
112/// Usage: structured_log!(TAG, value1, value2, ...)
113/// To use a different log buffer, you can specify it with log_id.
114/// Usage: structured_log!(log_id: LOG_ID, TAG, value1, value2, ...)
115/// Returns Result:
116/// Ok if entry was written successfully
117/// Err(str) with an error description
118#[macro_export]
119macro_rules! structured_log {
120 (log_id: $log_id:expr, $tag:expr, $($entry:expr),+) => (
121 {
122 $crate::__structured_log_internal!($log_id, $tag, $($entry),+)
123 }
124 );
125 ($tag:expr, $($entry:expr),+) => (
126 {
Markus Vill81bacf92024-01-31 15:49:32 +0100127 $crate::__structured_log_internal!($crate::LOG_ID_EVENTS, $tag, $($entry),+)
Markus Vill9b308492023-11-23 13:25:57 +0100128 }
129 )
130}