UKHO.Logging.EventHubLogProvider 1.24067.2

dotnet add package UKHO.Logging.EventHubLogProvider --version 1.24067.2
NuGet\Install-Package UKHO.Logging.EventHubLogProvider -Version 1.24067.2
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="UKHO.Logging.EventHubLogProvider" Version="1.24067.2" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add UKHO.Logging.EventHubLogProvider --version 1.24067.2
#r "nuget: UKHO.Logging.EventHubLogProvider, 1.24067.2"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install UKHO.Logging.EventHubLogProvider as a Cake Addin
#addin nuget:?package=UKHO.Logging.EventHubLogProvider&version=1.24067.2

// Install UKHO.Logging.EventHubLogProvider as a Cake Tool
#tool nuget:?package=UKHO.Logging.EventHubLogProvider&version=1.24067.2

Event Hub Log Provider

The Event Hub Log Provider provides a logging sink for the Microsoft.Extensions.Logging.Abstractions. Logs are sent to Event Hub as a JSON message. The EventHubLogProvider provides a number of standard properties to enrich every log message, and provides a mechanism to add application specific custom properties to logs.

Getting Started

Installation Guide

This package is available from NuGet: UKHO.Logging.EventHubLogProvider

    nuget install UKHO.Logging.EventHubLogProvider

There are two recommended setups depending on the version of .NET: a legacy setup for .NET Core, and a setup for .NET 5/6+.

.NET 5/6+ Setup

The EventHubLogProvider is added to the IServiceCollection service collection via an ILoggingBuilder.

NuGet packages can be installed for extensions to the builder, for example adding console logging in the below statement loggingBuilder.AddConsole(); would require installing the package ConsoleLoggerExtensions

    services.AddLogging(loggingBuilder =>
    {
        loggingBuilder.AddConfiguration(configuration.GetSection("Logging"));
        loggingBuilder.AddConsole();
        loggingBuilder.AddDebug();
        loggingBuilder.AddAzureWebAppDiagnostics();
        var eventHubLoggingConfiguration = new EventHubLoggingConfiguration();
        configuration.GetSection(EventHubLoggingConfiguration.ConfigSection).Bind(eventHubLoggingConfiguration);
        if (!string.IsNullOrEmpty(eventHubLoggingConfiguration.ConnectionString))
        {
            loggingBuilder.AddEventHub(options =>
            {
                options.Environment = eventHubLoggingConfiguration.Environment;
                options.DefaultMinimumLogLevel = (LogLevel)Enum.Parse(typeof(LogLevel), eventHubLoggingConfiguration.MinimumLoggingLevel, true);
                options.MinimumLogLevels["UKHO"] = (LogLevel)Enum.Parse(typeof(LogLevel), eventHubLoggingConfiguration.UkhoMinimumLoggingLevel, true);
                options.EventHubConnectionString = eventHubLoggingConfiguration.ConnectionString;
                options.EventHubEntityPath = eventHubLoggingConfiguration.EntityPath;
                options.System = eventHubLoggingConfiguration.System;
                options.Service = eventHubLoggingConfiguration.Service;
                options.NodeName = eventHubLoggingConfiguration.NodeName;
                options.AdditionalValuesProvider = ConfigAdditionalValuesProvider;
            });
        }
    });

If you've upgraded from an earlier version of .NET Core and have not migrated to the new minimal hosting model, i.e., there is still a startup.cs, the above code should be added to the ConfigureServices:

