Skip to content

Commit 5d70bc7

Browse files
authored
Merge pull request #167 from MV10/xml_config_parity
:shipit:
2 parents 2d1fa1b + 5c524cb commit 5d70bc7

19 files changed

+842
-121
lines changed

README.md

Lines changed: 64 additions & 22 deletions
Large diffs are not rendered by default.

src/Serilog.Sinks.MSSqlServer/Configuration/Microsoft.Extensions.Configuration/LoggerConfigurationMSSqlServerExtensions.cs

Lines changed: 30 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -151,9 +151,6 @@ private static string GetConnectionString(string nameOrConnectionString, IConfig
151151
return cs;
152152
}
153153

154-
// simulate using a property setter as an out parameter
155-
delegate void PropertySetter<T>(T value);
156-
157154
/// <summary>
158155
/// Create or add to the ColumnOptions object and apply any configuration changes to it.
159156
/// </summary>
@@ -184,7 +181,8 @@ void AddRemoveStandardColumns()
184181
{
185182
foreach (var col in addStd.GetChildren().ToList())
186183
{
187-
if (Enum.TryParse(col.Value, ignoreCase: true, result: out StandardColumn stdcol))
184+
if (Enum.TryParse(col.Value, ignoreCase: true, result: out StandardColumn stdcol)
185+
&& !opts.Store.Contains(stdcol))
188186
opts.Store.Add(stdcol);
189187
}
190188
}
@@ -195,7 +193,8 @@ void AddRemoveStandardColumns()
195193
{
196194
foreach (var col in removeStd.GetChildren().ToList())
197195
{
198-
if (Enum.TryParse(col.Value, ignoreCase: true, result: out StandardColumn stdcol))
196+
if (Enum.TryParse(col.Value, ignoreCase: true, result: out StandardColumn stdcol)
197+
&& opts.Store.Contains(stdcol))
199198
opts.Store.Remove(stdcol);
200199
}
201200
}
@@ -211,12 +210,12 @@ void AddAdditionalColumns()
211210
{
212211
foreach (var c in newcols)
213212
{
214-
if (!string.IsNullOrWhiteSpace(c.ColumnName))// && !string.IsNullOrWhiteSpace(c.DataType))
213+
if (!string.IsNullOrWhiteSpace(c.ColumnName))
215214
{
216215
if (opts.AdditionalColumns == null)
217216
opts.AdditionalColumns = new Collection<SqlColumn>();
218217

219-
opts.AdditionalColumns.Add(c);//.AsSqlColumn());
218+
opts.AdditionalColumns.Add(c);
220219
}
221220
}
222221
}
@@ -229,49 +228,49 @@ void ReadStandardColumns()
229228
{
230229
SetCommonColumnOptions(opts.Id);
231230
#pragma warning disable 618 // deprecated: BigInt property
232-
SetIfProvided<bool>((val) => { opts.Id.BigInt = val; }, section["bigInt"]);
231+
SetProperty.IfNotNull<bool>(section["bigInt"], (val) => opts.Id.BigInt = val);
233232
#pragma warning restore 618
234233
}
235234

236235
section = config.GetSection("level");
237236
if (section != null)
238237
{
239238
SetCommonColumnOptions(opts.Level);
240-
SetIfProvided<bool>((val) => { opts.Level.StoreAsEnum = val; }, section["storeAsEnum"]);
239+
SetProperty.IfNotNull<bool>(section["storeAsEnum"], (val) => opts.Level.StoreAsEnum = val);
241240
}
242241

243242
section = config.GetSection("properties");
244243
if (section != null)
245244
{
246245
SetCommonColumnOptions(opts.Properties);
247-
SetIfProvided<bool>((val) => { opts.Properties.ExcludeAdditionalProperties = val; }, section["excludeAdditionalProperties"]);
248-
SetIfProvided<string>((val) => { opts.Properties.DictionaryElementName = val; }, section["dictionaryElementName"]);
249-
SetIfProvided<string>((val) => { opts.Properties.ItemElementName = val; }, section["itemElementName"]);
250-
SetIfProvided<bool>((val) => { opts.Properties.OmitDictionaryContainerElement = val; }, section["omitDictionaryContainerElement"]);
251-
SetIfProvided<bool>((val) => { opts.Properties.OmitSequenceContainerElement = val; }, section["omitSequenceContainerElement"]);
252-
SetIfProvided<bool>((val) => { opts.Properties.OmitStructureContainerElement = val; }, section["omitStructureContainerElement"]);
253-
SetIfProvided<bool>((val) => { opts.Properties.OmitElementIfEmpty = val; }, section["omitElementIfEmpty"]);
254-
SetIfProvided<string>((val) => { opts.Properties.PropertyElementName = val; }, section["propertyElementName"]);
255-
SetIfProvided<string>((val) => { opts.Properties.RootElementName = val; }, section["rootElementName"]);
256-
SetIfProvided<string>((val) => { opts.Properties.SequenceElementName = val; }, section["sequenceElementName"]);
257-
SetIfProvided<string>((val) => { opts.Properties.StructureElementName = val; }, section["structureElementName"]);
258-
SetIfProvided<bool>((val) => { opts.Properties.UsePropertyKeyAsElementName = val; }, section["usePropertyKeyAsElementName"]);
246+
SetProperty.IfNotNull<bool>(section["excludeAdditionalProperties"], (val) => opts.Properties.ExcludeAdditionalProperties = val);
247+
SetProperty.IfNotNull<string>(section["dictionaryElementName"], (val) => opts.Properties.DictionaryElementName = val);
248+
SetProperty.IfNotNull<string>(section["itemElementName"], (val) => opts.Properties.ItemElementName = val);
249+
SetProperty.IfNotNull<bool>(section["omitDictionaryContainerElement"], (val) => opts.Properties.OmitDictionaryContainerElement = val);
250+
SetProperty.IfNotNull<bool>(section["omitSequenceContainerElement"], (val) => opts.Properties.OmitSequenceContainerElement = val);
251+
SetProperty.IfNotNull<bool>(section["omitStructureContainerElement"], (val) => opts.Properties.OmitStructureContainerElement = val);
252+
SetProperty.IfNotNull<bool>(section["omitElementIfEmpty"], (val) => opts.Properties.OmitElementIfEmpty = val);
253+
SetProperty.IfNotNull<string>(section["propertyElementName"], (val) => opts.Properties.PropertyElementName = val);
254+
SetProperty.IfNotNull<string>(section["rootElementName"], (val) => opts.Properties.RootElementName = val);
255+
SetProperty.IfNotNull<string>(section["sequenceElementName"], (val) => opts.Properties.SequenceElementName = val);
256+
SetProperty.IfNotNull<string>(section["structureElementName"], (val) => opts.Properties.StructureElementName = val);
257+
SetProperty.IfNotNull<bool>(section["usePropertyKeyAsElementName"], (val) => opts.Properties.UsePropertyKeyAsElementName = val);
259258
// TODO PropertiesFilter would need a compiled Predicate<string> (high Roslyn overhead, see Serilog Config repo #106)
260259
}
261260

262261
section = config.GetSection("timeStamp");
263262
if (section != null)
264263
{
265264
SetCommonColumnOptions(opts.TimeStamp);
266-
SetIfProvided<bool>((val) => { opts.TimeStamp.ConvertToUtc = val; }, section["convertToUtc"]);
265+
SetProperty.IfNotNull<bool>(section["convertToUtc"], (val) => opts.TimeStamp.ConvertToUtc = val);
267266
}
268267

269268
section = config.GetSection("logEvent");
270269
if (section != null)
271270
{
272271
SetCommonColumnOptions(opts.LogEvent);
273-
SetIfProvided<bool>((val) => { opts.LogEvent.ExcludeAdditionalProperties = val; }, section["excludeAdditionalProperties"]);
274-
SetIfProvided<bool>((val) => { opts.LogEvent.ExcludeStandardColumns = val; }, section["ExcludeStandardColumns"]);
272+
SetProperty.IfNotNull<bool>(section["excludeAdditionalProperties"], (val) => opts.LogEvent.ExcludeAdditionalProperties = val);
273+
SetProperty.IfNotNull<bool>(section["ExcludeStandardColumns"], (val) => opts.LogEvent.ExcludeStandardColumns = val);
275274
}
276275

277276
section = config.GetSection("message");
@@ -289,18 +288,18 @@ void ReadStandardColumns()
289288
// Standard Columns are subclasses of the SqlColumn class
290289
void SetCommonColumnOptions(SqlColumn target)
291290
{
292-
SetIfProvided<string>((val) => { target.ColumnName = val; }, section["columnName"]);
293-
SetIfProvided<string>((val) => { target.SetDataTypeFromConfigString(val); }, section["dataType"]);
294-
SetIfProvided<bool>((val) => { target.AllowNull = val; }, section["allowNull"]);
295-
SetIfProvided<int>((val) => { target.DataLength = val; }, section["dataLength"]);
296-
SetIfProvided<bool>((val) => { target.NonClusteredIndex = val; }, section["nonClusteredIndex"]);
291+
SetProperty.IfNotNullOrEmpty<string>(section["columnName"], (val) => target.ColumnName = val);
292+
SetProperty.IfNotNull<string>(section["dataType"], (val) => target.SetDataTypeFromConfigString(val));
293+
SetProperty.IfNotNull<bool>(section["allowNull"], (val) => target.AllowNull = val);
294+
SetProperty.IfNotNull<int>(section["dataLength"], (val) => target.DataLength = val);
295+
SetProperty.IfNotNull<bool>(section["nonClusteredIndex"], (val) => target.NonClusteredIndex = val);
297296
}
298297
}
299298

300299
void ReadMiscColumnOptions()
301300
{
302-
SetIfProvided<bool>((val) => { opts.DisableTriggers = val; }, config["disableTriggers"]);
303-
SetIfProvided<bool>((val) => { opts.ClusteredColumnstoreIndex = val; }, config["clusteredColumnstoreIndex"]);
301+
SetProperty.IfNotNull<bool>(config["disableTriggers"], (val) => opts.DisableTriggers = val);
302+
SetProperty.IfNotNull<bool>(config["clusteredColumnstoreIndex"], (val) => opts.ClusteredColumnstoreIndex = val);
304303

305304
string pkName = config["primaryKeyColumnName"];
306305
if (!string.IsNullOrEmpty(pkName))
@@ -334,23 +333,6 @@ void ReadMiscColumnOptions()
334333
throw new ArgumentException($"Could not match the configured primary key column name \"{pkName}\" with a data column in the table.");
335334
}
336335
}
337-
338-
// This is used to only set a column property when it is actually specified in the config.
339-
// When a value is requested from config, it returns null if that value hasn't been specified.
340-
// This also means you can't use config to set a property to null.
341-
void SetIfProvided<T>(PropertySetter<T> setter, string value)
342-
{
343-
if(value == null)
344-
return;
345-
try
346-
{
347-
var setting = (T)Convert.ChangeType(value, typeof(T));
348-
setter(setting);
349-
}
350-
// don't change the property if the conversion failed
351-
catch (InvalidCastException) { }
352-
catch (OverflowException) { }
353-
}
354336
}
355337
}
356338
}

src/Serilog.Sinks.MSSqlServer/Configuration/NetFramework.ConfigurationManager/ColumnCollection.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
using System.ComponentModel;
1615
using System.Configuration;
1716

1817
// Disable XML comment warnings for internal config classes which are required to have public members

src/Serilog.Sinks.MSSqlServer/Configuration/NetFramework.ConfigurationManager/ColumnConfig.cs

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,8 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
using Serilog.Sinks.MSSqlServer;
1615
using System;
1716
using System.Configuration;
18-
using System.Data;
1917

