From 2306df7fb8015ffa8434815d9fb1411c120c35a4 Mon Sep 17 00:00:00 2001 From: John McPherson Date: Thu, 14 Nov 2024 11:32:57 -0800 Subject: [PATCH] Add ODS logger and use it during init --- src/AppInstallerCLICore/Core.cpp | 22 ++++++-- .../AppInstallerCommonCore.vcxproj | 2 + .../AppInstallerCommonCore.vcxproj.filters | 6 +++ .../OutputDebugStringLogger.cpp | 50 +++++++++++++++++++ .../Public/winget/OutputDebugStringLogger.h | 29 +++++++++++ 5 files changed, 105 insertions(+), 4 deletions(-) create mode 100644 src/AppInstallerCommonCore/OutputDebugStringLogger.cpp create mode 100644 src/AppInstallerCommonCore/Public/winget/OutputDebugStringLogger.h diff --git a/src/AppInstallerCLICore/Core.cpp b/src/AppInstallerCLICore/Core.cpp index 4f92ce39f9..1b703e1874 100644 --- a/src/AppInstallerCLICore/Core.cpp +++ b/src/AppInstallerCLICore/Core.cpp @@ -9,6 +9,7 @@ #include "Commands/InstallCommand.h" #include "COMContext.h" #include +#include #ifndef AICLI_DISABLE_TEST_HOOKS #include @@ -66,21 +67,34 @@ namespace AppInstaller::CLI init_apartment(); -#ifndef AICLI_DISABLE_TEST_HOOKS +#ifndef AICLI_DISABLE_TEST_HOOKS + // We have to do this here so the auto minidump config initialization gets caught + Logging::OutputDebugStringLogger::Add(); + Logging::Log().EnableChannel(Logging::Channel::All); + Logging::Log().SetLevel(Logging::Level::Verbose); + if (Settings::User().Get()) { Debugging::EnableSelfInitiatedMinidump(); - } + } + + Logging::OutputDebugStringLogger::Remove(); #endif Logging::UseGlobalTelemetryLoggerActivityIdOnly(); Execution::Context context{ std::cout, std::cin }; - auto previousThreadGlobals = context.SetForCurrentThread(); + auto previousThreadGlobals = context.SetForCurrentThread(); + + // Set up debug string logging during initialization + Logging::OutputDebugStringLogger::Add(); + Logging::Log().EnableChannel(Logging::Channel::All); + Logging::Log().SetLevel(Logging::Level::Verbose); Logging::Log().EnableChannel(Settings::User().Get()); Logging::Log().SetLevel(Settings::User().Get()); - Logging::FileLogger::Add(); + Logging::FileLogger::Add(); + Logging::OutputDebugStringLogger::Remove(); Logging::EnableWilFailureTelemetry(); // Set output to UTF8 diff --git a/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj b/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj index 927547fc8f..bfaf4d6669 100644 --- a/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj +++ b/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj @@ -448,6 +448,7 @@ + @@ -504,6 +505,7 @@ + diff --git a/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj.filters b/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj.filters index 1cb64a4d0e..2c5d80bc70 100644 --- a/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj.filters +++ b/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj.filters @@ -207,6 +207,9 @@ Public\winget + + Public\winget + @@ -374,6 +377,9 @@ Source Files + + Source Files + diff --git a/src/AppInstallerCommonCore/OutputDebugStringLogger.cpp b/src/AppInstallerCommonCore/OutputDebugStringLogger.cpp new file mode 100644 index 0000000000..08103bbfd8 --- /dev/null +++ b/src/AppInstallerCommonCore/OutputDebugStringLogger.cpp @@ -0,0 +1,50 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#include "pch.h" +#include "winget/OutputDebugStringLogger.h" + +namespace AppInstaller::Logging +{ + namespace + { + static constexpr std::string_view s_OutputDebugStringLoggerName = "OutputDebugStringLogger"; + } + + std::string OutputDebugStringLogger::GetName() const + { + return std::string{ s_OutputDebugStringLoggerName }; + } + + void OutputDebugStringLogger::Write(Channel channel, Level, std::string_view message) noexcept try + { + std::stringstream strstr; + strstr << "[" << std::setw(GetMaxChannelNameLength()) << std::left << std::setfill(' ') << GetChannelName(channel) << "] " << message << std::endl; + std::string formattedMessage = std::move(strstr).str(); + + OutputDebugStringA(formattedMessage.c_str()); + } + catch (...) + { + // Just eat any exceptions here; better than losing logs + } + + void OutputDebugStringLogger::WriteDirect(Channel, Level, std::string_view message) noexcept try + { + std::string nullTerminatedMessage{ message }; + OutputDebugStringA(nullTerminatedMessage.c_str()); + } + catch (...) + { + // Just eat any exceptions here; better than losing logs + } + + void OutputDebugStringLogger::Add() + { + Log().AddLogger(std::make_unique()); + } + + void OutputDebugStringLogger::Remove() + { + Log().RemoveLogger(std::string{ s_OutputDebugStringLoggerName }); + } +} diff --git a/src/AppInstallerCommonCore/Public/winget/OutputDebugStringLogger.h b/src/AppInstallerCommonCore/Public/winget/OutputDebugStringLogger.h new file mode 100644 index 0000000000..751bf4b1f8 --- /dev/null +++ b/src/AppInstallerCommonCore/Public/winget/OutputDebugStringLogger.h @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#pragma once +#include + +namespace AppInstaller::Logging +{ + // Sends logs to the OutputDebugString function. + // Intended for use during initialization debugging. + struct OutputDebugStringLogger : ILogger + { + OutputDebugStringLogger() = default; + + ~OutputDebugStringLogger() = default; + + // ILogger + std::string GetName() const override; + + void Write(Channel channel, Level, std::string_view message) noexcept override; + + void WriteDirect(Channel channel, Level level, std::string_view message) noexcept override; + + // Adds OutputDebugStringLogger to the current Log + static void Add(); + + // Removes OutputDebugStringLogger from the current Log + static void Remove(); + }; +}