Skip to content

Commit 9a339d8

Browse files
committed
Enhancement #360: automatic DB creation
* Added sink option AutoCreateSqlDatabase * Lots of refactoring (removed duplicate code, cleaner interfaces of sink dependency classes, etc.) * Unit tests
1 parent cf08a68 commit 9a339d8

File tree

44 files changed

+769
-426
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+769
-426
lines changed

src/Serilog.Sinks.MSSqlServer/Configuration/Implementations/Microsoft.Extensions.Configuration/MicrosoftExtensionsSinkOptionsProvider.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ private static void ReadTableOptions(IConfigurationSection config, MSSqlServerSi
2323
{
2424
SetProperty.IfNotNull<string>(config["tableName"], val => sinkOptions.TableName = val);
2525
SetProperty.IfNotNull<string>(config["schemaName"], val => sinkOptions.SchemaName = val);
26+
SetProperty.IfNotNull<bool>(config["autoCreateSqlDatabase"], val => sinkOptions.AutoCreateSqlDatabase = val);
2627
SetProperty.IfNotNull<bool>(config["autoCreateSqlTable"], val => sinkOptions.AutoCreateSqlTable = val);
2728
SetProperty.IfNotNull<bool>(config["enlistInTransaction"], val => sinkOptions.EnlistInTransaction = val);
2829
}

src/Serilog.Sinks.MSSqlServer/Configuration/Implementations/System.Configuration/MSSqlServerConfigurationSection.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,12 @@ public ValueConfigElement SchemaName
151151
get => (ValueConfigElement)base[nameof(SchemaName)];
152152
}
153153

154+
[ConfigurationProperty(nameof(AutoCreateSqlDatabase))]
155+
public ValueConfigElement AutoCreateSqlDatabase
156+
{
157+
get => (ValueConfigElement)base[nameof(AutoCreateSqlDatabase)];
158+
}
159+
154160
[ConfigurationProperty(nameof(AutoCreateSqlTable))]
155161
public ValueConfigElement AutoCreateSqlTable
156162
{
@@ -179,11 +185,6 @@ public ValueConfigElement BatchPeriod
179185
public ValueConfigElement EagerlyEmitFirstEvent
180186
{
181187
get => (ValueConfigElement)base[nameof(EagerlyEmitFirstEvent)];
182-
internal set
183-
{
184-
// Internal setter for unit testing purpose
185-
base[nameof(PrimaryKeyColumnName)] = value;
186-
}
187188
}
188189
}
189190
}

