Skip to content

Commit c53f149

Browse files
authored
Merge pull request #301 from stedel/feature/300-datetime2-timestamp
Add support for DateTime2 DataType in TimeStamp column.
2 parents f85db02 + d70790f commit c53f149

File tree

5 files changed

+44
-7
lines changed

5 files changed

+44
-7
lines changed

README.md

Lines changed: 7 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

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)