Git Product home page Git Product logo

serilog-ui's Introduction

serilog-ui GitHub release (latest by date)

DotNET-build DotNET Coverage Quality Gate Status

JS-build Coverage Quality Gate Status

A simple Serilog log viewer for the following sinks:

  • Serilog.Sinks.MSSqlServer (Nuget)
  • Serilog.Sinks.MySql (Nuget) and Serilog.Sinks.MariaDB Nuget
  • Serilog.Sinks.Postgresql (Nuget)
  • Serilog.Sinks.MongoDB (Nuget)
  • Serilog.Sinks.ElasticSearch (Nuget)
  • Serilog.Sinks.RavenDB (Nuget)

Quick Start ๐Ÿ’จ

Nuget packages installation

Install the Serilog.UI NuGet package:

# using dotnet cli
dotnet add package Serilog.UI

# using package manager:
Install-Package Serilog.UI

Install one of the available providers, based upon your sink:

Provider install: dotnet install: pkg manager
Serilog.UI.MsSqlServerProvider [NuGet] dotnet add package Serilog.UI.MsSqlServerProvider Install-Package Serilog.UI.MsSqlServerProvider
Serilog.UI.MySqlProvider [NuGet] dotnet add package Serilog.UI.MySqlProvider Install-Package Serilog.UI.MySqlProvider
Serilog.UI.PostgreSqlProvider [NuGet] dotnet add package Serilog.UI.PostgreSqlProvider Install-Package Serilog.UI.PostgreSqlProvider
Serilog.UI.MongoDbProvider [NuGet] dotnet add package Serilog.UI.MongoDbProvider Install-Package Serilog.UI.MongoDbProvider
Serilog.UI.ElasticSearchProvider [NuGet] dotnet add package Serilog.UI.ElasticSearchProvider Install-Package Serilog.UI.ElasticSearchProvider
Serilog.UI.RavenDbProvider [NuGet] dotnet add package Serilog.UI.RavenDbProvider Install-Package Serilog.UI.RavenDbProvider

DI registration

Add AddSerilogUi() to IServiceCollection in your Startup.ConfigureServices method:

public void ConfigureServices(IServiceCollection services)
{
    // Register the serilog UI services
    services.AddSerilogUi(options => 
      // each provider exposes extension methods to configure.
      // example with MSSqlServerProvider:
      options.UseSqlServer("ConnectionString", "LogTableName"));
}

In the Startup.Configure method, enable the middleware to serve the log UI page. Note: call to the UseSerilogUi middleware must be placed after any Authentication and Authorization middleware, otherwise the authentication may not work:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    (...)

    app.UseRouting();
    app.UseAuthentication();
    app.UseAuthorization();
        
    // Enable middleware to serve log-ui (HTML, JS, CSS, etc.).
    app.UseSerilogUi();

    (...)

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");
    });
}

For further configuration: โฉ

Running the Tests: ๐Ÿงช

License

See LICENSE.

Issues and Contribution

Everything is welcome! ๐Ÿ† See the contribution guidelines for details.

Support

Thank you JetBrains for supporting this project.

JetBrains Logo (Main) logo

serilog-ui's People

Contributors

chaadfh avatar dependabot[bot] avatar followynne avatar hansoncaleb avatar igece avatar jorgevp avatar mesmailpour-spectra avatar millarex avatar mo-esmp avatar phillduffy avatar ricardodemauro avatar sommmen avatar traien avatar uthmanrahimi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

serilog-ui's Issues

Add back EnableAuthorization or provide equivalent example

First of all, great project, thanks for your work on this.

I've been using this in a work project for a few months now and updated to the latest version today only to find out my project wouldn't build any longer because of the removal of "EnableAuthorization"

Can I ask why this was removed and if there is any place I can look out for breaking changes like this to be communicated in the future?

I had to look at the commit history to make sure I wasn't crazy since there didn't seem to be a mention of its removal in the readme:

0ec5684#diff-b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5L89

I thought it was a very useful feature. If there aren't any plans to add it back, do you think we could get an equivalent example on the readme instead of the trimmed down "isAuthenticated" one?

Thanks

Feature: Allow custom authorization

Hiya,

Right now i keep having to add my token into the log view - this can be a bit tedious.
Would it be possible to use authorization the same way hangfire does, by allowing custom Authorization filters?

See:
https://docs.hangfire.io/en/latest/configuration/using-dashboard.html

The code looks simple enough from a first glance:

public interface IDashboardAsyncAuthorizationFilter
{
Task<bool> AuthorizeAsync([NotNull] DashboardContext context);
}

