Skip to content

Commit 5323191

Browse files
Support logging properties into user defined columns
1 parent 8b60f1d commit 5323191

File tree

2 files changed

+38
-6
lines changed

2 files changed

+38
-6
lines changed

src/Serilog.Sinks.MSSqlServer/LoggerConfigurationMSSqlServerExtensions.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Data;
23
using Serilog.Configuration;
34
using Serilog.Events;
45
using Serilog.Sinks.MSSqlServer;
@@ -38,6 +39,7 @@ public static class LoggerConfigurationMSSqlServerExtensions
3839
/// <param name="period">The time to wait between checking for event batches.</param>
3940
/// <param name="formatProvider">Supplies culture-specific formatting information, or null.</param>
4041
/// <param name="storeTimestampInUtc">Store Timestamp In UTC</param>
42+
/// <param name="additionalDataColumns">Additional columns for data storage.</param>
4143
/// <returns>Logger configuration, allowing configuration to continue.</returns>
4244
/// <exception cref="ArgumentNullException">A required parameter is null.</exception>
4345
public static LoggerConfiguration MSSqlServer(
@@ -47,14 +49,15 @@ public static LoggerConfiguration MSSqlServer(
4749
int batchPostingLimit = MSSqlServerSink.DefaultBatchPostingLimit,
4850
TimeSpan? period = null,
4951
IFormatProvider formatProvider = null,
50-
bool storeTimestampInUtc = false)
52+
bool storeTimestampInUtc = false,
53+
DataColumn[] additionalDataColumns = null)
5154
{
5255
if (loggerConfiguration == null) throw new ArgumentNullException("loggerConfiguration");
5356

5457
var defaultedPeriod = period ?? MSSqlServerSink.DefaultPeriod;
5558

5659
return loggerConfiguration.Sink(
57-
new MSSqlServerSink(connectionString, tableName, storeProperties, batchPostingLimit, defaultedPeriod, formatProvider, storeTimestampInUtc),
60+
new MSSqlServerSink(connectionString, tableName, storeProperties, batchPostingLimit, defaultedPeriod, formatProvider, storeTimestampInUtc, additionalDataColumns),
5861
restrictedToMinimumLevel);
5962
}
6063
}

src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/MSSqlServerSink.cs

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2013 Serilog Contributors
1+
// Copyright 2013 Serilog Contributors
22
//
33
// Licensed under the Apache License, Version 2.0 (the "License");
44
// you may not use this file except in compliance with the License.
@@ -49,6 +49,8 @@ public class MSSqlServerSink : PeriodicBatchingSink
4949
readonly CancellationTokenSource _token = new CancellationTokenSource();
5050
readonly bool _storeTimestampInUtc;
5151

52+
private DataColumn[] _additionalDataColumns;
53+
5254
/// <summary>
5355
/// Construct a sink posting to the specified database.
5456
/// </summary>
@@ -59,8 +61,9 @@ public class MSSqlServerSink : PeriodicBatchingSink
5961
/// <param name="period">The time to wait between checking for event batches.</param>
6062
/// <param name="formatProvider">Supplies culture-specific formatting information, or null.</param>
6163
/// <param name="storeTimestampInUtc">Store Timestamp In UTC</param>
64+
/// <param name="additionalDataColumns">Additional columns for data storage.</param>
6265
public MSSqlServerSink(string connectionString, string tableName, bool includeProperties, int batchPostingLimit,
63-
TimeSpan period, IFormatProvider formatProvider, bool storeTimestampInUtc)
66+
TimeSpan period, IFormatProvider formatProvider, bool storeTimestampInUtc, DataColumn[] additionalDataColumns = null )
6467
: base(batchPostingLimit, period)
6568
{
6669
if (string.IsNullOrWhiteSpace(connectionString))
@@ -75,6 +78,7 @@ public MSSqlServerSink(string connectionString, string tableName, bool includePr
7578
_includeProperties = includeProperties;
7679
_formatProvider = formatProvider;
7780
_storeTimestampInUtc = storeTimestampInUtc;
81+
_additionalDataColumns = additionalDataColumns;
7882

7983
// Prepare the data table
8084
_eventsTable = CreateDataTable();
@@ -162,6 +166,10 @@ DataTable CreateDataTable()
162166
};
163167
eventsTable.Columns.Add(props);
164168

169+
if ( _additionalDataColumns != null )
170+
{
171+
eventsTable.Columns.AddRange(_additionalDataColumns);
172+
}
165173

166174
// Create an array for DataColumn objects.
167175
var keys = new DataColumn[1];
@@ -171,7 +179,7 @@ DataTable CreateDataTable()
171179
return eventsTable;
172180
}
173181

174-
void FillDataTable(IEnumerable<LogEvent> events)
182+
void FillDataTable(IEnumerable<LogEvent> events)
175183
{
176184
// Add the new rows to the collection.
177185
foreach (var logEvent in events)
@@ -188,6 +196,10 @@ void FillDataTable(IEnumerable<LogEvent> events)
188196
{
189197
row["Properties"] = ConvertPropertiesToXmlStructure(logEvent.Properties);
190198
}
199+
if ( _additionalDataColumns != null )
200+
{
201+
ConvertPropertiesToColumn( row, logEvent.Properties );
202+
}
191203

192204
_eventsTable.Rows.Add(row);
193205
}
@@ -213,6 +225,23 @@ static string ConvertPropertiesToXmlStructure(
213225
return sb.ToString();
214226
}
215227

228+
/// <summary>
229+
/// Mapping values from properties which have a corresponding data row.
230+
/// Matching is done based on Column name and property key
231+
/// </summary>
232+
/// <param name="row"></param>
233+
/// <param name="properties"></param>
234+
private void ConvertPropertiesToColumn(
235+
DataRow row, IReadOnlyDictionary<string, LogEventPropertyValue> properties)
236+
{
237+
foreach (var property in properties)
238+
{
239+
if (row.Table.Columns.Contains(property.Key))
240+
{
241+
row[property.Key] = property.Value.ToString();
242+
}
243+
}
244+
}
216245

217246
/// <summary>
218247
/// Disposes the connection
@@ -223,7 +252,7 @@ protected override void Dispose(bool disposing)
223252
_token.Cancel();
224253

225254
if (_eventsTable != null)
226-
_eventsTable.Dispose();
255+
_eventsTable.Dispose();
227256

228257
base.Dispose(disposing);
229258
}

0 commit comments

Comments
 (0)