1 // 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 17 use log_event_list::__private_api::{LogContext, LogContextError}; 18 19 /// Add functionality to a type to log to a LogContext 20 pub trait Value { 21 /// Apend value to provided context add_to_context(&self, ctx: LogContext) -> Result<LogContext, LogContextError>22 fn add_to_context(&self, ctx: LogContext) -> Result<LogContext, LogContextError>; 23 } 24 25 impl Value for f32 { add_to_context(&self, ctx: LogContext) -> Result<LogContext, LogContextError>26 fn add_to_context(&self, ctx: LogContext) -> Result<LogContext, LogContextError> { 27 ctx.append_f32(*self) 28 } 29 } 30 31 impl Value for i32 { add_to_context(&self, ctx: LogContext) -> Result<LogContext, LogContextError>32 fn add_to_context(&self, ctx: LogContext) -> Result<LogContext, LogContextError> { 33 ctx.append_i32(*self) 34 } 35 } 36 37 impl Value for i64 { add_to_context(&self, ctx: LogContext) -> Result<LogContext, LogContextError>38 fn add_to_context(&self, ctx: LogContext) -> Result<LogContext, LogContextError> { 39 ctx.append_i64(*self) 40 } 41 } 42 43 impl Value for &str { add_to_context(&self, ctx: LogContext) -> Result<LogContext, LogContextError>44 fn add_to_context(&self, ctx: LogContext) -> Result<LogContext, LogContextError> { 45 ctx.append_str(self) 46 } 47 } 48 49 impl Value for String { add_to_context(&self, ctx: LogContext) -> Result<LogContext, LogContextError>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)] 57 pub enum StructuredLogSection { 58 /// Start a new section 59 SubsectionStart, 60 /// End a section 61 SubsectionEnd, 62 } 63 64 impl Value for StructuredLogSection { add_to_context(&self, ctx: LogContext) -> Result<LogContext, LogContextError>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++. 81 pub const LOG_ID_EVENTS: u32 = log_event_list_bindgen::log_id_LOG_ID_EVENTS; 82 /// Security log buffer. 83 pub const LOG_ID_SECURITY: u32 = log_event_list_bindgen::log_id_LOG_ID_SECURITY; 84 /// Statistics log buffer. 85 pub 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. 89 /// Warning: Since this macro is internal, it may change any time. 90 /// 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] 96 macro_rules! __structured_log_internal { 97 ($log_id:expr, $tag:expr, $($entry:expr),+) => ( 98 { 99 let mut ctx = 100 log_event_list::__private_api::LogContext::new($log_id, $tag) 101 .ok_or(log_event_list::__private_api::LogContextError).map_err(|_| 102 "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] 119 macro_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 { 127 $crate::__structured_log_internal!($crate::LOG_ID_EVENTS, $tag, $($entry),+) 128 } 129 ) 130 } 131