Skip to content

Commit fa57d29

Browse files
authored
Merge pull request #308 from serilog/dev
Release 5.5.1
2 parents 64dc4d5 + f58b93e commit fa57d29

File tree

10 files changed

+124
-9
lines changed

10 files changed

+124
-9
lines changed

CHANGES.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
# 5.5.1
2+
* Fixed issue #300 Support DateTime2 data type for TimeStamp column (thanks to @stedel for the contribution).
3+
* Added Sourcelink support and publish symbols to nuget.org which allows consumers of the package to debug into the sink code.
4+
* Added troubleshooting tip in README with workaround for SqlClient issue regarding missing Microsoft.Data.SqlClient.Sni.dll in .NET Framework apps and updated `samples\AppConfigDemo` accordingly.
5+
* Added information in README about batched sink SqlBulkCopy behavior according to issue #209.
6+
17
# 5.5.0
28
* Implemented enhancement #208: use Microsoft.Data.SqliClient for all platforms except net452 to enable Column Encryption (thanks to @mungk for the contribution).
39
* Fixed issue #290 MissingMethodException with .NET Standard 2.0.

README.md

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -436,14 +436,19 @@ This column stores the event level (Error, Information, etc.). For backwards-com
436436

437437
### TimeStamp
438438

439-
This column stores the time the log event was sent to Serilog as a SQL `datetime` (default) or `datetimeoffset` type. If `datetimeoffset` should be used, this can be configured as follows.
439+
This column stores the time the log event was sent to Serilog as a SQL `datetime` (default), `datetime2` or `datetimeoffset` type. If `datetime2` or `datetimeoffset` should be used, this can be configured as follows.
440440

441441
```csharp
442442
var columnOptions = new ColumnOptions();
443443
columnOptions.TimeStamp.DataType = SqlDbType.DateTimeOffset;
444444
```
445445

446-
Please be aware that you have to configure the sink for `datetimeoffset` if the used logging database table has a `TimeStamp` column of type `datetimeoffset`. On the other hand you must not configure for `datetimeoffset` if the `TimeStamp` column is of type `datetime`. Failing to configure the data type accordingly can result in log table entries with wrong timezone offsets or no log entries being created at all due to exceptions during logging.
446+
```csharp
447+
var columnOptions = new ColumnOptions();
448+
columnOptions.TimeStamp.DataType = SqlDbType.DateTime2;
449+
```
450+
451+
Please be aware that you have to configure the sink for `datetimeoffset` if the used logging database table has a `TimeStamp` column of type `datetimeoffset`. If the underlying database uses `datetime2` for the `TimeStamp` column, the sink must be configured to use `datetime2`. On the other hand you must not configure for `datetimeoffset` if the `TimeStamp` column is of type `datetime` or `datetime2`. Failing to configure the data type accordingly can result in log table entries with wrong timezone offsets or no log entries being created at all due to exceptions during logging.
447452

448453
While TimeStamp may appear to be a good candidate as a clustered primary key, even relatively low-volume logging can emit identical timestamps forcing SQL Server to add a "uniqueifier" value behind the scenes (effectively an auto-incrementing identity-like integer). For frequent timestamp range-searching and sorting, a non-clustered index is better.
449454