Hangfire.Dashboard.AspNetCoreDashboardMiddleware

foreach (IDashboardAuthorizationFilter authorizationFilter in this._options.Authorization)
{
  if (!authorizationFilter.Authorize((DashboardContext) context))
  {
    httpContext.Response.StatusCode = AspNetCoreDashboardMiddleware.GetUnauthorizedStatusCode(httpContext);
    context = (AspNetCoreDashboardContext) null;
    findResult = (Tuple<IDashboardDispatcher, Match>) null;
    return;
  }
}
foreach (IDashboardAsyncAuthorizationFilter authorizationFilter in this._options.AsyncAuthorization)
{
  if (!await authorizationFilter.AuthorizeAsync((DashboardContext) context))
  {
    httpContext.Response.StatusCode = AspNetCoreDashboardMiddleware.GetUnauthorizedStatusCode(httpContext);
    context = (AspNetCoreDashboardContext) null;
    findResult = (Tuple<IDashboardDispatcher, Match>) null;
    return;
  }
}

Startup:

endpoints.MapHangfireDashboard(new DashboardOptions
            {
                AsyncAuthorization = new[] {
                    new MyHangfireAuthenticationFilter(
                        new(
                            authApiUrl,
                            publicKeyUrl
                        ),
                        services.GetRequiredService<ILogger<MYHangfireAuthenticationFilter>>()
                    )
                }
            });

Custom filter:

public class MyHangfireAuthenticationFilter : IDashboardAsyncAuthorizationFilter
{
     ....
   public async Task<bool> AuthorizeAsync(DashboardContext context)
    {
        var httpContext = context.GetHttpContext();

        if (_options.ForceSsl && httpContext.Request.Scheme != "https")
        {

            var redirectUri = new UriBuilder("https", httpContext.Request.Host.ToString(), 443, httpContext.Request.Path).ToString();
            httpContext.Response.Redirect(redirectUri, true);

            return false;
        }

        // If cookie has a JWT token we don't have to send a request to the auth api, we can just validate the token
        if (httpContext.Request.Cookies.ContainsKey("token"))
        {
            try
            {
                _ = new JwtSecurityTokenHandler()
                    .ValidateToken(httpContext.Request.Cookies["token"],
                        new()
                        {
                            ClockSkew = TimeSpan.Zero,
                            ValidateAudience = false,
                            ValidateIssuer = false,
                            ValidateIssuerSigningKey = true,
                            ValidateLifetime = true,
                            IssuerSigningKey = await GetSecurityKey()
                        }, out _);

                return true;
            }
            catch(Exception ex)
            {
                // Validation failed
                _logger.LogError(ex, ex.Message);
            }
        }

        // No token or invalid token, check for basic auth headers to validate
        var authHeader = httpContext.Request.Headers["Authorization"];
        if (!string.IsNullOrWhiteSpace(authHeader))
        {
            var authValues = AuthenticationHeaderValue.Parse(authHeader);

            if (authValues.Scheme.Equals("Basic", StringComparison.InvariantCultureIgnoreCase))
            {
                if (string.IsNullOrWhiteSpace(authValues.Parameter))
                    throw new("string.IsNullOrWhiteSpace(authValues.Parameter)");

                var authString = Encoding.UTF8.GetString(Convert.FromBase64String(authValues.Parameter));

                var parts = authString.Split(':', 2);
                if (parts.Length == 2)
                {
                    var body = new
                    {
                        Email = parts[0],
                        Password = parts[1]
                    };
                    try
                    {
                        var content = new StringContent(JsonSerializer.Serialize(body), Encoding.UTF8,
                            "application/json");

                        // Some custom auth logic with an external server
                        var result = await HttpClient.PostAsync($"{_options.AuthUrl}/api/authorize/login", content);
                        if (result.IsSuccessStatusCode)
                        {
                            var response = await result.Content.ReadAsStringAsync();
                            var jsonResponse = JsonSerializer.Deserialize<JsonDocument>(response) ?? throw new NullReferenceException("JsonSerializer.Deserialize<JsonDocument>(response)");
                            var token = jsonResponse.RootElement.GetProperty("token").GetString() ?? throw new NullReferenceException("jsonResponse.RootElement.GetProperty(\"token\").GetString()");
                            httpContext.Response.Cookies.Append("token", token);


                            return true;
                        }
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError(ex, ex.Message);
                    }

                }
            }
        }

        await ShowChallenge(httpContext);

        return false;
    }
        
