1 /*
2 * Copyright (c) 2017, 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 #define OTBR_LOG_TAG "LOG"
30
31 #ifndef OTBR_SYSLOG_FACILITY_ID
32 #define OTBR_SYSLOG_FACILITY_ID LOG_USER
33 #endif
34
35 #include "common/logging.hpp"
36
37 #include <assert.h>
38 #include <errno.h>
39 #include <stdarg.h>
40 #include <stdint.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <sys/time.h>
45 #include <syslog.h>
46
47 #if OTBR_ENABLE_PLATFORM_ANDROID
48 #include <log/log.h>
49 #endif
50
51 #include <sstream>
52
53 #include "common/code_utils.hpp"
54 #include "common/time.hpp"
55
56 static otbrLogLevel sLevel = OTBR_LOG_INFO;
57 static const char sLevelString[][8] = {
58 "[EMERG]", "[ALERT]", "[CRIT]", "[ERR ]", "[WARN]", "[NOTE]", "[INFO]", "[DEBG]",
59 };
60 static bool sSyslogDisabled = false;
61
62 static otbrLogLevel sDefaultLevel = OTBR_LOG_INFO;
63
64 /** Get the current debug log level */
otbrLogGetLevel(void)65 otbrLogLevel otbrLogGetLevel(void)
66 {
67 return sLevel;
68 }
69
70 /** Get the default log level */
otbrLogGetDefaultLevel(void)71 otbrLogLevel otbrLogGetDefaultLevel(void)
72 {
73 return sDefaultLevel;
74 }
75
76 /**
77 * Set current log level.
78 */
otbrLogSetLevel(otbrLogLevel aLevel)79 void otbrLogSetLevel(otbrLogLevel aLevel)
80 {
81 assert(aLevel >= OTBR_LOG_EMERG && aLevel <= OTBR_LOG_DEBUG);
82 sLevel = aLevel;
83 }
84
85 /** Enable/disable logging with syslog */
otbrLogSyslogSetEnabled(bool aEnabled)86 void otbrLogSyslogSetEnabled(bool aEnabled)
87 {
88 sSyslogDisabled = !aEnabled;
89 }
90
91 /** Initialize logging */
otbrLogInit(const char * aProgramName,otbrLogLevel aLevel,bool aPrintStderr,bool aSyslogDisable)92 void otbrLogInit(const char *aProgramName, otbrLogLevel aLevel, bool aPrintStderr, bool aSyslogDisable)
93 {
94 assert(aLevel >= OTBR_LOG_EMERG && aLevel <= OTBR_LOG_DEBUG);
95 otbrLogSyslogSetEnabled(!aSyslogDisable);
96
97 #if OTBR_ENABLE_PLATFORM_ANDROID
98 OTBR_UNUSED_VARIABLE(aProgramName);
99 #else
100 assert(aProgramName != nullptr);
101
102 if (!sSyslogDisabled)
103 {
104 const char *ident;
105
106 ident = strrchr(aProgramName, '/');
107 ident = (ident != nullptr) ? ident + 1 : aProgramName;
108
109 openlog(ident, (LOG_CONS | LOG_PID) | (aPrintStderr ? LOG_PERROR : 0), OTBR_SYSLOG_FACILITY_ID);
110 }
111 #endif
112
113 sLevel = aLevel;
114 sDefaultLevel = sLevel;
115 }
116
GetPrefix(const char * aLogTag)117 static const char *GetPrefix(const char *aLogTag)
118 {
119 // Log prefix format : -xxx-----
120 const uint8_t kMaxTagSize = 7;
121 const uint8_t kBufferSize = kMaxTagSize + 3;
122 static char prefix[kBufferSize];
123 uint8_t tagLength = strlen(aLogTag) > kMaxTagSize ? kMaxTagSize : strlen(aLogTag);
124 int index = 0;
125
126 if (strlen(aLogTag) > 0)
127 {
128 prefix[0] = '-';
129 memcpy(&prefix[1], aLogTag, tagLength);
130
131 index = tagLength + 1;
132
133 memset(&prefix[index], '-', kMaxTagSize - tagLength + 1);
134 index += kMaxTagSize - tagLength + 1;
135 }
136
137 prefix[index++] = '\0';
138
139 return prefix;
140 }
141
142 #if OTBR_ENABLE_PLATFORM_ANDROID
ConvertToAndroidLogPriority(otbrLogLevel aLevel)143 static android_LogPriority ConvertToAndroidLogPriority(otbrLogLevel aLevel)
144 {
145 android_LogPriority priority;
146
147 switch (aLevel)
148 {
149 case OTBR_LOG_EMERG:
150 case OTBR_LOG_ALERT:
151 case OTBR_LOG_CRIT:
152 priority = ANDROID_LOG_FATAL;
153 break;
154 case OTBR_LOG_ERR:
155 priority = ANDROID_LOG_ERROR;
156 break;
157 case OTBR_LOG_WARNING:
158 priority = ANDROID_LOG_WARN;
159 break;
160 case OTBR_LOG_NOTICE:
161 case OTBR_LOG_INFO:
162 priority = ANDROID_LOG_INFO;
163 break;
164 case OTBR_LOG_DEBUG:
165 default:
166 priority = ANDROID_LOG_DEBUG;
167 break;
168 }
169
170 return priority;
171 }
172 #endif
173
174 /** log to the syslog or standard out */
otbrLog(otbrLogLevel aLevel,const char * aLogTag,const char * aFormat,...)175 void otbrLog(otbrLogLevel aLevel, const char *aLogTag, const char *aFormat, ...)
176 {
177 const uint16_t kBufferSize = 1024;
178 va_list ap;
179 char buffer[kBufferSize];
180
181 va_start(ap, aFormat);
182
183 if ((aLevel <= sLevel) && (vsnprintf(buffer, sizeof(buffer), aFormat, ap) > 0))
184 {
185 if (sSyslogDisabled)
186 {
187 printf("%s%s: %s\n", sLevelString[aLevel], GetPrefix(aLogTag), buffer);
188 }
189 else
190 {
191 #if OTBR_ENABLE_PLATFORM_ANDROID
192 __android_log_print(ConvertToAndroidLogPriority(aLevel), LOG_TAG, "%s%s: %s", sLevelString[aLevel],
193 GetPrefix(aLogTag), buffer);
194 #else
195 syslog(static_cast<int>(aLevel), "%s%s: %s", sLevelString[aLevel], GetPrefix(aLogTag), buffer);
196 #endif
197 }
198 }
199
200 va_end(ap);
201
202 return;
203 }
204
205 /** log to the syslog or standard out */
otbrLogv(otbrLogLevel aLevel,const char * aFormat,va_list aArgList)206 void otbrLogv(otbrLogLevel aLevel, const char *aFormat, va_list aArgList)
207 {
208 assert(aFormat);
209
210 if (aLevel <= sLevel)
211 {
212 otbrLogvNoFilter(aLevel, aFormat, aArgList);
213 }
214 }
215
216 /** log to the syslog or standard out */
otbrLogvNoFilter(otbrLogLevel aLevel,const char * aFormat,va_list aArgList)217 void otbrLogvNoFilter(otbrLogLevel aLevel, const char *aFormat, va_list aArgList)
218 {
219 if (sSyslogDisabled)
220 {
221 vprintf(aFormat, aArgList);
222 printf("\n");
223 }
224 else
225 {
226 #if OTBR_ENABLE_PLATFORM_ANDROID
227 __android_log_vprint(ConvertToAndroidLogPriority(aLevel), LOG_TAG, aFormat, aArgList);
228 #else
229 vsyslog(static_cast<int>(aLevel), aFormat, aArgList);
230 #endif
231 }
232 }
233
234 /** Hex dump data to the log */
otbrDump(otbrLogLevel aLevel,const char * aLogTag,const char * aPrefix,const void * aMemory,size_t aSize)235 void otbrDump(otbrLogLevel aLevel, const char *aLogTag, const char *aPrefix, const void *aMemory, size_t aSize)
236 {
237 static const char kHexChars[] = "0123456789abcdef";
238 assert(aPrefix && (aMemory || aSize == 0));
239 const uint8_t *pEnd;
240 const uint8_t *p8;
241 int addr;
242
243 if (aLevel >= sLevel)
244 {
245 return;
246 }
247
248 /* break hex dumps into 16byte lines
249 * In the form ADDR: XX XX XX XX ...
250 */
251
252 // we pre-increment... so subtract
253 addr = -16;
254
255 while (aSize > 0)
256 {
257 size_t this_size;
258 char hex[16 * 3 + 1];
259
260 addr = addr + 16;
261 p8 = (const uint8_t *)(aMemory) + addr;
262
263 /* truncate line to max 16 bytes */
264 this_size = aSize;
265 if (this_size > 16)
266 {
267 this_size = 16;
268 }
269 aSize = aSize - this_size;
270
271 char *ch = hex - 1;
272
273 for (pEnd = p8 + this_size; p8 < pEnd; p8++)
274 {
275 *++ch = kHexChars[(*p8) >> 4];
276 *++ch = kHexChars[(*p8) & 0x0f];
277 *++ch = ' ';
278 }
279 *ch = 0;
280
281 otbrLog(aLevel, aLogTag, "%s: %04x: %s", aPrefix, addr, hex);
282 }
283 }
284
otbrErrorString(otbrError aError)285 const char *otbrErrorString(otbrError aError)
286 {
287 const char *error;
288
289 switch (aError)
290 {
291 case OTBR_ERROR_NONE:
292 error = "OK";
293 break;
294
295 case OTBR_ERROR_ERRNO:
296 error = strerror(errno);
297 break;
298
299 case OTBR_ERROR_DBUS:
300 error = "DBUS error";
301 break;
302
303 case OTBR_ERROR_MDNS:
304 error = "MDNS error";
305 break;
306
307 case OTBR_ERROR_OPENTHREAD:
308 error = "OpenThread error";
309 break;
310
311 case OTBR_ERROR_NOT_FOUND:
312 error = "Not found";
313 break;
314
315 case OTBR_ERROR_PARSE:
316 error = "Parse error";
317 break;
318
319 case OTBR_ERROR_NOT_IMPLEMENTED:
320 error = "Not implemented";
321 break;
322
323 case OTBR_ERROR_INVALID_ARGS:
324 error = "Invalid arguments";
325 break;
326
327 case OTBR_ERROR_DUPLICATED:
328 error = "Duplicated";
329 break;
330
331 case OTBR_ERROR_ABORTED:
332 error = "Aborted";
333 break;
334
335 case OTBR_ERROR_INVALID_STATE:
336 error = "Invalid state";
337 break;
338
339 default:
340 error = "Unknown";
341 }
342
343 return error;
344 }
345
otbrLogDeinit(void)346 void otbrLogDeinit(void)
347 {
348 closelog();
349 }
350
ConvertToOtLogLevel(otbrLogLevel aLevel)351 otLogLevel ConvertToOtLogLevel(otbrLogLevel aLevel)
352 {
353 otLogLevel level;
354
355 switch (aLevel)
356 {
357 case OTBR_LOG_EMERG:
358 case OTBR_LOG_ALERT:
359 case OTBR_LOG_CRIT:
360 level = OT_LOG_LEVEL_CRIT;
361 break;
362 case OTBR_LOG_ERR:
363 case OTBR_LOG_WARNING:
364 level = OT_LOG_LEVEL_WARN;
365 break;
366 case OTBR_LOG_NOTICE:
367 level = OT_LOG_LEVEL_NOTE;
368 break;
369 case OTBR_LOG_INFO:
370 level = OT_LOG_LEVEL_INFO;
371 break;
372 case OTBR_LOG_DEBUG:
373 default:
374 level = OT_LOG_LEVEL_DEBG;
375 break;
376 }
377
378 return level;
379 }
380