Skip to content

Commit

Permalink
Merge pull request #13 from vonhoff/v1.2.3
Browse files Browse the repository at this point in the history
Version update to 2.0.0
  • Loading branch information
vonhoff authored Sep 8, 2024
2 parents b257725 + 945a908 commit 290a7bb
Show file tree
Hide file tree
Showing 15 changed files with 189 additions and 114 deletions.
88 changes: 48 additions & 40 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,40 @@
# Serilog.Sinks.RichTextBox.WinForms.Colored

[![NuGet Downloads](https://img.shields.io/nuget/dt/Serilog.Sinks.RichTextBox.WinForms.Colored.svg)](https://www.nuget.org/packages/Serilog.Sinks.RichTextBox.WinForms.Colored)
[![Latest version](https://img.shields.io/nuget/v/Serilog.Sinks.RichTextBox.WinForms.Colored.svg)](https://www.nuget.org/packages/Serilog.Sinks.RichTextBox.WinForms.Colored)
[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)

A [Serilog](https://serilog.net) sink that writes log events to any WinForms [RichTextBox](https://docs.microsoft.com/en-us/dotnet/desktop/winforms/controls/richtextbox-control-overview-windows-forms) control with coloring and custom theme support.
A [Serilog](https://github.com/serilog/serilog) sink that writes log events to
a [WinForms RichTextBox](https://docs.microsoft.com/en-us/dotnet/desktop/winforms/controls/richtextbox-control-overview-windows-forms)
with support for coloring and custom themes.

![Screenshot of Serilog.Sinks.RichTextBox.WinForms.Colored in action](https://raw.githubusercontent.com/vonhoff/Serilog.Sinks.RichTextBox.WinForms.Colored/main/Assets/screenshot.png)

## Features

![Screenshot of Serilog.Sinks.RichTextBox.WinForms.Colored in action](Assets/screenshot.png)
- Write log events to a WinForms RichTextBox control
- Customizable themes (Dark and Light presets available)
- Configurable output templates
- Auto-scrolling option
- Line limit control

## Getting started
## Installation

Install the [Serilog.Sinks.RichTextBox.WinForms.Colored](https://www.nuget.org/packages/Serilog.Sinks.RichTextBox.WinForms.Colored) package from NuGet:
Install the package from NuGet:

```powershell
Install-Package Serilog.Sinks.RichTextBox.WinForms.Colored
```

Declare your [RichTextBox](https://docs.microsoft.com/en-us/dotnet/desktop/winforms/controls/richtextbox-control-overview-windows-forms) control and give it a name that you can reference it from the code-behind. e.g.:
## Usage

### Basic Setup

Declare your RichTextBox control:

```csharp
private System.Windows.Forms.RichTextBox richTextBox1;

private void InitializeComponent()
{
this.richTextBox1.BackColor = System.Drawing.SystemColors.Window;
Expand All @@ -29,60 +45,52 @@ private void InitializeComponent()
}
```

Then enable the sink using the following snippet:
Configure the logger:

```csharp
var options = new RichTextBoxSinkOptions(ThemePresets.Dark, 200, 5, true);
var sink = new RichTextBoxSink(richTextBox1, _options);
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Verbose()
.WriteTo.Sink(sink, LogEventLevel.Verbose)
.Enrich.WithThreadId()
.WriteTo.RichTextBox(richTextBox1)
.CreateLogger();

Log.Information("Hello, world!");
```

Log events will be written to the `RichTextBox` control:

```
[11:54:36 INF] Hello, world!
```

### Themes

The following built-in themes are available at this time:

| Theme | Description
| ----------------------------------- | ----------------------------------------------------------------- |
| `ThemePresets.Dark` | Styled to replicate the default theme of _Serilog.Sinks.Console_ |
| `ThemePresets.Light` | A theme with a light background and contrasting colors. |

### Output templates
### Advanced Configuration

The format of events to the RichTextBox can be modified by providing a template renderer to the sink.
You can customize the sink using various parameters from the RichTextBox extension method:

```csharp
var options = new RichTextBoxSinkOptions(ThemePresets.Dark, 200, 5, true);
var renderer = new TemplateRenderer(ThemePresets.Dark, "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}");
var sink = new RichTextBoxSink(richTextBox1, _options, renderer);
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Verbose()
.WriteTo.Sink(sink, LogEventLevel.Verbose)
.Enrich.WithThreadId()
.WriteTo.RichTextBox(
richTextBoxControl: richTextBox1,
minimumLogEventLevel: LogEventLevel.Debug,
outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}",
theme: ThemePresets.Light,
messageBatchSize: 100,
messagePendingInterval: 10,
autoScroll: true,
maxLogLines: 1000)
.CreateLogger();

Log.Information("Hello, world!");
```

## Acknowledgments
### Themes

Available built-in themes:

| Theme | Description |
|----------------------|---------------------------------------------------------|
| `ThemePresets.Dark` | Similar to the default theme of _Serilog.Sinks.Console_ |
| `ThemePresets.Light` | Light background with contrasting colors |

If you find this sink useful in your projects, consider leaving a star! ⭐
## Support and Contribute

## Contribution
If you find value in this project, there are several ways you can contribute:

If you want to contribute to this project, you are welcome to submit pull requests or report issues on GitHub.
- **Become a Sponsor:** Support the project through [GitHub Sponsors](https://github.com/sponsors/vonhoff).
- **Show Your Appreciation:** Give the [project](https://github.com/vonhoff/Serilog.Sinks.RichTextBox.WinForms.Colored) a star on GitHub.
- **Contribute:** Improve documentation, report bugs, or submit pull requests.

## License

This project is licensed under the terms of the [Apache License, Version 2.0](LICENSE).
This project is licensed under the [Apache License, Version 2.0](LICENSE).
40 changes: 25 additions & 15 deletions SampleForm/Form1.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ namespace SampleForm
{
public partial class Form1 : Form
{
private RichTextBoxSinkOptions _options = null!;
private RichTextBoxSinkOptions? _options;

private void Initialize()
{
Expand Down Expand Up @@ -102,17 +102,17 @@ private void BtnInformation_Click(object sender, EventArgs e)

private void BtnParallelFor_Click(object sender, EventArgs e)
{
Parallel.For(1, 101, stepNumber =>
for (var stepNumber = 1; stepNumber <= 100; stepNumber++)
{
var stepName = FormattableString.Invariant($"Step {stepNumber:000}");

Log.Verbose("Hello from Parallel.For({StepName}) Verbose", stepName);
Log.Debug("Hello from Parallel.For({StepName}) Debug", stepName);
Log.Information("Hello from Parallel.For({StepName}) Information", stepName);
Log.Warning("Hello from Parallel.For({StepName}) Warning", stepName);
Log.Error("Hello from Parallel.For({StepName}) Error", stepName);
Log.Fatal("Hello from Parallel.For({StepName}) Fatal", stepName);
});
var stepName = $"Step {stepNumber:000}";

Log.Verbose("Hello from For({StepName}) Verbose", stepName);
Log.Debug("Hello from For({StepName}) Debug", stepName);
Log.Information("Hello from For({StepName}) Information", stepName);
Log.Warning("Hello from For({StepName}) Warning", stepName);
Log.Error("Hello from For({StepName}) Error", stepName);
Log.Fatal("Hello from For({StepName}) Fatal", stepName);
}
}

private async void BtnTaskRun_Click(object sender, EventArgs e)
Expand All @@ -124,7 +124,7 @@ private async void BtnTaskRun_Click(object sender, EventArgs e)
var stepNumber = i;
var task = Task.Run(() =>
{
var stepName = FormattableString.Invariant($"Step {stepNumber:000}");
var stepName = $"Step {stepNumber:000}";

Log.Verbose("Hello from Task.Run({StepName}) Verbose", stepName);
Log.Debug("Hello from Task.Run({StepName}) Debug", stepName);
Expand Down Expand Up @@ -181,16 +181,26 @@ private void BtnReset_Click(object sender, EventArgs e)

private void BtnAutoScroll_Click(object sender, EventArgs e)
{
if (_options == null)
{
return;
}

_options.AutoScroll = !_options.AutoScroll;
btnAutoScroll.Text = _options.AutoScroll ? "Disable Auto Scroll" : "Enable Auto Scroll";
}

private void BtnLogLimit_Click(object sender, EventArgs e)
{
bool limitEnabled = _options.MaxLogLines != int.MaxValue;
if (_options == null)
{
return;
}

var limitEnabled = _options.MaxLogLines != int.MaxValue;
_options.MaxLogLines = limitEnabled ? 0 : 35;
btnLogLimit.Text = limitEnabled ? "Enable Line Limit" : "Disable Line Limit";
Log.Information("Log line limit set to {lineLimit}", _options.MaxLogLines == int.MaxValue ? "Maximum" : _options.MaxLogLines);
Log.Information("Log line limit set to {lineLimit}", _options.MaxLogLines == int.MaxValue ? "Maximum" : _options.MaxLogLines.ToString());
}
}
}
}
1 change: 0 additions & 1 deletion SampleForm/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ internal static class Program
[STAThread]
private static void Main()
{
Application.SetHighDpiMode(HighDpiMode.SystemAware);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
Expand Down
7 changes: 2 additions & 5 deletions SampleForm/SampleForm.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,12 @@

<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0-windows</TargetFramework>
<TargetFrameworks>net452</TargetFrameworks>
<Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms>
<LangVersion>9.0</LangVersion>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Serilog" Version="3.0.1" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Serilog.Sinks.RichTextBox.WinForms\Serilog.Sinks.RichTextBox.WinForms.Colored.csproj" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<Authors>Simon Vonhoff</Authors>
Expand All @@ -21,15 +21,34 @@
<RepositoryUrl>https://github.com/vonhoff/serilog-sinks-richtextbox-winforms.git</RepositoryUrl>
<RootNamespace>Serilog</RootNamespace>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<TargetFramework>net6.0-windows7.0</TargetFramework>
<TargetFrameworks>net452;net6.0-windows;net8.0-windows</TargetFrameworks>
<UseWindowsForms>true</UseWindowsForms>
<Version>1.2.2</Version>
<PackageReleaseNotes>- Fixed bug with autoscrolling and line limit.
<Version>2.0.0</Version>
<PackageReleaseNotes>- Added support for .NET 8
- Added support for .NET Framework 4.5.2
- Added outputTemplate and formatProvider to options

See repository for more information:
https://github.com/vonhoff/Serilog.Sinks.RichTextBox.WinForms.Colored</PackageReleaseNotes>
<SupportedOSPlatformVersion>7.0</SupportedOSPlatformVersion>
<NeutralLanguage>en-US</NeutralLanguage>
<LangVersion>9.0</LangVersion>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net8.0-windows|AnyCPU'">
<WarningLevel>6</WarningLevel>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net8.0-windows|AnyCPU'">
<WarningLevel>6</WarningLevel>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net452|AnyCPU'">
<WarningLevel>5</WarningLevel>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net452|AnyCPU'">
<WarningLevel>5</WarningLevel>
</PropertyGroup>

<ItemGroup>
Expand All @@ -44,7 +63,7 @@ https://github.com/vonhoff/Serilog.Sinks.RichTextBox.WinForms.Colored</PackageRe
</ItemGroup>

<ItemGroup>
<PackageReference Include="Serilog" Version="3.0.1" />
<PackageReference Include="Serilog" Version="2.10.0" />
</ItemGroup>

</Project>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public static void Suspend(this Control control)
private static void InvokeWindowProcedure(in Control control, ref Message message)
{
var window = NativeWindow.FromHandle(control.Handle);
window.DefWndProc(ref message);
window?.DefWndProc(ref message);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System.Collections.Generic;

namespace Serilog.Sinks.RichTextBoxForms.Extensions
{
internal static class KeyValuePairExtensions
{
public static void Deconstruct<T1, T2>(this KeyValuePair<T1, T2> tuple, out T1 key, out T2 value)
{
key = tuple.Key;
value = tuple.Value;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@

using System;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows.Forms;

Expand Down Expand Up @@ -46,7 +45,7 @@ public static void AppendRtf(this RichTextBox richTextBox, string rtf, bool auto
{
if (richTextBox.InvokeRequired)
{
richTextBox.Invoke(() => AppendRtf(richTextBox, rtf, autoScroll, maxLogLines));
richTextBox.Invoke(new Action(() => AppendRtf(richTextBox, rtf, autoScroll, maxLogLines)));
return;
}

Expand Down Expand Up @@ -77,8 +76,16 @@ public static void AppendRtf(this RichTextBox richTextBox, string rtf, bool auto

if (richTextBox.Lines.Length > maxLogLines)
{
var linesToRemove = richTextBox.Lines.Length - maxLogLines;
var charsToRemove = 0;

for (var i = 0; i < linesToRemove; i++)
{
charsToRemove += richTextBox.Lines[i].Length + 1;
}

richTextBox.SelectionStart = 0;
richTextBox.SelectionLength = richTextBox.Lines[..^maxLogLines].Sum(line => line.Length + 1);
richTextBox.SelectionLength = charsToRemove;
richTextBox.SelectedText = NullCharacter;
previousSelection = 0;
previousLength = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
using System.IO;
using System.Windows.Forms;
using Serilog.Events;
using Serilog.Sinks.RichTextBoxForms.Extensions;
using Serilog.Sinks.RichTextBoxForms.Themes;

namespace Serilog.Sinks.RichTextBoxForms.Formatting
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
using System.IO;
using System.Windows.Forms;
using Serilog.Events;
using Serilog.Sinks.RichTextBoxForms.Extensions;
using Serilog.Sinks.RichTextBoxForms.Themes;

namespace Serilog.Sinks.RichTextBoxForms.Formatting
Expand Down Expand Up @@ -233,7 +234,7 @@ public static string GetQuotedJsonString(string str)
{
anyEscaped = true;

output.Write(str[cleanSegmentStart..i]);
output.Write(str.Substring(cleanSegmentStart, i - cleanSegmentStart));
cleanSegmentStart = i + 1;

switch (c)
Expand Down Expand Up @@ -282,7 +283,7 @@ public static string GetQuotedJsonString(string str)
{
if (cleanSegmentStart != str.Length)
{
output.Write(str[cleanSegmentStart..]);
output.Write(str.Substring(cleanSegmentStart));
}
}
else
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ namespace Serilog.Sinks.RichTextBoxForms.Formatting
{
public abstract class ValueFormatter : LogEventPropertyValueVisitor<ValueFormatterState, bool>
{
public Theme Theme { get; init; }
public Theme Theme { get; set; }

protected ValueFormatter(Theme theme)
{
Expand Down
Loading

0 comments on commit 290a7bb

Please sign in to comment.