    private async Task ShowChallenge(HttpContext context)
    {
        context.Response.StatusCode = 401;
        context.Response.Headers.Append("WWW-Authenticate", "Basic realm=\"Hangfire Dashboard\"");

        await context.Response.Body.WriteAsync(Encoding.UTF8.GetBytes("Authentication is required."));
    }

    private async ValueTask<SecurityKey> GetSecurityKey()
    {
        if (_key == null)
        {
            _key = ParsePublicKey(await HttpClient.GetStringAsync(_options.CertificateUrl));
        }

        return _key;
    }

    private RsaSecurityKey ParsePublicKey(string key)
    {
        var rsa = RSA.Create();
        var cert = new X509Certificate(Encoding.UTF8.GetBytes(key));

        rsa.ImportRSAPublicKey(cert.GetPublicKey(), out _);
        return new(rsa);
    }

}

public readonly struct HangfireAuthenticationOptions
{
    public string AuthUrl { get; }
    public string CertificateUrl { get; }
    public bool ForceSsl { get; }


    public HangfireAuthenticationOptions(string url, string certificateUrl, bool forceSsl = true)
    {
        AuthUrl = url;
        CertificateUrl = certificateUrl;
        ForceSsl = forceSsl;
    }

}

This way we'll get the native browser login modal, which makes it easy to log in (especially since the browser can remember my account details)

image

I'd prefer:

  • An Async interface
  • DI so that i can inject an ILogger

Deployed to developent, UI popup "You are not authorized to access logs"

Describe the bug
When we deploy our code to development and we go to serlog-ui, we get this popup: "You are not authorized to access logs"

To Reproduce
Steps to reproduce the behavior:

  1. /serilog-ui/index.html

Expected behavior
The grid with logs is shown instead of a popup

Screenshots
image

Desktop (please complete the following information):

  • OS: MacOs but app is deployed to K8S
  • Browser Chrome

When I am using MongoDb Sink provider Exception and properties column not populating in serilog.Ui

I configured MongoDB BSON Sink for logging details in a MongoDB database, and I can see the properties and Exception fields inside the collection with the exact exception which I am getting from the service, but Serilog.UI cannot bind the exception and property columns in the Serilog.UI grid.

I debugged the Serilog.UI.MongoDbProvider, and I tested the same code in my local repository. I observed that in the MongoDbDataProvider.cs class, the logs are not getting the exception and properties from the collection.

I'm not sure, but maybe I need to format the data while sinking. Can anyone please help me out with this issue?

I used the same code from Serilog.UI.MongoDbProvider for testing I got the result but with Exception field
IMG-0007

BUG: processor architecture mismatch

Hiya,

The MSSQL provider faults with a weird error:

warning MSB3270: There was a mismatch between the processor architecture of the project being built "MSIL" and the processor architecture of the reference "C:\Users\31611\.nuget\packages\serilog.ui.mssqlserverprovider\2.1.0\lib\netstandard2.0\Serilog.Ui.MsSqlServerProvider.dll", "AMD64". This mismatch may cause runtime failures. Please consider changing the targeted processor architecture of your project through the Configuration Manager so as to align the processor architectures between your project and references, or take a dependency on references with a processor architecture that matches the targeted processor architecture of your project.

Perhaps this is because of the following props in the .csproj?:

  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
    <PlatformTarget>x64</PlatformTarget>
    <WarningLevel>0</WarningLevel>
  </PropertyGroup>

I'm running a net6 project that looks like this:

<Project Sdk="Microsoft.NET.Sdk.Web">

	<PropertyGroup>
		<TargetFramework>net6.0</TargetFramework>
		<UserSecretsId>0844be79-0a19-44df-845c-fdb74a50cfb0</UserSecretsId>
		<RootNamespace>Comp.WebApi</RootNamespace>
		<ImplicitUsings>enable</ImplicitUsings>
	</PropertyGroup>

	<PropertyGroup>
		<GenerateDocumentationFile>true</GenerateDocumentationFile>
		<NoWarn>$(NoWarn);1591</NoWarn>
	</PropertyGroup>

	<PropertyGroup>
		<!-- See: https://docs.microsoft.com/en-us/aspnet/core/web-api/advanced/analyzers?view=aspnetcore-5.0&tabs=visual-studio -->
		<IncludeOpenAPIAnalyzers>true</IncludeOpenAPIAnalyzers>
	</PropertyGroup>

	<ItemGroup>
		<PackageReference Include="AutoMapper" Version="11.0.0" />
		<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="11.0.0" />
		<PackageReference Include="Hangfire.AspNetCore" Version="1.7.28" />
		<PackageReference Include="Hangfire.Console" Version="1.4.2" />
		<PackageReference Include="Hangfire.SqlServer" Version="1.7.28" />
		<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.1" />
		<PackageReference Include="Microsoft.BingAds.SDK" Version="13.0.12" />
		<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.1" />
		<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.1">
			<PrivateAssets>all</PrivateAssets>
			<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
		</PackageReference>
		<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.1" />
		<PackageReference Include="Microsoft.OData.Client" Version="7.9.4" />
		<PackageReference Include="Serilog.UI" Version="2.1.1" />
		<PackageReference Include="Serilog.UI.MsSqlServerProvider" Version="2.1.0" />
		<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
		<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
		<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.14.1" />
	</ItemGroup>

       ...

