Skip to content

Commit c05b658

Browse files
committed
reproduce PR 120
1 parent 48be22c commit c05b658

File tree

14 files changed

+696
-106
lines changed

14 files changed

+696
-106
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,3 +183,4 @@ UpgradeLog*.htm
183183
FakesAssemblies/
184184
/.vs/serilog-sinks-mssqlserver/v15/sqlite3
185185
/.vs/serilog-sinks-mssqlserver/v15/Server/sqlite3
186+
/.vs

README.md

Lines changed: 132 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,21 @@
33
A Serilog sink that writes events to Microsoft SQL Server. While a NoSql store allows for more flexibility to store the different kinds of properties, it sometimes is easier to use an already existing MS SQL server. This sink will write the logevent data to a table and can optionally also store the properties inside an Xml column so they can be queried.
44

55
**Package** - [Serilog.Sinks.MSSqlServer](http://nuget.org/packages/serilog.sinks.mssqlserver)
6-
| **Platforms** - .NET 4.5 and .NET Standard 2.0
7-
8-
From version 5.2 and up, this sink also support the Audit capabilities.
6+
| **Platforms** - .NET Framework 4.5 and .NET Standard 2.0
97

108
## Configuration
119

12-
At minimum a connection string and table name are required.
10+
At minimum a connection string and table name are required.
11+
12+
To use a connection string from the `connectionStrings` section of your application config, specify its name as the value of the connection string.
13+
1314

14-
To use a connection string from the `<connectionStrings>` element of your application config file, specify its name as the value of the connection string.
15+
#### Code (.NET Framework)
1516

16-
#### Code
17+
Older .NET Framework applications can use the `ConfigurationManager` API shown below. Newer .NET Framework applications (using a Framework version that is .NET Standard compliant) should use the _Microsoft.Extensions.Configuration_ version in the next section.
1718

1819
```csharp
19-
var connectionString = @"Server=..."; // or the name of a connection string in your .config file
20+
var connectionString = @"Server=..."; // or the name of a connection string in the app config
2021
var tableName = "Logs";
2122
var columnOptions = new ColumnOptions(); // optional
2223
@@ -25,9 +26,30 @@ var log = new LoggerConfiguration()
2526
.CreateLogger();
2627
```
2728

28-
#### XML
2929

30-
If you are configuring Serilog with the `ReadFrom.AppSettings()` XML configuration support, you can use:
30+
#### Code (.NET Standard / .NET Core)
31+
32+
The application configuration parameter is optional for .NET Standard libraries or .NET Core applications.
33+
34+
```csharp
35+
var appSettings = new ConfigurationBuilder()
36+
.SetBasePath(Directory.GetCurrentDirectory())
37+
.AddJsonFile("appsettings.json")
38+
.Build(); // more likely you will inject an IConfiguration reference
39+
40+
var connectionString = @"Server=..."; // or the name of a connection string in the app config
41+
var tableName = "Logs";
42+
var columnOptions = new ColumnOptions(); // optional
43+
44+
var log = new LoggerConfiguration()
45+
.WriteTo.MSSqlServer(connectionString, tableName, appConfiguration: appSettings, columnOptions: columnOptions)
46+
.CreateLogger();
47+
```
48+
49+
50+
#### Serilog AppSettings package (.NET Framework)
51+
52+
.NET Framework libraries or applications can call `ReadFrom.AppSettings()` to configure Serilog using the [_Serilog.Settings.AppSettings_](https://github.com/serilog/serilog-settings-appsettings) package. This will apply configuration parameters from the `app.config` or `web.config` file:
3153

3254
```xml
3355
<add key="serilog:using:MSSqlServer" value="Serilog.Sinks.MSSqlServer" />
@@ -36,6 +58,30 @@ If you are configuring Serilog with the `ReadFrom.AppSettings()` XML configurati
3658
<add key="serilog:write-to:MSSqlServer.autoCreateSqlTable" value="true"/>
3759
```
3860

61+
62+
#### Serilog Configuration package (.NET Standard / .NET Core)
63+
64+
.NET Standard libraries and .NET Core applications can call `ReadFrom.Configuration(IConfiguration)` to configure Serilog using the [_Serilog.Settings.Configuration_](https://github.com/serilog/serilog-settings-configuration) package (version [**3.0.0-dev-00111**](https://www.nuget.org/packages/Serilog.Settings.Configuration/3.0.0-dev-00111) or newer). This will apply configuration parameters from the application configuration (not only `appsettings.json` as shown here, but any other valid `IConfiguration` source):
65+
66+
67+
```json
68+
{
69+
"Serilog": {
70+
"Using": ["Serilog.Sinks.MSSqlServer"],
71+
"MinimumLevel": "Debug",
72+
"WriteTo": [
73+
{ "Name": "MSSqlServer",
74+
"Args": {
75+
"connectionString": "Server...",
76+
"tableName": "Logs"
77+
}
78+
}
79+
]
80+
}
81+
}
82+
```
83+
84+
3985
## Table definition
4086

4187
You'll need to create a table like this in your database:
@@ -75,15 +121,15 @@ If you set the `autoCreateSqlTable` option to `true`, the sink will create a tab
75121

76122
## Standard columns
77123

78-
The "standard columns" used by this sink (apart from obvious required columns like Id) are described by the StandardColumn enumeration and controlled by `columnOptions.Store`.
124+
The "standard columns" used by this sink (apart from obvious required columns like Id) are described by the StandardColumn enumeration and controlled through code by the `columnOptions.Store` collection.
79125

80126
By default (and consistent with the SQL command to create a table, above) these columns are included:
81-
- StandardColumn.Message
82-
- StandardColumn.MessageTemplate
83-
- StandardColumn.Level
84-
- StandardColumn.TimeStamp
85-
- StandardColumn.Exception
86-
- StandardColumn.Properties
127+
- `StandardColumn.Message`
128+
- `StandardColumn.MessageTemplate`
129+
- `StandardColumn.Level`
130+
- `StandardColumn.TimeStamp`
131+
- `StandardColumn.Exception`
132+
- `StandardColumn.Properties`
87133

88134
You can change this list, as long as the table definition is consistent:
89135

@@ -122,14 +168,14 @@ The log event properties `User` and `Other` will now be placed in the correspond
122168

123169
#### Excluding redundant items from the Properties column
124170

125-
By default, additional properties will still be included in the XML data saved to the Properties column (assuming that is not disabled via the `columnOptions.Store` parameter). This is consistent with the idea behind structured logging, and makes it easier to convert the log data to another (e.g. NoSQL) storage platform later if desired.
171+
By default, additional properties will still be included in the data saved to the XML Properties or JSON LogEvent column (assuming one or both are enabled via the `columnOptions.Store` parameter). This is consistent with the idea behind structured logging, and makes it easier to convert the log data to another (e.g. NoSQL) storage platform later if desired.
126172

127-
However, if necessary, then the properties being saved in their own columns can be excluded from the XML. Use the `columnOptions.Properties.ExcludeAdditionalProperties` parameter in the sink configuration to exclude the redundant properties from the XML.
173+
However, if necessary, then the properties being saved in their own columns can be excluded from the data. Use the `columnOptions.Properties.ExcludeAdditionalProperties` parameter in the sink configuration to exclude the redundant properties from the XML.
128174

129175

130-
### XML configuration for columns
176+
### Columns defined by AppSettings (.NET Framework)
131177

132-
Columns can be defined with the name and data type of the column in SQL Server. Columns specified must match database table exactly. DataType is case sensitive, based on SQL type (excluding precision/length).
178+
Custom columns can be defined with the name and data type of the column in SQL Server. Columns specified must match database table exactly. DataType is case sensitive, based on SQL type (excluding precision/length). This section will be processed automatically if it exists in the application's `web.config` or `app.config` file.
133179

134180
```xml
135181
<configSections>
@@ -144,6 +190,72 @@ Columns can be defined with the name and data type of the column in SQL Server.
144190
</MSSqlServerSettingsSection>
145191
```
146192

193+
### ColumnOptions defined by Configuration (.NET Standard / .NET Core)
194+
195+
For projects using the Serilog Configuration package, most properties of the `ColumnOptions` object are configurable. (The only property not currently supported is the filter-predicate `columnOptions.Properties.PropertyFilter`).
196+
197+
The equivalent of adding custom columns as shown in the .NET Framework example above looks like this:
198+
199+
```json
200+
{
201+
"Serilog": {
202+
"Using": ["Serilog.Sinks.MSSqlServer"],
203+
"MinimumLevel": "Debug",
204+
"WriteTo": [
205+
{ "Name": "MSSqlServer",
206+
"Args": {
207+
"connectionString": "Server...",
208+
"tableName": "Logs",
209+
"columnOptionsSection": {
210+
"customColumns": [
211+
{ "ColumnName": "EventType", "DataType": "int", "AllowNull": false },
212+
{ "ColumnName": "Release", "DataType": "varchar", "DataLength": 32 }
213+
]
214+
}
215+
}
216+
}
217+
]
218+
}
219+
}
220+
```
221+
222+
As the name suggests, `columnOptionSection` is an entire configuration section in its own right. All possible entries and some sample values are shown below. All properties and subsections are optional.
223+
224+
```json
225+
"columnOptionsSection": {
226+
"addStandardColumns": [ "LogEvent" ],
227+
"removeStandardColumns": [ "MessageTemplate", "Properties" ],
228+
"customColumns": [
229+
{ "ColumnName": "EventType", "DataType": "int", "AllowNull": false },
230+
{ "ColumnName": "Release", "DataType": "varchar", "DataLength": 32 }
231+
],
232+
"disableTriggers": true,
233+
"id": { "columnName": "Id" },
234+
"level": { "columnName": "Level", "storeAsEnum": false },
235+
"properties": {
236+
"columnName": "Properties",
237+
"excludeAdditionalProperties": true,
238+
"dictionaryElementName": "dict",
239+
"itemElementName": "item",
240+
"omitDictionaryContainerElement": false,
241+
"omitSequenceContainerElement": false,
242+
"omitStructureContainerElement": false,
243+
"omitElementIfEmpty": true,
244+
"propertyElementName": "prop",
245+
"rootElementName": "root",
246+
"sequenceElementName": "seq",
247+
"structureElementName": "struct",
248+
"usePropertyKeyAsElementName": false
249+
},
250+
"timeStamp": { "columnName": "Timestamp", "convertToUtc": true },
251+
"logEvent": { "columnName": "LogEvent", "excludeAdditionalProperties": true }
252+
"message": { "columnName": "Message" },
253+
"exception": { "columnName": "Exception" },
254+
"messageTemplate": { "columnName": "MessageTemplate" },
255+
}
256+
```
257+
258+
147259
### Options for serialization of the log event data
148260

149261
#### JSON (LogEvent column)
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
using System;
2+
using System.Data;
3+
4+
namespace Serilog.Configuration
5+
{
6+
/// <summary>
7+
/// Converts the SQL data types of custom columns specified
8+
/// in app configuration to the equivalent .NET types
9+
/// </summary>
10+
public static class ConvertSqlDataType
11+
{
12+
/// <summary>
13+
/// Converts the SQL data types of custom columns specified
14+
/// in app configuration to the equivalent .NET types
15+
/// </summary>
16+
/// <param name="sqlDataType">The SQL data type of custom columns from app configuration</param>
17+
/// <param name="length">A length applied to types that accept a length</param>
18+
/// <returns></returns>
19+
public static DataColumn GetEquivalentType(string sqlDataType, int length = 0)
20+
{
21+
DataColumn c = new DataColumn();
22+
switch(sqlDataType)
23+
{
24+
case "bigint":
25+
c.DataType = typeof(long);
26+
break;
27+
case "varbinary":
28+
case "binary":
29+
if(length == 0) throw new ArgumentException($"SQL {sqlDataType} column requires a non-zero length argument.");
30+
c.DataType = Type.GetType("System.Byte[]");
31+
c.ExtendedProperties["DataLength"] = length;
32+
break;
33+
case "bit":
34+
c.DataType = typeof(bool);
35+
break;
36+
case "char":
37+
case "nchar":
38+
case "ntext":
39+
case "nvarchar":
40+
case "text":
41+
case "varchar":
42+
if(length == 0) throw new ArgumentException($"SQL {sqlDataType} column requires a non-zero length argument.");
43+
c.DataType = Type.GetType("System.String");
44+
c.MaxLength = length;
45+
break;
46+
case "date":
47+
case "datetime":
48+
case "datetime2":
49+
case "smalldatetime":
50+
c.DataType = typeof(DateTime);
51+
break;
52+
case "decimal":
53+
case "money":
54+
case "numeric":
55+
case "smallmoney":
56+
c.DataType = typeof(Decimal);
57+
break;
58+
case "float":
59+
c.DataType = typeof(double);
60+
break;
61+
case "int":
62+
c.DataType = typeof(int);
63+
break;
64+
case "real":
65+
c.DataType = typeof(float);
66+
break;
67+
case "smallint":
68+
c.DataType = typeof(short);
69+
break;
70+
case "time":
71+
c.DataType = typeof(TimeSpan);
72+
break;
73+
case "uniqueidentifier":
74+
c.DataType = typeof(Guid);
75+
break;
76+
default:
77+
throw new ArgumentException($"SQL {sqlDataType} is not a recognized or supported column data-type.");
78+
}
79+
return c;
80+
}
81+
}
82+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// Copyright 2015 Serilog Contributors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
using System.Text.RegularExpressions;
16+
17+
namespace Serilog.Configuration
18+
{
19+
/// <summary>
20+
/// Details of an individual column described in the app config.
21+
/// </summary>
22+
public class Column
23+
{
24+
private string _dataType = "varchar";
25+
private const string ValidSqlDataTypes = "(bigint)|(bit)|(binary)|(varbinary)|(char)|(date)|(datetime)|(datetime2)|(decimal)|(float)|(int)|(money)|(nchar)|(ntext)|(numeric)|(nvarchar)|(real)|(smalldatetime)|(smallint)|(smallmoney)|(text)|(time)|(uniqueidentifier)|(varchar)";
26+
27+
/// <summary>
28+
/// The name of a custom SQL Server column.
29+
/// </summary>
30+
public string ColumnName { get; set; }
31+
32+
/// <summary>
33+
/// The data type of a custom SQL Server column.
34+
/// </summary>
35+
public string DataType
36+
{
37+
get => _dataType;
38+
set
39+
{
40+
if(Regex.Match(value, ValidSqlDataTypes).Success)
41+
{
42+
_dataType = value;
43+
}
44+
else
45+
{
46+
// If validation fails, ignore the value, which matches the behavior
47+
// of the .NET Framework [RegexStringValidator] attribute used by the
48+
// original version of the SQL sink project.
49+
}
50+
}
51+
}
52+
53+
/// <summary>
54+
/// The size of certain SQL Server column types such as varchar;
55+
/// </summary>
56+
public int DataLength { get; set; } = 0;
57+
58+
/// <summary>
59+
/// Controls whether the column is nullable
60+
/// </summary>
61+
public bool AllowNull { get; set; } = true;
62+
}
63+
}

0 commit comments

Comments
 (0)