Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert global loggers to Thread local loggers #3

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open
13 changes: 13 additions & 0 deletions src/AppInstallerCLICore/COMContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,17 @@ namespace AppInstaller
m_executionStage = executionStage;
m_comProgressCallback(ReportType::ExecutionPhaseUpdate, 0, 0, ProgressType::None, m_executionStage);
}

void COMContext::SetLoggers(std::wstring telemetryCorelationJson, std::wstring comCaller)
{
Logging::Log().SetLevel(Logging::Level::Verbose);

Logging::Telemetry().EnableWilFailureTelemetry();
Logging::Telemetry().SetTelemetryCorelationJson(telemetryCorelationJson);
Logging::Telemetry().SetCOMCaller(comCaller);

Logging::Telemetry().SetUserSettingsStatus();

Logging::Telemetry().LogStartup(true);
}
}
3 changes: 3 additions & 0 deletions src/AppInstallerCLICore/COMContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ namespace AppInstaller
}

private:

void SetLoggers(std::wstring telemetryCorelationJson, std::wstring comCaller);

CLI::Workflow::ExecutionStage m_executionStage = CLI::Workflow::ExecutionStage::Initial;
ProgressCallBackFunction m_comProgressCallback;
};
Expand Down
2 changes: 1 addition & 1 deletion src/AppInstallerCLICore/Commands/CompleteCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ namespace AppInstaller::CLI
}
catch (const CommandException& ce)
{
AICLI_LOG(CLI, Info, << "Error encountered during completion, ignoring: " << ce.Message());
AICLI_LOG(CLI, Info, << "Error encountered during completion, ignoring: " << ce.Message().get());
}
catch (...)
{
Expand Down
11 changes: 6 additions & 5 deletions src/AppInstallerCLICore/Core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,15 @@ 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
Logging::Log().EnableChannel(Logging::Channel::All);
Logging::Log().SetLevel(Logging::Level::Verbose);
Logging::AddFileLogger();
Logging::EnableWilFailureTelemetry();
Logging::Telemetry().EnableWilFailureTelemetry();
Logging::Telemetry().SetUserSettingsStatus();

// Set output to UTF8
ConsoleOutputCPRestore utf8CP(CP_UTF8);
Expand All @@ -60,9 +64,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
Expand Down Expand Up @@ -112,7 +113,7 @@ namespace AppInstaller::CLI
catch (const CommandException& ce)
{
command->OutputHelp(context.Reporter, &ce);
AICLI_LOG(CLI, Error, << "Error encountered parsing command line: " << ce.Message());
AICLI_LOG(CLI, Error, << "Error encountered parsing command line: " << ce.Message().get());
return APPINSTALLER_CLI_ERROR_INVALID_CL_ARGUMENTS;
}

Expand Down
5 changes: 5 additions & 0 deletions src/AppInstallerCLICore/ExecutionContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,4 +140,9 @@ namespace AppInstaller::CLI::Execution

m_executionStage = stage;
}

void Context::SetThreadLocalThreadGlobals()
{
t_pThreadGlobals = &m_threadGlobals;
}
}
8 changes: 7 additions & 1 deletion src/AppInstallerCLICore/ExecutionContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,10 @@ namespace AppInstaller::CLI::Execution
// arguments via Execution::Args.
struct Context : EnumBasedVariantMap<Data, details::DataMapping>
{
Context(std::ostream& out, std::istream& in) : Reporter(out, in) {}
Context(std::ostream& out, std::istream& in) : Reporter(out, in)
{
t_pThreadGlobals = &m_threadGlobals;
}

// Clone the reporter for this constructor.
Context(Execution::Reporter& reporter) : Reporter(reporter, Execution::Reporter::clone_t{}) {}
Expand Down Expand Up @@ -102,6 +105,8 @@ namespace AppInstaller::CLI::Execution
}

virtual void SetExecutionStage(Workflow::ExecutionStage stage, bool);

void SetThreadLocalThreadGlobals();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will need to return the internal RAII type that ThreadGlobals will return from its SetActive type function.


