Skip to content

Commit 25ccc2a

Browse files
authored
Add ODS logger and use it during init (#4969)
## Change The user settings (and then group policy) initialization happen before we get the file logger set up. To be able to see into what is happening there more easily, this change creates a logger that uses `OutputDebugString` and uses it during the initial file logger creation.
1 parent 03df824 commit 25ccc2a

File tree

6 files changed

+131
-8
lines changed

6 files changed

+131
-8
lines changed

src/AppInstallerCLICore/COMContext.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "COMContext.h"
55
#include <AppInstallerFileLogger.h>
66
#include <winget/TraceLogger.h>
7+
#include <winget/OutputDebugStringLogger.h>
78

89
namespace AppInstaller::CLI::Execution
910
{
@@ -77,12 +78,19 @@ namespace AppInstaller::CLI::Execution
7778

7879
void COMContext::SetLoggers(std::optional<AppInstaller::Logging::Channel> channel, std::optional<AppInstaller::Logging::Level> level)
7980
{
81+
// Set up debug string logging during initialization
82+
Logging::OutputDebugStringLogger::Add();
83+
Logging::Log().EnableChannel(Logging::Channel::All);
84+
Logging::Log().SetLevel(Logging::Level::Verbose);
85+
8086
Logging::Log().EnableChannel(channel.has_value() ? channel.value() : Settings::User().Get<Settings::Setting::LoggingChannelPreference>());
8187
Logging::Log().SetLevel(level.has_value() ? level.value() : Settings::User().Get<Settings::Setting::LoggingLevelPreference>());
8288

8389
// TODO: Log to file for COM API calls only when debugging in visual studio
8490
Logging::FileLogger::Add(s_comLogFileNamePrefix);
8591

92+
Logging::OutputDebugStringLogger::Remove();
93+
8694
#ifndef AICLI_DISABLE_TEST_HOOKS
8795
if (!Settings::User().Get<Settings::Setting::KeepAllLogFiles>())
8896
#endif

src/AppInstallerCLICore/Core.cpp

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "Commands/InstallCommand.h"
1010
#include "COMContext.h"
1111
#include <AppInstallerFileLogger.h>
12+
#include <winget/OutputDebugStringLogger.h>
1213

1314
#ifndef AICLI_DISABLE_TEST_HOOKS
1415
#include <winget/Debugging.h>
@@ -66,21 +67,34 @@ namespace AppInstaller::CLI
6667

6768
init_apartment();
6869

69-
#ifndef AICLI_DISABLE_TEST_HOOKS
70+
#ifndef AICLI_DISABLE_TEST_HOOKS
71+
// We have to do this here so the auto minidump config initialization gets caught
72+
Logging::OutputDebugStringLogger::Add();
73+
Logging::Log().EnableChannel(Logging::Channel::All);
74+
Logging::Log().SetLevel(Logging::Level::Verbose);
75+
7076
if (Settings::User().Get<Settings::Setting::EnableSelfInitiatedMinidump>())
7177
{
7278
Debugging::EnableSelfInitiatedMinidump();
73-
}
79+
}
80+
81+
Logging::OutputDebugStringLogger::Remove();
7482
#endif
7583

7684
Logging::UseGlobalTelemetryLoggerActivityIdOnly();
7785

7886
Execution::Context context{ std::cout, std::cin };
79-
auto previousThreadGlobals = context.SetForCurrentThread();
87+
auto previousThreadGlobals = context.SetForCurrentThread();
88+
89+
// Set up debug string logging during initialization
90+
Logging::OutputDebugStringLogger::Add();
91+
Logging::Log().EnableChannel(Logging::Channel::All);
92+
Logging::Log().SetLevel(Logging::Level::Verbose);
8093

8194
Logging::Log().EnableChannel(Settings::User().Get<Settings::Setting::LoggingChannelPreference>());
8295
Logging::Log().SetLevel(Settings::User().Get<Settings::Setting::LoggingLevelPreference>());
83-
Logging::FileLogger::Add();
96+
Logging::FileLogger::Add();
97+
Logging::OutputDebugStringLogger::Remove();
8498
Logging::EnableWilFailureTelemetry();
8599

86100
// Set output to UTF8
@@ -171,23 +185,37 @@ namespace AppInstaller::CLI
171185

172186
void ServerInitialize()
173187
{
174-
#ifndef AICLI_DISABLE_TEST_HOOKS
188+
#ifndef AICLI_DISABLE_TEST_HOOKS
189+
// We have to do this here so the auto minidump config initialization gets caught
190+
Logging::OutputDebugStringLogger::Add();
191+
Logging::Log().EnableChannel(Logging::Channel::All);
192+
Logging::Log().SetLevel(Logging::Level::Verbose);
193+
175194
if (Settings::User().Get<Settings::Setting::EnableSelfInitiatedMinidump>())
176195
{
177196
Debugging::EnableSelfInitiatedMinidump();
178-
}
197+
}
198+
199+
Logging::OutputDebugStringLogger::Remove();
179200
#endif
180201

181202
AppInstaller::CLI::Execution::COMContext::SetLoggers();
182203
}
183204

184205
void InProcInitialize()
185206
{
186-
#ifndef AICLI_DISABLE_TEST_HOOKS
207+
#ifndef AICLI_DISABLE_TEST_HOOKS
208+
// We have to do this here so the auto minidump config initialization gets caught
209+
Logging::OutputDebugStringLogger::Add();
210+
Logging::Log().EnableChannel(Logging::Channel::All);
211+
Logging::Log().SetLevel(Logging::Level::Verbose);
212+
187213
if (Settings::User().Get<Settings::Setting::EnableSelfInitiatedMinidump>())
188214
{
189215
Debugging::EnableSelfInitiatedMinidump();
190-
}
216+
}
217+
218+
Logging::OutputDebugStringLogger::Remove();
191219
#endif
192220

193221
// Explicitly set default channel and level before user settings from PackageManagerSettings

src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,7 @@
448448
</ClInclude>
449449
<ClInclude Include="Public\winget\NameNormalization.h" />
450450
<ClInclude Include="Public\winget\NetworkSettings.h" />
451+
<ClInclude Include="Public\winget\OutputDebugStringLogger.h" />
451452
<ClInclude Include="Public\winget\PackageDependenciesValidationUtil.h" />
452453
<ClInclude Include="Public\winget\PackageVersionDataManifest.h" />
453454
<ClInclude Include="Public\winget\Pin.h" />
@@ -504,6 +505,7 @@
504505
</ClCompile>
505506
<ClCompile Include="NameNormalization.cpp" />
506507
<ClCompile Include="NetworkSettings.cpp" />
508+
<ClCompile Include="OutputDebugStringLogger.cpp" />
507509
<ClCompile Include="PackageDependenciesValidationUtil.cpp" />
508510
<ClCompile Include="PackageVersionDataManifest.cpp" />
509511
<ClCompile Include="Pin.cpp" />

src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj.filters

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,9 @@
207207
<ClInclude Include="Public\winget\Fonts.h">
208208
<Filter>Public\winget</Filter>
209209
</ClInclude>
210+
<ClInclude Include="Public\winget\OutputDebugStringLogger.h">
211+
<Filter>Public\winget</Filter>
212+
</ClInclude>
210213
</ItemGroup>
211214
<ItemGroup>
212215
<ClCompile Include="pch.cpp">
@@ -374,6 +377,9 @@
374377
<ClCompile Include="Fonts.cpp">
375378
<Filter>Source Files</Filter>
376379
</ClCompile>
380+
<ClCompile Include="OutputDebugStringLogger.cpp">
381+
<Filter>Source Files</Filter>
382+
</ClCompile>
377383
</ItemGroup>
378384
<ItemGroup>
379385
<None Include="PropertySheet.props" />
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
#include "pch.h"
4+
#include "winget/OutputDebugStringLogger.h"
5+
6+
namespace AppInstaller::Logging
7+
{
8+
namespace
9+
{
10+
static constexpr std::string_view s_OutputDebugStringLoggerName = "OutputDebugStringLogger";
11+
}
12+
13+
std::string OutputDebugStringLogger::GetName() const
14+
{
15+
return std::string{ s_OutputDebugStringLoggerName };
16+
}
17+
18+
void OutputDebugStringLogger::Write(Channel channel, Level, std::string_view message) noexcept try
19+
{
20+
std::stringstream strstr;
21+
strstr << "[" << std::setw(GetMaxChannelNameLength()) << std::left << std::setfill(' ') << GetChannelName(channel) << "] " << message << std::endl;
22+
std::string formattedMessage = std::move(strstr).str();
23+
24+
OutputDebugStringA(formattedMessage.c_str());
25+
}
26+
catch (...)
27+
{
28+
// Just eat any exceptions here; better than losing logs
29+
}
30+
31+
void OutputDebugStringLogger::WriteDirect(Channel, Level, std::string_view message) noexcept try
32+
{
33+
std::string nullTerminatedMessage{ message };
34+
OutputDebugStringA(nullTerminatedMessage.c_str());
35+
}
36+
catch (...)
37+
{
38+
// Just eat any exceptions here; better than losing logs
39+
}
40+
41+
void OutputDebugStringLogger::Add()
42+
{
43+
Log().AddLogger(std::make_unique<OutputDebugStringLogger>());
44+
}
45+
46+
void OutputDebugStringLogger::Remove()
47+
{
48+
Log().RemoveLogger(std::string{ s_OutputDebugStringLoggerName });
49+
}
50+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
#pragma once
4+
#include <AppInstallerLogging.h>
5+
6+
namespace AppInstaller::Logging
7+
{
8+
// Sends logs to the OutputDebugString function.
9+
// Intended for use during initialization debugging.
10+
struct OutputDebugStringLogger : ILogger
11+
{
12+
OutputDebugStringLogger() = default;
13+
14+
~OutputDebugStringLogger() = default;
15+
16+
// ILogger
17+
std::string GetName() const override;
18+
19+
void Write(Channel channel, Level, std::string_view message) noexcept override;
20+
21+
void WriteDirect(Channel channel, Level level, std::string_view message) noexcept override;
22+
23+
// Adds OutputDebugStringLogger to the current Log
24+
static void Add();
25+
26+
// Removes OutputDebugStringLogger from the current Log
27+
static void Remove();
28+
};
29+
}

0 commit comments

Comments
 (0)