Skip to content

Commit 871bcc3

Browse files
author
MPCoreDeveloper
committed
refactor(serilog-sink): modernize to C# 14 with batch writes and new README
1 parent 9c7bb99 commit 871bcc3

File tree

6 files changed

+404
-420
lines changed

6 files changed

+404
-420
lines changed

src/SharpCoreDB.Serilog.Sinks/CHANGELOG.md

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,34 @@ All notable changes to SharpCoreDB.Serilog.Sinks will be documented in this file
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8-
## [1.0.0] - 2025-01-XX
8+
## [1.0.7] - 2025-06-02
9+
10+
### Changed
11+
- **BREAKING**: `SharpCoreDBSink` is now `sealed` — prevents unintended inheritance
12+
- **PERF**: Replaced per-event `ExecuteSQLAsync` loop with `ExecuteBatchSQLAsync` which routes through `InsertBatch` for direct storage engine writes
13+
- **PERF**: Cached INSERT SQL prefix to avoid repeated string interpolation per event
14+
- **PERF**: `StringBuilder` initialized with capacity hint to reduce resizing in hot path
15+
- **SAFETY**: Added `Flush()` call after batch writes to ensure data persistence to disk
16+
- **SAFETY**: Thread-safe table creation using C# 14 `Lock` class with double-check pattern
17+
- **SAFETY**: Added `ConfigureAwait(false)` on all async calls for library deadlock prevention
18+
- **C# 14**: Raw string literals for multi-line CREATE TABLE SQL
19+
- **C# 14**: Collection expressions (`List<string> statements = []`)
20+
- **C# 14**: `Lock` class instead of `object` for synchronization
21+
- Used `ArgumentException.ThrowIfNullOrWhiteSpace` for parameter validation
22+
- Improved XML documentation with `<see cref="..."/>` cross-references
23+
24+
### Removed
25+
- Unnecessary finalizer (`~SharpCoreDBSink`) — class holds no unmanaged resources
26+
- Simplified `Dispose` pattern for sealed class (no `Dispose(bool)` needed)
27+
- Removed `BeginBatchUpdate`/`EndBatchUpdate`/`CancelBatchUpdate` calls — `ExecuteBatchSQLAsync` handles transactions internally
28+
29+
### Fixed
30+
- `_tableCreated` field was not thread-safe — now protected by `Lock` with double-check pattern
31+
- Missing `Flush()` after writes could cause data loss on crash
32+
- Missing `ConfigureAwait(false)` could deadlock in synchronization contexts
33+
- Replaced manual `throw new ArgumentException` with `ArgumentException.ThrowIfNullOrWhiteSpace`
34+
35+
## [1.0.0] - 2025-01-28
936

1037
### Added
1138
- Initial release of SharpCoreDB.Serilog.Sinks

