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