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