2018
// Disable XML comment warnings for internal config classes which are required to have public members
2119
#pragma warning disable 1591
@@ -24,67 +22,70 @@ namespace Serilog.Sinks.MSSqlServer
2422
{
2523
public class ColumnConfig : ConfigurationElement
2624
{
27-
public ColumnConfig() { }
25+
public ColumnConfig()
26+
{ }
2827

2928
public ColumnConfig(string columnName, string dataType)
3029
{
3130
ColumnName = columnName;
3231
DataType = dataType;
3332
}
3433

34+
// inheritors can override to set IsRequired = false
3535
[ConfigurationProperty("ColumnName", IsRequired = true, IsKey = true)]
36-
public string ColumnName
36+
public virtual string ColumnName
3737
{
3838
get { return (string)this["ColumnName"]; }
3939
set { this["ColumnName"] = value; }
4040
}
4141

42-
[ConfigurationProperty("DataType", IsRequired = true, IsKey = false, DefaultValue ="varchar")]
42+
[ConfigurationProperty("DataType")]
4343
public string DataType
4444
{
4545
get { return (string)this["DataType"]; }
4646
set { this["DataType"] = value; }
4747
}
4848

49-
[ConfigurationProperty("DataLength", IsRequired = false, IsKey = false, DefaultValue = 128)]
50-
public int DataLength
49+
[ConfigurationProperty("DataLength")]
50+
public string DataLength
5151
{
52-
get { return (int)this["DataLength"]; }
52+
get { return (string)this["DataLength"]; }
5353
set { this["DataLength"] = value; }
5454
}
5555

56-
[ConfigurationProperty("AllowNull", IsRequired = false, IsKey = false, DefaultValue = true)]
57-
public bool AllowNull
56+
[ConfigurationProperty("AllowNull")]
57+
public string AllowNull
5858
{
59-
get { return (bool)this["AllowNull"]; }
59+
get { return (string)this["AllowNull"]; }
6060
set { this["AllowNull"] = value; }
6161
}
6262

63-
[ConfigurationProperty("NonClusteredIndex", IsRequired = false, IsKey = false, DefaultValue = false)]
64-
public bool NonClusteredIndex
63+
[ConfigurationProperty("NonClusteredIndex")]
64+
public string NonClusteredIndex
6565
{
66-
get { return (bool)this["NonClusteredIndex"]; }
66+
get { return (string)this["NonClusteredIndex"]; }
6767
set { this["NonClusteredIndex"] = value; }
6868
}
6969

7070
internal SqlColumn AsSqlColumn()
7171
{
72-
var commonColumn = new SqlColumn
73-
{
74-
ColumnName = ColumnName,
75-
AllowNull = AllowNull,
76-
DataLength = DataLength,
77-
NonClusteredIndex = NonClusteredIndex
78-
};
72+
var commonColumn = new SqlColumn();
7973

80-
if (!SqlDataTypes.TryParseIfSupported(DataType, out SqlDbType sqlType))
81-
throw new ArgumentException($"SQL column data type {DataType} is not recognized or supported by this sink.");
74+
// inheritors can override IsRequired; config might not change the names of Standard Columns
75+
SetProperty.IfProvidedNotEmpty<string>(this, "ColumnName", (val) => commonColumn.ColumnName = val);
8276

83-
commonColumn.DataType = sqlType;
77+
if (DataType != null)
78+
commonColumn.SetDataTypeFromConfigString(DataType);
79+
80+
SetProperty.IfProvided<int>(this, "DataLength", (val) => commonColumn.DataLength = val);
8481

8582
if (commonColumn.DataLength == 0 && SqlDataTypes.DataLengthRequired.Contains(commonColumn.DataType))
8683
throw new ArgumentException($"SQL column data type {commonColumn.DataType.ToString()} requires a non-zero DataLength property.");
8784

85+
SetProperty.IfProvided<bool>(this, "AllowNull", (val) => commonColumn.AllowNull = val);
86+
87+
SetProperty.IfProvided<bool>(this, "NonClusteredIndex", (val) => commonColumn.NonClusteredIndex = val);
88+
8889
return commonColumn;
8990
}
9091
}

0 commit comments

Comments
 (0)