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