diff --git a/.editorconfig b/.editorconfig
index f16002ac..d3a3808d 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -14,3 +14,14 @@ end_of_line = lf
[*.{cmd, bat}]
end_of_line = crlf
+
+[*.cs]
+
+# CA2227: Collection properties should be read only
+dotnet_diagnostic.CA2227.severity = none
+
+# CA1303: Do not pass literals as localized parameters
+dotnet_diagnostic.CA1303.severity = none
+
+# S108: Nested blocks of code should not be left empty
+dotnet_diagnostic.S108.severity = none
diff --git a/README.md b/README.md
index d38760c9..bd2821dd 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
A Serilog sink that writes events to Microsoft SQL Server. This sink will write the log event data to a table and can optionally also store the properties inside an XML or JSON column so they can be queried. Important properties can also be written to their own separate columns.
**Package** - [Serilog.Sinks.MSSqlServer](http://nuget.org/packages/serilog.sinks.mssqlserver)
-| **Minimum Platforms** - .NET Framework 4.5.2, .NET Core 2.0, .NET Standard 2.0
+| **Minimum Platforms** - .NET Framework 4.6.1, .NET Core 2.0, .NET Standard 2.0
#### Topics
@@ -34,9 +34,13 @@ All sink configuration methods accept the following arguments, though not necess
* `batchPostingLimit`
* `period`
* `formatProvider`
+* `useMsi`
+* `azureServiceTokenProviderResource`
### Basic Arguments
+Adding support for MSI (Managed Service Identities), and AccessTokens in sqlConnections.
+
At minimum, `connectionString` and `tableName` are required. If you are using an external configuration source such as an XML file or JSON file, you can use a named connection string instead of providing the full "raw" connection string.
If `schemaName` is omitted, the default is `dbo`.
@@ -70,7 +74,6 @@ Because of the way external configuration has been implemented in various .NET f
| Your Framework | TFM | Project Types | External Configuration |
| --- | --- | --- | --- |
-| .NET Framework 4.5.2 | `net452` | app or library | _System.Configuration_ |
| .NET Framework 4.6.1+ | `net461` | app or library | _System.Configuration_ |
| .NET Framework 4.6.1+ | `net461` | app or library | _Microsoft.Extensions.Configuration_ |
| .NET Standard 2.0 | `netstandard2.0` | library only | _Microsoft.Extensions.Configuration_ |
diff --git a/src/Serilog.Sinks.MSSqlServer/Configuration/Extensions/Hybrid/LoggerConfigurationMSSqlServerExtensions.cs b/src/Serilog.Sinks.MSSqlServer/Configuration/Extensions/Hybrid/LoggerConfigurationMSSqlServerExtensions.cs
index ad336244..db90ed1b 100644
--- a/src/Serilog.Sinks.MSSqlServer/Configuration/Extensions/Hybrid/LoggerConfigurationMSSqlServerExtensions.cs
+++ b/src/Serilog.Sinks.MSSqlServer/Configuration/Extensions/Hybrid/LoggerConfigurationMSSqlServerExtensions.cs
@@ -34,7 +34,8 @@ public static class LoggerConfigurationMSSqlServerExtensions
///
/// The configuration section name for app.config or web.config configuration files.
///
- public static string AppConfigSectionName = "MSSqlServerSettingsSection";
+ public static string AppConfigSectionName { get; } = "MSSqlServerSettingsSection";
+
///
/// Adds a sink that writes log events to a table in a MSSqlServer database.
@@ -54,6 +55,8 @@ public static class LoggerConfigurationMSSqlServerExtensions
/// An externally-modified group of column settings
/// A config section defining various column settings
/// Name of the schema for the table to store the data in. The default is 'dbo'.
+ /// Option to use MSI
+ /// Resource required in AzureServiceTokenProvider.GetAccessTokenAsync(azureServiceTokenProviderResource). This will error if null, and useMsi is st to true
/// Logger configuration, allowing configuration to continue.
/// A required parameter is null.
public static LoggerConfiguration MSSqlServer(
@@ -68,20 +71,28 @@ public static LoggerConfiguration MSSqlServer(
bool autoCreateSqlTable = false,
ColumnOptions columnOptions = null,
IConfigurationSection columnOptionsSection = null,
- string schemaName = "dbo"
+ string schemaName = "dbo",
+ bool useMsi = false,
+ string azureServiceTokenProviderResource = null
)
{
- if(loggerConfiguration == null)
+ if (useMsi && string.IsNullOrWhiteSpace(azureServiceTokenProviderResource))
+ throw new ArgumentNullException(nameof(azureServiceTokenProviderResource), "If useMsi is set to true, you must also provide an azureServiceTokenProviderResource");
+
+ if (loggerConfiguration == null)
throw new ArgumentNullException("loggerConfiguration");
var defaultedPeriod = period ?? MSSqlServerSink.DefaultPeriod;
var colOpts = columnOptions ?? new ColumnOptions();
var connStr = connectionString;
+ var tokenResource = azureServiceTokenProviderResource;
if (ConfigurationManager.GetSection(AppConfigSectionName) is MSSqlServerConfigurationSection serviceConfigSection)
{
colOpts = ApplySystemConfiguration.ConfigureColumnOptions(serviceConfigSection, colOpts);
connStr = ApplySystemConfiguration.GetConnectionString(connStr);
+ if(useMsi)
+ tokenResource = ApplySystemConfiguration.GetAzureServiceTokenProviderResource(tokenResource);
if (appConfiguration != null || columnOptionsSection != null)
SelfLog.WriteLine("Warning: Both System.Configuration (app.config or web.config) and Microsoft.Extensions.Configuration are being applied to the MSSQLServer sink.");
@@ -91,6 +102,8 @@ public static LoggerConfiguration MSSqlServer(
{
connStr = ApplyMicrosoftExtensionsConfiguration.GetConnectionString(connStr, appConfiguration);
colOpts = ApplyMicrosoftExtensionsConfiguration.ConfigureColumnOptions(colOpts, columnOptionsSection);
+ if (useMsi)
+ tokenResource = ApplyMicrosoftExtensionsConfiguration.GetAzureServiceTokenProviderResource(tokenResource, appConfiguration);
}
return loggerConfiguration.Sink(
@@ -102,7 +115,9 @@ public static LoggerConfiguration MSSqlServer(
formatProvider,
autoCreateSqlTable,
colOpts,
- schemaName
+ schemaName,
+ useMsi,
+ tokenResource
),
restrictedToMinimumLevel);
}
@@ -120,6 +135,8 @@ public static LoggerConfiguration MSSqlServer(
/// An externally-modified group of column settings
/// A config section defining various column settings
/// Name of the schema for the table to store the data in. The default is 'dbo'.
+ /// Option to use MSI
+ /// Resource required in AzureServiceTokenProvider.GetAccessTokenAsync(azureServiceTokenProviderResource). This will error if null, and useMsi is st to true
/// Logger configuration, allowing configuration to continue.
/// A required parameter is null.
public static LoggerConfiguration MSSqlServer(
@@ -132,19 +149,26 @@ public static LoggerConfiguration MSSqlServer(
bool autoCreateSqlTable = false,
ColumnOptions columnOptions = null,
IConfigurationSection columnOptionsSection = null,
- string schemaName = "dbo"
+ string schemaName = "dbo",
+ bool useMsi = false,
+ string azureServiceTokenProviderResource = null
)
{
- if(loggerAuditSinkConfiguration == null)
+ if (useMsi && string.IsNullOrWhiteSpace(azureServiceTokenProviderResource))
+ throw new ArgumentNullException(nameof(azureServiceTokenProviderResource), "If useMsi is set to true, you must also provide an azureServiceTokenProviderResource");
+
+ if (loggerAuditSinkConfiguration == null)
throw new ArgumentNullException("loggerAuditSinkConfiguration");
var colOpts = columnOptions ?? new ColumnOptions();
var connStr = connectionString;
+ var tokenResource = azureServiceTokenProviderResource;
if (ConfigurationManager.GetSection(AppConfigSectionName) is MSSqlServerConfigurationSection serviceConfigSection)
{
colOpts = ApplySystemConfiguration.ConfigureColumnOptions(serviceConfigSection, colOpts);
connStr = ApplySystemConfiguration.GetConnectionString(connStr);
+ tokenResource = ApplySystemConfiguration.GetAzureServiceTokenProviderResource(tokenResource);
if (appConfiguration != null || columnOptionsSection != null)
SelfLog.WriteLine("Warning: Both System.Configuration (app.config or web.config) and Microsoft.Extensions.Configuration are being applied to the MSSQLServer sink.");
@@ -154,6 +178,7 @@ public static LoggerConfiguration MSSqlServer(
{
connStr = ApplyMicrosoftExtensionsConfiguration.GetConnectionString(connStr, appConfiguration);
colOpts = ApplyMicrosoftExtensionsConfiguration.ConfigureColumnOptions(colOpts, columnOptionsSection);
+ tokenResource = ApplyMicrosoftExtensionsConfiguration.GetAzureServiceTokenProviderResource(tokenResource, appConfiguration);
}
return loggerAuditSinkConfiguration.Sink(
@@ -163,7 +188,9 @@ public static LoggerConfiguration MSSqlServer(
formatProvider,
autoCreateSqlTable,
colOpts,
- schemaName
+ schemaName,
+ useMsi,
+ tokenResource
),
restrictedToMinimumLevel);
}
diff --git a/src/Serilog.Sinks.MSSqlServer/Configuration/Extensions/Microsoft.Extensions.Configuration/LoggerConfigurationMSSqlServerExtensions.cs b/src/Serilog.Sinks.MSSqlServer/Configuration/Extensions/Microsoft.Extensions.Configuration/LoggerConfigurationMSSqlServerExtensions.cs
index 8f351bb2..da9f1788 100644
--- a/src/Serilog.Sinks.MSSqlServer/Configuration/Extensions/Microsoft.Extensions.Configuration/LoggerConfigurationMSSqlServerExtensions.cs
+++ b/src/Serilog.Sinks.MSSqlServer/Configuration/Extensions/Microsoft.Extensions.Configuration/LoggerConfigurationMSSqlServerExtensions.cs
@@ -45,6 +45,8 @@ public static partial class LoggerConfigurationMSSqlServerExtensions
/// An externally-modified group of column settings
/// A config section defining various column settings
/// Name of the schema for the table to store the data in. The default is 'dbo'.
+ /// Option to use MSI
+ /// Resource required in AzureServiceTokenProvider.GetAccessTokenAsync(azureServiceTokenProviderResource). This will error if null, and useMsi is st to true
/// Logger configuration, allowing configuration to continue.
/// A required parameter is null.
public static LoggerConfiguration MSSqlServer(
@@ -59,15 +61,21 @@ public static LoggerConfiguration MSSqlServer(
bool autoCreateSqlTable = false,
ColumnOptions columnOptions = null,
IConfigurationSection columnOptionsSection = null,
- string schemaName = "dbo"
+ string schemaName = "dbo",
+ bool useMsi = false,
+ string azureServiceTokenProviderResource = null
)
{
- if(loggerConfiguration == null)
+ if (useMsi && string.IsNullOrWhiteSpace(azureServiceTokenProviderResource))
+ throw new ArgumentNullException(nameof(azureServiceTokenProviderResource), "If useMsi is set to true, you must also provide an azureServiceTokenProviderResource");
+
+ if (loggerConfiguration == null)
throw new ArgumentNullException("loggerConfiguration");
var defaultedPeriod = period ?? MSSqlServerSink.DefaultPeriod;
var connectionStr = ApplyMicrosoftExtensionsConfiguration.GetConnectionString(connectionString, appConfiguration);
var colOpts = ApplyMicrosoftExtensionsConfiguration.ConfigureColumnOptions(columnOptions, columnOptionsSection);
+ var tokenResource = useMsi ? ApplyMicrosoftExtensionsConfiguration.GetAzureServiceTokenProviderResource(azureServiceTokenProviderResource, appConfiguration) : null;
return loggerConfiguration.Sink(
new MSSqlServerSink(
@@ -78,7 +86,9 @@ public static LoggerConfiguration MSSqlServer(
formatProvider,
autoCreateSqlTable,
colOpts,
- schemaName
+ schemaName,
+ useMsi,
+ tokenResource
),
restrictedToMinimumLevel);
}
@@ -96,6 +106,8 @@ public static LoggerConfiguration MSSqlServer(
/// An externally-modified group of column settings
/// A config section defining various column settings
/// Name of the schema for the table to store the data in. The default is 'dbo'.
+ /// Option to use MSI
+ /// Resource required in AzureServiceTokenProvider.GetAccessTokenAsync(azureServiceTokenProviderResource). This will error if null, and useMsi is st to true
/// Logger configuration, allowing configuration to continue.
/// A required parameter is null.
public static LoggerConfiguration MSSqlServer(
@@ -108,23 +120,31 @@ public static LoggerConfiguration MSSqlServer(
bool autoCreateSqlTable = false,
ColumnOptions columnOptions = null,
IConfigurationSection columnOptionsSection = null,
- string schemaName = "dbo"
+ string schemaName = "dbo",
+ bool useMsi = false,
+ string azureServiceTokenProviderResource = null
)
{
- if(loggerAuditSinkConfiguration == null)
+ if (useMsi && string.IsNullOrWhiteSpace(azureServiceTokenProviderResource))
+ throw new ArgumentNullException(nameof(azureServiceTokenProviderResource), "If useMsi is set to true, you must also provide an azureServiceTokenProviderResource");
+
+ if (loggerAuditSinkConfiguration == null)
throw new ArgumentNullException("loggerAuditSinkConfiguration");
var connectionStr = ApplyMicrosoftExtensionsConfiguration.GetConnectionString(connectionString, appConfiguration);
var colOpts = ApplyMicrosoftExtensionsConfiguration.ConfigureColumnOptions(columnOptions, columnOptionsSection);
+ var tokenResource = useMsi ? ApplyMicrosoftExtensionsConfiguration.GetAzureServiceTokenProviderResource(azureServiceTokenProviderResource, appConfiguration) : null;
return loggerAuditSinkConfiguration.Sink(
new MSSqlServerAuditSink(
- connectionString,
+ connectionStr,
tableName,
formatProvider,
autoCreateSqlTable,
- columnOptions,
- schemaName
+ colOpts,
+ schemaName,
+ useMsi,
+ tokenResource
),
restrictedToMinimumLevel);
}
diff --git a/src/Serilog.Sinks.MSSqlServer/Configuration/Extensions/System.Configuration/LoggerConfigurationMSSqlServerExtensions.cs b/src/Serilog.Sinks.MSSqlServer/Configuration/Extensions/System.Configuration/LoggerConfigurationMSSqlServerExtensions.cs
index ef8f9dd9..fe23eb12 100644
--- a/src/Serilog.Sinks.MSSqlServer/Configuration/Extensions/System.Configuration/LoggerConfigurationMSSqlServerExtensions.cs
+++ b/src/Serilog.Sinks.MSSqlServer/Configuration/Extensions/System.Configuration/LoggerConfigurationMSSqlServerExtensions.cs
@@ -48,6 +48,8 @@ public static class LoggerConfigurationMSSqlServerExtensions
/// Supplies culture-specific formatting information, or null.
/// Create log table with the provided name on destination sql server.
///
+ /// Option to use MSI
+ /// Resource required in AzureServiceTokenProvider.GetAccessTokenAsync(azureServiceTokenProviderResource). This will error if null, and useMsi is st to true
/// Logger configuration, allowing configuration to continue.
/// A required parameter is null.
public static LoggerConfiguration MSSqlServer(
@@ -60,9 +62,13 @@ public static LoggerConfiguration MSSqlServer(
IFormatProvider formatProvider = null,
bool autoCreateSqlTable = false,
ColumnOptions columnOptions = null,
- string schemaName = "dbo"
- )
+ string schemaName = "dbo",
+ bool useMsi = false,
+ string azureServiceTokenProviderResource = null)
{
+ if (useMsi && string.IsNullOrWhiteSpace(azureServiceTokenProviderResource))
+ throw new ArgumentNullException(nameof(azureServiceTokenProviderResource), "If useMsi is set to true, you must also provide an azureServiceTokenProviderResource");
+
if (loggerConfiguration == null) throw new ArgumentNullException("loggerConfiguration");
var defaultedPeriod = period ?? MSSqlServerSink.DefaultPeriod;
@@ -73,6 +79,8 @@ public static LoggerConfiguration MSSqlServer(
connectionString = ApplySystemConfiguration.GetConnectionString(connectionString);
+ var tokenResource = useMsi ? ApplySystemConfiguration.GetAzureServiceTokenProviderResource(azureServiceTokenProviderResource) : null;
+
return loggerConfiguration.Sink(
new MSSqlServerSink(
connectionString,
@@ -82,8 +90,9 @@ public static LoggerConfiguration MSSqlServer(
formatProvider,
autoCreateSqlTable,
colOpts,
- schemaName
- ),
+ schemaName,
+ useMsi,
+ tokenResource),
restrictedToMinimumLevel);
}
@@ -101,6 +110,8 @@ public static LoggerConfiguration MSSqlServer(
/// Supplies culture-specific formatting information, or null.
/// Create log table with the provided name on destination sql server.
///
+ /// Option to use MSI
+ /// Resource required in AzureServiceTokenProvider.GetAccessTokenAsync(azureServiceTokenProviderResource). This will error if null, and useMsi is st to true
/// Logger configuration, allowing configuration to continue.
/// A required parameter is null.
public static LoggerConfiguration MSSqlServer(this LoggerAuditSinkConfiguration loggerAuditSinkConfiguration,
@@ -110,8 +121,13 @@ public static LoggerConfiguration MSSqlServer(this LoggerAuditSinkConfiguration
IFormatProvider formatProvider = null,
bool autoCreateSqlTable = false,
ColumnOptions columnOptions = null,
- string schemaName = "dbo")
+ string schemaName = "dbo",
+ bool useMsi = false,
+ string azureServiceTokenProviderResource = null)
{
+ if (useMsi && string.IsNullOrWhiteSpace(azureServiceTokenProviderResource))
+ throw new ArgumentNullException(nameof(azureServiceTokenProviderResource), "If useMsi is set to true, you must also provide an azureServiceTokenProviderResource");
+
if (loggerAuditSinkConfiguration == null) throw new ArgumentNullException("loggerAuditSinkConfiguration");
var colOpts = columnOptions ?? new ColumnOptions();
@@ -121,6 +137,8 @@ public static LoggerConfiguration MSSqlServer(this LoggerAuditSinkConfiguration
connectionString = ApplySystemConfiguration.GetConnectionString(connectionString);
+ var tokenResource = useMsi ? ApplySystemConfiguration.GetAzureServiceTokenProviderResource(azureServiceTokenProviderResource) : null;
+
return loggerAuditSinkConfiguration.Sink(
new MSSqlServerAuditSink(
connectionString,
@@ -128,8 +146,9 @@ public static LoggerConfiguration MSSqlServer(this LoggerAuditSinkConfiguration
formatProvider,
autoCreateSqlTable,
colOpts,
- schemaName
- ),
+ schemaName,
+ useMsi,
+ tokenResource),
restrictedToMinimumLevel);
}
}
diff --git a/src/Serilog.Sinks.MSSqlServer/Configuration/Implementations/Microsoft.Extensions.Configuration/ApplyMicrosoftExtensionsConfiguration.cs b/src/Serilog.Sinks.MSSqlServer/Configuration/Implementations/Microsoft.Extensions.Configuration/ApplyMicrosoftExtensionsConfiguration.cs
index 7ee058bc..2d47d343 100644
--- a/src/Serilog.Sinks.MSSqlServer/Configuration/Implementations/Microsoft.Extensions.Configuration/ApplyMicrosoftExtensionsConfiguration.cs
+++ b/src/Serilog.Sinks.MSSqlServer/Configuration/Implementations/Microsoft.Extensions.Configuration/ApplyMicrosoftExtensionsConfiguration.cs
@@ -8,7 +8,7 @@
namespace Serilog.Sinks.MSSqlServer
{
///
- /// Configures the sink's connection string and ColumnOtions object.
+ /// Configures the sink's connection string and ColumnOtions object, and azure token provider resource.
///
internal static class ApplyMicrosoftExtensionsConfiguration
{
@@ -32,6 +32,26 @@ internal static string GetConnectionString(string nameOrConnectionString, IConfi
return cs;
}
+ ///
+ /// Examine if supplied resource string is a reference to an item in web.config
+ /// If it is, return the named item, if not, return string as supplied.
+ ///
+ ///
+ ///
+ ///
+ internal static string GetAzureServiceTokenProviderResource(string nameOrResource, IConfiguration appConfiguration)
+ {
+ // If there is an `/`, we assume this is a raw resource string not a named value
+ // If there are no `/`, attempt to pull the named value from config
+ if (nameOrResource.IndexOf('/') > -1) return nameOrResource;
+ string cs = appConfiguration?.GetValue(nameOrResource);
+ if (string.IsNullOrEmpty(cs))
+ {
+ SelfLog.WriteLine("MSSqlServer sink configured value {0} is not found in app settings and does not appear to be a raw resource string such as http://login.microsoftonline.com.", nameOrResource);
+ }
+ return cs;
+ }
+
///
/// Create or add to the ColumnOptions object and apply any configuration changes to it.
///
diff --git a/src/Serilog.Sinks.MSSqlServer/Configuration/Implementations/SetProperty.cs b/src/Serilog.Sinks.MSSqlServer/Configuration/Implementations/SetProperty.cs
index 6acdd42d..5907b809 100644
--- a/src/Serilog.Sinks.MSSqlServer/Configuration/Implementations/SetProperty.cs
+++ b/src/Serilog.Sinks.MSSqlServer/Configuration/Implementations/SetProperty.cs
@@ -8,12 +8,14 @@ namespace Serilog.Sinks.MSSqlServer
public static partial class SetProperty
{
// Usage:
- // SetProperty.IfValueNotNull(stringFromConfig, (boolOutputValue) => opts.BoolProperty = boolOutputValue);
+#pragma warning disable S125 // Sections of code should not be commented out
+ // SetProperty.IfValueNotNull(stringFromConfig, (boolOutputValue) => opts.BoolProperty = boolOutputValue);
///
/// Simulates passing a property-setter to an "out" argument.
///
- public delegate void PropertySetter(T value);
+ public delegate void PropertySetter(T value);
+#pragma warning restore S125 // Sections of code should not be commented out
///
/// This will only set a value (execute the PropertySetter delegate) if the value is non-null.
diff --git a/src/Serilog.Sinks.MSSqlServer/Configuration/Implementations/System.Configuration/ApplySystemConfiguration.cs b/src/Serilog.Sinks.MSSqlServer/Configuration/Implementations/System.Configuration/ApplySystemConfiguration.cs
index 4809061f..405adc31 100644
--- a/src/Serilog.Sinks.MSSqlServer/Configuration/Implementations/System.Configuration/ApplySystemConfiguration.cs
+++ b/src/Serilog.Sinks.MSSqlServer/Configuration/Implementations/System.Configuration/ApplySystemConfiguration.cs
@@ -7,7 +7,7 @@
namespace Serilog.Sinks.MSSqlServer
{
///
- /// Configures the sink's connection string and ColumnOtions object.
+ /// Configures the sink's connection string, ColumnOtions object, and azure token provider resource.
///
internal static class ApplySystemConfiguration
{
@@ -38,6 +38,25 @@ internal static string GetConnectionString(string nameOrConnectionString)
return nameOrConnectionString;
}
+ ///
+ /// Examine if supplied resource string is a reference to an item in web.config
+ /// If it is, return the named item, if not, return string as supplied.
+ ///
+ ///
+ ///
+ internal static string GetAzureServiceTokenProviderResource(string nameOrResource)
+ {
+ // If there is an `/`, we assume this is a raw resource string not a named value
+ // If there are no `/`, attempt to pull the named value from config
+ if (nameOrResource.IndexOf('/') > -1) return nameOrResource;
+ var cs = ConfigurationManager.AppSettings.Get(nameOrResource);
+ if (string.IsNullOrEmpty(cs))
+ {
+ SelfLog.WriteLine("MSSqlServer sink configured value {0} is not found in app settings and does not appear to be a raw resource string such as http://login.microsoftonline.com.", nameOrResource);
+ }
+ return cs;
+ }
+
///
/// Populate ColumnOptions properties and collections from app config
///
diff --git a/src/Serilog.Sinks.MSSqlServer/Configuration/Implementations/System.Configuration/ColumnConfig.cs b/src/Serilog.Sinks.MSSqlServer/Configuration/Implementations/System.Configuration/ColumnConfig.cs
index 26461060..dc0e14a7 100644
--- a/src/Serilog.Sinks.MSSqlServer/Configuration/Implementations/System.Configuration/ColumnConfig.cs
+++ b/src/Serilog.Sinks.MSSqlServer/Configuration/Implementations/System.Configuration/ColumnConfig.cs
@@ -35,36 +35,36 @@ public ColumnConfig(string columnName, string dataType)
[ConfigurationProperty("ColumnName", IsRequired = true, IsKey = true)]
public virtual string ColumnName
{
- get { return (string)this["ColumnName"]; }
- set { this["ColumnName"] = value; }
+ get { return (string)this[nameof(ColumnName)]; }
+ set { this[nameof(ColumnName)] = value; }
}
[ConfigurationProperty("DataType")]
public string DataType
{
- get { return (string)this["DataType"]; }
- set { this["DataType"] = value; }
+ get { return (string)this[nameof(DataType)]; }
+ set { this[nameof(DataType)] = value; }
}
[ConfigurationProperty("DataLength")]
public string DataLength
{
- get { return (string)this["DataLength"]; }
- set { this["DataLength"] = value; }
+ get { return (string)this[nameof(DataLength)]; }
+ set { this[nameof(DataLength)] = value; }
}
[ConfigurationProperty("AllowNull")]
public string AllowNull
{
- get { return (string)this["AllowNull"]; }
- set { this["AllowNull"] = value; }
+ get { return (string)this[nameof(AllowNull)]; }
+ set { this[nameof(AllowNull)] = value; }
}
[ConfigurationProperty("NonClusteredIndex")]
public string NonClusteredIndex
{
- get { return (string)this["NonClusteredIndex"]; }
- set { this["NonClusteredIndex"] = value; }
+ get { return (string)this[nameof(NonClusteredIndex)]; }
+ set { this[nameof(NonClusteredIndex)] = value; }
}
internal SqlColumn AsSqlColumn()
@@ -72,18 +72,18 @@ internal SqlColumn AsSqlColumn()
var sqlColumn = new SqlColumn();
// inheritors can override IsRequired; config might not change the names of Standard Columns
- SetProperty.IfProvidedNotEmpty(this, "ColumnName", (val) => sqlColumn.ColumnName = val);
+ SetProperty.IfProvidedNotEmpty(this, nameof(ColumnName), (val) => sqlColumn.ColumnName = val);
- SetProperty.IfProvidedNotEmpty(this, "DataType", (val) => sqlColumn.SetDataTypeFromConfigString(val));
+ SetProperty.IfProvidedNotEmpty(this, nameof(DataType), (val) => sqlColumn.SetDataTypeFromConfigString(val));
- SetProperty.IfProvided(this, "DataLength", (val) => sqlColumn.DataLength = val);
+ SetProperty.IfProvided(this, nameof(DataLength), (val) => sqlColumn.DataLength = val);
if (sqlColumn.DataLength == 0 && SqlDataTypes.DataLengthRequired.Contains(sqlColumn.DataType))
throw new ArgumentException($"SQL column {sqlColumn.ColumnName} of data type {sqlColumn.DataType.ToString()} requires a non-zero DataLength property.");
- SetProperty.IfProvided(this, "AllowNull", (val) => sqlColumn.AllowNull = val);
+ SetProperty.IfProvided(this, nameof(AllowNull), (val) => sqlColumn.AllowNull = val);
- SetProperty.IfProvided(this, "NonClusteredIndex", (val) => sqlColumn.NonClusteredIndex = val);
+ SetProperty.IfProvided(this, nameof(NonClusteredIndex), (val) => sqlColumn.NonClusteredIndex = val);
return sqlColumn;
}
diff --git a/src/Serilog.Sinks.MSSqlServer/Configuration/Implementations/System.Configuration/MSSqlServerConfigurationSection.cs b/src/Serilog.Sinks.MSSqlServer/Configuration/Implementations/System.Configuration/MSSqlServerConfigurationSection.cs
index 4c6134c9..6e9c629e 100644
--- a/src/Serilog.Sinks.MSSqlServer/Configuration/Implementations/System.Configuration/MSSqlServerConfigurationSection.cs
+++ b/src/Serilog.Sinks.MSSqlServer/Configuration/Implementations/System.Configuration/MSSqlServerConfigurationSection.cs
@@ -34,36 +34,36 @@ public static MSSqlServerConfigurationSection Settings
public MSSqlServerConfigurationSection()
{
- base["Level"] = new StandardColumnConfigLevel();
+ base[nameof(Level)] = new StandardColumnConfigLevel();
}
[ConfigurationProperty("DisableTriggers")]
public string DisableTriggers
{
- get => (string)base["DisableTriggers"];
+ get => (string)base[nameof(DisableTriggers)];
set
{
- base["DisableTriggers"] = value;
+ base[nameof(DisableTriggers)] = value;
}
}
[ConfigurationProperty("ClusteredColumnstoreIndex")]
public string ClusteredColumnstoreIndex
{
- get => (string)base["ClusteredColumnstoreIndex"];
+ get => (string)base[nameof(ClusteredColumnstoreIndex)];
set
{
- base["ClusteredColumnstoreIndex"] = value;
+ base[nameof(ClusteredColumnstoreIndex)] = value;
}
}
[ConfigurationProperty("PrimaryKeyColumnName")]
public string PrimaryKeyColumnName
{
- get => (string)base["PrimaryKeyColumnName"];
+ get => (string)base[nameof(PrimaryKeyColumnName)];
set
{
- base["PrimaryKeyColumnName"] = value;
+ base[nameof(PrimaryKeyColumnName)] = value;
}
}
@@ -71,57 +71,57 @@ public string PrimaryKeyColumnName
[ConfigurationCollection(typeof(StandardColumnCollection), AddItemName = "add")]
public StandardColumnCollection AddStandardColumns
{
- get => (StandardColumnCollection)base["AddStandardColumns"];
+ get => (StandardColumnCollection)base[nameof(AddStandardColumns)];
}
[ConfigurationProperty("RemoveStandardColumns", IsDefaultCollection = false)]
[ConfigurationCollection(typeof(StandardColumnCollection), AddItemName = "remove")]
public StandardColumnCollection RemoveStandardColumns
{
- get => (StandardColumnCollection)base["RemoveStandardColumns"];
+ get => (StandardColumnCollection)base[nameof(RemoveStandardColumns)];
}
[ConfigurationProperty("Columns", IsDefaultCollection = false)]
[ConfigurationCollection(typeof(ColumnCollection), AddItemName = "add")]
public ColumnCollection Columns
{
- get => (ColumnCollection)base["Columns"];
+ get => (ColumnCollection)base[nameof(Columns)];
}
[ConfigurationProperty("Exception")]
public StandardColumnConfigException Exception
{
- get => (StandardColumnConfigException)base["Exception"];
+ get => (StandardColumnConfigException)base[nameof(Exception)];
}
[ConfigurationProperty("Id")]
public StandardColumnConfigId Id
{
- get => (StandardColumnConfigId)base["Id"];
+ get => (StandardColumnConfigId)base[nameof(Id)];
}
[ConfigurationProperty("Level")]
public StandardColumnConfigLevel Level
{
- get => (StandardColumnConfigLevel)base["Level"];
+ get => (StandardColumnConfigLevel)base[nameof(Level)];
}
[ConfigurationProperty("LogEvent")]
public StandardColumnConfigLogEvent LogEvent
{
- get => (StandardColumnConfigLogEvent)base["LogEvent"];
+ get => (StandardColumnConfigLogEvent)base[nameof(LogEvent)];
}
[ConfigurationProperty("Message")]
public StandardColumnConfigMessage Message
{
- get => (StandardColumnConfigMessage)base["Message"];
+ get => (StandardColumnConfigMessage)base[nameof(Message)];
}
[ConfigurationProperty("MessageTemplate")]
public StandardColumnConfigMessageTemplate MessageTemplate
{
- get => (StandardColumnConfigMessageTemplate)base["MessageTemplate"];
+ get => (StandardColumnConfigMessageTemplate)base[nameof(MessageTemplate)];
}
// Name changed to avoid conflict with Properties in ConfigurationElement base class
@@ -134,7 +134,7 @@ public StandardColumnConfigProperties PropertiesColumn
[ConfigurationProperty("TimeStamp")]
public StandardColumnConfigTimeStamp TimeStamp
{
- get => (StandardColumnConfigTimeStamp)base["TimeStamp"];
+ get => (StandardColumnConfigTimeStamp)base[nameof(TimeStamp)];
}
}
}
diff --git a/src/Serilog.Sinks.MSSqlServer/Configuration/Implementations/System.Configuration/StandardColumnConfig.cs b/src/Serilog.Sinks.MSSqlServer/Configuration/Implementations/System.Configuration/StandardColumnConfig.cs
index 15130a02..11984ea2 100644
--- a/src/Serilog.Sinks.MSSqlServer/Configuration/Implementations/System.Configuration/StandardColumnConfig.cs
+++ b/src/Serilog.Sinks.MSSqlServer/Configuration/Implementations/System.Configuration/StandardColumnConfig.cs
@@ -13,8 +13,8 @@ public StandardColumnConfig()
[ConfigurationProperty("Name", IsRequired = true, IsKey = true)]
public string Name
{
- get { return (string)this["Name"]; }
- set { this["Name"] = value; }
+ get { return (string)this[nameof(Name)]; }
+ set { this[nameof(Name)] = value; }
}
}
}
diff --git a/src/Serilog.Sinks.MSSqlServer/Configuration/Implementations/System.Configuration/StandardColumnConfigLevel.cs b/src/Serilog.Sinks.MSSqlServer/Configuration/Implementations/System.Configuration/StandardColumnConfigLevel.cs
index 779bc389..9ec25199 100644
--- a/src/Serilog.Sinks.MSSqlServer/Configuration/Implementations/System.Configuration/StandardColumnConfigLevel.cs
+++ b/src/Serilog.Sinks.MSSqlServer/Configuration/Implementations/System.Configuration/StandardColumnConfigLevel.cs
@@ -21,10 +21,10 @@ public override string ColumnName
[ConfigurationProperty("StoreAsEnum")]
public string StoreAsEnum
{
- get => (string)base["StoreAsEnum"];
+ get => (string)base[nameof(StoreAsEnum)];
set
{
- base["StoreAsEnum"] = value;
+ base[nameof(StoreAsEnum)] = value;
}
}
diff --git a/src/Serilog.Sinks.MSSqlServer/Configuration/Implementations/System.Configuration/StandardColumnConfigLogEvent.cs b/src/Serilog.Sinks.MSSqlServer/Configuration/Implementations/System.Configuration/StandardColumnConfigLogEvent.cs
index 463e8baf..6ed363fe 100644
--- a/src/Serilog.Sinks.MSSqlServer/Configuration/Implementations/System.Configuration/StandardColumnConfigLogEvent.cs
+++ b/src/Serilog.Sinks.MSSqlServer/Configuration/Implementations/System.Configuration/StandardColumnConfigLogEvent.cs
@@ -21,20 +21,20 @@ public override string ColumnName
[ConfigurationProperty("ExcludeAdditionalProperties")]
public string ExcludeAdditionalProperties
{
- get => (string)base["ExcludeAdditionalProperties"];
+ get => (string)base[nameof(ExcludeAdditionalProperties)];
set
{
- base["ExcludeAdditionalProperties"] = value;
+ base[nameof(ExcludeAdditionalProperties)] = value;
}
}
[ConfigurationProperty("ExcludeStandardColumns")]
public string ExcludeStandardColumns
{
- get => (string)base["ExcludeStandardColumns"];
+ get => (string)base[nameof(ExcludeStandardColumns)];
set
{
- base["ExcludeStandardColumns"] = value;
+ base[nameof(ExcludeStandardColumns)] = value;
}
}
}
diff --git a/src/Serilog.Sinks.MSSqlServer/Configuration/Implementations/System.Configuration/StandardColumnConfigProperties.cs b/src/Serilog.Sinks.MSSqlServer/Configuration/Implementations/System.Configuration/StandardColumnConfigProperties.cs
index 0f279f33..08506f60 100644
--- a/src/Serilog.Sinks.MSSqlServer/Configuration/Implementations/System.Configuration/StandardColumnConfigProperties.cs
+++ b/src/Serilog.Sinks.MSSqlServer/Configuration/Implementations/System.Configuration/StandardColumnConfigProperties.cs
@@ -21,120 +21,120 @@ public override string ColumnName
[ConfigurationProperty("ExcludeAdditionalProperties")]
public string ExcludeAdditionalProperties
{
- get => (string)base["ExcludeAdditionalProperties"];
+ get => (string)base[nameof(ExcludeAdditionalProperties)];
set
{
- base["ExcludeAdditionalProperties"] = value;
+ base[nameof(ExcludeAdditionalProperties)] = value;
}
}
[ConfigurationProperty("DictionaryElementName")]
public string DictionaryElementName
{
- get => (string)base["DictionaryElementName"];
+ get => (string)base[nameof(DictionaryElementName)];
set
{
- base["DictionaryElementName"] = value;
+ base[nameof(DictionaryElementName)] = value;
}
}
[ConfigurationProperty("ItemElementName")]
public string ItemElementName
{
- get => (string)base["ItemElementName"];
+ get => (string)base[nameof(ItemElementName)];
set
{
- base["ItemElementName"] = value;
+ base[nameof(ItemElementName)] = value;
}
}
[ConfigurationProperty("OmitDictionaryContainerElement")]
public string OmitDictionaryContainerElement
{
- get => (string)base["OmitDictionaryContainerElement"];
+ get => (string)base[nameof(OmitDictionaryContainerElement)];
set
{
- base["OmitDictionaryContainerElement"] = value;
+ base[nameof(OmitDictionaryContainerElement)] = value;
}
}
[ConfigurationProperty("OmitSequenceContainerElement")]
public string OmitSequenceContainerElement
{
- get => (string)base["OmitSequenceContainerElement"];
+ get => (string)base[nameof(OmitSequenceContainerElement)];
set
{
- base["OmitSequenceContainerElement"] = value;
+ base[nameof(OmitSequenceContainerElement)] = value;
}
}
[ConfigurationProperty("OmitStructureContainerElement")]
public string OmitStructureContainerElement
{
- get => (string)base["OmitStructureContainerElement"];
+ get => (string)base[nameof(OmitStructureContainerElement)];
set
{
- base["OmitStructureContainerElement"] = value;
+ base[nameof(OmitStructureContainerElement)] = value;
}
}
[ConfigurationProperty("OmitElementIfEmpty")]
public string OmitElementIfEmpty
{
- get => (string)base["OmitElementIfEmpty"];
+ get => (string)base[nameof(OmitElementIfEmpty)];
set
{
- base["OmitElementIfEmpty"] = value;
+ base[nameof(OmitElementIfEmpty)] = value;
}
}
[ConfigurationProperty("PropertyElementName")]
public string PropertyElementName
{
- get => (string)base["PropertyElementName"];
+ get => (string)base[nameof(PropertyElementName)];
set
{
- base["PropertyElementName"] = value;
+ base[nameof(PropertyElementName)] = value;
}
}
[ConfigurationProperty("RootElementName")]
public string RootElementName
{
- get => (string)base["RootElementName"];
+ get => (string)base[nameof(RootElementName)];
set
{
- base["RootElementName"] = value;
+ base[nameof(RootElementName)] = value;
}
}
[ConfigurationProperty("SequenceElementName")]
public string SequenceElementName
{
- get => (string)base["SequenceElementName"];
+ get => (string)base[nameof(SequenceElementName)];
set
{
- base["SequenceElementName"] = value;
+ base[nameof(SequenceElementName)] = value;
}
}
[ConfigurationProperty("StructureElementName")]
public string StructureElementName
{
- get => (string)base["StructureElementName"];
+ get => (string)base[nameof(StructureElementName)];
set
{
- base["StructureElementName"] = value;
+ base[nameof(StructureElementName)] = value;
}
}
[ConfigurationProperty("UsePropertyKeyAsElementName")]
public string UsePropertyKeyAsElementName
{
- get => (string)base["UsePropertyKeyAsElementName"];
+ get => (string)base[nameof(UsePropertyKeyAsElementName)];
set
{
- base["UsePropertyKeyAsElementName"] = value;
+ base[nameof(UsePropertyKeyAsElementName)] = value;
}
}
diff --git a/src/Serilog.Sinks.MSSqlServer/Configuration/Implementations/System.Configuration/StandardColumnConfigTimeStamp.cs b/src/Serilog.Sinks.MSSqlServer/Configuration/Implementations/System.Configuration/StandardColumnConfigTimeStamp.cs
index 4747c915..cf0b73a3 100644
--- a/src/Serilog.Sinks.MSSqlServer/Configuration/Implementations/System.Configuration/StandardColumnConfigTimeStamp.cs
+++ b/src/Serilog.Sinks.MSSqlServer/Configuration/Implementations/System.Configuration/StandardColumnConfigTimeStamp.cs
@@ -21,10 +21,10 @@ public override string ColumnName
[ConfigurationProperty("ConvertToUtc")]
public string ConvertToUtc
{
- get => (string)base["ConvertToUtc"];
+ get => (string)base[nameof(ConvertToUtc)];
set
{
- base["ConvertToUtc"] = value;
+ base[nameof(ConvertToUtc)] = value;
}
}
diff --git a/src/Serilog.Sinks.MSSqlServer/GlobalSuppressions.cs b/src/Serilog.Sinks.MSSqlServer/GlobalSuppressions.cs
new file mode 100644
index 00000000..9f84e517
--- /dev/null
+++ b/src/Serilog.Sinks.MSSqlServer/GlobalSuppressions.cs
@@ -0,0 +1,59 @@
+// This file is used by Code Analysis to maintain SuppressMessage
+// attributes that are applied to this project.
+// Project-level suppressions either have no target or are given
+// a specific target and scoped to a namespace, type, member, etc.
+
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Major Code Smell", "S2589:Boolean expressions should not be gratuitous", Justification = "", Scope = "member", Target = "~M:Serilog.Sinks.MSSqlServer.MSSqlServerAuditSink.#ctor(System.String,System.String,System.IFormatProvider,System.Boolean,Serilog.Sinks.MSSqlServer.ColumnOptions,System.String)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1062:Validate arguments of public methods", Justification = "", Scope = "member", Target = "~M:Serilog.Sinks.MSSqlServer.MSSqlServerAuditSink.Emit(Serilog.Events.LogEvent)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Security", "CA2100:Review SQL queries for security vulnerabilities", Justification = "", Scope = "member", Target = "~M:Serilog.Sinks.MSSqlServer.MSSqlServerAuditSink.Emit(Serilog.Events.LogEvent)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "", Scope = "member", Target = "~M:Serilog.Sinks.MSSqlServer.SetProperty.IfNotNull``1(System.String,Serilog.Sinks.MSSqlServer.SetProperty.PropertySetter{``0})")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1062:Validate arguments of public methods", Justification = "", Scope = "member", Target = "~M:Serilog.Sinks.MSSqlServer.SetProperty.IfNotNull``1(System.String,Serilog.Sinks.MSSqlServer.SetProperty.PropertySetter{``0})")]
+
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1034:Nested types should not be visible", Justification = "", Scope = "type", Target = "~T:Serilog.Sinks.MSSqlServer.ColumnOptions.ExceptionColumnOptions")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1034:Nested types should not be visible", Justification = "", Scope = "type", Target = "~T:Serilog.Sinks.MSSqlServer.ColumnOptions.IdColumnOptions")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1034:Nested types should not be visible", Justification = "", Scope = "type", Target = "~T:Serilog.Sinks.MSSqlServer.ColumnOptions.LevelColumnOptions")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1034:Nested types should not be visible", Justification = "", Scope = "type", Target = "~T:Serilog.Sinks.MSSqlServer.ColumnOptions.LogEventColumnOptions")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1034:Nested types should not be visible", Justification = "", Scope = "type", Target = "~T:Serilog.Sinks.MSSqlServer.ColumnOptions.MessageColumnOptions")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1034:Nested types should not be visible", Justification = "", Scope = "type", Target = "~T:Serilog.Sinks.MSSqlServer.ColumnOptions.MessageTemplateColumnOptions")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1034:Nested types should not be visible", Justification = "", Scope = "type", Target = "~T:Serilog.Sinks.MSSqlServer.ColumnOptions.PropertiesColumnOptions")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1034:Nested types should not be visible", Justification = "", Scope = "type", Target = "~T:Serilog.Sinks.MSSqlServer.ColumnOptions.TimeStampColumnOptions")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "", Scope = "member", Target = "~M:Serilog.Sinks.MSSqlServer.JsonLogEventFormatter.Format(Serilog.Events.LogEvent,System.IO.TextWriter)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "", Scope = "member", Target = "~M:Serilog.Sinks.MSSqlServer.MSSqlServerSink.EmitBatchAsync(System.Collections.Generic.IEnumerable{Serilog.Events.LogEvent})~System.Threading.Tasks.Task")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "", Scope = "member", Target = "~M:Serilog.Sinks.MSSqlServer.MSSqlServerSinkTraits.ConvertPropertiesToXmlStructure(System.Collections.Generic.IEnumerable{System.Collections.Generic.KeyValuePair{System.String,Serilog.Events.LogEventPropertyValue}})~System.String")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "", Scope = "member", Target = "~M:Serilog.Sinks.MSSqlServer.MSSqlServerSinkTraits.TryChangeType(System.Object,System.Type,System.Object@)~System.Boolean")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "", Scope = "member", Target = "~M:Serilog.Sinks.MSSqlServer.SqlTableCreator.GetColumnDDL(Serilog.Sinks.MSSqlServer.SqlColumn)~System.String")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "", Scope = "member", Target = "~M:Serilog.Sinks.MSSqlServer.XmlPropertyFormatter.Simplify(Serilog.Events.LogEventPropertyValue,Serilog.Sinks.MSSqlServer.ColumnOptions.PropertiesColumnOptions)~System.String")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "", Scope = "member", Target = "~M:Serilog.Sinks.MSSqlServer.XmlPropertyFormatter.SimplifyScalar(System.Object)~System.String")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Minor Vulnerability", "S1104:Fields should not have public accessibility", Justification = "", Scope = "member", Target = "~F:Serilog.Sinks.MSSqlServer.SqlDataTypes.NotSupported")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1062:Validate arguments of public methods", Justification = "", Scope = "member", Target = "~M:Serilog.LoggerConfigurationMSSqlServerExtensions.MSSqlServer(Serilog.Configuration.LoggerSinkConfiguration,System.String,System.String,Microsoft.Extensions.Configuration.IConfiguration,Serilog.Events.LogEventLevel,System.Int32,System.Nullable{System.TimeSpan},System.IFormatProvider,System.Boolean,Serilog.Sinks.MSSqlServer.ColumnOptions,Microsoft.Extensions.Configuration.IConfigurationSection,System.String)~Serilog.LoggerConfiguration")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1062:Validate arguments of public methods", Justification = "", Scope = "member", Target = "~M:Serilog.Sinks.MSSqlServer.MSSqlServerSink.#ctor(System.String,System.String,System.Int32,System.TimeSpan,System.IFormatProvider,System.Boolean,Serilog.Sinks.MSSqlServer.ColumnOptions,System.String)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1062:Validate arguments of public methods", Justification = "", Scope = "member", Target = "~M:Serilog.Sinks.MSSqlServer.MSSqlServerSink.EmitBatchAsync(System.Collections.Generic.IEnumerable{Serilog.Events.LogEvent})~System.Threading.Tasks.Task")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1062:Validate arguments of public methods", Justification = "", Scope = "member", Target = "~M:Serilog.Sinks.MSSqlServer.SqlColumn.#ctor(System.Data.DataColumn)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1062:Validate arguments of public methods", Justification = "", Scope = "member", Target = "~M:Serilog.Sinks.MSSqlServer.XmlPropertyFormatter.Simplify(Serilog.Events.LogEventPropertyValue,Serilog.Sinks.MSSqlServer.ColumnOptions.PropertiesColumnOptions)~System.String")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:Serilog.Sinks.MSSqlServer.MSSqlServerSink.EmitBatchAsync(System.Collections.Generic.IEnumerable{Serilog.Events.LogEvent})~System.Threading.Tasks.Task")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:Serilog.Sinks.MSSqlServer.MSSqlServerSinkTraits.#ctor(System.String,System.String,System.String,Serilog.Sinks.MSSqlServer.ColumnOptions,System.IFormatProvider,System.Boolean)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:Serilog.Sinks.MSSqlServer.MSSqlServerSinkTraits.ConvertPropertiesToXmlStructure(System.Collections.Generic.IEnumerable{System.Collections.Generic.KeyValuePair{System.String,Serilog.Events.LogEventPropertyValue}})~System.String")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "", Scope = "member", Target = "~M:Serilog.Sinks.MSSqlServer.MSSqlServerSinkTraits.TryChangeType(System.Object,System.Type,System.Object@)~System.Boolean")]
+
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1308:Normalize strings to uppercase", Justification = "", Scope = "member", Target = "~M:Serilog.Sinks.MSSqlServer.SqlColumn.AsDataColumn~System.Data.DataColumn")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Minor Code Smell", "S1125:Boolean literals should not be redundant", Justification = "", Scope = "member", Target = "~M:Serilog.Sinks.MSSqlServer.ColumnOptions.FinalizeConfigurationForSinkConstructor")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Minor Code Smell", "S1125:Boolean literals should not be redundant", Justification = "", Scope = "member", Target = "~M:Serilog.Sinks.MSSqlServer.JsonLogEventFormatter.Format(Serilog.Events.LogEvent,System.IO.TextWriter)")]
+
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Info Code Smell", "S1135:Track uses of \"TODO\" tags", Justification = "", Scope = "member", Target = "~M:Serilog.Sinks.MSSqlServer.ApplyMicrosoftExtensionsConfiguration.ConfigureColumnOptions(Serilog.Sinks.MSSqlServer.ColumnOptions,Microsoft.Extensions.Configuration.IConfigurationSection)~Serilog.Sinks.MSSqlServer.ColumnOptions")]
+
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1062:Validate arguments of public methods", Justification = "", Scope = "member", Target = "~M:Serilog.LoggerConfigurationMSSqlServerExtensions.MSSqlServer(Serilog.Configuration.LoggerAuditSinkConfiguration,System.String,System.String,Microsoft.Extensions.Configuration.IConfiguration,Serilog.Events.LogEventLevel,System.IFormatProvider,System.Boolean,Serilog.Sinks.MSSqlServer.ColumnOptions,Microsoft.Extensions.Configuration.IConfigurationSection,System.String)~Serilog.LoggerConfiguration")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1062:Validate arguments of public methods", Justification = "", Scope = "member", Target = "~M:Serilog.Sinks.MSSqlServer.ColumnCollection.GetElementKey(System.Configuration.ConfigurationElement)~System.Object")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1062:Validate arguments of public methods", Justification = "", Scope = "member", Target = "~M:Serilog.Sinks.MSSqlServer.SetProperty.IfProvided``1(System.Configuration.ConfigurationElement,System.String,Serilog.Sinks.MSSqlServer.SetProperty.PropertySetter{``0})")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1062:Validate arguments of public methods", Justification = "", Scope = "member", Target = "~M:Serilog.Sinks.MSSqlServer.SetProperty.IfProvidedNotEmpty``1(System.Configuration.ConfigurationElement,System.String,Serilog.Sinks.MSSqlServer.SetProperty.PropertySetter{``0})")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1062:Validate arguments of public methods", Justification = "", Scope = "member", Target = "~M:Serilog.Sinks.MSSqlServer.StandardColumnCollection.GetElementKey(System.Configuration.ConfigurationElement)~System.Object")]
+
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1010:Collections should implement generic interface", Justification = "", Scope = "type", Target = "~T:Serilog.Sinks.MSSqlServer.ColumnCollection")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1010:Collections should implement generic interface", Justification = "", Scope = "type", Target = "~T:Serilog.Sinks.MSSqlServer.StandardColumnCollection")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Minor Vulnerability", "S1104:Fields should not have public accessibility", Justification = "", Scope = "member", Target = "~F:Serilog.LoggerConfigurationMSSqlServerExtensions.AppConfigSectionName")]
+
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Reliability", "CA2000:Dispose objects before losing scope", Justification = "", Scope = "member", Target = "~M:Serilog.LoggerConfigurationMSSqlServerExtensions.MSSqlServer(Serilog.Configuration.LoggerAuditSinkConfiguration,System.String,System.String,Microsoft.Extensions.Configuration.IConfiguration,Serilog.Events.LogEventLevel,System.IFormatProvider,System.Boolean,Serilog.Sinks.MSSqlServer.ColumnOptions,Microsoft.Extensions.Configuration.IConfigurationSection,System.String)~Serilog.LoggerConfiguration")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Reliability", "CA2000:Dispose objects before losing scope", Justification = "", Scope = "member", Target = "~M:Serilog.LoggerConfigurationMSSqlServerExtensions.MSSqlServer(Serilog.Configuration.LoggerSinkConfiguration,System.String,System.String,Microsoft.Extensions.Configuration.IConfiguration,Serilog.Events.LogEventLevel,System.Int32,System.Nullable{System.TimeSpan},System.IFormatProvider,System.Boolean,Serilog.Sinks.MSSqlServer.ColumnOptions,Microsoft.Extensions.Configuration.IConfigurationSection,System.String)~Serilog.LoggerConfiguration")]
+
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1307:Specify StringComparison", Justification = "", Scope = "member", Target = "~M:Serilog.Sinks.MSSqlServer.ApplyMicrosoftExtensionsConfiguration.GetConnectionString(System.String,Microsoft.Extensions.Configuration.IConfiguration)~System.String")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1307:Specify StringComparison", Justification = "", Scope = "member", Target = "~M:Serilog.Sinks.MSSqlServer.ApplySystemConfiguration.GetConnectionString(System.String)~System.String")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Security", "CA2100:Review SQL queries for security vulnerabilities", Justification = "", Scope = "member", Target = "~M:Serilog.Sinks.MSSqlServer.SqlTableCreator.CreateTable~System.Int32")]
\ No newline at end of file
diff --git a/src/Serilog.Sinks.MSSqlServer/Serilog.Sinks.MSSqlServer.csproj b/src/Serilog.Sinks.MSSqlServer/Serilog.Sinks.MSSqlServer.csproj
index 230e71b0..f9689e1b 100644
--- a/src/Serilog.Sinks.MSSqlServer/Serilog.Sinks.MSSqlServer.csproj
+++ b/src/Serilog.Sinks.MSSqlServer/Serilog.Sinks.MSSqlServer.csproj
@@ -4,7 +4,7 @@
A Serilog sink that writes events to Microsoft SQL Server
5.1.3
Michiel van Oudheusden;Serilog Contributors
- netstandard2.0;net452;netcoreapp2.0;net461
+ netstandard2.0;netcoreapp2.0;net461
true
true
Serilog.Sinks.MSSqlServer
@@ -22,12 +22,16 @@
false
false
false
+ true
+ false
+ false
+
-
-
-
+
+
+
@@ -45,34 +49,23 @@
-
+
-
-
-
+
+
+
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/ColumnOptions/FinalizeConfigurationForSinkConstructor.cs b/src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/ColumnOptions/FinalizeConfigurationForSinkConstructor.cs
index d290162d..1f2f428c 100644
--- a/src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/ColumnOptions/FinalizeConfigurationForSinkConstructor.cs
+++ b/src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/ColumnOptions/FinalizeConfigurationForSinkConstructor.cs
@@ -75,7 +75,7 @@ internal void FinalizeConfigurationForSinkConstructor()
configurationFinalized = true;
}
- private void ColumnstoreCompatibilityCheck(SqlColumn column)
+ private static void ColumnstoreCompatibilityCheck(SqlColumn column)
{
if (!SqlDataTypes.ColumnstoreCompatible.Contains(column.DataType))
throw new ArgumentException($"Columnstore indexes do not support data type \"{column.DataType.ToString()}\" declared for column \"{column.ColumnName}\".");
diff --git a/src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/ColumnOptions/IdColumnOptions.cs b/src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/ColumnOptions/IdColumnOptions.cs
index 0dd2cf6c..4118a478 100644
--- a/src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/ColumnOptions/IdColumnOptions.cs
+++ b/src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/ColumnOptions/IdColumnOptions.cs
@@ -38,7 +38,7 @@ public IdColumnOptions() : base()
///
/// The Id column must never allow null values (it is an auto-incremnting identity value and normally the primary key).
///
- public new bool AllowNull // shadow base class with "new" to prevent accidentally setting this to true
+ public new static bool AllowNull // shadow base class with "new" to prevent accidentally setting this to true
{
get => false;
set
diff --git a/src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/JsonLogEventFormatter.cs b/src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/JsonLogEventFormatter.cs
index ba427d11..6b53a655 100644
--- a/src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/JsonLogEventFormatter.cs
+++ b/src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/JsonLogEventFormatter.cs
@@ -31,7 +31,7 @@ internal class JsonLogEventFormatter : ITextFormatter
static readonly JsonValueFormatter ValueFormatter = new JsonValueFormatter(typeTagName: null);
private const string COMMA_DELIMITER = ",";
- MSSqlServerSinkTraits traits;
+ readonly MSSqlServerSinkTraits traits;
///
/// Constructor. A reference to the parent Traits object is used so that JSON
@@ -142,25 +142,28 @@ static void WriteRenderings(IEnumerable> tokens
output.Write(":[");
var fdelim = "";
- foreach (var format in ptoken)
+ var sw = new StringWriter();
+ using (sw)
{
- output.Write(fdelim);
- fdelim = COMMA_DELIMITER;
+ foreach (var format in ptoken)
+ {
+ output.Write(fdelim);
+ fdelim = COMMA_DELIMITER;
+
+ output.Write("{\"Format\":");
+ JsonValueFormatter.WriteQuotedJsonString(format.Format, output);
- output.Write("{\"Format\":");
- JsonValueFormatter.WriteQuotedJsonString(format.Format, output);
+ output.Write(",\"Rendering\":");
+ format.Render(properties, sw);
+ JsonValueFormatter.WriteQuotedJsonString(sw.ToString(), output);
+ output.Write('}');
+ }
- output.Write(",\"Rendering\":");
- var sw = new StringWriter();
- format.Render(properties, sw);
- JsonValueFormatter.WriteQuotedJsonString(sw.ToString(), output);
- output.Write('}');
+ output.Write(']');
}
- output.Write(']');
+ output.Write('}');
}
-
- output.Write('}');
}
}
}
diff --git a/src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/MSSqlServerAuditSink.cs b/src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/MSSqlServerAuditSink.cs
index 19669782..7fddadca 100644
--- a/src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/MSSqlServerAuditSink.cs
+++ b/src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/MSSqlServerAuditSink.cs
@@ -18,8 +18,8 @@
using System;
using System.Data;
using System.Data.SqlClient;
-using System.Linq;
using System.Text;
+using Microsoft.Azure.Services.AppAuthentication;
namespace Serilog.Sinks.MSSqlServer
{
@@ -40,25 +40,32 @@ public class MSSqlServerAuditSink : ILogEventSink, IDisposable
/// Supplies culture-specific formatting information, or null.
/// Create log table with the provided name on destination sql server.
/// Options that pertain to columns
+ /// Option to use MSI
+ /// Resource required in AzureServiceTokenProvider.GetAccessTokenAsync(azureServiceTokenProviderResource). This will error if null, and useMsi is st to true
public MSSqlServerAuditSink(
string connectionString,
string tableName,
IFormatProvider formatProvider,
bool autoCreateSqlTable = false,
ColumnOptions columnOptions = null,
- string schemaName = "dbo"
- )
+ string schemaName = "dbo",
+ bool useMsi = false,
+ string azureServiceTokenProviderResource = null)
{
columnOptions.FinalizeConfigurationForSinkConstructor();
+#pragma warning disable S2589 // Boolean expressions should not be gratuitous
if (columnOptions != null)
+#pragma warning restore S2589 // Boolean expressions should not be gratuitous
{
+#pragma warning disable S1066 // Collapsible "if" statements should be merged
if (columnOptions.DisableTriggers)
+#pragma warning restore S1066 // Collapsible "if" statements should be merged
throw new NotSupportedException($"The {nameof(ColumnOptions.DisableTriggers)} option is not supported for auditing.");
}
- _traits = new MSSqlServerSinkTraits(connectionString, tableName, schemaName, columnOptions, formatProvider, autoCreateSqlTable);
-
+ _traits = new MSSqlServerSinkTraits(connectionString, tableName, schemaName, columnOptions, formatProvider, autoCreateSqlTable, useMsi, azureServiceTokenProviderResource);
+
}
/// Emit the provided log event to the sink.
@@ -67,10 +74,16 @@ public void Emit(LogEvent logEvent)
{
try
{
- using (SqlConnection connection = new SqlConnection(_traits.connectionString))
+ using (var cn = new SqlConnection(_traits.connectionString))
{
- connection.Open();
- using (SqlCommand command = connection.CreateCommand())
+ if (_traits.useMsi)
+ {
+ cn.AccessToken = new AzureServiceTokenProvider()
+ .GetAccessTokenAsync(_traits.azureServiceTokenProviderResource).Result;
+ }
+
+ cn.Open();
+ using (SqlCommand command = cn.CreateCommand())
{
command.CommandType = CommandType.Text;
@@ -90,7 +103,7 @@ public void Emit(LogEvent logEvent)
parameterList.Append("@P");
parameterList.Append(index);
- SqlParameter parameter = new SqlParameter($"@P{index}", field.Value ?? DBNull.Value);
+ SqlParameter parameter = new SqlParameter($"@P{index}", field.Value ?? DBNull.Value);
// The default is SqlDbType.DateTime, which will truncate the DateTime value if the actual
// type in the database table is datetime2. So we explicitly set it to DateTime2, which will
@@ -117,7 +130,7 @@ public void Emit(LogEvent logEvent)
{
SelfLog.WriteLine("Unable to write log event to the database due to following error: {1}", ex.Message);
throw;
- }
+ }
}
///
diff --git a/src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/MSSqlServerSink.cs b/src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/MSSqlServerSink.cs
index 928864eb..57857e67 100644
--- a/src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/MSSqlServerSink.cs
+++ b/src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/MSSqlServerSink.cs
@@ -14,11 +14,11 @@
using System;
using System.Collections.Generic;
-using System.Collections.ObjectModel;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Threading.Tasks;
+using Microsoft.Azure.Services.AppAuthentication;
using Serilog.Debugging;
using Serilog.Events;
using Serilog.Sinks.PeriodicBatching;
@@ -43,6 +43,8 @@ public class MSSqlServerSink : PeriodicBatchingSink
private readonly MSSqlServerSinkTraits _traits;
+
+
///
/// Construct a sink posting to the specified database.
///
@@ -54,6 +56,8 @@ public class MSSqlServerSink : PeriodicBatchingSink
/// Supplies culture-specific formatting information, or null.
/// Create log table with the provided name on destination sql server.
/// Options that pertain to columns
+ /// Option to use MSI
+ /// Resource required in AzureServiceTokenProvider.GetAccessTokenAsync(azureServiceTokenProviderResource). This will error if null, and useMsi is st to true
public MSSqlServerSink(
string connectionString,
string tableName,
@@ -62,12 +66,13 @@ public MSSqlServerSink(
IFormatProvider formatProvider,
bool autoCreateSqlTable = false,
ColumnOptions columnOptions = null,
- string schemaName = "dbo"
- )
+ string schemaName = "dbo",
+ bool useMsi = false,
+ string azureServiceTokenProviderResource = null)
: base(batchPostingLimit, period)
{
columnOptions.FinalizeConfigurationForSinkConstructor();
- _traits = new MSSqlServerSinkTraits(connectionString, tableName, schemaName, columnOptions, formatProvider, autoCreateSqlTable);
+ _traits = new MSSqlServerSinkTraits(connectionString, tableName, schemaName, columnOptions, formatProvider, autoCreateSqlTable, useMsi, azureServiceTokenProviderResource);
}
///
@@ -88,6 +93,11 @@ protected override async Task EmitBatchAsync(IEnumerable events)
{
using (var cn = new SqlConnection(_traits.connectionString))
{
+ if (_traits.useMsi)
+ {
+ cn.AccessToken = new AzureServiceTokenProvider()
+ .GetAccessTokenAsync(_traits.azureServiceTokenProviderResource).Result;
+ }
await cn.OpenAsync().ConfigureAwait(false);
using (var copy = _traits.columnOptions.DisableTriggers
? new SqlBulkCopy(cn)
diff --git a/src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/MSSqlServerSinkTraits.cs b/src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/MSSqlServerSinkTraits.cs
index 71648933..73141433 100644
--- a/src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/MSSqlServerSinkTraits.cs
+++ b/src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/MSSqlServerSinkTraits.cs
@@ -17,7 +17,6 @@
using System;
using System.Collections.Generic;
using System.Data;
-using System.IO;
using System.Linq;
using System.Text;
@@ -27,6 +26,8 @@ namespace Serilog.Sinks.MSSqlServer
/// Contains common functionality and properties used by both MSSqlServerSinks.
internal sealed class MSSqlServerSinkTraits : IDisposable
{
+ public bool useMsi { get; } = false;
+ public string azureServiceTokenProviderResource { get; } = null;
public string connectionString { get; }
public string tableName { get; }
public string schemaName { get; }
@@ -37,14 +38,19 @@ internal sealed class MSSqlServerSinkTraits : IDisposable
public DataTable eventTable { get; }
public ISet standardColumnNames { get; }
- public MSSqlServerSinkTraits(string connectionString, string tableName, string schemaName, ColumnOptions columnOptions, IFormatProvider formatProvider, bool autoCreateSqlTable)
+ public MSSqlServerSinkTraits(string connectionString, string tableName, string schemaName, ColumnOptions columnOptions, IFormatProvider formatProvider, bool autoCreateSqlTable, bool useMsi = false, string azureServiceTokenProviderResource = null)
{
+ if (useMsi && string.IsNullOrWhiteSpace(azureServiceTokenProviderResource))
+ throw new ArgumentNullException(nameof(azureServiceTokenProviderResource), "If useMsi is set to true, you must also provide an azureServiceTokenProviderResource");
+
if (string.IsNullOrWhiteSpace(connectionString))
throw new ArgumentNullException(nameof(connectionString));
if (string.IsNullOrWhiteSpace(tableName))
throw new ArgumentNullException(nameof(tableName));
+ this.useMsi = useMsi;
+ this.azureServiceTokenProviderResource = azureServiceTokenProviderResource;
this.connectionString = connectionString;
this.tableName = tableName;
this.schemaName = schemaName;
@@ -93,7 +99,7 @@ public IEnumerable> GetColumnsAndValues(LogEvent lo
foreach (var column in columnOptions.Store)
{
// skip Id (auto-incrementing identity)
- if(column != StandardColumn.Id)
+ if (column != StandardColumn.Id)
yield return GetStandardColumnNameAndValue(column, logEvent);
}
@@ -128,7 +134,9 @@ internal KeyValuePair GetStandardColumnNameAndValue(StandardColu
case StandardColumn.LogEvent:
return new KeyValuePair(columnOptions.LogEvent.ColumnName, LogEventToJson(logEvent));
default:
- throw new ArgumentOutOfRangeException();
+#pragma warning disable S3928 // Parameter names used into ArgumentException constructors should match an existing one
+ throw new ArgumentOutOfRangeException($"{nameof(column)} is an invalid case.");
+#pragma warning restore S3928 // Parameter names used into ArgumentException constructors should match an existing one
}
}
@@ -260,13 +268,13 @@ private DataTable CreateDataTable()
var standardOpts = columnOptions.GetStandardColumnOptions(standardColumn);
var dataColumn = standardOpts.AsDataColumn();
eventsTable.Columns.Add(dataColumn);
- if(standardOpts == columnOptions.PrimaryKey)
+ if (standardOpts == columnOptions.PrimaryKey)
eventsTable.PrimaryKey = new DataColumn[] { dataColumn };
}
if (columnOptions.AdditionalColumns != null)
{
- foreach(var addCol in columnOptions.AdditionalColumns)
+ foreach (var addCol in columnOptions.AdditionalColumns)
{
var dataColumn = addCol.AsDataColumn();
eventsTable.Columns.Add(dataColumn);
diff --git a/src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/SqlColumn.cs b/src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/SqlColumn.cs
index 935cb9b3..1f88c81d 100644
--- a/src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/SqlColumn.cs
+++ b/src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/SqlColumn.cs
@@ -95,10 +95,13 @@ public SqlDbType DataType
///
public bool NonClusteredIndex { get; set; } = false;
- // Set by the constructors of the Standard Column classes that inherit from this;
- // allows Standard Columns and user-defined columns to coexist but remain identifiable
- // and allows casting back to the Standard Column without a lot of switch gymnastics.
+
+#pragma warning disable S125 // Sections of code should not be commented out
+ // Set by the constructors of the Standard Column classes that inherit from this;
+ // allows Standard Columns and user-defined columns to coexist but remain identifiable
+ // and allows casting back to the Standard Column without a lot of switch gymnastics.
internal StandardColumn? StandardColumnIdentifier { get; set; } = null;
+#pragma warning restore S125 // Sections of code should not be commented out
internal Type StandardColumnType { get; set; } = null;
///
diff --git a/src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/SqlDataTypes.cs b/src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/SqlDataTypes.cs
index 223b5756..71c12257 100644
--- a/src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/SqlDataTypes.cs
+++ b/src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/SqlDataTypes.cs
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Data;
-using System.Data.SqlTypes;
namespace Serilog.Sinks.MSSqlServer
{
@@ -10,11 +9,15 @@ namespace Serilog.Sinks.MSSqlServer
///
public static class SqlDataTypes
{
+#pragma warning disable S2223 // Non-constant static fields should not be visible
+#pragma warning disable CA2211 // Non-constant fields should not be visible
///
/// SqlDbType doesn't have anything like "None" so we indicate an unsupported type by
/// referencing a type we can guarantee the rest of the sink will never recognize.
///
public static SqlDbType NotSupported = SqlDbType.Variant;
+#pragma warning restore CA2211 // Non-constant fields should not be visible
+#pragma warning restore S2223 // Non-constant static fields should not be visible
///
/// A collection keyed on the SqlDbType enum with values representing the equivalent DataColumn .NET type.
diff --git a/src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/SqlTableCreator.cs b/src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/SqlTableCreator.cs
index 1601850d..30d7530b 100644
--- a/src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/SqlTableCreator.cs
+++ b/src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/SqlTableCreator.cs
@@ -2,30 +2,40 @@
using System.Data;
using System.Data.SqlClient;
using System.Text;
+using Microsoft.Azure.Services.AppAuthentication;
namespace Serilog.Sinks.MSSqlServer
{
internal class SqlTableCreator
{
private readonly string connectionString;
- private string tableName;
- private string schemaName;
- private DataTable dataTable;
- private ColumnOptions columnOptions;
-
- public SqlTableCreator(string connectionString, string schemaName, string tableName, DataTable dataTable, ColumnOptions columnOptions)
+ private readonly string tableName;
+ private readonly string schemaName;
+ private readonly DataTable dataTable;
+ private readonly ColumnOptions columnOptions;
+ private readonly bool useMsi;
+ private readonly string azureServiceTokenProviderResource;
+
+ public SqlTableCreator(string connectionString, string schemaName, string tableName, DataTable dataTable, ColumnOptions columnOptions, bool useMsi = false, string azureServiceTokenProviderResource = null)
{
this.connectionString = connectionString;
this.schemaName = schemaName;
this.tableName = tableName;
this.dataTable = dataTable;
this.columnOptions = columnOptions;
+ this.useMsi = useMsi;
+ this.azureServiceTokenProviderResource = azureServiceTokenProviderResource;
}
public int CreateTable()
{
- using (var conn = new SqlConnection(connectionString))
+ using (var conn = new SqlConnection(this.connectionString))
{
+ if (useMsi)
+ {
+ conn.AccessToken = new AzureServiceTokenProvider()
+ .GetAccessTokenAsync(azureServiceTokenProviderResource).Result;
+ }
string sql = GetSqlFromDataTable();
using (SqlCommand cmd = new SqlCommand(sql, conn))
{
@@ -94,7 +104,7 @@ private string GetSqlFromDataTable()
// Examples of possible output:
// [Id] BIGINT IDENTITY(1,1) NOT NULL
// [Message] VARCHAR(1024) NULL
- private string GetColumnDDL(SqlColumn column)
+ private static string GetColumnDDL(SqlColumn column)
{
var sb = new StringBuilder();
diff --git a/src/Serilog.Sinks.MSSqlServer/packages.config b/src/Serilog.Sinks.MSSqlServer/packages.config
index 4bb6d6db..569e1bea 100644
--- a/src/Serilog.Sinks.MSSqlServer/packages.config
+++ b/src/Serilog.Sinks.MSSqlServer/packages.config
@@ -1,5 +1,3 @@
-
-
diff --git a/test/Serilog.Sinks.MSSqlServer.Tests/App.config b/test/Serilog.Sinks.MSSqlServer.Tests/App.config
index 4fa31336..571ecf14 100644
--- a/test/Serilog.Sinks.MSSqlServer.Tests/App.config
+++ b/test/Serilog.Sinks.MSSqlServer.Tests/App.config
@@ -29,5 +29,9 @@
-
+
+
+
+
+
diff --git a/test/Serilog.Sinks.MSSqlServer.Tests/Configuration/Microsoft.Extensions.Configuration/ConfigurationExtensions.cs b/test/Serilog.Sinks.MSSqlServer.Tests/Configuration/Microsoft.Extensions.Configuration/ConfigurationExtensions.cs
index de702e49..381d9678 100644
--- a/test/Serilog.Sinks.MSSqlServer.Tests/Configuration/Microsoft.Extensions.Configuration/ConfigurationExtensions.cs
+++ b/test/Serilog.Sinks.MSSqlServer.Tests/Configuration/Microsoft.Extensions.Configuration/ConfigurationExtensions.cs
@@ -14,11 +14,15 @@ public class ConfigurationExtensions : IDisposable
{
static string ConnectionStringName = "NamedConnection";
static string ColumnOptionsSection = "CustomColumnNames";
+ static string DatabaseTokenProviderSection = "DatabaseTokenProviderSettings";
IConfiguration TestConfiguration() =>
new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary
{
+ { $"{DatabaseTokenProviderSection}:UseMsi", "true" },
+ { $"{DatabaseTokenProviderSection}:Resource", "https://database.windows.net/" },
+
{ $"ConnectionStrings:{ConnectionStringName}", DatabaseFixture.LogEventsConnectionString },
{ $"{ColumnOptionsSection}:message:columnName", "CustomMessage" },
@@ -30,6 +34,26 @@ IConfiguration TestConfiguration() =>
})
.Build();
+ [Fact]
+ public void AzureTokenProviderResourceByName()
+ {
+ var appConfig = TestConfiguration();
+
+ var loggerConfiguration = new LoggerConfiguration();
+ Log.Logger = loggerConfiguration.WriteTo.MSSqlServer(
+ connectionString: ConnectionStringName,
+ tableName: DatabaseFixture.LogTableName,
+ autoCreateSqlTable: true,
+ appConfiguration: appConfig,
+ useMsi: true,
+ azureServiceTokenProviderResource: "DatabaseTokenProviderSettings:Resource")
+ .CreateLogger();
+
+ // should not throw
+
+ Log.CloseAndFlush();
+ }
+
[Fact]
public void ConnectionStringByName()
{
diff --git a/test/Serilog.Sinks.MSSqlServer.Tests/Configuration/System.Configuration/ConfigurationExtensions.cs b/test/Serilog.Sinks.MSSqlServer.Tests/Configuration/System.Configuration/ConfigurationExtensions.cs
index 273c7b70..0036959f 100644
--- a/test/Serilog.Sinks.MSSqlServer.Tests/Configuration/System.Configuration/ConfigurationExtensions.cs
+++ b/test/Serilog.Sinks.MSSqlServer.Tests/Configuration/System.Configuration/ConfigurationExtensions.cs
@@ -1,10 +1,12 @@
-using System;
+using System.Collections.Generic;
+using System.Data.SqlClient;
+using System.Linq;
using Dapper;
using Xunit;
using FluentAssertions;
-using System.Collections.Generic;
-using System.Data.SqlClient;
-using System.Linq;
+using Microsoft.Extensions.Configuration;
+using System;
+
// Because System.Configuration is static and config is loaded automatically,
// the tests alter the static AppConfigSectionName string value exposed by the
@@ -18,6 +20,26 @@ namespace Serilog.Sinks.MSSqlServer.Tests
[Collection("LogTest")]
public class ConfigurationExtensions : IDisposable
{
+ [Fact]
+ public void AzureTokenProviderResourceByName()
+ {
+ string ConnectionStringName = "NamedConnection";
+ string DatabaseTokenProviderResourceName = "DatabaseTokenProviderResource";
+
+ var loggerConfiguration = new LoggerConfiguration();
+ Log.Logger = loggerConfiguration.WriteTo.MSSqlServer(
+ connectionString: ConnectionStringName,
+ tableName: DatabaseFixture.LogTableName,
+ autoCreateSqlTable: true,
+ useMsi: true,
+ azureServiceTokenProviderResource: DatabaseTokenProviderResourceName)
+ .CreateLogger();
+
+ // should not throw
+
+ Log.CloseAndFlush();
+ }
+
[Fact]
public void ConnectionStringByName()
{
diff --git a/test/Serilog.Sinks.MSSqlServer.Tests/Serilog.Sinks.MSSqlServer.Tests.csproj b/test/Serilog.Sinks.MSSqlServer.Tests/Serilog.Sinks.MSSqlServer.Tests.csproj
index 09b851a4..7c8d7959 100644
--- a/test/Serilog.Sinks.MSSqlServer.Tests/Serilog.Sinks.MSSqlServer.Tests.csproj
+++ b/test/Serilog.Sinks.MSSqlServer.Tests/Serilog.Sinks.MSSqlServer.Tests.csproj
@@ -13,24 +13,30 @@
-->
- netcoreapp2.0;net452
- netstandard2.0
+ netcoreapp2.1
+ netstandard2.0
Serilog.Sinks.MSSqlServer.Tests
- ../../assets/Serilog.snk
- true
+ Serilog.snk
+ false
true
Serilog.Sinks.MSSqlServer.Tests
true
win
+ false
-
-
-
+
+
-
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
@@ -41,30 +47,26 @@
-
-
-
-
-
-
-
-
-
+
-
+
-
-
-
+
+
+
all
runtime; build; native; contentfiles; analyzers
+
+
+
+
Always
diff --git a/test/Serilog.Sinks.MSSqlServer.Tests/TestTriggersOnLogTable.cs b/test/Serilog.Sinks.MSSqlServer.Tests/TestTriggersOnLogTable.cs
index 61a5809c..e77bcd9c 100644
--- a/test/Serilog.Sinks.MSSqlServer.Tests/TestTriggersOnLogTable.cs
+++ b/test/Serilog.Sinks.MSSqlServer.Tests/TestTriggersOnLogTable.cs
@@ -99,6 +99,7 @@ public void TestAuditTriggerOnLogTableFire()
logTriggerEvents.Should().NotBeNullOrEmpty();
}
+ Assert.True(true);
}
[Fact]
diff --git a/test/Serilog.Sinks.MSSqlServer.Tests/TestUseMsi.cs b/test/Serilog.Sinks.MSSqlServer.Tests/TestUseMsi.cs
new file mode 100644
index 00000000..e3876bf9
--- /dev/null
+++ b/test/Serilog.Sinks.MSSqlServer.Tests/TestUseMsi.cs
@@ -0,0 +1,45 @@
+using System;
+using Xunit;
+
+namespace Serilog.Sinks.MSSqlServer.Tests
+{
+ [Collection("LogTest")]
+ public class TestUseMsi : IDisposable
+ {
+ [Fact]
+ public void TestIfUseMsiTrueAndAzureServiceTokenProviderResourceNotSet_ThrowsArgumentNullException()
+ {
+ // arrange
+ var loggerConfiguration = new LoggerConfiguration();
+ Assert.Throws(() => loggerConfiguration.AuditTo.MSSqlServer(
+ connectionString: DatabaseFixture.LogEventsConnectionString,
+ tableName: DatabaseFixture.LogTableName,
+ autoCreateSqlTable: true,
+ columnOptions: new ColumnOptions(),
+ useMsi: true)
+ .CreateLogger());
+ }
+
+
+ [Fact]
+ public void TestIfUseMsiTrueAndAzureServiceTokenProviderResourceIsSet_CreatesLogger()
+ {
+ // arrange
+ var loggerConfiguration = new LoggerConfiguration();
+ var logger = loggerConfiguration.AuditTo.MSSqlServer(
+ connectionString: DatabaseFixture.LogEventsConnectionString,
+ tableName: DatabaseFixture.LogTableName,
+ autoCreateSqlTable: true,
+ columnOptions: new ColumnOptions(),
+ useMsi: true,
+ azureServiceTokenProviderResource: "http://a.com")
+ .CreateLogger();
+ Assert.True(true);
+ }
+
+ public void Dispose()
+ {
+ DatabaseFixture.DropTable();
+ }
+ }
+}