diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index efebcb0..f1aa6f3 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -30,8 +30,8 @@ jobs:
- name: Pack
run: dotnet pack -c Release -p:PackageVersion=${{ steps.gitversion.outputs.nuGetVersion }} -p:IncludeSymbols=true -p:SymbolPackageFormat=snupkg
-# && (github.ref_name == 'master')
+
- name: Publish
- if: github.event_name != 'pull_request'
+ if: github.event_name != 'pull_request' && (github.ref_name == 'master')
run: |
dotnet nuget push **/*.nupkg --source 'https://api.nuget.org/v3/index.json' -k ${{ secrets.NUGETKEY }}
diff --git a/src/Serilog.Sinks.MongoDB/Helpers/MongoDbDocumentHelpers.cs b/src/Serilog.Sinks.MongoDB/Helpers/MongoDbDocumentHelpers.cs
index 1004e37..ce63276 100644
--- a/src/Serilog.Sinks.MongoDB/Helpers/MongoDbDocumentHelpers.cs
+++ b/src/Serilog.Sinks.MongoDB/Helpers/MongoDbDocumentHelpers.cs
@@ -19,79 +19,67 @@
using Serilog.Events;
-namespace Serilog.Helpers
+namespace Serilog.Helpers;
+
+internal static class MongoDbDocumentHelpers
{
- internal static class MongoDbDocumentHelpers
+ ///
+ /// Credit to @IvaskevychYuriy for this excellent solution:
+ /// https://github.com/ChangemakerStudios/serilog-sinks-mongodb/pull/59#issuecomment-830079904
+ ///
+ ///
+ ///
+ internal static BsonDocument SanitizeDocumentRecursive(this BsonDocument document)
{
- ///
- /// Credit to @IvaskevychYuriy for this excellent solution:
- /// https://github.com/ChangemakerStudios/serilog-sinks-mongodb/pull/59#issuecomment-830079904
- ///
- ///
- ///
- internal static BsonDocument SanitizeDocumentRecursive(this BsonDocument document)
- {
- if (document == null) throw new ArgumentNullException(nameof(document));
+ if (document == null) throw new ArgumentNullException(nameof(document));
- var sanitizedElements = document.Select(
- e => new BsonElement(
- SanitizedElementName(e.Name),
- e.Value.IsBsonDocument
- ? SanitizeDocumentRecursive(e.Value.AsBsonDocument)
- : e.Value));
+ var sanitizedElements = document.Select(
+ e => new BsonElement(
+ SanitizedElementName(e.Name),
+ e.Value.IsBsonDocument
+ ? SanitizeDocumentRecursive(e.Value.AsBsonDocument)
+ : e.Value));
- return new BsonDocument(sanitizedElements);
- }
+ return new BsonDocument(sanitizedElements);
+ }
- internal static string SanitizedElementName(this string? name)
- {
- if (name == null) return "[NULL]";
+ internal static string SanitizedElementName(this string? name)
+ {
+ if (name == null) return "[NULL]";
- return name.Replace('.', '-').Replace('$', '_');
- }
+ return name.Replace('.', '-').Replace('$', '_');
+ }
- internal static BsonValue? ToBsonValue(this LogEventPropertyValue? value)
+ internal static BsonValue? ToBsonValue(this LogEventPropertyValue? value)
+ {
+ if (value == null) return null;
+
+ if (value is ScalarValue scalar)
{
- if (value == null) return null;
-
- if (value is ScalarValue scalar)
- {
- if (scalar.Value is Uri uri)
- {
- return BsonValue.Create(uri.ToString());
- }
-
- if (scalar.Value is TimeSpan ts)
- {
- return BsonValue.Create(ts.ToString());
- }
-
- if (scalar.Value is DateTimeOffset dto)
- {
- return BsonValue.Create(dto.ToString());
- }
-
- return BsonValue.Create(scalar.Value);
- }
-
- if (value is StructureValue sv)
- {
- return BsonDocument.Create(
- sv.Properties.ToDictionary(
- s => SanitizedElementName(s.Name),
- s => ToBsonValue(s.Value)));
- }
-
- if (value is DictionaryValue dv)
- return BsonDocument.Create(
- dv.Elements.ToDictionary(
- s => SanitizedElementName(s.Key.Value?.ToString()),
- s => ToBsonValue(s.Value)));
-
- if (value is SequenceValue sq)
- return BsonValue.Create(sq.Elements.Select(ToBsonValue).ToArray());
-
- return null;
+ if (scalar.Value is Uri uri) return BsonValue.Create(uri.ToString());
+
+ if (scalar.Value is TimeSpan ts) return BsonValue.Create(ts.ToString());
+
+ if (scalar.Value is DateTimeOffset dto) return BsonValue.Create(dto.ToString());
+
+ return BsonValue.Create(scalar.Value);
}
+
+ if (value is StructureValue sv)
+ return BsonDocument.Create(
+ sv.Properties.ToDictionary(
+ s => SanitizedElementName(s.Name),
+ s => ToBsonValue(s.Value)));
+
+ if (value is DictionaryValue dv)
+ return BsonDocument.Create(
+ dv.Elements.ToDictionary(
+ s => SanitizedElementName(s.Key.Value?.ToString()),
+ s => ToBsonValue(s.Value)));
+
+ if (value is SequenceValue sq)
+ return BsonValue.Create(sq.Elements.Select(ToBsonValue).ToArray());
+
+ return null;
}
}
\ No newline at end of file
diff --git a/src/Serilog.Sinks.MongoDB/Helpers/MongoDbHelpers.cs b/src/Serilog.Sinks.MongoDB/Helpers/MongoDbHelpers.cs
index ee0576c..67625a7 100644
--- a/src/Serilog.Sinks.MongoDB/Helpers/MongoDbHelpers.cs
+++ b/src/Serilog.Sinks.MongoDB/Helpers/MongoDbHelpers.cs
@@ -20,101 +20,103 @@
using Serilog.Debugging;
using Serilog.Sinks.MongoDB;
-namespace Serilog.Helpers
+namespace Serilog.Helpers;
+
+internal static class MongoDbHelper
{
- internal static class MongoDbHelper
+ ///
+ /// Returns true if a collection exists on the mongodb server.
+ ///
+ /// The database.
+ /// Name of the collection.
+ ///
+ internal static bool CollectionExists(this IMongoDatabase database, string collectionName)
+ {
+ var filter = new BsonDocument("name", collectionName);
+ var collectionCursor =
+ database.ListCollections(new ListCollectionsOptions { Filter = filter });
+ return collectionCursor.Any();
+ }
+
+ ///
+ /// Verifies the collection exists. If it doesn't, create it using the Collection Creation Options provided.
+ ///
+ /// The database.
+ /// Name of the collection.
+ /// The collection creation options.
+ internal static void VerifyCollectionExists(
+ this IMongoDatabase database,
+ string collectionName,
+ CreateCollectionOptions? collectionCreationOptions = null)
{
- ///
- /// Returns true if a collection exists on the mongodb server.
- ///
- /// The database.
- /// Name of the collection.
- ///
- internal static bool CollectionExists(this IMongoDatabase database, string collectionName)
+ if (database == null) throw new ArgumentNullException(nameof(database));
+ if (collectionName == null) throw new ArgumentNullException(nameof(collectionName));
+
+ if (database.CollectionExists(collectionName)) return;
+
+ try
{
- var filter = new BsonDocument("name", collectionName);
- var collectionCursor =
- database.ListCollections(new ListCollectionsOptions { Filter = filter });
- return collectionCursor.Any();
+ database.CreateCollection(collectionName, collectionCreationOptions);
}
+ catch (MongoCommandException e) when (e.ErrorMessage.Contains(
+ "collection already exists",
+ StringComparison.InvariantCultureIgnoreCase))
+ {
+ // handled
+ }
+ }
+
+ internal static void VerifyExpireTTLSetup(
+ this IMongoDatabase database,
+ string collectionName,
+ TimeSpan? expireTtl)
+ {
+ const string ExpireTTLIndexName = "serilog_sink_expired_ttl";
+
+ var logCollection = database.GetCollection(collectionName);
- ///
- /// Verifies the collection exists. If it doesn't, create it using the Collection Creation Options provided.
- ///
- /// The database.
- /// Name of the collection.
- /// The collection creation options.
- internal static void VerifyCollectionExists(
- this IMongoDatabase database,
- string collectionName,
- CreateCollectionOptions? collectionCreationOptions = null)
+ if (expireTtl.HasValue)
{
- if (database == null) throw new ArgumentNullException(nameof(database));
- if (collectionName == null) throw new ArgumentNullException(nameof(collectionName));
+ var indexKeysDefinition =
+ Builders.IndexKeys.Ascending(s => s.UtcTimeStamp);
+ var indexOptions = new CreateIndexOptions
+ { Name = ExpireTTLIndexName, ExpireAfter = expireTtl };
+ var indexModel = new CreateIndexModel(indexKeysDefinition, indexOptions);
- if (database.CollectionExists(collectionName)) return;
+ try
+ {
+ logCollection.Indexes.CreateOne(indexModel);
+
+ return;
+ }
+ catch (MongoCommandException ex) when (ex.ErrorMessage.Contains(
+ "already exists with different options"))
+ {
+ // handled -- just drop and recreate
+ logCollection.Indexes.DropOne(ExpireTTLIndexName);
+ }
try
{
- database.CreateCollection(collectionName, collectionCreationOptions);
+ // delete the index and re-create since it exists with different expiration value
+ logCollection.Indexes.CreateOne(indexModel);
}
- catch (MongoCommandException e) when (e.ErrorMessage.Contains("collection already exists"))
+ catch (MongoCommandException ex)
{
- // handled
+ SelfLog.WriteLine(
+ "Failure dropping/creating MongoDB Expire TTL Index: {0}",
+ ex.ErrorMessage);
}
}
-
- internal static void VerifyExpireTTLSetup(
- this IMongoDatabase database,
- string collectionName,
- TimeSpan? expireTtl)
+ else
{
- const string ExpireTTLIndexName = "serilog_sink_expired_ttl";
-
- var logCollection = database.GetCollection(collectionName);
-
- if (expireTtl.HasValue)
+ // make sure the expire TTL index doesn't exist
+ try
{
- var indexKeysDefinition =
- Builders.IndexKeys.Ascending(s => s.UtcTimeStamp);
- var indexOptions = new CreateIndexOptions
- { Name = ExpireTTLIndexName, ExpireAfter = expireTtl };
- var indexModel = new CreateIndexModel(indexKeysDefinition, indexOptions);
-
- try
- {
- logCollection.Indexes.CreateOne(indexModel);
-
- return;
- }
- catch (MongoCommandException ex) when (ex.ErrorMessage.Contains("already exists with different options"))
- {
- // handled -- just drop and recreate
- logCollection.Indexes.DropOne(ExpireTTLIndexName);
- }
-
- try
- {
- // delete the index and re-create since it exists with different expiration value
- logCollection.Indexes.CreateOne(indexModel);
- }
- catch (MongoCommandException ex)
- {
- SelfLog.WriteLine(
- "Failure dropping/creating MongoDB Expire TTL Index: {0}",
- ex.ErrorMessage);
- }
+ logCollection.Indexes.DropOne(ExpireTTLIndexName);
}
- else
+ catch (MongoCommandException)
{
- // make sure the expire TTL index doesn't exist
- try
- {
- logCollection.Indexes.DropOne(ExpireTTLIndexName);
- }
- catch (MongoCommandException)
- {
- }
}
}
}
diff --git a/src/Serilog.Sinks.MongoDB/Helpers/RollingIntervalHelper.cs b/src/Serilog.Sinks.MongoDB/Helpers/RollingIntervalHelper.cs
index 87117c7..f5ea6e8 100644
--- a/src/Serilog.Sinks.MongoDB/Helpers/RollingIntervalHelper.cs
+++ b/src/Serilog.Sinks.MongoDB/Helpers/RollingIntervalHelper.cs
@@ -13,43 +13,45 @@
// limitations under the License.
using System;
+using System.Globalization;
+
using Serilog.Sinks.MongoDB;
-namespace Serilog.Helpers
+namespace Serilog.Helpers;
+
+internal static class RollingIntervalHelper
{
- internal static class RollingIntervalHelper
+ ///
+ /// Returns collection name based on rolling interval.
+ ///
+ /// log202210
+ /// The .
+ /// Collection name.
+ /// If passed invalid rolling interval.
+ internal static string GetCollectionName(this RollingInterval interval, string collectionName)
{
- ///
- /// Returns collection name based on rolling interval.
- ///
- /// log202210
- /// The .
- /// Collection name.
- /// If passed invalid rolling interval.
- internal static string GetCollectionName(this RollingInterval interval, string collectionName)
- {
- if (interval == RollingInterval.Infinite) return collectionName;
+ if (interval == RollingInterval.Infinite) return collectionName;
- return $"{collectionName}_{DateTime.Now.ToString(GetDateTimeFormatForInterval(interval))}";
- }
+ return
+ $"{collectionName}_{DateTime.Now.ToString(GetDateTimeFormatForInterval(interval), CultureInfo.InvariantCulture)}";
+ }
- internal static string GetDateTimeFormatForInterval(this RollingInterval interval)
+ internal static string GetDateTimeFormatForInterval(this RollingInterval interval)
+ {
+ switch (interval)
{
- switch (interval)
- {
- case RollingInterval.Year:
- return "yyyy";
- case RollingInterval.Month:
- return "yyyyMM";
- case RollingInterval.Day:
- return "yyyyMMdd";
- case RollingInterval.Hour:
- return "yyyyMMddhh";
- case RollingInterval.Minute:
- return "yyyyMMddhhmm";
- default:
- throw new ArgumentException("Invalid rolling interval");
- }
+ case RollingInterval.Year:
+ return "yyyy";
+ case RollingInterval.Month:
+ return "yyyyMM";
+ case RollingInterval.Day:
+ return "yyyyMMdd";
+ case RollingInterval.Hour:
+ return "yyyyMMddhh";
+ case RollingInterval.Minute:
+ return "yyyyMMddhhmm";
+ default:
+ throw new ArgumentException("Invalid rolling interval");
}
}
}
\ No newline at end of file
diff --git a/src/Serilog.Sinks.MongoDB/Helpers/StringHelpers.cs b/src/Serilog.Sinks.MongoDB/Helpers/StringHelpers.cs
new file mode 100644
index 0000000..d00a4e5
--- /dev/null
+++ b/src/Serilog.Sinks.MongoDB/Helpers/StringHelpers.cs
@@ -0,0 +1,28 @@
+// Copyright 2014-2022 Serilog Contributors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// ReSharper disable once CheckNamespace
+namespace System;
+#if !NETSTANDARD2_1
+internal static class StringHelpers
+{
+ internal static bool Contains(
+ this string? str,
+ string value,
+ StringComparison comparison)
+ {
+ return str?.IndexOf(value, comparison) >= 0;
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/Serilog.Sinks.MongoDB/LoggerConfigurationMongoDBExtensions.cs b/src/Serilog.Sinks.MongoDB/LoggerConfigurationMongoDBExtensions.cs
index 5c07f77..35a4a69 100644
--- a/src/Serilog.Sinks.MongoDB/LoggerConfigurationMongoDBExtensions.cs
+++ b/src/Serilog.Sinks.MongoDB/LoggerConfigurationMongoDBExtensions.cs
@@ -22,281 +22,272 @@
using Serilog.Sinks.MongoDB;
// ReSharper disable once CheckNamespace
-namespace Serilog
+namespace Serilog;
+
+///
+/// Adds the WriteTo.MongoDB() extension method to .
+///
+public static class LoggerConfigurationMongoDBExtensions
{
///
- /// Adds the WriteTo.MongoDB() extension method to .
+ /// Adds a sink that writes log events as bson documents to a MongoDb database.
+ /// For AppSettings Configuration.
+ ///
+ ///
+ /// Mongo Url Connection String
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static LoggerConfiguration MongoDBBson(
+ this LoggerSinkConfiguration loggerConfiguration,
+ string databaseUrl,
+ string collectionName = MongoDBSinkDefaults.CollectionName,
+ LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum,
+ int batchPostingLimit = MongoDBSinkDefaults.BatchPostingLimit,
+ TimeSpan? period = null,
+ long? cappedMaxSizeMb = null,
+ long? cappedMaxDocuments = null,
+ RollingInterval? rollingInterval = null)
+ {
+ var cfg = new MongoDBSinkConfiguration();
+
+ cfg.SetMongoUrl(databaseUrl);
+ cfg.SetCollectionName(collectionName);
+ cfg.SetBatchPostingLimit(batchPostingLimit);
+
+ if (period.HasValue) cfg.SetBatchPeriod(period.Value);
+
+ if (cappedMaxSizeMb.HasValue || cappedMaxDocuments.HasValue)
+ cfg.SetCreateCappedCollection(
+ cappedMaxSizeMb ?? MongoDBSinkDefaults.CappedCollectionMaxSizeMb,
+ cappedMaxDocuments);
+
+ if (rollingInterval.HasValue) cfg.SetRollingInternal(rollingInterval.Value);
+
+ cfg.Validate();
+
+ return loggerConfiguration.Sink(
+ new MongoDBSink(cfg),
+ restrictedToMinimumLevel);
+ }
+
+ ///
+ /// Adds a sink that writes log events as bson documents to a MongoDb database.
+ /// Fluent configuration.
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static LoggerConfiguration MongoDBBson(
+ this LoggerSinkConfiguration loggerConfiguration,
+ Action configureAction,
+ LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum)
+ {
+ if (loggerConfiguration == null)
+ throw new ArgumentNullException(nameof(loggerConfiguration));
+ if (configureAction == null) throw new ArgumentNullException(nameof(configureAction));
+
+ var cfg = new MongoDBSinkConfiguration();
+
+ configureAction(cfg);
+
+ cfg.Validate();
+
+ return loggerConfiguration.Sink(
+ new MongoDBSink(cfg),
+ restrictedToMinimumLevel);
+ }
+
+ ///
+ /// Adds a sink that writes log events as documents to a MongoDb database.
+ ///
+ /// The logger configuration.
+ /// The URL of a created MongoDB collection that log events will be written to.
+ /// The minimum log event level required in order to write an event to the sink.
+ /// Name of the collection. Default is "log".
+ /// The maximum number of events to post in a single batch.
+ /// The time to wait between checking for event batches.
+ /// Supplies culture-specific formatting information, or null.
+ /// Formatter to produce json for MongoDB.
+ /// Logger configuration, allowing configuration to continue.
+ /// A required parameter is null.
+ public static LoggerConfiguration MongoDB(
+ this LoggerSinkConfiguration loggerConfiguration,
+ string databaseUrl,
+ string collectionName = MongoDBSinkDefaults.CollectionName,
+ LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum,
+ int batchPostingLimit = MongoDBSinkDefaults.BatchPostingLimit,
+ TimeSpan? period = null,
+ IFormatProvider? formatProvider = null,
+ ITextFormatter? mongoDBJsonFormatter = null)
+ {
+ if (loggerConfiguration == null)
+ throw new ArgumentNullException(nameof(loggerConfiguration));
+ if (string.IsNullOrWhiteSpace(databaseUrl))
+ throw new ArgumentNullException(nameof(databaseUrl));
+
+ var cfg = new MongoDBSinkConfiguration { Legacy = true };
+
+ cfg.SetConnectionString(databaseUrl);
+ cfg.SetBatchPostingLimit(batchPostingLimit);
+ if (period.HasValue) cfg.SetBatchPeriod(period.Value);
+ cfg.SetCollectionName(collectionName);
+
+ return
+ loggerConfiguration.Sink(
+ new MongoDBSinkLegacy(
+ cfg,
+ formatProvider,
+ mongoDBJsonFormatter),
+ restrictedToMinimumLevel);
+ }
+
+ ///
+ /// Adds a sink that writes log events as documents to a MongoDb database.
///
- public static class LoggerConfigurationMongoDBExtensions
+ /// The logger configuration.
+ /// The MongoDb database where the log collection will live.
+ /// The minimum log event level required in order to write an event to the sink.
+ /// Name of the collection. Default is "log".
+ /// The maximum number of events to post in a single batch.
+ /// The time to wait between checking for event batches.
+ /// Supplies culture-specific formatting information, or null.
+ /// Formatter to produce json for MongoDB.
+ /// Logger configuration, allowing configuration to continue.
+ /// A required parameter is null.
+ public static LoggerConfiguration MongoDB(
+ this LoggerSinkConfiguration loggerConfiguration,
+ IMongoDatabase database,
+ LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum,
+ string collectionName = MongoDBSinkDefaults.CollectionName,
+ int batchPostingLimit = MongoDBSinkDefaults.BatchPostingLimit,
+ TimeSpan? period = null,
+ IFormatProvider? formatProvider = null,
+ ITextFormatter? mongoDBJsonFormatter = null)
{
- ///
- /// Adds a sink that writes log events as bson documents to a MongoDb database.
- /// For AppSettings Configuration.
- ///
- ///
- /// Mongo Url Connection String
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- public static LoggerConfiguration MongoDBBson(
- this LoggerSinkConfiguration loggerConfiguration,
- string databaseUrl,
- string collectionName = MongoDBSinkDefaults.CollectionName,
- LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum,
- int batchPostingLimit = MongoDBSinkDefaults.BatchPostingLimit,
- TimeSpan? period = null,
- long? cappedMaxSizeMb = null,
- long? cappedMaxDocuments = null,
- RollingInterval? rollingInterval = null)
- {
- var cfg = new MongoDBSinkConfiguration();
-
- cfg.SetMongoUrl(databaseUrl);
- cfg.SetCollectionName(collectionName);
- cfg.SetBatchPostingLimit(batchPostingLimit);
-
- if (period.HasValue)
- {
- cfg.SetBatchPeriod(period.Value);
- }
-
- if (cappedMaxSizeMb.HasValue || cappedMaxDocuments.HasValue)
- {
- cfg.SetCreateCappedCollection(
- cappedMaxSizeMb ?? MongoDBSinkDefaults.CappedCollectionMaxSizeMb,
- cappedMaxDocuments);
- }
-
- if (rollingInterval.HasValue)
- {
- cfg.SetRollingInternal(rollingInterval.Value);
- }
-
- cfg.Validate();
-
- return loggerConfiguration.Sink(
- new MongoDBSink(cfg),
+ if (loggerConfiguration == null)
+ throw new ArgumentNullException(nameof(loggerConfiguration));
+ if (database == null) throw new ArgumentNullException(nameof(database));
+
+ var cfg = new MongoDBSinkConfiguration { Legacy = true };
+
+ cfg.SetMongoDatabase(database);
+ cfg.SetBatchPostingLimit(batchPostingLimit);
+ if (period.HasValue) cfg.SetBatchPeriod(period.Value);
+ cfg.SetCollectionName(collectionName);
+
+ return
+ loggerConfiguration.Sink(
+ new MongoDBSinkLegacy(
+ cfg,
+ formatProvider,
+ mongoDBJsonFormatter),
restrictedToMinimumLevel);
- }
-
- ///
- /// Adds a sink that writes log events as bson documents to a MongoDb database.
- /// Fluent configuration.
- ///
- ///
- ///
- ///
- ///
- public static LoggerConfiguration MongoDBBson(
- this LoggerSinkConfiguration loggerConfiguration,
- Action configureAction,
- LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum)
- {
- if (loggerConfiguration == null)
- throw new ArgumentNullException(nameof(loggerConfiguration));
- if (configureAction == null) throw new ArgumentNullException(nameof(configureAction));
-
- var cfg = new MongoDBSinkConfiguration();
-
- configureAction(cfg);
-
- cfg.Validate();
-
- return loggerConfiguration.Sink(
- new MongoDBSink(cfg),
+ }
+
+ ///
+ /// Adds a sink that writes log events as documents to a capped collection in a MongoDb database.
+ ///
+ /// The logger configuration.
+ ///
+ /// The URL of a MongoDb database where the log collection will live (used for backwards
+ /// compatibility).
+ ///
+ /// The minimum log event level required in order to write an event to the sink.
+ /// Max total size in megabytes of the created capped collection. (Default: 50mb)
+ /// Max number of documents of the created capped collection.
+ /// Name of the collection. Default is "log".
+ /// The maximum number of events to post in a single batch.
+ /// The time to wait between checking for event batches.
+ /// Supplies culture-specific formatting information, or null.
+ /// Formatter to produce json for MongoDB.
+ /// Logger configuration, allowing configuration to continue.
+ /// A required parameter is null.
+ public static LoggerConfiguration MongoDBCapped(
+ this LoggerSinkConfiguration loggerConfiguration,
+ string databaseUrl,
+ LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum,
+ long cappedMaxSizeMb = 50,
+ long? cappedMaxDocuments = null,
+ string collectionName = MongoDBSinkDefaults.CollectionName,
+ int batchPostingLimit = MongoDBSinkDefaults.BatchPostingLimit,
+ TimeSpan? period = null,
+ IFormatProvider? formatProvider = null,
+ ITextFormatter? mongoDBJsonFormatter = null)
+ {
+ if (loggerConfiguration == null)
+ throw new ArgumentNullException(nameof(loggerConfiguration));
+ if (string.IsNullOrWhiteSpace(databaseUrl))
+ throw new ArgumentNullException(nameof(databaseUrl));
+
+ var cfg = new MongoDBSinkConfiguration { Legacy = true };
+
+ cfg.SetConnectionString(databaseUrl);
+ cfg.SetBatchPostingLimit(batchPostingLimit);
+ if (period.HasValue) cfg.SetBatchPeriod(period.Value);
+ cfg.SetCollectionName(collectionName);
+ cfg.SetCreateCappedCollection(cappedMaxSizeMb, cappedMaxDocuments);
+
+ return
+ loggerConfiguration.Sink(
+ new MongoDBSinkLegacy(
+ cfg,
+ formatProvider,
+ mongoDBJsonFormatter),
+ restrictedToMinimumLevel);
+ }
+
+ ///
+ /// Adds a sink that writes log events as documents to a capped collection in a MongoDb database.
+ ///
+ /// The logger configuration.
+ /// The MongoDb database where the log collection will live.
+ /// The minimum log event level required in order to write an event to the sink.
+ /// Max total size in megabytes of the created capped collection. (Default: 50mb)
+ /// Max number of documents of the created capped collection.
+ /// Name of the collection. Default is "log".
+ /// The maximum number of events to post in a single batch.
+ /// The time to wait between checking for event batches.
+ /// Supplies culture-specific formatting information, or null.
+ /// Formatter to produce json for MongoDB.
+ /// Logger configuration, allowing configuration to continue.
+ /// A required parameter is null.
+ public static LoggerConfiguration MongoDBCapped(
+ this LoggerSinkConfiguration loggerConfiguration,
+ IMongoDatabase database,
+ LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum,
+ long cappedMaxSizeMb = 50,
+ long? cappedMaxDocuments = null,
+ string collectionName = MongoDBSinkDefaults.CollectionName,
+ int batchPostingLimit = MongoDBSinkDefaults.BatchPostingLimit,
+ TimeSpan? period = null,
+ IFormatProvider? formatProvider = null,
+ ITextFormatter? mongoDBJsonFormatter = null)
+ {
+ if (loggerConfiguration == null)
+ throw new ArgumentNullException(nameof(loggerConfiguration));
+ if (database == null) throw new ArgumentNullException(nameof(database));
+
+ var cfg = new MongoDBSinkConfiguration { Legacy = true };
+
+ cfg.SetMongoDatabase(database);
+ cfg.SetBatchPostingLimit(batchPostingLimit);
+ if (period.HasValue) cfg.SetBatchPeriod(period.Value);
+ cfg.SetCollectionName(collectionName);
+ cfg.SetCreateCappedCollection(cappedMaxSizeMb, cappedMaxDocuments);
+
+ return
+ loggerConfiguration.Sink(
+ new MongoDBSinkLegacy(
+ cfg,
+ formatProvider,
+ mongoDBJsonFormatter),
restrictedToMinimumLevel);
- }
-
- ///
- /// Adds a sink that writes log events as documents to a MongoDb database.
- ///
- /// The logger configuration.
- /// The URL of a created MongoDB collection that log events will be written to.
- /// The minimum log event level required in order to write an event to the sink.
- /// Name of the collection. Default is "log".
- /// The maximum number of events to post in a single batch.
- /// The time to wait between checking for event batches.
- /// Supplies culture-specific formatting information, or null.
- /// Formatter to produce json for MongoDB.
- /// Logger configuration, allowing configuration to continue.
- /// A required parameter is null.
- public static LoggerConfiguration MongoDB(
- this LoggerSinkConfiguration loggerConfiguration,
- string databaseUrl,
- string collectionName = MongoDBSinkDefaults.CollectionName,
- LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum,
- int batchPostingLimit = MongoDBSinkDefaults.BatchPostingLimit,
- TimeSpan? period = null,
- IFormatProvider? formatProvider = null,
- ITextFormatter? mongoDBJsonFormatter = null)
- {
- if (loggerConfiguration == null)
- throw new ArgumentNullException(nameof(loggerConfiguration));
- if (string.IsNullOrWhiteSpace(databaseUrl))
- throw new ArgumentNullException(nameof(databaseUrl));
-
- var cfg = new MongoDBSinkConfiguration() { Legacy = true };
-
- cfg.SetConnectionString(databaseUrl);
- cfg.SetBatchPostingLimit(batchPostingLimit);
- if (period.HasValue) cfg.SetBatchPeriod(period.Value);
- cfg.SetCollectionName(collectionName);
-
- return
- loggerConfiguration.Sink(
- new MongoDBSinkLegacy(
- cfg,
- formatProvider,
- mongoDBJsonFormatter),
- restrictedToMinimumLevel);
- }
-
- ///
- /// Adds a sink that writes log events as documents to a MongoDb database.
- ///
- /// The logger configuration.
- /// The MongoDb database where the log collection will live.
- /// The minimum log event level required in order to write an event to the sink.
- /// Name of the collection. Default is "log".
- /// The maximum number of events to post in a single batch.
- /// The time to wait between checking for event batches.
- /// Supplies culture-specific formatting information, or null.
- /// Formatter to produce json for MongoDB.
- /// Logger configuration, allowing configuration to continue.
- /// A required parameter is null.
- public static LoggerConfiguration MongoDB(
- this LoggerSinkConfiguration loggerConfiguration,
- IMongoDatabase database,
- LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum,
- string collectionName = MongoDBSinkDefaults.CollectionName,
- int batchPostingLimit = MongoDBSinkDefaults.BatchPostingLimit,
- TimeSpan? period = null,
- IFormatProvider? formatProvider = null,
- ITextFormatter? mongoDBJsonFormatter = null)
- {
- if (loggerConfiguration == null)
- throw new ArgumentNullException(nameof(loggerConfiguration));
- if (database == null) throw new ArgumentNullException(nameof(database));
-
- var cfg = new MongoDBSinkConfiguration() { Legacy = true };
-
- cfg.SetMongoDatabase(database);
- cfg.SetBatchPostingLimit(batchPostingLimit);
- if (period.HasValue) cfg.SetBatchPeriod(period.Value);
- cfg.SetCollectionName(collectionName);
-
- return
- loggerConfiguration.Sink(
- new MongoDBSinkLegacy(
- cfg,
- formatProvider,
- mongoDBJsonFormatter),
- restrictedToMinimumLevel);
- }
-
- ///
- /// Adds a sink that writes log events as documents to a capped collection in a MongoDb database.
- ///
- /// The logger configuration.
- ///
- /// The URL of a MongoDb database where the log collection will live (used for backwards
- /// compatibility).
- ///
- /// The minimum log event level required in order to write an event to the sink.
- /// Max total size in megabytes of the created capped collection. (Default: 50mb)
- /// Max number of documents of the created capped collection.
- /// Name of the collection. Default is "log".
- /// The maximum number of events to post in a single batch.
- /// The time to wait between checking for event batches.
- /// Supplies culture-specific formatting information, or null.
- /// Formatter to produce json for MongoDB.
- /// Logger configuration, allowing configuration to continue.
- /// A required parameter is null.
- public static LoggerConfiguration MongoDBCapped(
- this LoggerSinkConfiguration loggerConfiguration,
- string databaseUrl,
- LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum,
- long cappedMaxSizeMb = 50,
- long? cappedMaxDocuments = null,
- string collectionName = MongoDBSinkDefaults.CollectionName,
- int batchPostingLimit = MongoDBSinkDefaults.BatchPostingLimit,
- TimeSpan? period = null,
- IFormatProvider? formatProvider = null,
- ITextFormatter? mongoDBJsonFormatter = null)
- {
- if (loggerConfiguration == null)
- throw new ArgumentNullException(nameof(loggerConfiguration));
- if (string.IsNullOrWhiteSpace(databaseUrl))
- throw new ArgumentNullException(nameof(databaseUrl));
-
- var cfg = new MongoDBSinkConfiguration() { Legacy = true };
-
- cfg.SetConnectionString(databaseUrl);
- cfg.SetBatchPostingLimit(batchPostingLimit);
- if (period.HasValue) cfg.SetBatchPeriod(period.Value);
- cfg.SetCollectionName(collectionName);
- cfg.SetCreateCappedCollection(cappedMaxSizeMb, cappedMaxDocuments);
-
- return
- loggerConfiguration.Sink(
- new MongoDBSinkLegacy(
- cfg,
- formatProvider,
- mongoDBJsonFormatter),
- restrictedToMinimumLevel);
- }
-
- ///
- /// Adds a sink that writes log events as documents to a capped collection in a MongoDb database.
- ///
- /// The logger configuration.
- /// The MongoDb database where the log collection will live.
- /// The minimum log event level required in order to write an event to the sink.
- /// Max total size in megabytes of the created capped collection. (Default: 50mb)
- /// Max number of documents of the created capped collection.
- /// Name of the collection. Default is "log".
- /// The maximum number of events to post in a single batch.
- /// The time to wait between checking for event batches.
- /// Supplies culture-specific formatting information, or null.
- /// Formatter to produce json for MongoDB.
- /// Logger configuration, allowing configuration to continue.
- /// A required parameter is null.
- public static LoggerConfiguration MongoDBCapped(
- this LoggerSinkConfiguration loggerConfiguration,
- IMongoDatabase database,
- LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum,
- long cappedMaxSizeMb = 50,
- long? cappedMaxDocuments = null,
- string collectionName = MongoDBSinkDefaults.CollectionName,
- int batchPostingLimit = MongoDBSinkDefaults.BatchPostingLimit,
- TimeSpan? period = null,
- IFormatProvider? formatProvider = null,
- ITextFormatter? mongoDBJsonFormatter = null)
- {
- if (loggerConfiguration == null)
- throw new ArgumentNullException(nameof(loggerConfiguration));
- if (database == null) throw new ArgumentNullException(nameof(database));
-
- var cfg = new MongoDBSinkConfiguration() { Legacy = true };
-
- cfg.SetMongoDatabase(database);
- cfg.SetBatchPostingLimit(batchPostingLimit);
- if (period.HasValue) cfg.SetBatchPeriod(period.Value);
- cfg.SetCollectionName(collectionName);
- cfg.SetCreateCappedCollection(cappedMaxSizeMb, cappedMaxDocuments);
-
- return
- loggerConfiguration.Sink(
- new MongoDBSinkLegacy(
- cfg,
- formatProvider,
- mongoDBJsonFormatter),
- restrictedToMinimumLevel);
- }
}
}
\ No newline at end of file
diff --git a/src/Serilog.Sinks.MongoDB/Serilog.Sinks.MongoDB.csproj b/src/Serilog.Sinks.MongoDB/Serilog.Sinks.MongoDB.csproj
index 35ffe66..21cefca 100644
--- a/src/Serilog.Sinks.MongoDB/Serilog.Sinks.MongoDB.csproj
+++ b/src/Serilog.Sinks.MongoDB/Serilog.Sinks.MongoDB.csproj
@@ -40,6 +40,10 @@
+
+
+
+
diff --git a/src/Serilog.Sinks.MongoDB/Sinks/MongoDB/LogEntry.cs b/src/Serilog.Sinks.MongoDB/Sinks/MongoDB/LogEntry.cs
index 6f07950..e78458d 100644
--- a/src/Serilog.Sinks.MongoDB/Sinks/MongoDB/LogEntry.cs
+++ b/src/Serilog.Sinks.MongoDB/Sinks/MongoDB/LogEntry.cs
@@ -21,42 +21,41 @@
using Serilog.Events;
using Serilog.Helpers;
-namespace Serilog.Sinks.MongoDB
+namespace Serilog.Sinks.MongoDB;
+
+public class LogEntry
{
- public class LogEntry
- {
- [BsonRepresentation(BsonType.ObjectId)]
- public string? Id { get; set; }
+ [BsonRepresentation(BsonType.ObjectId)]
+ public string? Id { get; set; }
- [BsonRepresentation(BsonType.String)]
- public LogEventLevel Level { get; set; }
+ [BsonRepresentation(BsonType.String)]
+ public LogEventLevel Level { get; set; }
- public DateTime UtcTimeStamp { get; set; }
+ public DateTime UtcTimeStamp { get; set; }
- public MessageTemplate? MessageTemplate { get; set; }
+ public MessageTemplate? MessageTemplate { get; set; }
- public string? RenderedMessage { get; set; }
+ public string? RenderedMessage { get; set; }
- public BsonDocument? Properties { get; set; }
+ public BsonDocument? Properties { get; set; }
- public BsonDocument? Exception { get; set; }
+ public BsonDocument? Exception { get; set; }
+
+ public static LogEntry MapFrom(LogEvent logEvent)
+ {
+ if (logEvent == null) throw new ArgumentNullException(nameof(logEvent));
- public static LogEntry MapFrom(LogEvent logEvent)
+ return new LogEntry
{
- if (logEvent == null) throw new ArgumentNullException(nameof(logEvent));
-
- return new LogEntry
- {
- MessageTemplate = logEvent.MessageTemplate,
- RenderedMessage = logEvent.RenderMessage(),
- Level = logEvent.Level,
- UtcTimeStamp = logEvent.Timestamp.ToUniversalTime().UtcDateTime,
- Exception = logEvent.Exception?.ToBsonDocument().SanitizeDocumentRecursive(),
- Properties = BsonDocument.Create(
- logEvent.Properties.ToDictionary(
- s => s.Key.SanitizedElementName(),
- s => s.Value.ToBsonValue()))
- };
- }
+ MessageTemplate = logEvent.MessageTemplate,
+ RenderedMessage = logEvent.RenderMessage(),
+ Level = logEvent.Level,
+ UtcTimeStamp = logEvent.Timestamp.ToUniversalTime().UtcDateTime,
+ Exception = logEvent.Exception?.ToBsonDocument().SanitizeDocumentRecursive(),
+ Properties = BsonDocument.Create(
+ logEvent.Properties.ToDictionary(
+ s => s.Key.SanitizedElementName(),
+ s => s.Value.ToBsonValue()))
+ };
}
}
\ No newline at end of file
diff --git a/src/Serilog.Sinks.MongoDB/Sinks/MongoDB/MongoDBJsonFormatter.cs b/src/Serilog.Sinks.MongoDB/Sinks/MongoDB/MongoDBJsonFormatter.cs
index 01be606..593c9cc 100644
--- a/src/Serilog.Sinks.MongoDB/Sinks/MongoDB/MongoDBJsonFormatter.cs
+++ b/src/Serilog.Sinks.MongoDB/Sinks/MongoDB/MongoDBJsonFormatter.cs
@@ -20,78 +20,83 @@
using Serilog.Formatting.Json;
-namespace Serilog.Sinks.MongoDB
+namespace Serilog.Sinks.MongoDB;
+
+///
+/// JsonFormatter for MongoDB
+///
+public class MongoDBJsonFormatter : JsonFormatter
{
+ private readonly IDictionary> _dateTimeWriters;
+
///
- /// JsonFormatter for MongoDB
+ /// See .
+ /// Default JsonFormatter writes DateTimeOffset as string with round trip date/time pattern to MongoDB,
+ /// which contains the local time zone component. String search on these field, with different timezones,
+ /// will not return the correct values. This JsonFormatter writes them as MongoDB Date objects.
///
- public class MongoDBJsonFormatter : JsonFormatter
+ ///
+ /// If true, the properties of the event will be written to
+ /// the output without enclosing braces. Otherwise, if false, each event will be written as a well-formed
+ /// JSON object.
+ ///
+ ///
+ /// A string that will be written after each log event is formatted.
+ /// If null, will be used. Ignored if
+ /// is true.
+ ///
+ ///
+ /// If true, the message will be rendered and written to the output as a
+ /// property named RenderedMessage.
+ ///
+ /// Supplies culture-specific formatting information, or null.
+ public MongoDBJsonFormatter(
+ bool omitEnclosingObject = false,
+ string? closingDelimiter = null,
+ bool renderMessage = false,
+ IFormatProvider? formatProvider = null)
+ : base(omitEnclosingObject, closingDelimiter, renderMessage, formatProvider)
{
- private readonly IDictionary> _dateTimeWriters;
-
- ///
- /// See .
- /// Default JsonFormatter writes DateTimeOffset as string with round trip date/time pattern to MongoDB,
- /// which contains the local time zone component. String search on these field, with different timezones,
- /// will not return the correct values. This JsonFormatter writes them as MongoDB Date objects.
- ///
- /// If true, the properties of the event will be written to
- /// the output without enclosing braces. Otherwise, if false, each event will be written as a well-formed
- /// JSON object.
- /// A string that will be written after each log event is formatted.
- /// If null, will be used. Ignored if
- /// is true.
- /// If true, the message will be rendered and written to the output as a
- /// property named RenderedMessage.
- /// Supplies culture-specific formatting information, or null.
- public MongoDBJsonFormatter(
- bool omitEnclosingObject = false,
- string? closingDelimiter = null,
- bool renderMessage = false,
- IFormatProvider? formatProvider = null)
- : base(omitEnclosingObject, closingDelimiter, renderMessage, formatProvider)
+ this._dateTimeWriters = new Dictionary>
{
- this._dateTimeWriters = new Dictionary>
- {
- {typeof (DateTime), (v, w) => WriteDateTime((DateTime) v, w)},
- {typeof (DateTimeOffset), (v, w) => WriteOffset((DateTimeOffset) v, w)}
- };
- }
-
- ///
- /// Writes out a json property with the specified value on output writer
- ///
- protected override void WriteJsonProperty(
- string name,
- object? value,
- ref string precedingDelimiter,
- TextWriter output)
- {
- name = name.Replace('$', '_').Replace('.', '-');
+ { typeof(DateTime), (v, w) => WriteDateTime((DateTime)v, w) },
+ { typeof(DateTimeOffset), (v, w) => WriteOffset((DateTimeOffset)v, w) }
+ };
+ }
- if (value != null && this._dateTimeWriters.TryGetValue(value.GetType(), out var action))
- {
- output.Write(precedingDelimiter);
- output.Write("\"");
- output.Write(name);
- output.Write("\":");
- action(value, output);
- precedingDelimiter = ",";
- }
- else
- {
- base.WriteJsonProperty(name, value, ref precedingDelimiter, output);
- }
- }
+ ///
+ /// Writes out a json property with the specified value on output writer
+ ///
+ protected override void WriteJsonProperty(
+ string name,
+ object? value,
+ ref string precedingDelimiter,
+ TextWriter output)
+ {
+ name = name.Replace('$', '_').Replace('.', '-');
- private static void WriteOffset(DateTimeOffset value, TextWriter output)
+ if (value != null && this._dateTimeWriters.TryGetValue(value.GetType(), out var action))
{
- output.Write($"{{ \"$date\" : {BsonUtils.ToMillisecondsSinceEpoch(value.UtcDateTime)} }}");
+ output.Write(precedingDelimiter);
+ output.Write("\"");
+ output.Write(name);
+ output.Write("\":");
+ action(value, output);
+ precedingDelimiter = ",";
}
-
- private static void WriteDateTime(DateTime value, TextWriter output)
+ else
{
- output.Write($"{{ \"$date\" : {BsonUtils.ToMillisecondsSinceEpoch(value)} }}");
+ base.WriteJsonProperty(name, value, ref precedingDelimiter, output);
}
}
+
+ private static void WriteOffset(DateTimeOffset value, TextWriter output)
+ {
+ output.Write($"{{ \"$date\" : {BsonUtils.ToMillisecondsSinceEpoch(value.UtcDateTime)} }}");
+ }
+
+ private static void WriteDateTime(DateTime value, TextWriter output)
+ {
+ output.Write($"{{ \"$date\" : {BsonUtils.ToMillisecondsSinceEpoch(value)} }}");
+ }
}
\ No newline at end of file
diff --git a/src/Serilog.Sinks.MongoDB/Sinks/MongoDB/MongoDBSink.cs b/src/Serilog.Sinks.MongoDB/Sinks/MongoDB/MongoDBSink.cs
index fdb0002..b3f3bf8 100644
--- a/src/Serilog.Sinks.MongoDB/Sinks/MongoDB/MongoDBSink.cs
+++ b/src/Serilog.Sinks.MongoDB/Sinks/MongoDB/MongoDBSink.cs
@@ -21,32 +21,31 @@
using Serilog.Events;
-namespace Serilog.Sinks.MongoDB
+namespace Serilog.Sinks.MongoDB;
+
+public class MongoDBSink : MongoDBSinkBase
{
- public class MongoDBSink : MongoDBSinkBase
+ static MongoDBSink()
{
- static MongoDBSink()
- {
- if (!BsonClassMap.IsClassMapRegistered(typeof(Exception)))
- BsonClassMap.RegisterClassMap(
- cm =>
- {
- cm.AutoMap();
- cm.MapProperty(s => s.Message);
- cm.MapProperty(s => s.Source);
- cm.MapProperty(s => s.StackTrace);
- cm.MapProperty(s => s.Data);
- });
- }
+ if (!BsonClassMap.IsClassMapRegistered(typeof(Exception)))
+ BsonClassMap.RegisterClassMap(
+ cm =>
+ {
+ cm.AutoMap();
+ cm.MapProperty(s => s.Message);
+ cm.MapProperty(s => s.Source);
+ cm.MapProperty(s => s.StackTrace);
+ cm.MapProperty(s => s.Data);
+ });
+ }
- public MongoDBSink(MongoDBSinkConfiguration configuration)
- : base(configuration)
- {
- }
+ public MongoDBSink(MongoDBSinkConfiguration configuration)
+ : base(configuration)
+ {
+ }
- protected override Task EmitBatchAsync(IEnumerable events)
- {
- return this.InsertMany(events.Select(LogEntry.MapFrom));
- }
+ protected override Task EmitBatchAsync(IEnumerable events)
+ {
+ return this.InsertMany(events.Select(LogEntry.MapFrom));
}
}
\ No newline at end of file
diff --git a/src/Serilog.Sinks.MongoDB/Sinks/MongoDB/MongoDBSinkBase.cs b/src/Serilog.Sinks.MongoDB/Sinks/MongoDB/MongoDBSinkBase.cs
index e700971..48d2efe 100644
--- a/src/Serilog.Sinks.MongoDB/Sinks/MongoDB/MongoDBSinkBase.cs
+++ b/src/Serilog.Sinks.MongoDB/Sinks/MongoDB/MongoDBSinkBase.cs
@@ -22,71 +22,71 @@
using Serilog.Helpers;
using Serilog.Sinks.PeriodicBatching;
-namespace Serilog.Sinks.MongoDB
+namespace Serilog.Sinks.MongoDB;
+
+///
+/// Writes log events as documents to a MongoDb database.
+///
+public abstract class MongoDBSinkBase : PeriodicBatchingSink
{
+ private readonly MongoDBSinkConfiguration _configuration;
+
+ private readonly Lazy _mongoDatabase;
+
+ ///
+ /// Construct a sink posting to a specified database.
+ ///
+ protected MongoDBSinkBase(MongoDBSinkConfiguration configuration)
+ : base(configuration.BatchPostingLimit, configuration.BatchPeriod)
+ {
+ if (configuration == null) throw new ArgumentNullException(nameof(configuration));
+
+ this._configuration = configuration;
+
+ // validate the settings
+ configuration.Validate();
+
+ this._mongoDatabase = new Lazy(
+ () => GetVerifiedMongoDatabaseFromConfiguration(this._configuration),
+ LazyThreadSafetyMode.ExecutionAndPublication);
+ }
+
+ protected string CollectionName => this._configuration.CollectionName;
+
+ protected RollingInterval RollingInterval => this._configuration.RollingInterval;
+
+ protected static IMongoDatabase GetVerifiedMongoDatabaseFromConfiguration(
+ MongoDBSinkConfiguration configuration)
+ {
+ var mongoDatabase = configuration.MongoDatabase
+ ?? new MongoClient(configuration.MongoUrl).GetDatabase(
+ configuration.MongoUrl!.DatabaseName);
+
+ // connection attempt
+ mongoDatabase.VerifyCollectionExists(
+ configuration.CollectionName,
+ configuration.CollectionCreationOptions);
+
+ // setup TTL if desired
+ mongoDatabase.VerifyExpireTTLSetup(
+ configuration.CollectionName,
+ configuration.ExpireTTL);
+
+ return mongoDatabase;
+ }
+
///
- /// Writes log events as documents to a MongoDb database.
+ /// Gets the log collection.
///
- public abstract class MongoDBSinkBase : PeriodicBatchingSink
+ ///
+ public IMongoCollection GetCollection()
+ {
+ var collectionName = this.RollingInterval.GetCollectionName(this.CollectionName);
+ return this._mongoDatabase.Value.GetCollection(collectionName);
+ }
+
+ protected Task InsertMany(IEnumerable objects)
{
- private readonly MongoDBSinkConfiguration _configuration;
-
- private readonly Lazy _mongoDatabase;
-
- ///
- /// Construct a sink posting to a specified database.
- ///
- protected MongoDBSinkBase(MongoDBSinkConfiguration configuration)
- : base(configuration.BatchPostingLimit, configuration.BatchPeriod)
- {
- if (configuration == null) throw new ArgumentNullException(nameof(configuration));
-
- this._configuration = configuration;
-
- // validate the settings
- configuration.Validate();
-
- this._mongoDatabase = new Lazy(
- () => GetVerifiedMongoDatabaseFromConfiguration(this._configuration),
- LazyThreadSafetyMode.ExecutionAndPublication);
- }
-
- protected string CollectionName => _configuration.CollectionName;
-
- protected RollingInterval RollingInterval => _configuration.RollingInterval;
- protected static IMongoDatabase GetVerifiedMongoDatabaseFromConfiguration(
- MongoDBSinkConfiguration configuration)
- {
- var mongoDatabase = configuration.MongoDatabase
- ?? new MongoClient(configuration.MongoUrl).GetDatabase(
- configuration.MongoUrl!.DatabaseName);
-
- // connection attempt
- mongoDatabase.VerifyCollectionExists(
- configuration.CollectionName,
- configuration.CollectionCreationOptions);
-
- // setup TTL if desired
- mongoDatabase.VerifyExpireTTLSetup(
- configuration.CollectionName,
- configuration.ExpireTTL);
-
- return mongoDatabase;
- }
-
- ///
- /// Gets the log collection.
- ///
- ///
- public IMongoCollection GetCollection()
- {
- var collectionName = RollingInterval.GetCollectionName(CollectionName);
- return this._mongoDatabase.Value.GetCollection(collectionName);
- }
-
- protected Task InsertMany(IEnumerable objects)
- {
- return Task.WhenAll(this.GetCollection().InsertManyAsync(objects));
- }
+ return Task.WhenAll(this.GetCollection().InsertManyAsync(objects));
}
}
\ No newline at end of file
diff --git a/src/Serilog.Sinks.MongoDB/Sinks/MongoDB/MongoDBSinkConfiguration.cs b/src/Serilog.Sinks.MongoDB/Sinks/MongoDB/MongoDBSinkConfiguration.cs
index bd10bc0..533d541 100644
--- a/src/Serilog.Sinks.MongoDB/Sinks/MongoDB/MongoDBSinkConfiguration.cs
+++ b/src/Serilog.Sinks.MongoDB/Sinks/MongoDB/MongoDBSinkConfiguration.cs
@@ -16,146 +16,140 @@
using MongoDB.Driver;
-namespace Serilog.Sinks.MongoDB
+namespace Serilog.Sinks.MongoDB;
+
+public class MongoDBSinkConfiguration
{
- public class MongoDBSinkConfiguration
- {
- public string CollectionName { get; private set; } = MongoDBSinkDefaults.CollectionName;
+ public string CollectionName { get; private set; } = MongoDBSinkDefaults.CollectionName;
- public int BatchPostingLimit { get; private set; } = MongoDBSinkDefaults.BatchPostingLimit;
+ public int BatchPostingLimit { get; private set; } = MongoDBSinkDefaults.BatchPostingLimit;
- public CreateCollectionOptions? CollectionCreationOptions { get; private set; }
+ public CreateCollectionOptions? CollectionCreationOptions { get; private set; }
- public TimeSpan? ExpireTTL { get; private set; }
+ public TimeSpan? ExpireTTL { get; private set; }
- public TimeSpan BatchPeriod { get; private set; } = MongoDBSinkDefaults.BatchPeriod;
+ public TimeSpan BatchPeriod { get; private set; } = MongoDBSinkDefaults.BatchPeriod;
- public MongoUrl? MongoUrl { get; private set; }
+ public MongoUrl? MongoUrl { get; private set; }
- public IMongoDatabase? MongoDatabase { get; private set; }
+ public IMongoDatabase? MongoDatabase { get; private set; }
- public bool Legacy { get; internal set; }
+ public bool Legacy { get; internal set; }
- public RollingInterval RollingInterval { get; private set; } = RollingInterval.Infinite;
+ public RollingInterval RollingInterval { get; private set; } = RollingInterval.Infinite;
- public void Validate()
- {
- if (MongoDatabase == null && MongoUrl == null)
- {
- throw new ArgumentOutOfRangeException(
- "MongoDatabase or MongoUrl",
- "Invalid Configuration: MongoDatabase or Mongo Connection String must be specified.");
- }
-
- if (MongoUrl != null && string.IsNullOrWhiteSpace(MongoUrl.DatabaseName))
- {
- throw new ArgumentNullException(
- nameof(MongoUrl.DatabaseName),
- "Database name is required in the MongoDb connection string. Use: mongodb://mongoDbServer/databaseName");
- }
-
- if (ExpireTTL.HasValue && Legacy)
- {
- throw new ArgumentNullException(
- nameof(ExpireTTL),
- "Expiration TTL is only supported on the MongoDBBson Sink");
- }
- }
+ public void Validate()
+ {
+ if (this.MongoDatabase == null && this.MongoUrl == null)
+ throw new ArgumentOutOfRangeException(
+ "MongoDatabase or MongoUrl",
+ "Invalid Configuration: MongoDatabase or Mongo Connection String must be specified.");
+
+ if (this.MongoUrl != null && string.IsNullOrWhiteSpace(this.MongoUrl.DatabaseName))
+ throw new ArgumentNullException(
+ nameof(this.MongoUrl.DatabaseName),
+ "Database name is required in the MongoDb connection string. Use: mongodb://mongoDbServer/databaseName");
+
+ if (this.ExpireTTL.HasValue && this.Legacy)
+ throw new ArgumentNullException(
+ nameof(this.ExpireTTL),
+ "Expiration TTL is only supported on the MongoDBBson Sink");
+ }
- ///
- /// Set the RollingInterval. (Default: RollingInterval.Infinite)
- ///
- ///
- public void SetRollingInternal(RollingInterval rollingInterval)
- {
- RollingInterval = rollingInterval;
- }
+ ///
+ /// Set the RollingInterval. (Default: RollingInterval.Infinite)
+ ///
+ ///
+ public void SetRollingInternal(RollingInterval rollingInterval)
+ {
+ this.RollingInterval = rollingInterval;
+ }
- ///
- /// Set the periodic batch timeout period. (Default: 2 seconds)
- ///
- ///
- public void SetBatchPeriod(TimeSpan period)
- {
- this.BatchPeriod = period;
- }
+ ///
+ /// Set the periodic batch timeout period. (Default: 2 seconds)
+ ///
+ ///
+ public void SetBatchPeriod(TimeSpan period)
+ {
+ this.BatchPeriod = period;
+ }
- ///
- /// Sets the expiration time on all log documents: https://docs.mongodb.com/manual/tutorial/expire-data/
- /// Only supported for the MongoDBBson sink.
- ///
- ///
- public void SetExpireTTL(TimeSpan? timeToLive)
- {
- this.ExpireTTL = timeToLive;
- }
+ ///
+ /// Sets the expiration time on all log documents: https://docs.mongodb.com/manual/tutorial/expire-data/
+ /// Only supported for the MongoDBBson sink.
+ ///
+ ///
+ public void SetExpireTTL(TimeSpan? timeToLive)
+ {
+ this.ExpireTTL = timeToLive;
+ }
- ///
- /// Setup capped collections during collection creation
- ///
- /// (Optional) Max Size in Mb of the Capped Collection. Default is 50mb.
- /// (Optional) Max Number of Documents in the Capped Collection. Default is none.
- public void SetCreateCappedCollection(
- long cappedMaxSizeMb = MongoDBSinkDefaults.CappedCollectionMaxSizeMb,
- long? cappedMaxDocuments = null)
+ ///
+ /// Setup capped collections during collection creation
+ ///
+ /// (Optional) Max Size in Mb of the Capped Collection. Default is 50mb.
+ /// (Optional) Max Number of Documents in the Capped Collection. Default is none.
+ public void SetCreateCappedCollection(
+ long cappedMaxSizeMb = MongoDBSinkDefaults.CappedCollectionMaxSizeMb,
+ long? cappedMaxDocuments = null)
+ {
+ this.CollectionCreationOptions = new CreateCollectionOptions
{
- this.CollectionCreationOptions = new CreateCollectionOptions
- {
- Capped = true,
- MaxSize = cappedMaxSizeMb * 1024 * 1024
- };
-
- if (cappedMaxDocuments.HasValue)
- this.CollectionCreationOptions.MaxDocuments = cappedMaxDocuments.Value;
- }
+ Capped = true,
+ MaxSize = cappedMaxSizeMb * 1024 * 1024
+ };
- ///
- /// Set the mongo database instance directly
- ///
- ///
- public void SetMongoDatabase(IMongoDatabase database)
- {
- this.MongoDatabase = database ?? throw new ArgumentNullException(nameof(database));
- this.MongoUrl = null;
- }
+ if (cappedMaxDocuments.HasValue)
+ this.CollectionCreationOptions.MaxDocuments = cappedMaxDocuments.Value;
+ }
- ///
- /// Set the mongo url (connection string) -- e.g. mongodb://localhost/databaseName
- ///
- ///
- public void SetMongoUrl(string mongoUrl)
- {
- if (string.IsNullOrWhiteSpace(mongoUrl))
- throw new ArgumentNullException(nameof(mongoUrl));
+ ///
+ /// Set the mongo database instance directly
+ ///
+ ///
+ public void SetMongoDatabase(IMongoDatabase database)
+ {
+ this.MongoDatabase = database ?? throw new ArgumentNullException(nameof(database));
+ this.MongoUrl = null;
+ }
- this.MongoUrl = MongoUrl.Create(mongoUrl);
- this.MongoDatabase = null;
- }
+ ///
+ /// Set the mongo url (connection string) -- e.g. mongodb://localhost/databaseName
+ ///
+ ///
+ public void SetMongoUrl(string mongoUrl)
+ {
+ if (string.IsNullOrWhiteSpace(mongoUrl))
+ throw new ArgumentNullException(nameof(mongoUrl));
- ///
- /// Set the MongoDB collection name (Default: 'logs')
- ///
- ///
- public void SetCollectionName(string collectionName)
- {
- if (collectionName == string.Empty)
- {
- throw new ArgumentOutOfRangeException(nameof(collectionName), "Must not be string.empty");
- }
+ this.MongoUrl = MongoUrl.Create(mongoUrl);
+ this.MongoDatabase = null;
+ }
- CollectionName = collectionName ?? MongoDBSinkDefaults.CollectionName;
- }
+ ///
+ /// Set the MongoDB collection name (Default: 'logs')
+ ///
+ ///
+ public void SetCollectionName(string collectionName)
+ {
+ if (collectionName == string.Empty)
+ throw new ArgumentOutOfRangeException(
+ nameof(collectionName),
+ "Must not be string.empty");
- ///
- /// Set the batch posting limit (Default: 50)
- ///
- ///
- public void SetBatchPostingLimit(int batchPostingLimit)
- {
- this.BatchPostingLimit = batchPostingLimit;
- }
+ this.CollectionName = collectionName ?? MongoDBSinkDefaults.CollectionName;
+ }
+
+ ///
+ /// Set the batch posting limit (Default: 50)
+ ///
+ ///
+ public void SetBatchPostingLimit(int batchPostingLimit)
+ {
+ this.BatchPostingLimit = batchPostingLimit;
+ }
-#if NET452
+#if NET472
///
/// Tries to set the Mongo url from a connection string in the .config file.
///
@@ -190,17 +184,16 @@ public void SetConnectionString(string connectionString)
this.SetMongoUrl(connectionString);
}
#else
- ///
- /// Set the Mongo url (connection string)
- ///
- ///
- public void SetConnectionString(string connectionString)
- {
- if (string.IsNullOrWhiteSpace(connectionString))
- throw new ArgumentNullException(nameof(connectionString));
+ ///
+ /// Set the Mongo url (connection string)
+ ///
+ ///
+ public void SetConnectionString(string connectionString)
+ {
+ if (string.IsNullOrWhiteSpace(connectionString))
+ throw new ArgumentNullException(nameof(connectionString));
- this.SetMongoUrl(connectionString);
- }
-#endif
+ this.SetMongoUrl(connectionString);
}
+#endif
}
\ No newline at end of file
diff --git a/src/Serilog.Sinks.MongoDB/Sinks/MongoDB/MongoDBSinkDefaults.cs b/src/Serilog.Sinks.MongoDB/Sinks/MongoDB/MongoDBSinkDefaults.cs
index b6ae57e..a2717aa 100644
--- a/src/Serilog.Sinks.MongoDB/Sinks/MongoDB/MongoDBSinkDefaults.cs
+++ b/src/Serilog.Sinks.MongoDB/Sinks/MongoDB/MongoDBSinkDefaults.cs
@@ -14,29 +14,28 @@
using System;
-namespace Serilog.Sinks.MongoDB
+namespace Serilog.Sinks.MongoDB;
+
+public static class MongoDBSinkDefaults
{
- public static class MongoDBSinkDefaults
- {
- ///
- /// A reasonable default for the number of events posted in
- /// each batch.
- ///
- public const int BatchPostingLimit = 50;
+ ///
+ /// A reasonable default for the number of events posted in
+ /// each batch.
+ ///
+ public const int BatchPostingLimit = 50;
- ///
- /// The default name for the log collection.
- ///
- public const string CollectionName = "log";
+ ///
+ /// The default name for the log collection.
+ ///
+ public const string CollectionName = "log";
- ///
- /// Default capped collection max size in megabytes
- ///
- public const int CappedCollectionMaxSizeMb = 50;
+ ///
+ /// Default capped collection max size in megabytes
+ ///
+ public const int CappedCollectionMaxSizeMb = 50;
- ///
- /// A reasonable default time to wait between checking for event batches.
- ///
- public static readonly TimeSpan BatchPeriod = TimeSpan.FromSeconds(2);
- }
+ ///
+ /// A reasonable default time to wait between checking for event batches.
+ ///
+ public static readonly TimeSpan BatchPeriod = TimeSpan.FromSeconds(2);
}
\ No newline at end of file
diff --git a/src/Serilog.Sinks.MongoDB/Sinks/MongoDB/MongoDBSinkLegacy.cs b/src/Serilog.Sinks.MongoDB/Sinks/MongoDB/MongoDBSinkLegacy.cs
index 6ecc378..b76c55e 100644
--- a/src/Serilog.Sinks.MongoDB/Sinks/MongoDB/MongoDBSinkLegacy.cs
+++ b/src/Serilog.Sinks.MongoDB/Sinks/MongoDB/MongoDBSinkLegacy.cs
@@ -24,93 +24,91 @@
using Serilog.Formatting;
using Serilog.Helpers;
-namespace Serilog.Sinks.MongoDB
+namespace Serilog.Sinks.MongoDB;
+
+public class MongoDBSinkLegacy : MongoDBSinkBase
{
- public class MongoDBSinkLegacy : MongoDBSinkBase
+ private readonly ITextFormatter _formatter;
+
+ public MongoDBSinkLegacy(
+ MongoDBSinkConfiguration configuration,
+ IFormatProvider? formatProvider = null,
+ ITextFormatter? textFormatter = null)
+ : base(configuration)
{
- private readonly ITextFormatter _formatter;
+ this._formatter = textFormatter ?? new MongoDBJsonFormatter(
+ renderMessage: true,
+ formatProvider: formatProvider);
+ }
- public MongoDBSinkLegacy(
- MongoDBSinkConfiguration configuration,
- IFormatProvider? formatProvider = null,
- ITextFormatter? textFormatter = null)
- : base(configuration)
- {
- this._formatter = textFormatter ?? new MongoDBJsonFormatter(
- renderMessage: true,
- formatProvider: formatProvider);
- }
+ ///
+ /// Creates Json from the log events enumerable
+ ///
+ ///
+ ///
+ private string GenerateJson(IEnumerable events)
+ {
+ var logEventLines = new List();
- ///
- /// Creates Json from the log events enumerable
- ///
- ///
- ///
- private string GenerateJson(IEnumerable events)
+ foreach (var logEvent in events)
{
- var logEventLines = new List();
+ string logEventLine;
- foreach (var logEvent in events)
+ using (var writer = new StringWriter())
{
- string logEventLine;
-
- using (var writer = new StringWriter())
- {
- this._formatter.Format(logEvent, writer);
- logEventLine = writer.ToString().Trim();
- }
-
- if (logEventLine.EndsWith("}"))
- {
- // remove so we can add Utc to end
- logEventLine = logEventLine.Substring(0, logEventLine.Length - 1);
- }
+ this._formatter.Format(logEvent, writer);
+ logEventLine = writer.ToString().Trim();
+ }
- logEventLine += $@", ""UtcTimestamp"": ""{logEvent.Timestamp.ToUniversalTime().DateTime:u}"" }}";
+ if (logEventLine.EndsWith("}"))
+ // remove so we can add Utc to end
+ logEventLine = logEventLine.Substring(0, logEventLine.Length - 1);
- logEventLines.Add(logEventLine);
- }
+ logEventLine +=
+ $@", ""UtcTimestamp"": ""{logEvent.Timestamp.ToUniversalTime().DateTime:u}"" }}";
- return $@"{{ ""logEvents"": [{string.Join(",", logEventLines)}] }}";
+ logEventLines.Add(logEventLine);
}
- ///
- /// Generate BSON documents from LogEvents.
- ///
- /// The events.
- ///
- ///
- ///
- protected IReadOnlyCollection GenerateBsonDocuments(
- IEnumerable events)
- {
- if (events == null) throw new ArgumentNullException(nameof(events));
+ return $@"{{ ""logEvents"": [{string.Join(",", logEventLines)}] }}";
+ }
- var json = this.GenerateJson(events);
- var bson = BsonDocument.Parse(json);
+ ///
+ /// Generate BSON documents from LogEvents.
+ ///
+ /// The events.
+ ///
+ ///
+ ///
+ protected IReadOnlyCollection GenerateBsonDocuments(
+ IEnumerable events)
+ {
+ if (events == null) throw new ArgumentNullException(nameof(events));
- return bson["logEvents"].AsBsonArray
- .Select(x => x.AsBsonDocument.SanitizeDocumentRecursive()).ToList();
- }
+ var json = this.GenerateJson(events);
+ var bson = BsonDocument.Parse(json);
- ///
- /// Emit a batch of log events, running asynchronously.
- ///
- /// The events to emit.
- ///
- ///
- /// Override either
- ///
- /// or
- ///
- /// ,
- /// not both. Overriding EmitBatch() is preferred.
- ///
- protected override Task EmitBatchAsync(IEnumerable events)
- {
- return this.InsertMany(this.GenerateBsonDocuments(events));
- }
+ return bson["logEvents"].AsBsonArray
+ .Select(x => x.AsBsonDocument.SanitizeDocumentRecursive()).ToList();
+ }
+
+ ///
+ /// Emit a batch of log events, running asynchronously.
+ ///
+ /// The events to emit.
+ ///
+ ///
+ /// Override either
+ ///
+ /// or
+ ///
+ /// ,
+ /// not both. Overriding EmitBatch() is preferred.
+ ///
+ protected override Task EmitBatchAsync(IEnumerable events)
+ {
+ return this.InsertMany(this.GenerateBsonDocuments(events));
}
}
\ No newline at end of file
diff --git a/src/Serilog.Sinks.MongoDB/Sinks/MongoDB/RollingInterval.cs b/src/Serilog.Sinks.MongoDB/Sinks/MongoDB/RollingInterval.cs
index 153fadb..7c1422f 100644
--- a/src/Serilog.Sinks.MongoDB/Sinks/MongoDB/RollingInterval.cs
+++ b/src/Serilog.Sinks.MongoDB/Sinks/MongoDB/RollingInterval.cs
@@ -12,41 +12,40 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-namespace Serilog.Sinks.MongoDB
+namespace Serilog.Sinks.MongoDB;
+
+///
+/// Specifies the frequency at which the log file should roll.
+///
+public enum RollingInterval
{
///
- /// Specifies the frequency at which the log file should roll.
+ /// The log file will never roll; no time period information will be appended to the log file name.
///
- public enum RollingInterval
- {
- ///
- /// The log file will never roll; no time period information will be appended to the log file name.
- ///
- Infinite,
+ Infinite,
- ///
- /// Roll every year. Filenames will have a four-digit year appended in the pattern yyyy
.
- ///
- Year,
+ ///
+ /// Roll every year. Filenames will have a four-digit year appended in the pattern yyyy
.
+ ///
+ Year,
- ///
- /// Roll every calendar month. Filenames will have yyyyMM
appended.
- ///
- Month,
+ ///
+ /// Roll every calendar month. Filenames will have yyyyMM
appended.
+ ///
+ Month,
- ///
- /// Roll every day. Filenames will have yyyyMMdd
appended.
- ///
- Day,
+ ///
+ /// Roll every day. Filenames will have yyyyMMdd
appended.
+ ///
+ Day,
- ///
- /// Roll every hour. Filenames will have yyyyMMddHH
appended.
- ///
- Hour,
+ ///
+ /// Roll every hour. Filenames will have yyyyMMddHH
appended.
+ ///
+ Hour,
- ///
- /// Roll every minute. Filenames will have yyyyMMddHHmm
appended.
- ///
- Minute
- }
+ ///
+ /// Roll every minute. Filenames will have yyyyMMddHHmm
appended.
+ ///
+ Minute
}
\ No newline at end of file
diff --git a/test/Serilog.Sinks.MongoDB.Tests/LoggerConfigurationMongoDBExtensionsTests.cs b/test/Serilog.Sinks.MongoDB.Tests/LoggerConfigurationMongoDBExtensionsTests.cs
index 1c9ac73..e1558e4 100644
--- a/test/Serilog.Sinks.MongoDB.Tests/LoggerConfigurationMongoDBExtensionsTests.cs
+++ b/test/Serilog.Sinks.MongoDB.Tests/LoggerConfigurationMongoDBExtensionsTests.cs
@@ -1,6 +1,4 @@
-using System;
-
-using FluentAssertions;
+using FluentAssertions;
using Microsoft.Extensions.Configuration;
@@ -39,7 +37,6 @@ private static void TestCollectionAndDocumentExists(RollingInterval? rollingInte
configuration.SetCollectionName(MongoCollectionName);
}).CreateLogger())
{
-
logger.Information(Message);
}
diff --git a/test/Serilog.Sinks.MongoDB.Tests/Serilog.Sinks.MongoDB.Tests.csproj b/test/Serilog.Sinks.MongoDB.Tests/Serilog.Sinks.MongoDB.Tests.csproj
index 89a8006..02b2f3b 100644
--- a/test/Serilog.Sinks.MongoDB.Tests/Serilog.Sinks.MongoDB.Tests.csproj
+++ b/test/Serilog.Sinks.MongoDB.Tests/Serilog.Sinks.MongoDB.Tests.csproj
@@ -2,6 +2,7 @@
net6.0
+ latest