public void ConfigureServices(IServiceCollection services)
{
    services.AddLogging(loggingBuilder =>
    {
            ...
}

An HttpContextAccessor is unavailable in the ConfigureServices method, however, a reference to it can be acquired in the Configure method:

public class Startup
{
    private readonly IConfiguration configuration;
    private IHttpContextAccessor _httpContextAccessor;
...


public void Configure(IApplicationBuilder app,
                            IWebHostEnvironment env
                            IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    ...

Then, the additional values can be gathered as follows:

private void ConfigAdditionalValuesProvider(IDictionary<string, object> additionalValues)
{
    if (_httpContextAccessor.HttpContext != null)
    {
        additionalValues["_RemoteIPAddress"] =
            _httpContextAccessor.HttpContext.Connection.RemoteIpAddress?.ToString();

        additionalValues["_User-Agent"] =
            _httpContextAccessor.HttpContext.Request.Headers["User-Agent"].FirstOrDefault() ?? string.Empty;

        additionalValues["_AssemblyVersion"] = Assembly
            .GetExecutingAssembly()
            .GetCustomAttributes<AssemblyFileVersionAttribute>().Single()
            .Version;

        additionalValues["_X-Correlation-ID"] =
            _httpContextAccessor.HttpContext.Request.Headers?[""].FirstOrDefault() ?? string.Empty;
    }
}
Legacy .NET Core Setup

The EventHubLogProvider is added to a LoggerFactory as follows:

var connectionString = ""; //Connection string to Event Hub with write permissions.
var entityPath = ""; //Event Hub entity path.
loggerFactory.AddEventHub(
    config =>
    {
        /*
        optional(AzureStorageLogProviderOptions)
        Setting this property and setting ("AzureStorageOptions:Enabled") = true 
        enables the azure storage logging provider 
        (for messages with size >= 1Mb)  
    
        Please check "Azure Storage Logging Provider" for more information.
        */
        config.AzureStorageLogProviderOptions = new AzureStorageLogProviderOptions(
                                        Configuration.GetValue<String>("AzureStorageOptions:SasUrl")
                                        ,Configuration.GetValue<Boolean>("AzureStorageOptions:Enabled")
                                        ,Configuration.GetValue<String>                                 ("AzureStorageOptions:SuccessfulMessageTemplate") 
                                        ,Configuration.GetValue<String>("AzureStorageOptions:FailedMessageTemplate")
                                        );
         
        
        config.Environment = "Production";
        config.DefaultMinimumLogLevel = LogLevel.Warning;
        config.MinimumLogLevels["Microsoft.AspNetCore"] = LogLevel.Trace;
        config.MinimumLogLevels["Microsoft.AspNetCore.Server"] = LogLevel.Error;
        config.EventHubConnectionString = connectionString;
        config.EventHubEntityPath = entityPath;
        config.System = "My System Name";
        config.Service = "My Service Name";
        config.NodeName = "Node 123";
        config.AdditionalValuesProvider = additionalValues =>
                                        {
                                            additionalValues["_AssemblyVersion"] = Assembly.GetExecutingAssembly()
                                                .GetCustomAttributes<AssemblyFileVersionAttribute>().Single().Version;
                                            additionalValues["_X-Correlation-ID"] = correlationId;
                                        };
        config.ValidateConnectionString = true;
    });

Within a standard ASP .Net Core project, this provider is best added in the Start-up's Configure method as this will allow access to a IHttpContextAccessor for injecting request data to all logs.

 public void Configure(IApplicationBuilder app,
                              IHostingEnvironment env,
                              ILoggerFactory loggerFactory,
                              IHttpContextAccessor httpContextAccessor)
    {
        ...
   
        loggerFactory.AddConsole();
        loggerFactory.AddEventHub(
            config =>
            {
                /*
                optional(AzureStorageLogProviderOptions)
                Setting this property and setting ("AzureStorageOptions:Enabled") = true 
                enables the azure storage logging provider 
                (for messages with size >= 1Mb)  
    
                Please check "Azure Storage Logging Provider" for more information.
                */
                config.AzureStorageLogProviderOptions = new AzureStorageLogProviderOptions(
                                        Configuration.GetValue<String>("AzureStorageOptions:SasUrl")
                                        ,Configuration.GetValue<Boolean>("AzureStorageOptions:Enabled")
                                        ,Configuration.GetValue<String>                                 ("AzureStorageOptions:SuccessfulMessageTemplate") 
                                        ,Configuration.GetValue<String>("AzureStorageOptions:FailedMessageTemplate")
                                        );
                config.Environment = "Production";
                config.DefaultMinimumLogLevel = LogLevel.Warning;
                config.MinimumLogLevels["Microsoft.AspNetCore"] = LogLevel.Trace;
                config.MinimumLogLevels["Microsoft.AspNetCore.Server"] = LogLevel.Error;
                config.EventHubConnectionString = connectionString;
                config.EventHubEntityPath = entityPath;
                config.System = "My System Name";
                config.Service = "My Service Name";
                config.NodeName = "Node 123";
                config.AdditionalValuesProvider = additionalValues =>
                                                {
                                                    additionalValues["_AssemblyVersion"] = Assembly.GetExecutingAssembly()
                                                        .GetCustomAttributes<AssemblyFileVersionAttribute>().Single().Version;
                                                    additionalValues["_X-Correlation-ID"] = correlationId;
                                                    additionalValues["_RemoteIPAddress"] = httpContextAccessor.HttpContext.Connection.RemoteIpAddress.ToString();
                                                    additionalValues["_User-Agent"] = httpContextAccessor.HttpContext.Request.Headers["User-Agent"].FirstOrDefault() ?? string.Empty;
                                                };
                config.ValidateConnectionString = true;
            });
    }

Customisation of Log Parameter Serialization

The default log parameter serialization uses NewtonSoft.Net JsonConvert to serialize the log parameters to JSON. On occasion, it maybe desirable to customise the JSON produced to control how individual properties are serialized. This can be done by providing custom converters that extend the Newtonsoft.Json.JsonConverter class:

loggerFactory.AddEventHub(
            config =>
            {
                ...
                config.CustomLogSerializerConverters = new List<JsonConverter> { new VersionJsonConverter() };
                ...
            });

The JsonConverter must implement WriteJson, but the ReadJson method can be left unimplemented and the CanRead property can return false. The CanConvert method must only return true for the types that you wish to override the serialization of. More details about custom converters can be found in the JsonConvert documentation https://www.newtonsoft.com/json/help/html/CustomJsonConverter.htm.

    public class VersionJsonConverter : JsonConverter
    {
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            if (value is Version version)
            {
                writer.WriteValue($"{version.MajorVersion}.{version.MinorVersion}.{version.Build}.{version.Revision}");
            }
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }

        public override bool CanConvert(Type objectType)
        {
            return objectType == typeof(Version);
        }

        public override bool CanRead => false;
    }

Azure Storage Logging Provider

The Azure Storage Logging Provider is a storage logging provider that stores messages with size equal or greater than 1Mb into an Azure storage container. Finally, it updates the log entry with the azure storage blob details. Enabling the Azure storage provider is optional.

The provider can be enabled by providing the AzureStorageLogProviderOptions model which consists of:

//The SAS url for the storage container, recommended rights set : racwl
string azureStorageContainerSasUrlString  
//Enables (true) or disables(false) the Azure storage logging provider
bool azureStorageLoggerEnabled,
//A template for the messages that are successfully stored*
string successfulMessageTemplate,
//A template for the messages that failed to be stored*
string failedMessageTemplate

/*
The templates are configurable. 
The parameters must be added with the following format: {{property_name}} 

Available properties:

<param name="reasonPhrase">The result reason phrase</param>
<param name="statusCode">The http status code</param>
<param name="requestId">The client request Id</param>
<param name="fileSHA">The blob SHA 256</param>
<param name="isStored">The flag that determines if the result was successful/failed</param>
<param name="blobFullName">The blob full name</param>
<param name="fileSize">The file size (optional)</param>
<param name="modifiedDate">The modified date(optional)</param>

public string ReasonPhrase { get; set; }
public int StatusCode { get; set; }
public string RequestId { get; set; }
public string FileSHA { get; set; }
public bool IsStored { get; set; }
public string BlobFullName { get; set; }
public long FileSize { get; set; }
public DateTime ModifiedDate { get; set; }

*/

Example of a configuration section(json)

    "AzureStorageOptions": {
    "SasUrl": "the_sas_url", //removed for security reasons
    "Enabled": true,
    "SuccessfulMessageTemplate": "Azure Storage Logging: A blob with the error details was created at {{BlobFullName}}. Reason: ErrorMessageEqualOrGreaterTo1MB ResponseMessage: {{ReasonPhrase}} ResponseCode: {{StatusCode}} RequestId: {{RequestId}} Sha256: {{FileSHA}} FileSize(Bs): {{FileSize}} FileModifiedDate: {{ModifiedDate}}",
    "FailedMessageTemplate": "Azure Storage Logging: Storing blob failed. Reason: ErrorMessageEqualOrGreaterTo1MB ResponseMessage: {{ReasonPhrase}} ResponseCode: {{StatusCode}} RequestId: {{RequestId}}"
  }

Azure Storage Provider Functional Diagram

The diagram (Visio) can be downloaded using the following link

EventHub Logging Provider Help File

Version 1.0.0

How to Engage, Contribute, and Give Feedback

Some of the best ways to contribute are to try things out, file issues and make pull-requests.


The UK Hydrographic Office (UKHO) supplies hydrographic information to protect lives at sea. Maintaining the confidentially, integrity and availability of our services is paramount. Found a security bug? Please report it to us at UKHO-ITSO@gov.co.uk

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 is compatible.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.24067.2 528 3/7/2024
1.23242.1 1,732 8/30/2023
1.23073.7 1,953 3/14/2023
1.22356.5 844 12/22/2022
1.22356.1 375 12/22/2022
1.22220.1 1,319 8/8/2022
1.22217.9 439 8/8/2022
1.22047.3 1,731 2/16/2022
1.22047.1 591 2/16/2022
1.20077.2 2,054 3/17/2020
1.20013.11 612 1/13/2020
1.20013.5 573 1/13/2020