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 #include <sstream>
48
49 #include "common/code_utils.hpp"
50 #include "common/time.hpp"
51
52 static otbrLogLevel sLevel = OTBR_LOG_INFO;
53 static const char sLevelString[][8] = {
54 "[EMERG]", "[ALERT]", "[CRIT]", "[ERR ]", "[WARN]", "[NOTE]", "[INFO]", "[DEBG]",
55 };
56 static bool sSyslogDisabled = false;
57
58 static otbrLogLevel sDefaultLevel = OTBR_LOG_INFO;
59
60 /** Get the current debug log level */
otbrLogGetLevel(void)61 otbrLogLevel otbrLogGetLevel(void)
62 {
63 return sLevel;
64 }
65
66 /** Get the default log level */
otbrLogGetDefaultLevel(void)67 otbrLogLevel otbrLogGetDefaultLevel(void)
68 {
69 return sDefaultLevel;
70 }
71
72 /**
73 * Set current log level.
74 */
otbrLogSetLevel(otbrLogLevel aLevel)75 void otbrLogSetLevel(otbrLogLevel aLevel)
76 {
77 assert(aLevel >= OTBR_LOG_EMERG && aLevel <= OTBR_LOG_DEBUG);
78 sLevel = aLevel;
79 }
80
81 /** Enable/disable logging with syslog */
otbrLogSyslogSetEnabled(bool aEnabled)82 void otbrLogSyslogSetEnabled(bool aEnabled)
83 {
84 sSyslogDisabled = !aEnabled;
85 }
86
87 /** Initialize logging */
otbrLogInit(const char * aProgramName,otbrLogLevel aLevel,bool aPrintStderr,bool aSyslogDisable)88 void otbrLogInit(const char *aProgramName, otbrLogLevel aLevel, bool aPrintStderr, bool aSyslogDisable)
89 {
90 const char *ident;
91
92 assert(aProgramName != nullptr);
93 assert(aLevel >= OTBR_LOG_EMERG && aLevel <= OTBR_LOG_DEBUG);
94
95 ident = strrchr(aProgramName, '/');
96 ident = (ident != nullptr) ? ident + 1 : aProgramName;
97
98 otbrLogSyslogSetEnabled(!aSyslogDisable);
99
100 if (!sSyslogDisabled)
101 {
102 openlog(ident, (LOG_CONS | LOG_PID) | (aPrintStderr ? LOG_PERROR : 0), OTBR_SYSLOG_FACILITY_ID);
103 }
104 sLevel = aLevel;
105 sDefaultLevel = sLevel;
106 }
107
GetPrefix(const char * aLogTag)108 static const char *GetPrefix(const char *aLogTag)
109 {
110 // Log prefix format : -xxx-----
111 const uint8_t kMaxTagSize = 7;
112 const uint8_t kBufferSize = kMaxTagSize + 3;
113 static char prefix[kBufferSize];
114 uint8_t tagLength = strlen(aLogTag) > kMaxTagSize ? kMaxTagSize : strlen(aLogTag);
115 int index = 0;
116
117 if (strlen(aLogTag) > 0)
118 {
119 prefix[0] = '-';
120 memcpy(&prefix[1], aLogTag, tagLength);
121
122 index = tagLength + 1;
123
124 memset(&prefix[index], '-', kMaxTagSize - tagLength + 1);
125 index += kMaxTagSize - tagLength + 1;
126 }
127
128 prefix[index++] = '\0';
129
130 return prefix;
131 }
132
133 /** log to the syslog or standard out */
otbrLog(otbrLogLevel aLevel,const char * aLogTag,const char * aFormat,...)134 void otbrLog(otbrLogLevel aLevel, const char *aLogTag, const char *aFormat, ...)
135 {
136 const uint16_t kBufferSize = 1024;
137 va_list ap;
138 char buffer[kBufferSize];
139
140 va_start(ap, aFormat);
141
142 if ((aLevel <= sLevel) && (vsnprintf(buffer, sizeof(buffer), aFormat, ap) > 0))
143 {
144 if (sSyslogDisabled)
145 {
146 printf("%s%s: %s\n", sLevelString[aLevel], GetPrefix(aLogTag), buffer);
147 }
148 else
149 {
150 syslog(static_cast<int>(aLevel), "%s%s: %s", sLevelString[aLevel], GetPrefix(aLogTag), buffer);
151 }
152 }
153
154 va_end(ap);
155
156 return;
157 }
158
159 /** log to the syslog or standard out */
otbrLogv(otbrLogLevel aLevel,const char * aFormat,va_list aArgList)160 void otbrLogv(otbrLogLevel aLevel, const char *aFormat, va_list aArgList)
161 {
162 assert(aFormat);
163
164 if (aLevel <= sLevel)
165 {
166 otbrLogvNoFilter(aLevel, aFormat, aArgList);
167 }
168 }
169
170 /** log to the syslog or standard out */
otbrLogvNoFilter(otbrLogLevel aLevel,const char * aFormat,va_list aArgList)171 void otbrLogvNoFilter(otbrLogLevel aLevel, const char *aFormat, va_list aArgList)
172 {
173 if (sSyslogDisabled)
174 {
175 vprintf(aFormat, aArgList);
176 printf("\n");
177 }
178 else
179 {
180 vsyslog(static_cast<int>(aLevel), aFormat, aArgList);
181 }
182 }
183
184 /** Hex dump data to the log */
otbrDump(otbrLogLevel aLevel,const char * aLogTag,const char * aPrefix,const void * aMemory,size_t aSize)185 void otbrDump(otbrLogLevel aLevel, const char *aLogTag, const char *aPrefix, const void *aMemory, size_t aSize)
186 {
187 static const char kHexChars[] = "0123456789abcdef";
188 assert(aPrefix && (aMemory || aSize == 0));
189 const uint8_t *pEnd;
190 const uint8_t *p8;
191 int addr;
192
193 if (aLevel >= sLevel)
194 {
195 return;
196 }
197
198 /* break hex dumps into 16byte lines
199 * In the form ADDR: XX XX XX XX ...
200 */
201
202 // we pre-increment... so subtract
203 addr = -16;
204
205 while (aSize > 0)
206 {
207 size_t this_size;
208 char hex[16 * 3 + 1];
209
210 addr = addr + 16;
211 p8 = (const uint8_t *)(aMemory) + addr;
212
213 /* truncate line to max 16 bytes */
214 this_size = aSize;
215 if (this_size > 16)
216 {
217 this_size = 16;
218 }
219 aSize = aSize - this_size;
220
221 char *ch = hex - 1;
222
223 for (pEnd = p8 + this_size; p8 < pEnd; p8++)
224 {
225 *++ch = kHexChars[(*p8) >> 4];
226 *++ch = kHexChars[(*p8) & 0x0f];
227 *++ch = ' ';
228 }
229 *ch = 0;
230
231 otbrLog(aLevel, aLogTag, "%s: %04x: %s", aPrefix, addr, hex);
232 }
233 }
234
otbrErrorString(otbrError aError)235 const char *otbrErrorString(otbrError aError)
236 {
237 const char *error;
238
239 switch (aError)
240 {
241 case OTBR_ERROR_NONE:
242 error = "OK";
243 break;
244
245 case OTBR_ERROR_ERRNO:
246 error = strerror(errno);
247 break;
248
249 case OTBR_ERROR_DBUS:
250 error = "DBUS error";
251 break;
252
253 case OTBR_ERROR_MDNS:
254 error = "MDNS error";
255 break;
256
257 case OTBR_ERROR_OPENTHREAD:
258 error = "OpenThread error";
259 break;
260
261 case OTBR_ERROR_NOT_FOUND:
262 error = "Not found";
263 break;
264
265 case OTBR_ERROR_PARSE:
266 error = "Parse error";
267 break;
268
269 case OTBR_ERROR_NOT_IMPLEMENTED:
270 error = "Not implemented";
271 break;
272
273 case OTBR_ERROR_INVALID_ARGS:
274 error = "Invalid arguments";
275 break;
276
277 case OTBR_ERROR_DUPLICATED:
278 error = "Duplicated";
279 break;
280
281 case OTBR_ERROR_ABORTED:
282 error = "Aborted";
283 break;
284
285 case OTBR_ERROR_INVALID_STATE:
286 error = "Invalid state";
287 break;
288
289 default:
290 error = "Unknown";
291 }
292
293 return error;
294 }
295
otbrLogDeinit(void)296 void otbrLogDeinit(void)
297 {
298 closelog();
299 }
300