3

I have a C# Windows Forms application that is referencing a DLL (managed code) that is using SeriLog to log events. The SeriLog logger is defined in the Windows Forms (main) application, so I have control over the type of sink I am using. Currently I am just logging to a local text file.

My question: is there an elegant way for me to view the log in a Listbox or similar WinForms control in real time while the application is running? The only way I can see at the moment is to read the Log file every few seconds and display the latest item. But I am sure there may be a more elegant way to do capture just the last one or two logged items?

Fritz45
  • 752
  • 1
  • 10
  • 23

3 Answers3

3

This has the exact answer you're looking for: Is it possible to display Serilog log in the program's GUI?

However something has happened in the last 5 years!!! There's now a library called: https://github.com/serilog/serilog-sinks-reflectinsight

We've added a Serilog Sink for ReflectInsight live log viewer. This allows you to leverage your current investment in Serilog, but leverage the power and flexibility that comes with the ReflectInsight viewer. You can view your Serilog messages in real-time, in a rich viewer that allows you to filter out and search for what really matters to you.

Jeremy Thompson
  • 61,933
  • 36
  • 195
  • 321
  • 1
    Thanks Jeremy. I was able to find and implement a solution using the link you posted above. So I have marked this as the answer. The ReflectInsight viewer looks really cool but it is a complete overkill for what I am trying to do now. Thanks for your help. – Fritz45 Sep 03 '21 at 22:02
2

Given that you have control over the logging pipeline and can choose the sink(s) that will be used, one option would be to use the Serilog.Sinks.RichTextBox sink which can write logs to a RichTextBox control with colors, formatting, etc.

Serilog.Sinks.RichTextBox

The sink was originally built for WPF apps, but you can easily use it in a Windows Forms application with an ElementHost. There's an example in the repository that shows how to use it with Windows Forms.

Disclaimer: I'm the author of the Serilog.Sinks.RichTextBox sink.

C. Augusto Proiete
  • 24,684
  • 2
  • 63
  • 91
  • Thanks Augusto. I tried to install your package but received 'Unable to find package 'Serilog.Sinks.RichTextBox.Wpf'' when I tried to install it via the package manager console – Fritz45 Sep 03 '21 at 04:15
  • @Fritz45 You need the `Prerelease` flag if you're installing via NuGet Package Manager Console i.e. `Install-Package Serilog.Sinks.RichTextBox.Wpf -Prerelease` – C. Augusto Proiete Sep 03 '21 at 18:35
  • 1
    Thanks Augusto. I was able to install your component using the command you gave above. I also found your example on how to implement the WPF component in a Windows Forms app quite clear. In the end, though, it just seemed like an overkill for me and I have gone with the solution above. I will continue to follow your development though. Thanks! – Fritz45 Sep 03 '21 at 22:00
1

Use FileSystemWatcher to monitor the file change and then update that Listbox in the OnChanged event handler

static void Main()
{
        using var watcher = new FileSystemWatcher(@"C:\path\to\folder");
        //choose what you wish
        watcher.NotifyFilter = NotifyFilters.Attributes
                             | NotifyFilters.CreationTime
                             | NotifyFilters.DirectoryName
                             | NotifyFilters.FileName
                             | NotifyFilters.LastAccess
                             | NotifyFilters.LastWrite
                             | NotifyFilters.Security
                             | NotifyFilters.Size;

        watcher.Changed += OnChanged;
        watcher.Created += OnCreated;
        watcher.Deleted += OnDeleted;
        watcher.Renamed += OnRenamed;
        watcher.Error += OnError;

        watcher.Filter = "YourLogFile.txt";
        watcher.IncludeSubdirectories = false;
        watcher.EnableRaisingEvents = true;

        Console.WriteLine("Press enter to exit.");
        Console.ReadLine();
    }

    private static void OnChanged(object sender, FileSystemEventArgs e)
    {
        if (e.ChangeType != WatcherChangeTypes.Changed)
        {
            return;
        }
        //Console.WriteLine($"Changed: {e.FullPath}");
        //Update your Listbox content
    }
David
  • 15,894
  • 22
  • 55
  • 66
  • 2
    Note that, in the current configuration (though `static void Main()` is not exactly meaningful here), the `Changed` event is raised in a Thread other than the UI Thread, so *Update your Listbox content* will throw. Either set the SynchronizingObject or `BeginInvoke()` (not `Invoke()`, in this context). – Jimi Sep 03 '21 at 03:15
  • There's something else about this as a design pattern. When you have the code that is issuing commands, why then have another library that polls for the changes? You're better off using the tool to render the commands as they are issued. `FileSystemWatcher` is used for monitoring file activity typically by external apps, not internal logging. – Jeremy Thompson Sep 03 '21 at 03:21
  • Thanks David. This looks like a good generic approach. But if will still require me to load the entire file each time. I just want to add new log items as they are logged by the SeriLog logger – Fritz45 Sep 03 '21 at 03:58
  • +1 for propose a 1 minute hack for Dev in Linqpad, for example; not to think to use it in Staging or Production... – Marcelo Scofano Diniz Oct 02 '22 at 14:52