• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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