src/SharpCoreDB.Serilog.Sinks/LoggerConfigurationExtensions.cs

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,13 @@
66
using SharpCoreDB.Interfaces;
77
using SharpCoreDB.Services;
88
using Microsoft.Extensions.DependencyInjection;
9+
910
namespace SharpCoreDB.Serilog.Sinks;
10-
/// Michel Posseth
11+
12+
/// Michel Posseth
1113
/// <summary>
1214
/// Extension methods for configuring the SharpCoreDB sink with Serilog.
15+
/// Provides three overloads: database instance, connection string, and options object.
1316
/// </summary>
1417
public static class LoggerConfigurationExtensions
1518
{
@@ -39,7 +42,6 @@ public static LoggerConfiguration SharpCoreDB(
3942
string storageEngine = "AppendOnly")
4043
{
4144
ArgumentNullException.ThrowIfNull(loggerSinkConfiguration);
42-
4345
ArgumentNullException.ThrowIfNull(database);
4446

4547
var actualPeriod = period ?? DefaultPeriod;
@@ -65,6 +67,7 @@ public static LoggerConfiguration SharpCoreDB(
6567

6668
/// <summary>
6769
/// Writes log events to a SharpCoreDB database using a connection string.
70+
/// Creates a database instance internally with logging-optimized configuration.
6871
/// </summary>
6972
/// <param name="loggerSinkConfiguration">The logger sink configuration.</param>
7073
/// <param name="path">The path to the .scdb file.</param>
@@ -90,22 +93,14 @@ public static LoggerConfiguration SharpCoreDB(
9093
IServiceProvider? serviceProvider = null)
9194
{
9295
ArgumentNullException.ThrowIfNull(loggerSinkConfiguration);
93-
94-
if (string.IsNullOrWhiteSpace(path))
95-
{
96-
throw new ArgumentException("Path cannot be null or whitespace.", nameof(path));
97-
}
98-
99-
if (string.IsNullOrWhiteSpace(password))
100-
{
101-
throw new ArgumentException("Password cannot be null or whitespace.", nameof(password));
102-
}
96+
ArgumentException.ThrowIfNullOrWhiteSpace(path);
97+
ArgumentException.ThrowIfNullOrWhiteSpace(password);
10398

10499
// Create or use provided service provider
105100
var services = serviceProvider ?? CreateDefaultServiceProvider();
106101
var factory = services.GetRequiredService<DatabaseFactory>();
107-
108-
// Create database with optimized config for logging
102+
103+
// Create database with config optimized for logging workloads
109104
var config = new DatabaseConfig
110105
{
111106
EnableQueryCache = false, // Logs are typically write-once
@@ -131,7 +126,7 @@ public static LoggerConfiguration SharpCoreDB(
131126
}
132127

133128
/// <summary>
134-
/// Writes log events to a SharpCoreDB database using options.
129+
/// Writes log events to a SharpCoreDB database using an options object.
135130
/// </summary>
136131
/// <param name="loggerSinkConfiguration">The logger sink configuration.</param>
137132
/// <param name="options">The sink options.</param>
@@ -141,10 +136,9 @@ public static LoggerConfiguration SharpCoreDB(
141136
SharpCoreDBSinkOptions options)
142137
{
143138
ArgumentNullException.ThrowIfNull(loggerSinkConfiguration);
144-
145139
ArgumentNullException.ThrowIfNull(options);
146140

147-
if (options.Database != null)
141+
if (options.Database is not null)
148142
{
149143
return SharpCoreDB(
150144
loggerSinkConfiguration,

src/SharpCoreDB.Serilog.Sinks/PROJECT_SUMMARY.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ A production-ready Serilog sink for SharpCoreDB, providing efficient batch loggi
66

77
## Key Features
88

9-
* **Efficient Batching**: Uses Serilog.Sinks.PeriodicBatching for optimal performance
9+
* **Efficient Batching**: Uses `ExecuteBatchSQLAsync``InsertBatch` for optimal storage engine throughput
1010
* **Encrypted Storage**: Leverages SharpCoreDB's AES-256-GCM encryption
1111
* **High Performance**: 10,000+ logs/second capability
1212
* **ULID Primary Keys**: Sortable, timestamp-based unique identifiers
@@ -31,9 +31,9 @@ SharpCoreDB.Serilog.Sinks/
3131
## Technology Stack
3232

3333
* **.NET 10**: Latest .NET platform
34-
* **C# 12+**: Modern C# features
35-
* **Serilog 4.2.0**: Structured logging
36-
* **Serilog.Sinks.PeriodicBatching 5.0.0**: Batch processing
34+
* **C# 14**: Modern C# features (Lock class, raw string literals, collection expressions)
35+
* **Serilog 4.x**: Structured logging
36+
* **Serilog.Sinks.PeriodicBatching 5.x**: Batch processing
3737
* **SharpCoreDB**: Encrypted database backend
3838

3939
## Database Schema
@@ -53,9 +53,10 @@ CREATE TABLE Logs (
5353

5454
* **Write Throughput**: 10,000+ logs/second
5555
* **Batch Latency**: Sub-millisecond per batch
56-
* **Memory Usage**: Minimal footprint
56+
* **Memory Usage**: Minimal footprint (cached INSERT prefix, capacity-hinted StringBuilder)
5757
* **Storage Overhead**: Efficient with compression
5858
* **Encryption Overhead**: Near-zero with AES-NI
59+
* **Thread Safety**: C# 14 `Lock` class with double-check pattern for table init
5960

6061
## Configuration Options
6162

0 commit comments

Comments
 (0)