</Project>

FetchDataAsync missing when update to 2.1.0

I am getting following exception when using Serilog.UI 2.1.0. Was working for 2.0.0.

TypeLoadException: Method 'FetchDataAsync' in type 'Serilog.Ui.MsSqlServerProvider.SqlServerDataProvider' from assembly 'Serilog.Ui.MsSqlServerProvider, Version=1.0.6.0, Culture=neutral, PublicKeyToken=null' does not have an implementation.

I am still using MsSqlServerProvider 1.0.6 because from 2.0.0 onward, I get a compilation error which cause my Asp.net Core 3.1 project not loading when deployed to Azure.

C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\MSBuild\Current\Bin\Microsoft.Common.CurrentVersion.targets(2182,5): warning MSB3270: There was a mismatch between the processor architecture of the project being built "MSIL" and the processor architecture of the reference "C:\Users\hcchoi\.nuget\packages\serilog.ui.mssqlserverprovider\2.0.0\lib\netstandard2.0\Serilog.Ui.MsSqlServerProvider.dll", "AMD64". This mismatch may cause runtime failures. Please consider changing the targeted processor architecture of your project through the Configuration Manager so as to align the processor architectures between your project and references, or take a dependency on references with a processor architecture that matches the targeted processor architecture of your project.

XML output isn't rendered correctly

Describe the bug
Opening the properties details view multiple times does funny things to rendered xml. <test> becomes &lt;test&gt;, closing and opening another time will produce &amp;lt;test&amp;gt;

To Reproduce
Steps to reproduce the behavior:

  1. Go to dashboard
  2. Click on 'View'
  3. Close dialog
  4. Click on 'View' again
  5. See < being converted to <

Expected behavior
The details dialog should show xml tags.

Screenshots
image

Desktop (please complete the following information):

  • OS: Windows
  • Browser: Edge
  • Version: 120

Smartphone (please complete the following information):

  • Device: [e.g. iPhone6]
  • OS: [e.g. iOS8.1]
  • Browser [e.g. stock browser, safari]
  • Version [e.g. 22]

Additional context
Add any other context about the problem here.

Support provider name customization

Is your feature request related to a problem? Please describe.
As an end user, I'd love to be able to customize the name of the Provider Name that can be viewed in the UI dropdown.

Describe the solution you'd like
I'd love to be able to customize the Provider Name when I register the provider in the service provider, using an optional parameter or an extension method.

Additional context
As per request from comment in #66

Multi log-table support?

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?

BUG: when opening properties for the second time, the tags are escaped twice

Describe the bug
A clear and concise description of what the bug is.

To Reproduce
Steps to reproduce the behavior:

firefox_UArZiBs7kZ.mp4
  1. Open properties of a row
  2. Close the modal
  3. Open again
  4. Observe that <``> are encoded.

Expected behavior
A clear and concise description of what you expected to happen.

Screenshots
If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

  • OS: [e.g. iOS]
  • Browser [e.g. chrome, safari]
  • Version [e.g. 22]

Win11, tested with firefox and chrome

Smartphone (please complete the following information):

  • Device: [e.g. iPhone6]
  • OS: [e.g. iOS8.1]
  • Browser [e.g. stock browser, safari]
  • Version [e.g. 22]

Additional context
Add any other context about the problem here.

Taking a quick look now.

Fails to insert data into MariaDB

Describe the bug
logs table doesn't get created and fails on inserting data

MariaDb is 11.2

Here is my appsettings.development.json:
image

And my connection string:
image

Here is how I use and configure logger, which works fine for files and console:
image

To Reproduce
image

Expected behavior
Should insert data into database

Screenshots
If applicable, add screenshots to help explain your problem.
image

