Update the use of clock_gettime(2)
[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 static oic_log_level LEVEL_XTABLE[] =
58 { OIC_LOG_DEBUG, OIC_LOG_INFO, OIC_LOG_WARNING, OIC_LOG_ERROR, OIC_LOG_FATAL };
59
60 #endif
61
62 static const uint16_t LINE_BUFFER_SIZE = (16 * 2) + 16 +
63         1; // Show 16 bytes, 2 chars/byte, spaces between bytes, null termination
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__
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
82 PROGMEM const char level0[] = "DEBUG";
83 PROGMEM const char level1[] = "INFO";
84 PROGMEM const char level2[] = "WARNING";
85 PROGMEM const char level3[] = "ERROR";
86 PROGMEM const char level4[] = "FATAL";
87
88 PROGMEM const char *const LEVEL[] =
89 {   level0, level1, level2, level3, level4};
90
91 static void OICLogString(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) { strcpy_P(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) { strcpy_P(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 #ifndef __TIZEN__
105 void OICLogConfig(oic_log_ctx_t *ctx)
106 {
107     logCtx = ctx;
108 }
109
110 void OICLogInit()
111 {
112
113 }
114
115 void OICLogShutdown()
116 {
117 #ifdef __linux__
118     if (logCtx && logCtx->destroy)
119     {
120         logCtx->destroy(logCtx);
121     }
122 #endif
123 }
124
125 /**
126  * Output a log string with the specified priority level.
127  * Only defined for Linux and Android
128  *
129  * @param level  - DEBUG, INFO, WARNING, ERROR, FATAL
130  * @param tag    - Module name
131  * @param logStr - log string
132  */
133 void OICLog(LogLevel level, const char *tag, const char *logStr)
134 {
135     if (!logStr || !tag)
136     {
137         return;
138     }
139
140 #ifdef __ANDROID__
141
142 #ifdef ADB_SHELL
143     printf("%s: %s: %s\n", LEVEL[level], tag, logStr);
144 #else
145     __android_log_write(LEVEL[level], tag, logStr);
146 #endif
147
148 #elif defined __linux__
149     if (logCtx && logCtx->write_level)
150     {
151         logCtx->write_level(logCtx, LEVEL_XTABLE[level], logStr);
152
153     }
154     else
155     {
156         int min = 0;
157         int sec = 0;
158         int ms = 0;
159 #ifdef _POSIX_TIMERS
160         struct timespec when = {};
161         clockid_t clk = CLOCK_REALTIME;
162 #ifdef CLOCK_REALTIME_COARSE
163         clk = CLOCK_REALTIME_COARSE;
164 #endif
165         if (!clock_gettime(clk, &when))
166         {
167             min = (when.tv_sec / 60) % 60;
168             sec = when.tv_sec % 60;
169             ms = when.tv_nsec / 1000000;
170         }
171 #else
172         struct timeval now;
173         if (!gettimeofday(&now, NULL))
174         {
175             min = (now.tv_sec / 60) % 60;
176             sec = now.tv_sec % 60;
177             ms = now.tv_usec * 1000;
178         }
179 #endif
180         printf("%02d:%02d.%03d %s: %s: %s\n", min, sec, ms, LEVEL[level], tag, logStr);
181     }
182 #endif
183 }
184
185 /**
186  * Output a variable argument list 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 format - variadic log string
192  */
193 void OICLogv(LogLevel level, const char *tag, const char *format, ...)
194 {
195     if (!format || !tag)
196     {
197         return;
198     }
199     char buffer[MAX_LOG_V_BUFFER_SIZE];
200     memset(buffer, 0, sizeof buffer);
201     va_list args;
202     va_start(args, format);
203     vsnprintf(buffer, sizeof buffer - 1, format, args);
204     va_end(args);
205     OICLog(level, tag, buffer);
206 }
207
208 /**
209  * Output the contents of the specified buffer (in hex) with the specified priority level.
210  *
211  * @param level      - DEBUG, INFO, WARNING, ERROR, FATAL
212  * @param tag        - Module name
213  * @param buffer     - pointer to buffer of bytes
214  * @param bufferSize - max number of byte in buffer
215  */
216 void OICLogBuffer(LogLevel level, const char *tag, const uint8_t *buffer, uint16_t bufferSize)
217 {
218     if (!buffer || !tag || (bufferSize == 0))
219     {
220         return;
221     }
222
223     char lineBuffer[LINE_BUFFER_SIZE];
224     memset(lineBuffer, 0, sizeof lineBuffer);
225     int lineIndex = 0;
226     int i;
227     for (i = 0; i < bufferSize; i++)
228     {
229         // Format the buffer data into a line
230         sprintf(&lineBuffer[lineIndex++ * 3], "%02X ", buffer[i]);
231         // Output 16 values per line
232         if (((i + 1) % 16) == 0)
233         {
234             OICLog(level, tag, lineBuffer);
235             memset(lineBuffer, 0, sizeof lineBuffer);
236             lineIndex = 0;
237         }
238     }
239     // Output last values in the line, if any
240     if (bufferSize % 16)
241     {
242         OICLog(level, tag, lineBuffer);
243     }
244 }
245 #endif //__TIZEN__
246 #endif //ARDUINO
247 #ifdef ARDUINO
248 /**
249  * Initialize the serial logger for Arduino
250  * Only defined for Arduino
251  */
252 void OICLogInit()
253 {
254     Serial.begin(115200);
255 }
256
257 /**
258  * Output a log string with the specified priority level.
259  * Only defined for Arduino.  Only uses PROGMEM strings
260  * for the tag parameter
261  *
262  * @param level  - DEBUG, INFO, WARNING, ERROR, FATAL
263  * @param tag    - Module name
264  * @param logStr - log string
265  */
266  void OICLogString(LogLevel level, PROGMEM const char * tag,
267          const char * logStr)
268  {
269      if (!logStr || !tag)
270      {
271          return;
272      }
273
274      char buffer[LINE_BUFFER_SIZE] = {0};
275      strcpy_P(buffer, (char*)pgm_read_word(&(LEVEL[level])));
276      Serial.print(buffer);
277
278      char c = NULL;
279      Serial.print(F(": "));
280      while ((c = pgm_read_byte(tag)))
281      {
282          Serial.write(c);
283          tag++;
284      }
285      Serial.print(F(": "));
286
287      Serial.println(logStr);
288  }
289
290 /**
291  * Output the contents of the specified buffer (in hex) with the specified
292  * priority level.
293  *
294  * @param level      - DEBUG, INFO, WARNING, ERROR, FATAL
295  * @param tag        - Module name
296  * @param buffer     - pointer to buffer of bytes
297  * @param bufferSize - max number of byte in buffer
298  */
299  void OICLogBuffer(LogLevel level, PROGMEM const char * tag,
300          const uint8_t * buffer, uint16_t bufferSize)
301  {
302      if (!buffer || !tag || (bufferSize == 0))
303      {
304          return;
305      }
306
307      char lineBuffer[LINE_BUFFER_SIZE] = {0};
308      uint8_t lineIndex = 0;
309      for (uint8_t i = 0; i < bufferSize; i++)
310      {
311          // Format the buffer data into a line
312          sprintf(&lineBuffer[lineIndex++ * 3], "%02X ", buffer[i]);
313          // Output 16 values per line
314          if (((i+1)%16) == 0)
315          {
316              OICLogString(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          OICLogString(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 OICLog(LogLevel level, PROGMEM const char *tag, const int16_t 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 OICLogv(LogLevel level, PROGMEM const char *tag, const int16_t 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      Serial.write(c);
385      tag++;
386      }
387     Serial.print(F(": "));
388     Serial.print(lineNum);
389     Serial.print(F(": "));
390
391 #ifdef __AVR__
392     vsnprintf_P(buffer, sizeof(buffer), format, ap);
393 #else
394     vsnprintf(buffer, sizeof(buffer), format, ap);
395 #endif
396     for (char *p = &buffer[0]; *p; p++)
397     {
398         // emulate cooked mode for newlines
399         if (*p == '\n')
400         {
401             Serial.write('\r');
402         }
403         Serial.write(*p);
404     }
405     Serial.println();
406     va_end(ap);
407 }
408 /**
409  * Output a variable argument list log string with the specified priority level.
410  * Only defined for Arduino as depicted below.
411  *
412  * @param level  - DEBUG, INFO, WARNING, ERROR, FATAL
413  * @param tag    - Module name
414  * @param format - variadic log string
415  */
416 void OICLogv(LogLevel level, const char *tag, const __FlashStringHelper *format, ...)
417 {
418     char buffer[LINE_BUFFER_SIZE];
419     va_list ap;
420     va_start(ap, format);
421     // strcpy_P(buffer, (char*)pgm_read_word(&(LEVEL[level])));
422     // Serial.print(buffer);
423
424     Serial.print(LEVEL[level]);
425     // char c;
426     Serial.print(F(": "));
427
428     /*while ((c = pgm_read_byte(tag))) {
429      Serial.write(c);
430      tag++;
431      }*/
432     Serial.print(tag);
433     Serial.print(F(": "));
434
435 #ifdef __AVR__
436     vsnprintf_P(buffer, sizeof(buffer), (const char *)format, ap); // progmem for AVR
437 #else
438     vsnprintf(buffer, sizeof(buffer), (const char *)format, ap); // for the rest of the world
439 #endif
440     for (char *p = &buffer[0]; *p; p++)
441     {
442         // emulate cooked mode for newlines
443         if (*p == '\n')
444         {
445             // Serial.write('\r');
446             Serial.print('\r');
447         }
448         //Serial.write(*p);
449         Serial.print(p);
450     }
451     Serial.println();
452     va_end(ap);
453 }
454
455 #endif //ARDUINO
456