src/Serilog.Sinks.MSSqlServer/Configuration/Implementations/System.Configuration/SystemConfigurationSinkOptionsProvider.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ private static void ReadTableOptions(MSSqlServerConfigurationSection config, MSS
1818
{
1919
SetProperty.IfProvided<string>(config.TableName, nameof(config.TableName.Value), value => sinkOptions.TableName = value);
2020
SetProperty.IfProvided<string>(config.SchemaName, nameof(config.SchemaName.Value), value => sinkOptions.SchemaName = value);
21+
SetProperty.IfProvided<bool>(config.AutoCreateSqlDatabase, nameof(config.AutoCreateSqlDatabase.Value),
22+
value => sinkOptions.AutoCreateSqlDatabase = value);
2123
SetProperty.IfProvided<bool>(config.AutoCreateSqlTable, nameof(config.AutoCreateSqlTable.Value),
2224
value => sinkOptions.AutoCreateSqlTable = value);
2325
SetProperty.IfProvided<bool>(config.EnlistInTransaction, nameof(config.EnlistInTransaction.Value),

src/Serilog.Sinks.MSSqlServer/GlobalSuppressions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
[assembly: SuppressMessage("Design", "CA1010:Collections should implement generic interface", Justification = "Cannot be changed on public classes for backward compatibility reasons.", Scope = "namespaceanddescendants", Target = "~N:Serilog.Sinks.MSSqlServer")]
1313
[assembly: SuppressMessage("Performance", "CA1822: Mark members as static", Justification = "Using instance members over static for better testablilty.", Scope = "namespaceanddescendants", Target = "~N:Serilog.Sinks.MSSqlServer")]
1414
[assembly: SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Too hard to change. Accepted for now.", Scope = "member", Target = "~M:Serilog.Sinks.MSSqlServer.SetProperty.IfNotNull``1(System.String,Serilog.Sinks.MSSqlServer.SetProperty.PropertySetter{``0})")]
15-
[assembly: SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Too hard to change. Accepted for now.", Scope = "member", Target = "~M:Serilog.Sinks.MSSqlServer.Platform.SqlTableCreator.CreateTable(System.Data.DataTable)")]
15+
[assembly: SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Too hard to change. Accepted for now.", Scope = "member", Target = "~M:Serilog.Sinks.MSSqlServer.Platform.SqlCommandExecutor.Execute()")]
1616
[assembly: SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Too hard to change. Accepted for now.", Scope = "member", Target = "~M:Serilog.Sinks.MSSqlServer.Output.StandardColumnDataGenerator.ConvertPropertiesToXmlStructure(System.Collections.Generic.IEnumerable{System.Collections.Generic.KeyValuePair{System.String,Serilog.Events.LogEventPropertyValue}})~System.String")]
1717
[assembly: SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Too hard to change. Accepted for now.", Scope = "member", Target = "~M:Serilog.Sinks.MSSqlServer.Output.AdditionalColumnDataGenerator.TryChangeType(System.Object,System.Type,System.Object@)~System.Boolean")]
1818
[assembly: SuppressMessage("Naming", "CA1711:Identifiers should not have incorrect suffix", Justification = "Cannot be changed on public classes for backward compatibility reasons.", Scope = "type", Target = "~T:Serilog.Sinks.MSSqlServer.StandardColumnConfigException")]

src/Serilog.Sinks.MSSqlServer/Serilog.Sinks.MSSqlServer.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<PropertyGroup>
44
<Description>A Serilog sink that writes events to Microsoft SQL Server</Description>
5-
<VersionPrefix>6.2.1</VersionPrefix>
5+
<VersionPrefix>6.3.0</VersionPrefix>
66
<Authors>Michiel van Oudheusden;Christian Kadluba;Serilog Contributors</Authors>
77
<TargetFrameworks>netstandard2.0;net462;net472;net6.0</TargetFrameworks>
88
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>

src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/Dependencies/SinkDependencies.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ namespace Serilog.Sinks.MSSqlServer.Dependencies
55
internal class SinkDependencies
66
{
77
public IDataTableCreator DataTableCreator { get; set; }
8-
public ISqlTableCreator SqlTableCreator { get; set; }
8+
public ISqlCommandExecutor SqlDatabaseCreator { get; set; }
9+
public ISqlCommandExecutor SqlTableCreator { get; set; }
910
public ISqlBulkBatchWriter SqlBulkBatchWriter { get; set; }
1011
public ISqlLogEventWriter SqlLogEventWriter { get; set; }
1112
}

src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/Dependencies/SinkDependenciesFactory.cs

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
using Serilog.Sinks.MSSqlServer.Output;
44
using Serilog.Sinks.MSSqlServer.Platform;
55
using Serilog.Sinks.MSSqlServer.Platform.SqlClient;
6-
using Serilog.Sinks.MSSqlServer.Sinks.MSSqlServer.Output;
76

87
namespace Serilog.Sinks.MSSqlServer.Dependencies
98
{
@@ -19,10 +18,24 @@ internal static SinkDependencies Create(
1918
columnOptions = columnOptions ?? new ColumnOptions();
2019
columnOptions.FinalizeConfigurationForSinkConstructor();
2120

22-
var sqlConnectionFactory =
23-
new SqlConnectionFactory(connectionString,
24-
sinkOptions?.EnlistInTransaction ?? default,
25-
new SqlConnectionStringBuilderWrapper());
21+
// Add 'Enlist=false', so that ambient transactions (TransactionScope) will not affect/rollback logging
22+
// unless sink option EnlistInTransaction is set to true.
23+
var sqlConnectionStringBuilderWrapper = new SqlConnectionStringBuilderWrapper(
24+
connectionString, sinkOptions.EnlistInTransaction);
25+
var sqlConnectionFactory = new SqlConnectionFactory(sqlConnectionStringBuilderWrapper);
26+
var dataTableCreator = new DataTableCreator(sinkOptions.TableName, columnOptions);
27+
var sqlCreateTableWriter = new SqlCreateTableWriter(sinkOptions.SchemaName,
28+
sinkOptions.TableName, columnOptions, dataTableCreator);
29+
30+
var sqlConnectionStringBuilderWrapperNoDb = new SqlConnectionStringBuilderWrapper(
31+
connectionString, sinkOptions.EnlistInTransaction)
32+
{
33+
InitialCatalog = ""
34+
};
35+
var sqlConnectionFactoryNoDb =
36+
new SqlConnectionFactory(sqlConnectionStringBuilderWrapperNoDb);
37+
var sqlCreateDatabaseWriter = new SqlCreateDatabaseWriter(sqlConnectionStringBuilderWrapper.InitialCatalog);
38+
2639
var logEventDataGenerator =
2740
new LogEventDataGenerator(columnOptions,
2841
new StandardColumnDataGenerator(columnOptions, formatProvider,
@@ -34,13 +47,14 @@ internal static SinkDependencies Create(
3447

3548
var sinkDependencies = new SinkDependencies
3649
{
50+
DataTableCreator = dataTableCreator,
51+
SqlDatabaseCreator = new SqlDatabaseCreator(
52+
sqlCreateDatabaseWriter, sqlConnectionFactoryNoDb),
3753
SqlTableCreator = new SqlTableCreator(
38-
sinkOptions.TableName, sinkOptions.SchemaName, columnOptions,
39-
new SqlCreateTableWriter(), sqlConnectionFactory),
40-
DataTableCreator = new DataTableCreator(sinkOptions.TableName, columnOptions),
54+
sqlCreateTableWriter, sqlConnectionFactory),
4155
SqlBulkBatchWriter = new SqlBulkBatchWriter(
42-
sinkOptions.TableName, sinkOptions.SchemaName,
43-
columnOptions.DisableTriggers, sqlConnectionFactory, logEventDataGenerator),
56+
sinkOptions.TableName, sinkOptions.SchemaName, columnOptions.DisableTriggers,
57+
sqlConnectionFactory, logEventDataGenerator),
4458
SqlLogEventWriter = new SqlLogEventWriter(
4559
sinkOptions.TableName, sinkOptions.SchemaName,
4660
sqlConnectionFactory, logEventDataGenerator)

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

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ internal MSSqlServerAuditSink(
8989

9090
_sqlLogEventWriter = sinkDependencies.SqlLogEventWriter;
9191

92-
CreateTable(sinkOptions, sinkDependencies);
92+
CreateDatabaseAndTable(sinkOptions, sinkDependencies);
9393
}
9494

9595
/// <summary>Emit the provided log event to the sink.</summary>
@@ -150,14 +150,16 @@ private static void CheckSinkDependencies(SinkDependencies sinkDependencies)
150150
}
151151
}
152152

153-
private static void CreateTable(MSSqlServerSinkOptions sinkOptions, SinkDependencies sinkDependencies)
153+
private static void CreateDatabaseAndTable(MSSqlServerSinkOptions sinkOptions, SinkDependencies sinkDependencies)
154154
{
155+
if (sinkOptions.AutoCreateSqlDatabase)
156+
{
157+
sinkDependencies.SqlDatabaseCreator.Execute();
158+
}
159+
155160
if (sinkOptions.AutoCreateSqlTable)
156161
{
157-
using (var eventTable = sinkDependencies.DataTableCreator.CreateDataTable())
158-
{
159-
sinkDependencies.SqlTableCreator.CreateTable(eventTable);
160-
}
162+
sinkDependencies.SqlTableCreator.Execute();
161163
}
162164
}
163165
}

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

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ internal MSSqlServerSink(
111111
_sqlBulkBatchWriter = sinkDependencies.SqlBulkBatchWriter;
112112
_eventTable = sinkDependencies.DataTableCreator.CreateDataTable();
113113

114-
CreateTable(sinkOptions, sinkDependencies);
114+
CreateDatabaseAndTable(sinkOptions, sinkDependencies);
115115
}
116116

117117
/// <summary>
@@ -189,11 +189,16 @@ private static void CheckSinkDependencies(SinkDependencies sinkDependencies)
189189
}
190190
}
191191

192-
private void CreateTable(MSSqlServerSinkOptions sinkOptions, SinkDependencies sinkDependencies)
192+
private void CreateDatabaseAndTable(MSSqlServerSinkOptions sinkOptions, SinkDependencies sinkDependencies)
193193
{
194+
if (sinkOptions.AutoCreateSqlDatabase)
195+
{
196+
sinkDependencies.SqlDatabaseCreator.Execute();
197+
}
198+
194199
if (sinkOptions.AutoCreateSqlTable)
195200
{
196-
sinkDependencies.SqlTableCreator.CreateTable(_eventTable);
201+
sinkDependencies.SqlTableCreator.Execute();
197202
}
198203
}
199204
}

src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/MSSqlServerSinkOptions.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ internal MSSqlServerSinkOptions(
4343
/// </summary>
4444
public string SchemaName { get; set; }
4545

46+
/// <summary>
47+
/// Flag to automatically create the log events database if it does not exist (default: false)
48+
/// </summary>
49+
public bool AutoCreateSqlDatabase { get; set; }
50+
4651
/// <summary>
4752
/// Flag to automatically create the log events table if it does not exist (default: false)
4853
/// </summary>

0 commit comments

Comments
 (0)