Line data Source code
1 : /*
2 : * Copyright (c) 2020-2023 Project CHIP Authors
3 : * Copyright (c) 2013-2017 Nest Labs, Inc.
4 : *
5 : * Licensed under the Apache License, Version 2.0 (the "License");
6 : * you may not use this file except in compliance with the License.
7 : * You may obtain a copy of the License at
8 : *
9 : * http://www.apache.org/licenses/LICENSE-2.0
10 : *
11 : * Unless required by applicable law or agreed to in writing, software
12 : * distributed under the License is distributed on an "AS IS" BASIS,
13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : * See the License for the specific language governing permissions and
15 : * limitations under the License.
16 : */
17 :
18 : /**
19 : * @file
20 : * This file implements macros, constants, and interfaces for a
21 : * platform-independent logging interface for the chip SDK.
22 : *
23 : */
24 :
25 : #include "TextOnlyLogging.h"
26 :
27 : #include <lib/core/CHIPConfig.h>
28 : #include <lib/core/ErrorStr.h>
29 : #include <lib/support/CHIPMem.h>
30 :
31 : #include <platform/logging/LogV.h>
32 :
33 : #include <stdarg.h>
34 : #include <stdio.h>
35 : #include <string.h>
36 :
37 : #include <atomic>
38 :
39 : #if CHIP_PW_TOKENIZER_LOGGING
40 : #include "pw_tokenizer/encode_args.h"
41 : #endif
42 :
43 : namespace chip {
44 : namespace Logging {
45 :
46 : #if _CHIP_USE_LOGGING
47 :
48 : #if CHIP_PW_TOKENIZER_LOGGING
49 :
50 : void HandleTokenizedLog(uint32_t levels, pw_tokenizer_Token token, pw_tokenizer_ArgTypes types, ...)
51 : {
52 : uint8_t encoded_message[PW_TOKENIZER_CFG_ENCODING_BUFFER_SIZE_BYTES];
53 :
54 : memcpy(encoded_message, &token, sizeof(token));
55 :
56 : va_list args;
57 : va_start(args, types);
58 : // Use the C argument encoding API, since the C++ API requires C++17.
59 : const size_t encoded_size = sizeof(token) +
60 : pw_tokenizer_EncodeArgs(types, args, encoded_message + sizeof(token), sizeof(encoded_message) - sizeof(token));
61 : va_end(args);
62 :
63 : uint8_t log_category = levels >> 8 & 0xFF;
64 : uint8_t log_module = levels & 0xFF;
65 : char * logging_buffer = nullptr;
66 :
67 : // To reduce the number of alloc/free that is happening we will use a stack
68 : // buffer when buffer required to log is small.
69 : char stack_buffer[32];
70 : char * allocated_buffer = nullptr;
71 : size_t required_buffer_size = 2 * encoded_size + 1;
72 :
73 : if (required_buffer_size > sizeof(stack_buffer))
74 : {
75 : allocated_buffer = (char *) chip::Platform::MemoryAlloc(required_buffer_size);
76 : if (allocated_buffer)
77 : {
78 : logging_buffer = allocated_buffer;
79 : }
80 : }
81 : else
82 : {
83 : logging_buffer = stack_buffer;
84 : }
85 :
86 : if (logging_buffer)
87 : {
88 : for (size_t i = 0; i < encoded_size; i++)
89 : {
90 : sprintf(logging_buffer + 2 * i, "%02x", encoded_message[i]);
91 : }
92 : logging_buffer[2 * encoded_size] = '\0';
93 : Log(log_module, log_category, "%s", logging_buffer);
94 : }
95 : if (allocated_buffer)
96 : {
97 : chip::Platform::MemoryFree(allocated_buffer);
98 : }
99 : }
100 :
101 : #endif
102 :
103 : namespace {
104 :
105 : std::atomic<LogRedirectCallback_t> sLogRedirectCallback{ nullptr };
106 :
107 : /*
108 : * Array of strings containing the short names for each of the chip log modules.
109 : */
110 : static const char ModuleNames[kLogModule_Max][kMaxModuleNameLen + 1] = {
111 : #define _CHIP_LOGMODULE_NAME_INIT(MOD, NAME, ...) NAME,
112 : CHIP_LOGMODULES_ENUMERATE(_CHIP_LOGMODULE_NAME_INIT)
113 : };
114 :
115 : } // namespace
116 :
117 48614 : const char * GetModuleName(LogModule module)
118 : {
119 48614 : return ModuleNames[(module < kLogModule_Max) ? module : kLogModule_NotSpecified];
120 : }
121 :
122 10 : void SetLogRedirectCallback(LogRedirectCallback_t callback)
123 : {
124 10 : sLogRedirectCallback.store(callback);
125 10 : }
126 :
127 : /**
128 : * Log, to the platform-specified mechanism, the specified log
129 : * message, @a msg, for the specified module, @a module, in the
130 : * provided category, @a category.
131 : *
132 : * @param[in] module A LogModule enumeration indicating the
133 : * source of the chip package module that
134 : * generated the log message. This must be
135 : * translated within the function to a module
136 : * name for inclusion in the log message.
137 : * @param[in] category A LogCategory enumeration indicating the
138 : * category of the log message. The category
139 : * may be filtered in or out if
140 : * CHIP_LOG_FILTERING was asserted.
141 : * @param[in] msg A pointer to a NULL-terminated C string with
142 : * C Standard Library-style format specifiers
143 : * containing the log message to be formatted and
144 : * logged.
145 : * @param[in] ... A variadic argument list whose elements should
146 : * correspond to the format specifiers in @a msg.
147 : *
148 : */
149 48614 : void Log(uint8_t module, uint8_t category, const char * msg, ...)
150 : {
151 :
152 : va_list v;
153 48614 : va_start(v, msg);
154 48614 : LogV(module, category, msg, v);
155 48614 : va_end(v);
156 48614 : }
157 :
158 48614 : void LogV(uint8_t module, uint8_t category, const char * msg, va_list args)
159 : {
160 48614 : const char * moduleName = GetModuleName(static_cast<LogModule>(module));
161 48614 : LogRedirectCallback_t redirect = sLogRedirectCallback.load();
162 48614 : if (redirect != nullptr)
163 : {
164 11 : redirect(moduleName, category, msg, args);
165 : }
166 : else
167 : {
168 48603 : Platform::LogV(moduleName, category, msg, args);
169 : }
170 48614 : }
171 :
172 23 : void LogFailure(uint8_t module, CHIP_ERROR err, const char * msg)
173 : {
174 46 : if (err != CHIP_NO_ERROR)
175 : {
176 23 : Log(module, kLogCategory_Error, "%s: %" CHIP_ERROR_FORMAT, msg, err.Format());
177 : }
178 23 : }
179 :
180 0 : void LogFailure(uint8_t module, CHIP_ERROR err)
181 : {
182 0 : if (err != CHIP_NO_ERROR)
183 : {
184 0 : Log(module, kLogCategory_Error, "Error %" CHIP_ERROR_FORMAT, err.Format());
185 : }
186 0 : }
187 :
188 0 : void LogVerifyOrReturnError(const char * expr, int line, CHIP_ERROR code)
189 : {
190 0 : Log(kLogModule_NotSpecified, kLogCategory_Error, "%s:%d false: %" CHIP_ERROR_FORMAT, expr, line, code.Format());
191 0 : }
192 :
193 : #if CHIP_CONFIG_ERROR_SOURCE
194 8 : void LogVerifyOrReturnErrorWithSource(CHIP_ERROR code, const char * file, int line)
195 : {
196 8 : Log(kLogModule_NotSpecified, kLogCategory_Error, "%s at %s:%d", ErrorStr(code), file, line);
197 8 : }
198 : #endif
199 :
200 : #if CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE
201 0 : void LogVerifyOrDie(const char * file, int line, const char * condition)
202 : {
203 0 : if (condition != nullptr)
204 : {
205 0 : Log(kLogModule_Support, kLogCategory_Error, "VerifyOrDie failure at %s:%d: %s", file, line, condition);
206 : }
207 : else
208 : {
209 0 : Log(kLogModule_Support, kLogCategory_Error, "VerifyOrDie failure at %s:%d", file, line);
210 : }
211 0 : chipAbort();
212 : }
213 :
214 0 : void LogSuccessOrDie(const char * file, int line, CHIP_ERROR err, const char * expr)
215 : {
216 0 : if (expr != nullptr)
217 : {
218 0 : Log(kLogModule_Support, kLogCategory_Error, "SuccessOrDie failure %s at %s:%d: %s", ErrorStr(err), file, line, expr);
219 : }
220 : else
221 : {
222 0 : Log(kLogModule_Support, kLogCategory_Error, "SuccessOrDie failure %s at %s:%d", ErrorStr(err), file, line);
223 : }
224 0 : chipAbort();
225 : }
226 : #endif
227 :
228 0 : void LogVerifyOrDieWithMsg(uint8_t module, const char * msg)
229 : {
230 0 : Log(module, kLogCategory_Error, "%s", msg);
231 0 : chipAbort();
232 : }
233 :
234 : #if CHIP_LOG_FILTERING
235 : std::atomic<uint8_t> gLogFilter(kLogCategory_Max);
236 :
237 1405716 : uint8_t GetLogFilter()
238 : {
239 1405716 : return gLogFilter.load();
240 : }
241 :
242 413 : void SetLogFilter(uint8_t category)
243 : {
244 413 : gLogFilter.store(category);
245 413 : }
246 :
247 1405711 : bool IsCategoryEnabled(uint8_t category)
248 : {
249 1405711 : return (category <= GetLogFilter());
250 : }
251 : #endif // CHIP_LOG_FILTERING
252 :
253 : #endif // _CHIP_USE_LOGGING
254 :
255 : } // namespace Logging
256 : } // namespace chip
|