Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions src/AppInstallerCommonCore/AppInstallerTelemetry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "Public/winget/ThreadGlobals.h"
#include "winget/Filesystem.h"
#include "winget/UserSettings.h"
#include <AppInstallerDateTime.h>

#define AICLI_TraceLoggingStringView(_sv_,_name_) TraceLoggingCountedUtf8String(_sv_.data(), static_cast<ULONG>(_sv_.size()), _name_)
#define AICLI_TraceLoggingWStringView(_sv_,_name_) TraceLoggingCountedWideString(_sv_.data(), static_cast<ULONG>(_sv_.size()), _name_)
Expand Down Expand Up @@ -737,6 +738,74 @@ namespace AppInstaller::Logging
}
}

void TelemetryTraceLogger::LogPreindexedPackageUpdate(
std::string_view sourceId,
std::optional<std::chrono::system_clock::time_point> previousIndexPublishedAt,
std::chrono::system_clock::time_point newIndexPublishedAt,
bool usedDeltaDownload,
std::optional<std::chrono::system_clock::time_point> previousBaselinePublishedAt,
std::optional<std::chrono::system_clock::time_point> newBaselinePublishedAt,
bool baselineUpdated,
uint64_t downloadedBytes,
bool isManualUpdate) const noexcept
{
// Converts a system_clock time_point to FILETIME. An empty optional maps to FILETIME{0,0} (null sentinel).
auto toFileTime = [](const std::optional<std::chrono::system_clock::time_point>& tp) -> FILETIME
{
return tp ? Utility::ConvertSystemClockToFileTime(*tp) : FILETIME{};
};

bool isNewClient = !previousIndexPublishedAt.has_value();

double indexStalenessDays = -1.0;
if (previousIndexPublishedAt)
{
indexStalenessDays = std::chrono::duration<double, std::ratio<86400>>(
newIndexPublishedAt - *previousIndexPublishedAt).count();
}

double baselineStalenessDays = -1.0;
if (previousBaselinePublishedAt && newBaselinePublishedAt)
{
baselineStalenessDays = std::chrono::duration<double, std::ratio<86400>>(
*newBaselinePublishedAt - *previousBaselinePublishedAt).count();
}

FILETIME previousIndexFt = toFileTime(previousIndexPublishedAt);
FILETIME newIndexFt = toFileTime(newIndexPublishedAt);
FILETIME previousBaselineFt = toFileTime(previousBaselinePublishedAt);
FILETIME newBaselineFt = toFileTime(newBaselinePublishedAt);

if (IsTelemetryEnabled())
{
AICLI_TraceLoggingWriteActivity(
"PreindexedPackageUpdate",
AICLI_TraceLoggingStringView(sourceId, "SourceId"),
TraceLoggingFileTime(previousIndexFt, "PreviousIndexPublishedAt"),
TraceLoggingFileTime(newIndexFt, "NewIndexPublishedAt"),
TraceLoggingFloat64(indexStalenessDays, "IndexStalenessDays"),
TraceLoggingBool(isNewClient, "IsNewClient"),
TraceLoggingBool(usedDeltaDownload, "UsedDeltaDownload"),
TraceLoggingFileTime(previousBaselineFt, "PreviousBaselinePublishedAt"),
TraceLoggingFileTime(newBaselineFt, "NewBaselinePublishedAt"),
TraceLoggingFloat64(baselineStalenessDays, "BaselineStalenessDays"),
TraceLoggingBool(baselineUpdated, "BaselineUpdated"),
TraceLoggingUInt64(downloadedBytes, "DownloadedBytes"),
TraceLoggingBool(isManualUpdate, "IsManualUpdate"),
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance),
TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES));
}

AICLI_LOG(Repo, Verbose, << "PreindexedPackageUpdate: Source [" << sourceId
<< "] IsNewClient [" << isNewClient
<< "] IndexStalenessDays [" << indexStalenessDays
<< "] UsedDeltaDownload [" << usedDeltaDownload
<< "] BaselineStalenessDays [" << baselineStalenessDays
<< "] BaselineUpdated [" << baselineUpdated
<< "] DownloadedBytes [" << downloadedBytes
<< "] IsManualUpdate [" << isManualUpdate << "]");
}

void TelemetryTraceLogger::LogRepairFailure(std::string_view id, std::string_view version, std::string_view type, uint32_t errorCode) const noexcept
{
if (IsTelemetryEnabled())
Expand Down
15 changes: 15 additions & 0 deletions src/AppInstallerCommonCore/Public/AppInstallerTelemetry.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
#include <AppInstallerLanguageUtilities.h>
#include <wil/result_macros.h>

#include <chrono>
#include <optional>
#include <string_view>
#include <vector>
#include <cguid.h>
Expand Down Expand Up @@ -267,6 +269,19 @@ namespace AppInstaller::Logging

void LogNonFatalDOError(std::string_view url, HRESULT hr) const noexcept;

// Logs details of a preindexed package source update (full or delta).
// Nullable datetime fields use a null optional; nullable float fields use -1.0.
void LogPreindexedPackageUpdate(
std::string_view sourceId,
std::optional<std::chrono::system_clock::time_point> previousIndexPublishedAt,
std::chrono::system_clock::time_point newIndexPublishedAt,
bool usedDeltaDownload,
std::optional<std::chrono::system_clock::time_point> previousBaselinePublishedAt,
std::optional<std::chrono::system_clock::time_point> newBaselinePublishedAt,
bool baselineUpdated,
uint64_t downloadedBytes,
bool isManualUpdate) const noexcept;

protected:
bool IsTelemetryEnabled() const noexcept;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,32 @@ namespace AppInstaller::Repository::Microsoft
return false;
}

