winget-cli

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit b4693b191463df328d21021a17cc2b09b665ef33
parent a14de79013927fab44f529fd2299a99414d3b059
Author: yao-msft <50888816+yao-msft@users.noreply.github.com>
Date:   Tue,  9 Nov 2021 17:27:55 -0800

Prevent circular dependency in global telemetry logger creation (#1674)


Diffstat:
Msrc/AppInstallerCommonCore/AppInstallerTelemetry.cpp | 32++++++++++++++++++++++++++++----
Msrc/AppInstallerCommonCore/Public/AppInstallerTelemetry.h | 18+++++++++++-------
Msrc/AppInstallerCommonCore/Public/winget/ThreadGlobals.h | 3+--
Msrc/AppInstallerCommonCore/Public/winget/UserSettings.h | 6++----
Msrc/AppInstallerCommonCore/ThreadGlobals.cpp | 2+-
Msrc/AppInstallerCommonCore/TraceLogger.cpp | 4++--
Msrc/AppInstallerCommonCore/UserSettings.cpp | 34++++++++++++++++++++++++++++++++--
Msrc/WinGetUtil/Exports.cpp | 10++++++++--
8 files changed, 85 insertions(+), 24 deletions(-)

diff --git a/src/AppInstallerCommonCore/AppInstallerTelemetry.cpp b/src/AppInstallerCommonCore/AppInstallerTelemetry.cpp @@ -80,8 +80,24 @@ namespace AppInstaller::Logging void TelemetryTraceLogger::Initialize() { - m_isSettingEnabled = !Settings::User().Get<Settings::Setting::TelemetryDisable>(); - m_userProfile = Runtime::GetPathTo(Runtime::PathName::UserProfile).wstring(); + if (!m_isInitialized) + { + InitializeInternal(Settings::User()); + } + } + + bool TelemetryTraceLogger::TryInitialize() + { + if (!m_isInitialized) + { + auto userSettings = Settings::TryGetUser(); + if (userSettings) + { + InitializeInternal(*userSettings); + } + } + + return m_isInitialized; } void TelemetryTraceLogger::SetTelemetryCorrelationJson(const std::wstring_view jsonStr_view) noexcept @@ -520,7 +536,14 @@ namespace AppInstaller::Logging bool TelemetryTraceLogger::IsTelemetryEnabled() const noexcept { - return g_IsTelemetryProviderEnabled && m_isSettingEnabled && m_isRuntimeEnabled; + return g_IsTelemetryProviderEnabled && m_isInitialized && m_isSettingEnabled && m_isRuntimeEnabled; + } + + void TelemetryTraceLogger::InitializeInternal(const AppInstaller::Settings::UserSettings& userSettings) + { + m_isSettingEnabled = !userSettings.Get<Settings::Setting::TelemetryDisable>(); + m_userProfile = Runtime::GetPathTo(Runtime::PathName::UserProfile).wstring(); + m_isInitialized = true; } std::wstring TelemetryTraceLogger::AnonymizeString(const wchar_t* input) const noexcept @@ -553,7 +576,8 @@ namespace AppInstaller::Logging } else { - static GlobalTelemetryTraceLogger processGlobalTelemetry; + static TelemetryTraceLogger processGlobalTelemetry; + processGlobalTelemetry.TryInitialize(); return processGlobalTelemetry; } } diff --git a/src/AppInstallerCommonCore/Public/AppInstallerTelemetry.h b/src/AppInstallerCommonCore/Public/AppInstallerTelemetry.h @@ -8,6 +8,11 @@ #include <vector> #include <cguid.h> +namespace AppInstaller::Settings +{ + struct UserSettings; +} + namespace AppInstaller::Logging { // This type contains the registration lifetime of the telemetry trace logging provider. @@ -36,6 +41,9 @@ namespace AppInstaller::Logging // Capture if UserSettings is enabled and set user profile path void Initialize(); + // Try to capture if UserSettings is enabled and set user profile path, returns whether the action is successfully completed. + bool TryInitialize(); + // Store the passed in name of the Caller for COM calls void SetCaller(const std::string& caller); @@ -131,6 +139,8 @@ namespace AppInstaller::Logging protected: bool IsTelemetryEnabled() const noexcept; + void InitializeInternal(const AppInstaller::Settings::UserSettings& userSettings); + // 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(const wchar_t* input) const noexcept; @@ -138,6 +148,7 @@ namespace AppInstaller::Logging bool m_isSettingEnabled = true; std::atomic_bool m_isRuntimeEnabled{ true }; + std::atomic_bool m_isInitialized{ false }; GUID m_activityId = GUID_NULL; std::wstring m_telemetryCorrelationJsonW = L"{}"; @@ -147,13 +158,6 @@ namespace AppInstaller::Logging std::wstring m_userProfile; }; - struct GlobalTelemetryTraceLogger : TelemetryTraceLogger - { - GlobalTelemetryTraceLogger() { Initialize(); } - - ~GlobalTelemetryTraceLogger() = default; - }; - // Helper to make the call sites look clean. TelemetryTraceLogger& Telemetry(); diff --git a/src/AppInstallerCommonCore/Public/winget/ThreadGlobals.h b/src/AppInstallerCommonCore/Public/winget/ThreadGlobals.h @@ -26,13 +26,12 @@ namespace AppInstaller::ThreadLocalStorage static ThreadGlobals* GetForCurrentThread(); private: - + void Initialize(); std::unique_ptr<AppInstaller::Logging::DiagnosticLogger> m_pDiagnosticLogger; std::unique_ptr<AppInstaller::Logging::TelemetryTraceLogger> m_pTelemetryLogger; std::once_flag loggerInitOnceFlag; - }; struct PreviousThreadGlobals diff --git a/src/AppInstallerCommonCore/Public/winget/UserSettings.h b/src/AppInstallerCommonCore/Public/winget/UserSettings.h @@ -188,8 +188,6 @@ namespace AppInstaller::Settings ~UserSettings() = default; }; - inline UserSettings const& User() - { - return UserSettings::Instance(); - } + const UserSettings* TryGetUser(); + UserSettings const& User(); } diff --git a/src/AppInstallerCommonCore/ThreadGlobals.cpp b/src/AppInstallerCommonCore/ThreadGlobals.cpp @@ -35,7 +35,7 @@ namespace AppInstaller::ThreadLocalStorage { m_pDiagnosticLogger = std::make_unique<DiagnosticLogger>(); m_pTelemetryLogger = std::make_unique<TelemetryTraceLogger>(); - + // The above make_unique for TelemetryTraceLogger will either create an object or will throw which is caught below. m_pTelemetryLogger->Initialize(); }); diff --git a/src/AppInstallerCommonCore/TraceLogger.cpp b/src/AppInstallerCommonCore/TraceLogger.cpp @@ -15,7 +15,7 @@ namespace AppInstaller::Logging TraceLoggingWriteActivity(g_hTraceProvider, "Diagnostics", - nullptr, // TODO: ActivityId of the Global and COMContext telemetry to be logged in future + Telemetry().GetActivityId(), nullptr, TraceLoggingString(strstr.str().c_str(), "LogMessage")); } @@ -28,7 +28,7 @@ namespace AppInstaller::Logging { TraceLoggingWriteActivity(g_hTraceProvider, "Diagnostics", - nullptr, // TODO: ActivityId of the Global and COMContext telemetry to be logged in future + Telemetry().GetActivityId(), nullptr, TraceLoggingCountedUtf8String(message.data(), static_cast<ULONG>(message.size()), "LogMessage")); } diff --git a/src/AppInstallerCommonCore/UserSettings.cpp b/src/AppInstallerCommonCore/UserSettings.cpp @@ -305,20 +305,50 @@ namespace AppInstaller::Settings } #endif + static std::atomic_bool s_userSettingsInitialized{ false }; + static std::atomic_bool s_userSettingsInInitialization{ false }; + UserSettings const& UserSettings::Instance() { - static UserSettings userSettings; - #ifndef AICLI_DISABLE_TEST_HOOKS if (s_UserSettings_Override) { return *s_UserSettings_Override; } #endif + if (!s_userSettingsInitialized) + { + s_userSettingsInInitialization = true; + } + + static UserSettings userSettings; + s_userSettingsInitialized = true; + s_userSettingsInInitialization = false; return userSettings; } + const UserSettings* TryGetUser() + { + if (s_userSettingsInitialized) + { + return &UserSettings::Instance(); + } + + // Try to initialize UserSettings, return nullptr if it's already in initialization. + if (s_userSettingsInInitialization) + { + return nullptr; + } + + return &UserSettings::Instance(); + } + + UserSettings const& User() + { + return UserSettings::Instance(); + } + UserSettings::UserSettings() : m_type(UserSettingsType::Default) { Json::Value settingsRoot = Json::Value::nullSingleton(); diff --git a/src/WinGetUtil/Exports.cpp b/src/WinGetUtil/Exports.cpp @@ -10,6 +10,7 @@ #include <AppInstallerTelemetry.h> #include <Microsoft/SQLiteIndex.h> #include <winget/ManifestYamlParser.h> +#include <winget/ThreadGlobals.h> using namespace AppInstaller::Utility; using namespace AppInstaller::Manifest; @@ -21,8 +22,13 @@ extern "C" { THROW_HR_IF(E_INVALIDARG, !logPath); - static std::once_flag s_initLogging; - std::call_once(s_initLogging, []() { + thread_local AppInstaller::ThreadLocalStorage::ThreadGlobals threadGlobals; + thread_local std::once_flag initLogging; + + std::call_once(initLogging, []() { + std::unique_ptr<AppInstaller::ThreadLocalStorage::PreviousThreadGlobals> previous = threadGlobals.SetForCurrentThread(); + // Intentionally release to leave the local ThreadGlobals. + previous.release(); // Enable all logs for now. AppInstaller::Logging::Log().EnableChannel(AppInstaller::Logging::Channel::All); AppInstaller::Logging::Log().SetLevel(AppInstaller::Logging::Level::Verbose);