This looks to me like failed insert into logs database. It doesn't get automatically created even thou I set autoCreateTable": true,
After I manually create logs table, this is what happens when I try to reach SerilogUI web page.

An error occurred while deserializing the Exception property of class Serilog.Ui.MongoDbProvider.MongoDbLogModel: Cannot deserialize a 'String' from BsonType 'Document'.

Hello, I just configured Serilog with mongo db, and Serlilog ui to see the logs, but the error show in an alert box as soon as page opens.

not: ฤฑ can see logs in mongodb compass software.

An error occurred while deserializing the Exception property of class Serilog.Ui.MongoDbProvider.MongoDbLogModel: Cannot deserialize a 'String' from BsonType 'Document'.

serilog version: 2.1
asp.net core version: 5
mongodb version: 5.0.2

Add date range filter

Would be good if provided some date range filter (between this and that date).

Thanks

Could not load file or assembly 'Serilog.Ui.Core, Version=2.1.0'

Describe the bug
In production, i have 2 webapps and one background processor, both using nearly the same serilog configuration.
Recently some package upgrades came to my attention;

image

This build works locally, but for some reason not on my production server;

Unhandled exception. System.IO.FileNotFoundException: Could not load file or assembly 'Serilog.Ui.Core, Version=2.1.0.0, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified.
File name: 'Serilog.Ui.Core, Version=2.1.0.0, Culture=neutral, PublicKeyToken=null'
   at System.Reflection.RuntimeAssembly.InternalLoad(AssemblyName assemblyName, StackCrawlMark& stackMark, AssemblyLoadContext assemblyLoadContext, RuntimeAssembly requestingAssembly, Boolean throwOnFileNotFound)
   at System.Reflection.Assembly.Load(AssemblyName assemblyRef)
   at Serilog.Settings.Configuration.ConfigurationReader.LoadConfigurationAssemblies(IConfiguration section, AssemblyFinder assemblyFinder)
   at Serilog.Settings.Configuration.ConfigurationReader..ctor(IConfiguration configSection, AssemblyFinder assemblyFinder, ConfigurationReaderOptions readerOptions, IConfiguration configuration)
   at Serilog.ConfigurationLoggerConfigurationExtensions.GetConfigurationReader(IConfiguration configuration, ConfigurationReaderOptions readerOptions, DependencyContext dependencyContext)
   at Serilog.ConfigurationLoggerConfigurationExtensions.Configuration(LoggerSettingsConfiguration settingConfiguration, IConfiguration configuration, ConfigurationReaderOptions readerOptions)
  • Both web apps run under IIS and they both are not able to startup. The background processor seems to run fine - but it's hard to see.

I'm unsure why this happens and i'm curious if this impacts others, or any suggestions on what may cause this.

To Reproduce
Steps to reproduce the behavior:

Have not found a way to reproduce (yet) - but i'll hope to gather more information after some time.

Expected behavior
The app to startup normally.

Screenshots
If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

  • OS: Windows
  • Browser n/a
  • Version 2.4.0 (latest)

UseMongoDb should two parameters

UseMongoDb( this SerilogUiOptionsBuilder optionsBuilder, string connectionString, string databaseName, string collectionName )

because the connectionString contains the databaseName, so the databaseName is redundant.

About search and authorization,some advices

Hello boss,Currently using Serilog.UI.MongoDbProviderr
1.Search by date, can it be accurate to the second?
2.Search message ,Can you support Chinese search?
3.You can add username and password to authorize when authorizing, and the experience will be better.

The above three points are some of the problems that I encounter in my daily life. I hope that the boss will make changes. Thank you very much.

Is alert supported or is it on the roadmap?

I couldn't find any information about alert. Is it currently possible to configure alert based on certain constraints(such as error count, log level, and so on) and get notification on email, slack, or other means of communication? if not is it on the road map? I'd be happy to contribute.

Timestamp returned as Jan 1, 1901 0:00:00.000

Using Serilog.UI.MsSqlServerProvider all timestamps are displayed in the UI as 'Jan 1, 1901 0:00:00.000'

Screenshot 2023-10-31 164910-2

This stems from the value returned in the http request:

"timestamp": "0001-01-01T00:00:00"

However filtering by time period works fine so it seems to be able to read the datetime correctly for that purpose.

To Reproduce
Created an empty Blazor web app, added these packages:
Serilog.UI 2.5.0
Serilog.UI.MsSqlServerProvider 2.2.2

Only configuration was to specify the connection string, table name and schema using 'UseSqlServer'

Expected behavior
To display the datetimes from the database. Example rows from the table:

