diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index edb94a8f2e..64087646b0 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -9,6 +9,7 @@ AICLIC ajor amrutha anonymized +ANSISTRING APARTMENTTHREADED apfn apiset @@ -51,9 +52,11 @@ certmgr certs Cfg cgmanifest +cguid chcp ci cinq +Cj CLIE cloudapp CLSID @@ -84,6 +87,7 @@ enr enums EQU ERANGE +errcode errno etest execustom @@ -259,6 +263,7 @@ srs Standalone startswith streambuf +strlen strtoull subdir subkey @@ -272,6 +277,7 @@ temppath testexampleinstaller thiscouldbeapc threehundred +Tlg tombstoned transitioning UCase diff --git a/src/AppInstallerCLICore/COMContext.cpp b/src/AppInstallerCLICore/COMContext.cpp index ee2cb11fea..a5f80b5823 100644 --- a/src/AppInstallerCLICore/COMContext.cpp +++ b/src/AppInstallerCLICore/COMContext.cpp @@ -32,4 +32,23 @@ namespace AppInstaller m_executionStage = executionStage; m_comProgressCallback(ReportType::ExecutionPhaseUpdate, 0, 0, ProgressType::None, m_executionStage); } -} \ No newline at end of file + + void COMContext::SetLoggers(std::string telemetryCorelationJson, std::string comCaller) + { + SetThreadGlobalsActive(); + + Logging::Log().SetLevel(Logging::Level::Verbose); + Logging::AddTraceLogger(); + +#ifdef _DEBUG + // Log to file for COM API calls only when debugging in visual studio + Logging::AddFileLogger(); + Logging::BeginLogFileCleanup(); +#endif + + Logging::EnableWilFailureTelemetry(); + Logging::Telemetry().SetTelemetryCorelationJson(telemetryCorelationJson); + Logging::Telemetry().SetCOMCaller(comCaller); + Logging::Telemetry().LogStartup(true); + } +} diff --git a/src/AppInstallerCLICore/COMContext.h b/src/AppInstallerCLICore/COMContext.h index 9eb2039800..7916350a42 100644 --- a/src/AppInstallerCLICore/COMContext.h +++ b/src/AppInstallerCLICore/COMContext.h @@ -56,12 +56,17 @@ namespace AppInstaller //Execution::Context void SetExecutionStage(CLI::Workflow::ExecutionStage executionPhase, bool); + // Set Progress Callback function void SetProgressCallbackFunction(ProgressCallBackFunction&& f) { m_comProgressCallback = std::move(f); } private: + + // Set diagnostic and telemetry loggers + void SetLoggers(std::string telemetryCorelationJson, std::string comCaller); + CLI::Workflow::ExecutionStage m_executionStage = CLI::Workflow::ExecutionStage::Initial; ProgressCallBackFunction m_comProgressCallback; }; diff --git a/src/AppInstallerCLICore/Core.cpp b/src/AppInstallerCLICore/Core.cpp index 21b7457dcc..6a8948e740 100644 --- a/src/AppInstallerCLICore/Core.cpp +++ b/src/AppInstallerCLICore/Core.cpp @@ -46,10 +46,17 @@ namespace AppInstaller::CLI { init_apartment(); + Execution::Context context{ std::cout, std::cin }; + context.EnableCtrlHandler(); + // Enable all logging for this phase; we will update once we have the arguments + context.SetThreadGlobalsActive(); + Logging::Log().EnableChannel(Logging::Channel::All); Logging::Log().SetLevel(Logging::Level::Verbose); Logging::AddFileLogger(); + + Logging::AddTraceLogger(); Logging::EnableWilFailureTelemetry(); // Set output to UTF8 @@ -60,9 +67,6 @@ namespace AppInstaller::CLI // Initiate the background cleanup of the log file location. Logging::BeginLogFileCleanup(); - Execution::Context context{ std::cout, std::cin }; - context.EnableCtrlHandler(); - context << Workflow::ReportExecutionStage(Workflow::ExecutionStage::ParseArgs); // Convert incoming wide char args to UTF8 diff --git a/src/AppInstallerCLICore/ExecutionContext.cpp b/src/AppInstallerCLICore/ExecutionContext.cpp index 47385895ce..1327c5cb75 100644 --- a/src/AppInstallerCLICore/ExecutionContext.cpp +++ b/src/AppInstallerCLICore/ExecutionContext.cpp @@ -140,4 +140,9 @@ namespace AppInstaller::CLI::Execution m_executionStage = stage; } + + void Context::SetThreadGlobalsActive() + { + m_threadGlobals.SetForCurrentThread(); + } } diff --git a/src/AppInstallerCLICore/ExecutionContext.h b/src/AppInstallerCLICore/ExecutionContext.h index 0b43412450..cd30184ac9 100644 --- a/src/AppInstallerCLICore/ExecutionContext.h +++ b/src/AppInstallerCLICore/ExecutionContext.h @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. #pragma once -#include +#include #include "ExecutionReporter.h" #include "ExecutionArgs.h" #include "ExecutionContextData.h" @@ -101,6 +101,9 @@ namespace AppInstaller::CLI::Execution } virtual void SetExecutionStage(Workflow::ExecutionStage stage, bool); + + // Set Globals for Current Thread + void SetThreadGlobalsActive(); #ifndef AICLI_DISABLE_TEST_HOOKS // Enable tests to override behavior @@ -114,5 +117,6 @@ namespace AppInstaller::CLI::Execution size_t m_CtrlSignalCount = 0; ContextFlag m_flags = ContextFlag::None; Workflow::ExecutionStage m_executionStage = Workflow::ExecutionStage::Initial; + AppInstaller::ThreadLocalStorage::ThreadGlobals m_threadGlobals; }; } diff --git a/src/AppInstallerCLITests/ActivateThreadGlobals.cpp b/src/AppInstallerCLITests/ActivateThreadGlobals.cpp new file mode 100644 index 0000000000..36df3c56a2 --- /dev/null +++ b/src/AppInstallerCLITests/ActivateThreadGlobals.cpp @@ -0,0 +1,17 @@ +#include "pch.h" +#include "Public/ThreadGlobals.h" + +namespace AppInstaller::ThreadLocalStorage +{ + ThreadGlobals* ThreadGlobals::ActivateThreadGlobals(AppInstaller::ThreadLocalStorage::ThreadGlobals* pThreadGlobals) + { + static AppInstaller::ThreadLocalStorage::ThreadGlobals* t_pThreadGlobals = nullptr; + + if (pThreadGlobals) + { + t_pThreadGlobals = pThreadGlobals; + } + + return t_pThreadGlobals; + } +} diff --git a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj index e9b308f106..71b50a3f97 100644 --- a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj +++ b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj @@ -182,6 +182,7 @@ + diff --git a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters index 4a61cf30ce..c49e996f66 100644 --- a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters +++ b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters @@ -1,454 +1,457 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - {d5cac203-3846-4b39-a1cd-8de9303757b4} - - - {69fcd25c-e737-4d28-a6d1-39ce491bf293} - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - - - - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData - - - TestData\MultiFileManifestV1 - - - TestData\MultiFileManifestV1 - - - TestData\MultiFileManifestV1 - - - TestData\MultiFileManifestV1 - - - TestData - - - TestData - - - TestData - - + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {d5cac203-3846-4b39-a1cd-8de9303757b4} + + + {69fcd25c-e737-4d28-a6d1-39ce491bf293} + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + + + + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData + + + TestData\MultiFileManifestV1 + + + TestData\MultiFileManifestV1 + + + TestData\MultiFileManifestV1 + + + TestData\MultiFileManifestV1 + + + TestData + + + TestData + + + TestData + + \ No newline at end of file diff --git a/src/AppInstallerCLITests/main.cpp b/src/AppInstallerCLITests/main.cpp index 9d192bd916..e38b14f209 100644 --- a/src/AppInstallerCLITests/main.cpp +++ b/src/AppInstallerCLITests/main.cpp @@ -9,6 +9,7 @@ #include #include +#include #include "TestCommon.h" #include "TestHooks.h" @@ -18,6 +19,7 @@ using namespace Windows::Foundation; using namespace std::string_literals; using namespace AppInstaller; +ThreadLocalStorage::ThreadGlobals g_ThreadGlobals; // Logs the the AppInstaller log target to break up individual tests struct LoggingBreakListener : public Catch::TestEventListenerBase @@ -54,6 +56,8 @@ int main(int argc, char** argv) bool waitBeforeReturn = false; bool keepSQLLogging = false; + g_ThreadGlobals.SetForCurrentThread(); + std::vector args; for (int i = 0; i < argc; ++i) { diff --git a/src/AppInstallerCommonCore/ActivateThreadGlobals.cpp b/src/AppInstallerCommonCore/ActivateThreadGlobals.cpp new file mode 100644 index 0000000000..3f8f5d92dd --- /dev/null +++ b/src/AppInstallerCommonCore/ActivateThreadGlobals.cpp @@ -0,0 +1,17 @@ +#include "pch.h" +#include "Public/ThreadGlobals.h" + +namespace AppInstaller::ThreadLocalStorage +{ + ThreadGlobals* ThreadGlobals::ActivateThreadGlobals(AppInstaller::ThreadLocalStorage::ThreadGlobals* pThreadGlobals) + { + thread_local AppInstaller::ThreadLocalStorage::ThreadGlobals* t_pThreadGlobals = nullptr; + + if (pThreadGlobals) + { + t_pThreadGlobals = pThreadGlobals; + } + + return t_pThreadGlobals; + } +} diff --git a/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj b/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj index 0b4cfb5380..c1342f46f8 100644 --- a/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj +++ b/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj @@ -1,385 +1,390 @@ - - - - - true - true - true - 15.0 - {5890d6ed-7c3b-40f3-b436-b54f640d9e65} - Win32Proj - AppInstallerLoggingCore - 10.0.18362.0 - 10.0.16299.0 - true - true - - - - - Debug - ARM - - - Debug - ARM64 - - - Debug - Win32 - - - Fuzzing - x64 - - - Release - ARM - - - Release - ARM64 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - StaticLibrary - v140 - v141 - v142 - Unicode - - - true - true - - - false - true - false - - - false - false - false - true - - - Spectre - - - Spectre - - - Spectre - - - Spectre - - - - - - - - - - - - - - - - - true - $(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\ - true - true - ..\CodeAnalysis.ruleset - - - true - $(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\ - true - true - ..\CodeAnalysis.ruleset - - - true - $(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\ - true - true - ..\CodeAnalysis.ruleset - - - true - $(SolutionDir)x86\$(Configuration)\$(ProjectName)\ - true - true - ..\CodeAnalysis.ruleset - - - false - $(SolutionDir)x86\$(Configuration)\$(ProjectName)\ - true - false - ..\CodeAnalysis.ruleset - - - false - $(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\ - true - false - ..\CodeAnalysis.ruleset - - - false - $(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\ - - - false - $(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\ - true - false - ..\CodeAnalysis.ruleset - - - false - $(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\ - true - false - ..\CodeAnalysis.ruleset - - - - Use - pch.h - $(IntDir)pch.pch - _CONSOLE;%(PreprocessorDefinitions) - Level4 - %(AdditionalOptions) /permissive- /D _SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING - - - - - Disabled - _DEBUG;%(PreprocessorDefinitions);CLICOREDLLBUILD - $(ProjectDir);$(ProjectDir)Public;$(ProjectDir)Telemetry;$(ProjectDir)..\binver;$(ProjectDir)..\YamlCppLib\libyaml\include;$(ProjectDir)..\JsonCppLib\json;$(ProjectDir)..\JsonCppLib;%(AdditionalIncludeDirectories) - $(ProjectDir);$(ProjectDir)Public;$(ProjectDir)Telemetry;$(ProjectDir)..\binver;$(ProjectDir)..\YamlCppLib\libyaml\include;$(ProjectDir)..\JsonCppLib\json;$(ProjectDir)..\JsonCppLib;%(AdditionalIncludeDirectories) - $(ProjectDir);$(ProjectDir)Public;$(ProjectDir)Telemetry;$(ProjectDir)..\binver;$(ProjectDir)..\YamlCppLib\libyaml\include;$(ProjectDir)..\JsonCppLib\json;$(ProjectDir)..\JsonCppLib;%(AdditionalIncludeDirectories) - true - true - true - true - true - true - true - true - true - - - false - Windows - Windows - Windows - - - - - WIN32;%(PreprocessorDefinitions);CLICOREDLLBUILD - $(ProjectDir);$(ProjectDir)Public;$(ProjectDir)Telemetry;$(ProjectDir)..\binver;$(ProjectDir)..\YamlCppLib\libyaml\include;$(ProjectDir)..\JsonCppLib\json;$(ProjectDir)..\JsonCppLib;%(AdditionalIncludeDirectories) - true - true - true - - - Windows - - - - - MaxSpeed - true - true - NDEBUG;%(PreprocessorDefinitions);CLICOREDLLBUILD - $(ProjectDir);$(ProjectDir)Public;$(ProjectDir)Telemetry;$(ProjectDir)..\binver;$(ProjectDir)..\YamlCppLib\libyaml\include;$(ProjectDir)..\JsonCppLib\json;$(ProjectDir)..\JsonCppLib;%(AdditionalIncludeDirectories) - $(ProjectDir);$(ProjectDir)Public;$(ProjectDir)Telemetry;$(ProjectDir)..\binver;$(ProjectDir)..\YamlCppLib\libyaml\include;$(ProjectDir)..\JsonCppLib\json;$(ProjectDir)..\JsonCppLib;%(AdditionalIncludeDirectories) - $(ProjectDir);$(ProjectDir)Public;$(ProjectDir)Telemetry;$(ProjectDir)..\binver;$(ProjectDir)..\YamlCppLib\libyaml\include;$(ProjectDir)..\JsonCppLib\json;$(ProjectDir)..\JsonCppLib;%(AdditionalIncludeDirectories) - $(ProjectDir);$(ProjectDir)Public;$(ProjectDir)Telemetry;$(ProjectDir)..\binver;$(ProjectDir)..\YamlCppLib\libyaml\include;$(ProjectDir)..\JsonCppLib\json;$(ProjectDir)..\JsonCppLib;%(AdditionalIncludeDirectories) - true - true - true - true - true - true - true - true - false - false - false - false - - - true - true - false - Windows - Windows - Windows - Windows - - - - - MaxSpeed - true - true - NDEBUG;%(PreprocessorDefinitions);CLICOREDLLBUILD;WINGET_DISABLE_FOR_FUZZING - $(ProjectDir);$(ProjectDir)Public;$(ProjectDir)Telemetry;$(ProjectDir)..\binver;$(ProjectDir)..\YamlCppLib\libyaml\include;$(ProjectDir)..\JsonCppLib\json;$(ProjectDir)..\JsonCppLib;%(AdditionalIncludeDirectories) - true - stdcpp17 - MultiThreaded - %(AdditionalOptions) /fsanitize-coverage=inline-8bit-counters /fsanitize-coverage=edge /fsanitize-coverage=trace-cmp /fsanitize-coverage=trace-div - - - true - true - false - Windows - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - true - - - - - - true - - - - - - true - - - - true - - - true - - - true - - - - - - - - - - - - true - - - - - - - Create - - - - - - - - - - - - - - - - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - + + + + + true + true + true + 15.0 + {5890d6ed-7c3b-40f3-b436-b54f640d9e65} + Win32Proj + AppInstallerLoggingCore + 10.0.18362.0 + 10.0.16299.0 + true + true + + + + + Debug + ARM + + + Debug + ARM64 + + + Debug + Win32 + + + Fuzzing + x64 + + + Release + ARM + + + Release + ARM64 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + StaticLibrary + v140 + v141 + v142 + Unicode + + + true + true + + + false + true + false + + + false + false + false + true + + + Spectre + + + Spectre + + + Spectre + + + Spectre + + + + + + + + + + + + + + + + + true + $(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\ + true + true + ..\CodeAnalysis.ruleset + + + true + $(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\ + true + true + ..\CodeAnalysis.ruleset + + + true + $(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\ + true + true + ..\CodeAnalysis.ruleset + + + true + $(SolutionDir)x86\$(Configuration)\$(ProjectName)\ + true + true + ..\CodeAnalysis.ruleset + + + false + $(SolutionDir)x86\$(Configuration)\$(ProjectName)\ + true + false + ..\CodeAnalysis.ruleset + + + false + $(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\ + true + false + ..\CodeAnalysis.ruleset + + + false + $(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\ + + + false + $(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\ + true + false + ..\CodeAnalysis.ruleset + + + false + $(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\ + true + false + ..\CodeAnalysis.ruleset + + + + Use + pch.h + $(IntDir)pch.pch + _CONSOLE;%(PreprocessorDefinitions) + Level4 + %(AdditionalOptions) /permissive- /D _SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING + + + + + Disabled + _DEBUG;%(PreprocessorDefinitions);CLICOREDLLBUILD + $(ProjectDir);$(ProjectDir)Public;$(ProjectDir)Telemetry;$(ProjectDir)..\binver;$(ProjectDir)..\YamlCppLib\libyaml\include;$(ProjectDir)..\JsonCppLib\json;$(ProjectDir)..\JsonCppLib;%(AdditionalIncludeDirectories) + $(ProjectDir);$(ProjectDir)Public;$(ProjectDir)Telemetry;$(ProjectDir)..\binver;$(ProjectDir)..\YamlCppLib\libyaml\include;$(ProjectDir)..\JsonCppLib\json;$(ProjectDir)..\JsonCppLib;%(AdditionalIncludeDirectories) + $(ProjectDir);$(ProjectDir)Public;$(ProjectDir)Telemetry;$(ProjectDir)..\binver;$(ProjectDir)..\YamlCppLib\libyaml\include;$(ProjectDir)..\JsonCppLib\json;$(ProjectDir)..\JsonCppLib;%(AdditionalIncludeDirectories) + true + true + true + true + true + true + true + true + true + + + false + Windows + Windows + Windows + + + + + WIN32;%(PreprocessorDefinitions);CLICOREDLLBUILD + $(ProjectDir);$(ProjectDir)Public;$(ProjectDir)Telemetry;$(ProjectDir)..\binver;$(ProjectDir)..\YamlCppLib\libyaml\include;$(ProjectDir)..\JsonCppLib\json;$(ProjectDir)..\JsonCppLib;%(AdditionalIncludeDirectories) + true + true + true + + + Windows + + + + + MaxSpeed + true + true + NDEBUG;%(PreprocessorDefinitions);CLICOREDLLBUILD + $(ProjectDir);$(ProjectDir)Public;$(ProjectDir)Telemetry;$(ProjectDir)..\binver;$(ProjectDir)..\YamlCppLib\libyaml\include;$(ProjectDir)..\JsonCppLib\json;$(ProjectDir)..\JsonCppLib;%(AdditionalIncludeDirectories) + $(ProjectDir);$(ProjectDir)Public;$(ProjectDir)Telemetry;$(ProjectDir)..\binver;$(ProjectDir)..\YamlCppLib\libyaml\include;$(ProjectDir)..\JsonCppLib\json;$(ProjectDir)..\JsonCppLib;%(AdditionalIncludeDirectories) + $(ProjectDir);$(ProjectDir)Public;$(ProjectDir)Telemetry;$(ProjectDir)..\binver;$(ProjectDir)..\YamlCppLib\libyaml\include;$(ProjectDir)..\JsonCppLib\json;$(ProjectDir)..\JsonCppLib;%(AdditionalIncludeDirectories) + $(ProjectDir);$(ProjectDir)Public;$(ProjectDir)Telemetry;$(ProjectDir)..\binver;$(ProjectDir)..\YamlCppLib\libyaml\include;$(ProjectDir)..\JsonCppLib\json;$(ProjectDir)..\JsonCppLib;%(AdditionalIncludeDirectories) + true + true + true + true + true + true + true + true + false + false + false + false + + + true + true + false + Windows + Windows + Windows + Windows + + + + + MaxSpeed + true + true + NDEBUG;%(PreprocessorDefinitions);CLICOREDLLBUILD;WINGET_DISABLE_FOR_FUZZING + $(ProjectDir);$(ProjectDir)Public;$(ProjectDir)Telemetry;$(ProjectDir)..\binver;$(ProjectDir)..\YamlCppLib\libyaml\include;$(ProjectDir)..\JsonCppLib\json;$(ProjectDir)..\JsonCppLib;%(AdditionalIncludeDirectories) + true + stdcpp17 + MultiThreaded + %(AdditionalOptions) /fsanitize-coverage=inline-8bit-counters /fsanitize-coverage=edge /fsanitize-coverage=trace-cmp /fsanitize-coverage=trace-div + + + true + true + false + Windows + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + + + + true + + + + + + true + + + + true + + + true + + + true + + + + + + + + + + + + true + + + + + + + + Create + + + + + + + + + + + + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + \ No newline at end of file diff --git a/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj.filters b/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj.filters index c1b010760e..069cc02a49 100644 --- a/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj.filters +++ b/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj.filters @@ -1,298 +1,313 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - {552a58eb-8d07-41b2-87b5-3e71b9fb3cfd} - - - {5cdf3fa3-e657-4d84-81bb-f740aa476143} - - - {a9c14af9-ca74-4945-a19c-9e99df23a5ae} - - - {41035fd6-dc74-4464-b9b1-4ffe95d6789c} - - - {9b8e2682-3eb7-4530-bc9a-a57fafc44177} - - - - - Header Files - - - Telemetry - Do Not Modify - - - Telemetry - Do Not Modify - - - Telemetry - Do Not Modify - - - Public - - - Public - - - Public - - - Public - - - Public - - - Public - - - Public - - - Public - - - Public - - - HttpStream - - - HttpStream - - - HttpStream - - - Public - - - Public - - - Public - - - Public - - - Public - - - Public - - - Public - - - Public\winget - - - Public\winget - - - Public\winget - - - Public\winget - - - Header Files - - - Public\winget - - - Header Files - - - Public\winget - - - Public\winget - - - Public\winget - - - Public\winget - - - Public\winget - - - Public\winget - - - Public\winget - - - Public\winget - - - Public\winget - - - Public\winget - - - Public\winget - - - Public\winget - - - Public\winget - - - Public\winget - - - Public\winget - - - Public\winget - - - Header Files - - - - - Source Files - - - Telemetry - Do Not Modify - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - HttpStream - - - HttpStream - - - HttpStream - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Manifest - - - Manifest - - - Source Files - - - Source Files - - - Source Files - - - Manifest - - - Manifest - - - Manifest - - - Manifest - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - - + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {552a58eb-8d07-41b2-87b5-3e71b9fb3cfd} + + + {5cdf3fa3-e657-4d84-81bb-f740aa476143} + + + {a9c14af9-ca74-4945-a19c-9e99df23a5ae} + + + {41035fd6-dc74-4464-b9b1-4ffe95d6789c} + + + {9b8e2682-3eb7-4530-bc9a-a57fafc44177} + + + + + Header Files + + + Telemetry - Do Not Modify + + + Telemetry - Do Not Modify + + + Telemetry - Do Not Modify + + + Public + + + Public + + + Public + + + Public + + + Public + + + Public + + + Public + + + Public + + + Public + + + HttpStream + + + HttpStream + + + HttpStream + + + Public + + + Public + + + Public + + + Public + + + Public + + + Public + + + Public + + + Public\winget + + + Public\winget + + + Public\winget + + + Public\winget + + + Header Files + + + Public\winget + + + Header Files + + + Public\winget + + + Public\winget + + + Public\winget + + + Public\winget + + + Public\winget + + + Public\winget + + + Public\winget + + + Public\winget + + + Public\winget + + + Public\winget + + + Public\winget + + + Public\winget + + + Public\winget + + + Public + + + Public + + + Public\winget + + + Public\winget + + + Public\winget + + + Header Files + + + + + Source Files + + + Telemetry - Do Not Modify + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + HttpStream + + + HttpStream + + + HttpStream + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Manifest + + + Manifest + + + Source Files + + + Source Files + + + Source Files + + + Manifest + + + Manifest + + + Manifest + + + Manifest + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + + \ No newline at end of file diff --git a/src/AppInstallerCommonCore/AppInstallerLogging.cpp b/src/AppInstallerCommonCore/AppInstallerLogging.cpp index 1f0d6cf57b..aa3968f709 100644 --- a/src/AppInstallerCommonCore/AppInstallerLogging.cpp +++ b/src/AppInstallerCommonCore/AppInstallerLogging.cpp @@ -4,10 +4,13 @@ #include "Public/AppInstallerLogging.h" #include "Public/AppInstallerFileLogger.h" +#include "Public/AppInstallerTraceLogger.h" #include "Public/AppInstallerTelemetry.h" #include "Public/AppInstallerDateTime.h" #include "Public/AppInstallerRuntime.h" +#include "Public/ThreadGlobals.h" + namespace AppInstaller::Logging { namespace @@ -42,18 +45,13 @@ namespace AppInstaller::Logging case Channel::YAML: return "YAML"; case Channel::Core: return "CORE"; case Channel::Test: return "TEST"; + case Channel::Log: return "LOG"; default: return "NONE"; } } size_t GetMaxChannelNameLength() { return 4; } - DiagnosticLogger& DiagnosticLogger::GetInstance() - { - static DiagnosticLogger instance; - return instance; - } - void DiagnosticLogger::AddLogger(std::unique_ptr&& logger) { m_loggers.emplace_back(std::move(logger)); @@ -129,11 +127,21 @@ namespace AppInstaller::Logging } } + DiagnosticLogger& Log() + { + return AppInstaller::ThreadLocalStorage::ThreadGlobals::GetForCurrentThread()->GetDiagnosticLogger(); + } + void AddFileLogger(const std::filesystem::path& filePath) { Log().AddLogger(std::make_unique(filePath)); } + void AddTraceLogger() + { + Log().AddLogger(std::make_unique()); + } + void BeginLogFileCleanup() { FileLogger::BeginCleanup(Runtime::GetPathTo(Runtime::PathName::DefaultLogLocation)); @@ -143,6 +151,7 @@ namespace AppInstaller::Logging { return out << std::hex << std::setw(8) << std::setfill('0'); } + } std::ostream& operator<<(std::ostream& out, const std::chrono::system_clock::time_point& time) diff --git a/src/AppInstallerCommonCore/AppInstallerTelemetry.cpp b/src/AppInstallerCommonCore/AppInstallerTelemetry.cpp index aca1e8ba5a..d195a2ecea 100644 --- a/src/AppInstallerCommonCore/AppInstallerTelemetry.cpp +++ b/src/AppInstallerCommonCore/AppInstallerTelemetry.cpp @@ -7,6 +7,7 @@ #include "Public/AppInstallerSHA256.h" #include "Public/AppInstallerStrings.h" #include "winget/UserSettings.h" +#include "Public/ThreadGlobals.h" #define AICLI_TraceLoggingStringView(_sv_,_name_) TraceLoggingCountedUtf8String(_sv_.data(), static_cast(_sv_.size()), _name_) #define AICLI_TraceLoggingWStringView(_sv_,_name_) TraceLoggingCountedWideString(_sv_.data(), static_cast(_sv_.size()), _name_) @@ -46,27 +47,20 @@ namespace AppInstaller::Logging { Telemetry().LogFailure(info); } - - GUID CreateGuid() - { - GUID result{}; - (void)CoCreateGuid(&result); - return result; - } - - const GUID* GetActivityId() - { - static GUID activityId = CreateGuid(); - return &activityId; - } } TelemetryTraceLogger::TelemetryTraceLogger() { - // TODO: Needs to be made a singleton registration/removal in the future + HRESULT hr = S_OK; + RegisterTraceLogging(); - m_isSettingEnabled = !Settings::User().Get(); + hr = CoCreateGuid(&m_activityId); + if (FAILED(hr)) + { + AICLI_LOG(Log, Error, << "Failed to Create ActivityId GUID"); + } + m_userProfile = Runtime::GetPathTo(Runtime::PathName::UserProfile).wstring(); } @@ -75,10 +69,9 @@ namespace AppInstaller::Logging UnRegisterTraceLogging(); } - TelemetryTraceLogger& TelemetryTraceLogger::GetInstance() + const GUID* TelemetryTraceLogger::GetActivityId() const { - static TelemetryTraceLogger instance; - return instance; + return &m_activityId; } bool TelemetryTraceLogger::DisableRuntime() @@ -91,11 +84,50 @@ namespace AppInstaller::Logging m_isRuntimeEnabled = true; } + void TelemetryTraceLogger::SetUserSettingsStatus() + { + m_isSettingEnabled = !Settings::User().Get(); + } + + void TelemetryTraceLogger::SetTelemetryCorelationJson(std::string jsonStr) + { + m_telemetryCorelationJson = jsonStr; + } + + std::string TelemetryTraceLogger::GetTelemetryCorelationJson() const + { + // Check if passed in string is a valid Json formatted before returning the value + // If invalid, return empty Json + Json::CharReaderBuilder jsonBuilder; + Json::CharReader* jsonReader = jsonBuilder.newCharReader();; + Json::Value jsonValue; + std::string jsonStr = m_telemetryCorelationJson; + std::string errors; + + bool result = jsonReader->parse(jsonStr.c_str(), + jsonStr.c_str() + jsonStr.size(), + &jsonValue, + &errors); + + delete jsonReader; + + if (!result) + { + jsonStr = "{}"; + } + return jsonStr; + } + + void TelemetryTraceLogger::SetCOMCaller(std::string comCaller) + { + m_comCaller = comCaller; + } + void TelemetryTraceLogger::LogFailure(const wil::FailureInfo& failure) const noexcept { if (IsTelemetryEnabled()) { - TraceLoggingWriteActivity(g_hTelemetryProvider, + TraceLoggingWriteActivity(g_hTraceProvider, "FailureInfo", GetActivityId(), nullptr, @@ -120,7 +152,7 @@ namespace AppInstaller::Logging }()); } - void TelemetryTraceLogger::LogStartup() const noexcept + void TelemetryTraceLogger::LogStartup(bool isCOMCall) const noexcept { LocIndString version = Runtime::GetClientVersion(); LocIndString packageVersion; @@ -129,14 +161,24 @@ namespace AppInstaller::Logging packageVersion = Runtime::GetPackageVersion(); } + std::string jsonStr = GetTelemetryCorelationJson(); + if (IsTelemetryEnabled()) { - TraceLoggingWriteActivity(g_hTelemetryProvider, + TraceLoggingWriteActivity(g_hTraceProvider, "ClientVersion", GetActivityId(), nullptr, TraceLoggingCountedString(version->c_str(), static_cast(version->size()), "Version"), TraceLoggingCountedString(packageVersion->c_str(), static_cast(packageVersion->size()), "PackageVersion"), + TraceLoggingBool(isCOMCall, "IsCOMCall"), + TraceLoggingCountedString(m_comCaller.c_str(), static_cast(m_comCaller.size()), "COMCaller"), + TraceLoggingPackedFieldEx( + jsonStr.c_str(), + static_cast((strlen(jsonStr.c_str()) + 1) * sizeof(char)), + TlgInANSISTRING, + TlgOutJSON, + "COMCallerCj"), TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance), TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)); } @@ -148,13 +190,15 @@ namespace AppInstaller::Logging { AICLI_LOG(Core, Info, << "Package: " << packageVersion); } + + AICLI_LOG(Core, Info, << "IsCOMCall:" << isCOMCall << "; COMCaller: " << m_comCaller << "; COMCallerCj: " << jsonStr << ";"); } void TelemetryTraceLogger::LogCommand(std::string_view commandName) const noexcept { if (IsTelemetryEnabled()) { - TraceLoggingWriteActivity(g_hTelemetryProvider, + TraceLoggingWriteActivity(g_hTraceProvider, "CommandFound", GetActivityId(), nullptr, @@ -170,7 +214,7 @@ namespace AppInstaller::Logging { if (IsTelemetryEnabled()) { - TraceLoggingWriteActivity(g_hTelemetryProvider, + TraceLoggingWriteActivity(g_hTraceProvider, "CommandSuccess", GetActivityId(), nullptr, @@ -186,7 +230,7 @@ namespace AppInstaller::Logging { if (IsTelemetryEnabled()) { - TraceLoggingWriteActivity(g_hTelemetryProvider, + TraceLoggingWriteActivity(g_hTraceProvider, "CommandTermination", GetActivityId(), nullptr, @@ -206,7 +250,7 @@ namespace AppInstaller::Logging { if (IsTelemetryEnabled()) { - TraceLoggingWriteActivity(g_hTelemetryProvider, + TraceLoggingWriteActivity(g_hTraceProvider, "Exception", GetActivityId(), nullptr, @@ -226,7 +270,7 @@ namespace AppInstaller::Logging { if (IsTelemetryEnabled()) { - TraceLoggingWriteActivity(g_hTelemetryProvider, + TraceLoggingWriteActivity(g_hTraceProvider, "GetManifest", GetActivityId(), nullptr, @@ -241,7 +285,7 @@ namespace AppInstaller::Logging { if (IsTelemetryEnabled()) { - TraceLoggingWriteActivity(g_hTelemetryProvider, + TraceLoggingWriteActivity(g_hTraceProvider, "ManifestFields", GetActivityId(), nullptr, @@ -260,7 +304,7 @@ namespace AppInstaller::Logging { if (IsTelemetryEnabled()) { - TraceLoggingWriteActivity(g_hTelemetryProvider, + TraceLoggingWriteActivity(g_hTraceProvider, "NoAppMatch", GetActivityId(), nullptr, @@ -276,7 +320,7 @@ namespace AppInstaller::Logging { if (IsTelemetryEnabled()) { - TraceLoggingWriteActivity(g_hTelemetryProvider, + TraceLoggingWriteActivity(g_hTraceProvider, "MultiAppMatch", GetActivityId(), nullptr, @@ -292,7 +336,7 @@ namespace AppInstaller::Logging { if (IsTelemetryEnabled()) { - TraceLoggingWriteActivity(g_hTelemetryProvider, + TraceLoggingWriteActivity(g_hTraceProvider, "AppFound", GetActivityId(), nullptr, @@ -310,7 +354,7 @@ namespace AppInstaller::Logging { if (IsTelemetryEnabled()) { - TraceLoggingWriteActivity(g_hTelemetryProvider, + TraceLoggingWriteActivity(g_hTraceProvider, "SelectedInstaller", GetActivityId(), nullptr, @@ -345,7 +389,7 @@ namespace AppInstaller::Logging { if (IsTelemetryEnabled()) { - TraceLoggingWriteActivity(g_hTelemetryProvider, + TraceLoggingWriteActivity(g_hTraceProvider, "SearchRequest", GetActivityId(), nullptr, @@ -368,7 +412,7 @@ namespace AppInstaller::Logging { if (IsTelemetryEnabled()) { - TraceLoggingWriteActivity(g_hTelemetryProvider, + TraceLoggingWriteActivity(g_hTraceProvider, "SearchResultCount", GetActivityId(), nullptr, @@ -389,7 +433,7 @@ namespace AppInstaller::Logging { if (IsTelemetryEnabled()) { - TraceLoggingWriteActivity(g_hTelemetryProvider, + TraceLoggingWriteActivity(g_hTraceProvider, "HashMismatch", GetActivityId(), nullptr, @@ -416,7 +460,7 @@ namespace AppInstaller::Logging { if (IsTelemetryEnabled()) { - TraceLoggingWriteActivity(g_hTelemetryProvider, + TraceLoggingWriteActivity(g_hTraceProvider, "InstallerFailure", GetActivityId(), nullptr, @@ -437,7 +481,7 @@ namespace AppInstaller::Logging { if (IsTelemetryEnabled()) { - TraceLoggingWriteActivity(g_hTelemetryProvider, + TraceLoggingWriteActivity(g_hTraceProvider, "UninstallerFailure", GetActivityId(), nullptr, @@ -477,7 +521,7 @@ namespace AppInstaller::Logging } catch (...) {} - TraceLoggingWriteActivity(g_hTelemetryProvider, + TraceLoggingWriteActivity(g_hTraceProvider, "InstallARPChange", GetActivityId(), nullptr, @@ -534,7 +578,7 @@ namespace AppInstaller::Logging } #endif - return TelemetryTraceLogger::GetInstance(); + return AppInstaller::ThreadLocalStorage::ThreadGlobals::GetForCurrentThread()->GetTelemetryLogger(); } void EnableWilFailureTelemetry() diff --git a/src/AppInstallerCommonCore/Public/AppInstallerLogging.h b/src/AppInstallerCommonCore/Public/AppInstallerLogging.h index e6b7163e09..e6b3b1b05c 100644 --- a/src/AppInstallerCommonCore/Public/AppInstallerLogging.h +++ b/src/AppInstallerCommonCore/Public/AppInstallerLogging.h @@ -36,6 +36,7 @@ namespace AppInstaller::Logging YAML, Core, Test, + Log, All, }; @@ -72,6 +73,8 @@ namespace AppInstaller::Logging // desired level, as nothing is enabled by default. struct DiagnosticLogger { + DiagnosticLogger() = default; + ~DiagnosticLogger() = default; DiagnosticLogger(const DiagnosticLogger&) = delete; @@ -80,9 +83,6 @@ namespace AppInstaller::Logging DiagnosticLogger(DiagnosticLogger&&) = delete; DiagnosticLogger& operator=(DiagnosticLogger&&) = delete; - // Gets the singleton instance of this type. - static DiagnosticLogger& GetInstance(); - // NOTE: The logger management functionality is *SINGLE THREAD SAFE*. // This includes with logging itself. // As it is not expected that adding/removing loggers is an @@ -119,7 +119,6 @@ namespace AppInstaller::Logging void Write(Channel channel, Level level, std::string_view message); private: - DiagnosticLogger() = default; std::vector> m_loggers; uint64_t m_enabledChannels = 0; @@ -127,14 +126,14 @@ namespace AppInstaller::Logging }; // Helper to make the call sites look clean. - inline DiagnosticLogger& Log() - { - return DiagnosticLogger::GetInstance(); - } + DiagnosticLogger& Log(); // Adds the default file logger to the DiagnosticLogger. void AddFileLogger(const std::filesystem::path& filePath = {}); + // Adds the trace logger to the DiagnosticLogger. + void AddTraceLogger(); + // Starts a background task to clean up old log files. void BeginLogFileCleanup(); diff --git a/src/AppInstallerCommonCore/Public/AppInstallerTelemetry.h b/src/AppInstallerCommonCore/Public/AppInstallerTelemetry.h index 84d134c0ab..12c6bda2ce 100644 --- a/src/AppInstallerCommonCore/Public/AppInstallerTelemetry.h +++ b/src/AppInstallerCommonCore/Public/AppInstallerTelemetry.h @@ -1,177 +1,195 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. -#pragma once -#include -#include - -#include -#include - -namespace AppInstaller::Logging -{ - // This type contains the registration lifetime of the telemetry trace logging provider. - // Due to the nature of trace logging, specific methods should be added per desired trace. - // As there should not be a significantly large number of individual telemetry events, - // this should not become a burden. - struct TelemetryTraceLogger - { - virtual ~TelemetryTraceLogger(); - - TelemetryTraceLogger(const TelemetryTraceLogger&) = default; - TelemetryTraceLogger& operator=(const TelemetryTraceLogger&) = default; - - TelemetryTraceLogger(TelemetryTraceLogger&&) = default; - TelemetryTraceLogger& operator=(TelemetryTraceLogger&&) = default; - - // Gets the singleton instance of this type. - static TelemetryTraceLogger& GetInstance(); - - // Control whether this trace logger is enabled at runtime. - bool DisableRuntime(); - void EnableRuntime(); - - // Logs the failure info. - void LogFailure(const wil::FailureInfo& failure) const noexcept; - - // Logs the initial process startup. - void LogStartup() const noexcept; - - // Logs the invoked command. - void LogCommand(std::string_view commandName) const noexcept; - - // Logs the invoked command success. - void LogCommandSuccess(std::string_view commandName) const noexcept; - - // Logs the invoked command termination. - void LogCommandTermination(HRESULT hr, std::string_view file, size_t line) const noexcept; - - // Logs the invoked command termination. - void LogException(std::string_view commandName, std::string_view type, std::string_view message) const noexcept; - - // Logs whether the manifest used in workflow is local - void LogIsManifestLocal(bool isLocalManifest) const noexcept; - - // Logs the Manifest fields. - void LogManifestFields(std::string_view id, std::string_view name, std::string_view version) const noexcept; - - // Logs when there is no matching App found for search - void LogNoAppMatch() const noexcept; - - // Logs when there is multiple matching Apps found for search - void LogMultiAppMatch() const noexcept; - - // Logs the name and Id of app found - void LogAppFound(std::string_view name, std::string_view id) const noexcept; - - // Logs the selected installer details - void LogSelectedInstaller(int arch, std::string_view url, std::string_view installerType, std::string_view scope, std::string_view language) const noexcept; - - // Logs details of a search request. - void LogSearchRequest( - std::string_view type, - std::string_view query, - std::string_view id, - std::string_view name, - std::string_view moniker, - std::string_view tag, - std::string_view command, - size_t maximum, - std::string_view request) const noexcept; - - // Logs the Search Result - void LogSearchResultCount(uint64_t resultCount) const noexcept; - - // Logs a mismatch between the expected and actual hash values. - void LogInstallerHashMismatch( - std::string_view id, - std::string_view version, - std::string_view channel, - const std::vector& expected, - const std::vector& actual, - bool overrideHashMismatch) const noexcept; - - // Logs a failed installation attempt. - void LogInstallerFailure(std::string_view id, std::string_view version, std::string_view channel, std::string_view type, uint32_t errorCode) const noexcept; - - // Logs a failed uninstallation attempt. - void LogUninstallerFailure(std::string_view id, std::string_view version, std::string_view type, uint32_t errorCode) const noexcept; - - // Logs data about the changes that ocurred in the ARP entries based on an install. - // First 4 arguments are well known values for the package that we installed. - // The next 3 are counts of the number of packages in each category. - // The last 4 are the fields directly from the ARP entry that has been determined to be related to the package that - // was installed, or they will be empty if there is no data or ambiguity about which entry should be logged. - virtual void LogSuccessfulInstallARPChange( - std::string_view sourceIdentifier, - std::string_view packageIdentifier, - std::string_view packageVersion, - std::string_view packageChannel, - size_t changesToARP, - size_t matchesInARP, - size_t countOfIntersectionOfChangesAndMatches, - std::string_view arpName, - std::string_view arpVersion, - std::string_view arpPublisher, - std::string_view arpLanguage) const noexcept; - - protected: - TelemetryTraceLogger(); - - bool IsTelemetryEnabled() const noexcept; - - // Used to anonymize a string to the best of our ability. - // Should primarily be used on failure messages or paths if needed. - std::wstring AnonymizeString(std::wstring_view input) const noexcept; - - bool m_isSettingEnabled = true; - std::atomic_bool m_isRuntimeEnabled{ true }; - - // Data that is needed by AnonymizeString - std::wstring m_userProfile; - }; - - // Helper to make the call sites look clean. - TelemetryTraceLogger& Telemetry(); - - // Turns on wil failure telemetry and logging. - void EnableWilFailureTelemetry(); - - // An RAII object to disable telemetry during its lifetime. - // Primarily used by the complete command to prevent messy input from spamming us. - struct DisableTelemetryScope - { - DisableTelemetryScope(); - - DisableTelemetryScope(const DisableTelemetryScope&) = delete; - DisableTelemetryScope& operator=(const DisableTelemetryScope&) = delete; - - DisableTelemetryScope(DisableTelemetryScope&&) = default; - DisableTelemetryScope& operator=(DisableTelemetryScope&&) = default; - - ~DisableTelemetryScope(); - - private: - DestructionToken m_token; - }; - - // Sets an execution stage to be reported when failures occur. - void SetExecutionStage(uint32_t stage); - - // An RAII object to log telemetry as sub execution. - // Does not support nested sub execution. - struct SubExecutionTelemetryScope - { - SubExecutionTelemetryScope(); - - SubExecutionTelemetryScope(const SubExecutionTelemetryScope&) = delete; - SubExecutionTelemetryScope& operator=(const SubExecutionTelemetryScope&) = delete; - - SubExecutionTelemetryScope(SubExecutionTelemetryScope&&) = default; - SubExecutionTelemetryScope& operator=(SubExecutionTelemetryScope&&) = default; - - ~SubExecutionTelemetryScope(); - - private: - static std::atomic_uint32_t m_sessionId; - }; -} +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#pragma once +#include +#include + +#include +#include +#include + +namespace AppInstaller::Logging +{ + // This type contains the registration lifetime of the telemetry trace logging provider. + // Due to the nature of trace logging, specific methods should be added per desired trace. + // As there should not be a significantly large number of individual telemetry events, + // this should not become a burden. + struct TelemetryTraceLogger + { + TelemetryTraceLogger(); + + virtual ~TelemetryTraceLogger(); + + TelemetryTraceLogger(const TelemetryTraceLogger&) = default; + TelemetryTraceLogger& operator=(const TelemetryTraceLogger&) = default; + + TelemetryTraceLogger(TelemetryTraceLogger&&) = default; + TelemetryTraceLogger& operator=(TelemetryTraceLogger&&) = default; + + // Control whether this trace logger is enabled at runtime. + bool DisableRuntime(); + void EnableRuntime(); + + // Return address of m_activityId + const GUID* GetActivityId() const; + + // Capture if UserSettings is enabled + void SetUserSettingsStatus(); + + // Store the passed in name of the Caller for COM calls + void SetCOMCaller(std::string comCaller); + + // Store the passed in Telemetry Corelation Json for COM calls + void SetTelemetryCorelationJson(std::string jsonStr); + + // Logs the failure info. + void LogFailure(const wil::FailureInfo& failure) const noexcept; + + // Logs the initial process startup. + void LogStartup(bool isCOMCall = false) const noexcept; + + // Logs the invoked command. + void LogCommand(std::string_view commandName) const noexcept; + + // Logs the invoked command success. + void LogCommandSuccess(std::string_view commandName) const noexcept; + + // Logs the invoked command termination. + void LogCommandTermination(HRESULT hr, std::string_view file, size_t line) const noexcept; + + // Logs the invoked command termination. + void LogException(std::string_view commandName, std::string_view type, std::string_view message) const noexcept; + + // Logs whether the manifest used in workflow is local + void LogIsManifestLocal(bool isLocalManifest) const noexcept; + + // Logs the Manifest fields. + void LogManifestFields(std::string_view id, std::string_view name, std::string_view version) const noexcept; + + // Logs when there is no matching App found for search + void LogNoAppMatch() const noexcept; + + // Logs when there is multiple matching Apps found for search + void LogMultiAppMatch() const noexcept; + + // Logs the name and Id of app found + void LogAppFound(std::string_view name, std::string_view id) const noexcept; + + // Logs the selected installer details + void LogSelectedInstaller(int arch, std::string_view url, std::string_view installerType, std::string_view scope, std::string_view language) const noexcept; + + // Logs details of a search request. + void LogSearchRequest( + std::string_view type, + std::string_view query, + std::string_view id, + std::string_view name, + std::string_view moniker, + std::string_view tag, + std::string_view command, + size_t maximum, + std::string_view request) const noexcept; + + // Logs the Search Result + void LogSearchResultCount(uint64_t resultCount) const noexcept; + + // Logs a mismatch between the expected and actual hash values. + void LogInstallerHashMismatch( + std::string_view id, + std::string_view version, + std::string_view channel, + const std::vector& expected, + const std::vector& actual, + bool overrideHashMismatch) const noexcept; + + // Logs a failed installation attempt. + void LogInstallerFailure(std::string_view id, std::string_view version, std::string_view channel, std::string_view type, uint32_t errorCode) const noexcept; + + // Logs a failed uninstallation attempt. + void LogUninstallerFailure(std::string_view id, std::string_view version, std::string_view type, uint32_t errorCode) const noexcept; + + // Logs data about the changes that ocurred in the ARP entries based on an install. + // First 4 arguments are well known values for the package that we installed. + // The next 3 are counts of the number of packages in each category. + // The last 4 are the fields directly from the ARP entry that has been determined to be related to the package that + // was installed, or they will be empty if there is no data or ambiguity about which entry should be logged. + virtual void LogSuccessfulInstallARPChange( + std::string_view sourceIdentifier, + std::string_view packageIdentifier, + std::string_view packageVersion, + std::string_view packageChannel, + size_t changesToARP, + size_t matchesInARP, + size_t countOfIntersectionOfChangesAndMatches, + std::string_view arpName, + std::string_view arpVersion, + std::string_view arpPublisher, + std::string_view arpLanguage) const noexcept; + + protected: + + // Check for valid Json string and return a valid Json + std::string GetTelemetryCorelationJson() const; + + bool IsTelemetryEnabled() const noexcept; + + // Used to anonymize a string to the best of our ability. + // Should primarily be used on failure messages or paths if needed. + std::wstring AnonymizeString(std::wstring_view input) const noexcept; + + bool m_isSettingEnabled = true; + std::atomic_bool m_isRuntimeEnabled{ true }; + + GUID m_activityId = GUID_NULL; + std::string m_telemetryCorelationJson = "{}"; + std::string m_comCaller = ""; + + // Data that is needed by AnonymizeString + std::wstring m_userProfile; + }; + + // Helper to make the call sites look clean. + TelemetryTraceLogger& Telemetry(); + + // Turns on wil failure telemetry and logging. + void EnableWilFailureTelemetry(); + + // An RAII object to disable telemetry during its lifetime. + // Primarily used by the complete command to prevent messy input from spamming us. + struct DisableTelemetryScope + { + DisableTelemetryScope(); + + DisableTelemetryScope(const DisableTelemetryScope&) = delete; + DisableTelemetryScope& operator=(const DisableTelemetryScope&) = delete; + + DisableTelemetryScope(DisableTelemetryScope&&) = default; + DisableTelemetryScope& operator=(DisableTelemetryScope&&) = default; + + ~DisableTelemetryScope(); + + private: + DestructionToken m_token; + }; + + // Sets an execution stage to be reported when failures occur. + void SetExecutionStage(uint32_t stage); + + // An RAII object to log telemetry as sub execution. + // Does not support nested sub execution. + struct SubExecutionTelemetryScope + { + SubExecutionTelemetryScope(); + + SubExecutionTelemetryScope(const SubExecutionTelemetryScope&) = delete; + SubExecutionTelemetryScope& operator=(const SubExecutionTelemetryScope&) = delete; + + SubExecutionTelemetryScope(SubExecutionTelemetryScope&&) = default; + SubExecutionTelemetryScope& operator=(SubExecutionTelemetryScope&&) = default; + + ~SubExecutionTelemetryScope(); + + private: + static std::atomic_uint32_t m_sessionId; + }; +} diff --git a/src/AppInstallerCommonCore/Public/AppInstallerTraceLogger.h b/src/AppInstallerCommonCore/Public/AppInstallerTraceLogger.h new file mode 100644 index 0000000000..d01630c063 --- /dev/null +++ b/src/AppInstallerCommonCore/Public/AppInstallerTraceLogger.h @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#pragma once +#include +#include + +#include +#include + +namespace AppInstaller::Logging +{ + // Log ETW events for tracing. + // Doesn't save events to a file on disk. + struct TraceLogger : ILogger + { + TraceLogger() = default; + + ~TraceLogger() = default; + + // ILogger + virtual std::string GetName() const override; + virtual void Write(Channel channel, Level, std::string_view message) noexcept override; + }; +} diff --git a/src/AppInstallerCommonCore/Public/ThreadGlobals.h b/src/AppInstallerCommonCore/Public/ThreadGlobals.h new file mode 100644 index 0000000000..139a2ddeb6 --- /dev/null +++ b/src/AppInstallerCommonCore/Public/ThreadGlobals.h @@ -0,0 +1,37 @@ +#pragma once + +#include +#include +#include + +namespace AppInstaller::ThreadLocalStorage +{ + using namespace AppInstaller::Logging; + + struct ThreadGlobals + { + ThreadGlobals() = default; + ~ThreadGlobals() = default; + + DiagnosticLogger& GetDiagnosticLogger(); + + TelemetryTraceLogger& GetTelemetryLogger(); + + // Set Globals for Current Thread + void SetForCurrentThread(); + + // Return Globals for Current Thread + static ThreadGlobals* GetForCurrentThread(); + + private: + + // Set and return Globals for Current Thread + static ThreadGlobals* ActivateThreadGlobals(ThreadGlobals* pThreadGlobals = nullptr); + + std::unique_ptr m_pDiagnosticLogger; + std::unique_ptr m_pTelemetryLogger; + std::once_flag diagLoggerInitOnceFlag; + std::once_flag telLoggerInitOnceFlag; + }; +} + diff --git a/src/AppInstallerCommonCore/Public/TraceLogger.cpp b/src/AppInstallerCommonCore/Public/TraceLogger.cpp new file mode 100644 index 0000000000..9e3f32860d --- /dev/null +++ b/src/AppInstallerCommonCore/Public/TraceLogger.cpp @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#include "pch.h" +#include "Public/AppInstallerTraceLogger.h" +#include "Public/ThreadGlobals.h" + +namespace AppInstaller::Logging +{ + void TraceLogger::Write(Channel channel, Level, std::string_view message) noexcept try + { + // Send to a string first to create a single block to write to a file. + std::stringstream strstr; + strstr << std::chrono::system_clock::now() << " [" << std::setw(GetMaxChannelNameLength()) << std::left << std::setfill(' ') << GetChannelName(channel) << "] " << message << std::endl; + + using namespace AppInstaller::ThreadLocalStorage; + + TraceLoggingWriteActivity(g_hTraceProvider, + "Diagnostics", + ThreadGlobals::GetForCurrentThread()->GetTelemetryLogger().GetActivityId(), + nullptr, + TraceLoggingString(strstr.str().c_str(), "LogMessage")); + } + catch (...) + { + // Just eat any exceptions here; better to lose logs than functionality + } + + std::string TraceLogger::GetName() const + { + return "TraceLogger"; + } +} diff --git a/src/AppInstallerCommonCore/Telemetry/TraceLogging.cpp b/src/AppInstallerCommonCore/Telemetry/TraceLogging.cpp index 06ce64dff2..8bba41763e 100644 --- a/src/AppInstallerCommonCore/Telemetry/TraceLogging.cpp +++ b/src/AppInstallerCommonCore/Telemetry/TraceLogging.cpp @@ -3,10 +3,11 @@ #include "pch.h" #include "TraceLogging.h" +#include "AppInstallerLogging.h" // GUID for Microsoft.PackageManager.Client : {c0cf606f-569b-5c20-27d9-88a745fa2175} TRACELOGGING_DEFINE_PROVIDER( - g_hTelemetryProvider, + g_hTraceProvider, "Microsoft.PackageManager.Client", (0xc0cf606f, 0x569b, 0x5c20, 0x27, 0xd9, 0x88, 0xa7, 0x45, 0xfa, 0x21, 0x75), TraceLoggingOptionMicrosoftTelemetry()); @@ -14,7 +15,7 @@ TRACELOGGING_DEFINE_PROVIDER( bool g_IsTelemetryProviderEnabled{}; UCHAR g_TelemetryProviderLevel{}; ULONGLONG g_TelemetryProviderMatchAnyKeyword{}; -GUID g_TelemetryProviderActivityId{}; +std::once_flag g_registerTraceProvideOnlyOnce{}; void WINAPI TelemetryProviderEnabledCallback( _In_ LPCGUID /*sourceId*/, @@ -32,27 +33,22 @@ void WINAPI TelemetryProviderEnabledCallback( void RegisterTraceLogging() { - HRESULT hr = S_OK; - - TraceLoggingRegisterEx(g_hTelemetryProvider, TelemetryProviderEnabledCallback, nullptr); - //Generate the ActivityId used to track the session - hr = CoCreateGuid(&g_TelemetryProviderActivityId); - if (FAILED(hr)) + try { - TraceLoggingWriteActivity( - g_hTelemetryProvider, - "CreateGuidError", - nullptr, - nullptr, - TraceLoggingHResult(hr), - TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance), - TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)); - - g_TelemetryProviderActivityId = GUID_NULL; - }; + std::call_once(g_registerTraceProvideOnlyOnce, []() + { + TraceLoggingRegisterEx(g_hTraceProvider, TelemetryProviderEnabledCallback, nullptr); + }); + } + catch (std::exception ex) + { + // May throw std::system_error if any condition prevents calls to call_once from executing as specified + // Loggers are best effort and shouldn't block core functionality. So eat up the exceptions here + AICLI_LOG(Log, Error, << "Exception caught when registering Trace Logging provider: " << ex.what() << '\n'); + } } void UnRegisterTraceLogging() { - TraceLoggingUnregister(g_hTelemetryProvider); + TraceLoggingUnregister(g_hTraceProvider); } diff --git a/src/AppInstallerCommonCore/Telemetry/TraceLogging.h b/src/AppInstallerCommonCore/Telemetry/TraceLogging.h index b9d8337da4..b96787e426 100644 --- a/src/AppInstallerCommonCore/Telemetry/TraceLogging.h +++ b/src/AppInstallerCommonCore/Telemetry/TraceLogging.h @@ -5,6 +5,7 @@ #include "WinEventLogLevels.h" #include +#include #include "MicrosoftTelemetry.h" @@ -60,11 +61,12 @@ // TraceLogging provider name for telemetry. #define TELEMETRY_PROVIDER_NAME "Microsoft.PackageManager.Client" -TRACELOGGING_DECLARE_PROVIDER(g_hTelemetryProvider); +TRACELOGGING_DECLARE_PROVIDER(g_hTraceProvider); extern bool g_IsTelemetryProviderEnabled; extern UCHAR g_TelemetryProviderLevel; extern ULONGLONG g_TelemetryProviderMatchAnyKeyword; extern GUID g_TelemetryProviderActivityId; +extern std::once_flag g_registerTraceProvideOnlyOnce; extern void RegisterTraceLogging(); extern void UnRegisterTraceLogging(); diff --git a/src/AppInstallerCommonCore/ThreadGlobals.cpp b/src/AppInstallerCommonCore/ThreadGlobals.cpp new file mode 100644 index 0000000000..348756692c --- /dev/null +++ b/src/AppInstallerCommonCore/ThreadGlobals.cpp @@ -0,0 +1,55 @@ +#include "pch.h" +#include "Public/ThreadGlobals.h" + +namespace AppInstaller::ThreadLocalStorage +{ + DiagnosticLogger& ThreadGlobals::GetDiagnosticLogger() + { + if (!m_pDiagnosticLogger) + { + try + { + std::call_once(diagLoggerInitOnceFlag, [this]() + { + m_pDiagnosticLogger = std::make_unique(); + }); + } + catch (std::exception& ex) + { + // May throw std::system_error if any condition prevents calls to call_once from executing as specified + // May throw std::bad_alloc or any exception thrown by the constructor of TelemetryTraceLogger + // Loggers are best effort and shouldn't block core functionality. So eat up the exceptions here + AICLI_LOG(Log, Error, << "Exception caught when creating DIAGNOSTIC Trace logger: " << ex.what() << '\n'); + } + } + return *(m_pDiagnosticLogger.get()); + } + + TelemetryTraceLogger& ThreadGlobals::GetTelemetryLogger() + { + return *(m_pTelemetryLogger.get()); + } + + void ThreadGlobals::SetForCurrentThread() + { + try + { + m_pTelemetryLogger = std::make_unique(); + } + catch (std::exception& ex) + { + // May throw std::bad_alloc or any exception thrown by the constructor of TelemetryTraceLogger + // Loggers are best effort and shouldn't block core functionality. So eat up the exceptions here + AICLI_LOG(Log, Error, << "Exception caught when creating TELEMETRY Trace logger: " << ex.what() << '\n'); + } + + ActivateThreadGlobals(this); + + m_pTelemetryLogger->SetUserSettingsStatus(); + } + + ThreadGlobals* ThreadGlobals::GetForCurrentThread() + { + return ActivateThreadGlobals(); + } +} diff --git a/src/AppInstallerRepositoryCore/SQLiteWrapper.cpp b/src/AppInstallerRepositoryCore/SQLiteWrapper.cpp index 533c7858c5..6c07eef373 100644 --- a/src/AppInstallerRepositoryCore/SQLiteWrapper.cpp +++ b/src/AppInstallerRepositoryCore/SQLiteWrapper.cpp @@ -126,7 +126,10 @@ namespace AppInstaller::Repository::SQLite { AICLI_LOG(SQL, Info, << "Opening SQLite connection: '" << target << "' [" << std::hex << static_cast(disposition) << ", " << std::hex << static_cast(flags) << "]"); int resultingFlags = static_cast(disposition) | static_cast(flags); - THROW_IF_SQLITE_FAILED(sqlite3_open_v2(target.c_str(), &m_dbconn, resultingFlags, nullptr)); + if (sqlite3_open_v2(target.c_str(), &m_dbconn, resultingFlags, nullptr) != SQLITE_OK) + { + THROW_SQLITE(sqlite3_extended_errcode(m_dbconn.get())); + } } Connection Connection::Create(const std::string& target, OpenDisposition disposition, OpenFlags flags) diff --git a/src/WinGetUtil/ActivateThreadGlobals.cpp b/src/WinGetUtil/ActivateThreadGlobals.cpp new file mode 100644 index 0000000000..37eba2131a --- /dev/null +++ b/src/WinGetUtil/ActivateThreadGlobals.cpp @@ -0,0 +1,23 @@ +#include "pch.h" +#include "Public/ThreadGlobals.h" + +AppInstaller::ThreadLocalStorage::ThreadGlobals g_ThreadGlobals; + +namespace AppInstaller::ThreadLocalStorage +{ + ThreadGlobals* ThreadGlobals::ActivateThreadGlobals(AppInstaller::ThreadLocalStorage::ThreadGlobals*) + { + static AppInstaller::ThreadLocalStorage::ThreadGlobals* t_pThreadGlobals = nullptr; + + if (t_pThreadGlobals == nullptr) + { + t_pThreadGlobals = &g_ThreadGlobals; + } + + // If WinGetUtil were to call Telemetry logger as well, we would need to call SetForCurrentThread() method of ThreadGlobals to Create Telemetry logger object + // As it is currently used by E2ETests, this doesn't seem to call Telemetry logger ever + + + return t_pThreadGlobals; + } +} diff --git a/src/WinGetUtil/Exports.cpp b/src/WinGetUtil/Exports.cpp index 9a4b3706bc..56daf4445d 100644 --- a/src/WinGetUtil/Exports.cpp +++ b/src/WinGetUtil/Exports.cpp @@ -10,6 +10,7 @@ #include #include #include +#include using namespace AppInstaller::Utility; using namespace AppInstaller::Manifest; diff --git a/src/WinGetUtil/WinGetUtil.vcxproj b/src/WinGetUtil/WinGetUtil.vcxproj index 0c7e22051f..b5996ce45d 100644 --- a/src/WinGetUtil/WinGetUtil.vcxproj +++ b/src/WinGetUtil/WinGetUtil.vcxproj @@ -287,6 +287,7 @@ + Create diff --git a/src/WinGetUtil/WinGetUtil.vcxproj.filters b/src/WinGetUtil/WinGetUtil.vcxproj.filters index 529885e975..b1a95b3b15 100644 --- a/src/WinGetUtil/WinGetUtil.vcxproj.filters +++ b/src/WinGetUtil/WinGetUtil.vcxproj.filters @@ -29,6 +29,9 @@ Source Files + + Source Files +