Imported Upstream version 0.9.2
[platform/upstream/iotivity.git] / resource / csdk / logger / src / logger.c
1 //******************************************************************
2 //
3 // Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21 // Defining _POSIX_C_SOURCE macro with 199309L (or greater) as value
22 // causes header files to expose definitions
23 // corresponding to the POSIX.1b, Real-time extensions
24 // (IEEE Std 1003.1b-1993) specification
25 //
26 // For this specific file, see use of clock_gettime,
27 // Refer to http://pubs.opengroup.org/stage7tc1/functions/clock_gettime.html
28 // and to http://man7.org/linux/man-pages/man2/clock_gettime.2.html
29 #ifndef _POSIX_C_SOURCE
30 #define _POSIX_C_SOURCE 200809L
31 #endif
32
33 // Platform check can be extended to check and/or define more, or could be
34 // moved into a config.h
35 #if !defined(__ARDUINO__) && !defined(ARDUINO)
36 #define HAVE_UNISTD_H 1
37 #endif
38
39 // Pull in _POSIX_TIMERS feature test macro to check for
40 // clock_gettime() support.
41 #ifdef HAVE_UNISTD_H
42 #include <unistd.h>
43
44 // if we have unistd.h, we're a Unix system
45 #include <time.h>
46 #include <sys/time.h>
47 #endif
48
49 #include "logger.h"
50 #include "string.h"
51 #include "oc_logger.h"
52 #include "oc_console_logger.h"
53
54 static oc_log_ctx_t *logCtx = 0;
55
56 static oc_log_level LEVEL_XTABLE[] = {OC_LOG_DEBUG, OC_LOG_INFO, OC_LOG_WARNING, OC_LOG_ERROR, OC_LOG_FATAL};
57
58 static const uint16_t LINE_BUFFER_SIZE = (16 * 2) + 16 + 1;  // Show 16 bytes, 2 chars/byte, spaces between bytes, null termination
59
60 // Convert LogLevel to platform-specific severity level.  Store in PROGMEM on Arduino
61 #ifdef __ANDROID__
62     static android_LogPriority LEVEL[] = {ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, ANDROID_LOG_WARN, ANDROID_LOG_ERROR, ANDROID_LOG_FATAL};
63 #elif defined(__linux__) || defined(__APPLE__)
64     static const char * LEVEL[] __attribute__ ((unused)) = {"DEBUG", "INFO", "WARNING", "ERROR", "FATAL"};
65 #elif defined ARDUINO
66     #include <stdarg.h>
67
68     PROGMEM const char level0[] = "DEBUG";
69     PROGMEM const char level1[] = "INFO";
70     PROGMEM const char level2[] = "WARNING";
71     PROGMEM const char level3[] = "ERROR";
72     PROGMEM const char level4[] = "FATAL";
73
74     PROGMEM const char * const LEVEL[]  = {level0, level1, level2, level3, level4};
75
76     static void OCLogString(LogLevel level, PROGMEM const char * tag, PROGMEM const char * logStr);
77 #ifdef ARDUINO_ARCH_AVR
78     //Mega2560 and other 8-bit AVR microcontrollers
79     #define GET_PROGMEM_BUFFER(buffer, addr) { strcpy_P(buffer, (char*)pgm_read_word(addr));}
80 #elif defined ARDUINO_ARCH_SAM
81     //Arduino Due and other 32-bit ARM micro-controllers
82     #define GET_PROGMEM_BUFFER(buffer, addr) { strcpy_P(buffer, (char*)pgm_read_dword(addr));}
83 #else
84     #define GET_PROGMEM_BUFFER(buffer, addr) { buffer[0] = '\0';}
85 #endif
86 #endif // __ANDROID__
87
88
89 #ifndef ARDUINO
90
91 void OCLogConfig(oc_log_ctx_t *ctx) {
92     logCtx = ctx;
93 }
94
95 void OCLogInit() {
96
97 }
98
99 void OCLogShutdown() {
100 #if defined(__linux__) || defined(__APPLE__)
101     if (logCtx && logCtx->destroy)
102     {
103         logCtx->destroy(logCtx);
104     }
105 #endif
106 }
107
108 /**
109  * Output a variable argument list log string with the specified priority level.
110  * Only defined for Linux and Android
111  *
112  * @param level  - DEBUG, INFO, WARNING, ERROR, FATAL
113  * @param tag    - Module name
114  * @param format - variadic log string
115  */
116 void OCLogv(LogLevel level, const char * tag, const char * format, ...) {
117     if (!format || !tag) {
118         return;
119     }
120     char buffer[MAX_LOG_V_BUFFER_SIZE] = {};
121     va_list args;
122     va_start(args, format);
123     vsnprintf(buffer, sizeof buffer - 1, format, args);
124     va_end(args);
125     OCLog(level, tag, buffer);
126 }
127
128 static void osalGetTime(int *min,int *sec, int *ms)
129 {
130     if (min && sec && ms)
131     {
132 #if defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0
133         struct timespec when = {};
134         clockid_t clk = CLOCK_REALTIME;
135 #ifdef CLOCK_REALTIME_COARSE
136         clk = CLOCK_REALTIME_COARSE;
137 #endif
138         if (!clock_gettime(clk, &when))
139         {
140             *min = (when.tv_sec / 60) % 60;
141             *sec = when.tv_sec % 60;
142             *ms = when.tv_nsec / 1000000;
143         }
144 #else
145         struct timeval now;
146         if (!gettimeofday(&now, NULL))
147         {
148             *min = (now.tv_sec / 60) % 60;
149             *sec = now.tv_sec % 60;
150             *ms = now.tv_usec * 1000;
151         }
152 #endif
153     }
154 }
155
156 /**
157  * Output a log string with the specified priority level.
158  * Only defined for Linux and Android
159  *
160  * @param level  - DEBUG, INFO, WARNING, ERROR, FATAL
161  * @param tag    - Module name
162  * @param logStr - log string
163  */
164 void OCLog(LogLevel level, const char * tag, const char * logStr) {
165     if (!logStr || !tag) {
166         return;
167     }
168
169 #ifdef __ANDROID__
170     __android_log_write(LEVEL[level], tag, logStr);
171 #elif defined(__linux__) || defined(__APPLE__)
172     if (logCtx && logCtx->write_level)
173     {
174         logCtx->write_level(logCtx, LEVEL_XTABLE[level], logStr);
175     }
176     else
177     {
178
179         int min = 0;
180         int sec = 0;
181         int ms = 0;
182         osalGetTime(&min,&sec,&ms);
183
184         printf("%02d:%02d.%03d %s: %s: %s\n", min, sec, ms, LEVEL[level], tag, logStr);
185     }
186 #endif
187 }
188
189 /**
190  * Output the contents of the specified buffer (in hex) with the specified priority level.
191  *
192  * @param level      - DEBUG, INFO, WARNING, ERROR, FATAL
193  * @param tag        - Module name
194  * @param buffer     - pointer to buffer of bytes
195  * @param bufferSize - max number of byte in buffer
196  */
197 void OCLogBuffer(LogLevel level, const char * tag, const uint8_t * buffer, uint16_t bufferSize) {
198     if (!buffer || !tag || (bufferSize == 0)) {
199         return;
200     }
201
202     // No idea why the static initialization won't work here, it seems the compiler is convinced
203     // that this is a variable-sized object.
204     char lineBuffer[LINE_BUFFER_SIZE];
205     memset(lineBuffer, 0, sizeof lineBuffer);
206     int lineIndex = 0;
207     int i;
208     for (i = 0; i < bufferSize; i++) {
209         // Format the buffer data into a line
210         snprintf(&lineBuffer[lineIndex*3], sizeof(lineBuffer)-lineIndex*3, "%02X ", buffer[i]);
211         lineIndex++;
212         // Output 16 values per line
213         if (((i+1)%16) == 0) {
214             OCLog(level, tag, lineBuffer);
215             memset(lineBuffer, 0, sizeof lineBuffer);
216             lineIndex = 0;
217         }
218     }
219     // Output last values in the line, if any
220     if (bufferSize % 16) {
221         OCLog(level, tag, lineBuffer);
222     }
223 }
224
225 #else
226     /**
227      * Initialize the serial logger for Arduino
228      * Only defined for Arduino
229      */
230     void OCLogInit() {
231         Serial.begin(115200);
232     }
233
234     /**
235      * Output a log string with the specified priority level.
236      * Only defined for Arduino.  Only uses PROGMEM strings
237      * for the tag parameter
238      *
239      * @param level  - DEBUG, INFO, WARNING, ERROR, FATAL
240      * @param tag    - Module name
241      * @param logStr - log string
242      */
243     void OCLogString(LogLevel level, PROGMEM const char * tag, const char * logStr) {
244         if (!logStr || !tag) {
245           return;
246         }
247
248         char buffer[LINE_BUFFER_SIZE];
249
250         GET_PROGMEM_BUFFER(buffer, &(LEVEL[level]));
251         Serial.print(buffer);
252
253         char c;
254         Serial.print(F(": "));
255         while ((c = pgm_read_byte(tag))) {
256           Serial.write(c);
257           tag++;
258         }
259         Serial.print(F(": "));
260
261         Serial.println(logStr);
262     }
263
264     /**
265      * Output the contents of the specified buffer (in hex) with the specified priority level.
266      *
267      * @param level      - DEBUG, INFO, WARNING, ERROR, FATAL
268      * @param tag        - Module name
269      * @param buffer     - pointer to buffer of bytes
270      * @param bufferSize - max number of byte in buffer
271      */
272     void OCLogBuffer(LogLevel level, PROGMEM const char * tag, const uint8_t * buffer, uint16_t bufferSize) {
273         if (!buffer || !tag || (bufferSize == 0)) {
274             return;
275         }
276
277         char lineBuffer[LINE_BUFFER_SIZE] = {0};
278         uint8_t lineIndex = 0;
279         for (uint8_t i = 0; i < bufferSize; i++) {
280             // Format the buffer data into a line
281             snprintf(&lineBuffer[lineIndex*3], sizeof(lineBuffer)-lineIndex*3, "%02X ", buffer[i]);
282             lineIndex++;
283             // Output 16 values per line
284             if (((i+1)%16) == 0) {
285                 OCLogString(level, tag, lineBuffer);
286                 memset(lineBuffer, 0, sizeof lineBuffer);
287                 lineIndex = 0;
288             }
289         }
290         // Output last values in the line, if any
291         if (bufferSize % 16) {
292             OCLogString(level, tag, lineBuffer);
293         }
294     }
295
296     /**
297      * Output a log string with the specified priority level.
298      * Only defined for Arduino.  Uses PROGMEM strings
299      *
300      * @param level  - DEBUG, INFO, WARNING, ERROR, FATAL
301      * @param tag    - Module name
302      * @param logStr - log string
303      */
304     void OCLog(LogLevel level, PROGMEM const char * tag, PROGMEM const char * logStr) {
305         if (!logStr || !tag) {
306           return;
307         }
308
309         char buffer[LINE_BUFFER_SIZE];
310
311         GET_PROGMEM_BUFFER(buffer, &(LEVEL[level]));
312         Serial.print(buffer);
313
314         char c;
315         Serial.print(F(": "));
316         while ((c = pgm_read_byte(tag))) {
317           Serial.write(c);
318           tag++;
319         }
320         Serial.print(F(": "));
321
322         while ((c = pgm_read_byte(logStr))) {
323           Serial.write(c);
324           logStr++;
325         }
326         Serial.println();
327     }
328
329     /**
330      * Output a variable argument list log string with the specified priority level.
331      * Only defined for Arduino as depicted below.
332      *
333      * @param level  - DEBUG, INFO, WARNING, ERROR, FATAL
334      * @param tag    - Module name
335      * @param format - variadic log string
336      */
337     void OCLogv(LogLevel level, PROGMEM const char * tag, const char * format, ...)
338     {
339         char buffer[LINE_BUFFER_SIZE];
340         va_list ap;
341         va_start(ap, format);
342
343         GET_PROGMEM_BUFFER(buffer, &(LEVEL[level]));
344         Serial.print(buffer);
345
346         char c;
347         Serial.print(F(": "));
348
349         while ((c = pgm_read_byte(tag))) {
350             Serial.write(c);
351             tag++;
352         }
353         Serial.print(F(": "));
354
355         vsnprintf(buffer, sizeof(buffer), format, ap);
356         for(char *p = &buffer[0]; *p; p++) // emulate cooked mode for newlines
357         {
358             if(*p == '\n')
359             {
360                 Serial.write('\r');
361             }
362             Serial.write(*p);
363         }
364         Serial.println();
365         va_end(ap);
366     }
367     /**
368      * Output a variable argument list log string with the specified priority level.
369      * Only defined for Arduino as depicted below.
370      *
371      * @param level  - DEBUG, INFO, WARNING, ERROR, FATAL
372      * @param tag    - Module name
373      * @param format - variadic log string
374      */
375     void OCLogv(LogLevel level, PROGMEM const char * tag, const __FlashStringHelper *format, ...)
376     {
377         char buffer[LINE_BUFFER_SIZE];
378         va_list ap;
379         va_start(ap, format);
380
381         GET_PROGMEM_BUFFER(buffer, &(LEVEL[level]));
382         Serial.print(buffer);
383
384         char c;
385         Serial.print(F(": "));
386
387         while ((c = pgm_read_byte(tag))) {
388           Serial.write(c);
389           tag++;
390         }
391         Serial.print(F(": "));
392
393         #ifdef __AVR__
394             vsnprintf_P(buffer, sizeof(buffer), (const char *)format, ap); // progmem for AVR
395         #else
396             vsnprintf(buffer, sizeof(buffer), (const char *)format, ap); // for the rest of the world
397         #endif
398         for(char *p = &buffer[0]; *p; p++) // emulate cooked mode for newlines
399         {
400             if(*p == '\n')
401             {
402                 Serial.write('\r');
403             }
404             Serial.write(*p);
405         }
406         Serial.println();
407         va_end(ap);
408     }
409
410
411 #endif
412
413
414