684c0ba78c3be7b71622eed3fdae30ea26729275
[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         sprintf(&lineBuffer[lineIndex++ * 3], "%02X ", buffer[i]);
150         // Output 16 values per line
151         if (((i+1)%16) == 0) {
152             OCLog(level, tag, lineBuffer);
153             memset(lineBuffer, 0, sizeof lineBuffer);
154             lineIndex = 0;
155         }
156     }
157     // Output last values in the line, if any
158     if (bufferSize % 16) {
159         OCLog(level, tag, lineBuffer);
160     }
161 }
162
163 #else
164     /**
165      * Initialize the serial logger for Arduino
166      * Only defined for Arduino
167      */
168     void OCLogInit() {
169         Serial.begin(115200);
170     }
171
172     /**
173      * Output a log string with the specified priority level.
174      * Only defined for Arduino.  Only uses PROGMEM strings
175      * for the tag parameter
176      *
177      * @param level  - DEBUG, INFO, WARNING, ERROR, FATAL
178      * @param tag    - Module name
179      * @param logStr - log string
180      */
181     void OCLogString(LogLevel level, PROGMEM const char * tag, const char * logStr) {
182         if (!logStr || !tag) {
183           return;
184         }
185
186         char buffer[LINE_BUFFER_SIZE];
187
188         GET_PROGMEM_BUFFER(buffer, &(LEVEL[level]));
189         Serial.print(buffer);
190
191         char c;
192         Serial.print(F(": "));
193         while ((c = pgm_read_byte(tag))) {
194           Serial.write(c);
195           tag++;
196         }
197         Serial.print(F(": "));
198
199         Serial.println(logStr);
200     }
201
202     /**
203      * Output the contents of the specified buffer (in hex) with the specified priority level.
204      *
205      * @param level      - DEBUG, INFO, WARNING, ERROR, FATAL
206      * @param tag        - Module name
207      * @param buffer     - pointer to buffer of bytes
208      * @param bufferSize - max number of byte in buffer
209      */
210     void OCLogBuffer(LogLevel level, PROGMEM const char * tag, const uint8_t * buffer, uint16_t bufferSize) {
211         if (!buffer || !tag || (bufferSize == 0)) {
212             return;
213         }
214
215         char lineBuffer[LINE_BUFFER_SIZE] = {0};
216         uint8_t lineIndex = 0;
217         for (uint8_t i = 0; i < bufferSize; i++) {
218             // Format the buffer data into a line
219             sprintf(&lineBuffer[lineIndex++ * 3], "%02X ", buffer[i]);
220             // Output 16 values per line
221             if (((i+1)%16) == 0) {
222                 OCLogString(level, tag, lineBuffer);
223                 memset(lineBuffer, 0, sizeof lineBuffer);
224                 lineIndex = 0;
225             }
226         }
227         // Output last values in the line, if any
228         if (bufferSize % 16) {
229             OCLogString(level, tag, lineBuffer);
230         }
231     }
232
233     /**
234      * Output a log string with the specified priority level.
235      * Only defined for Arduino.  Uses PROGMEM strings
236      *
237      * @param level  - DEBUG, INFO, WARNING, ERROR, FATAL
238      * @param tag    - Module name
239      * @param logStr - log string
240      */
241     void OCLog(LogLevel level, PROGMEM const char * tag, PROGMEM const char * logStr) {
242         if (!logStr || !tag) {
243           return;
244         }
245
246         char buffer[LINE_BUFFER_SIZE];
247
248         GET_PROGMEM_BUFFER(buffer, &(LEVEL[level]));
249         Serial.print(buffer);
250
251         char c;
252         Serial.print(F(": "));
253         while ((c = pgm_read_byte(tag))) {
254           Serial.write(c);
255           tag++;
256         }
257         Serial.print(F(": "));
258
259         while ((c = pgm_read_byte(logStr))) {
260           Serial.write(c);
261           logStr++;
262         }
263         Serial.println();
264     }
265
266     /**
267      * Output a variable argument list log string with the specified priority level.
268      * Only defined for Arduino as depicted below.
269      *
270      * @param level  - DEBUG, INFO, WARNING, ERROR, FATAL
271      * @param tag    - Module name
272      * @param format - variadic log string
273      */
274     void OCLogv(LogLevel level, PROGMEM const char * tag, const char * format, ...)
275     {
276         char buffer[LINE_BUFFER_SIZE];
277         va_list ap;
278         va_start(ap, format);
279
280         GET_PROGMEM_BUFFER(buffer, &(LEVEL[level]));
281         Serial.print(buffer);
282
283         char c;
284         Serial.print(F(": "));
285
286         while ((c = pgm_read_byte(tag))) {
287             Serial.write(c);
288             tag++;
289         }
290         Serial.print(F(": "));
291
292         vsnprintf(buffer, sizeof(buffer), format, ap);
293         for(char *p = &buffer[0]; *p; p++) // emulate cooked mode for newlines
294         {
295             if(*p == '\n')
296             {
297                 Serial.write('\r');
298             }
299             Serial.write(*p);
300         }
301         Serial.println();
302         va_end(ap);
303     }
304     /**
305      * Output a variable argument list log string with the specified priority level.
306      * Only defined for Arduino as depicted below.
307      *
308      * @param level  - DEBUG, INFO, WARNING, ERROR, FATAL
309      * @param tag    - Module name
310      * @param format - variadic log string
311      */
312     void OCLogv(LogLevel level, PROGMEM const char * tag, const __FlashStringHelper *format, ...)
313     {
314         char buffer[LINE_BUFFER_SIZE];
315         va_list ap;
316         va_start(ap, format);
317
318         GET_PROGMEM_BUFFER(buffer, &(LEVEL[level]));
319         Serial.print(buffer);
320
321         char c;
322         Serial.print(F(": "));
323
324         while ((c = pgm_read_byte(tag))) {
325           Serial.write(c);
326           tag++;
327         }
328         Serial.print(F(": "));
329
330         #ifdef __AVR__
331             vsnprintf_P(buffer, sizeof(buffer), (const char *)format, ap); // progmem for AVR
332         #else
333             vsnprintf(buffer, sizeof(buffer), (const char *)format, ap); // for the rest of the world
334         #endif
335         for(char *p = &buffer[0]; *p; p++) // emulate cooked mode for newlines
336         {
337             if(*p == '\n')
338             {
339                 Serial.write('\r');
340             }
341             Serial.write(*p);
342         }
343         Serial.println();
344         va_end(ap);
345     }
346
347
348 #endif
349
350