Update snapshot(2017-12-14)
[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 #include "iotivity_config.h"
34
35 // Pull in _POSIX_TIMERS feature test macro to check for
36 // clock_gettime() support.
37 #ifdef HAVE_UNISTD_H
38 #include <unistd.h>
39 #endif
40
41 #ifdef HAVE_ARDUINO_TIME_H
42 #include <Time.h>
43 #else
44 #include <time.h>
45 #endif
46
47 #ifdef HAVE_SYS_TIME_H
48 #include <sys/time.h>
49 #endif
50 #ifdef HAVE_WINDOWS_H
51 #include <windows.h>
52 #endif
53
54 #include "logger.h"
55 #include "string.h"
56 #include "logger_types.h"
57
58 // log level
59 LogLevel g_level = DEBUG;
60 // privacy log
61 bool g_hidePrivateLogEntries = false;
62
63 #ifndef __TIZEN__
64 static oc_log_ctx_t *logCtx = 0;
65 #endif
66
67 #if defined(_MSC_VER)
68 #define LINE_BUFFER_SIZE (16 * 2) + 16 + 1  // Show 16 bytes, 2 chars/byte, spaces between bytes, null termination
69 #define S_LINE_BUFFER_SIZE (50 * 2) + 50 + 1  // Show 50 bytes, 2 chars/byte, spaces between bytes, null termination
70 #else
71 static const uint16_t LINE_BUFFER_SIZE = (16 * 2) + 16 + 1;  // Show 16 bytes, 2 chars/byte, spaces between bytes, null termination
72 static const uint16_t S_LINE_BUFFER_SIZE = (50 * 2) + 50 + 1;  // Show 50 bytes, 2 chars/byte, spaces between bytes, null termination
73 #endif //defined(_MSC_VER)
74
75 #if defined(__ANDROID__) || defined(__TIZEN__)
76 #elif defined __linux__ || defined __APPLE__ || defined _WIN32 || defined(__TIZENRT__)
77 static oc_log_level LEVEL_XTABLE[] = {OC_LOG_DEBUG, OC_LOG_INFO,
78                                       OC_LOG_WARNING, OC_LOG_ERROR, OC_LOG_FATAL};
79 #endif
80
81 // Convert LogLevel to platform-specific severity level.  Store in PROGMEM on Arduino
82 #ifdef __ANDROID__
83 #ifdef ADB_SHELL
84     static const char *LEVEL[] =
85     {"DEBUG", "INFO", "WARNING", "ERROR", "FATAL"};
86
87 #else
88     static android_LogPriority LEVEL[] =
89     {ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, ANDROID_LOG_WARN, ANDROID_LOG_ERROR, ANDROID_LOG_FATAL};
90 #endif
91 #elif defined(__linux__) || defined(__APPLE__) || defined(__msys_nt__)|| defined(__TIZENRT__)
92     static const char * LEVEL[] __attribute__ ((unused)) = {"DEBUG", "INFO", "WARNING", "ERROR", "FATAL"};
93 #elif defined(_MSC_VER)
94     static const char * LEVEL[] = {"DEBUG", "INFO", "WARNING", "ERROR", "FATAL"};
95 #elif defined ARDUINO
96 #include <stdarg.h>
97 #include "Arduino.h"
98 #include "oic_string.h"
99
100     PROGMEM const char level0[] = "DEBUG";
101     PROGMEM const char level1[] = "INFO";
102     PROGMEM const char level2[] = "WARNING";
103     PROGMEM const char level3[] = "ERROR";
104     PROGMEM const char level4[] = "FATAL";
105
106     PROGMEM const char * const LEVEL[]  = {level0, level1, level2, level3, level4};
107
108     static void OCLogString(LogLevel level, PROGMEM const char * tag, PROGMEM const char * logStr);
109 #ifdef ARDUINO_ARCH_AVR
110     //Mega2560 and other 8-bit AVR microcontrollers
111     #define GET_PROGMEM_BUFFER(buffer, addr) { OICStrcpy(buffer, sizeof(buffer), (char*)pgm_read_word(addr));}
112 #elif defined ARDUINO_ARCH_SAM
113     //Arduino Due and other 32-bit ARM micro-controllers
114     #define GET_PROGMEM_BUFFER(buffer, addr) { OICStrcpy(buffer, sizeof(buffer), (char*)pgm_read_dword(addr));}
115 #else
116     #define GET_PROGMEM_BUFFER(buffer, addr) { buffer[0] = '\0';}
117 #endif
118 #else // !defined(__ANDROID__) && !defined(ARDUINO)
119     static const char *LEVEL[] __attribute__ ((unused)) =
120     {"DEBUG", "INFO", "WARNING", "ERROR", "FATAL"};
121 #endif
122
123 #ifndef ARDUINO
124
125 /**
126  * Output the contents of the specified buffer (in hex) with the specified priority level.
127  *
128  * @param level      - DEBUG, INFO, WARNING, ERROR, FATAL
129  * @param tag        - Module name
130  * @param buffer     - pointer to buffer of bytes
131  * @param bufferSize - max number of byte in buffer
132  */
133 void OCLogBuffer(LogLevel level, const char * tag, const uint8_t * buffer, uint16_t bufferSize)
134 {
135     if (!buffer || !tag || (bufferSize == 0))
136     {
137         return;
138     }
139
140     // No idea why the static initialization won't work here, it seems the compiler is convinced
141     // that this is a variable-sized object.
142     char lineBuffer[LINE_BUFFER_SIZE];
143     memset(lineBuffer, 0, sizeof lineBuffer);
144     int lineIndex = 0;
145     int i;
146     for (i = 0; i < bufferSize; i++)
147     {
148         // Format the buffer data into a line
149         snprintf(&lineBuffer[lineIndex*3], sizeof(lineBuffer)-lineIndex*3, "%02X ", buffer[i]);
150         lineIndex++;
151         // Output 16 values per line
152         if (((i+1)%16) == 0)
153         {
154             OCLogv(level, tag, "%s", lineBuffer);
155             memset(lineBuffer, 0, sizeof lineBuffer);
156             lineIndex = 0;
157         }
158     }
159     // Output last values in the line, if any
160     if (bufferSize % 16)
161     {
162         OCLogv(level, tag, "%s", lineBuffer);
163     }
164 }
165
166 void OCPrintCALogBuffer(LogLevel level, const char *tag, const uint8_t *buffer,
167                         uint16_t bufferSize, uint8_t isHeader)
168 {
169     if (!buffer || !tag || (bufferSize == 0))
170     {
171         return;
172     }
173
174     // No idea why the static initialization won't work here, it seems the compiler is convinced
175     // that this is a variable-sized object.
176     char lineBuffer[S_LINE_BUFFER_SIZE];
177     int lineIndex = 0;
178     int i;
179     for (i = 0; i < bufferSize; i++)
180     {
181         // Format the buffer data into a line
182         snprintf(&lineBuffer[lineIndex*3], sizeof(lineBuffer)-lineIndex*3, "%02X ", buffer[i]);
183         lineIndex++;
184         // Output 50 values per line
185         if (((i+1)%50) == 0)
186         {
187             if (1 == isHeader)
188             {
189                 OCLogv(level, tag, "| Analyzer(Header) | %s", lineBuffer);
190             }
191             else
192             {
193                 OCLogv(level, tag, "| Analyzer(Body) | %s", lineBuffer);
194             }
195             memset(lineBuffer, 0, sizeof lineBuffer);
196             lineIndex = 0;
197         }
198     }
199
200     if (bufferSize % 50)
201     {
202         if (1 == isHeader)
203         {
204             OCLogv(level, tag, "| Analyzer(Header) | %s", lineBuffer);
205         }
206         else
207         {
208             OCLogv(level, tag, "| Analyzer(Body) | %s", lineBuffer);
209         }
210     }
211 }
212
213 void OCSetLogLevel(LogLevel level, bool hidePrivateLogEntries)
214 {
215     g_level = level;
216     g_hidePrivateLogEntries = hidePrivateLogEntries;
217 }
218
219 bool OCGetPrivateLogLevel()
220 {
221     return g_hidePrivateLogEntries;
222 }
223
224 #ifndef __TIZEN__
225 void OCLogConfig(oc_log_ctx_t *ctx)
226 {
227     logCtx = ctx;
228 }
229
230 void OCLogInit()
231 {
232
233 }
234
235 void OCLogShutdown()
236 {
237 #if defined(__linux__) || defined(__APPLE__) || defined(_WIN32)|| defined(__TIZENRT__)
238     if (logCtx && logCtx->destroy)
239     {
240         logCtx->destroy(logCtx);
241     }
242 #endif
243 }
244
245 /**
246  * Output a variable argument list log string with the specified priority level.
247  * Only defined for Linux and Android
248  *
249  * @param level  - DEBUG, INFO, WARNING, ERROR, FATAL
250  * @param tag    - Module name
251  * @param format - variadic log string
252  */
253 void OCLogv(LogLevel level, const char * tag, const char * format, ...)
254 {
255     if (!format || !tag) {
256         return;
257     }
258
259     if (g_level > level && ERROR != level && WARNING != level && FATAL != level)
260     {
261         return;
262     }
263
264     if (true == g_hidePrivateLogEntries && INFO_PRIVATE == level)
265     {
266         return;
267     }
268
269     char buffer[MAX_LOG_V_BUFFER_SIZE] = {0};
270     va_list args;
271     va_start(args, format);
272     vsnprintf(buffer, sizeof buffer - 1, format, args);
273     va_end(args);
274     OCLog(level, tag, buffer);
275 }
276
277 /**
278  * Output a log string with the specified priority level.
279  * Only defined for Linux and Android
280  *
281  * @param level  - DEBUG, INFO, WARNING, ERROR, FATAL
282  * @param tag    - Module name
283  * @param logStr - log string
284  */
285 void OCLog(LogLevel level, const char * tag, const char * logStr)
286 {
287     if (!logStr || !tag)
288     {
289        return;
290     }
291
292     if (g_level > level && ERROR != level && WARNING != level && FATAL != level)
293     {
294         return;
295     }
296
297     if (true == g_hidePrivateLogEntries && INFO_PRIVATE == level)
298     {
299         return;
300     }
301
302     switch(level)
303     {
304         case DEBUG_LITE:
305             level = DEBUG;
306             break;
307         case INFO_LITE:
308             level = INFO;
309             break;
310         case INFO_PRIVATE:
311             level = INFO;
312             break;
313         default:
314             break;
315     }
316
317    #ifdef __ANDROID__
318
319    #ifdef ADB_SHELL
320        printf("%s: %s: %s\n", LEVEL[level], tag, logStr);
321    #else
322        __android_log_write(LEVEL[level], tag, logStr);
323    #endif
324
325    #else
326        if (logCtx && logCtx->write_level)
327        {
328            logCtx->write_level(logCtx, LEVEL_XTABLE[level], logStr);
329
330        }
331        else
332        {
333            int min = 0;
334            int sec = 0;
335            int ms = 0;
336    #if defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0
337            struct timespec when = { .tv_sec = 0, .tv_nsec = 0 };
338            clockid_t clk = CLOCK_REALTIME;
339    #ifdef CLOCK_REALTIME_COARSE
340            clk = CLOCK_REALTIME_COARSE;
341    #endif
342            if (!clock_gettime(clk, &when))
343            {
344                min = (when.tv_sec / 60) % 60;
345                sec = when.tv_sec % 60;
346                ms = when.tv_nsec / 1000000;
347            }
348    #elif defined(_WIN32)
349            SYSTEMTIME systemTime = {0};
350            GetLocalTime(&systemTime);
351            min = (int)systemTime.wMinute;
352            sec = (int)systemTime.wSecond;
353            ms  = (int)systemTime.wMilliseconds;
354    #else
355            struct timeval now;
356            if (!gettimeofday(&now, NULL))
357            {
358                min = (now.tv_sec / 60) % 60;
359                sec = now.tv_sec % 60;
360                ms = now.tv_usec * 1000;
361            }
362    #endif
363            printf("%02d:%02d.%03d %s: %s: %s\n", min, sec, ms, LEVEL[level], tag, logStr);
364        }
365    #endif
366    }
367 #endif //__TIZEN__
368 #endif //ARDUINO
369 #ifdef ARDUINO
370 /**
371  * Initialize the serial logger for Arduino
372  * Only defined for Arduino
373  */
374 void OCLogInit()
375 {
376     Serial.begin(115200);
377 }
378
379 /**
380  * Output a log string with the specified priority level.
381  * Only defined for Arduino.  Only uses PROGMEM strings
382  * for the tag parameter
383  *
384  * @param level  - DEBUG, INFO, WARNING, ERROR, FATAL
385  * @param tag    - Module name
386  * @param logStr - log string
387  */
388 void OCLogString(LogLevel level, PROGMEM const char * tag, const char * logStr)
389 {
390     if (!logStr || !tag)
391     {
392       return;
393     }
394
395     char buffer[LINE_BUFFER_SIZE];
396
397     GET_PROGMEM_BUFFER(buffer, &(LEVEL[level]));
398     Serial.print(buffer);
399
400     char c;
401     Serial.print(F(": "));
402     while ((c = pgm_read_byte(tag)))
403     {
404       Serial.write(c);
405       tag++;
406     }
407     Serial.print(F(": "));
408
409     Serial.println(logStr);
410 }
411
412 /**
413  * Output the contents of the specified buffer (in hex) with the specified
414  * priority level.
415  *
416  * @param level      - DEBUG, INFO, WARNING, ERROR, FATAL
417  * @param tag        - Module name
418  * @param buffer     - pointer to buffer of bytes
419  * @param bufferSize - max number of byte in buffer
420  */
421  void OCLogBuffer(LogLevel level, PROGMEM const char * tag,
422                   const uint8_t * buffer, size_t bufferSize)
423  {
424      if (!buffer || !tag || (bufferSize == 0))
425      {
426          return;
427      }
428
429      char lineBuffer[LINE_BUFFER_SIZE] = {0};
430      uint8_t lineIndex = 0;
431      for (uint8_t i = 0; i < bufferSize; i++)
432      {
433         // Format the buffer data into a line
434         snprintf(&lineBuffer[lineIndex*3], sizeof(lineBuffer)-lineIndex*3, "%02X ", buffer[i]);
435         lineIndex++;
436          // Output 16 values per line
437          if (((i+1)%16) == 0)
438          {
439              OCLogString(level, tag, lineBuffer);
440              memset(lineBuffer, 0, sizeof lineBuffer);
441              lineIndex = 0;
442          }
443      }
444      // Output last values in the line, if any
445      if (bufferSize % 16)
446      {
447          OCLogString(level, tag, lineBuffer);
448      }
449  }
450
451 /**
452  * Output a log string with the specified priority level.
453  * Only defined for Arduino.  Uses PROGMEM strings
454  *
455  * @param level  - DEBUG, INFO, WARNING, ERROR, FATAL
456  * @param tag    - Module name
457  * @param logStr - log string
458  */
459 void OCLog(LogLevel level, PROGMEM const char *tag, const int lineNum,
460            PROGMEM const char *logStr)
461 {
462     if (!logStr || !tag)
463     {
464         return;
465     }
466     char buffer[LINE_BUFFER_SIZE] = {0};
467     GET_PROGMEM_BUFFER(buffer, &(LEVEL[level]));
468     Serial.print(buffer);
469     char c;
470     Serial.print(F(": "));
471     while ((c = pgm_read_byte(tag)))
472     {
473         Serial.write(c);
474         tag++;
475     }
476     Serial.print(F(": "));
477     Serial.print(lineNum);
478     Serial.print(F(": "));
479     while ((c = pgm_read_byte(logStr)))
480     {
481         Serial.write(c);
482         logStr++;
483     }
484     Serial.println();
485 }
486
487 /**
488  * Output a variable argument list log string with the specified priority level.
489  * Only defined for Arduino as depicted below.
490  *
491  * @param level  - DEBUG, INFO, WARNING, ERROR, FATAL
492  * @param tag    - Module name
493  * @param format - variadic log string
494  */
495 void OCLogv(LogLevel level, PROGMEM const char *tag, const int lineNum,
496                 PROGMEM const char *format, ...)
497 {
498     char buffer[LINE_BUFFER_SIZE];
499     va_list ap;
500     va_start(ap, format);
501     GET_PROGMEM_BUFFER(buffer, &(LEVEL[level]));
502     Serial.print(buffer);
503
504     char c;
505     Serial.print(F(": "));
506     while ((c = pgm_read_byte(tag)))
507     {
508      Serial.write(c);
509      tag++;
510      }
511     Serial.print(F(": "));
512     Serial.print(lineNum);
513     Serial.print(F(": "));
514
515 #ifdef __AVR__
516     vsnprintf_P(buffer, sizeof(buffer), format, ap);
517 #else
518     vsnprintf(buffer, sizeof(buffer), format, ap);
519 #endif
520     for (char *p = &buffer[0]; *p; p++)
521     {
522         // emulate cooked mode for newlines
523         if (*p == '\n')
524         {
525             Serial.write('\r');
526         }
527         Serial.write(*p);
528     }
529     Serial.println();
530     va_end(ap);
531 }
532 /**
533  * Output a variable argument list log string with the specified priority level.
534  * Only defined for Arduino as depicted below.
535  *
536  * @param level  - DEBUG, INFO, WARNING, ERROR, FATAL
537  * @param tag    - Module name
538  * @param format - variadic log string
539  */
540 void OCLogv(LogLevel level, const char *tag, const __FlashStringHelper *format, ...)
541 {
542     char buffer[LINE_BUFFER_SIZE];
543     va_list ap;
544     va_start(ap, format);
545     // strcpy_P(buffer, (char*)pgm_read_word(&(LEVEL[level])));
546     // Serial.print(buffer);
547
548     Serial.print(LEVEL[level]);
549     // char c;
550     Serial.print(F(": "));
551
552     /*while ((c = pgm_read_byte(tag))) {
553      Serial.write(c);
554      tag++;
555      }*/
556     Serial.print(tag);
557     Serial.print(F(": "));
558
559 #ifdef __AVR__
560     vsnprintf_P(buffer, sizeof(buffer), (const char *)format, ap); // progmem for AVR
561 #else
562     vsnprintf(buffer, sizeof(buffer), (const char *)format, ap); // for the rest of the world
563 #endif
564     for (char *p = &buffer[0]; *p; p++)
565     {
566         // emulate cooked mode for newlines
567         if (*p == '\n')
568         {
569             // Serial.write('\r');
570             Serial.print('\r');
571         }
572         //Serial.write(*p);
573         Serial.print(p);
574     }
575     Serial.println();
576     va_end(ap);
577 }
578
579 #endif //ARDUINO