Skip to content

Commit

Permalink
Merge pull request #496 from serilog-mssql/dev
Browse files Browse the repository at this point in the history
Release 6.4.0
  • Loading branch information
ckadluba authored Nov 25, 2023
2 parents e85fbb0 + 357f24d commit bf1f5e6
Show file tree
Hide file tree
Showing 26 changed files with 98 additions and 39 deletions.
4 changes: 4 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# 6.4.0
* Implemented #436: Truncate additional columns (thanks to @nhart12)
* Fixed issue #489: allow varchar on standard columns (thanks to @nhart12)

# 6.3.0
* Implemented #360: Automatic DB creation

Expand Down
1 change: 1 addition & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageVersion Include="System.Configuration.ConfigurationManager" Version="6.0.1" />
<PackageVersion Include="System.Collections" Version="4.3.0" />
<PackageVersion Include="System.IO.FileSystem.Primitives" Version="4.3.0" />
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -512,7 +512,7 @@ The content of this column is rendered as JSON by default or with a custom IText

## Custom Property Columns

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)`.
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.

```csharp
var columnOptions = new ColumnOptions
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2020 Serilog Contributors
// Copyright 2023 Serilog Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -15,7 +15,6 @@
using System;
using Microsoft.Extensions.Configuration;
using Serilog.Configuration;
using Serilog.Core;
using Serilog.Debugging;
using Serilog.Events;
using Serilog.Formatting;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2020 Serilog Contributors
// Copyright 2023 Serilog Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down
5 changes: 5 additions & 0 deletions src/Serilog.Sinks.MSSqlServer/Extensions/StringExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ namespace Serilog.Sinks.MSSqlServer.Extensions
{
internal static class StringExtensions
{
public static string TruncateOutput(this string value, int dataLength) =>
dataLength < 0
? value // No need to truncate if length set to maximum
: value.Truncate(dataLength, "...");

public static string Truncate(this string value, int maxLength, string suffix)
{
if (value == null) return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<Description>A Serilog sink that writes events to Microsoft SQL Server</Description>
<VersionPrefix>6.3.0</VersionPrefix>
<VersionPrefix>6.4.0</VersionPrefix>
<Authors>Michiel van Oudheusden;Christian Kadluba;Serilog Contributors</Authors>
<TargetFrameworks>netstandard2.0;net462;net472;net6.0</TargetFrameworks>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ public ExceptionColumnOptions() : base()
get => base.DataType;
set
{
if (value != SqlDbType.NVarChar)
throw new ArgumentException("The Standard Column \"Exception\" must be NVarChar.");
if (!SqlDataTypes.VariableCharacterColumnTypes.Contains(value))
throw new ArgumentException("The Standard Column \"Exception\" must be NVarChar or VarChar.");
base.DataType = value;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ public LevelColumnOptions() : base()
get => base.DataType;
set
{
if (value != SqlDbType.NVarChar && value != SqlDbType.TinyInt)
throw new ArgumentException("The Standard Column \"Level\" must be of data type NVarChar or TinyInt.");
if (!SqlDataTypes.VariableCharacterColumnTypes.Contains(value) && value != SqlDbType.TinyInt)
throw new ArgumentException("The Standard Column \"Level\" must be of data type NVarChar, VarChar or TinyInt.");
base.DataType = value;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ public LogEventColumnOptions() : base()
get => base.DataType;
set
{
if (value != SqlDbType.NVarChar)
throw new ArgumentException("The Standard Column \"LogEvent\" must be NVarChar.");
if (!SqlDataTypes.VariableCharacterColumnTypes.Contains(value))
throw new ArgumentException("The Standard Column \"LogEvent\" must be NVarChar or VarChar.");
base.DataType = value;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ public MessageColumnOptions() : base()
get => base.DataType;
set
{
if (value != SqlDbType.NVarChar)
throw new ArgumentException("The Standard Column \"Message\" must be NVarChar.");
if (!SqlDataTypes.VariableCharacterColumnTypes.Contains(value))
throw new ArgumentException("The Standard Column \"Message\" must be NVarChar or VarChar.");
base.DataType = value;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ public MessageTemplateColumnOptions() : base()
get => base.DataType;
set
{
if (value != SqlDbType.NVarChar)
throw new ArgumentException("The Standard Column \"MessageTemplate\" must be NVarChar.");
if (!SqlDataTypes.VariableCharacterColumnTypes.Contains(value))
throw new ArgumentException("The Standard Column \"MessageTemplate\" must be NVarChar or VarChar.");
base.DataType = value;
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2020 Serilog Contributors
// Copyright 2023 Serilog Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2020 Serilog Contributors
// Copyright 2023 Serilog Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.ComponentModel;
using Serilog.Events;
using Serilog.Sinks.MSSqlServer.Extensions;

namespace Serilog.Sinks.MSSqlServer.Output
{
Expand Down Expand Up @@ -45,6 +46,11 @@ public KeyValuePair<string, object> GetAdditionalColumnNameAndValue(SqlColumn ad
var columnType = additionalColumn.AsDataColumn().DataType;
if (columnType.IsAssignableFrom(scalarValue.Value.GetType()))
{
if (SqlDataTypes.DataLengthRequired.Contains(additionalColumn.DataType))
{
return new KeyValuePair<string, object>(columnName, scalarValue.Value.ToString().TruncateOutput(additionalColumn.DataLength));

}
return new KeyValuePair<string, object>(columnName, scalarValue.Value);
}

Expand All @@ -54,6 +60,9 @@ public KeyValuePair<string, object> GetAdditionalColumnNameAndValue(SqlColumn ad
}
else
{
if (additionalColumn.AllowNull) {
return new KeyValuePair<string, object>(columnName, DBNull.Value);
}
return new KeyValuePair<string, object>(columnName, property.Value.ToString());
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2020 Serilog Contributors
// Copyright 2023 Serilog Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2020 Serilog Contributors
// Copyright 2023 Serilog Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,15 @@ public KeyValuePair<string, object> GetStandardColumnNameAndValue(StandardColumn
switch (column)
{
case StandardColumn.Message:
return new KeyValuePair<string, object>(_columnOptions.Message.ColumnName, TruncateOutput(logEvent.RenderMessage(_formatProvider), _columnOptions.Message.DataLength));
return new KeyValuePair<string, object>(_columnOptions.Message.ColumnName, logEvent.RenderMessage(_formatProvider).TruncateOutput(_columnOptions.Message.DataLength));
case StandardColumn.MessageTemplate:
return new KeyValuePair<string, object>(_columnOptions.MessageTemplate.ColumnName, TruncateOutput(logEvent.MessageTemplate.Text, _columnOptions.MessageTemplate.DataLength));
return new KeyValuePair<string, object>(_columnOptions.MessageTemplate.ColumnName, logEvent.MessageTemplate.Text.TruncateOutput(_columnOptions.MessageTemplate.DataLength));
case StandardColumn.Level:
return new KeyValuePair<string, object>(_columnOptions.Level.ColumnName, _columnOptions.Level.StoreAsEnum ? (object)logEvent.Level : logEvent.Level.ToString());
case StandardColumn.TimeStamp:
return GetTimeStampStandardColumnNameAndValue(logEvent);
case StandardColumn.Exception:
return new KeyValuePair<string, object>(_columnOptions.Exception.ColumnName, TruncateOutput(logEvent.Exception?.ToString(), _columnOptions.Exception.DataLength));
return new KeyValuePair<string, object>(_columnOptions.Exception.ColumnName, logEvent.Exception?.ToString().TruncateOutput(_columnOptions.Exception.DataLength));
case StandardColumn.Properties:
return new KeyValuePair<string, object>(_columnOptions.Properties.ColumnName, ConvertPropertiesToXmlStructure(logEvent.Properties));
case StandardColumn.LogEvent:
Expand All @@ -63,11 +63,6 @@ public KeyValuePair<string, object> GetStandardColumnNameAndValue(StandardColumn
}
}

private static string TruncateOutput(string value, int dataLength) =>
dataLength < 0
? value // No need to truncate if length set to maximum
: value.Truncate(dataLength, "...");

private KeyValuePair<string, object> GetTimeStampStandardColumnNameAndValue(LogEvent logEvent)
{
var dateTimeOffset = _columnOptions.TimeStamp.ConvertToUtc ? logEvent.Timestamp.ToUniversalTime() : logEvent.Timestamp;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public void Execute()
catch (Exception ex)
{
HandleException(ex);
throw;
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Text;
using static System.FormattableString;

namespace Serilog.Sinks.MSSqlServer.Platform
Expand All @@ -15,6 +16,15 @@ public SqlCreateDatabaseWriter(string databaseName)
public string DatabaseName => _databaseName;

public string GetSql()
=> Invariant($"CREATE DATABASE [{_databaseName}]");
{
var sql = new StringBuilder();

sql.AppendLine(Invariant($"IF NOT EXISTS (SELECT name FROM sys.databases WHERE name = '{_databaseName}')"));
sql.AppendLine("BEGIN");
sql.AppendLine(Invariant($"CREATE DATABASE [{_databaseName}]"));
sql.AppendLine("END");

return sql.ToString();
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data;

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

/// <summary>
/// SQL column types for supported strings
/// </summary>
public static readonly ReadOnlyCollection<SqlDbType> VariableCharacterColumnTypes = new ReadOnlyCollection<SqlDbType>(new List<SqlDbType> {
SqlDbType.NVarChar,
SqlDbType.VarChar
});

/// <summary>
/// The SQL column types which require a non-zero DataLength property.
/// </summary>
Expand Down
7 changes: 5 additions & 2 deletions test/Serilog.Sinks.MSSqlServer.Tests/Misc/SqlTypesTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,12 @@ public void AuditLogCharacterDataSqlTypes()
Log.Information("NVarChar {NVarChar}", twentyChars);
Log.Information("VarChar {VarChar}", twentyChars);

// should throw truncation exception
// should truncate but not throw

Assert.Throws<AggregateException>(() => Log.Information("Char {Char}", thirtyChars));
Log.Information("Char {Char}", thirtyChars);
Log.Information("NChar {NChar}", thirtyChars);
Log.Information("NVarChar {NVarChar}", thirtyChars);
Log.Information("VarChar {VarChar}", thirtyChars);

Log.CloseAndFlush();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
<ProjectReference Include="..\..\src\Serilog.Sinks.MSSqlServer\Serilog.Sinks.MSSqlServer.csproj" />
<PackageReference Include="FluentAssertions" />
<PackageReference Include="Dapper.StrongName" />
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="Moq" />
<PackageReference Include="xunit" />
<PackageReference Include="xunit.runner.visualstudio" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ public void GetAdditionalColumnNameAndValueReturnsNullForNotFoundHierachicalProp
}

[Fact]
public void GetAdditionalColumnNameAndValueConvertsValueTypeToStringIfConversionToColumnTypeFails()
public void GetAdditionalColumnNameAndValueUsesNullIfConversionToColumnTypeFails()
{
// Arrange
const string columnName = "AdditionalProperty1";
Expand All @@ -131,8 +131,8 @@ public void GetAdditionalColumnNameAndValueConvertsValueTypeToStringIfConversion
// Assert
_columnSimplePropertyValueResolver.Verify(r => r.GetPropertyValueForColumn(additionalColumn, properties), Times.Once);
Assert.Equal(columnName, result.Key);
Assert.IsType<string>(result.Value);
Assert.Equal("1", result.Value); // Cannot convert int to SqlDbType.DateTimeOffset so returns string
Assert.IsType<DBNull>(result.Value);
Assert.Equal(DBNull.Value, result.Value); // Cannot convert int to SqlDbType.DateTimeOffset so returns null
}

[Fact]
Expand Down Expand Up @@ -180,5 +180,27 @@ public void GetAdditionalColumnNameAndValueConvertsNullValueForNullable()
Assert.IsType<DBNull>(result.Value);
Assert.Equal(DBNull.Value, result.Value);
}

[Fact]
public void GetAdditionalColumnNameAndValueReturnsTruncatedForCharacterTypesWithDataLength()
{
// Arrange
const string columnName = "AdditionalProperty1";
const string propertyValue = "Additional Property Value";
var additionalColumn = new SqlColumn(columnName, SqlDbType.NVarChar);
additionalColumn.DataLength = 10;
var properties = new Dictionary<string, LogEventPropertyValue>();
_columnSimplePropertyValueResolver.Setup(r => r.GetPropertyValueForColumn(
It.IsAny<SqlColumn>(), It.IsAny<IReadOnlyDictionary<string, LogEventPropertyValue>>()))
.Returns(new KeyValuePair<string, LogEventPropertyValue>(columnName, new ScalarValue(propertyValue)));

// Act
var result = _sut.GetAdditionalColumnNameAndValue(additionalColumn, properties);

// Assert
_columnSimplePropertyValueResolver.Verify(r => r.GetPropertyValueForColumn(additionalColumn, properties), Times.Once);
Assert.Equal(columnName, result.Key);
Assert.Equal("Additio...", result.Value);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public void HandlesExceptionFromSqlWriter()
};

// Act
_sut.Execute();
Assert.Throws<InvalidOperationException>(() => _sut.Execute());

// Assert
Assert.True(handlerCalled);
Expand All @@ -124,7 +124,7 @@ public void HandlesExceptionFromConnectionFactory()
};

// Act
_sut.Execute();
Assert.Throws<InvalidOperationException>(() => _sut.Execute());

// Assert
Assert.True(handlerCalled);
Expand All @@ -148,7 +148,7 @@ public void HandlesExceptionFromConnection()
};

// Act
_sut.Execute();
Assert.Throws<InvalidOperationException>(() => _sut.Execute());

// Assert
Assert.True(handlerCalled);
Expand All @@ -172,7 +172,7 @@ public void HandlesExceptionFromCommand()
};

// Act
_sut.Execute();
Assert.Throws<InvalidOperationException>(() => _sut.Execute());

// Assert
Assert.True(handlerCalled);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public void GetSqlWritesCorrectCommand()
{
// Arrange
const string databaseName = "LogDatabase";
const string expectedResult = "CREATE DATABASE [LogDatabase]";
const string expectedResult = "IF NOT EXISTS (SELECT name FROM sys.databases WHERE name = 'LogDatabase')\r\nBEGIN\r\nCREATE DATABASE [LogDatabase]\r\nEND\r\n";
var sut = new SqlCreateDatabaseWriter(databaseName);

// Act
Expand All @@ -27,7 +27,7 @@ public void GetSqlWritesCorrectCommandForDatabaseNameWithSpaces()
{
// Arrange
const string databaseName = "Log Data Base";
const string expectedResult = "CREATE DATABASE [Log Data Base]";
const string expectedResult = "IF NOT EXISTS (SELECT name FROM sys.databases WHERE name = 'Log Data Base')\r\nBEGIN\r\nCREATE DATABASE [Log Data Base]\r\nEND\r\n";
var sut = new SqlCreateDatabaseWriter(databaseName);

// Act
Expand Down

0 comments on commit bf1f5e6

Please sign in to comment.