]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/common/logging/iot_logging.c
Correct an err in queue.c introduced when previously updating behaviour when queue...
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-IoT-Libraries / c_sdk / standard / common / logging / iot_logging.c
1 /*\r
2  * Amazon FreeRTOS Common V1.0.0\r
3  * Copyright (C) 2018 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\r
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
6  * this software and associated documentation files (the "Software"), to deal in\r
7  * the Software without restriction, including without limitation the rights to\r
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
9  * the Software, and to permit persons to whom the Software is furnished to do so,\r
10  * subject to the following conditions:\r
11  *\r
12  * The above copyright notice and this permission notice shall be included in all\r
13  * copies or substantial portions of the Software.\r
14  *\r
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
21  *\r
22  * http://aws.amazon.com/freertos\r
23  * http://www.FreeRTOS.org\r
24  */\r
25 \r
26 /**\r
27  * @file iot_logging.c\r
28  * @brief Implementation of logging functions from iot_logging.h\r
29  */\r
30 \r
31 /* The config header is always included first. */\r
32 #include "iot_config.h"\r
33 \r
34 /* Standard includes. */\r
35 #include <stdarg.h>\r
36 #include <stdio.h>\r
37 #include <string.h>\r
38 \r
39 /* Platform clock include. */\r
40 #include "platform/iot_clock.h"\r
41 \r
42 /* Logging includes. */\r
43 #include "private/iot_logging.h"\r
44 \r
45 /*-----------------------------------------------------------*/\r
46 \r
47 /* This implementation assumes the following values for the log level constants.\r
48  * Ensure that the values have not been modified. */\r
49 #if IOT_LOG_NONE != 0\r
50     #error "IOT_LOG_NONE must be 0."\r
51 #endif\r
52 #if IOT_LOG_ERROR != 1\r
53     #error "IOT_LOG_ERROR must be 1."\r
54 #endif\r
55 #if IOT_LOG_WARN != 2\r
56     #error "IOT_LOG_WARN must be 2."\r
57 #endif\r
58 #if IOT_LOG_INFO != 3\r
59     #error "IOT_LOG_INFO must be 3."\r
60 #endif\r
61 #if IOT_LOG_DEBUG != 4\r
62     #error "IOT_LOG_DEBUG must be 4."\r
63 #endif\r
64 \r
65 /**\r
66  * @def IotLogging_Puts( message )\r
67  * @brief Function the logging library uses to print a line.\r
68  *\r
69  * This function can be set by using a define. By default, the standard library\r
70  * [puts](http://pubs.opengroup.org/onlinepubs/9699919799/functions/puts.html)\r
71  * function is used.\r
72  */\r
73 #ifndef IotLogging_Puts\r
74     #define IotLogging_Puts    puts\r
75 #endif\r
76 \r
77 /*\r
78  * Provide default values for undefined memory allocation functions based on\r
79  * the usage of dynamic memory allocation.\r
80  */\r
81 #if IOT_STATIC_MEMORY_ONLY == 1\r
82     /* Static memory allocation header. */\r
83     #include "private/iot_static_memory.h"\r
84 \r
85 /**\r
86  * @brief Allocate a new logging buffer. This function must have the same\r
87  * signature as [malloc](http://pubs.opengroup.org/onlinepubs/9699919799/functions/malloc.html).\r
88  */\r
89     #ifndef IotLogging_Malloc\r
90         #define IotLogging_Malloc    Iot_MallocMessageBuffer\r
91     #endif\r
92 \r
93 /**\r
94  * @brief Free a logging buffer. This function must have the same signature\r
95  * as [free](http://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html).\r
96  */\r
97     #ifndef IotLogging_Free\r
98         #define IotLogging_Free    Iot_FreeMessageBuffer\r
99     #endif\r
100 \r
101 /**\r
102  * @brief Get the size of a logging buffer. Statically-allocated buffers\r
103  * should all have the same size.\r
104  */\r
105     #ifndef IotLogging_StaticBufferSize\r
106         #define IotLogging_StaticBufferSize    Iot_MessageBufferSize\r
107     #endif\r
108 #else /* if IOT_STATIC_MEMORY_ONLY == 1 */\r
109     #ifndef IotLogging_Malloc\r
110         #include <stdlib.h>\r
111         #define IotLogging_Malloc    malloc\r
112     #endif\r
113 \r
114     #ifndef IotLogging_Free\r
115         #include <stdlib.h>\r
116         #define IotLogging_Free    free\r
117     #endif\r
118 #endif /* if IOT_STATIC_MEMORY_ONLY == 1 */\r
119 \r
120 /**\r
121  * @brief A guess of the maximum length of a timestring.\r
122  *\r
123  * There's no way for this logging library to know the length of a timestring\r
124  * before it's generated. Therefore, the logging library will assume a maximum\r
125  * length of any timestring it may get. This value should be generous enough\r
126  * to accommodate the vast majority of timestrings.\r
127  *\r
128  * @see @ref platform_clock_function_gettimestring\r
129  */\r
130 #define MAX_TIMESTRING_LENGTH    ( 64 )\r
131 \r
132 /**\r
133  * @brief The longest string in #_pLogLevelStrings (below), plus 3 to accommodate\r
134  * `[]` and a null-terminator.\r
135  */\r
136 #define MAX_LOG_LEVEL_LENGTH     ( 8 )\r
137 \r
138 /**\r
139  * @brief How many bytes @ref logging_function_genericprintbuffer should output on\r
140  * each line.\r
141  */\r
142 #define BYTES_PER_LINE           ( 16 )\r
143 \r
144 /*-----------------------------------------------------------*/\r
145 \r
146 /**\r
147  * @brief Lookup table for log levels.\r
148  *\r
149  * Converts one of the @ref logging_constants_levels to a string.\r
150  */\r
151 static const char * const _pLogLevelStrings[ 5 ] =\r
152 {\r
153     "",      /* IOT_LOG_NONE */\r
154     "ERROR", /* IOT_LOG_ERROR */\r
155     "WARN ", /* IOT_LOG_WARN */\r
156     "INFO ", /* IOT_LOG_INFO */\r
157     "DEBUG"  /* IOT_LOG_DEBUG */\r
158 };\r
159 \r
160 /*-----------------------------------------------------------*/\r
161 \r
162 #if !defined( IOT_STATIC_MEMORY_ONLY ) || ( IOT_STATIC_MEMORY_ONLY == 0 )\r
163     static bool _reallocLoggingBuffer( void ** pOldBuffer,\r
164                                        size_t newSize,\r
165                                        size_t oldSize )\r
166     {\r
167         bool status = false;\r
168 \r
169         /* Allocate a new, larger buffer. */\r
170         void * pNewBuffer = IotLogging_Malloc( newSize );\r
171 \r
172         /* Ensure that memory allocation succeeded. */\r
173         if( pNewBuffer != NULL )\r
174         {\r
175             /* Copy the data from the old buffer to the new buffer. */\r
176             ( void ) memcpy( pNewBuffer, *pOldBuffer, oldSize );\r
177 \r
178             /* Free the old buffer and update the pointer. */\r
179             IotLogging_Free( *pOldBuffer );\r
180             *pOldBuffer = pNewBuffer;\r
181 \r
182             status = true;\r
183         }\r
184 \r
185         return status;\r
186     }\r
187 #endif /* if !defined( IOT_STATIC_MEMORY_ONLY ) || ( IOT_STATIC_MEMORY_ONLY == 0 ) */\r
188 \r
189 /*-----------------------------------------------------------*/\r
190 \r
191 void IotLog_Generic( int libraryLogSetting,\r
192                      const char * const pLibraryName,\r
193                      int messageLevel,\r
194                      const IotLogConfig_t * const pLogConfig,\r
195                      const char * const pFormat,\r
196                      ... )\r
197 {\r
198     int requiredMessageSize = 0;\r
199     size_t bufferSize = 0,\r
200            bufferPosition = 0, timestringLength = 0;\r
201     char * pLoggingBuffer = NULL;\r
202     va_list args;\r
203 \r
204     /* If the library's log level setting is lower than the message level,\r
205      * return without doing anything. */\r
206     if( ( messageLevel == 0 ) || ( messageLevel > libraryLogSetting ) )\r
207     {\r
208         return;\r
209     }\r
210 \r
211     if( ( pLogConfig == NULL ) || ( pLogConfig->hideLogLevel == false ) )\r
212     {\r
213         /* Add length of log level if requested. */\r
214         bufferSize += MAX_LOG_LEVEL_LENGTH;\r
215     }\r
216 \r
217     /* Estimate the amount of buffer needed for this log message. */\r
218     if( ( pLogConfig == NULL ) || ( pLogConfig->hideLibraryName == false ) )\r
219     {\r
220         /* Add size of library name if requested. Add 2 to accommodate "[]". */\r
221         bufferSize += strlen( pLibraryName ) + 2;\r
222     }\r
223 \r
224     if( ( pLogConfig == NULL ) || ( pLogConfig->hideTimestring == false ) )\r
225     {\r
226         /* Add length of timestring if requested. */\r
227         bufferSize += MAX_TIMESTRING_LENGTH;\r
228     }\r
229 \r
230     /* Add 64 as an initial (arbitrary) guess for the length of the message. */\r
231     bufferSize += 64;\r
232 \r
233     /* In static memory mode, check that the log message will fit in the a\r
234      * static buffer. */\r
235     #if IOT_STATIC_MEMORY_ONLY == 1\r
236         if( bufferSize >= IotLogging_StaticBufferSize() )\r
237         {\r
238             /* If the static buffers are likely too small to fit the log message,\r
239              * return. */\r
240             return;\r
241         }\r
242 \r
243         /* Otherwise, update the buffer size to the size of a static buffer. */\r
244         bufferSize = IotLogging_StaticBufferSize();\r
245     #endif\r
246 \r
247     /* Allocate memory for the logging buffer. */\r
248     pLoggingBuffer = ( char * ) IotLogging_Malloc( bufferSize );\r
249 \r
250     if( pLoggingBuffer == NULL )\r
251     {\r
252         return;\r
253     }\r
254 \r
255     /* Print the message log level if requested. */\r
256     if( ( pLogConfig == NULL ) || ( pLogConfig->hideLogLevel == false ) )\r
257     {\r
258         /* Ensure that message level is valid. */\r
259         if( ( messageLevel >= IOT_LOG_NONE ) && ( messageLevel <= IOT_LOG_DEBUG ) )\r
260         {\r
261             /* Add the log level string to the logging buffer. */\r
262             requiredMessageSize = snprintf( pLoggingBuffer + bufferPosition,\r
263                                             bufferSize - bufferPosition,\r
264                                             "[%s]",\r
265                                             _pLogLevelStrings[ messageLevel ] );\r
266 \r
267             /* Check for encoding errors. */\r
268             if( requiredMessageSize <= 0 )\r
269             {\r
270                 IotLogging_Free( pLoggingBuffer );\r
271 \r
272                 return;\r
273             }\r
274 \r
275             /* Update the buffer position. */\r
276             bufferPosition += ( size_t ) requiredMessageSize;\r
277         }\r
278     }\r
279 \r
280     /* Print the library name if requested. */\r
281     if( ( pLogConfig == NULL ) || ( pLogConfig->hideLibraryName == false ) )\r
282     {\r
283         /* Add the library name to the logging buffer. */\r
284         requiredMessageSize = snprintf( pLoggingBuffer + bufferPosition,\r
285                                         bufferSize - bufferPosition,\r
286                                         "[%s]",\r
287                                         pLibraryName );\r
288 \r
289         /* Check for encoding errors. */\r
290         if( requiredMessageSize <= 0 )\r
291         {\r
292             IotLogging_Free( pLoggingBuffer );\r
293 \r
294             return;\r
295         }\r
296 \r
297         /* Update the buffer position. */\r
298         bufferPosition += ( size_t ) requiredMessageSize;\r
299     }\r
300 \r
301     /* Print the timestring if requested. */\r
302     if( ( pLogConfig == NULL ) || ( pLogConfig->hideTimestring == false ) )\r
303     {\r
304         /* Add the opening '[' enclosing the timestring. */\r
305         pLoggingBuffer[ bufferPosition ] = '[';\r
306         bufferPosition++;\r
307 \r
308         /* Generate the timestring and add it to the buffer. */\r
309         if( IotClock_GetTimestring( pLoggingBuffer + bufferPosition,\r
310                                     bufferSize - bufferPosition,\r
311                                     &timestringLength ) == true )\r
312         {\r
313             /* If the timestring was successfully generated, add the closing "]". */\r
314             bufferPosition += timestringLength;\r
315             pLoggingBuffer[ bufferPosition ] = ']';\r
316             bufferPosition++;\r
317         }\r
318         else\r
319         {\r
320             /* Sufficient memory for a timestring should have been allocated. A timestring\r
321              * probably failed to generate due to a clock read error; remove the opening '['\r
322              * from the logging buffer. */\r
323             bufferPosition--;\r
324             pLoggingBuffer[ bufferPosition ] = '\0';\r
325         }\r
326     }\r
327 \r
328     /* Add a padding space between the last closing ']' and the message, unless\r
329      * the logging buffer is empty. */\r
330     if( bufferPosition > 0 )\r
331     {\r
332         pLoggingBuffer[ bufferPosition ] = ' ';\r
333         bufferPosition++;\r
334     }\r
335 \r
336     va_start( args, pFormat );\r
337 \r
338     /* Add the log message to the logging buffer. */\r
339     requiredMessageSize = vsnprintf( pLoggingBuffer + bufferPosition,\r
340                                      bufferSize - bufferPosition,\r
341                                      pFormat,\r
342                                      args );\r
343 \r
344     va_end( args );\r
345 \r
346     /* If the logging buffer was too small to fit the log message, reallocate\r
347      * a larger logging buffer. */\r
348     if( ( size_t ) requiredMessageSize >= bufferSize - bufferPosition )\r
349     {\r
350         #if IOT_STATIC_MEMORY_ONLY == 1\r
351 \r
352             /* There's no point trying to allocate a larger static buffer. Return\r
353              * immediately. */\r
354             IotLogging_Free( pLoggingBuffer );\r
355 \r
356             return;\r
357         #else\r
358             if( _reallocLoggingBuffer( ( void ** ) &pLoggingBuffer,\r
359                                        ( size_t ) requiredMessageSize + bufferPosition + 1,\r
360                                        bufferSize ) == false )\r
361             {\r
362                 /* If buffer reallocation failed, return. */\r
363                 IotLogging_Free( pLoggingBuffer );\r
364 \r
365                 return;\r
366             }\r
367 \r
368             /* Reallocation successful, update buffer size. */\r
369             bufferSize = ( size_t ) requiredMessageSize + bufferPosition + 1;\r
370 \r
371             /* Add the log message to the buffer. Now that the buffer has been\r
372              * reallocated, this should succeed. */\r
373             va_start( args, pFormat );\r
374             requiredMessageSize = vsnprintf( pLoggingBuffer + bufferPosition,\r
375                                              bufferSize - bufferPosition,\r
376                                              pFormat,\r
377                                              args );\r
378             va_end( args );\r
379         #endif /* if IOT_STATIC_MEMORY_ONLY == 1 */\r
380     }\r
381 \r
382     /* Check for encoding errors. */\r
383     if( requiredMessageSize <= 0 )\r
384     {\r
385         IotLogging_Free( pLoggingBuffer );\r
386 \r
387         return;\r
388     }\r
389 \r
390     /* Print the logging buffer to stdout. */\r
391     IotLogging_Puts( pLoggingBuffer );\r
392 \r
393     /* Free the logging buffer. */\r
394     IotLogging_Free( pLoggingBuffer );\r
395 }\r
396 \r
397 /*-----------------------------------------------------------*/\r
398 \r
399 void IotLog_GenericPrintBuffer( const char * const pLibraryName,\r
400                                 const char * const pHeader,\r
401                                 const uint8_t * const pBuffer,\r
402                                 size_t bufferSize )\r
403 {\r
404     size_t i = 0, offset = 0;\r
405 \r
406     /* Allocate memory to hold each line of the log message. Since each byte\r
407      * of pBuffer is printed in 4 characters (2 digits, a space, and a null-\r
408      * terminator), the size of each line is 4 * BYTES_PER_LINE. */\r
409     char * pMessageBuffer = IotLogging_Malloc( 4 * BYTES_PER_LINE );\r
410 \r
411     /* Exit if no memory is available. */\r
412     if( pMessageBuffer == NULL )\r
413     {\r
414         return;\r
415     }\r
416 \r
417     /* Print pHeader before printing pBuffer. */\r
418     if( pHeader != NULL )\r
419     {\r
420         IotLog_Generic( IOT_LOG_DEBUG,\r
421                         pLibraryName,\r
422                         IOT_LOG_DEBUG,\r
423                         NULL,\r
424                         pHeader );\r
425     }\r
426 \r
427     /* Print each byte in pBuffer. */\r
428     for( i = 0; i < bufferSize; i++ )\r
429     {\r
430         /* Print a line if BYTES_PER_LINE is reached. But don't print a line\r
431          * at the beginning (when i=0). */\r
432         if( ( i % BYTES_PER_LINE == 0 ) && ( i != 0 ) )\r
433         {\r
434             IotLogging_Puts( pMessageBuffer );\r
435 \r
436             /* Reset offset so that pMessageBuffer is filled from the beginning. */\r
437             offset = 0;\r
438         }\r
439 \r
440         /* Print a single byte into pMessageBuffer. */\r
441         ( void ) snprintf( pMessageBuffer + offset, 4, "%02x ", pBuffer[ i ] );\r
442 \r
443         /* Move the offset where the next character is printed. */\r
444         offset += 3;\r
445     }\r
446 \r
447     /* Print the final line of bytes. This line isn't printed by the for-loop above. */\r
448     IotLogging_Puts( pMessageBuffer );\r
449 \r
450     /* Free memory used by this function. */\r
451     IotLogging_Free( pMessageBuffer );\r
452 }\r
453 \r
454 /*-----------------------------------------------------------*/\r