Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Streaming events: can't deserialize Trace level (writing events with MS.Ext.Logging) #127

Open
migajek opened this issue Dec 1, 2023 · 5 comments

Comments

@migajek
Copy link

migajek commented Dec 1, 2023

tl;dr:
When writing logs with MS Ext Logging and streaming them back to application as demonstrated in this library documentation, deserializing LogEvent using LogEventReader.ReadFromJObject fails with exception "Requested value 'Trace' was not found".

long verson:
I'm using Seq as a logging storage for Microsoft.Extensions.Logging based app (using Seq.Extensions.Logging)
Therefore the message levels stored in Seq are levels defined by MS Ext Logging.

When streaming events back to the application, the documentation states the events should be deserialized into Serilog's LogEvent instances (using LogEventReader.ReadFromJObject) - unfortunately, the level is Serilog's LogEventLevel which is not compatible with MS Ext Logging levels (Trace vs Verbose and Critical vs Fatal)

Technical aspects of the issue aside, I find it a little inconsistent:

  • using SeqConnection.Events.Find / List methods, we deal with Seq's EventEntity (which defines Level as string so we're fine here)
  • using SeqConnection.Events.Stream method we deal with the Serilog's LogEvent json representation for some reason
@migajek
Copy link
Author

migajek commented Dec 1, 2023

Quick and a little dirty workaround for now:

_stream
                .Select(FixEntryLoggingLevel)
                .Select(LogEventReader.ReadFromJObject)
                .Subscribe(...)

...

  private static JObject FixEntryLoggingLevel(JObject entry)
    {
        if (!entry.TryGetValue("@l", out var levelToken))
        {
            return entry;
        }

        var value = levelToken?.Value<string>();
        entry["@l"] = value switch
        {
            "Trace" => "Verbose",
            "None" => "Verbose",
            "Critical" => "Fatal",
            _ => value
        };
        return entry;
    }

@nblumhardt
Copy link
Member

Hi @migajek; thanks for raising this.

LogEventReader is part of Serilog.Formatting.Compact.Reader, which this package doesn't depend on or use; unfortunately it's a Serilog component and will likely only work when the events originated from Serilog.

The JSON transformation trick you're using here is probably the best way to go, for now; having it mentioned here will hopefully help anyone who hits this to work around it in the future 👍

@migajek
Copy link
Author

migajek commented Dec 4, 2023

Hi @nblumhardt, thanks - I understand LogEventReader belongs to Serilog - I'm not however suggesting the change to how reader works, rather what the API exposes :)

I don't really understand why Seq provides different JSON representation for streaming API, comparing to fetching API. I suppose you have good reasons for that (be it performance or some internal technical considerations).

However , if I may suggest - I'd consider providing the same EventEntity on both surface APIs.

I am assuming my usage scenario might be quite common - I'm combining past and incoming events together: fetch last N events for given filter, and subscribe to incoming events using the same filter.
It just feels strange to use two different models for the same piece of data :)

@nblumhardt
Copy link
Member

That makes sense - thanks @migajek. Does need some more thought at our end 👍

@migajek
Copy link
Author

migajek commented Dec 5, 2023

thanks :) sure, I'm fine with the workaround for now. Will keep an eye on this
cheers

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants