1 /* 2 * Copyright 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #pragma once 18 19 #include "StringUtils.h" 20 #include "TraceConstants.h" 21 22 #include <string> 23 #include <type_traits> 24 25 namespace android::audio_utils::trace { 26 27 /* 28 * Audio Tracing. 29 * 30 * We use an "Object" metadata formatter to ensure consistent 31 * behavior. The Object formatter is not thread-safe, so 32 * locking must be provided by the caller. 33 * 34 * Object: 35 * This is a C++ object encapsulating key, value pairs. 36 * 37 * Native Java equivalent 38 * int32 (int) 39 * int64 (long) 40 * float (float) 41 * double (double) 42 * std::string (String) 43 * 44 * TBD: Array definition. 45 * TBD: Recursive definition. 46 * 47 * The Object may be dumped in text form (used for ATRACE) 48 * using the method toTrace(). 49 * 50 * The canonical Object format will have all key, value pairs sorted 51 * by key, with no duplicate keys. 52 * 53 * For practical use, we relax the sorting requirement by allowing 54 * "new" keys to be appended to the end. 55 * 56 * To service such requirements (and to add JSON, XML based 57 * output) requires an auxiliary map<> data structure, which 58 * is heavier weight. 59 * 60 * Currently the object supports a set() but no get(). 61 * 62 * TODO(b/377400056): Add JSON output formatting. 63 * TODO(b/377400056): Add XML output formatting. 64 * TODO(b/377400056): Enforce sorted output. 65 * TODO(b/377400056): Select trailing commas. 66 * TODO(b/377400056): Enable sorted output. 67 * TODO(b/377400056): Allow key conversion between camel case to snake case. 68 * TODO(b/377400056): Escape string delimiter token from strings. 69 * TODO(b/377400056): Consider nested objects, or strings that contain {}. 70 */ 71 class Object { 72 public: 73 /** 74 * Add a numeric value to the Object. 75 * 76 * @param key name to us. 77 * @param value an arithmetic value. 78 * @return Object for use in fluent style. 79 */ 80 template <typename S, typename T> 81 requires std::is_convertible_v<S, std::string> && std::is_arithmetic_v<T> set(const S & key,const T & value)82 Object& set(const S& key, const T& value) { 83 if (!object_.empty()) object_.append(object_delimiter_token_); 84 object_.append(key).append(assign_token_).append(std::to_string(value)); 85 return *this; 86 } 87 88 /** 89 * Add a string value to the Object. 90 * 91 * @param key name to us. 92 * @param value a string convertible value. 93 * @return Object for use in fluent style. 94 */ 95 template <typename S, typename T> 96 requires std::is_convertible_v<S, std::string> && std::is_convertible_v<T, std::string> set(const S & key,const T & value)97 Object& set(const S& key, const T& value) { 98 if (!object_.empty()) object_.append(object_delimiter_token_); 99 object_.append(key).append(assign_token_).append(string_begin_token_); 100 // ATRACE does not like '|', so replace with '+'. 101 stringutils::appendWithReplacement(object_, value, '|', '+'); 102 object_.append(string_end_token_); 103 return *this; 104 } 105 106 /** 107 * Returns true if the Object is empty (nothing is recorded). 108 */ empty()109 bool empty() const { return object_.empty(); } 110 111 /** 112 * Clears the contents of the object. 113 */ clear()114 void clear() { object_.clear(); } 115 116 /** 117 * Returns a text-formatted string suitable for ATRACE. 118 */ 119 template <typename S> 120 requires std::is_convertible_v<S, std::string> toTrace(const S & tag)121 std::string toTrace(const S& tag) const { 122 std::string ret(tag); 123 ret.append(object_begin_token_).append(object_).append(object_end_token_); 124 return ret; 125 } 126 toTrace()127 std::string toTrace() const { 128 return toTrace(""); 129 } 130 131 protected: 132 // Make these configurable (ATRACE text definition) 133 static constexpr char assign_token_[] = "="; 134 static constexpr char object_begin_token_[] = "{ "; 135 static constexpr char object_end_token_[] = " }"; 136 static constexpr char object_delimiter_token_[] = " "; 137 static constexpr char string_begin_token_[] = "\""; 138 static constexpr char string_end_token_[] = "\""; 139 140 std::string object_; 141 }; 142 143 } // namespace android::audio_utils::trace 144