Skip to content

Commit 0317d75

Browse files
committed
Refactor renderer constructors to use options object
Refactored all token renderer and TemplateRenderer constructors to accept a RichTextBoxSinkOptions object instead of individual parameters. Updated tests and extension methods accordingly. Standardized default JSON indentation to 2 spaces and removed unused parameters for consistency.
1 parent 03852f4 commit 0317d75

File tree

14 files changed

+83
-91
lines changed

14 files changed

+83
-91
lines changed

README.md

Lines changed: 15 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@
55
[![Latest version](https://img.shields.io/nuget/v/Serilog.Sinks.RichTextBox.WinForms.Colored.svg)](https://www.nuget.org/packages/Serilog.Sinks.RichTextBox.WinForms.Colored)
66
[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
77

8-
A [Serilog](https://github.com/serilog/serilog) sink that writes log events to
9-
a [WinForms RichTextBox](https://docs.microsoft.com/en-us/dotnet/desktop/winforms/controls/richtextbox-control-overview-windows-forms)
10-
with support for coloring and custom themes.
8+
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.
119

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

@@ -18,8 +16,7 @@ with support for coloring and custom themes.
1816
- High-performance asynchronous processing
1917
- Line limit to control memory usage
2018
- Support for pretty-printing of JSON objects
21-
- WCAG compliant color schemes based on
22-
the [Serilog WPF RichTextBox](https://github.com/serilog-contrib/serilog-sinks-richtextbox) sink.
19+
- WCAG compliant color schemes based on the [Serilog WPF RichTextBox](https://github.com/serilog-contrib/serilog-sinks-richtextbox) sink.
2320

2421
## Getting Started
2522

@@ -54,20 +51,19 @@ Log.Logger = new LoggerConfiguration()
5451
Log.Information("Hello, world!");
5552
```
5653

57-
See the [Extension Method](Serilog.Sinks.RichTextBox.WinForms.Colored/RichTextBoxSinkLoggerConfigurationExtensions.cs)
58-
for more configuration options.
54+
See the [Extension Method](Serilog.Sinks.RichTextBox.WinForms.Colored/RichTextBoxSinkLoggerConfigurationExtensions.cs) for more configuration options.
5955

6056
## Configuration Options
6157

62-
| Option | Description | Default Value |
63-
|-------------------|------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------|
64-
| `theme` | The color theme applied when rendering individual message tokens. | `ThemePresets.Literate` |
65-
| `autoScroll` | When `true` (default) the target control scrolls automatically to the most recent log line. | `true` |
66-
| `maxLogLines` | Maximum number of log events retained in the in-memory circular buffer and rendered in the control. | `256` |
67-
| `outputTemplate` | Serilog output template that controls textual formatting of each log event. | `[${Timestamp:HH:mm:ss} ${Level:u3}] ${Message:lj}${NewLine}${Exception}` |
68-
| `formatProvider` | Optional culture-specific or custom formatting provider used when rendering scalar values; `null` for the invariant culture. | `CultureInfo.InvariantCulture` |
69-
| `prettyPrintJson` | When `true`, formats JSON values with indentation and line breaks for better readability. | `false` |
70-
| `spacesPerIndent` | Number of spaces per indentation level when pretty printing JSON. | `2` |
58+
| Option | Description | Default Value |
59+
|-------------------|------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------|
60+
| `theme` | The color theme applied when rendering individual message tokens. | `ThemePresets.Literate` |
61+
| `autoScroll` | When `true` (default) the target control scrolls automatically to the most recent log line. | `true` |
62+
| `maxLogLines` | Maximum number of log events retained in the in-memory circular buffer and rendered in the control. | `256` |
63+
| `outputTemplate` | Serilog output template that controls textual formatting of each log event. | `[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}` |
64+
| `formatProvider` | Optional culture-specific or custom formatting provider used when rendering scalar values; `null` for the invariant culture. | `CultureInfo.InvariantCulture` |
65+
| `prettyPrintJson` | When `true`, formats JSON values with indentation and line breaks for better readability. | `false` |
66+
| `spacesPerIndent` | Number of spaces per indentation level when pretty printing JSON. | `2` |
7167

7268
## Themes
7369

@@ -80,21 +76,13 @@ Available built-in themes:
8076
| `ThemePresets.Colored` | A theme based on the original Serilog.Sinks.ColoredConsole sink |
8177
| `ThemePresets.Luminous` | A light theme with high contrast for accessibility |
8278

83-
The themes based on the original sinks are slightly adjusted to
84-
be [WCAG compliant](https://www.w3.org/WAI/WCAG22/Understanding/contrast-minimum), ensuring that the contrast ratio
85-
between text and background colors is at least 4.5:1.
79+
The themes based on the original sinks are slightly adjusted to be [WCAG compliant](https://www.w3.org/WAI/WCAG22/Understanding/contrast-minimum), ensuring that the contrast ratio between text and background colors is at least 4.5:1.
8680

87-
You can create your own custom themes by creating a new instance of
88-
the [Theme](Serilog.Sinks.RichTextBox.WinForms.Colored/Sinks/RichTextBoxForms/Themes/Theme.cs) class and passing it to
89-
the `RichTextBox` extension method. Look at
90-
the [existing themes](Serilog.Sinks.RichTextBox.WinForms.Colored/Sinks/RichTextBoxForms/Themes/ThemePresets.cs) for
91-
examples.
81+
You can create your own custom themes by creating a new instance of the [Theme](Serilog.Sinks.RichTextBox.WinForms.Colored/Sinks/RichTextBoxForms/Themes/Theme.cs) class and passing it to the `RichTextBox` extension method. Look at the [existing themes](Serilog.Sinks.RichTextBox.WinForms.Colored/Sinks/RichTextBoxForms/Themes/ThemePresets.cs) for examples.
9282

9383
## Support the Project 💖
9484

95-
This project has been maintained since 2022 and is still under active development. If you find it useful, please
96-
consider supporting it. Your support will help keep the project alive and allow me to dedicate more time to making
97-
improvements. You can support it through:
85+
This project has been maintained since 2022 and is still under active development. If you find it useful, please consider supporting it. Your support will help keep the project alive and allow me to dedicate more time to making improvements. You can support it through:
9886

9987
* [GitHub Sponsors](https://github.com/sponsors/vonhoff)
10088
* [Ko-fi](https://ko-fi.com/vonhoff)

Serilog.Sinks.RichTextBox.WinForms.Colored.Test/Integration/PropertiesTokenRendererTests.cs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Serilog.Events;
22
using Serilog.Parsing;
3+
using Serilog.Sinks.RichTextBoxForms;
34
using Serilog.Sinks.RichTextBoxForms.Rendering;
45
using Xunit;
56

@@ -13,7 +14,8 @@ public void Render_WithAdditionalProperties_FormatsCorrectly()
1314
var template = _parser.Parse("Message: {Message}");
1415
var outputTemplate = _parser.Parse("Message: {Message} {Properties}");
1516
var token = outputTemplate.Tokens.OfType<PropertyToken>().Single(t => t.PropertyName == "Properties");
16-
var renderer = new PropertiesTokenRenderer(_defaultTheme, token, outputTemplate, null);
17+
var options = new RichTextBoxSinkOptions(_defaultTheme, formatProvider: null);
18+
var renderer = new PropertiesTokenRenderer(token, outputTemplate, options);
1719

1820
var logEvent = new LogEvent(
1921
DateTimeOffset.Now,
@@ -39,7 +41,8 @@ public void Render_WithJsonFormatting_FormatsCorrectly()
3941
var template = _parser.Parse("Message: {Message}");
4042
var outputTemplate = _parser.Parse("Message: {Message} {Properties:j}");
4143
var token = outputTemplate.Tokens.OfType<PropertyToken>().Single(t => t.PropertyName == "Properties");
42-
var renderer = new PropertiesTokenRenderer(_defaultTheme, token, outputTemplate, null);
44+
var options = new RichTextBoxSinkOptions(_defaultTheme, formatProvider: null);
45+
var renderer = new PropertiesTokenRenderer(token, outputTemplate, options);
4346

4447
var logEvent = new LogEvent(
4548
DateTimeOffset.Now,
@@ -67,7 +70,8 @@ public void Render_WithNestedProperties_FormatsCorrectly()
6770
var template = _parser.Parse("Message: {Message}");
6871
var outputTemplate = _parser.Parse("Message: {Message} {Properties}");
6972
var token = outputTemplate.Tokens.OfType<PropertyToken>().Single(t => t.PropertyName == "Properties");
70-
var renderer = new PropertiesTokenRenderer(_defaultTheme, token, outputTemplate, null);
73+
var options = new RichTextBoxSinkOptions(_defaultTheme, formatProvider: null);
74+
var renderer = new PropertiesTokenRenderer(token, outputTemplate, options);
7175

7276
var nestedStructure = new StructureValue(new[]
7377
{
@@ -98,7 +102,8 @@ public void Render_WithNoAdditionalProperties_FormatsCorrectly()
98102
var template = _parser.Parse("Message: {Message}");
99103
var outputTemplate = _parser.Parse("Message: {Message} {Properties}");
100104
var token = outputTemplate.Tokens.OfType<PropertyToken>().Single(t => t.PropertyName == "Properties");
101-
var renderer = new PropertiesTokenRenderer(_defaultTheme, token, outputTemplate, null);
105+
var options = new RichTextBoxSinkOptions(_defaultTheme, formatProvider: null);
106+
var renderer = new PropertiesTokenRenderer(token, outputTemplate, options);
102107

103108
var logEvent = new LogEvent(
104109
DateTimeOffset.Now,
@@ -122,7 +127,8 @@ public void Render_WithPropertiesInOutputTemplate_ExcludesThem()
122127
var template = _parser.Parse("Message: {Message}");
123128
var outputTemplate = _parser.Parse("Message: {Message} {Properties} {Custom}");
124129
var token = outputTemplate.Tokens.OfType<PropertyToken>().Single(t => t.PropertyName == "Properties");
125-
var renderer = new PropertiesTokenRenderer(_defaultTheme, token, outputTemplate, null);
130+
var options = new RichTextBoxSinkOptions(_defaultTheme, formatProvider: null);
131+
var renderer = new PropertiesTokenRenderer(token, outputTemplate, options);
126132

127133
var logEvent = new LogEvent(
128134
DateTimeOffset.Now,

Serilog.Sinks.RichTextBox.WinForms.Colored.Test/Integration/TokenRendererTests.cs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Serilog.Events;
22
using Serilog.Parsing;
3+
using Serilog.Sinks.RichTextBoxForms;
34
using Serilog.Sinks.RichTextBoxForms.Rendering;
45
using Xunit;
56

@@ -60,7 +61,8 @@ public void EventPropertyTokenRenderer_RendersNonStringScalarValue()
6061
{
6162
var template = _parser.Parse("Number: {Number}");
6263
var propertyToken = template.Tokens.OfType<PropertyToken>().Single(t => t.PropertyName == "Number");
63-
var renderer = new EventPropertyTokenRenderer(_defaultTheme, propertyToken, null);
64+
var options = new RichTextBoxSinkOptions(_defaultTheme, formatProvider: null);
65+
var renderer = new EventPropertyTokenRenderer(propertyToken, options);
6466

6567
var logEvent = new LogEvent(
6668
DateTimeOffset.Now,
@@ -80,7 +82,8 @@ public void EventPropertyTokenRenderer_RendersStructureValue()
8082
{
8183
var template = _parser.Parse("User: {User}");
8284
var propertyToken = template.Tokens.OfType<PropertyToken>().Single(t => t.PropertyName == "User");
83-
var renderer = new EventPropertyTokenRenderer(_defaultTheme, propertyToken, null);
85+
var options = new RichTextBoxSinkOptions(_defaultTheme, formatProvider: null);
86+
var renderer = new EventPropertyTokenRenderer(propertyToken, options);
8487

8588
var structureValue = new StructureValue(new[]
8689
{
@@ -109,7 +112,8 @@ public void EventPropertyTokenRenderer_RendersSequenceValue()
109112
{
110113
var template = _parser.Parse("Items: {Items}");
111114
var propertyToken = template.Tokens.OfType<PropertyToken>().Single(t => t.PropertyName == "Items");
112-
var renderer = new EventPropertyTokenRenderer(_defaultTheme, propertyToken, null);
115+
var options = new RichTextBoxSinkOptions(_defaultTheme, formatProvider: null);
116+
var renderer = new EventPropertyTokenRenderer(propertyToken, options);
113117

114118
var sequenceValue = new SequenceValue(new[]
115119
{
@@ -138,7 +142,8 @@ public void EventPropertyTokenRenderer_RendersDictionaryValue()
138142
{
139143
var template = _parser.Parse("Config: {Config}");
140144
var propertyToken = template.Tokens.OfType<PropertyToken>().Single(t => t.PropertyName == "Config");
141-
var renderer = new EventPropertyTokenRenderer(_defaultTheme, propertyToken, null);
145+
var options = new RichTextBoxSinkOptions(_defaultTheme, formatProvider: null);
146+
var renderer = new EventPropertyTokenRenderer(propertyToken, options);
142147

143148
var dict = new Dictionary<ScalarValue, LogEventPropertyValue>
144149
{
@@ -168,7 +173,8 @@ public void EventPropertyTokenRenderer_HandlesMissingProperty()
168173
{
169174
var template = _parser.Parse("Missing: {Missing}");
170175
var propertyToken = template.Tokens.OfType<PropertyToken>().Single(t => t.PropertyName == "Missing");
171-
var renderer = new EventPropertyTokenRenderer(_defaultTheme, propertyToken, null);
176+
var options = new RichTextBoxSinkOptions(_defaultTheme, formatProvider: null);
177+
var renderer = new EventPropertyTokenRenderer(propertyToken, options);
172178

173179
var logEvent = new LogEvent(
174180
DateTimeOffset.Now,
@@ -188,7 +194,8 @@ public void EventPropertyTokenRenderer_RendersStringValue()
188194
{
189195
var template = _parser.Parse("Message: {Message}");
190196
var propertyToken = template.Tokens.OfType<PropertyToken>().Single(t => t.PropertyName == "Message");
191-
var renderer = new EventPropertyTokenRenderer(_defaultTheme, propertyToken, null);
197+
var options = new RichTextBoxSinkOptions(_defaultTheme, formatProvider: null);
198+
var renderer = new EventPropertyTokenRenderer(propertyToken, options);
192199

193200
var logEvent = new LogEvent(
194201
DateTimeOffset.Now,

Serilog.Sinks.RichTextBox.WinForms.Colored.Test/RichTextBoxSinkTestBase.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,16 @@ protected RichTextBoxSinkTestBase()
2020
{
2121
_richTextBox = new RichTextBox();
2222
_defaultTheme = ThemePresets.Literate;
23-
_renderer = new TemplateRenderer(_defaultTheme, "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:l}{NewLine}{Exception}", null);
2423
_parser = new MessageTemplateParser();
2524

2625
var options = new RichTextBoxSinkOptions(
2726
theme: _defaultTheme,
27+
outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:l}{NewLine}{Exception}",
2828
autoScroll: true,
2929
maxLogLines: 1000
3030
);
3131

32+
_renderer = new TemplateRenderer(options);
3233
_sink = new RichTextBoxSink(_richTextBox, options);
3334

3435
// Wrap the RichTextBox in an IRtfCanvas adapter so that unit tests
@@ -40,15 +41,17 @@ protected RichTextBoxSinkTestBase()
4041
protected string RenderAndGetText(LogEvent logEvent, string outputTemplate, IFormatProvider? formatProvider = null)
4142
{
4243
_richTextBox.Clear();
43-
var renderer = new TemplateRenderer(_defaultTheme, outputTemplate, formatProvider);
44+
var options = new RichTextBoxSinkOptions(_defaultTheme, outputTemplate: outputTemplate, formatProvider: formatProvider);
45+
var renderer = new TemplateRenderer(options);
4446
renderer.Render(logEvent, _canvas);
4547
return _richTextBox.Text.TrimEnd('\n', '\r');
4648
}
4749

4850
protected string RenderAndGetText(LogEvent logEvent, string outputTemplate, RichTextBoxSinkOptions options)
4951
{
5052
_richTextBox.Clear();
51-
var renderer = new TemplateRenderer(options.Theme, outputTemplate, options.FormatProvider, options);
53+
var rendererOptions = new RichTextBoxSinkOptions(options.Theme, options.AutoScroll, options.MaxLogLines, outputTemplate, options.FormatProvider, options.PrettyPrintJson, options.SpacesPerIndent);
54+
var renderer = new TemplateRenderer(rendererOptions);
5255
renderer.Render(logEvent, _canvas);
5356
return _richTextBox.Text.TrimEnd('\n', '\r');
5457
}

Serilog.Sinks.RichTextBox.WinForms.Colored/RichTextBoxSinkLoggerConfigurationExtensions.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ public static LoggerConfiguration RichTextBox(
6565
var appliedTheme = theme ?? ThemePresets.Literate;
6666
var appliedFormatProvider = formatProvider ?? CultureInfo.InvariantCulture;
6767
var options = new RichTextBoxSinkOptions(appliedTheme, autoScroll, maxLogLines, outputTemplate, appliedFormatProvider, prettyPrintJson, spacesPerIndent);
68-
var renderer = new TemplateRenderer(appliedTheme, outputTemplate, appliedFormatProvider, options);
68+
var renderer = new TemplateRenderer(options);
6969
richTextBoxSink = new RichTextBoxSink(richTextBoxControl, options, renderer);
7070
return sinkConfiguration.Sink(richTextBoxSink, minimumLogEventLevel, levelSwitch);
7171
}
@@ -83,7 +83,7 @@ public static LoggerConfiguration RichTextBox(
8383
/// <param name="minimumLogEventLevel">Minimum log level for events to be written.</param>
8484
/// <param name="levelSwitch">Optional switch to change the minimum log level at runtime.</param>
8585
/// <param name="prettyPrintJson">If <c>true</c>, formats JSON values with indentation and line breaks. Defaults to <c>false</c>.</param>
86-
/// <param name="spacesPerIndent">Number of spaces per indentation level when pretty printing JSON. Defaults to 4. Must be between 1 and 16.</param>
86+
/// <param name="spacesPerIndent">Number of spaces per indentation level when pretty printing JSON. Defaults to 4.</param>
8787
/// <returns>The logger configuration, for chaining.</returns>
8888
public static LoggerConfiguration RichTextBox(
8989
this LoggerSinkConfiguration sinkConfiguration,
@@ -96,7 +96,7 @@ public static LoggerConfiguration RichTextBox(
9696
LogEventLevel minimumLogEventLevel = LogEventLevel.Verbose,
9797
LoggingLevelSwitch? levelSwitch = null,
9898
bool prettyPrintJson = false,
99-
int spacesPerIndent = 4)
99+
int spacesPerIndent = 2)
100100
{
101101
return RichTextBox(
102102
sinkConfiguration,

0 commit comments

Comments
 (0)