question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Multi log-table support?

See original GitHub issue

Hiya,

I’ve got the following setup, where i have 2 webapis and 1 hangfire backouground service running. They all log to different tables with serilog’s MSSQL sink:

image

I’d love if the ui would support multiple services in some way.

I imagine something like:

        services.AddSerilogUi(options => options.UseSqlServer(_defaultConnectionString, "WebApi", "AppLogs"));
        services.AddSerilogUi(options => options.UseSqlServer(_defaultConnectionString, "AuthApi", "AppLogs"));
        services.AddSerilogUi(options => options.UseSqlServer(_defaultConnectionString, "Hangfire", "AppLogs"));

      ...
     app.UseSerilogUi(x => x.Endpoint("/applogs/webapi"));
     app.UseSerilogUi(x => x.Endpoint("/applogs/authapi"));
     app.UseSerilogUi(x => x.Endpoint("/applogs/hangfire"));

But that doesn’t work since UseSqlServer registers a singleton that is used for any SqlServerDataProviders:

((ISerilogUiOptionsBuilder) optionsBuilder).Services.AddSingleton<RelationalDbOptions>(implementationInstance);.

I could also use one single logging table for all services, but then i’d need to be able to filter per application (an enrichter and a way to filter a spec. log property?).

Any ideas?

Issue Analytics

  • State:open
  • Created 2 years ago
  • Comments:13 (10 by maintainers)

github_iconTop GitHub Comments

1reaction
sommmencommented, May 20, 2022

Hi @sommmen cc @mo-esmp

Do you think something similar to https://github.com/followynne/serilog-ui/tree/feat/multi-table-reads could work? I tried this simple implementation that would work with the UI dropdown you mentioned in an earlier comment. I kept the current configuration as easy as possible, as it’s just a test, but I think the string[] could be expanded with overrides to match other use cases:

  • it could become an IEnumerable, to bind different configs objects in depth
  • it could become a separate interface, that the user implements to create dynamic configs (ex: reading a dynamic source to retrieve connection strings, and table names… even after the service registration)

I gave a look at the IOptions registration, which is interesting but it would require creating different serilog-ui pages. If you think it would be a better option to create 1 separate page than choosing the queried table from a dropdown, we could explore it…

Let me know!

Hiya,

I myself was thinking more in the line of registering multiple providers or services, i don’t feel like a provider should be able to handle multiple tables, its only there to provide data.

Just cloned the repo so ill take a stroll through the code, your solution seems very easy to implement so perhaps thats a good way to move forward.

2 unrelated remarks:

  • First time building the app failed, i had to run npm install outside vs and then it seemed to work. unfortunately npm kept some files hostage so the build did not complete untill i closed the console host but hey thats a common issue so i recognized it quickly.
  • You refactored the method UseMySqlServer its a public method and part of the lib interface so i’d suggest creating an override or adding optional properties so you don’t break the interface and library consumers dont have to update code unnecesarily - i understand this is just a proto ofc.
1reaction
sommmencommented, Jan 13, 2022

Could you please provide some codes on how to setup Serilog to log data in multiple tables in an ASP.NET Core application?

Here’s a sample project to emulate the situation, one console app with 3 mssql sinks all pushing to 3 different tables.

SerilogUiMultiDbSample.zip

using System.Diagnostics;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Serilog;
using Serilog.Debugging;
using Serilog.Events;
using SerilogUiMultiDbSample;

SelfLog.Enable(msg =>
{
    Console.WriteLine(msg);
    Trace.WriteLine(msg);
    Debug.WriteLine(msg);

    if (Debugger.IsAttached)
        Debugger.Break();
});

Log.Logger = new LoggerConfiguration()
    .MinimumLevel.Debug()
    .MinimumLevel.Override("Microsoft", LogEventLevel.Information)
    .Enrich.FromLogContext()
    .WriteTo.Console()
    .CreateLogger();