return UpdateInternal(packageInfo.PackageLocation(), details, progress);
std::optional<uint64_t> downloadedBytes;
bool result = UpdateInternal(packageInfo.PackageLocation(), details, progress, downloadedBytes);

if (downloadedBytes)
{
try
{
auto manifests = packageInfo.MsixInfo().GetAppPackageManifests();
if (!manifests.empty())
{
Logging::Telemetry().LogPreindexedPackageUpdate(
details.Identifier,
std::nullopt,
Utility::GetTimePointFromVersion(manifests[0].GetIdentity().GetVersion()),
false,
std::nullopt,
std::nullopt,
false,
downloadedBytes.value(),
true);
}
}
CATCH_LOG();
}

return result;
}

bool Update(const SourceDetails& details, IProgressCallback& progress) override final
Expand All @@ -257,7 +282,7 @@ namespace AppInstaller::Repository::Microsoft
// Retrieves the currently cached version of the package.
virtual std::optional<Msix::PackageVersion> GetCurrentVersion(const SourceDetails& details) = 0;

virtual bool UpdateInternal(const std::string& packageLocation, const SourceDetails& details, IProgressCallback& progress) = 0;
virtual bool UpdateInternal(const std::string& packageLocation, const SourceDetails& details, IProgressCallback& progress, std::optional<uint64_t>& downloadedBytes) = 0;

bool Remove(const SourceDetails& details, IProgressCallback& progress) override final
{
Expand Down Expand Up @@ -325,7 +350,30 @@ namespace AppInstaller::Repository::Microsoft
return false;
}

return UpdateInternal(updateCheck.PackageLocation(), details, progress);
std::optional<uint64_t> downloadedBytes = 0;
bool result = UpdateInternal(updateCheck.PackageLocation(), details, progress, downloadedBytes);

if (downloadedBytes)
{
std::optional<std::chrono::system_clock::time_point> previousIndexPublishedAt;
if (currentVersion)
{
previousIndexPublishedAt = Utility::GetTimePointFromVersion(currentVersion.value());
}

Logging::Telemetry().LogPreindexedPackageUpdate(
details.Identifier,
previousIndexPublishedAt,
Utility::GetTimePointFromVersion(updateCheck.AvailableVersion()),
false,
std::nullopt,
std::nullopt,
false,
downloadedBytes.value(),
!isBackground);
}

return result;
}
};

Expand Down Expand Up @@ -577,7 +625,7 @@ namespace AppInstaller::Repository::Microsoft
return PackagedContextGetCurrentVersion(details);
}

bool UpdateInternal(const std::string& packageLocation, const SourceDetails& details, IProgressCallback& progress) override
bool UpdateInternal(const std::string& packageLocation, const SourceDetails& details, IProgressCallback& progress, std::optional<uint64_t>& downloadedBytes) override
{
// Due to complications with deployment, download the file and deploy from
// a local source while we investigate further.
Expand All @@ -589,7 +637,8 @@ namespace AppInstaller::Repository::Microsoft
localFile = Runtime::GetPathTo(Runtime::PathName::Temp);
localFile /= GetPackageFamilyNameFromDetails(details) + ".msix";

Utility::Download(packageLocation, localFile, Utility::DownloadType::Index, progress);
auto downloadResult = Utility::Download(packageLocation, localFile, Utility::DownloadType::Index, progress);
downloadedBytes = downloadResult.SizeInBytes;
}
else
{
Expand Down Expand Up @@ -731,7 +780,7 @@ namespace AppInstaller::Repository::Microsoft
return DesktopContextGetCurrentVersion(details);
}

bool UpdateInternal(const std::string& packageLocation, const SourceDetails& details, IProgressCallback& progress) override
bool UpdateInternal(const std::string& packageLocation, const SourceDetails& details, IProgressCallback& progress, std::optional<uint64_t>& downloadedBytes) override
{
// We will extract the manifest and index files directly to this location
std::filesystem::path packageState = GetStatePathFromDetails(details);
Expand All @@ -754,7 +803,8 @@ namespace AppInstaller::Repository::Microsoft

if (Utility::IsUrlRemote(packageLocation))
{
AppInstaller::Utility::Download(packageLocation, tempPackagePath, AppInstaller::Utility::DownloadType::Index, progress);
auto downloadResult = AppInstaller::Utility::Download(packageLocation, tempPackagePath, AppInstaller::Utility::DownloadType::Index, progress);
downloadedBytes = downloadResult.SizeInBytes;
}
else
{
Expand Down
5 changes: 5 additions & 0 deletions src/AppInstallerSharedLib/DateTime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,11 @@ namespace AppInstaller::Utility
return winrt::clock::to_sys(winrt::clock::from_FILETIME(fileTime));
}

FILETIME ConvertSystemClockToFileTime(const std::chrono::system_clock::time_point& time)
{
return winrt::clock::to_FILETIME(winrt::clock::from_sys(time));
}

std::chrono::system_clock::time_point GetTimePointFromVersion(const UInt64Version& version)
{
// Our custom format for converting UTC into a version is:
Expand Down
3 changes: 3 additions & 0 deletions src/AppInstallerSharedLib/Public/AppInstallerDateTime.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ namespace AppInstaller::Utility
// Converts the given file time to a system_clock::time_point.
std::chrono::system_clock::time_point ConvertFiletimeToSystemClock(const FILETIME& fileTime);

// Converts the given system_clock::time_point to a FILETIME.
FILETIME ConvertSystemClockToFileTime(const std::chrono::system_clock::time_point& time);

// Converts the given package version into a time_point using our custom format.
// Ensure that the package is expected to use this format, or you may get strange times.
// If the version is not convertable, the minimum time is returned.
Expand Down