winget-cli

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

Telemetry.cpp (16794B)


      1 // Copyright (c) Microsoft Corporation.
      2 // Licensed under the MIT License.
      3 #include "pch.h"
      4 #include "Telemetry.h"
      5 #include "TraceLogging.h"
      6 #include <AppInstallerErrors.h>
      7 #include <AppInstallerLogging.h>
      8 #include <AppInstallerStrings.h>
      9 #include <winget/Runtime.h>
     10 
     11 #define AICLI_TraceLoggingStringView(_sv_,_name_) TraceLoggingCountedUtf8String(_sv_.data(), static_cast<ULONG>(_sv_.size()), _name_)
     12 #define AICLI_TraceLoggingWStringView(_sv_,_name_) TraceLoggingCountedWideString(_sv_.data(), static_cast<ULONG>(_sv_.size()), _name_)
     13 
     14 #define AICLI_TraceLoggingProcessingSummaryForIntent(_forIntent_,_name_,_pluralName_) \
     15     TraceLoggingUInt32(_forIntent_.Count, _name_ ## "Count"), \
     16     TraceLoggingUInt32(_forIntent_.Run, _pluralName_ ## "Run"), \
     17     TraceLoggingUInt32(_forIntent_.Failed, _pluralName_ ## "Failed")
     18 
     19 #define AICLI_TraceLoggingWriteActivity(_eventName_,...) TraceLoggingWriteActivity(\
     20 g_hTraceProvider,\
     21 _eventName_,\
     22 GetActivityId(),\
     23 nullptr,\
     24 TraceLoggingCountedUtf8String(m_version.c_str(),  static_cast<ULONG>(m_version.size()), "CodeVersion"),\
     25 TraceLoggingCountedUtf8String(m_caller.c_str(),  static_cast<ULONG>(m_caller.size()), "Caller"),\
     26 __VA_ARGS__)
     27 
     28 #ifdef AICLI_DISABLE_TEST_HOOKS
     29 
     30 #define WinGet_EventItem(_value_,_name_) 
     31 #define WinGet_SummaryForIntentItem(_forIntent_,_name_,_pluralName_) 
     32 #define WinGet_WriteEventToDiagnostics(_eventName_,...) 
     33 
     34 #else
     35 
     36 struct WinGetAbsorbVA_ARGSCommas
     37 {
     38     WinGetAbsorbVA_ARGSCommas(int, int) {}
     39 };
     40 
     41 inline std::ostream& operator<<(std::ostream& out, const WinGetAbsorbVA_ARGSCommas&) { return out; }
     42 inline std::ostream& operator<<(std::ostream& out, std::wstring_view value) { out << AppInstaller::Utility::ConvertToUTF8(value); return out; }
     43 
     44 #define WinGet_EventItem(_value_,_name_) \
     45     0) << (_name_) << ": " << (_value_) << '\n' << WinGetAbsorbVA_ARGSCommas(0
     46 
     47 #define WinGet_SummaryForIntentItem(_forIntent_,_name_,_pluralName_) \
     48     WinGet_EventItem(_forIntent_.Count, _name_ ## "Count"), \
     49     WinGet_EventItem(_forIntent_.Run, _pluralName_ ## "Run"), \
     50     WinGet_EventItem(_forIntent_.Failed, _pluralName_ ## "Failed")
     51 
     52 #define WinGet_WriteEventToDiagnostics(_eventName_,...) \
     53 { \
     54     std::ostringstream _debugEventStream; \
     55     _debugEventStream << \
     56         "#DebugEventStream\n" << \
     57         "Event: " << (_eventName_) << '\n' << \
     58         "ActivityID: " << *GetActivityId() << '\n' << \
     59         "CodeVersion: " << m_version << '\n' << \
     60         "Caller: " << m_caller << '\n' \
     61         << WinGetAbsorbVA_ARGSCommas(0, __VA_ARGS__ ,0) \
     62         ; \
     63     AICLI_LOG_LARGE_STRING(Config, Verbose, , _debugEventStream.str()); \
     64 }
     65 
     66 #endif
     67 
     68 using namespace std::string_view_literals;
     69 
     70 namespace winrt::Microsoft::Management::Configuration::implementation
     71 {
     72     namespace
     73     {
     74         // The data collected from running through a set of results.
     75         struct ConfigRunSummaryData
     76         {
     77             hresult Result = S_OK;
     78             ConfigurationUnitResultSource FailurePoint = ConfigurationUnitResultSource::None;
     79             TelemetryTraceLogger::ProcessingSummaryForIntent AssertSummary{ ConfigurationUnitIntent::Assert };
     80             TelemetryTraceLogger::ProcessingSummaryForIntent InformSummary{ ConfigurationUnitIntent::Inform };
     81             TelemetryTraceLogger::ProcessingSummaryForIntent ApplySummary{ ConfigurationUnitIntent::Apply };
     82         };
     83 
     84         size_t GetPriority(ConfigurationUnitResultSource source)
     85         {
     86             switch (source)
     87             {
     88             case ConfigurationUnitResultSource::Internal: return 0;
     89             case ConfigurationUnitResultSource::UnitProcessing: return 100;
     90             case ConfigurationUnitResultSource::SystemState: return 200;
     91             case ConfigurationUnitResultSource::ConfigurationSet: return 300;
     92             case ConfigurationUnitResultSource::Precondition: return 400;
     93             default: return 500;
     94             case ConfigurationUnitResultSource::None: return 600;
     95             }
     96         }
     97 
     98         bool FirstHasPriority(ConfigurationUnitResultSource first, ConfigurationUnitResultSource second)
     99         {
    100             return GetPriority(first) < GetPriority(second);
    101         }
    102 
    103         void ProcessUnitResult(const Configuration::ConfigurationUnit unit, const IConfigurationUnitResultInformation& resultInformation, ConfigRunSummaryData& result)
    104         {
    105             hresult resultCode = resultInformation.ResultCode();
    106             if (FAILED(resultCode))
    107             {
    108                 if (result.Result == S_OK || result.Result == resultCode)
    109                 {
    110                     result.Result = resultCode;
    111                 }
    112                 else
    113                 {
    114                     result.Result = WINGET_CONFIG_ERROR_SET_APPLY_FAILED;
    115                 }
    116             }
    117 
    118             ConfigurationUnitResultSource unitFailurePoint = resultInformation.ResultSource();
    119             if (FirstHasPriority(unitFailurePoint, result.FailurePoint))
    120             {
    121                 result.FailurePoint = unitFailurePoint;
    122             }
    123 
    124             TelemetryTraceLogger::ProcessingSummaryForIntent* summaryItem = nullptr;
    125             switch (unit.Intent())
    126             {
    127             case ConfigurationUnitIntent::Assert:
    128                 summaryItem = &result.AssertSummary;
    129                 break;
    130             case ConfigurationUnitIntent::Inform:
    131                 summaryItem = &result.InformSummary;
    132                 break;
    133             case ConfigurationUnitIntent::Apply:
    134             case ConfigurationUnitIntent::Unknown:
    135                 summaryItem = &result.ApplySummary;
    136                 break;
    137             default:
    138                 return;
    139             }
    140 
    141             summaryItem->Count++;
    142 
    143             ConfigurationUnitResultSource resultSource = resultInformation.ResultSource();
    144             if (resultSource != ConfigurationUnitResultSource::Precondition &&
    145                 resultSource != ConfigurationUnitResultSource::ConfigurationSet)
    146             {
    147                 summaryItem->Run++;
    148             }
    149 
    150             if (FAILED(resultCode))
    151             {
    152                 summaryItem->Failed++;
    153             }
    154         }
    155 
    156         // Runs through a set of results, summarizing them.
    157         template <typename Enumerable>
    158         ConfigRunSummaryData ProcessRunResult(const Enumerable& results)
    159         {
    160             ConfigRunSummaryData result;
    161 
    162             for (const auto& item : results)
    163             {
    164                 ProcessUnitResult(item.Unit(), item.ResultInformation(), result);
    165             }
    166 
    167             return result;
    168         }
    169     }
    170 
    171     TelemetryTraceLogger::TelemetryTraceLogger()
    172     {
    173         std::ignore = CoCreateGuid(&m_activityId);
    174         m_version = AppInstaller::Runtime::GetClientVersion();
    175     }
    176 
    177     void TelemetryTraceLogger::SetActivityId(const guid& value)
    178     {
    179         m_activityId = value;
    180     }
    181 
    182     const GUID* TelemetryTraceLogger::GetActivityId() const
    183     {
    184         return &m_activityId;
    185     }
    186 
    187     bool TelemetryTraceLogger::EnableRuntime(bool value)
    188     {
    189         return m_isRuntimeEnabled.exchange(value);
    190     }
    191 
    192     bool TelemetryTraceLogger::IsEnabled() const
    193     {
    194         return m_isRuntimeEnabled;
    195     }
    196 
    197     void TelemetryTraceLogger::SetCaller(std::string_view caller)
    198     {
    199         m_caller = caller;
    200     }
    201 
    202     std::string_view TelemetryTraceLogger::GetCaller() const
    203     {
    204         return m_caller;
    205     }
    206 
    207     void TelemetryTraceLogger::LogConfigUnitRun(
    208         const guid& setIdentifier,
    209         const guid& unitIdentifier,
    210         hstring unitName,
    211         hstring moduleName,
    212         ConfigurationUnitIntent unitIntent,
    213         ConfigurationUnitIntent runIntent,
    214         std::string_view action,
    215         hresult result,
    216         ConfigurationUnitResultSource failurePoint,
    217         std::wstring_view settingNames) const noexcept try
    218     {
    219         // Change unknown to Apply for telemetry, as it will have been treated that way
    220         if (unitIntent == ConfigurationUnitIntent::Unknown)
    221         {
    222             unitIntent = ConfigurationUnitIntent::Apply;
    223         }
    224 
    225         if (IsTelemetryEnabled())
    226         {
    227             AICLI_TraceLoggingWriteActivity(
    228                 "ConfigUnitRun",
    229                 TraceLoggingGuid(setIdentifier, "SetID"),
    230                 TraceLoggingGuid(unitIdentifier, "UnitID"),
    231                 AICLI_TraceLoggingWStringView(unitName, "UnitName"),
    232                 AICLI_TraceLoggingWStringView(moduleName, "ModuleName"),
    233                 TraceLoggingInt32(static_cast<int32_t>(unitIntent), "UnitIntent"),
    234                 TraceLoggingInt32(static_cast<int32_t>(runIntent), "RunIntent"),
    235                 AICLI_TraceLoggingStringView(action, "Action"),
    236                 TraceLoggingHResult(result, "Result"),
    237                 TraceLoggingInt32(static_cast<int32_t>(failurePoint), "FailurePoint"),
    238                 AICLI_TraceLoggingWStringView(settingNames, "SettingsProvided"),
    239                 TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance),
    240                 TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA));
    241 
    242             // Keep in sync with above event!
    243             WinGet_WriteEventToDiagnostics(
    244                 "ConfigUnitRun",
    245                 WinGet_EventItem(setIdentifier, "SetID"),
    246                 WinGet_EventItem(unitIdentifier, "UnitID"),
    247                 WinGet_EventItem(unitName, "UnitName"),
    248                 WinGet_EventItem(moduleName, "ModuleName"),
    249                 WinGet_EventItem(static_cast<int32_t>(unitIntent), "UnitIntent"),
    250                 WinGet_EventItem(static_cast<int32_t>(runIntent), "RunIntent"),
    251                 WinGet_EventItem(action, "Action"),
    252                 WinGet_EventItem(result, "Result"),
    253                 WinGet_EventItem(static_cast<int32_t>(failurePoint), "FailurePoint"),
    254                 WinGet_EventItem(settingNames, "SettingsProvided"));
    255         }
    256     }
    257     CATCH_LOG();
    258 
    259     void TelemetryTraceLogger::LogConfigUnitRunIfAppropriate(
    260         const guid& setIdentifier,
    261         const Configuration::ConfigurationUnit& unit,
    262         ConfigurationUnitIntent runIntent,
    263         std::string_view action,
    264         const IConfigurationUnitResultInformation& resultInformation) const noexcept try
    265     {
    266         if (!IsTelemetryEnabled())
    267         {
    268             return;
    269         }
    270 
    271         // We only want to send telemetry for publicly available units.
    272         IConfigurationUnitProcessorDetails details = unit.Details();
    273         if (!details || !details.IsPublic())
    274         {
    275             return;
    276         }
    277 
    278         // Create a single string from the set of top level setting names, ex. "a|b|c".
    279         const winrt::Windows::Foundation::Collections::ValueSet& settings = unit.Settings();
    280         std::wostringstream strstr;
    281 
    282         for (const auto& setting : settings)
    283         {
    284             strstr << static_cast<std::wstring_view>(setting.Key()) << L'|';
    285         }
    286         std::wstring allSettingsNames = strstr.str();
    287         if (!allSettingsNames.empty())
    288         {
    289             allSettingsNames.pop_back();
    290         }
    291 
    292         LogConfigUnitRun(setIdentifier, unit.InstanceIdentifier(), unit.Type(), details.ModuleName(), unit.Intent(), runIntent, action, resultInformation.ResultCode(), resultInformation.ResultSource(), allSettingsNames);
    293     }
    294     CATCH_LOG();
    295 
    296     void TelemetryTraceLogger::LogConfigProcessingSummary(
    297         const guid& setIdentifier,
    298         std::string_view inputHash,
    299         ConfigurationUnitIntent runIntent,
    300         hresult result,
    301         ConfigurationUnitResultSource failurePoint,
    302         const ProcessingSummaryForIntent& assertSummary,
    303         const ProcessingSummaryForIntent& informSummary,
    304         const ProcessingSummaryForIntent& applySummary) const noexcept try
    305     {
    306         if (IsTelemetryEnabled())
    307         {
    308             AICLI_TraceLoggingWriteActivity(
    309                 "ConfigProcessingSummary",
    310                 TraceLoggingGuid(setIdentifier, "SetID"),
    311                 AICLI_TraceLoggingStringView(inputHash, "InputHash"),
    312                 TraceLoggingBool(false, "FromHistory"), // deprecated
    313                 TraceLoggingInt32(static_cast<int32_t>(runIntent), "RunIntent"),
    314                 TraceLoggingHResult(result, "Result"),
    315                 TraceLoggingInt32(static_cast<int32_t>(failurePoint), "FailurePoint"),
    316                 AICLI_TraceLoggingProcessingSummaryForIntent(assertSummary, "Assert", "Asserts"),
    317                 AICLI_TraceLoggingProcessingSummaryForIntent(informSummary, "Inform", "Informs"),
    318                 AICLI_TraceLoggingProcessingSummaryForIntent(applySummary, "Apply", "Applies"),
    319                 TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance),
    320                 TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA));
    321 
    322             // Keep in sync with above event!
    323             WinGet_WriteEventToDiagnostics(
    324                 "ConfigProcessingSummary",
    325                 WinGet_EventItem(setIdentifier, "SetID"),
    326                 WinGet_EventItem(inputHash, "InputHash"),
    327                 WinGet_EventItem(false, "FromHistory"), // deprecated
    328                 WinGet_EventItem(static_cast<int32_t>(runIntent), "RunIntent"),
    329                 WinGet_EventItem(result, "Result"),
    330                 WinGet_EventItem(static_cast<int32_t>(failurePoint), "FailurePoint"),
    331                 WinGet_SummaryForIntentItem(assertSummary, "Assert", "Asserts"),
    332                 WinGet_SummaryForIntentItem(informSummary, "Inform", "Informs"),
    333                 WinGet_SummaryForIntentItem(applySummary, "Apply", "Applies"));
    334         }
    335     }
    336     CATCH_LOG();
    337 
    338     void TelemetryTraceLogger::LogConfigProcessingSummaryForTest(
    339         const ConfigurationSet& configurationSet,
    340         const TestConfigurationSetResult& result) const noexcept try
    341     {
    342         if (!IsTelemetryEnabled())
    343         {
    344             return;
    345         }
    346 
    347         ConfigRunSummaryData summaryData = ProcessRunResult(result.UnitResults());
    348 
    349         LogConfigProcessingSummary(configurationSet.InstanceIdentifier(), configurationSet.GetInputHash(), ConfigurationUnitIntent::Assert,
    350             summaryData.Result, summaryData.FailurePoint, summaryData.AssertSummary, summaryData.InformSummary, summaryData.ApplySummary);
    351     }
    352     CATCH_LOG();
    353 
    354     void TelemetryTraceLogger::LogConfigProcessingSummaryForTestException(
    355         const ConfigurationSet& configurationSet,
    356         hresult error,
    357         const TestConfigurationSetResult& result) const noexcept try
    358     {
    359         if (!IsTelemetryEnabled())
    360         {
    361             return;
    362         }
    363 
    364         ConfigRunSummaryData summaryData = ProcessRunResult(result.UnitResults());
    365 
    366         LogConfigProcessingSummary(configurationSet.InstanceIdentifier(), configurationSet.GetInputHash(), ConfigurationUnitIntent::Assert,
    367             error, ConfigurationUnitResultSource::Internal, summaryData.AssertSummary, summaryData.InformSummary, summaryData.ApplySummary);
    368     }
    369     CATCH_LOG();
    370 
    371     void TelemetryTraceLogger::LogConfigProcessingSummaryForApply(
    372         const ConfigurationSet& configurationSet,
    373         const ApplyConfigurationSetResult& result) const noexcept try
    374     {
    375         if (!IsTelemetryEnabled())
    376         {
    377             return;
    378         }
    379 
    380         ConfigRunSummaryData summaryData = ProcessRunResult(result.UnitResults());
    381 
    382         LogConfigProcessingSummary(configurationSet.InstanceIdentifier(), configurationSet.GetInputHash(), ConfigurationUnitIntent::Apply,
    383             result.ResultCode(), summaryData.FailurePoint, summaryData.AssertSummary, summaryData.InformSummary, summaryData.ApplySummary);
    384     }
    385     CATCH_LOG();
    386 
    387     void TelemetryTraceLogger::LogConfigProcessingSummaryForApplyException(
    388         const ConfigurationSet& configurationSet,
    389         hresult error,
    390         const ApplyConfigurationSetResult& result) const noexcept try
    391     {
    392         if (!IsTelemetryEnabled())
    393         {
    394             return;
    395         }
    396 
    397         ConfigRunSummaryData summaryData = ProcessRunResult(result.UnitResults());
    398 
    399         LogConfigProcessingSummary(configurationSet.InstanceIdentifier(), configurationSet.GetInputHash(), ConfigurationUnitIntent::Apply,
    400             error, ConfigurationUnitResultSource::Internal, summaryData.AssertSummary, summaryData.InformSummary, summaryData.ApplySummary);
    401     }
    402     CATCH_LOG();
    403 
    404     bool TelemetryTraceLogger::IsTelemetryEnabled() const noexcept
    405     {
    406 #ifdef AICLI_DISABLE_TEST_HOOKS
    407         return g_IsTelemetryProviderEnabled && m_isRuntimeEnabled;
    408 #else
    409         // For testing, only use the local enable state.
    410         return m_isRuntimeEnabled;
    411 #endif
    412     }
    413 }