1 /*
2 * Copyright (c) 2017-2022, The OpenThread Authors.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the copyright holder nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /**
30 * @file
31 * This file implements the logging related functions.
32 */
33
34 #include "log.hpp"
35
36 #include <ctype.h>
37
38 #include <openthread/platform/logging.h>
39
40 #include "common/code_utils.hpp"
41 #include "common/instance.hpp"
42 #include "common/string.hpp"
43
44 /*
45 * Verify debug UART dependency.
46 *
47 * It is reasonable to only enable the debug UART and not enable logs to the DEBUG UART.
48 */
49 #if (OPENTHREAD_CONFIG_LOG_OUTPUT == OPENTHREAD_CONFIG_LOG_OUTPUT_DEBUG_UART) && (!OPENTHREAD_CONFIG_ENABLE_DEBUG_UART)
50 #error "OPENTHREAD_CONFIG_ENABLE_DEBUG_UART_LOG requires OPENTHREAD_CONFIG_ENABLE_DEBUG_UART"
51 #endif
52
53 #if OPENTHREAD_CONFIG_LOG_PREPEND_UPTIME && !OPENTHREAD_CONFIG_UPTIME_ENABLE
54 #error "OPENTHREAD_CONFIG_LOG_PREPEND_UPTIME requires OPENTHREAD_CONFIG_UPTIME_ENABLE"
55 #endif
56
57 #if OPENTHREAD_CONFIG_LOG_PREPEND_UPTIME && OPENTHREAD_CONFIG_MULTIPLE_INSTANCE_ENABLE
58 #error "OPENTHREAD_CONFIG_LOG_PREPEND_UPTIME is not supported under OPENTHREAD_CONFIG_MULTIPLE_INSTANCE_ENABLE"
59 #endif
60
61 namespace ot {
62
63 #if OT_SHOULD_LOG
64
LogAtLevel(const char * aModuleName,const char * aFormat,...)65 template <LogLevel kLogLevel> void Logger::LogAtLevel(const char *aModuleName, const char *aFormat, ...)
66 {
67 va_list args;
68
69 va_start(args, aFormat);
70 LogVarArgs(aModuleName, kLogLevel, aFormat, args);
71 va_end(args);
72 }
73
74 // Explicit instantiations
75 template void Logger::LogAtLevel<kLogLevelNone>(const char *aModuleName, const char *aFormat, ...);
76 template void Logger::LogAtLevel<kLogLevelCrit>(const char *aModuleName, const char *aFormat, ...);
77 template void Logger::LogAtLevel<kLogLevelWarn>(const char *aModuleName, const char *aFormat, ...);
78 template void Logger::LogAtLevel<kLogLevelNote>(const char *aModuleName, const char *aFormat, ...);
79 template void Logger::LogAtLevel<kLogLevelInfo>(const char *aModuleName, const char *aFormat, ...);
80 template void Logger::LogAtLevel<kLogLevelDebg>(const char *aModuleName, const char *aFormat, ...);
81
LogInModule(const char * aModuleName,LogLevel aLogLevel,const char * aFormat,...)82 void Logger::LogInModule(const char *aModuleName, LogLevel aLogLevel, const char *aFormat, ...)
83 {
84 va_list args;
85
86 va_start(args, aFormat);
87 LogVarArgs(aModuleName, aLogLevel, aFormat, args);
88 va_end(args);
89 }
90
LogVarArgs(const char * aModuleName,LogLevel aLogLevel,const char * aFormat,va_list aArgs)91 void Logger::LogVarArgs(const char *aModuleName, LogLevel aLogLevel, const char *aFormat, va_list aArgs)
92 {
93 static const char kModuleNamePadding[] = "--------------";
94
95 ot::String<OPENTHREAD_CONFIG_LOG_MAX_SIZE> logString;
96
97 static_assert(sizeof(kModuleNamePadding) == kMaxLogModuleNameLength + 1, "Padding string is not correct");
98
99 #if OPENTHREAD_CONFIG_LOG_PREPEND_UPTIME
100 ot::Uptime::UptimeToString(ot::Instance::Get().Get<ot::Uptime>().GetUptime(), logString);
101 logString.Append(" ");
102 #endif
103
104 #if OPENTHREAD_CONFIG_LOG_LEVEL_DYNAMIC_ENABLE
105 VerifyOrExit(Instance::GetLogLevel() >= aLogLevel);
106 #endif
107
108 #if OPENTHREAD_CONFIG_LOG_PREPEND_LEVEL
109 {
110 static const char kLevelChars[] = {
111 '-', /* kLogLevelNone */
112 'C', /* kLogLevelCrit */
113 'W', /* kLogLevelWarn */
114 'N', /* kLogLevelNote */
115 'I', /* kLogLevelInfo */
116 'D', /* kLogLevelDebg */
117 };
118
119 logString.Append("[%c] ", kLevelChars[aLogLevel]);
120 }
121 #endif
122
123 logString.Append("%.*s%s: ", kMaxLogModuleNameLength, aModuleName,
124 &kModuleNamePadding[StringLength(aModuleName, kMaxLogModuleNameLength)]);
125
126 logString.AppendVarArgs(aFormat, aArgs);
127
128 logString.Append("%s", OPENTHREAD_CONFIG_LOG_SUFFIX);
129 otPlatLog(aLogLevel, OT_LOG_REGION_CORE, "%s", logString.AsCString());
130
131 ExitNow();
132
133 exit:
134 return;
135 }
136
137 #if OPENTHREAD_CONFIG_LOG_PKT_DUMP
138
139 template <LogLevel kLogLevel>
DumpAtLevel(const char * aModuleName,const char * aText,const void * aData,uint16_t aDataLength)140 void Logger::DumpAtLevel(const char *aModuleName, const char *aText, const void *aData, uint16_t aDataLength)
141 {
142 DumpInModule(aModuleName, kLogLevel, aText, aData, aDataLength);
143 }
144
145 // Explicit instantiations
146 template void Logger::DumpAtLevel<kLogLevelNone>(const char *aModuleName,
147 const char *aText,
148 const void *aData,
149 uint16_t aDataLength);
150 template void Logger::DumpAtLevel<kLogLevelCrit>(const char *aModuleName,
151 const char *aText,
152 const void *aData,
153 uint16_t aDataLength);
154 template void Logger::DumpAtLevel<kLogLevelWarn>(const char *aModuleName,
155 const char *aText,
156 const void *aData,
157 uint16_t aDataLength);
158 template void Logger::DumpAtLevel<kLogLevelNote>(const char *aModuleName,
159 const char *aText,
160 const void *aData,
161 uint16_t aDataLength);
162 template void Logger::DumpAtLevel<kLogLevelInfo>(const char *aModuleName,
163 const char *aText,
164 const void *aData,
165 uint16_t aDataLength);
166 template void Logger::DumpAtLevel<kLogLevelDebg>(const char *aModuleName,
167 const char *aText,
168 const void *aData,
169 uint16_t aDataLength);
170
DumpLine(const char * aModuleName,LogLevel aLogLevel,const uint8_t * aData,const uint16_t aDataLength)171 void Logger::DumpLine(const char *aModuleName, LogLevel aLogLevel, const uint8_t *aData, const uint16_t aDataLength)
172 {
173 ot::String<kStringLineLength> string;
174
175 string.Append("|");
176
177 for (uint8_t i = 0; i < kDumpBytesPerLine; i++)
178 {
179 if (i < aDataLength)
180 {
181 string.Append(" %02X", aData[i]);
182 }
183 else
184 {
185 string.Append(" ..");
186 }
187
188 if (!((i + 1) % 8))
189 {
190 string.Append(" |");
191 }
192 }
193
194 string.Append(" ");
195
196 for (uint8_t i = 0; i < kDumpBytesPerLine; i++)
197 {
198 char c = '.';
199
200 if (i < aDataLength)
201 {
202 char byteAsChar = static_cast<char>(0x7f & aData[i]);
203
204 if (isprint(byteAsChar))
205 {
206 c = byteAsChar;
207 }
208 }
209
210 string.Append("%c", c);
211 }
212
213 LogInModule(aModuleName, aLogLevel, "%s", string.AsCString());
214 }
215
DumpInModule(const char * aModuleName,LogLevel aLogLevel,const char * aText,const void * aData,uint16_t aDataLength)216 void Logger::DumpInModule(const char *aModuleName,
217 LogLevel aLogLevel,
218 const char *aText,
219 const void *aData,
220 uint16_t aDataLength)
221 {
222 constexpr uint16_t kWidth = 72;
223 constexpr uint16_t kTextSuffixLen = sizeof("[ len=000]") - 1;
224
225 uint16_t txtLen = StringLength(aText, kWidth - kTextSuffixLen) + kTextSuffixLen;
226 ot::String<kStringLineLength> string;
227
228 VerifyOrExit(otLoggingGetLevel() >= aLogLevel);
229
230 for (uint16_t i = 0; i < static_cast<uint16_t>((kWidth - txtLen) / 2); i++)
231 {
232 string.Append("=");
233 }
234
235 string.Append("[%s len=%03u]", aText, aDataLength);
236
237 for (uint16_t i = 0; i < static_cast<uint16_t>(kWidth - txtLen - (kWidth - txtLen) / 2); i++)
238 {
239 string.Append("=");
240 }
241
242 LogInModule(aModuleName, aLogLevel, "%s", string.AsCString());
243
244 for (uint16_t i = 0; i < aDataLength; i += kDumpBytesPerLine)
245 {
246 DumpLine(aModuleName, aLogLevel, static_cast<const uint8_t *>(aData) + i,
247 OT_MIN((aDataLength - i), kDumpBytesPerLine));
248 }
249
250 string.Clear();
251
252 for (uint16_t i = 0; i < kWidth; i++)
253 {
254 string.Append("-");
255 }
256
257 LogInModule(aModuleName, aLogLevel, "%s", string.AsCString());
258
259 exit:
260 return;
261 }
262 #endif // OPENTHREAD_CONFIG_LOG_PKT_DUMP
263
264 #endif // OT_SHOULD_LOG
265
266 } // namespace ot
267