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

Log using Microsoft.Extensions.Logging.Abstractions; implement WpfProgram #255

Merged
merged 16 commits into from
Aug 11, 2020
Merged

Log using Microsoft.Extensions.Logging.Abstractions; implement WpfProgram #255

merged 16 commits into from
Aug 11, 2020

Conversation

cmeeren
Copy link
Member

@cmeeren cmeeren commented Aug 7, 2020

Fixes #105

Logging implemented using Microsoft.Extensions.Logging.Abstractions.

I also had to create a separate Program type for Elmish.WPF. I think that has been mentioned/discussed previously, can't remember where.

Log levels can be discussed, but I think they are uncontroversial - most of what we log fits with Trace semantics (the most verbose level of logging), and other than that there are just a few Warnings.

image

Client usage is very simple and I'd say well-known in .NET. The samples are now using Serilog.

At a minimum, if users want to see logs from Elmish.WPF using Serilog, they have to install Serilog.Extensions.Logging (and a chosen sink, e.g. Serilog.Sinks.Console). The Serilog logger is initialized as normal (e.g. the static logger):

Log.Logger <- LoggerConfiguration().WriteTo.Console().CreateLogger()

Then users simply use SerilogLoggerFactory in the call to WpfProgram.withLogger:

WpfProgram.mkSimple (fun () -> init) update bindings
  |> WpfProgram.withLogger (new SerilogLoggerFactory())
  |> WpfProgram.runWindow window

Currently we log to four categories which the user can control. To see everything (as in the samples), users must do something similar to this:

LoggerConfiguration()
  .MinimumLevel.Override("Elmish.Messages", Events.LogEventLevel.Verbose)
  .MinimumLevel.Override("Elmish.State", Events.LogEventLevel.Verbose)
  .MinimumLevel.Override("Elmish.WPF.Bindings", Events.LogEventLevel.Verbose)
  .MinimumLevel.Override("Elmish.WPF.BindingPerformance", Events.LogEventLevel.Verbose)
  .WriteTo.Console()

(If they really just want it all, they can use .MinimumLevel.Verbose() instead of the four lines above, but I chose to use those four lines in the samples to clearly show how to opt into specific kinds of logs.)

I really like this way of logging and find it a good fit for Elmish.WPF. IMHO the dependency on Microsoft.Extensions.Logging.Abstractions is entirely unproblematic. The users have control over logging without having to write a lot of custom boilerplate.

Heck, even the "lazy" behavior of binding measure logs is preserved this way. If Trace (Verbose in Serilog) is not enabled for the Elmish.WPF.BindingPerformance category, then no measurements are performed.

We can of course adjust the categories if we want.

@TysonMN

This comment has been minimized.

@TysonMN
Copy link
Member

TysonMN commented Aug 8, 2020

LoggerConfiguration()
  .MinimumLevel.Override("Elmish.Messages", Events.LogEventLevel.Verbose)
  .MinimumLevel.Override("Elmish.State", Events.LogEventLevel.Verbose)
  .MinimumLevel.Override("Elmish.WPF.Bindings", Events.LogEventLevel.Verbose)
  .MinimumLevel.Override("Elmish.WPF.BindingPerformance", Events.LogEventLevel.Verbose)
  .WriteTo.Console()

What do you think about extracting those strings to reduce the magic to something like this? Then auto-complete would help the user more quickly type these from scratch and get them correct.

LoggerConfiguration()
  .MinimumLevel.Override(LoggerName.Elmish.Messages, Events.LogEventLevel.Verbose)
  .MinimumLevel.Override(LoggerName.Elmish.State, Events.LogEventLevel.Verbose)
  .MinimumLevel.Override(LoggerName.Elmish.WPF.Bindings, Events.LogEventLevel.Verbose)
  .MinimumLevel.Override(LoggerName.Elmish.WPF.BindingPerformance, Events.LogEventLevel.Verbose)
  .WriteTo.Console()

@cmeeren
Copy link
Member Author

cmeeren commented Aug 8, 2020

I vote for 1.

Yes, let's go with 1 👍

What do you think about extracting those strings to reduce the magic

For this use case I have never seen anyone defining constants (doesn't mean no-one is doing it, though). But it can't hurt. IMHO we should primarily document the normal string version and also mention that the strings are accessible in the LoggerName module. Perhaps we should call it LogCategory or LoggerCategory, since "category" is used in the MS library.

@cmeeren
Copy link
Member Author

cmeeren commented Aug 8, 2020

Oh wait, I'm not sure it's a good idea with log category constants anyway. The categories are hierarchical, so one can use "Elmish" to enable anything starting with "Elmish", or enable Elmish.WPF and then disable "Elmish.WPF.BindingPerformance". This is possible despite "Elmish" or "Elmish.WPF" not being used directly as logger categories.

I think perhaps it's best if we just document the logger categories and have users use strings, as they probably are using everywhere else, too.

@cmeeren
Copy link
Member Author

cmeeren commented Aug 8, 2020

For your review: I have not spent that much effort on log levels or logger categories. I think it can work as it is now, but I'm certainly open to other suggestions. For example, we may consider renaming Elmish.State and Elmish.Messages to start with Elmish.WPF for consistency. Users shouldn't care about the fact that these logs are enabled by an Elmish hook (heck, even so it's Elmish.WPF that does the actual logging).

src/Elmish.WPF/ViewModel.fs Outdated Show resolved Hide resolved
@cmeeren cmeeren changed the base branch from master to v4 August 9, 2020 13:00
@TysonMN TysonMN mentioned this pull request Aug 9, 2020
9 tasks
@TysonMN

This comment has been minimized.

src/Elmish.WPF/ViewModel.fs Outdated Show resolved Hide resolved
@cmeeren

This comment has been minimized.

README.md Show resolved Hide resolved
README.md Show resolved Hide resolved
README.md Show resolved Hide resolved
@TysonMN
Copy link
Member

TysonMN commented Aug 10, 2020

I just closely reviewed all the file changes. I left some minor change suggestions. Otherwise, everything else looks good.

cmeeren and others added 3 commits August 11, 2020 07:35
Co-authored-by: Tyson Williams <34664007+bender2k14@users.noreply.github.com>
@cmeeren
Copy link
Member Author

cmeeren commented Aug 11, 2020

Everything ready, then?

By the way, if you ever want to squash all commits in a PR before merging, you can do it using the dropdown on the Merge button.

@TysonMN
Copy link
Member

TysonMN commented Aug 11, 2020

Yep, ready.

I am such a perfectionist. Sometimes I want more than just one commit, and I am curious to see what the commit message is when you do it now.

@cmeeren cmeeren merged commit 815dc23 into elmish:v4 Aug 11, 2020
@cmeeren
Copy link
Member Author

cmeeren commented Aug 11, 2020

I am such a perfectionist.

I have noticed 😆

You can choose the message yourself when doing it this way. By default it seems to set the first commit message line to the PR title, and it also includes every commit message on the subsequent lines (I removed those).

@cmeeren cmeeren deleted the logging-microsoft branch August 11, 2020 16:47
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

Successfully merging this pull request may close these issues.

Potential logging improvements
2 participants