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