Skip to content

Commit 480d36b

Browse files
authored
Merge pull request #490 from nhart12/dev
Truncate additional columns, allow varchar on standard columns
2 parents 3fdce96 + b9e9a15 commit 480d36b

File tree

12 files changed

+67
-24
lines changed

12 files changed

+67
-24
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,7 @@ The content of this column is rendered as JSON by default or with a custom IText
512512

513513
## Custom Property Columns
514514

515-
By default, any log event properties you include in your log statements will be saved to the XML `Properties` column or the JSON `LogEvent` column. But they can also be stored in their own individual columns via the `AdditionalColumns` collection. This adds overhead to write operations but is very useful for frequently-queried properties. Only `ColumnName` is required; the default configuration is `varchar(max)`.
515+
By default, any log event properties you include in your log statements will be saved to the XML `Properties` column or the JSON `LogEvent` column. But they can also be stored in their own individual columns via the `AdditionalColumns` collection. This adds overhead to write operations but is very useful for frequently-queried properties. Only `ColumnName` is required; the default configuration is `varchar(max)`. If you specify a DataLength on a column of character data types (NVarChar, VarChar, Char, NChar) the string will be automatically truncated to the datalength to fit in the column.
516516

517517
```csharp
518518
var columnOptions = new ColumnOptions

src/Serilog.Sinks.MSSqlServer/Extensions/StringExtensions.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ namespace Serilog.Sinks.MSSqlServer.Extensions
44
{
55
internal static class StringExtensions
66
{
7+
public static string TruncateOutput(this string value, int dataLength) =>
8+
dataLength < 0
9+
? value // No need to truncate if length set to maximum
10+
: value.Truncate(dataLength, "...");
11+
712
public static string Truncate(this string value, int maxLength, string suffix)
813
{
914
if (value == null) return null;

src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/ColumnOptions/ExceptionColumnOptions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ public ExceptionColumnOptions() : base()
2727
get => base.DataType;
2828
set
2929
{
30-
if (value != SqlDbType.NVarChar)
31-
throw new ArgumentException("The Standard Column \"Exception\" must be NVarChar.");
30+
if (!SqlDataTypes.VariableCharacterColumnTypes.Contains(value))
31+
throw new ArgumentException("The Standard Column \"Exception\" must be NVarChar or VarChar.");
3232
base.DataType = value;
3333
}
3434
}

src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/ColumnOptions/LevelColumnOptions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ public LevelColumnOptions() : base()
2828
get => base.DataType;
2929
set
3030
{
31-
if (value != SqlDbType.NVarChar && value != SqlDbType.TinyInt)
32-
throw new ArgumentException("The Standard Column \"Level\" must be of data type NVarChar or TinyInt.");
31+
if (!SqlDataTypes.VariableCharacterColumnTypes.Contains(value) && value != SqlDbType.TinyInt)
32+
throw new ArgumentException("The Standard Column \"Level\" must be of data type NVarChar, VarChar or TinyInt.");
3333
base.DataType = value;
3434
}
3535
}

src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/ColumnOptions/LogEventColumnOptions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ public LogEventColumnOptions() : base()
2727
get => base.DataType;
2828
set
2929
{
30-
if (value != SqlDbType.NVarChar)
31-
throw new ArgumentException("The Standard Column \"LogEvent\" must be NVarChar.");
30+
if (!SqlDataTypes.VariableCharacterColumnTypes.Contains(value))
31+
throw new ArgumentException("The Standard Column \"LogEvent\" must be NVarChar or VarChar.");
3232
base.DataType = value;
3333
}
3434
}

src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/ColumnOptions/MessageColumnOptions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ public MessageColumnOptions() : base()
2727
get => base.DataType;
2828
set
2929
{
30-
if (value != SqlDbType.NVarChar)
31-
throw new ArgumentException("The Standard Column \"Message\" must be NVarChar.");
30+
if (!SqlDataTypes.VariableCharacterColumnTypes.Contains(value))
31+
throw new ArgumentException("The Standard Column \"Message\" must be NVarChar or VarChar.");
3232
base.DataType = value;
3333
}
3434
}

src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/ColumnOptions/MessageTemplateColumnOptions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ public MessageTemplateColumnOptions() : base()
2727
get => base.DataType;
2828
set
2929
{
30-
if (value != SqlDbType.NVarChar)
31-
throw new ArgumentException("The Standard Column \"MessageTemplate\" must be NVarChar.");
30+
if (!SqlDataTypes.VariableCharacterColumnTypes.Contains(value))
31+
throw new ArgumentException("The Standard Column \"MessageTemplate\" must be NVarChar or VarChar.");
3232
base.DataType = value;
3333
}
3434
}

src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/Output/AdditionalColumnDataGenerator.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using System.ComponentModel;
44
using Serilog.Events;
5+
using Serilog.Sinks.MSSqlServer.Extensions;
56

67
namespace Serilog.Sinks.MSSqlServer.Output
78
{
@@ -45,6 +46,11 @@ public KeyValuePair<string, object> GetAdditionalColumnNameAndValue(SqlColumn ad
4546
var columnType = additionalColumn.AsDataColumn().DataType;
4647
if (columnType.IsAssignableFrom(scalarValue.Value.GetType()))
4748
{
49+
if (SqlDataTypes.DataLengthRequired.Contains(additionalColumn.DataType))
50+
{
51+
return new KeyValuePair<string, object>(columnName, scalarValue.Value.ToString().TruncateOutput(additionalColumn.DataLength));
52+
53+
}
4854
return new KeyValuePair<string, object>(columnName, scalarValue.Value);
4955
}
5056

@@ -54,6 +60,9 @@ public KeyValuePair<string, object> GetAdditionalColumnNameAndValue(SqlColumn ad
5460
}
5561
else
5662
{
63+
if (additionalColumn.AllowNull) {
64+
return new KeyValuePair<string, object>(columnName, DBNull.Value);
65+
}
5766
return new KeyValuePair<string, object>(columnName, property.Value.ToString());
5867
}
5968
}

src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/Output/StandardColumnDataGenerator.cs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,15 +45,15 @@ public KeyValuePair<string, object> GetStandardColumnNameAndValue(StandardColumn
4545
switch (column)
4646
{
4747
case StandardColumn.Message:
48-
return new KeyValuePair<string, object>(_columnOptions.Message.ColumnName, TruncateOutput(logEvent.RenderMessage(_formatProvider), _columnOptions.Message.DataLength));
48+
return new KeyValuePair<string, object>(_columnOptions.Message.ColumnName, logEvent.RenderMessage(_formatProvider).TruncateOutput(_columnOptions.Message.DataLength));
4949
case StandardColumn.MessageTemplate:
50-
return new KeyValuePair<string, object>(_columnOptions.MessageTemplate.ColumnName, TruncateOutput(logEvent.MessageTemplate.Text, _columnOptions.MessageTemplate.DataLength));
50+
return new KeyValuePair<string, object>(_columnOptions.MessageTemplate.ColumnName, logEvent.MessageTemplate.Text.TruncateOutput(_columnOptions.MessageTemplate.DataLength));
5151
case StandardColumn.Level:
5252
return new KeyValuePair<string, object>(_columnOptions.Level.ColumnName, _columnOptions.Level.StoreAsEnum ? (object)logEvent.Level : logEvent.Level.ToString());
5353
case StandardColumn.TimeStamp:
5454
return GetTimeStampStandardColumnNameAndValue(logEvent);
5555
case StandardColumn.Exception:
56-
return new KeyValuePair<string, object>(_columnOptions.Exception.ColumnName, TruncateOutput(logEvent.Exception?.ToString(), _columnOptions.Exception.DataLength));
56+
return new KeyValuePair<string, object>(_columnOptions.Exception.ColumnName, logEvent.Exception?.ToString().TruncateOutput(_columnOptions.Exception.DataLength));
5757
case StandardColumn.Properties:
5858
return new KeyValuePair<string, object>(_columnOptions.Properties.ColumnName, ConvertPropertiesToXmlStructure(logEvent.Properties));
5959
case StandardColumn.LogEvent:
@@ -63,11 +63,6 @@ public KeyValuePair<string, object> GetStandardColumnNameAndValue(StandardColumn
6363
}
6464
}
6565

66-
private static string TruncateOutput(string value, int dataLength) =>
67-
dataLength < 0
68-
? value // No need to truncate if length set to maximum
69-
: value.Truncate(dataLength, "...");
70-
7166
private KeyValuePair<string, object> GetTimeStampStandardColumnNameAndValue(LogEvent logEvent)
7267
{
7368
var dateTimeOffset = _columnOptions.TimeStamp.ConvertToUtc ? logEvent.Timestamp.ToUniversalTime() : logEvent.Timestamp;

src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/SqlDataTypes.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Collections.ObjectModel;
34
using System.Data;
45

56
namespace Serilog.Sinks.MSSqlServer
@@ -51,6 +52,14 @@ public static class SqlDataTypes
5152
// not supported by enum: numeric, FILESTREAM, rowversion
5253
};
5354

55+
/// <summary>
56+
/// SQL column types for supported strings
57+
/// </summary>
58+
public static readonly ReadOnlyCollection<SqlDbType> VariableCharacterColumnTypes = new ReadOnlyCollection<SqlDbType>(new List<SqlDbType> {
59+
SqlDbType.NVarChar,
60+
SqlDbType.VarChar
61+
});
62+
5463
/// <summary>
5564
/// The SQL column types which require a non-zero DataLength property.
5665
/// </summary>

0 commit comments

Comments
 (0)