Screenshot 2023-10-31 165024

File based provider?

Hiya,

This seems exactly what a was looking for.
Only I have a File sink setup instead of sql.
Would it be feasible to implement a file-based provider for serilog-ui?

An excerpt of my log file;

[10:20:51 INF] Sulis python based parser: null {"SourceContext":"Tdc.GenesisMachine.RemoteData.Shared.Windows.ProcessRunner"}
[10:20:51 INF] Process Sulis python based parser exited with exit code 0 at 19-2-2021 10:20:51 {"SourceContext":"Tdc.GenesisMachine.RemoteData.Shared.Windows.ProcessRunner"}
[10:20:51 INF] Done running {"Name":"Sulis python based parser","WaitForExit":true,"DurationMilliseconds":882.0070000000001,"TimeOutMilliseconds":0,"ExitedWhenWaitingForTimeout":false,"exitLogInfo":{"ExitCode":0,"ExitTime":"2021-02-19T10:20:51.9647150+01:00"}} {"SourceContext":"Tdc.GenesisMachine.RemoteData.Shared.Windows.ProcessRunner"}
[10:30:31 INF] Skipping download of remote file /StaticFiles/TemboAnalyticsLogs_20201023.zip, local file ...\Tembo Paper - KAMPEN (NL) - Sulis_P02378_Line1\TDCNL_0045~TemboAnalyticsLogs_20201023.zip was up to date, Local file size: 7116022 vs remote file size: 7116022 {"SourceContext":"Tdc.GenesisMachine.RemoteData.Shared.HangFireJobs.RemoteDataFilePuller"}
[10:30:31 INF] Skipping download of remote file /StaticFiles/TemboAnalyticsLogs_20201026.zip, local file ...\Tembo Paper - KAMPEN (NL) - Sulis_P02378_Line1\TDCNL_0045~TemboAnalyticsLogs_20201026.zip was up to date, Local file size: 7393688 vs remote file size: 7393688 {"SourceContext":"Tdc.GenesisMachine.RemoteData.Shared.HangFireJobs.RemoteDataFilePuller"}
[10:30:31 INF] Skipping download of remote file /StaticFiles/TemboAnalyticsLogs_20201027.zip, local file ...\Tembo Paper - KAMPEN (NL) - Sulis_P02378_Line1\TDCNL_0045~TemboAnalyticsLogs_20201027.zip was up to date, Local file size: 7628661 vs remote file size: 7628661 {"SourceContext":"Tdc.GenesisMachine.RemoteData.Shared.HangFireJobs.RemoteDataFilePuller"}

The logging config is as follows:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information",
      "System.Net.Http.HttpClient": "Information",
      "Hangfire": "Information"
    }
  },
  "Serilog": {
    "Using": [ "Serilog.Sinks.Console" ],
    "WriteTo": [
      {
        "Name": "Console",
        "outPutTemplate": "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj} {Properties:j}{NewLine}{Exception}"
      },
      {
        "Name": "File",
        "Args": {
          "path": "%CUROUTDIR%\\..\\Logs\\RemoteData.WorkerService.txt",
          "rollingInterval": "Day",
          "rollOnFileSizeLimit": true,
          "retainedFileCountLimit": 31,
          "fileSizeLimitBytes": 5242880,
          "outPutTemplate": "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj} {Properties:j}{NewLine}{Exception}"
        }
      }
    ]
  }

I could of course change the template to something that would be easier to parse.
I'd just like your opinion if something like this would be feasible and perhaps I take a crack at it.

Adding another provider for sql server for a fancy log viewer seems a bit too much consider the scope of my project.
Although perhaps that's a common solution.

In anyway I want to keep file based logging.

Small issues

First of all thanks for creating this project, it is exactly what I was looking for.

A couple of small issues I noticed:

  1. As I am testing Serilog, my log table only contains 12 entries but the paging of the viewer does not work. It shows 5 pages, and as I click on each page it says for example "Showing 10 to 20 of 12 entries" but it shows entries 2- 11. On page 5 it says "Showing 40 to 50 of 12 entries" but shows entries 1 - 8.
  2. The properties view does not work in Firefox / IE, only in Chrome.
  3. Not sure if this is intentional but the main NuGet package is called Serilog.UI, but the provider package names start with Serilog.Ui (different casing).

Are you happy to accept pull requests to this project? I would like to add in custom column support and property searching at some stage.

"Error parsing column 3 (TimeStamp=1/29/2023 9:10:58 AM -06:00 - Object)\"}"

