Skip to content

Commit 078a925

Browse files
authored
Merge pull request #241 from ckadluba/refactoring-cleanup-tests
Refactoring, cleanup and tests
2 parents 01c2310 + 7ff2ada commit 078a925

27 files changed

+619
-370
lines changed

CHANGES.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,20 @@
1-
5.2
1+
5.2.0
2+
* Enhancement #232: Allow to override formatter for rendering LogEvent column.
3+
* Fixed #187 (again - still an exception when using logevent column with TimeStamp column type DateTimeOffset).
4+
* Added sample programs
5+
6+
5.1.4
7+
* Fixed #187 Support datetimeoffset as a column type for default column TimeStamp.
8+
* Fixed #229 Slight issue with documentation.
9+
10+
5.1.3
11+
* Support binary data type, support specify data length in column config, support specify allow null column
12+
* Also build on unit-test commits
13+
* Added issue templase
14+
* Hybrid config implementation
15+
* Bugfixes
16+
17+
5.1.2
218
* Support for Audit sink added (#118/#110).
319

420
4.0.0
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
using Microsoft.Extensions.Configuration;
2-
using Serilog.Debugging;
3-
using System;
4-
using System.Collections.Generic;
5-
using System.Collections.ObjectModel;
6-
using System.Linq;
2+
using Serilog.Sinks.MSSqlServer.Configuration;
73

84
namespace Serilog.Sinks.MSSqlServer
95
{
@@ -12,208 +8,27 @@ namespace Serilog.Sinks.MSSqlServer
128
/// </summary>
139
internal static class ApplyMicrosoftExtensionsConfiguration
1410
{
11+
internal static IMicrosoftExtensionsConnectionStringProvider ConnectionStringProvider { get; set; } = new MicrosoftExtensionsConnectionStringProvider();
12+
13+
internal static IMicrosoftExtensionsColumnOptionsProvider ColumnOptionsProvider { get; set; } = new MicrosoftExtensionsColumnOptionsProvider();
14+
1515
/// <summary>
1616
/// Examine if supplied connection string is a reference to an item in the "ConnectionStrings" section of web.config
1717
/// If it is, return the ConnectionStrings item, if not, return string as supplied.
1818
/// </summary>
1919
/// <param name="nameOrConnectionString">The name of the ConnectionStrings key or raw connection string.</param>
2020
/// <param name="appConfiguration">Additional application-level configuration.</param>
2121
/// <remarks>Pulled from review of Entity Framework 6 methodology for doing the same</remarks>
22-
internal static string GetConnectionString(string nameOrConnectionString, IConfiguration appConfiguration)
23-
{
24-
// If there is an `=`, we assume this is a raw connection string not a named value
25-
// If there are no `=`, attempt to pull the named value from config
26-
if (nameOrConnectionString.IndexOf('=') > -1) return nameOrConnectionString;
27-
string cs = appConfiguration?.GetConnectionString(nameOrConnectionString);
28-
if (string.IsNullOrEmpty(cs))
29-
{
30-
SelfLog.WriteLine("MSSqlServer sink configured value {0} is not found in ConnectionStrings settings and does not appear to be a raw connection string.", nameOrConnectionString);
31-
}
32-
return cs;
33-
}
22+
internal static string GetConnectionString(string nameOrConnectionString, IConfiguration appConfiguration) =>
23+
ConnectionStringProvider.GetConnectionString(nameOrConnectionString, appConfiguration);
3424

3525
/// <summary>
3626
/// Create or add to the ColumnOptions object and apply any configuration changes to it.
3727
/// </summary>
3828
/// <param name="columnOptions">An optional externally-created ColumnOptions object to be updated with additional configuration values.</param>
3929
/// <param name="config">A configuration section typically named "columnOptionsSection" (see docs).</param>
4030
/// <returns></returns>
41-
internal static ColumnOptions ConfigureColumnOptions(ColumnOptions columnOptions, IConfigurationSection config)
42-
{
43-
// Do not use configuration binding (ie GetSection.Get<ColumnOptions>). That will create a new
44-
// ColumnOptions object which would overwrite settings if the caller passed in a ColumnOptions
45-
// object via the extension method's columnOptions parameter.
46-
47-
var opts = columnOptions ?? new ColumnOptions();
48-
if (config == null || !config.GetChildren().Any()) return opts;
49-
50-
AddRemoveStandardColumns();
51-
AddAdditionalColumns();
52-
ReadStandardColumns();
53-
ReadMiscColumnOptions();
54-
55-
return opts;
56-
57-
void AddRemoveStandardColumns()
58-
{
59-
// add standard columns
60-
var addStd = config.GetSection("addStandardColumns");
61-
if (addStd.GetChildren().Any())
62-
{
63-
foreach (var col in addStd.GetChildren().ToList())
64-
{
65-
if (Enum.TryParse(col.Value, ignoreCase: true, result: out StandardColumn stdcol)
66-
&& !opts.Store.Contains(stdcol))
67-
opts.Store.Add(stdcol);
68-
}
69-
}
70-
71-
// remove standard columns
72-
var removeStd = config.GetSection("removeStandardColumns");
73-
if (removeStd.GetChildren().Any())
74-
{
75-
foreach (var col in removeStd.GetChildren().ToList())
76-
{
77-
if (Enum.TryParse(col.Value, ignoreCase: true, result: out StandardColumn stdcol)
78-
&& opts.Store.Contains(stdcol))
79-
opts.Store.Remove(stdcol);
80-
}
81-
}
82-
}
83-
84-
void AddAdditionalColumns()
85-
{
86-
var newcols =
87-
config.GetSection("additionalColumns").Get<List<SqlColumn>>()
88-
?? config.GetSection("customColumns").Get<List<SqlColumn>>(); // backwards-compatibility
89-
90-
if (newcols != null)
91-
{
92-
foreach (var c in newcols)
93-
{
94-
if (!string.IsNullOrWhiteSpace(c.ColumnName))
95-
{
96-
if (opts.AdditionalColumns == null)
97-
opts.AdditionalColumns = new Collection<SqlColumn>();
98-
99-
opts.AdditionalColumns.Add(c);
100-
}
101-
}
102-
}
103-
}
104-
105-
void ReadStandardColumns()
106-
{
107-
var section = config.GetSection("id");
108-
if (section != null)
109-
{
110-
SetCommonColumnOptions(opts.Id);
111-
#pragma warning disable 618 // deprecated: BigInt property
112-
SetProperty.IfNotNull<bool>(section["bigInt"], (val) => opts.Id.BigInt = val);
113-
#pragma warning restore 618
114-
}
115-
116-
section = config.GetSection("level");
117-
if (section != null)
118-
{
119-
SetCommonColumnOptions(opts.Level);
120-
SetProperty.IfNotNull<bool>(section["storeAsEnum"], (val) => opts.Level.StoreAsEnum = val);
121-
}
122-
123-
section = config.GetSection("properties");
124-
if (section != null)
125-
{
126-
SetCommonColumnOptions(opts.Properties);
127-
SetProperty.IfNotNull<bool>(section["excludeAdditionalProperties"], (val) => opts.Properties.ExcludeAdditionalProperties = val);
128-
SetProperty.IfNotNull<string>(section["dictionaryElementName"], (val) => opts.Properties.DictionaryElementName = val);
129-
SetProperty.IfNotNull<string>(section["itemElementName"], (val) => opts.Properties.ItemElementName = val);
130-
SetProperty.IfNotNull<bool>(section["omitDictionaryContainerElement"], (val) => opts.Properties.OmitDictionaryContainerElement = val);
131-
SetProperty.IfNotNull<bool>(section["omitSequenceContainerElement"], (val) => opts.Properties.OmitSequenceContainerElement = val);
132-
SetProperty.IfNotNull<bool>(section["omitStructureContainerElement"], (val) => opts.Properties.OmitStructureContainerElement = val);
133-
SetProperty.IfNotNull<bool>(section["omitElementIfEmpty"], (val) => opts.Properties.OmitElementIfEmpty = val);
134-
SetProperty.IfNotNull<string>(section["propertyElementName"], (val) => opts.Properties.PropertyElementName = val);
135-
SetProperty.IfNotNull<string>(section["rootElementName"], (val) => opts.Properties.RootElementName = val);
136-
SetProperty.IfNotNull<string>(section["sequenceElementName"], (val) => opts.Properties.SequenceElementName = val);
137-
SetProperty.IfNotNull<string>(section["structureElementName"], (val) => opts.Properties.StructureElementName = val);
138-
SetProperty.IfNotNull<bool>(section["usePropertyKeyAsElementName"], (val) => opts.Properties.UsePropertyKeyAsElementName = val);
139-
// TODO PropertiesFilter would need a compiled Predicate<string> (high Roslyn overhead, see Serilog Config repo #106)
140-
}
141-
142-
section = config.GetSection("timeStamp");
143-
if (section != null)
144-
{
145-
SetCommonColumnOptions(opts.TimeStamp);
146-
SetProperty.IfNotNull<bool>(section["convertToUtc"], (val) => opts.TimeStamp.ConvertToUtc = val);
147-
}
148-
149-
section = config.GetSection("logEvent");
150-
if (section != null)
151-
{
152-
SetCommonColumnOptions(opts.LogEvent);
153-
SetProperty.IfNotNull<bool>(section["excludeAdditionalProperties"], (val) => opts.LogEvent.ExcludeAdditionalProperties = val);
154-
SetProperty.IfNotNull<bool>(section["ExcludeStandardColumns"], (val) => opts.LogEvent.ExcludeStandardColumns = val);
155-
}
156-
157-
section = config.GetSection("message");
158-
if (section != null)
159-
SetCommonColumnOptions(opts.Message);
160-
161-
section = config.GetSection("exception");
162-
if (section != null)
163-
SetCommonColumnOptions(opts.Exception);
164-
165-
section = config.GetSection("messageTemplate");
166-
if (section != null)
167-
SetCommonColumnOptions(opts.MessageTemplate);
168-
169-
// Standard Columns are subclasses of the SqlColumn class
170-
void SetCommonColumnOptions(SqlColumn target)
171-
{
172-
SetProperty.IfNotNullOrEmpty<string>(section["columnName"], (val) => target.ColumnName = val);
173-
SetProperty.IfNotNull<string>(section["dataType"], (val) => target.SetDataTypeFromConfigString(val));
174-
SetProperty.IfNotNull<bool>(section["allowNull"], (val) => target.AllowNull = val);
175-
SetProperty.IfNotNull<int>(section["dataLength"], (val) => target.DataLength = val);
176-
SetProperty.IfNotNull<bool>(section["nonClusteredIndex"], (val) => target.NonClusteredIndex = val);
177-
}
178-
}
179-
180-
void ReadMiscColumnOptions()
181-
{
182-
SetProperty.IfNotNull<bool>(config["disableTriggers"], (val) => opts.DisableTriggers = val);
183-
SetProperty.IfNotNull<bool>(config["clusteredColumnstoreIndex"], (val) => opts.ClusteredColumnstoreIndex = val);
184-
185-
string pkName = config["primaryKeyColumnName"];
186-
if (!string.IsNullOrEmpty(pkName))
187-
{
188-
if (opts.ClusteredColumnstoreIndex)
189-
throw new ArgumentException("SQL Clustered Columnstore Indexes and primary key constraints are mutually exclusive.");
190-
191-
foreach (var standardCol in opts.Store)
192-
{
193-
var stdColOpts = opts.GetStandardColumnOptions(standardCol);
194-
if (pkName.Equals(stdColOpts.ColumnName, StringComparison.InvariantCultureIgnoreCase))
195-
{
196-
opts.PrimaryKey = stdColOpts;
197-
break;
198-
}
199-
}
200-
201-
if (opts.PrimaryKey == null && opts.AdditionalColumns != null)
202-
{
203-
foreach (var col in opts.AdditionalColumns)
204-
{
205-
if (pkName.Equals(col.ColumnName, StringComparison.InvariantCultureIgnoreCase))
206-
{
207-
opts.PrimaryKey = col;
208-
break;
209-
}
210-
}
211-
}
212-
213-
if (opts.PrimaryKey == null)
214-
throw new ArgumentException($"Could not match the configured primary key column name \"{pkName}\" with a data column in the table.");
215-
}
216-
}
217-
}
31+
internal static ColumnOptions ConfigureColumnOptions(ColumnOptions columnOptions, IConfigurationSection config) =>
32+
ColumnOptionsProvider.ConfigureColumnOptions(columnOptions, config);
21833
}
21934
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using Microsoft.Extensions.Configuration;
2+
3+
namespace Serilog.Sinks.MSSqlServer.Configuration
4+
{
5+
internal interface IMicrosoftExtensionsColumnOptionsProvider
6+
{
7+
ColumnOptions ConfigureColumnOptions(ColumnOptions columnOptions, IConfigurationSection config);
8+
}
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using Microsoft.Extensions.Configuration;
2+
3+
namespace Serilog.Sinks.MSSqlServer.Configuration
4+
{
5+
internal interface IMicrosoftExtensionsConnectionStringProvider
6+
{
7+
string GetConnectionString(string nameOrConnectionString, IConfiguration appConfiguration);
8+
}
9+
}

0 commit comments

Comments
 (0)