Skip to content

Commit 62c6e6d

Browse files
committed
Add some missing logging and telemetry handling
1 parent 160d7ad commit 62c6e6d

File tree

7 files changed

+57
-17
lines changed

7 files changed

+57
-17
lines changed

src/Containers/Microsoft.NET.Build.Containers/LocalDaemons/DockerCli.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ public DockerCli(string? command, ILoggerFactory loggerFactory)
5151
public DockerCli(ILoggerFactory loggerFactory) : this(null, loggerFactory)
5252
{ }
5353

54+
public bool IsDocker => _command == DockerCommand;
55+
public bool IsPodman => _command == PodmanCommand;
56+
5457
private static string FindFullPathFromPath(string command)
5558
{
5659
foreach (string directory in (Environment.GetEnvironmentVariable("PATH") ?? string.Empty).Split(Path.PathSeparator))

src/Containers/Microsoft.NET.Build.Containers/Tasks/DownloadLayers.cs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ public async Task<bool> ExecuteAsync()
4949

5050
if (string.IsNullOrEmpty(digest) || string.IsNullOrEmpty(size) || string.IsNullOrEmpty(mediaType))
5151
{
52-
throw new ArgumentException($"Layer {layer.ItemSpec} must have Digest, Size, and MediaType metadata");
52+
logger.LogError(new EventId(123456, "layer_item_validation_failure"), $"Layer {layer.ItemSpec} must have Digest, Size, and MediaType metadata");
5353
}
5454

5555
var descriptor = new Descriptor(mediaType, digest, long.Parse(size));
@@ -58,18 +58,16 @@ public async Task<bool> ExecuteAsync()
5858
{
5959
if (t.IsFaulted)
6060
{
61-
this.Log.LogError($"Failed to download layer {digest} from {Registry}/{Repository}: {t.Exception?.Flatten().Message}");
61+
logger.LogError(new EventId(123457, "layer_download_failure"), exception: t.Exception, $"Failed to download layer {digest} from {Registry}/{Repository}");
6262
}
6363
else if (t.IsCanceled)
6464
{
65-
this.Log.LogError($"Failed to download layer {digest} from {Registry}/{Repository}: Task was cancelled");
65+
logger.LogError(new EventId(123457, "layer_download_failure"), exception: t.Exception, $"Failed to download layer {digest} from {Registry}/{Repository}");
6666
}
6767
})
6868
);
6969
}
7070
await Task.WhenAll(layerDownloadTasks);
71-
return true;
71+
return !Log.HasLoggedErrors;
7272
}
73-
74-
7573
}

src/Containers/Microsoft.NET.Build.Containers/Tasks/MakeContainerTarball.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,9 @@ public async Task<bool> ExecuteAsync()
5353
var filePath = DetermineFilePath();
5454
await using var fileStream = File.Create(filePath);
5555
GeneratedArchiveFilePath = filePath;
56+
var telemetry = new Telemetry(new(null, null, null, Telemetry.LocalStorageType.Tarball), Log);
5657
await DockerCli.WriteImageToStreamAsync(Repository, Tags, config!, layers, manifestStructure, fileStream, _cts.Token);
58+
telemetry.LogPublishSuccess();
5759
return true;
5860
}
5961

src/Containers/Microsoft.NET.Build.Containers/Tasks/PushContainerToLocal.cs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,34 @@ public async Task<bool> ExecuteAsync()
4646
var configDigest = manifestStructure.Config.digest;
4747
var config = await JsonSerializer.DeserializeAsync<JsonObject>(File.OpenRead(Configuration.ItemSpec), cancellationToken: _cts.Token);
4848
var containerCli = new DockerCli(LocalRegistry, msbuildLoggerFactory);
49+
50+
var telemetry = new Telemetry(new(null, null, null, containerCli.IsDocker ? Telemetry.LocalStorageType.Docker : Telemetry.LocalStorageType.Podman), Log);
51+
if (!await containerCli.IsAvailableAsync(_cts.Token).ConfigureAwait(false))
52+
{
53+
telemetry.LogMissingLocalBinary();
54+
Log.LogErrorWithCodeFromResources(nameof(Strings.LocalRegistryNotAvailable));
55+
return false;
56+
}
57+
4958
var layers = Layers.Select(l => new Layer(new(l.ItemSpec), GetDescriptor(l))).ToArray();
50-
await containerCli.LoadAsync((Repository, Tags, configDigest, config!, layers), DockerCli.WriteDockerImageToStreamAsync, _cts.Token);
59+
try
60+
{
61+
await containerCli.LoadAsync((Repository, Tags, configDigest, config!, layers), DockerCli.WriteDockerImageToStreamAsync, _cts.Token);
62+
}
63+
catch (AggregateException ex) when (ex.InnerException is DockerLoadException dle)
64+
{
65+
telemetry.LogLocalLoadError();
66+
Log.LogErrorFromException(dle, showStackTrace: false);
67+
}
68+
catch (ArgumentException argEx)
69+
{
70+
Log.LogErrorFromException(argEx, showStackTrace: false);
71+
}
72+
catch (DockerLoadException dle)
73+
{
74+
telemetry.LogLocalLoadError();
75+
Log.LogErrorFromException(dle, showStackTrace: false);
76+
}
5177
return true;
5278
}
5379