@@ -699,6 +704,11 @@ Any Serilog application should _always_ call `Log.CloseAndFlush` before shutting
699704
AppDomain.CurrentDomain.ProcessExit += (s, e) => Log.CloseAndFlush();
700705
```
701706

707+
### Consider batched sink SqlBulkCopy behavior
708+
709+
If you initialize the sink with `WriteTo` then it uses a batched sink semantics. This means that it does not directly issue an SQL command to the database for each log call, but it collectes log events in a buffer and later asynchronously writes a bulk of them to the database using [SqlBulkCopy](https://docs.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqlbulkcopy?view=dotnet-plat-ext-3.1). **If SqlBulkCopy fails to write a single row of the batch to the database, the whole batch will be lost.** Unfortunately it is not easily possible (and probably only with a significant performance impact) to find out what lines of the batch caused problems. Therefore the sink cannot easily retry the operation with the problem lines removed. Typical problems can be that data (like the log message) exceeds the field length in the database or fields which cannot be null are null in the log event. Keep this in mind when using the batched version of the sink and avoid log events to be created with data that is invalid according to your database schema. Use a wrapper class or Serilog Enrichers to validate and correct the log event data before it gets written to the database.
710+
711+
702712
### Test outside of Visual Studio
703713

704714
When you exit an application running in debug mode under Visual Studio, normal shutdown processes may be interrupted. Visual Studio issues a nearly-instant process kill command when it decides you're done debugging. This is a particularly common problem with ASP.NET and ASP.NET Core applications, in which Visual Studio instantly terminates the application as soon as the browser is closed. Even `finally` blocks usually fail to execute. If you aren't seeing your last few events written, try testing your application outside of Visual Studio.
@@ -711,6 +721,10 @@ If you're reading about a feature that doesn't seem to work, check whether you'r
711721

712722
Please check your NuGet references and confirm you are specifically referencing _Serilog.Sinks.MSSqlServer_. In the early days of .NET Core, there was a popular Core-specific fork of this sink, but the documentation and NuGet project URLs pointed here. Today the package is marked deprecated, but we continue to see some confusion around this.
713723

724+
### .NET Framework apps must reference Microsoft.Data.SqlClient
725+
726+
If you are using the sink in a .NET Framework app, make sure to add a nuget package reference to Microsoft.Data.SqlClient in your app project. This is necessary due to a bug in SqlClient which can lead to exceptions about missing Microsoft assemblies. Details can be found in [issue 283](https://github.com/serilog/serilog-sinks-mssqlserver/issues/283#issuecomment-664397489) and [issue 208](https://github.com/serilog/serilog-sinks-mssqlserver/issues/208#issuecomment-664503566).
727+
714728
## Querying Property Data
715729

716730
Extracting and querying the property column directly can be helpful when looking for specific log sequences. SQL Server has query syntax supporting columns that store either XML or JSON data.

appveyor.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ build_script:
99
test: off
1010
artifacts:
1111
- path: artifacts/Serilog.*.nupkg
12+
- path: artifacts/Serilog.*.snupkg
1213
deploy:
1314
- provider: NuGet
1415
api_key:
@@ -18,7 +19,9 @@ deploy:
1819
- provider: GitHub
1920
auth_token:
2021
secure: p4LpVhBKxGS5WqucHxFQ5c7C8cP74kbNB0Z8k9Oxx/PMaDQ1+ibmoexNqVU5ZlmX
21-
artifact: /Serilog.*\.nupkg/
22+
artifacts:
23+
/Serilog.*\.nupkg/
24+
/Serilog.*\.snupkg/
2225
tag: v$(appveyor_build_version)
2326
on:
2427
branch: master

sample/AppConfigDemo/AppConfigDemo.csproj

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
<FileAlignment>512</FileAlignment>
1313
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
1414
<Deterministic>true</Deterministic>
15+
<NuGetPackageImportStamp>
16+
</NuGetPackageImportStamp>
1517
</PropertyGroup>
1618
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
1719
<PlatformTarget>AnyCPU</PlatformTarget>
@@ -33,12 +35,36 @@
3335
<WarningLevel>4</WarningLevel>
3436
</PropertyGroup>
3537
<ItemGroup>
38+
<Reference Include="Microsoft.Data.SqlClient, Version=1.13.20136.2, Culture=neutral, PublicKeyToken=23ec7fc2d6eaa4a5, processorArchitecture=MSIL">
39+
<HintPath>..\..\packages\Microsoft.Data.SqlClient.1.1.3\lib\net46\Microsoft.Data.SqlClient.dll</HintPath>
40+
</Reference>
3641
<Reference Include="Microsoft.Extensions.Configuration.Abstractions, Version=3.1.4.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
3742
<HintPath>..\..\packages\Microsoft.Extensions.Configuration.Abstractions.3.1.4\lib\netstandard2.0\Microsoft.Extensions.Configuration.Abstractions.dll</HintPath>
3843
</Reference>
3944
<Reference Include="Microsoft.Extensions.Primitives, Version=3.1.4.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
4045
<HintPath>..\..\packages\Microsoft.Extensions.Primitives.3.1.4\lib\netstandard2.0\Microsoft.Extensions.Primitives.dll</HintPath>
4146
</Reference>
47+
<Reference Include="Microsoft.Identity.Client, Version=3.0.8.0, Culture=neutral, PublicKeyToken=0a613f4dd989e8ae, processorArchitecture=MSIL">
48+
<HintPath>..\..\packages\Microsoft.Identity.Client.3.0.8\lib\net45\Microsoft.Identity.Client.dll</HintPath>
49+
</Reference>
50+
<Reference Include="Microsoft.IdentityModel.JsonWebTokens, Version=5.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
51+
<HintPath>..\..\packages\Microsoft.IdentityModel.JsonWebTokens.5.5.0\lib\net461\Microsoft.IdentityModel.JsonWebTokens.dll</HintPath>
52+
</Reference>
53+
<Reference Include="Microsoft.IdentityModel.Logging, Version=5.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
54+
<HintPath>..\..\packages\Microsoft.IdentityModel.Logging.5.5.0\lib\net461\Microsoft.IdentityModel.Logging.dll</HintPath>
55+
</Reference>
56+
<Reference Include="Microsoft.IdentityModel.Protocols, Version=5.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
57+
<HintPath>..\..\packages\Microsoft.IdentityModel.Protocols.5.5.0\lib\net461\Microsoft.IdentityModel.Protocols.dll</HintPath>
58+
</Reference>
59+
<Reference Include="Microsoft.IdentityModel.Protocols.OpenIdConnect, Version=5.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
60+
<HintPath>..\..\packages\Microsoft.IdentityModel.Protocols.OpenIdConnect.5.5.0\lib\net461\Microsoft.IdentityModel.Protocols.OpenIdConnect.dll</HintPath>
61+
</Reference>
62+
<Reference Include="Microsoft.IdentityModel.Tokens, Version=5.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
63+
<HintPath>..\..\packages\Microsoft.IdentityModel.Tokens.5.5.0\lib\net461\Microsoft.IdentityModel.Tokens.dll</HintPath>
64+
</Reference>
65+
<Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
66+
<HintPath>..\..\packages\Newtonsoft.Json.10.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
67+
</Reference>
4268
<Reference Include="Serilog, Version=2.0.0.0, Culture=neutral, PublicKeyToken=24c2f752a8e58a10, processorArchitecture=MSIL">
4369
<HintPath>..\..\packages\Serilog.2.9.0\lib\net46\Serilog.dll</HintPath>
4470
</Reference>
@@ -48,6 +74,16 @@
4874
</Reference>
4975
<Reference Include="System.Configuration" />
5076
<Reference Include="System.Core" />
77+
<Reference Include="System.Data.Common, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
78+
<HintPath>..\..\packages\System.Data.Common.4.3.0\lib\net451\System.Data.Common.dll</HintPath>
79+
<Private>True</Private>
80+
<Private>True</Private>
81+
</Reference>
82+
<Reference Include="System.Drawing" />
83+
<Reference Include="System.IdentityModel" />
84+
<Reference Include="System.IdentityModel.Tokens.Jwt, Version=5.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
85+
<HintPath>..\..\packages\System.IdentityModel.Tokens.Jwt.5.5.0\lib\net461\System.IdentityModel.Tokens.Jwt.dll</HintPath>
86+
</Reference>
5187
<Reference Include="System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
5288
<HintPath>..\..\packages\System.Memory.4.5.4\lib\net461\System.Memory.dll</HintPath>
5389
</Reference>
@@ -58,6 +94,7 @@
5894
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.6.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
5995
<HintPath>..\..\packages\System.Runtime.CompilerServices.Unsafe.4.7.1\lib\net461\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
6096
</Reference>
97+
<Reference Include="System.Windows.Forms" />
6198
<Reference Include="System.Xml.Linq" />
6299
<Reference Include="System.Data.DataSetExtensions" />
63100
<Reference Include="Microsoft.CSharp" />
@@ -82,4 +119,11 @@
82119
<Folder Include="Properties\" />
83120
</ItemGroup>
84121
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
122+
<Import Project="..\..\packages\Microsoft.Data.SqlClient.SNI.1.1.0\build\net46\Microsoft.Data.SqlClient.SNI.targets" Condition="Exists('..\..\packages\Microsoft.Data.SqlClient.SNI.1.1.0\build\net46\Microsoft.Data.SqlClient.SNI.targets')" />
123+
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
124+
<PropertyGroup>
125+
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
126+
</PropertyGroup>
127+
<Error Condition="!Exists('..\..\packages\Microsoft.Data.SqlClient.SNI.1.1.0\build\net46\Microsoft.Data.SqlClient.SNI.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Data.SqlClient.SNI.1.1.0\build\net46\Microsoft.Data.SqlClient.SNI.targets'))" />
128+
</Target>
85129
</Project>

sample/AppConfigDemo/packages.config

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,21 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<packages>
3+
<package id="Microsoft.Data.SqlClient" version="1.1.3" targetFramework="net461" />
4+
<package id="Microsoft.Data.SqlClient.SNI" version="1.1.0" targetFramework="net461" />
35
<package id="Microsoft.Extensions.Configuration.Abstractions" version="3.1.4" targetFramework="net461" />
46
<package id="Microsoft.Extensions.Primitives" version="3.1.4" targetFramework="net461" />
7+
<package id="Microsoft.Identity.Client" version="3.0.8" targetFramework="net461" />
8+
<package id="Microsoft.IdentityModel.JsonWebTokens" version="5.5.0" targetFramework="net461" />
9+
<package id="Microsoft.IdentityModel.Logging" version="5.5.0" targetFramework="net461" />
10+
<package id="Microsoft.IdentityModel.Protocols" version="5.5.0" targetFramework="net461" />
11+
<package id="Microsoft.IdentityModel.Protocols.OpenIdConnect" version="5.5.0" targetFramework="net461" />
12+
<package id="Microsoft.IdentityModel.Tokens" version="5.5.0" targetFramework="net461" />
13+
<package id="Newtonsoft.Json" version="10.0.1" targetFramework="net461" />
514
<package id="Serilog" version="2.9.0" targetFramework="net461" />
615
<package id="Serilog.Settings.AppSettings" version="2.2.2" targetFramework="net461" />
716
<package id="System.Buffers" version="4.5.1" targetFramework="net461" />
17+
<package id="System.Data.Common" version="4.3.0" targetFramework="net461" />
18+
<package id="System.IdentityModel.Tokens.Jwt" version="5.5.0" targetFramework="net461" />
819
<package id="System.Memory" version="4.5.4" targetFramework="net461" />
920
<package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net461" />
1021
<package id="System.Runtime.CompilerServices.Unsafe" version="4.7.1" targetFramework="net461" />

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

Lines changed: 6 additions & 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>5.5.0</VersionPrefix>
5+
<VersionPrefix>5.5.1</VersionPrefix>
66
<Authors>Michiel van Oudheusden;Christian Kadluba;Serilog Contributors</Authors>
77
<TargetFrameworks>netstandard2.0;net452;net461;net472;netcoreapp2.0;netcoreapp2.2</TargetFrameworks>
88
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
@@ -18,6 +18,10 @@
1818
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
1919
<RepositoryUrl>https://github.com/serilog/serilog-sinks-mssqlserver</RepositoryUrl>
2020
<RepositoryType>git</RepositoryType>
21+
<PublishRepositoryUrl>true</PublishRepositoryUrl>
22+
<EmbedUntrackedSources>true</EmbedUntrackedSources>
23+
<IncludeSymbols>true</IncludeSymbols>
24+
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
2125
<RuntimeIdentifiers>win</RuntimeIdentifiers>
2226
<GenerateAssemblyTitleAttribute>false</GenerateAssemblyTitleAttribute>
2327
<GenerateAssemblyDescriptionAttribute>false</GenerateAssemblyDescriptionAttribute>
@@ -26,6 +30,7 @@
2630

2731
<ItemGroup>
2832
<!-- Whenever these are updated, also update versions in packages.config for net452 -->
33+
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All"/>
2934
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="3.0.0">
3035
<PrivateAssets>all</PrivateAssets>
3136
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,15 @@ public TimeStampColumnOptions() : base()
2020
}
2121

2222
/// <summary>
23-
/// The TimeStamp column only supports the DateTime and DateTimeOffset data types.
23+
/// The TimeStamp column only supports the DateTime, DateTime2 and DateTimeOffset data types.
2424
/// </summary>
2525
public new SqlDbType DataType
2626
{
2727
get => base.DataType;
2828
set
2929
{
30-
if (value != SqlDbType.DateTime && value != SqlDbType.DateTimeOffset)
31-
throw new ArgumentException("The Standard Column \"TimeStamp\" only supports the DateTime and DateTimeOffset formats.");
30+
if (value != SqlDbType.DateTime && value != SqlDbType.DateTimeOffset && value != SqlDbType.DateTime2)
31+
throw new ArgumentException("The Standard Column \"TimeStamp\" only supports the DateTime, DateTime2 and DateTimeOffset formats.");
3232
base.DataType = value;
3333
}
3434
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ private void WriteTimeStampIfPresent(LogEvent logEvent, TextWriter output, ref s
124124
output.Write(precedingDelimiter);
125125
precedingDelimiter = _commaDelimiter;
126126
var colData = WritePropertyName(logEvent, output, StandardColumn.TimeStamp);
127-
var value = _columnOptions.TimeStamp.DataType == SqlDbType.DateTime
127+
var value = (_columnOptions.TimeStamp.DataType == SqlDbType.DateTime || _columnOptions.TimeStamp.DataType == SqlDbType.DateTime2)
128128
? ((DateTime)colData.Value).ToString("o", CultureInfo.InvariantCulture)
129129
: ((DateTimeOffset)colData.Value).ToString("o", CultureInfo.InvariantCulture);
130130
JsonValueFormatter.WriteQuotedJsonString(value, output);

test/Serilog.Sinks.MSSqlServer.Tests/Sinks/MSSqlServer/ColumnOptions/TimeStampColumnOptionsTests.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,5 +40,16 @@ public void CannotSetDataTypeNVarChar()
4040
// Act and assert - should throw
4141
Assert.Throws<ArgumentException>(() => options.TimeStamp.DataType = SqlDbType.NVarChar);
4242
}
43+
44+
[Trait("Feature", "#300")]
45+
[Fact]
46+
public void CanSetDataTypeDateTime2()
47+
{
48+
// Arrange
49+
var options = new Serilog.Sinks.MSSqlServer.ColumnOptions();
50+
51+
// Act - should not throw
52+
options.TimeStamp.DataType = SqlDbType.DateTime2;
53+
}
4354
}
4455
}

test/Serilog.Sinks.MSSqlServer.Tests/Sinks/MSSqlServer/Output/JsonLogEventFormatterTests.cs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
using System;
22
using System.Collections.Generic;
33
using System.Data;
44
using System.IO;
@@ -90,6 +90,27 @@ public void FormatTimeStampColumnTypeDateTimeRendersCorrectTimeStamp()
9090
Assert.Equal(expectedResult, renderResult);
9191
}
9292

93+
[Fact]
94+
[Trait("Feature", "#300")]
95+
public void FormatTimeStampColumnTypeDateTime2RendersCorrectTimeStamp()
96+
{
97+
// Arrange
98+
const string expectedResult = "{\"TimeStamp\":\"2020-07-01T09:41:10.1230000\",\"Level\":\"Information\",\"Message\":\"\",\"MessageTemplate\":\"Test message template\"}";
99+
_testColumnOptions.TimeStamp.DataType = SqlDbType.DateTime2;
100+
var testLogEvent = CreateTestLogEvent(new DateTimeOffset(2020, 7, 1, 9, 41, 10, 123, TimeSpan.Zero));
101+
102+
// Act
103+
string renderResult;
104+
using (var outputWriter = new StringWriter())
105+
{
106+
_sut.Format(testLogEvent, outputWriter);
107+
renderResult = outputWriter.ToString();
108+
}
109+
110+
// Assert
111+
Assert.Equal(expectedResult, renderResult);
112+
}
113+
93114
[Fact]
94115
public void FormatWithPropertiesRendersCorrectProperties()
95116
{

0 commit comments

Comments
 (0)