Skip to content

Commit cd2119f

Browse files
committed
* Internal ctors for sinks with injectable dependencies for tests
* Extracted DataTableCreator from MSSqlServerSinkTraits
1 parent b0b4fca commit cd2119f

File tree

7 files changed

+265
-223
lines changed

7 files changed

+265
-223
lines changed

src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/MSSqlServerAuditSink.cs

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
using Serilog.Debugging;
2121
using Serilog.Events;
2222
using Serilog.Formatting;
23+
using Serilog.Sinks.MSSqlServer.Output;
2324
using Serilog.Sinks.MSSqlServer.Sinks.MSSqlServer.Options;
2425
using Serilog.Sinks.MSSqlServer.Sinks.MSSqlServer.Platform;
2526

@@ -33,6 +34,7 @@ public class MSSqlServerAuditSink : ILogEventSink, IDisposable
3334
{
3435
private readonly SinkOptions _sinkOptions;
3536
private readonly ISqlConnectionFactory _sqlConnectionFactory;
37+
private readonly ILogEventDataGenerator _logEventDataGenerator;
3638
private readonly MSSqlServerSinkTraits _traits;
3739

3840
/// <summary>
@@ -77,6 +79,23 @@ public MSSqlServerAuditSink(
7779
IFormatProvider formatProvider = null,
7880
ColumnOptions columnOptions = null,
7981
ITextFormatter logEventFormatter = null)
82+
: this(sinkOptions, columnOptions,
83+
new SqlConnectionFactory(connectionString,
84+
new AzureManagedServiceAuthenticator(
85+
sinkOptions?.UseAzureManagedIdentity ?? default,
86+
sinkOptions.AzureServiceTokenProviderResource)),
87+
new LogEventDataGenerator(columnOptions,
88+
new StandardColumnDataGenerator(columnOptions, formatProvider, logEventFormatter),
89+
new PropertiesColumnDataGenerator(columnOptions)))
90+
{
91+
}
92+
93+
// Internal constructor with injectable dependencies for better testability
94+
internal MSSqlServerAuditSink(
95+
SinkOptions sinkOptions,
96+
ColumnOptions columnOptions,
97+
ISqlConnectionFactory sqlConnectionFactory,
98+
ILogEventDataGenerator logEventDataGenerator)
8099
{
81100
_sinkOptions = sinkOptions;
82101
if (_sinkOptions?.TableName == null)
@@ -89,12 +108,12 @@ public MSSqlServerAuditSink(
89108
if (columnOptions.DisableTriggers)
90109
throw new NotSupportedException($"The {nameof(ColumnOptions.DisableTriggers)} option is not supported for auditing.");
91110

92-
var azureManagedServiceAuthenticator = new AzureManagedServiceAuthenticator(_sinkOptions.UseAzureManagedIdentity,
93-
_sinkOptions.AzureServiceTokenProviderResource);
94-
_sqlConnectionFactory = new SqlConnectionFactory(connectionString, azureManagedServiceAuthenticator);
111+
_sqlConnectionFactory = sqlConnectionFactory ?? throw new ArgumentNullException(nameof(sqlConnectionFactory));
112+
113+
_logEventDataGenerator = logEventDataGenerator ?? throw new ArgumentNullException(nameof(logEventDataGenerator));
95114

96115
_traits = new MSSqlServerSinkTraits(_sqlConnectionFactory, _sinkOptions.TableName, _sinkOptions.SchemaName,
97-
columnOptions, formatProvider, _sinkOptions.AutoCreateSqlTable, logEventFormatter);
116+
columnOptions, _sinkOptions.AutoCreateSqlTable);
98117
}
99118

100119
/// <summary>Emit the provided log event to the sink.</summary>
@@ -114,7 +133,7 @@ public void Emit(LogEvent logEvent)
114133
var parameterList = new StringBuilder(") VALUES (");
115134

116135
var index = 0;
117-
foreach (var field in _traits.GetColumnsAndValues(logEvent))
136+
foreach (var field in _logEventDataGenerator.GetColumnsAndValues(logEvent))
118137
{
119138
if (index != 0)
120139
{

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

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
using Serilog.Debugging;
2323
using Serilog.Events;
2424
using Serilog.Formatting;
25+
using Serilog.Sinks.MSSqlServer.Output;
2526
using Serilog.Sinks.MSSqlServer.Sinks.MSSqlServer.Options;
2627
using Serilog.Sinks.MSSqlServer.Sinks.MSSqlServer.Platform;
2728
using Serilog.Sinks.PeriodicBatching;
@@ -36,6 +37,7 @@ public class MSSqlServerSink : PeriodicBatchingSink
3637
private readonly SinkOptions _sinkOptions;
3738
private readonly ColumnOptions _columnOptions;
3839
private readonly ISqlConnectionFactory _sqlConnectionFactory;
40+
private readonly ILogEventDataGenerator _logEventDataGenerator;
3941
private readonly MSSqlServerSinkTraits _traits;
4042

4143
/// <summary>
@@ -99,6 +101,23 @@ public MSSqlServerSink(
99101
IFormatProvider formatProvider = null,
100102
ColumnOptions columnOptions = null,
101103
ITextFormatter logEventFormatter = null)
104+
: this(sinkOptions, columnOptions,
105+
new SqlConnectionFactory(connectionString,
106+
new AzureManagedServiceAuthenticator(
107+
sinkOptions?.UseAzureManagedIdentity ?? default,
108+
sinkOptions.AzureServiceTokenProviderResource)),
109+
new LogEventDataGenerator(columnOptions,
110+
new StandardColumnDataGenerator(columnOptions, formatProvider, logEventFormatter),
111+
new PropertiesColumnDataGenerator(columnOptions)))
112+
{
113+
}
114+
115+
// Internal constructor with injectable dependencies for better testability
116+
internal MSSqlServerSink(
117+
SinkOptions sinkOptions,
118+
ColumnOptions columnOptions,
119+
ISqlConnectionFactory sqlConnectionFactory,
120+
ILogEventDataGenerator logEventDataGenerator)
102121
: base(sinkOptions?.BatchPostingLimit ?? DefaultBatchPostingLimit, sinkOptions?.BatchPeriod ?? DefaultPeriod)
103122
{
104123
_sinkOptions = sinkOptions;
@@ -110,12 +129,12 @@ public MSSqlServerSink(
110129
_columnOptions = columnOptions ?? new ColumnOptions();
111130
_columnOptions.FinalizeConfigurationForSinkConstructor();
112131

113-
var azureManagedServiceAuthenticator = new AzureManagedServiceAuthenticator(sinkOptions.UseAzureManagedIdentity,
114-
sinkOptions.AzureServiceTokenProviderResource);
115-
_sqlConnectionFactory = new SqlConnectionFactory(connectionString, azureManagedServiceAuthenticator);
132+
_sqlConnectionFactory = sqlConnectionFactory ?? throw new ArgumentNullException(nameof(sqlConnectionFactory));
133+
134+
_logEventDataGenerator = logEventDataGenerator ?? throw new ArgumentNullException(nameof(logEventDataGenerator));
116135

117136
_traits = new MSSqlServerSinkTraits(_sqlConnectionFactory, sinkOptions.TableName, sinkOptions.SchemaName,
118-
_columnOptions, formatProvider, sinkOptions.AutoCreateSqlTable, logEventFormatter);
137+
_columnOptions, sinkOptions.AutoCreateSqlTable);
119138
}
120139

121140
/// <summary>
@@ -185,7 +204,7 @@ private void FillDataTable(IEnumerable<LogEvent> events)
185204
{
186205
var row = _traits.EventTable.NewRow();
187206

188-
foreach (var field in _traits.GetColumnsAndValues(logEvent))
207+
foreach (var field in _logEventDataGenerator.GetColumnsAndValues(logEvent))
189208
{
190209
row[field.Key] = field.Value;
191210
}

src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/MSSqlServerSinkTraits.cs

Lines changed: 5 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,15 @@
1-
// Copyright 2020 Serilog Contributors
2-
//
3-
// Licensed under the Apache License, Version 2.0 (the "License");
4-
// you may not use this file except in compliance with the License.
5-
// You may obtain a copy of the License at
6-
//
7-
// http://www.apache.org/licenses/LICENSE-2.0
8-
//
9-
// Unless required by applicable law or agreed to in writing, software
10-
// distributed under the License is distributed on an "AS IS" BASIS,
11-
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12-
// See the License for the specific language governing permissions and
13-
// limitations under the License.
14-
151
using System;
16-
using System.Collections.Generic;
172
using System.Data;
18-
using Serilog.Debugging;
19-
using Serilog.Events;
20-
using Serilog.Formatting;
21-
using Serilog.Sinks.MSSqlServer.Output;
223
using Serilog.Sinks.MSSqlServer.Platform;
234
using Serilog.Sinks.MSSqlServer.Sinks.MSSqlServer.Platform;
245

256
namespace Serilog.Sinks.MSSqlServer
267
{
27-
/// <summary>Contains common functionality and properties used by both MSSqlServerSinks.</summary>
288
internal class MSSqlServerSinkTraits : IDisposable
299
{
3010
private readonly string _tableName;
3111
private readonly string _schemaName;
3212
private readonly ColumnOptions _columnOptions;
33-
private readonly ILogEventDataGenerator _logEventDataGenerator;
3413
private bool _disposedValue;
3514

3615
public DataTable EventTable { get; }
@@ -40,11 +19,9 @@ public MSSqlServerSinkTraits(
4019
string tableName,
4120
string schemaName,
4221
ColumnOptions columnOptions,
43-
IFormatProvider formatProvider,
44-
bool autoCreateSqlTable,
45-
ITextFormatter logEventFormatter)
46-
: this(tableName, schemaName, columnOptions, formatProvider, autoCreateSqlTable,
47-
logEventFormatter, new SqlTableCreator(new SqlCreateTableWriter(), sqlConnectionFactory))
22+
bool autoCreateSqlTable)
23+
: this(tableName, schemaName, columnOptions, autoCreateSqlTable,
24+
new SqlTableCreator(new SqlCreateTableWriter(), sqlConnectionFactory))
4825
{
4926
}
5027

@@ -53,9 +30,7 @@ internal MSSqlServerSinkTraits(
5330
string tableName,
5431
string schemaName,
5532
ColumnOptions columnOptions,
56-
IFormatProvider formatProvider,
5733
bool autoCreateSqlTable,
58-
ITextFormatter logEventFormatter,
5934
ISqlTableCreator sqlTableCreator)
6035
{
6136
if (string.IsNullOrWhiteSpace(tableName))
@@ -69,50 +44,15 @@ internal MSSqlServerSinkTraits(
6944
throw new ArgumentNullException(nameof(sqlTableCreator));
7045

7146
// TODO initialize this outside of this class
72-
var standardColumnDataGenerator = new StandardColumnDataGenerator(columnOptions, formatProvider, logEventFormatter);
73-
var propertiesColumnDataGenerator = new PropertiesColumnDataGenerator(columnOptions);
74-
_logEventDataGenerator = new LogEventDataGenerator(columnOptions, standardColumnDataGenerator, propertiesColumnDataGenerator);
75-
76-
EventTable = CreateDataTable();
47+
var dataTableCreator = new DataTableCreator();
48+
EventTable = dataTableCreator.CreateDataTable(_tableName, _columnOptions);
7749

7850
if (autoCreateSqlTable)
7951
{
8052
sqlTableCreator.CreateTable(_schemaName, _tableName, EventTable, _columnOptions);
8153
}
8254
}
8355

84-
public IEnumerable<KeyValuePair<string, object>> GetColumnsAndValues(LogEvent logEvent)
85-
{
86-
return _logEventDataGenerator.GetColumnsAndValues(logEvent);
87-
}
88-
89-
private DataTable CreateDataTable()
90-
{
91-
var eventsTable = new DataTable(_tableName);
92-
93-
foreach (var standardColumn in _columnOptions.Store)
94-
{
95-
var standardOpts = _columnOptions.GetStandardColumnOptions(standardColumn);
96-
var dataColumn = standardOpts.AsDataColumn();
97-
eventsTable.Columns.Add(dataColumn);
98-
if (standardOpts == _columnOptions.PrimaryKey)
99-
eventsTable.PrimaryKey = new DataColumn[] { dataColumn };
100-
}
101-
102-
if (_columnOptions.AdditionalColumns != null)
103-
{
104-
foreach (var addCol in _columnOptions.AdditionalColumns)
105-
{
106-
var dataColumn = addCol.AsDataColumn();
107-
eventsTable.Columns.Add(dataColumn);
108-
if (addCol == _columnOptions.PrimaryKey)
109-
eventsTable.PrimaryKey = new DataColumn[] { dataColumn };
110-
}
111-
}
112-
113-
return eventsTable;
114-
}
115-
11656
protected virtual void Dispose(bool disposing)
11757
{
11858
if (!_disposedValue)
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using System.Data;
2+
3+
namespace Serilog.Sinks.MSSqlServer.Platform
4+
{
5+
internal class DataTableCreator : IDataTableCreator
6+
{
7+
public DataTable CreateDataTable(string tableName, ColumnOptions columnOptions)
8+
{
9+
var eventsTable = new DataTable(tableName);
10+
11+
foreach (var standardColumn in columnOptions.Store)
12+
{
13+
var standardOpts = columnOptions.GetStandardColumnOptions(standardColumn);
14+
var dataColumn = standardOpts.AsDataColumn();
15+
eventsTable.Columns.Add(dataColumn);
16+
if (standardOpts == columnOptions.PrimaryKey)
17+
eventsTable.PrimaryKey = new DataColumn[] { dataColumn };
18+
}
19+
20+
if (columnOptions.AdditionalColumns != null)
21+
{
22+
foreach (var addCol in columnOptions.AdditionalColumns)
23+
{
24+
var dataColumn = addCol.AsDataColumn();
25+
eventsTable.Columns.Add(dataColumn);
26+
if (addCol == columnOptions.PrimaryKey)
27+
eventsTable.PrimaryKey = new DataColumn[] { dataColumn };
28+
}
29+
}
30+
31+
return eventsTable;
32+
}
33+
}
34+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using System.Data;
2+
3+
namespace Serilog.Sinks.MSSqlServer.Platform
4+
{
5+
internal interface IDataTableCreator
6+
{
7+
DataTable CreateDataTable(string tableName, ColumnOptions columnOptions);
8+
}
9+
}

0 commit comments

Comments
 (0)