Nigel Rantor / azure_c_shared_utility

Fork of azure_c_shared_utility by Azure IoT

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers consolelogger.c Source File

consolelogger.c

00001 // Copyright (c) Microsoft. All rights reserved.
00002 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
00003 
00004 #include <stdarg.h>
00005 #include <stdio.h>
00006 #include <time.h>
00007 #include "azure_c_shared_utility/xlogging.h"
00008 #include "azure_c_shared_utility/consolelogger.h"
00009 
00010 #if (defined(_MSC_VER)) && (!(defined WINCE))
00011 #include "windows.h"
00012 
00013 /*returns a string as if printed by vprintf*/
00014 static char* vprintf_alloc(const char* format, va_list va)
00015 {
00016     char* result;
00017     int neededSize = vsnprintf(NULL, 0, format, va);
00018     if (neededSize < 0)
00019     {
00020         result = NULL;
00021     }
00022     else
00023     {
00024         result = (char*)malloc(neededSize + 1);
00025         if (result == NULL)
00026         {
00027             /*return as is*/
00028         }
00029         else
00030         {
00031             if (vsnprintf(result, neededSize + 1, format, va) != neededSize)
00032             {
00033                 free(result);
00034                 result = NULL;
00035             }
00036         }
00037     }
00038     return result;
00039 }
00040 
00041 /*returns a string as if printed by printf*/
00042 static char* printf_alloc(const char* format, ...)
00043 {
00044     char* result;
00045     va_list va;
00046     va_start(va, format);
00047     result = vprintf_alloc(format, va);
00048     va_end(va);
00049     return result;
00050 }
00051 
00052 /*returns NULL if it fails*/
00053 static char* lastErrorToString(DWORD lastError)
00054 {
00055     char* result;
00056     if (lastError == 0)
00057     {
00058         result = printf_alloc(""); /*no error should appear*/
00059         if (result == NULL)
00060         {
00061             (void)printf("failure in printf_alloc");
00062         }
00063         else
00064         {
00065             /*return as is*/
00066         }
00067     }
00068     else
00069     {
00070         char temp[MESSAGE_BUFFER_SIZE];
00071         if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, lastError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), temp, MESSAGE_BUFFER_SIZE, NULL) == 0)
00072         {
00073             result = printf_alloc("GetLastError()=0X%x", lastError);
00074             if (result == NULL)
00075             {
00076                 (void)printf("failure in printf_alloc\n");
00077                 /*return as is*/
00078             }
00079             else
00080             {
00081                 /*return as is*/
00082             }
00083         }
00084         else
00085         {
00086             /*eliminate the \r or \n from the string*/
00087             /*one replace of each is enough*/
00088             char* whereAreThey;
00089             if ((whereAreThey = strchr(temp, '\r')) != NULL)
00090             {
00091                 *whereAreThey = '\0';
00092             }
00093             if ((whereAreThey = strchr(temp, '\n')) != NULL)
00094             {
00095                 *whereAreThey = '\0';
00096             }
00097 
00098             result = printf_alloc("GetLastError()==0X%x (%s)", lastError, temp);
00099 
00100             if (result == NULL)
00101             {
00102                 (void)printf("failure in printf_alloc\n");
00103                 /*return as is*/
00104             }
00105             else
00106             {
00107                 /*return as is*/
00108             }
00109         }
00110     }
00111     return result;
00112 }
00113 /*this function will use 1x printf (in the happy case) .*/
00114 /*more than 1x printf / function call can mean intermingled LogErrors in a multithreaded env*/
00115 /*the function will also attempt to produce some human readable strings for GetLastError*/
00116 void consolelogger_log_with_GetLastError(const char* file, const char* func, int line, const char* format, ...)
00117 {
00118     DWORD lastError;
00119     char* lastErrorAsString;
00120     int lastErrorAsString_should_be_freed;
00121     time_t t;
00122     int systemMessage_should_be_freed;
00123     char* systemMessage;
00124     int userMessage_should_be_freed;
00125     char* userMessage;
00126 
00127     va_list args;
00128     va_start(args, format);
00129 
00130     /*this is what this case will do:
00131     1. snip the last error
00132     2. create a string with what that last error means
00133     3. printf the system message (__FILE__, __LINE__ etc) + the last error + whatever the user wanted
00134     */
00135     /*1. snip the last error*/
00136     lastError = GetLastError();
00137 
00138     /*2. create a string with what that last error means*/
00139     lastErrorAsString = lastErrorToString(lastError);
00140     if (lastErrorAsString == NULL)
00141     {
00142         (void)printf("failure in lastErrorToString");
00143         lastErrorAsString = "";
00144         lastErrorAsString_should_be_freed = 0;
00145     }
00146     else
00147     {
00148         lastErrorAsString_should_be_freed = 1;
00149     }
00150 
00151     t = time(NULL);
00152     systemMessage = printf_alloc("Error: Time:%.24s File:%s Func:%s Line:%d %s", ctime(&t), file, func, line, lastErrorAsString);
00153 
00154     if (systemMessage == NULL)
00155     {
00156         systemMessage = "";
00157         (void)printf("Error: [FAILED] Time:%.24s File : %s Func : %s Line : %d %s", ctime(&t), file, func, line, lastErrorAsString);
00158         systemMessage_should_be_freed = 0;
00159     }
00160     else
00161     {
00162         systemMessage_should_be_freed = 1;
00163     }
00164 
00165     userMessage = vprintf_alloc(format, args);
00166     if (userMessage == NULL)
00167     {
00168         (void)printf("[FAILED] ");
00169         (void)vprintf(format, args);
00170         (void)printf("\n");
00171         userMessage_should_be_freed = 0;
00172     }
00173     else
00174     {
00175         /*3. printf the system message(__FILE__, __LINE__ etc) + the last error + whatever the user wanted*/
00176         (void)printf("%s %s\n", systemMessage, userMessage);
00177         userMessage_should_be_freed = 1;
00178     }
00179 
00180     if (userMessage_should_be_freed == 1)
00181     {
00182         free(userMessage);
00183     }
00184 
00185     if (systemMessage_should_be_freed == 1)
00186     {
00187         free(systemMessage);
00188     }
00189 
00190     if (lastErrorAsString_should_be_freed == 1)
00191     {
00192         free(lastErrorAsString);
00193     }
00194     va_end(args);
00195 }
00196 #endif
00197 
00198 #if defined(__GNUC__)
00199 __attribute__ ((format (printf, 6, 7)))
00200 #endif
00201 void consolelogger_log(LOG_CATEGORY log_category, const char* file, const char* func, int line, unsigned int options, const char* format, ...)
00202 {
00203     time_t t;
00204     va_list args;
00205     va_start(args, format);
00206 
00207     t = time(NULL); 
00208     
00209     switch (log_category)
00210     {
00211     case AZ_LOG_INFO:
00212         (void)printf("Info: ");
00213         break;
00214     case AZ_LOG_ERROR:
00215         (void)printf("Error: Time:%.24s File:%s Func:%s Line:%d ", ctime(&t), file, func, line);
00216         break;
00217     default:
00218         break;
00219     }
00220 
00221     (void)vprintf(format, args);
00222     va_end(args);
00223 
00224     (void)log_category;
00225     if (options & LOG_LINE)
00226     {
00227         (void)printf("\r\n");
00228     }
00229 }
00230