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