#ifndef AICLI_DISABLE_TEST_HOOKS
// Enable tests to override behavior
Expand All @@ -115,5 +120,6 @@ namespace AppInstaller::CLI::Execution
size_t m_CtrlSignalCount = 0;
ContextFlag m_flags = ContextFlag::None;
Workflow::ExecutionStage m_executionStage = Workflow::ExecutionStage::Initial;
AppInstaller::Logging::ThreadGlobals m_threadGlobals;
};
}
3 changes: 2 additions & 1 deletion src/AppInstallerCLITests/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,8 @@ int main(int argc, char** argv)
Logging::Log().DisableChannel(Logging::Channel::SQL);
}
Logging::Log().SetLevel(Logging::Level::Verbose);
Logging::EnableWilFailureTelemetry();
Logging::Telemetry().EnableWilFailureTelemetry();
AppInstaller::Logging::Telemetry().SetUserSettingsStatus();

// Force all tests to run against settings inside this container.
// This prevents test runs from trashing the users actual settings.
Expand Down
88 changes: 84 additions & 4 deletions src/AppInstallerCommonCore/AppInstallerLogging.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
#include "Public/AppInstallerDateTime.h"
#include "Public/AppInstallerRuntime.h"

thread_local AppInstaller::Logging::ThreadGlobals* t_pThreadGlobals = nullptr;

namespace AppInstaller::Logging
{
namespace
Expand Down Expand Up @@ -48,10 +50,17 @@ namespace AppInstaller::Logging

size_t GetMaxChannelNameLength() { return 4; }

DiagnosticLogger& DiagnosticLogger::GetInstance()
void TraceLogger::LogMessage(std::string str) noexcept try
{
TraceLoggingWriteActivity(g_hTraceProvider,
"Diagnostics",
t_pThreadGlobals->GetTelemetryLogger().GetActivityId(),
nullptr,
TraceLoggingString(str.c_str(), "LogMessage"));
}
catch (...)
{
static DiagnosticLogger instance;
return instance;
// Just eat any exceptions here; better to lose logs than functionality
}

void DiagnosticLogger::AddLogger(std::unique_ptr<ILogger>&& logger)
Expand Down Expand Up @@ -120,13 +129,18 @@ namespace AppInstaller::Logging
{
THROW_HR_IF_MSG(E_INVALIDARG, channel == Channel::All, "Cannot write to all channels");

// 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;

if (IsEnabled(channel, level))
{
for (auto& logger : m_loggers)
{
logger->Write(channel, level, message);
logger->Write(strstr.str());
}
}
traceLogger.LogMessage(strstr.str());
}

void AddFileLogger(const std::filesystem::path& filePath)
Expand All @@ -143,6 +157,72 @@ namespace AppInstaller::Logging
{
return out << std::hex << std::setw(8) << std::setfill('0');
}

DiagnosticLogger& ThreadGlobals::GetDiagnosticLogger()
{
if (!m_pDiagnosticLogger)
{
try
{
std::call_once(diagLoggerInitOnceFlag, [this]()
{
InitDiagnosticLogger();
});
}
catch (...)
{
// 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
}
}
return *(m_pDiagnosticLogger.get());
}

void ThreadGlobals::InitDiagnosticLogger()
{
try
{
m_pDiagnosticLogger = std::make_unique<DiagnosticLogger>();
}
catch (...)
{
// May throw std::bad_alloc or any exception thrown by the constructor of DiagnosticLogger
// Loggers are best effort and shouldn't block core functionality. So eat up the exceptions here
}
}

TelemetryTraceLogger& ThreadGlobals::GetTelemetryLogger()
{
if (!m_pTelemetryLogger)
{
try
{
std::call_once(telLoggerInitOnceFlag, [this]()
{
InitTelemetryLogger();
});
}
catch (...)
{
// 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
}
}
return *(m_pTelemetryLogger.get());
}

void ThreadGlobals::InitTelemetryLogger()
{
try
{
m_pTelemetryLogger = std::make_unique<TelemetryTraceLogger>();
}
catch (...)
{
// 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
}
}
}

std::ostream& operator<<(std::ostream& out, const std::chrono::system_clock::time_point& time)
Expand Down
Loading