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