I am using the out of the box config for Serilog MSSQL writing. Not sure what it refers to as column 3 but the thrid column in SQL is the message template

Here is the error that it is throwing
errorMessage
:
"{"errorMessage":"Error parsing column 3 (TimeStamp=1/29/2023 9:10:58 AM -06:00 - Object)"}"

For reference
image

Error Message column does not exist

Using Postgresql provider I get the error message:

"errorMessage": "{"errorMessage":"42703: column \"message\" does not exist\r\n\r\nPOSITION: 8"}"

The column does exist in the table.

.net core 7, web api project
serilog.sinks.postgresql.alternative 4.0.2
serilog.ui.postgresqlprovider 2.2.2

table schema
CREATE TABLE IF NOT EXISTS "Logs" (
"Message" TEXT,
"MessageTemplate" TEXT,
"Level" INTEGER,
"Timestamp" TIMESTAMP WITH TIME ZONE,
"Exception" TEXT,
"LogEvent" JSONB
) USING HEAP;

builder.Services.AddSerilogUi(options =>
{
options.UseNpgSql(dbSettings["ConnectionString"], "Logs", "public");
});

What am I missing?

Thanks!

Insert log test data through sinks

Hence, reading log data from log data providers is dependent on log table schema; we should insert log data through sinks and not directly into the database. @followynne What do you think of this?

Ability to enable/disable authentication

I'm using the serilog ui in an isolated container that does not use the authorization and identity provider from the httpcontext. Since by design my service cannot use an account I would like to enable/disable the authentication in the ui when declaring the Authorization Options when declaring the Serilog UI service. I will submit a PR for this issue.

Any support for ColumnOptions?

As I'm using some additional columns in my log table I wanna know if are you supporting these kinds of column options.
If not can you recommend any workaround to display additional columns in the UI grid?

could not open a grid page where there is an SqlException

Error Message: Serilog.Ui.MongoDbProvider.MongoDbLogModel: Ambiguous discriminator 'SqlException'.

MongoDb Version: 4.4.5
Serilog UI MongoDb provider Version: 2.1.2
Serilog UI version: 2.1.2

Possible object in mongodb that causes error maybe as below:

