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/num_utils.hpp"
43 #include "common/string.hpp"
44
45 /*
46 * Verify debug UART dependency.
47 *
48 * It is reasonable to only enable the debug UART and not enable logs to the DEBUG UART.
49 */
50 #if (OPENTHREAD_CONFIG_LOG_OUTPUT == OPENTHREAD_CONFIG_LOG_OUTPUT_DEBUG_UART) && (!OPENTHREAD_CONFIG_ENABLE_DEBUG_UART)
51 #error "OPENTHREAD_CONFIG_ENABLE_DEBUG_UART_LOG requires OPENTHREAD_CONFIG_ENABLE_DEBUG_UART"
52 #endif
53
54 #if OPENTHREAD_CONFIG_LOG_PREPEND_UPTIME && !OPENTHREAD_CONFIG_UPTIME_ENABLE
55 #error "OPENTHREAD_CONFIG_LOG_PREPEND_UPTIME requires OPENTHREAD_CONFIG_UPTIME_ENABLE"
56 #endif
57
58 #if OPENTHREAD_CONFIG_LOG_PREPEND_UPTIME && OPENTHREAD_CONFIG_MULTIPLE_INSTANCE_ENABLE
59 #error "OPENTHREAD_CONFIG_LOG_PREPEND_UPTIME is not supported under OPENTHREAD_CONFIG_MULTIPLE_INSTANCE_ENABLE"
60 #endif
61
62 namespace ot {
63
64 #if OT_SHOULD_LOG
65
LogAtLevel(const char * aModuleName,const char * aFormat,...)66 template <LogLevel kLogLevel> void Logger::LogAtLevel(const char *aModuleName, const char *aFormat, ...)
67 {
68 va_list args;
69
70 va_start(args, aFormat);
71 LogVarArgs(aModuleName, kLogLevel, aFormat, args);
72 va_end(args);
73 }
74
75 // Explicit instantiations
76 template void Logger::LogAtLevel<kLogLevelNone>(const char *aModuleName, const char *aFormat, ...);
77 template void Logger::LogAtLevel<kLogLevelCrit>(const char *aModuleName, const char *aFormat, ...);
78 template void Logger::LogAtLevel<kLogLevelWarn>(const char *aModuleName, const char *aFormat, ...);
79 template void Logger::LogAtLevel<kLogLevelNote>(const char *aModuleName, const char *aFormat, ...);
80 template void Logger::LogAtLevel<kLogLevelInfo>(const char *aModuleName, const char *aFormat, ...);
81 template void Logger::LogAtLevel<kLogLevelDebg>(const char *aModuleName, const char *aFormat, ...);
82
LogInModule(const char * aModuleName,LogLevel aLogLevel,const char * aFormat,...)83 void Logger::LogInModule(const char *aModuleName, LogLevel aLogLevel, const char *aFormat, ...)
84 {
85 va_list args;
86
87 va_start(args, aFormat);
88 LogVarArgs(aModuleName, aLogLevel, aFormat, args);
89 va_end(args);
90 }
91
LogVarArgs(const char * aModuleName,LogLevel aLogLevel,const char * aFormat,va_list aArgs)92 void Logger::LogVarArgs(const char *aModuleName, LogLevel aLogLevel, const char *aFormat, va_list aArgs)
93 {
94 static const char kModuleNamePadding[] = "--------------";
95
96 ot::String<OPENTHREAD_CONFIG_LOG_MAX_SIZE> logString;
97
98 static_assert(sizeof(kModuleNamePadding) == kMaxLogModuleNameLength + 1, "Padding string is not correct");
99
100 #if OPENTHREAD_CONFIG_LOG_PREPEND_UPTIME
101 ot::Uptime::UptimeToString(ot::Instance::Get().Get<ot::Uptime>().GetUptime(), logString, /* aInlcudeMsec */ true);
102 logString.Append(" ");
103 #endif
104
105 #if OPENTHREAD_CONFIG_LOG_LEVEL_DYNAMIC_ENABLE
106 VerifyOrExit(Instance::GetLogLevel() >= aLogLevel);
107 #endif
108
109 #if OPENTHREAD_CONFIG_LOG_PREPEND_LEVEL
110 {
111 static const char kLevelChars[] = {
112 '-', /* kLogLevelNone */
113 'C', /* kLogLevelCrit */
114 'W', /* kLogLevelWarn */
115 'N', /* kLogLevelNote */
116 'I', /* kLogLevelInfo */
117 'D', /* kLogLevelDebg */
118 };
119
120 logString.Append("[%c] ", kLevelChars[aLogLevel]);
121 }
122 #endif
123
124 logString.Append("%.*s%s: ", kMaxLogModuleNameLength, aModuleName,
125 &kModuleNamePadding[StringLength(aModuleName, kMaxLogModuleNameLength)]);
126
127 logString.AppendVarArgs(aFormat, aArgs);
128
129 logString.Append("%s", OPENTHREAD_CONFIG_LOG_SUFFIX);
130 otPlatLog(aLogLevel, OT_LOG_REGION_CORE, "%s", logString.AsCString());
131
132 ExitNow();
133
134 exit:
135 return;
136 }
137
138 #if OPENTHREAD_CONFIG_LOG_PKT_DUMP
139
140 template <LogLevel kLogLevel>
DumpAtLevel(const char * aModuleName,const char * aText,const void * aData,uint16_t aDataLength)141 void Logger::DumpAtLevel(const char *aModuleName, const char *aText, const void *aData, uint16_t aDataLength)
142 {
143 DumpInModule(aModuleName, kLogLevel, aText, aData, aDataLength);
144 }
145
146 // Explicit instantiations
147 template void Logger::DumpAtLevel<kLogLevelNone>(const char *aModuleName,
148 const char *aText,
149 const void *aData,
150 uint16_t aDataLength);
151 template void Logger::DumpAtLevel<kLogLevelCrit>(const char *aModuleName,
152 const char *aText,
153 const void *aData,
154 uint16_t aDataLength);
155 template void Logger::DumpAtLevel<kLogLevelWarn>(const char *aModuleName,
156 const char *aText,
157 const void *aData,
158 uint16_t aDataLength);
159 template void Logger::DumpAtLevel<kLogLevelNote>(const char *aModuleName,
160 const char *aText,
161 const void *aData,
162 uint16_t aDataLength);
163 template void Logger::DumpAtLevel<kLogLevelInfo>(const char *aModuleName,
164 const char *aText,
165 const void *aData,
166 uint16_t aDataLength);
167 template void Logger::DumpAtLevel<kLogLevelDebg>(const char *aModuleName,
168 const char *aText,
169 const void *aData,
170 uint16_t aDataLength);
171
DumpLine(const char * aModuleName,LogLevel aLogLevel,const uint8_t * aData,const uint16_t aDataLength)172 void Logger::DumpLine(const char *aModuleName, LogLevel aLogLevel, const uint8_t *aData, const uint16_t aDataLength)
173 {
174 ot::String<kStringLineLength> string;
175
176 string.Append("|");
177
178 for (uint8_t i = 0; i < kDumpBytesPerLine; i++)
179 {
180 if (i < aDataLength)
181 {
182 string.Append(" %02X", aData[i]);
183 }
184 else
185 {
186 string.Append(" ..");
187 }
188
189 if (!((i + 1) % 8))
190 {
191 string.Append(" |");
192 }
193 }
194
195 string.Append(" ");
196
197 for (uint8_t i = 0; i < kDumpBytesPerLine; i++)
198 {
199 char c = '.';
200
201 if (i < aDataLength)
202 {
203 char byteAsChar = static_cast<char>(0x7f & aData[i]);
204
205 if (isprint(byteAsChar))
206 {
207 c = byteAsChar;
208 }
209 }
210
211 string.Append("%c", c);
212 }
213
214 LogInModule(aModuleName, aLogLevel, "%s", string.AsCString());
215 }
216
DumpInModule(const char * aModuleName,LogLevel aLogLevel,const char * aText,const void * aData,uint16_t aDataLength)217 void Logger::DumpInModule(const char *aModuleName,
218 LogLevel aLogLevel,
219 const char *aText,
220 const void *aData,
221 uint16_t aDataLength)
222 {
223 constexpr uint16_t kWidth = 72;
224 constexpr uint16_t kTextSuffixLen = sizeof("[ len=000]") - 1;
225
226 uint16_t txtLen = StringLength(aText, kWidth - kTextSuffixLen) + kTextSuffixLen;
227 ot::String<kStringLineLength> string;
228
229 VerifyOrExit(otLoggingGetLevel() >= aLogLevel);
230
231 for (uint16_t i = 0; i < static_cast<uint16_t>((kWidth - txtLen) / 2); i++)
232 {
233 string.Append("=");
234 }
235
236 string.Append("[%s len=%03u]", aText, aDataLength);
237
238 for (uint16_t i = 0; i < static_cast<uint16_t>(kWidth - txtLen - (kWidth - txtLen) / 2); i++)
239 {
240 string.Append("=");
241 }
242
243 LogInModule(aModuleName, aLogLevel, "%s", string.AsCString());
244
245 for (uint16_t i = 0; i < aDataLength; i += kDumpBytesPerLine)
246 {
247 DumpLine(aModuleName, aLogLevel, static_cast<const uint8_t *>(aData) + i,
248 Min(static_cast<uint8_t>(aDataLength - i), kDumpBytesPerLine));
249 }
250
251 string.Clear();
252
253 for (uint16_t i = 0; i < kWidth; i++)
254 {
255 string.Append("-");
256 }
257
258 LogInModule(aModuleName, aLogLevel, "%s", string.AsCString());
259
260 exit:
261 return;
262 }
263 #endif // OPENTHREAD_CONFIG_LOG_PKT_DUMP
264
265 #endif // OT_SHOULD_LOG
266
267 } // namespace ot
268