src/Containers/Microsoft.NET.Build.Containers/Tasks/PushContainerToRemoteRegistry.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ public async Task<bool> ExecuteAsync()
4343
ILogger logger = msbuildLoggerFactory.CreateLogger(nameof(PushContainerToRemoteRegistry));
4444
var destinationRegistry = new Registry(Registry, msbuildLoggerFactory.CreateLogger(Registry), RegistryMode.Push);
4545

46+
var telemetry = new Telemetry(new(null, null, Telemetry.GetRegistryType(destinationRegistry), null), Log);
4647
// functionally, we need to
4748
// * upload the layers
4849
var layerUploadTasks = Layers.Select(l => new Layer(new(l.ItemSpec), GetDescriptor(l))).Select(async l =>
@@ -124,6 +125,7 @@ public async Task<bool> ExecuteAsync()
124125
await destinationRegistry.UploadManifestAsync(Repository, tag, manifestStructure, _cts.Token);
125126
logger.LogInformation(Strings.Registry_TagUploaded, tag, Registry);
126127
}
128+
telemetry.LogPublishSuccess();
127129
return true;
128130
}
129131

src/Containers/Microsoft.NET.Build.Containers/Tasks/SelectRuntimeIdentifierSpecificItems.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,20 +32,23 @@ public override bool Execute()
3232
ILoggerFactory msbuildLoggerFactory = new LoggerFactory(new[] { loggerProvider });
3333
ILogger logger = msbuildLoggerFactory.CreateLogger<CreateImageIndex>();
3434
var graph = NuGet.RuntimeModel.JsonRuntimeFormat.ReadRuntimeGraph(RuntimeIdentifierGraphPath);
35-
35+
3636
var selectedItems = new List<ITaskItem>(Items.Length);
3737
foreach (var item in Items)
3838
{
39-
if (item.GetMetadata("RuntimeIdentifier") is string ridValue &&
39+
if (item.GetMetadata("RuntimeIdentifier") is string ridValue &&
4040
graph.AreCompatible(TargetRuntimeIdentifier, ridValue))
4141
{
4242
selectedItems.Add(item);
4343
}
4444
}
4545

46+
// TODO: log if no items were selected
47+
// TODO: log telemetry.LogRidMismatch
48+
4649
SelectedItems = selectedItems.ToArray();
4750
return true;
4851
}
4952

50-
53+
5154
}

src/Containers/Microsoft.NET.Build.Containers/Telemetry.cs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,27 +15,33 @@ internal class Telemetry
1515
/// <param name="LocalPullType">If the base image came from a local store of some kind, what kind of store was it?</param>
1616
/// <param name="RemotePushType">If the new image is being pushed to a remote registry, what kind of registry is it?</param>
1717
/// <param name="LocalPushType">If the new image is being stored in a local store of some kind, what kind of store is it?</param>
18-
private record class PublishTelemetryContext(RegistryType? RemotePullType, LocalStorageType? LocalPullType, RegistryType? RemotePushType, LocalStorageType? LocalPushType);
19-
private enum RegistryType { Azure, AWS, Google, GitHub, DockerHub, MCR, Other }
20-
private enum LocalStorageType { Docker, Podman, Tarball }
18+
internal record class PublishTelemetryContext(RegistryType? RemotePullType, LocalStorageType? LocalPullType, RegistryType? RemotePushType, LocalStorageType? LocalPushType);
19+
internal enum RegistryType { Azure, AWS, Google, GitHub, DockerHub, MCR, Other }
20+
internal enum LocalStorageType { Docker, Podman, Tarball }
2121

2222
private readonly Microsoft.Build.Utilities.TaskLoggingHelper Log;
2323
private readonly PublishTelemetryContext Context;
2424

2525
internal Telemetry(
2626
SourceImageReference source,
2727
DestinationImageReference destination,
28-
Microsoft.Build.Utilities.TaskLoggingHelper Log)
28+
Microsoft.Build.Utilities.TaskLoggingHelper log)
2929
{
30-
this.Log = Log;
30+
Log = log;
3131
Context = new PublishTelemetryContext(
3232
source.Registry is not null ? GetRegistryType(source.Registry) : null,
3333
null, // we don't support local pull yet, but we may in the future
3434
destination.RemoteRegistry is not null ? GetRegistryType(destination.RemoteRegistry) : null,
3535
destination.LocalRegistry is not null ? GetLocalStorageType(destination.LocalRegistry) : null);
3636
}
3737

38-
private RegistryType GetRegistryType(Registry r)
38+
internal Telemetry(PublishTelemetryContext context, Microsoft.Build.Utilities.TaskLoggingHelper log)
39+
{
40+
Log = log;
41+
Context = context;
42+
}
43+
44+
internal static RegistryType GetRegistryType(Registry r)
3945
{
4046
if (r.IsMcr) return RegistryType.MCR;
4147
if (r.IsGithubPackageRegistry) return RegistryType.GitHub;
@@ -113,4 +119,4 @@ public void LogLocalLoadError()
113119
props.Add("error", "local_load");
114120
Log.LogTelemetry("sdk/container/publish/error", props);
115121
}
116-
}
122+
}

0 commit comments

Comments
 (0)