Created
May 2, 2022 09:59
-
-
Save meixger/c3f0bb3e4b64a9915ed16692743c5962 to your computer and use it in GitHub Desktop.
Azure App Service RoleName for Serilog
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// <summary> | |
/// We need to check the App Service Kudo header WAS-DEFAULT-HOSTNAME. | |
/// The environment variable "WEBSITE_HOSTNAME" will not be updated to production after swapping App Service slots. | |
/// </summary> | |
public class RoleNameContainer | |
{ | |
// See internal class https://github.com/microsoft/ApplicationInsights-dotnet/blob/2.19.0/NETCORE/src/Microsoft.ApplicationInsights.AspNetCore/Implementation/RoleNameContainer.cs | |
// https://github.com/microsoft/ApplicationInsights-dotnet/blob/51dc14afaf7de2b6902a10d6518d2d400cb61f67/NETCORE/src/Microsoft.ApplicationInsights.AspNetCore/DiagnosticListeners/Implementation/HostingDiagnosticListener.cs#L192 | |
private const string WebAppHostNameHeaderName = "WAS-DEFAULT-HOSTNAME"; | |
private const string WebAppHostNameEnvironmentVariable = "WEBSITE_HOSTNAME"; | |
private string roleName = string.Empty; | |
/// <summary> | |
/// Initializes a new instance of the <see cref="Microsoft.ApplicationInsights.AspNetCore.Implementation.RoleNameContainer"/> class. | |
/// Will set the RoleName based on an environment variable. | |
/// </summary> | |
/// <param name="hostNameSuffix">Host name suffix will be used to parse the prefix from the host name. The value of the prefix is the RoleName.</param> | |
internal RoleNameContainer(string hostNameSuffix = ".azurewebsites.net") | |
{ | |
this.HostNameSuffix = hostNameSuffix; | |
var enVarValue = Environment.GetEnvironmentVariable(WebAppHostNameEnvironmentVariable); | |
this.ParseAndSetRoleName(enVarValue); | |
this.IsAzureWebApp = !string.IsNullOrEmpty(enVarValue); | |
} | |
/// <summary> | |
/// Gets or sets static instance for Initializer and DiagnosticListener to share access to RoleName variable. | |
/// </summary> | |
public static RoleNameContainer Instance { get; set; } | |
/// <summary> | |
/// Gets or sets role name of the current application. | |
/// </summary> | |
public string RoleName | |
{ | |
get => this.roleName; | |
set | |
{ | |
if (value != this.roleName) | |
{ | |
Interlocked.Exchange(ref this.roleName, value); | |
} | |
} | |
} | |
/// <summary> | |
/// Gets a value indicating whether indicates if the current app is an Azure Web App based on the presence of a specific environment variable. Set in constructor. | |
/// </summary> | |
public bool IsAzureWebApp { get; private set; } | |
/// <summary> | |
/// Gets suffix of website name. This must be changed when running in non public Azure region. | |
/// Default value (Public Cloud): ".azurewebsites.net" | |
/// For US Gov Cloud: ".azurewebsites.us" | |
/// For Azure Germany: ".azurewebsites.de". | |
/// </summary> | |
public string HostNameSuffix { get; private set; } | |
/// <summary> | |
/// Attempt to set the role name from a given collection of request headers. | |
/// </summary> | |
/// <param name="requestHeaders">Request headers to check for role name.</param> | |
public void Set(IHeaderDictionary requestHeaders) | |
{ | |
string headerValue = requestHeaders[WebAppHostNameHeaderName]; | |
this.ParseAndSetRoleName(headerValue); | |
} | |
private void ParseAndSetRoleName(string input) | |
{ | |
if (string.IsNullOrEmpty(input)) | |
{ | |
// do nothing | |
} | |
else if (input.EndsWith(this.HostNameSuffix, StringComparison.OrdinalIgnoreCase)) | |
{ | |
this.RoleName = input.Substring(0, input.Length - this.HostNameSuffix.Length); | |
} | |
else | |
{ | |
this.RoleName = input; | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public static class RoleNameContainerExtensions | |
{ | |
/// <summary> | |
/// Gets the role name from App Service Kudo header | |
/// </summary> | |
public static IApplicationBuilder UseRoleNameContainer(this IApplicationBuilder app) | |
{ | |
app.Use(next => async context => | |
{ | |
RoleNameContainer.Instance ??= new RoleNameContainer(); | |
RoleNameContainer.Instance.Set(context.Request.Headers); | |
await next(context); | |
}); | |
return app; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class SerilogAppInsightsTraceTelemetryConverter : TraceTelemetryConverter | |
{ | |
// SeriLog does not populate the cloud_RoleName property: | |
// https://github.com/serilog/serilog-sinks-applicationinsights/issues/152 | |
public override IEnumerable<ITelemetry> Convert(LogEvent logEvent, IFormatProvider formatProvider) | |
{ | |
foreach (var telemetry in base.Convert(logEvent, formatProvider)) | |
{ | |
if (RoleNameContainer.Instance?.IsAzureWebApp ?? false) | |
if (string.IsNullOrEmpty(telemetry.Context.Cloud.RoleName)) | |
telemetry.Context.Cloud.RoleName = RoleNameContainer.Instance.RoleName; | |
yield return telemetry; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment