Skip to content

Commit e9b7179

Browse files
authored
Log enrichment with entry assembly metadata (#10283)
* log enrichment * If no metadata, no property added. * Wiring Assembly through from the top call. Flag to disable metadata logging. TelemetryInitializer with similar functionality, so we can use it both in Serilog and ApplicationInsights context.
1 parent a8789a9 commit e9b7179

6 files changed

Lines changed: 214 additions & 4 deletions

File tree

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Reflection;
6+
using Serilog;
7+
using Serilog.Configuration;
8+
using Serilog.Enrichers;
9+
10+
namespace NuGet.Services.Logging
11+
{
12+
public static class NuGetAssemblyMetadataEnricherExtensions
13+
{
14+
public static LoggerConfiguration WithNuGetAssemblyMetadata(
15+
this LoggerEnrichmentConfiguration enrichmentConfiguration,
16+
Assembly metadataSourceAssembly)
17+
{
18+
if (enrichmentConfiguration == null)
19+
{
20+
throw new ArgumentNullException(nameof(enrichmentConfiguration));
21+
}
22+
23+
if (metadataSourceAssembly == null)
24+
{
25+
throw new ArgumentNullException(nameof(metadataSourceAssembly));
26+
}
27+
28+
return enrichmentConfiguration.With(new NuGetAssemblyMetadataEnricher(metadataSourceAssembly));
29+
}
30+
}
31+
}

src/NuGet.Services.Logging/LoggingSetup.cs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
// Copyright (c) .NET Foundation. All rights reserved.
1+
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System.Diagnostics;
55
using System.Linq;
6+
using System.Reflection;
67
using Microsoft.ApplicationInsights.Extensibility;
78
using Microsoft.Extensions.Logging;
89
using Serilog;
@@ -12,14 +13,25 @@ namespace NuGet.Services.Logging
1213
{
1314
public static class LoggingSetup
1415
{
15-
public static LoggerConfiguration CreateDefaultLoggerConfiguration(bool withConsoleLogger = false)
16+
public static LoggerConfiguration CreateDefaultLoggerConfiguration(
17+
bool withConsoleLogger = false,
18+
bool withAssemblyMetadata = true,
19+
Assembly metadataSourceAssembly = null)
1620
{
1721
var loggerConfiguration = new LoggerConfiguration()
1822
.MinimumLevel.Verbose();
1923

2024
loggerConfiguration.Enrich.WithMachineName();
2125
loggerConfiguration.Enrich.WithProcessId();
2226
loggerConfiguration.Enrich.FromLogContext();
27+
if (withAssemblyMetadata)
28+
{
29+
metadataSourceAssembly ??= Assembly.GetEntryAssembly();
30+
if (metadataSourceAssembly != null)
31+
{
32+
loggerConfiguration.Enrich.WithNuGetAssemblyMetadata(metadataSourceAssembly);
33+
}
34+
}
2335

2436
if (withConsoleLogger)
2537
{
@@ -64,4 +76,4 @@ public static ILoggerFactory CreateLoggerFactory(
6476
return loggerFactory;
6577
}
6678
}
67-
}
79+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System.Reflection;
5+
6+
#nullable enable
7+
8+
namespace NuGet.Services.Logging
9+
{
10+
public class NuGetAssemblyMetadata
11+
{
12+
private const string BranchMetadataKey = "Branch";
13+
private const string CommitIdMetadataKey = "CommitId";
14+
private const string BuildDateUtcMetadataKey = "BuildDateUtc";
15+
16+
public string? AssemblyInformationalVersion { get; set; } = null;
17+
public string? Branch { get; set; } = null;
18+
public string? CommitId { get; set; } = null;
19+
public string? BuildDateUtc { get; set; } = null;
20+
21+
public NuGetAssemblyMetadata(Assembly metadataSourceAssembly)
22+
{
23+
var attributes = metadataSourceAssembly?.GetCustomAttributes();
24+
if (attributes is null)
25+
{
26+
return;
27+
}
28+
foreach (var attribute in attributes)
29+
{
30+
if (attribute is AssemblyInformationalVersionAttribute informationalVersion)
31+
{
32+
AssemblyInformationalVersion = informationalVersion.InformationalVersion;
33+
}
34+
if (attribute is AssemblyMetadataAttribute metadataAttribute)
35+
{
36+
switch (metadataAttribute.Key)
37+
{
38+
case BranchMetadataKey:
39+
Branch = metadataAttribute.Value;
40+
break;
41+
case CommitIdMetadataKey:
42+
CommitId = metadataAttribute.Value;
43+
break;
44+
case BuildDateUtcMetadataKey:
45+
BuildDateUtc = metadataAttribute.Value;
46+
break;
47+
}
48+
}
49+
}
50+
}
51+
}
52+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Reflection;
6+
using Serilog.Core;
7+
using Serilog.Events;
8+
9+
#nullable enable
10+
11+
namespace NuGet.Services.Logging
12+
{
13+
/// <summary>
14+
/// Enriches logs with entry assembly NuGet metadata:
15+
/// AssemblyInformationalVersion
16+
/// Branch
17+
/// CommitId
18+
/// BuildDateUtc
19+
/// See PowerShell script that adds it: https://github.com/NuGet/NuGetGallery/blob/27bc6a62ead3110c1d8d2d2794fc8b8b646b1f1d/build/common.ps1#L884-L889
20+
/// </summary>
21+
public class NuGetAssemblyMetadataEnricher : ILogEventEnricher
22+
{
23+
public const string PropertyName = "NuGetStartingAssemblyMetadata";
24+
25+
private LogEventProperty? _cachedProperty = null;
26+
private readonly bool _hasAssemblyMetadata = false;
27+
private readonly NuGetAssemblyMetadata _assemblyMetadata;
28+
29+
public NuGetAssemblyMetadataEnricher(Assembly metadataSourceAssembly)
30+
{
31+
if (metadataSourceAssembly == null)
32+
{
33+
throw new ArgumentNullException(nameof(metadataSourceAssembly));
34+
}
35+
36+
_assemblyMetadata = new NuGetAssemblyMetadata(metadataSourceAssembly);
37+
_hasAssemblyMetadata =
38+
_assemblyMetadata.AssemblyInformationalVersion != null
39+
|| _assemblyMetadata.Branch != null
40+
|| _assemblyMetadata.CommitId != null
41+
|| _assemblyMetadata.BuildDateUtc != null;
42+
}
43+
44+
public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
45+
{
46+
if (!_hasAssemblyMetadata)
47+
{
48+
return;
49+
}
50+
51+
_cachedProperty ??= propertyFactory.CreateProperty(PropertyName, _assemblyMetadata, destructureObjects: true);
52+
53+
logEvent.AddPropertyIfAbsent(_cachedProperty);
54+
}
55+
}
56+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Reflection;
7+
using Microsoft.ApplicationInsights.Channel;
8+
using Microsoft.ApplicationInsights.DataContracts;
9+
using Microsoft.ApplicationInsights.Extensibility;
10+
11+
#nullable enable
12+
13+
namespace NuGet.Services.Logging
14+
{
15+
public class NuGetAssemblyMetadataTelemetryInitializer : ITelemetryInitializer
16+
{
17+
private readonly NuGetAssemblyMetadata _assemblyMetadata;
18+
19+
public NuGetAssemblyMetadataTelemetryInitializer(Assembly metadataSourceAssembly)
20+
{
21+
if (metadataSourceAssembly is null)
22+
{
23+
throw new ArgumentNullException(nameof(metadataSourceAssembly));
24+
}
25+
26+
_assemblyMetadata = new NuGetAssemblyMetadata(metadataSourceAssembly);
27+
}
28+
29+
public void Initialize(ITelemetry telemetry)
30+
{
31+
if (telemetry is not ISupportProperties itemTelemetry)
32+
{
33+
return;
34+
}
35+
36+
itemTelemetry.Properties
37+
.AddPropertyIfAbsent(nameof(_assemblyMetadata.AssemblyInformationalVersion), _assemblyMetadata.AssemblyInformationalVersion)
38+
.AddPropertyIfAbsent(nameof(_assemblyMetadata.Branch), _assemblyMetadata.Branch)
39+
.AddPropertyIfAbsent(nameof(_assemblyMetadata.CommitId), _assemblyMetadata.CommitId)
40+
.AddPropertyIfAbsent(nameof(_assemblyMetadata.BuildDateUtc), _assemblyMetadata.BuildDateUtc);
41+
}
42+
}
43+
44+
internal static class DictionaryExtensions
45+
{
46+
public static IDictionary<string, string> AddPropertyIfAbsent(
47+
this IDictionary<string, string> dictionary,
48+
string propertyName,
49+
string? propertyValue)
50+
{
51+
if (!dictionary.ContainsKey(propertyName) && propertyValue is not null)
52+
{
53+
dictionary.Add(propertyName, propertyValue);
54+
}
55+
56+
return dictionary;
57+
}
58+
}
59+
}

src/NuGetGallery/App_Start/DefaultDependenciesModule.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ protected override void Load(ContainerBuilder builder)
108108
configuration.Current,
109109
out ITelemetryClient telemetryClient);
110110

111-
var loggerConfiguration = LoggingSetup.CreateDefaultLoggerConfiguration(withConsoleLogger: false);
111+
var loggerConfiguration = LoggingSetup.CreateDefaultLoggerConfiguration(withConsoleLogger: false, withAssemblyMetadata: false);
112112
var loggerFactory = LoggingSetup.CreateLoggerFactory(
113113
loggerConfiguration,
114114
telemetryConfiguration: applicationInsightsConfiguration.TelemetryConfiguration);

0 commit comments

Comments
 (0)