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