GFlisch / Arc4u

Apache License 2.0
23 stars 18 forks source link

Provide possibility to set Splunk meta-data field 'host' dynamically #80

Open HaGGi13 opened 1 year ago

HaGGi13 commented 1 year ago

Is your feature request related to a problem? Please describe.

In our project we use the Serilog Splunk sink to ingest log messages into Splunk. Unfortunately we noticed the message's meta-data field host was not set properly. As this field's value should contain the host machine name, it must be determined on runtime to avoid hard-coding it as the service/application will be deployed on many different servers.

This issue was already addressed in the serilog-contrib/serliog-sinks-splunk issue backlog:

Describe the solution you'd like

The best solution we can get is that the Serilog sink used supports this. If they don't implement this like requested in following issue, we can contribute and implement this by our own.

Describe alternatives you've considered

Until this is supported by the extension used, a workaround can be applied like following. After the configuration (appsettings.json) is loaded in memory, it can be extended by the needed information. To do so we have to check if a Splunk ingest configuration exists. Only if a Splunk configuration exist, the meta-data field host should be added or overwritten in the memory hold configuration. Only after that the Logger object can be created by utilizing the in memory stored configuration.

This should be already auto generated by the Guidance on project creation.

Workaround (implementation example)

Unfortunately this approach contains hard-coded JSON configuration paths as at point in time this was implemented we were in a rush and needed an implementation. Hence it would be awesome to determine those paths dynamically.

Please find the following workaround as code files in the attachements.

Within the Startup.cs

public class Startup
{
    private IConfiguration Configuration { get; }

    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        if (Configuration.IsSplunkConfigured())
        {
            Configuration.SetSplunkHost(System.Environment.MachineName);
        }

        var logger = new LoggerConfiguration()
            .ReadFrom.Configuration(Configuration)
            .CreateLogger();

        // ... other code...
    }

    public void Configure(IApplicationBuilder app)
    {
        // ... other code...
    }
}

Used extension methods from ConfigurationExtensions.cs

public static class ConfigurationExtensions
{
    private const string SplunkLoggerNamePath = "Serilog:WriteTo:SplunkLogger:Name";

    private const string SplunkLoggerHostPath =
        "Serilog:WriteTo:SplunkLogger:Args:configureLogger:WriteTo:0:Args:host";

    /// <summary>
    /// Checks if a Serilog Splunk logger was configured.
    /// </summary>
    /// <param name="configuration">The configuration to search for the logger in.</param>
    /// <param name="loggerNameConfigPath">The logger's name fields config path in the <c>appsettings.json</c> file.</param>
    /// <returns>If a Splunk logger name was found <c>true</c>; otherwise <c>false</c></returns>
    public static bool IsSplunkConfigured(this IConfiguration configuration, string loggerNameConfigPath = SplunkLoggerNamePath)
    {
        var loggerName = configuration.GetValue<string>(loggerNameConfigPath);

        return !string.IsNullOrWhiteSpace(loggerName);
    }

    /// <summary>
    /// Adds the meta data field <c>host</c> to the configuration, which is part of each Splunk event message.<br/>
    /// As this cannot be set as regular message property, it must be defined upfront for the EventCollector creation.
    /// This is because the application host name must be its value and it cannot be resolved dynamically.
    /// </summary>
    /// <param name="configuration">The configuration to extend by the <c>host</c> field incl. value.</param>
    /// <param name="hostName">The host name's value to set</param>
    /// <param name="hostConfigPath">The <c>host</c> field path in the <c>appsettings.json</c> file.</param>
    public static void SetSplunkHost(this IConfiguration configuration, string hostName, string hostConfigPath = SplunkLoggerHostPath)
    {
        configuration[hostConfigPath] = hostName;
    }
}

Attachements

Workaround-serilog-sinks-splunk_host-field.zip

HaGGi13 commented 1 year ago

I am sorry, this should be added to the Arc4u project and not Guidance. If this is an issue, may I ask you to move this issue to the Arc4u project?

HaGGi13 commented 6 months ago

I have no clue why this was marked as a bug instead of an enhancement, as I have had selected the "new feature" template, but do you have any progress or ideas to share on that?

Thanks.