| File: Telemetry.cs | Web Access |
| Project: src\sdk\src\Containers\Microsoft.NET.Build.Containers\Microsoft.NET.Build.Containers.csproj (Microsoft.NET.Build.Containers) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.NET.Build.Containers.LocalDaemons; namespace Microsoft.NET.Build.Containers; internal class Telemetry { /// <summary> /// Interesting data about the container publish - used to track the usage rates of various sources/targets of the process /// and to help diagnose issues with the container publish overall. /// </summary> /// <param name="RemotePullType">If the base image came from a remote registry, what kind of registry was it?</param> /// <param name="LocalPullType">If the base image came from a local store of some kind, what kind of store was it?</param> /// <param name="RemotePushType">If the new image is being pushed to a remote registry, what kind of registry is it?</param> /// <param name="LocalPushType">If the new image is being stored in a local store of some kind, what kind of store is it?</param> private record class PublishTelemetryContext(RegistryType? RemotePullType, LocalStorageType? LocalPullType, RegistryType? RemotePushType, LocalStorageType? LocalPushType); private enum RegistryType { Azure, AWS, Google, GitHub, DockerHub, MCR, Other } private enum LocalStorageType { Docker, Podman, Tarball } private readonly Microsoft.Build.Utilities.TaskLoggingHelper Log; private readonly PublishTelemetryContext Context; internal Telemetry( SourceImageReference source, DestinationImageReference destination, Microsoft.Build.Utilities.TaskLoggingHelper Log) { this.Log = Log; Context = new PublishTelemetryContext( source.Registry is not null ? GetRegistryType(source.Registry) : null, null, // we don't support local pull yet, but we may in the future destination.RemoteRegistry is not null ? GetRegistryType(destination.RemoteRegistry) : null, destination.LocalRegistry is not null ? GetLocalStorageType(destination.LocalRegistry) : null); } private RegistryType GetRegistryType(Registry r) { if (r.IsMcr) return RegistryType.MCR; if (r.IsGithubPackageRegistry) return RegistryType.GitHub; if (r.IsAmazonECRRegistry) return RegistryType.AWS; if (r.IsAzureContainerRegistry) return RegistryType.Azure; if (r.IsGoogleArtifactRegistry) return RegistryType.Google; if (r.IsDockerHub) return RegistryType.DockerHub; return RegistryType.Other; } private LocalStorageType GetLocalStorageType(ILocalRegistry r) { if (r is ArchiveFileRegistry) return LocalStorageType.Tarball; var d = r as DockerCli; System.Diagnostics.Debug.Assert(d != null, "Unknown local registry type"); if (d.GetCommand() == DockerCli.DockerCommand) return LocalStorageType.Docker; else return LocalStorageType.Podman; } private IDictionary<string, string?> ContextProperties() => new Dictionary<string, string?> { { nameof(Context.RemotePullType), Context.RemotePullType?.ToString() }, { nameof(Context.LocalPullType), Context.LocalPullType?.ToString() }, { nameof(Context.RemotePushType), Context.RemotePushType?.ToString() }, { nameof(Context.LocalPushType), Context.LocalPushType?.ToString() } }; public void LogPublishSuccess() { Log.LogTelemetry("sdk/container/publish/success", ContextProperties()); } public void LogUnknownRepository() { var props = ContextProperties(); props.Add("error", "unknown_repository"); Log.LogTelemetry("sdk/container/publish/error", props); } public void LogCredentialFailure(SourceImageReference _) { var props = ContextProperties(); props.Add("error", "credential_failure"); props.Add("direction", "pull"); Log.LogTelemetry("sdk/container/publish/error", props); } public void LogCredentialFailure(DestinationImageReference d) { var props = ContextProperties(); props.Add("error", "credential_failure"); props.Add("direction", "push"); Log.LogTelemetry("sdk/container/publish/error", props); } public void LogRidMismatch(string desiredRid, string[] availableRids) { var props = ContextProperties(); props.Add("error", "rid_mismatch"); props.Add("target_rid", desiredRid); props.Add("available_rids", string.Join(",", availableRids)); Log.LogTelemetry("sdk/container/publish/error", props); } public void LogMissingLocalBinary() { var props = ContextProperties(); props.Add("error", "missing_binary"); Log.LogTelemetry("sdk/container/publish/error", props); } public void LogLocalLoadError() { var props = ContextProperties(); props.Add("error", "local_load"); Log.LogTelemetry("sdk/container/publish/error", props); } }