// Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. #include #include #include #include "windows.h" #include "azure_c_shared_utility/xlogging.h" #include "azure_c_shared_utility/consolelogger.h" #ifdef USE_TRACELOGGING #include "TraceLoggingProvider.h" #include "evntrace.h" #endif /*returns a string as if printed by vprintf*/ static char* vprintf_alloc(const char* format, va_list va) { char* result; int neededSize = vsnprintf(NULL, 0, format, va); if (neededSize < 0 || (neededSize + 1) < 0) { result = NULL; } else { result = (char*)malloc(neededSize + 1); if (result == NULL) { /*return as is*/ } else { if (vsnprintf(result, neededSize + 1, format, va) != neededSize) { free(result); result = NULL; } } } return result; } /*returns a string as if printed by printf*/ static char* printf_alloc(const char* format, ...) { char* result; va_list va; va_start(va, format); result = vprintf_alloc(format, va); va_end(va); return result; } /*returns NULL if it fails*/ static char* lastErrorToString(DWORD lastError) { char* result; if (lastError == 0) { result = printf_alloc(""); /*no error should appear*/ if (result == NULL) { (void)printf("failure in printf_alloc\r\n"); } else { /*return as is*/ } } else { char temp[MESSAGE_BUFFER_SIZE]; if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, lastError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), temp, MESSAGE_BUFFER_SIZE, NULL) == 0) { result = printf_alloc("GetLastError()=0X%x", lastError); if (result == NULL) { (void)printf("failure in printf_alloc\r\n"); /*return as is*/ } else { /*return as is*/ } } else { /*eliminate the \r or \n from the string*/ /*one replace of each is enough*/ char* whereAreThey; if ((whereAreThey = strchr(temp, '\r')) != NULL) { *whereAreThey = '\0'; } if ((whereAreThey = strchr(temp, '\n')) != NULL) { *whereAreThey = '\0'; } result = printf_alloc("GetLastError()==0X%x (%s)", lastError, temp); if (result == NULL) { (void)printf("failure in printf_alloc\r\n"); /*return as is*/ } else { /*return as is*/ } } } return result; } #ifdef USE_TRACELOGGING TRACELOGGING_DEFINE_PROVIDER( g_hMyComponentProvider, "block_storage_2", (0xDAD29F36, 0x0A48, 0x4DEF, 0x9D, 0x50, 0x8E, 0xF9, 0x03, 0x6B, 0x92, 0xB4)); /*DAD29F36-0A48-4DEF-9D50-8EF9036B92B4*/ static volatile LONG isETWLoggerInit = 0; static void lazyRegisterEventProvider(void) { /*lazily init the logger*/ if (InterlockedCompareExchange(&isETWLoggerInit, 1, 0) == 0) { // Register the provider TLG_STATUS t = TraceLoggingRegister(g_hMyComponentProvider); if (SUCCEEDED(t)) { LogInfo("block_storage_2 ETW provider was registered succesfully (self test). Executable file full path name = %s", _pgmptr); /*_pgmptr comes from https://docs.microsoft.com/windows/win32/api/libloaderapi/nf-libloaderapi-getmodulefilenamea */ } else { (void)printf("block_storage_2 ETW provider was NOT registered."); (void)InterlockedExchange(&isETWLoggerInit, 0); } } else { /*do nothing, already registered/attempted*/ } } static void perform_EventWriteLogErrorEvent(const char* content, const char* file, const SYSTEMTIME* t, const char* func, int line) { (void)t; TraceLoggingWrite(g_hMyComponentProvider, "LogError", TraceLoggingLevel(TRACE_LEVEL_ERROR), TraceLoggingString(file, "file"), TraceLoggingString(func, "func"), TraceLoggingInt32(line, "line"), TraceLoggingString(content, "content") ); #if CALL_CONSOLE_LOGGER consolelogger_log(AZ_LOG_ERROR, file, func, line, LOG_LINE, "%s", content); #endif } static void perform_EventWriteLogLastError(const char* userMessage, const char* file, const SYSTEMTIME* t, const char* func, int line, const char* lastErrorAsString) { (void)t; TraceLoggingWrite(g_hMyComponentProvider, "LogLastError", TraceLoggingLevel(TRACE_LEVEL_ERROR), TraceLoggingString(file, "file"), TraceLoggingString(func, "func"), TraceLoggingInt32(line, "line"), TraceLoggingString(userMessage, "content"), TraceLoggingString(lastErrorAsString, "GetLastError") ); #if CALL_CONSOLE_LOGGER consolelogger_log(AZ_LOG_ERROR, file, func, line, LOG_LINE, "%s %s", userMessage, lastErrorAsString); #endif } static void perform_EventWriteLogInfoEvent(const char* message) { TraceLoggingWrite(g_hMyComponentProvider, "LogInfo", TraceLoggingLevel(TRACE_LEVEL_INFORMATION), TraceLoggingString(message, "content") ); #if CALL_CONSOLE_LOGGER consolelogger_log(AZ_LOG_INFO, NULL, NULL, 0, LOG_LINE, "%s", message); #endif } void etwlogger_log_with_GetLastError(const char* file, const char* func, int line, const char* format, ...) { DWORD lastError; char* lastErrorAsString; lastError = GetLastError(); lazyRegisterEventProvider(); va_list args; va_start(args, format); SYSTEMTIME t; GetSystemTime(&t); lastErrorAsString = lastErrorToString(lastError); if (lastErrorAsString == NULL) { char* userMessage = vprintf_alloc(format, args); if (userMessage == NULL) { perform_EventWriteLogLastError("unable to print user error", file, &t, func, line, "last error was erroneously NULL"); } else { perform_EventWriteLogLastError(userMessage, file, &t, func, line, "last error was erroneously NULL"); free(userMessage); } } else { char* userMessage = vprintf_alloc(format, args); if (userMessage == NULL) { perform_EventWriteLogLastError("unable to print user error", file, &t, func, line, lastErrorAsString); } else { perform_EventWriteLogLastError(userMessage, file, &t, func, line, lastErrorAsString); free(userMessage); } free(lastErrorAsString); } va_end(args); } void etwlogger_log(LOG_CATEGORY log_category, const char* file, const char* func, int line, unsigned int options, const char* format, ...) { (void)options; lazyRegisterEventProvider(); va_list args; va_start(args, format); char* text = vprintf_alloc(format, args); if (text == NULL) { switch (log_category) { case AZ_LOG_INFO: { perform_EventWriteLogInfoEvent("INTERNAL LOGGING ERROR: failed in vprintf_alloc"); break; } case AZ_LOG_ERROR: { SYSTEMTIME t; GetSystemTime(&t); perform_EventWriteLogErrorEvent("INTERNAL LOGGING ERROR: failed in vprintf_alloc", file, &t, func, line); break; } default: break; } } else { switch (log_category) { case AZ_LOG_INFO: { perform_EventWriteLogInfoEvent(text); break; } case AZ_LOG_ERROR: { SYSTEMTIME t; GetSystemTime(&t); perform_EventWriteLogErrorEvent(text, file, &t, func, line); break; } default: break; } free(text); } va_end(args); } #endif