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