Merge remote-tracking branch 'origin/routing-manager'
[platform/upstream/iotivity.git] / resource / csdk / connectivity / common / 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 "oic_logger.h"
52 #include "oic_console_logger.h"
53
54 #ifndef __TIZEN__
55 static oic_log_ctx_t *logCtx = 0;
56
57 #ifndef __ANDROID__
58 static oic_log_level LEVEL_XTABLE[] =
59 { OIC_LOG_DEBUG, OIC_LOG_INFO, OIC_LOG_WARNING, OIC_LOG_ERROR, OIC_LOG_FATAL };
60 #endif
61
62 #endif
63
64 static const uint16_t LINE_BUFFER_SIZE = (16 * 2) + 16 +
65         1; // Show 16 bytes, 2 chars/byte, spaces between bytes, null termination
66
67 // Convert LogLevel to platform-specific severity level.  Store in PROGMEM on Arduino
68 #ifdef __ANDROID__
69 #ifdef ADB_SHELL
70 static const char *LEVEL[] =
71 {   "DEBUG", "INFO", "WARNING", "ERROR", "FATAL"};
72
73 #else
74 static android_LogPriority LEVEL[] =
75 {   ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, ANDROID_LOG_WARN, ANDROID_LOG_ERROR, ANDROID_LOG_FATAL};
76 #endif
77 #elif defined (__linux__) || defined (__APPLE__)
78 static const char *LEVEL[] __attribute__ ((unused)) =
79 {   "DEBUG", "INFO", "WARNING", "ERROR", "FATAL"};
80 #elif defined ARDUINO
81 #include <stdarg.h>
82 #include "Arduino.h"
83
84 PROGMEM const char level0[] = "DEBUG";
85 PROGMEM const char level1[] = "INFO";
86 PROGMEM const char level2[] = "WARNING";
87 PROGMEM const char level3[] = "ERROR";
88 PROGMEM const char level4[] = "FATAL";
89
90 PROGMEM const char *const LEVEL[] =
91 {   level0, level1, level2, level3, level4};
92
93 static void OICLogString(LogLevel level, PROGMEM const char *tag, PROGMEM const char *logStr);
94 #ifdef ARDUINO_ARCH_AVR
95 //Mega2560 and other 8-bit AVR microcontrollers
96 #define GET_PROGMEM_BUFFER(buffer, addr) { strcpy_P(buffer, (char*)pgm_read_word(addr));}
97 #elif defined ARDUINO_ARCH_SAM
98 //Arduino Due and other 32-bit ARM micro-controllers
99 #define GET_PROGMEM_BUFFER(buffer, addr) { strcpy_P(buffer, (char*)pgm_read_dword(addr));}
100 #else
101 #define GET_PROGMEM_BUFFER(buffer, addr) { buffer[0] = '\0';}
102 #endif
103 #endif // __ANDROID__
104
105 #ifndef ARDUINO
106 #ifndef __TIZEN__
107 void OICLogConfig(oic_log_ctx_t *ctx)
108 {
109     logCtx = ctx;
110 }
111
112 void OICLogInit()
113 {
114
115 }
116
117 void OICLogShutdown()
118 {
119 #if defined(__linux__) || defined(__APPLE__)
120     if (logCtx && logCtx->destroy)
121     {
122         logCtx->destroy(logCtx);
123     }
124 #endif
125 }
126
127 /**
128  * Output a log string with the specified priority level.
129  * Only defined for Linux and Android
130  *
131  * @param level  - DEBUG, INFO, WARNING, ERROR, FATAL
132  * @param tag    - Module name
133  * @param logStr - log string
134  */
135 void OICLog(LogLevel level, const char *tag, const char *logStr)
136 {
137     if (!logStr || !tag)
138     {
139         return;
140     }
141
142 #ifdef __ANDROID__
143
144 #ifdef ADB_SHELL
145     printf("%s: %s: %s\n", LEVEL[level], tag, logStr);
146 #else
147     __android_log_write(LEVEL[level], tag, logStr);
148 #endif
149
150 #elif defined __linux__ || defined __APPLE__
151     if (logCtx && logCtx->write_level)
152     {
153         logCtx->write_level(logCtx, LEVEL_XTABLE[level], logStr);
154
155     }
156     else
157     {
158         int min = 0;
159         int sec = 0;
160         int ms = 0;
161 #if defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0
162         struct timespec when = { 0, 0 };
163         clockid_t clk = CLOCK_REALTIME;
164 #ifdef CLOCK_REALTIME_COARSE
165         clk = CLOCK_REALTIME_COARSE;
166 #endif
167         if (!clock_gettime(clk, &when))
168         {
169             min = (when.tv_sec / 60) % 60;
170             sec = when.tv_sec % 60;
171             ms = when.tv_nsec / 1000000;
172         }
173 #else
174         struct timeval now;
175         if (!gettimeofday(&now, NULL))
176         {
177             min = (now.tv_sec / 60) % 60;
178             sec = now.tv_sec % 60;
179             ms = now.tv_usec * 1000;
180         }
181 #endif
182         printf("%02d:%02d.%03d %s: %s: %s\n", min, sec, ms, LEVEL[level], tag, logStr);
183     }
184 #endif
185 }
186
187 /**
188  * Output a variable argument list log string with the specified priority level.
189  * Only defined for Linux and Android
190  *
191  * @param level  - DEBUG, INFO, WARNING, ERROR, FATAL
192  * @param tag    - Module name
193  * @param format - variadic log string
194  */
195 void OICLogv(LogLevel level, const char *tag, const char *format, ...)
196 {
197     if (!format || !tag)
198     {
199         return;
200     }
201     char buffer[MAX_LOG_V_BUFFER_SIZE] = {};
202     va_list args;
203     va_start(args, format);
204     vsnprintf(buffer, sizeof buffer - 1, format, args);
205     va_end(args);
206     OICLog(level, tag, buffer);
207 }
208
209 /**
210  * Output the contents of the specified buffer (in hex) with the specified priority level.
211  *
212  * @param level      - DEBUG, INFO, WARNING, ERROR, FATAL
213  * @param tag        - Module name
214  * @param buffer     - pointer to buffer of bytes
215  * @param bufferSize - max number of byte in buffer
216  */
217 void OICLogBuffer(LogLevel level, const char *tag, const uint8_t *buffer, uint16_t bufferSize)
218 {
219     if (!buffer || !tag || (bufferSize == 0))
220     {
221         return;
222     }
223
224     // I've got no idea why static initialization doesn't work here.  It seems that the compiler
225     // seems to think that this is a variable-sized object
226     char lineBuffer[LINE_BUFFER_SIZE];
227     memset(lineBuffer, 0, sizeof lineBuffer);
228     int lineIndex = 0;
229     int i;
230     for (i = 0; i < bufferSize; i++)
231     {
232         // Format the buffer data into a line
233         snprintf(&lineBuffer[lineIndex*3], sizeof(lineBuffer)-lineIndex*3, "%02X ", buffer[i]);
234         lineIndex++;
235         // Output 16 values per line
236         if (((i + 1) % 16) == 0)
237         {
238             OICLog(level, tag, lineBuffer);
239             memset(lineBuffer, 0, sizeof lineBuffer);
240             lineIndex = 0;
241         }
242     }
243     // Output last values in the line, if any
244     if (bufferSize % 16)
245     {
246         OICLog(level, tag, lineBuffer);
247     }
248 }
249 #endif //__TIZEN__
250 #endif //ARDUINO
251 #ifdef ARDUINO
252 /**
253  * Initialize the serial logger for Arduino
254  * Only defined for Arduino
255  */
256 void OICLogInit()
257 {
258     Serial.begin(115200);
259 }
260
261 /**
262  * Output a log string with the specified priority level.
263  * Only defined for Arduino.  Only uses PROGMEM strings
264  * for the tag parameter
265  *
266  * @param level  - DEBUG, INFO, WARNING, ERROR, FATAL
267  * @param tag    - Module name
268  * @param logStr - log string
269  */
270  void OICLogString(LogLevel level, PROGMEM const char * tag,
271          const char * logStr)
272  {
273      if (!logStr || !tag)
274      {
275          return;
276      }
277
278      char buffer[LINE_BUFFER_SIZE] = {};
279      strcpy_P(buffer, (char*)pgm_read_word(&(LEVEL[level])));
280      Serial.print(buffer);
281
282      char c = NULL;
283      Serial.print(F(": "));
284      while ((c = pgm_read_byte(tag)))
285      {
286          Serial.write(c);
287          tag++;
288      }
289      Serial.print(F(": "));
290
291      Serial.println(logStr);
292  }
293
294 /**
295  * Output the contents of the specified buffer (in hex) with the specified
296  * priority level.
297  *
298  * @param level      - DEBUG, INFO, WARNING, ERROR, FATAL
299  * @param tag        - Module name
300  * @param buffer     - pointer to buffer of bytes
301  * @param bufferSize - max number of byte in buffer
302  */
303  void OICLogBuffer(LogLevel level, PROGMEM const char * tag,
304          const uint8_t * buffer, uint16_t bufferSize)
305  {
306      if (!buffer || !tag || (bufferSize == 0))
307      {
308          return;
309      }
310
311      char lineBuffer[LINE_BUFFER_SIZE] = {0};
312      uint8_t lineIndex = 0;
313      for (uint8_t i = 0; i < bufferSize; i++)
314      {
315         // Format the buffer data into a line
316         snprintf(&lineBuffer[lineIndex*3], sizeof(lineBuffer)-lineIndex*3, "%02X ", buffer[i]);
317         lineIndex++;
318          // Output 16 values per line
319          if (((i+1)%16) == 0)
320          {
321              OICLogString(level, tag, lineBuffer);
322              memset(lineBuffer, 0, sizeof lineBuffer);
323              lineIndex = 0;
324          }
325      }
326      // Output last values in the line, if any
327      if (bufferSize % 16)
328      {
329          OICLogString(level, tag, lineBuffer);
330      }
331  }
332
333 /**
334  * Output a log string with the specified priority level.
335  * Only defined for Arduino.  Uses PROGMEM strings
336  *
337  * @param level  - DEBUG, INFO, WARNING, ERROR, FATAL
338  * @param tag    - Module name
339  * @param logStr - log string
340  */
341 void OICLog(LogLevel level, PROGMEM const char *tag, const int16_t lineNum,
342               PROGMEM const char *logStr)
343 {
344     if (!logStr || !tag)
345     {
346         return;
347     }
348     char buffer[LINE_BUFFER_SIZE] = {0};
349     GET_PROGMEM_BUFFER(buffer, &(LEVEL[level]));
350     Serial.print(buffer);
351     char c;
352     Serial.print(F(": "));
353     while ((c = pgm_read_byte(tag)))
354     {
355         Serial.write(c);
356         tag++;
357     }
358     Serial.print(F(": "));
359     Serial.print(lineNum);
360     Serial.print(F(": "));
361     while ((c = pgm_read_byte(logStr)))
362     {
363         Serial.write(c);
364         logStr++;
365     }
366     Serial.println();
367 }
368
369 /**
370  * Output a variable argument list log string with the specified priority level.
371  * Only defined for Arduino as depicted below.
372  *
373  * @param level  - DEBUG, INFO, WARNING, ERROR, FATAL
374  * @param tag    - Module name
375  * @param format - variadic log string
376  */
377 void OICLogv(LogLevel level, PROGMEM const char *tag, const int16_t lineNum,
378                 PROGMEM const char *format, ...)
379 {
380     char buffer[LINE_BUFFER_SIZE];
381     va_list ap;
382     va_start(ap, format);
383     GET_PROGMEM_BUFFER(buffer, &(LEVEL[level]));
384     Serial.print(buffer);
385
386     char c;
387     Serial.print(F(": "));
388     while ((c = pgm_read_byte(tag))) {
389      Serial.write(c);
390      tag++;
391      }
392     Serial.print(F(": "));
393     Serial.print(lineNum);
394     Serial.print(F(": "));
395
396 #ifdef __AVR__
397     vsnprintf_P(buffer, sizeof(buffer), format, ap);
398 #else
399     vsnprintf(buffer, sizeof(buffer), format, ap);
400 #endif
401     for (char *p = &buffer[0]; *p; p++)
402     {
403         // emulate cooked mode for newlines
404         if (*p == '\n')
405         {
406             Serial.write('\r');
407         }
408         Serial.write(*p);
409     }
410     Serial.println();
411     va_end(ap);
412 }
413 /**
414  * Output a variable argument list log string with the specified priority level.
415  * Only defined for Arduino as depicted below.
416  *
417  * @param level  - DEBUG, INFO, WARNING, ERROR, FATAL
418  * @param tag    - Module name
419  * @param format - variadic log string
420  */
421 void OICLogv(LogLevel level, const char *tag, const __FlashStringHelper *format, ...)
422 {
423     char buffer[LINE_BUFFER_SIZE];
424     va_list ap;
425     va_start(ap, format);
426     // strcpy_P(buffer, (char*)pgm_read_word(&(LEVEL[level])));
427     // Serial.print(buffer);
428
429     Serial.print(LEVEL[level]);
430     // char c;
431     Serial.print(F(": "));
432
433     /*while ((c = pgm_read_byte(tag))) {
434      Serial.write(c);
435      tag++;
436      }*/
437     Serial.print(tag);
438     Serial.print(F(": "));
439
440 #ifdef __AVR__
441     vsnprintf_P(buffer, sizeof(buffer), (const char *)format, ap); // progmem for AVR
442 #else
443     vsnprintf(buffer, sizeof(buffer), (const char *)format, ap); // for the rest of the world
444 #endif
445     for (char *p = &buffer[0]; *p; p++)
446     {
447         // emulate cooked mode for newlines
448         if (*p == '\n')
449         {
450             // Serial.write('\r');
451             Serial.print('\r');
452         }
453         //Serial.write(*p);
454         Serial.print(p);
455     }
456     Serial.println();
457     va_end(ap);
458 }
459
460 #endif //ARDUINO