2 * Amazon FreeRTOS Common V1.0.0
\r
3 * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
\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
12 * The above copyright notice and this permission notice shall be included in all
\r
13 * copies or substantial portions of the Software.
\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
22 * http://aws.amazon.com/freertos
\r
23 * http://www.FreeRTOS.org
\r
27 * @file iot_logging.c
\r
28 * @brief Implementation of logging functions from iot_logging.h
\r
31 /* The config header is always included first. */
\r
32 #include "iot_config.h"
\r
34 /* Standard includes. */
\r
39 /* Platform clock include. */
\r
40 #include "platform/iot_clock.h"
\r
42 /* Logging includes. */
\r
43 #include "private/iot_logging.h"
\r
45 /*-----------------------------------------------------------*/
\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
52 #if IOT_LOG_ERROR != 1
\r
53 #error "IOT_LOG_ERROR must be 1."
\r
55 #if IOT_LOG_WARN != 2
\r
56 #error "IOT_LOG_WARN must be 2."
\r
58 #if IOT_LOG_INFO != 3
\r
59 #error "IOT_LOG_INFO must be 3."
\r
61 #if IOT_LOG_DEBUG != 4
\r
62 #error "IOT_LOG_DEBUG must be 4."
\r
66 * @def IotLogging_Puts( message )
\r
67 * @brief Function the logging library uses to print a line.
\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
73 #ifndef IotLogging_Puts
\r
74 #define IotLogging_Puts puts
\r
78 * Provide default values for undefined memory allocation functions based on
\r
79 * the usage of dynamic memory allocation.
\r
81 #if IOT_STATIC_MEMORY_ONLY == 1
\r
82 /* Static memory allocation header. */
\r
83 #include "private/iot_static_memory.h"
\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
89 #ifndef IotLogging_Malloc
\r
90 #define IotLogging_Malloc Iot_MallocMessageBuffer
\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
97 #ifndef IotLogging_Free
\r
98 #define IotLogging_Free Iot_FreeMessageBuffer
\r
102 * @brief Get the size of a logging buffer. Statically-allocated buffers
\r
103 * should all have the same size.
\r
105 #ifndef IotLogging_StaticBufferSize
\r
106 #define IotLogging_StaticBufferSize Iot_MessageBufferSize
\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
114 #ifndef IotLogging_Free
\r
115 #include <stdlib.h>
\r
116 #define IotLogging_Free free
\r
118 #endif /* if IOT_STATIC_MEMORY_ONLY == 1 */
\r
121 * @brief A guess of the maximum length of a timestring.
\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
128 * @see @ref platform_clock_function_gettimestring
\r
130 #define MAX_TIMESTRING_LENGTH ( 64 )
\r
133 * @brief The longest string in #_pLogLevelStrings (below), plus 3 to accommodate
\r
134 * `[]` and a null-terminator.
\r
136 #define MAX_LOG_LEVEL_LENGTH ( 8 )
\r
139 * @brief How many bytes @ref logging_function_genericprintbuffer should output on
\r
142 #define BYTES_PER_LINE ( 16 )
\r
144 /*-----------------------------------------------------------*/
\r
147 * @brief Lookup table for log levels.
\r
149 * Converts one of the @ref logging_constants_levels to a string.
\r
151 static const char * const _pLogLevelStrings[ 5 ] =
\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
160 /*-----------------------------------------------------------*/
\r
162 #if !defined( IOT_STATIC_MEMORY_ONLY ) || ( IOT_STATIC_MEMORY_ONLY == 0 )
\r
163 static bool _reallocLoggingBuffer( void ** pOldBuffer,
\r
167 bool status = false;
\r
169 /* Allocate a new, larger buffer. */
\r
170 void * pNewBuffer = IotLogging_Malloc( newSize );
\r
172 /* Ensure that memory allocation succeeded. */
\r
173 if( pNewBuffer != NULL )
\r
175 /* Copy the data from the old buffer to the new buffer. */
\r
176 ( void ) memcpy( pNewBuffer, *pOldBuffer, oldSize );
\r
178 /* Free the old buffer and update the pointer. */
\r
179 IotLogging_Free( *pOldBuffer );
\r
180 *pOldBuffer = pNewBuffer;
\r
187 #endif /* if !defined( IOT_STATIC_MEMORY_ONLY ) || ( IOT_STATIC_MEMORY_ONLY == 0 ) */
\r
189 /*-----------------------------------------------------------*/
\r
191 void IotLog_Generic( int libraryLogSetting,
\r
192 const char * const pLibraryName,
\r
194 const IotLogConfig_t * const pLogConfig,
\r
195 const char * const pFormat,
\r
198 int requiredMessageSize = 0;
\r
199 size_t bufferSize = 0,
\r
200 bufferPosition = 0, timestringLength = 0;
\r
201 char * pLoggingBuffer = NULL;
\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
211 if( ( pLogConfig == NULL ) || ( pLogConfig->hideLogLevel == false ) )
\r
213 /* Add length of log level if requested. */
\r
214 bufferSize += MAX_LOG_LEVEL_LENGTH;
\r
217 /* Estimate the amount of buffer needed for this log message. */
\r
218 if( ( pLogConfig == NULL ) || ( pLogConfig->hideLibraryName == false ) )
\r
220 /* Add size of library name if requested. Add 2 to accommodate "[]". */
\r
221 bufferSize += strlen( pLibraryName ) + 2;
\r
224 if( ( pLogConfig == NULL ) || ( pLogConfig->hideTimestring == false ) )
\r
226 /* Add length of timestring if requested. */
\r
227 bufferSize += MAX_TIMESTRING_LENGTH;
\r
230 /* Add 64 as an initial (arbitrary) guess for the length of the message. */
\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
238 /* If the static buffers are likely too small to fit the log message,
\r
243 /* Otherwise, update the buffer size to the size of a static buffer. */
\r
244 bufferSize = IotLogging_StaticBufferSize();
\r
247 /* Allocate memory for the logging buffer. */
\r
248 pLoggingBuffer = ( char * ) IotLogging_Malloc( bufferSize );
\r
250 if( pLoggingBuffer == NULL )
\r
255 /* Print the message log level if requested. */
\r
256 if( ( pLogConfig == NULL ) || ( pLogConfig->hideLogLevel == false ) )
\r
258 /* Ensure that message level is valid. */
\r
259 if( ( messageLevel >= IOT_LOG_NONE ) && ( messageLevel <= IOT_LOG_DEBUG ) )
\r
261 /* Add the log level string to the logging buffer. */
\r
262 requiredMessageSize = snprintf( pLoggingBuffer + bufferPosition,
\r
263 bufferSize - bufferPosition,
\r
265 _pLogLevelStrings[ messageLevel ] );
\r
267 /* Check for encoding errors. */
\r
268 if( requiredMessageSize <= 0 )
\r
270 IotLogging_Free( pLoggingBuffer );
\r
275 /* Update the buffer position. */
\r
276 bufferPosition += ( size_t ) requiredMessageSize;
\r
280 /* Print the library name if requested. */
\r
281 if( ( pLogConfig == NULL ) || ( pLogConfig->hideLibraryName == false ) )
\r
283 /* Add the library name to the logging buffer. */
\r
284 requiredMessageSize = snprintf( pLoggingBuffer + bufferPosition,
\r
285 bufferSize - bufferPosition,
\r
289 /* Check for encoding errors. */
\r
290 if( requiredMessageSize <= 0 )
\r
292 IotLogging_Free( pLoggingBuffer );
\r
297 /* Update the buffer position. */
\r
298 bufferPosition += ( size_t ) requiredMessageSize;
\r
301 /* Print the timestring if requested. */
\r
302 if( ( pLogConfig == NULL ) || ( pLogConfig->hideTimestring == false ) )
\r
304 /* Add the opening '[' enclosing the timestring. */
\r
305 pLoggingBuffer[ bufferPosition ] = '[';
\r
308 /* Generate the timestring and add it to the buffer. */
\r
309 if( IotClock_GetTimestring( pLoggingBuffer + bufferPosition,
\r
310 bufferSize - bufferPosition,
\r
311 ×tringLength ) == true )
\r
313 /* If the timestring was successfully generated, add the closing "]". */
\r
314 bufferPosition += timestringLength;
\r
315 pLoggingBuffer[ bufferPosition ] = ']';
\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
324 pLoggingBuffer[ bufferPosition ] = '\0';
\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
332 pLoggingBuffer[ bufferPosition ] = ' ';
\r
336 va_start( args, pFormat );
\r
338 /* Add the log message to the logging buffer. */
\r
339 requiredMessageSize = vsnprintf( pLoggingBuffer + bufferPosition,
\r
340 bufferSize - bufferPosition,
\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
350 #if IOT_STATIC_MEMORY_ONLY == 1
\r
352 /* There's no point trying to allocate a larger static buffer. Return
\r
354 IotLogging_Free( pLoggingBuffer );
\r
358 if( _reallocLoggingBuffer( ( void ** ) &pLoggingBuffer,
\r
359 ( size_t ) requiredMessageSize + bufferPosition + 1,
\r
360 bufferSize ) == false )
\r
362 /* If buffer reallocation failed, return. */
\r
363 IotLogging_Free( pLoggingBuffer );
\r
368 /* Reallocation successful, update buffer size. */
\r
369 bufferSize = ( size_t ) requiredMessageSize + bufferPosition + 1;
\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
379 #endif /* if IOT_STATIC_MEMORY_ONLY == 1 */
\r
382 /* Check for encoding errors. */
\r
383 if( requiredMessageSize <= 0 )
\r
385 IotLogging_Free( pLoggingBuffer );
\r
390 /* Print the logging buffer to stdout. */
\r
391 IotLogging_Puts( pLoggingBuffer );
\r
393 /* Free the logging buffer. */
\r
394 IotLogging_Free( pLoggingBuffer );
\r
397 /*-----------------------------------------------------------*/
\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
404 size_t i = 0, offset = 0;
\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
411 /* Exit if no memory is available. */
\r
412 if( pMessageBuffer == NULL )
\r
417 /* Print pHeader before printing pBuffer. */
\r
418 if( pHeader != NULL )
\r
420 IotLog_Generic( IOT_LOG_DEBUG,
\r
427 /* Print each byte in pBuffer. */
\r
428 for( i = 0; i < bufferSize; i++ )
\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
434 IotLogging_Puts( pMessageBuffer );
\r
436 /* Reset offset so that pMessageBuffer is filled from the beginning. */
\r
440 /* Print a single byte into pMessageBuffer. */
\r
441 ( void ) snprintf( pMessageBuffer + offset, 4, "%02x ", pBuffer[ i ] );
\r
443 /* Move the offset where the next character is printed. */
\r
447 /* Print the final line of bytes. This line isn't printed by the for-loop above. */
\r
448 IotLogging_Puts( pMessageBuffer );
\r
450 /* Free memory used by this function. */
\r
451 IotLogging_Free( pMessageBuffer );
\r
454 /*-----------------------------------------------------------*/
\r