xref: /aosp_15_r20/system/media/audio_utils/include/audio_utils/Trace.h (revision b9df5ad1c9ac98a7fefaac271a55f7ae3db05414)
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