{"_id":{"$oid":"61a8dadd1ab0e48d55b06626"},"Level":"Error","UtcTimeStamp":{"$date":"2021-12-02T14:40:30.436Z"},"MessageTemplate":{"Text":"An exception occurred while iterating over the results of a query for context type '{contextType}'.{newline}{error}","Tokens":[{"_t":"TextToken","StartIndex":0,"Text":"An exception occurred while iterating over the results of a query for context type '"},{"_t":"PropertyToken","StartIndex":84},{"_t":"TextToken","StartIndex":97,"Text":"'."},{"_t":"PropertyToken","StartIndex":99},{"_t":"PropertyToken","StartIndex":108}]},"RenderedMessage":"An exception occurred while iterating over the results of a query for context type '\"AcerPlatformV2.Infrastructure.LoggerDbContext\"'.\"\r\n\"\"Microsoft.Data.SqlClient.SqlException (0x80131904): Invalid object name 'SystemControlLogs'.\r\n   at Microsoft.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)\r\n   at Microsoft.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)\r\n   at Microsoft.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)\r\n   at Microsoft.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)\r\n   at Microsoft.Data.SqlClient.SqlDataReader.TryConsumeMetaData()\r\n   at Microsoft.Data.SqlClient.SqlDataReader.get_MetaData()\r\n   at Microsoft.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString, Boolean isInternal, Boolean forDescribeParameterEncryption, Boolean shouldCacheForAlwaysEncrypted)\r\n   at Microsoft.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean isAsync, Int32 timeout, Task& task, Boolean asyncWrite, Boolean inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest)\r\n   at Microsoft.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry, String method)\r\n   at Microsoft.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method)\r\n   at Microsoft.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior)\r\n   at Microsoft.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior)\r\n   at System.Data.Common.DbCommand.ExecuteReader()\r\n   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReader(RelationalCommandParameterObject parameterObject)\r\n   at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.Enumerator.InitializeReader(DbContext _, Boolean result)\r\n   at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)\r\n   at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.Enumerator.MoveNext()\r\nClientConnectionId:47fb5428-dd6e-4ff3-a4d4-03d1960792a9\r\nError Number:208,State:1,Class:16\"","Properties":{"contextType":"AcerPlatformV2.Infrastructure.LoggerDbContext","newline":"\r\n","error":"Microsoft.Data.SqlClient.SqlException (0x80131904): Invalid object name 'SystemControlLogs'.\r\n   at Microsoft.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)\r\n   at Microsoft.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)\r\n   at Microsoft.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)\r\n   at Microsoft.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)\r\n   at Microsoft.Data.SqlClient.SqlDataReader.TryConsumeMetaData()\r\n   at Microsoft.Data.SqlClient.SqlDataReader.get_MetaData()\r\n   at Microsoft.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString, Boolean isInternal, Boolean forDescribeParameterEncryption, Boolean shouldCacheForAlwaysEncrypted)\r\n   at Microsoft.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean isAsync, Int32 timeout, Task& task, Boolean asyncWrite, Boolean inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest)\r\n   at Microsoft.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry, String method)\r\n   at Microsoft.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method)\r\n   at Microsoft.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior)\r\n   at Microsoft.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior)\r\n   at System.Data.Common.DbCommand.ExecuteReader()\r\n   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReader(RelationalCommandParameterObject parameterObject)\r\n   at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.Enumerator.InitializeReader(DbContext _, Boolean result)\r\n   at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)\r\n   at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.Enumerator.MoveNext()\r\nClientConnectionId:47fb5428-dd6e-4ff3-a4d4-03d1960792a9\r\nError Number:208,State:1,Class:16","EventId":{"Id":10100,"Name":"Microsoft.EntityFrameworkCore.Query.QueryIterationFailed"},"SourceContext":"Microsoft.EntityFrameworkCore.Query"},"Exception":{"_t":"SqlException","HelpLink":null,"Source":"Core Microsoft SqlClient Data Provider","HResult":-2146232060,"Message":"Invalid object name 'SystemControlLogs'.","StackTrace":"   at Microsoft.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)\r\n   at Microsoft.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)\r\n   at Microsoft.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)\r\n   at Microsoft.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)\r\n   at Microsoft.Data.SqlClient.SqlDataReader.TryConsumeMetaData()\r\n   at Microsoft.Data.SqlClient.SqlDataReader.get_MetaData()\r\n   at Microsoft.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString, Boolean isInternal, Boolean forDescribeParameterEncryption, Boolean shouldCacheForAlwaysEncrypted)\r\n   at Microsoft.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean isAsync, Int32 timeout, Task& task, Boolean asyncWrite, Boolean inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest)\r\n   at Microsoft.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry, String method)\r\n   at Microsoft.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method)\r\n   at Microsoft.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior)\r\n   at Microsoft.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior)\r\n   at System.Data.Common.DbCommand.ExecuteReader()\r\n   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReader(RelationalCommandParameterObject parameterObject)\r\n   at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.Enumerator.InitializeReader(DbContext _, Boolean result)\r\n   at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)\r\n   at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.Enumerator.MoveNext()\r\n   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)\r\n   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)\r\n   at AcerPlatformV2.Business.Services.SystemControlLogService.GetLastLogs(Int32 logCount) in D:\\MT\\Projects\\GatewayProUI.git\\AcerPlatformV2.Business\\Services\\SystemControlLogService.cs:line 108\r\n   at AcerPlatformV2.Presentation.ModelServices.MonitoringModelService.SystemControlErrorLogNotification() in D:\\MT\\Projects\\GatewayProUI.git\\AcerPlatformV2.Presentation\\ModelServices\\MonitoringModelService.cs:line 112\r\n   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()","Data":{"HelpLink-ProdName":"Microsoft SQL Server","HelpLink-ProdVer":"13.00.4001","HelpLink-EvtSrc":"MSSQLServer","HelpLink-EvtID":"208","HelpLink-BaseHelpUrl":"http://go.microsoft.com/fwlink","HelpLink-LinkId":"20476"}}}

SQLite support

Hi,
it's SQLite support considered in a near future?

I could consider trying a PR if necessary.

Thank you!

Npgsql DateTime filtering problem

Hi.
I use NpgSql 7.0.2 with Postgres 14, DotNet 7
While sort by TimeStamp i had error:
photo_2023-08-23_14-55-23

NpgSql > 6.0.0 have dateTime breaking changes:
image

I think adding a parameter to the incoming date UTS should solve the error that occurs.
Like: DateTime.SpecifyKind(entryDateTimeValue, DateTimeKind.Utc);

Bug? js file does not load

Serilog no longer loads issues for me and i'm seeing the following error in the browser:

GET https://[REDACTED]/serilog-ui/index.6bbf471b.js net::ERR_ABORTED 404

Any clues what is going on?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.