try
{
    var host = Host
        .CreateDefaultBuilder()
        .ConfigureServices(services => { services.AddHostedService<TestBackgroundService>(); })
        .UseSerilog((context, loggerConfig) =>
        {
            loggerConfig
                .ReadFrom
                .Configuration(context.Configuration);
        })
        .Build();

    host.Run();
}
catch (Exception ex)
{
    Log.Error(ex, "Caught ex");
}
finally
{
    Log.CloseAndFlush();
}
using System.Numerics;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace SerilogUiMultiDbSample
{
    internal class TestBackgroundService : BackgroundService
    {
        private ILogger<TestBackgroundService> _logger;

        public TestBackgroundService(ILogger<TestBackgroundService> logger)
        {
            _logger = logger;
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            _logger.LogInformation("Starting right now!");

            while (!stoppingToken.IsCancellationRequested)
            {
                await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken: stoppingToken);

                var rand = new Random();

                using (_logger.BeginScope(new Dictionary<string, object>()
                       {
                           {"ARandomPropertyForSerilog", rand.Next(0, 420)},
                           {"DateTimeNow", DateTime.Now}
                       }))
                {
                    _logger.LogInformation("{DateTimeString} Big ben will bong {times} times.", DateTime.Now.ToString("T"), DateTime.Now.Hour);
                }
            }
        }
    }
}
{
  "ConnectionStrings": {
    "DefaultConnection": "Server=localhost\\SQLEXPRESS;Database=Test;User Id=sa;Password=opg;Trusted_Connection=False;Encrypt=False;MultipleActiveResultSets=True"
  },
  "Serilog": {
    "MinimumLevel": {
      "Default": "Information",
      "Override": {
        "Microsoft": "Warning",
        "Microsoft.Hosting.Lifetime": "Information",
        "System": "Warning",
        "System.Net.Http.HttpClient": "Warning",
        "Hangfire": "Warning"
      }
    },
    "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.MSSqlServer" ],
    "Enrich": [ "FromLogContext" ],
    "WriteTo": [
      {
        "Name": "Console",
        "Args": {
          "outputTemplate": "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj} {SourceContext}{NewLine}{Exception}"
        }
      },
      {
        "Name": "MSSqlServer",
        "Args": {
          "connectionString": "DefaultConnection",
          "sinkOptionsSection": {
            "tableName": "WebApi",
            "schemaName": "AppLog",
            "autoCreateSqlTable": true
          }
        }
      },
      {
        "Name": "MSSqlServer",
        "Args": {
          "connectionString": "DefaultConnection",
          "sinkOptionsSection": {
            "tableName": "AuthApi",
            "schemaName": "AppLog",
            "autoCreateSqlTable": true
          }
        }
      },
      {
        "Name": "MSSqlServer",
        "Args": {
          "connectionString": "DefaultConnection",
          "sinkOptionsSection": {
            "tableName": "Hangfire",
            "schemaName": "AppLog",
            "autoCreateSqlTable": true
          }
        }
      }
    ]
  }
}

EDIT: Oops - thats a normal net core project - not ASP. I read over that. The exact same code can be applied to an asp net core project though - is this ok for you?

Read more comments on GitHub >

github_iconTop Results From Across the Web

Tree Log Table Base - Etsy
Beautiful sanded Teak Wood log base, great for use as a stool, coffee table with glass top, end table, solid wood furniture, ready...
Read more >
table base for glass top dining table - Amazon.com
Design 59 Metal Dining Table Legs, Table Base for Desk, Kitchen, Restaurant & ... Powell Natural Wood Glass Top Parnell X Base Dining...
Read more >
How To: Log Slice Side Table - YouTube
Follow along as I make a side table out of a slice off an old red oak log.The legs are steel, 1"x1" square...
Read more >
How To Build a Solid Wood Table Top - YouTube
Subscribe now and never miss a new video! In this video you'll learn How To Build a Solid Wood Table Top from a...
Read more >
Wholesale wood multi table For Amazing Dining Settings
You can shop for wood multi table at Alibaba.com to get beautiful dining tables with designs. Find wholesale wood multi table here to...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found