From e92c7bae2dc2ce3d5c7254d96de15cd30d59e5ed Mon Sep 17 00:00:00 2001 From: stijnmoreels <9039753+stijnmoreels@users.noreply.github.com> Date: Fri, 20 Oct 2023 08:17:23 +0200 Subject: [PATCH] fix: do not alter telemetry ctx pt.1 --- .../ILoggerHttpRequestDataExtensions.cs | 2 +- ...LoggerAzureKeyVaultDependencyExtensions.cs | 5 +- .../ILoggerBlobStorageDependencyExtensions.cs | 4 +- .../Extensions/ILoggerEventExtensions.cs | 2 +- .../ILoggerHttpDependencyExtensions.cs | 4 +- .../ILoggerIotHubDependencyExtensions.cs | 8 +- .../Extensions/ILoggerMetricExtensions.cs | 4 +- .../Extensions/ILoggerRequestExtensions.cs | 8 +- .../ILoggerSqlDependencyExtensions.cs | 4 +- ...ILoggerTableStorageDependencyExtensions.cs | 4 +- .../AzureBlobStorageDependencyLoggingTests.cs | 52 +++++++++-- .../AzureKeyVaultDependencyLoggingTests.cs | 53 ++++++++++- .../AzureTableStorageDependencyTests.cs | 21 +++++ .../Logging/HttpDependencyLoggingTests.cs | 39 ++++++++ .../Logging/HttpRequestDataLoggingTests.cs | 25 +++++- .../Logging/HttpRequestLoggingTests.cs | 24 +++++ .../Logging/IoTHubDependencyLoggingTests.cs | 42 +++++++++ .../Telemetry/Logging/MetricLoggingTests.cs | 16 ++++ .../Logging/SecurityEventLoggingTests.cs | 14 +++ .../Logging/SqlDependencyLoggingTests.cs | 88 +++++++++++++++++++ 20 files changed, 373 insertions(+), 46 deletions(-) diff --git a/src/Arcus.Observability.Telemetry.AzureFunctions/Extensions/ILoggerHttpRequestDataExtensions.cs b/src/Arcus.Observability.Telemetry.AzureFunctions/Extensions/ILoggerHttpRequestDataExtensions.cs index b43dd3f5..945e889b 100644 --- a/src/Arcus.Observability.Telemetry.AzureFunctions/Extensions/ILoggerHttpRequestDataExtensions.cs +++ b/src/Arcus.Observability.Telemetry.AzureFunctions/Extensions/ILoggerHttpRequestDataExtensions.cs @@ -121,7 +121,7 @@ public static void LogRequest( Guard.NotNull(request, nameof(request), "Requires a HTTP request instance to track a HTTP request"); Guard.NotLessThan(duration, TimeSpan.Zero, nameof(duration), "Requires a positive time duration of the request operation"); - context = context ?? new Dictionary(); + context = context is null ? new Dictionary() : new Dictionary(context); logger.LogWarning(MessageFormats.RequestFormat, RequestLogEntry.CreateForHttpRequest(request.Method, diff --git a/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerAzureKeyVaultDependencyExtensions.cs b/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerAzureKeyVaultDependencyExtensions.cs index 603a16f0..a0918103 100644 --- a/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerAzureKeyVaultDependencyExtensions.cs +++ b/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerAzureKeyVaultDependencyExtensions.cs @@ -70,7 +70,6 @@ public static void LogAzureKeyVaultDependency( Guard.NotNullOrWhitespace(secretName, nameof(secretName), "Requires a non-blank secret name for the Azure Key Vault"); Guard.NotNull(measurement, nameof(measurement), "Requires a dependency measurement instance to track the latency of the Azure Key Vault when tracking an Azure Key Vault dependency"); - context = context ?? new Dictionary(); LogAzureKeyVaultDependency(logger, vaultUri, secretName, isSuccessful, measurement, dependencyId: null, context); } @@ -135,7 +134,6 @@ public static void LogAzureKeyVaultDependency( Guard.NotNullOrWhitespace(secretName, nameof(secretName), "Requires a non-blank secret name for the Azure Key Vault"); Guard.NotNull(measurement, nameof(measurement), "Requires a dependency measurement instance to track the latency of the Azure Key Vault when tracking an Azure Key Vault dependency"); - context = context ?? new Dictionary(); LogAzureKeyVaultDependency(logger, vaultUri, secretName, isSuccessful, measurement.StartTime, measurement.Elapsed, dependencyId, context); } @@ -168,7 +166,6 @@ public static void LogAzureKeyVaultDependency( Guard.NotNullOrWhitespace(secretName, nameof(secretName), "Requires a non-blank secret name for the Azure Key Vault"); Guard.NotLessThan(duration, TimeSpan.Zero, nameof(duration), "Requires a positive time duration of the Azure Key Vault operation"); - context = context ?? new Dictionary(); LogAzureKeyVaultDependency(logger, vaultUri, secretName, isSuccessful, startTime, duration, dependencyId: null, context); } @@ -203,7 +200,7 @@ public static void LogAzureKeyVaultDependency( Guard.NotNullOrWhitespace(secretName, nameof(secretName), "Requires a non-blank secret name for the Azure Key Vault"); Guard.NotLessThan(duration, TimeSpan.Zero, nameof(duration), "Requires a positive time duration of the Azure Key Vault operation"); - context = context ?? new Dictionary(); + context = context is null ? new Dictionary() : new Dictionary(context); logger.LogWarning(MessageFormats.DependencyFormat, new DependencyLogEntry( dependencyType: "Azure key vault", diff --git a/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerBlobStorageDependencyExtensions.cs b/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerBlobStorageDependencyExtensions.cs index 24ddb66c..abe76466 100644 --- a/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerBlobStorageDependencyExtensions.cs +++ b/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerBlobStorageDependencyExtensions.cs @@ -124,8 +124,6 @@ public static void LogBlobStorageDependency( Guard.NotNullOrWhitespace(containerName, nameof(containerName), "Requires a non-blank container name in the Azure BLob storage resource to track an Azure Blob storage dependency"); Guard.NotLessThan(duration, TimeSpan.Zero, nameof(duration), "Requires a positive time duration of the Azure Blob storage operation"); - context = context ?? new Dictionary(); - LogBlobStorageDependency(logger, accountName, containerName, isSuccessful, startTime, duration, dependencyId: null, context); } @@ -158,7 +156,7 @@ public static void LogBlobStorageDependency( Guard.NotNullOrWhitespace(containerName, nameof(containerName), "Requires a non-blank container name in the Azure BLob storage resource to track an Azure Blob storage dependency"); Guard.NotLessThan(duration, TimeSpan.Zero, nameof(duration), "Requires a positive time duration of the Azure Blob storage operation"); - context = context ?? new Dictionary(); + context = context is null ? new Dictionary() : new Dictionary(context); string dependencyName = $"{accountName}/{containerName}"; diff --git a/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerEventExtensions.cs b/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerEventExtensions.cs index fdf0e65c..a789a1cf 100644 --- a/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerEventExtensions.cs +++ b/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerEventExtensions.cs @@ -26,7 +26,7 @@ public static void LogSecurityEvent(this ILogger logger, string name, Dictionary Guard.NotNull(logger, nameof(logger), "Requires a logger instance to track telemetry"); Guard.NotNullOrWhitespace(name, nameof(name), "Requires a non-blank name of the event to track an security event"); - context = context ?? new Dictionary(); + context = context is null ? new Dictionary() : new Dictionary(context); context["EventType"] = "Security"; LogCustomEvent(logger, name, context); diff --git a/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerHttpDependencyExtensions.cs b/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerHttpDependencyExtensions.cs index 70c8782e..d06ec960 100644 --- a/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerHttpDependencyExtensions.cs +++ b/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerHttpDependencyExtensions.cs @@ -152,8 +152,6 @@ public static void LogHttpDependency( Guard.For(() => request.RequestUri is null, new ArgumentException("Requires a HTTP request URI to track a HTTP dependency", nameof(request))); Guard.For(() => request.Method is null, new ArgumentException("Requires a HTTP request method to track a HTTP dependency", nameof(request))); - context = context ?? new Dictionary(); - LogHttpDependency(logger, request, statusCode, startTime, duration, dependencyId: null, context); } @@ -220,7 +218,7 @@ public static void LogHttpDependency( Guard.NotLessThan(statusCode, 100, nameof(statusCode), "Requires a valid HTTP response status code that's within the range of 100 to 599, inclusive"); Guard.NotGreaterThan(statusCode, 599, nameof(statusCode), "Requires a valid HTTP response status code that's within the range of 100 to 599, inclusive"); - context = context ?? new Dictionary(); + context = context is null ? new Dictionary() : new Dictionary(context); Uri requestUri = request.RequestUri; string targetName = requestUri.Host; diff --git a/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerIotHubDependencyExtensions.cs b/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerIotHubDependencyExtensions.cs index 2babab4a..85d0c07d 100644 --- a/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerIotHubDependencyExtensions.cs +++ b/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerIotHubDependencyExtensions.cs @@ -113,8 +113,6 @@ public static void LogIotHubDependency( Guard.NotNullOrWhitespace(iotHubName, nameof(iotHubName), "Requires a non-blank resource name of the IoT Hub resource to track a IoT Hub dependency"); Guard.NotLessThan(duration, TimeSpan.Zero, nameof(duration), "Requires a positive time duration of the IoT Hub operation"); - context = context ?? new Dictionary(); - LogIotHubDependency(logger, iotHubName, isSuccessful, startTime, duration, dependencyId: null, context); } @@ -142,8 +140,6 @@ public static void LogIotHubDependencyWithConnectionString( Guard.NotNullOrWhitespace(iotHubConnectionString, nameof(iotHubConnectionString), "Requires an IoT Hub connection string to retrieve the IoT host name to track the IoT Hub dependency"); Guard.NotNull(measurement, nameof(measurement), "Requires an measurement instance to measure the duration of interaction with the IoT Hub dependency"); - context = context ?? new Dictionary(); - LogIotHubDependencyWithConnectionString(logger, iotHubConnectionString, isSuccessful, measurement.StartTime, measurement.Elapsed, dependencyId, context); } @@ -172,8 +168,6 @@ public static void LogIotHubDependencyWithConnectionString( Guard.NotNull(logger, nameof(logger), "Requires an logger instance to track the IoT Hub dependency"); Guard.NotNullOrWhitespace(iotHubConnectionString, nameof(iotHubConnectionString), "Requires an IoT Hub connection string to retrieve the IoT host name to track the IoT Hub dependency"); - context = context ?? new Dictionary(); - var result = IotHubConnectionStringParser.Parse(iotHubConnectionString); LogIotHubDependency(logger, iotHubName: result.HostName, isSuccessful, startTime, duration, dependencyId, context); } @@ -204,7 +198,7 @@ public static void LogIotHubDependency( Guard.NotNullOrWhitespace(iotHubName, nameof(iotHubName), "Requires a non-blank resource name of the IoT Hub resource to track a IoT Hub dependency"); Guard.NotLessThan(duration, TimeSpan.Zero, nameof(duration), "Requires a positive time duration of the IoT Hub operation"); - context = context ?? new Dictionary(); + context = context is null ? new Dictionary() : new Dictionary(context); logger.LogWarning(MessageFormats.DependencyFormat, new DependencyLogEntry( dependencyType: "Azure IoT Hub", diff --git a/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerMetricExtensions.cs b/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerMetricExtensions.cs index f5bd179d..3213e25a 100644 --- a/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerMetricExtensions.cs +++ b/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerMetricExtensions.cs @@ -27,8 +27,6 @@ public static void LogCustomMetric(this ILogger logger, string name, double valu Guard.NotNull(logger, nameof(logger), "Requires a logger instance to track telemetry"); Guard.NotNullOrWhitespace(name, nameof(name), "Requires a non-blank name to track a metric"); - context = context ?? new Dictionary(); - LogCustomMetric(logger, name, value, DateTimeOffset.UtcNow, context); } @@ -67,7 +65,7 @@ public static void LogCustomMetric(this ILogger logger, string name, double valu Guard.NotNull(logger, nameof(logger), "Requires a logger instance to track telemetry"); Guard.NotNullOrWhitespace(name, nameof(name), "Requires a non-blank name to track a metric"); - context = context ?? new Dictionary(); + context = context is null ? new Dictionary() : new Dictionary(context); logger.LogWarning(MessageFormats.MetricFormat, new MetricLogEntry(name, value, timestamp, context)); } diff --git a/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerRequestExtensions.cs b/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerRequestExtensions.cs index a414c417..08feb935 100644 --- a/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerRequestExtensions.cs +++ b/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerRequestExtensions.cs @@ -307,8 +307,6 @@ public static void LogRequest( Guard.NotNull(request, nameof(request), "Requires a HTTP request instance to track a HTTP request"); Guard.NotNull(measurement, nameof(measurement), "Requires an measurement instance to time the duration of the HTTP request"); - context = context ?? new Dictionary(); - LogRequest(logger, request, responseStatusCode, measurement.StartTime, measurement.Elapsed, context); } @@ -340,8 +338,6 @@ public static void LogRequest( Guard.NotNull(request, nameof(request), "Requires a HTTP request instance to track a HTTP request"); Guard.NotLessThan(duration, TimeSpan.Zero, nameof(duration), "Requires a positive time duration of the request operation"); - context = context ?? new Dictionary(); - LogRequest(logger, request, responseStatusCode, operationName: null, startTime, duration, context); } @@ -419,8 +415,6 @@ public static void LogRequest( Guard.NotNull(request, nameof(request), "Requires a HTTP request instance to track a HTTP request"); Guard.NotNull(measurement, nameof(measurement), "Requires an measurement instance to time the duration of the HTTP request"); - context = context ?? new Dictionary(); - LogRequest(logger, request, responseStatusCode, operationName, measurement.StartTime, measurement.Elapsed, context); } @@ -457,7 +451,7 @@ public static void LogRequest( Guard.NotNull(request, nameof(request), "Requires a HTTP request instance to track a HTTP request"); Guard.NotLessThan(duration, TimeSpan.Zero, nameof(duration), "Requires a positive time duration of the request operation"); - context = context ?? new Dictionary(); + context = context is null ? new Dictionary() : new Dictionary(context); logger.LogWarning(MessageFormats.RequestFormat, RequestLogEntry.CreateForHttpRequest( diff --git a/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerSqlDependencyExtensions.cs b/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerSqlDependencyExtensions.cs index 71203b38..42ecd685 100644 --- a/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerSqlDependencyExtensions.cs +++ b/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerSqlDependencyExtensions.cs @@ -307,8 +307,6 @@ public static void LogSqlDependency( Guard.NotNullOrWhitespace(databaseName, nameof(databaseName), "Requires a non-blank SQL database name to track a SQL dependency"); Guard.NotNull(measurement, nameof(measurement), "Requires a dependency measurement instance to measure the latency of the SQL storage when tracking an SQL dependency"); - context = context ?? new Dictionary(); - LogSqlDependency(logger, serverName, databaseName, sqlCommand, operationName, isSuccessful, measurement.StartTime, measurement.Elapsed, dependencyId, context); } @@ -345,7 +343,7 @@ public static void LogSqlDependency( Guard.NotNullOrWhitespace(databaseName, nameof(databaseName), "Requires a non-blank SQL database name to track a SQL dependency"); Guard.NotLessThan(duration, TimeSpan.Zero, nameof(duration), "Requires a positive time duration of the SQL dependency operation"); - context = context ?? new Dictionary(); + context = context is null ? new Dictionary() : new Dictionary(context); logger.LogWarning(MessageFormats.SqlDependencyFormat, new DependencyLogEntry( dependencyType: "Sql", diff --git a/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerTableStorageDependencyExtensions.cs b/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerTableStorageDependencyExtensions.cs index 383babeb..f836ef6c 100644 --- a/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerTableStorageDependencyExtensions.cs +++ b/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerTableStorageDependencyExtensions.cs @@ -124,8 +124,6 @@ public static void LogTableStorageDependency( Guard.NotNullOrWhitespace(tableName, nameof(tableName), "Requires a non-blank table name in the Azure Table storage resource to track an Azure Table storage dependency"); Guard.NotLessThan(duration, TimeSpan.Zero, nameof(duration), "Requires a positive time duration of the Azure Table storage operation"); - context = context ?? new Dictionary(); - LogTableStorageDependency(logger, accountName, tableName, isSuccessful, startTime, duration, dependencyId: null, context); } @@ -158,7 +156,7 @@ public static void LogTableStorageDependency( Guard.NotNullOrWhitespace(tableName, nameof(tableName), "Requires a non-blank table name in the Azure Table storage resource to track an Azure Table storage dependency"); Guard.NotLessThan(duration, TimeSpan.Zero, nameof(duration), "Requires a positive time duration of the Azure Table storage operation"); - context = context ?? new Dictionary(); + context = context is null ? new Dictionary() : new Dictionary(context); string dependencyName = $"{accountName}/{tableName}"; diff --git a/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/AzureBlobStorageDependencyLoggingTests.cs b/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/AzureBlobStorageDependencyLoggingTests.cs index 83198ad9..c457f19c 100644 --- a/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/AzureBlobStorageDependencyLoggingTests.cs +++ b/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/AzureBlobStorageDependencyLoggingTests.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using Arcus.Observability.Telemetry.Core; using Arcus.Observability.Telemetry.Core.Logging; using Bogus; @@ -196,7 +197,7 @@ public void LogBlobStorageDependencyWithDurationMeasurement_WithoutAccountName_F var measurement = DurationMeasurement.Start(); measurement.Dispose(); - // Act / + // Act / Assert Assert.ThrowsAny( () => logger.LogBlobStorageDependency(accountName, containerName, isSuccessful, measurement)); } @@ -214,7 +215,7 @@ public void LogBlobStorageDependencyWithDurationMeasurementWithDependencyId_With measurement.Dispose(); string dependencyId = _bogusGenerator.Lorem.Word(); - // Act / + // Act / Assert Assert.ThrowsAny( () => logger.LogBlobStorageDependency(accountName, containerName, isSuccessful, measurement, dependencyId)); } @@ -231,7 +232,7 @@ public void LogBlobStorageDependencyWithDurationMeasurement_WithoutContainerName var measurement = DurationMeasurement.Start(); measurement.Dispose(); - // Act / + // Act / Assert Assert.ThrowsAny( () => logger.LogBlobStorageDependency(accountName, containerName, isSuccessful, measurement)); } @@ -249,7 +250,7 @@ public void LogBlobStorageDependencyWithDurationMeasurementWithDependencyId_With measurement.Dispose(); string dependencyId = _bogusGenerator.Lorem.Word(); - // Act / + // Act / Assert Assert.ThrowsAny( () => logger.LogBlobStorageDependency(accountName, containerName, isSuccessful, measurement, dependencyId)); } @@ -263,7 +264,7 @@ public void LogBlobStorageDependencyWithDurationMeasurement_WithoutMeasurement_F string containerName = _bogusGenerator.Finance.AccountName(); bool isSuccessful = _bogusGenerator.Random.Bool(); - // Act / + // Act / Assert Assert.ThrowsAny( () => logger.LogBlobStorageDependency(accountName, containerName, isSuccessful, measurement: (DurationMeasurement)null)); } @@ -278,9 +279,48 @@ public void LogBlobStorageDependencyWithDurationMeasurementWithDependencyId_With bool isSuccessful = _bogusGenerator.Random.Bool(); string dependencyId = _bogusGenerator.Lorem.Word(); - // Act / + // Act / Assert Assert.ThrowsAny( () => logger.LogBlobStorageDependency(accountName, containerName, isSuccessful, measurement: null, dependencyId)); } + + [Fact] + public void LogBlobStorageDependencyWithDurationMeasurement_WithContext_DoesNotAlterContext() + { + // Arrange + var logger = new TestLogger(); + string accountName = _bogusGenerator.Finance.AccountName(); + string containerName = _bogusGenerator.Finance.AccountName(); + bool isSuccessful = _bogusGenerator.Random.Bool(); + string dependencyId = _bogusGenerator.Lorem.Word(); + using var measurement = DurationMeasurement.Start(); + var context = new Dictionary(); + + // Act + logger.LogBlobStorageDependency(accountName, containerName, isSuccessful, measurement, dependencyId, context); + + // Assert + Assert.Empty(context); + } + + [Fact] + public void LogBlobStorageDependencyWithStartDuration_WithContext_DoesNotAlterContext() + { + // Arrange + var logger = new TestLogger(); + string accountName = _bogusGenerator.Finance.AccountName(); + string containerName = _bogusGenerator.Finance.AccountName(); + bool isSuccessful = _bogusGenerator.Random.Bool(); + string dependencyId = _bogusGenerator.Lorem.Word(); + var startTime = _bogusGenerator.Date.RecentOffset(); + var duration = _bogusGenerator.Date.Timespan(); + var context = new Dictionary(); + + // Act + logger.LogBlobStorageDependency(accountName, containerName, isSuccessful, startTime, duration, dependencyId, context); + + // Assert + Assert.Empty(context); + } } } diff --git a/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/AzureKeyVaultDependencyLoggingTests.cs b/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/AzureKeyVaultDependencyLoggingTests.cs index d5c9ee15..0ff2b6fb 100644 --- a/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/AzureKeyVaultDependencyLoggingTests.cs +++ b/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/AzureKeyVaultDependencyLoggingTests.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using Arcus.Observability.Telemetry.Core; using Bogus; using Microsoft.Extensions.Logging; @@ -9,7 +10,57 @@ namespace Arcus.Observability.Tests.Unit.Telemetry.Logging [Trait("Category", "Unit")] public class AzureKeyVaultDependencyLoggingTests { - private readonly Faker _bogusGenerator = new Faker(); + private static readonly Faker Bogus = new Faker(); + + [Fact] + public void LogAzureKeyVaultDependency_WithValidArguments_Succeeds() + { + // Arrange + var logger = new TestLogger(); + var vaultUri = Bogus.Internet.Url(); + var secretName = Bogus.Lorem.Word(); + bool isSuccessful = Bogus.Random.Bool(); + var startTime = Bogus.Date.RecentOffset(); + var duration = Bogus.Date.Timespan(); + var dependencyId = Bogus.Random.Guid().ToString(); + var key = Bogus.Lorem.Word(); + var value = Bogus.Random.Guid().ToString(); + var context = new Dictionary { [key] = value }; + + // Act + logger.LogAzureKeyVaultDependency(vaultUri, secretName, isSuccessful, startTime, duration, dependencyId, context); + + // Assert + string message = logger.WrittenMessage; + Assert.Contains(vaultUri, message); + Assert.Contains(secretName, message); + Assert.Contains(isSuccessful.ToString(), message); + Assert.Contains(startTime.ToString(FormatSpecifiers.InvariantTimestampFormat), message); + Assert.Contains(duration.ToString(), message); + Assert.Contains(dependencyId, message); + Assert.Contains(key, message); + Assert.Contains(value, message); + } + + [Fact] + public void LogAzureKeyVaultDependency_WithContext_DoesNotAlterContext() + { + // Arrange + var logger = new TestLogger(); + var vaultUri = Bogus.Internet.Url(); + var secretName = Bogus.Lorem.Word(); + bool isSuccessful = Bogus.Random.Bool(); + var startTime = Bogus.Date.RecentOffset(); + var duration = Bogus.Date.Timespan(); + var dependencyId = Bogus.Random.Guid().ToString(); + var context = new Dictionary(); + + // Act + logger.LogAzureKeyVaultDependency(vaultUri, secretName, isSuccessful, startTime, duration, dependencyId, context); + + // Assert + Assert.Empty(context); + } [Theory] [ClassData(typeof(Blanks))] diff --git a/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/AzureTableStorageDependencyTests.cs b/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/AzureTableStorageDependencyTests.cs index 170ca2df..3a97d10a 100644 --- a/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/AzureTableStorageDependencyTests.cs +++ b/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/AzureTableStorageDependencyTests.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using Arcus.Observability.Telemetry.Core; using Arcus.Observability.Telemetry.Core.Logging; using Bogus; @@ -282,5 +283,25 @@ public void LogTableStorageDependencyWithDurationMeasurementWithDependencyId_Wit Assert.ThrowsAny( () => logger.LogTableStorageDependency(accountName, tableName, isSuccessful, measurement: null, dependencyId)); } + + [Fact] + public void LogTableStorageDependency_WithContext_DoesNotAlterContext() + { + // Arrange + var logger = new TestLogger(); + string accountName = _bogusGenerator.Commerce.ProductName(); + string tableName = _bogusGenerator.Commerce.ProductName(); + bool isSuccessful = _bogusGenerator.Random.Bool(); + string dependencyId = _bogusGenerator.Lorem.Word(); + var startTime = _bogusGenerator.Date.RecentOffset(); + var duration = _bogusGenerator.Date.Timespan(); + var context = new Dictionary(); + + // Act + logger.LogTableStorageDependency(accountName, tableName, isSuccessful, startTime, duration, dependencyId, context); + + // Assert + Assert.Empty(context); + } } } diff --git a/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/HttpDependencyLoggingTests.cs b/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/HttpDependencyLoggingTests.cs index ec121407..7a3b224c 100644 --- a/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/HttpDependencyLoggingTests.cs +++ b/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/HttpDependencyLoggingTests.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Net; using System.Net.Http; using Arcus.Observability.Telemetry.Core; @@ -582,6 +583,44 @@ public void LogHttpDependencyWithRequestMessage_WithHttpStatusCodeOutsideAllowed Assert.ThrowsAny(() => logger.LogHttpDependency(request, statusCode, DateTimeOffset.Now, TimeSpan.Zero, dependencyId)); } + [Fact] + public void LogHttpDependencyWithDurationMeasurement_WithContext_DoesNotAlterContext() + { + // Arrange + var logger = new TestLogger(); + var request = new HttpRequestMessage(HttpMethod.Get, BogusGenerator.Internet.Url()); + var statusCode = (int) BogusGenerator.PickRandom(); + string dependencyId = BogusGenerator.Random.Guid().ToString(); + using var measurement = DurationMeasurement.Start(); + var context = new Dictionary(); + + // Act + logger.LogHttpDependency(request, statusCode, measurement, dependencyId, context); + + // Assert + Assert.Empty(context); + } + + [Fact] + public void LogHttpDependencyWithStartDuration_WithContext_DoesNotAlterContext() + { + // Arrange + var logger = new TestLogger(); + var request = new HttpRequestMessage(HttpMethod.Get, BogusGenerator.Internet.Url()); + var statusCode = (int) BogusGenerator.PickRandom(); + string dependencyId = BogusGenerator.Random.Guid().ToString(); + var startTIme = BogusGenerator.Date.RecentOffset(); + var duration = BogusGenerator.Date.Timespan(); + var context = new Dictionary(); + + // Act + logger.LogHttpDependency(request, statusCode, startTIme, duration, dependencyId, context); + + // Assert + Assert.Empty(context); + } + + private static HttpRequest CreateStubRequest(HttpMethod method, string host, string path, string scheme) { var stubRequest = new Mock(); diff --git a/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/HttpRequestDataLoggingTests.cs b/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/HttpRequestDataLoggingTests.cs index 967e5722..f27a8f59 100644 --- a/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/HttpRequestDataLoggingTests.cs +++ b/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/HttpRequestDataLoggingTests.cs @@ -5,17 +5,14 @@ using Arcus.Observability.Telemetry.Core; using Arcus.Observability.Telemetry.Core.Logging; using Bogus; -#if NET6_0 using Microsoft.Azure.Functions.Worker; using Microsoft.Azure.Functions.Worker.Http; -#endif using Microsoft.Extensions.Logging; using Moq; using Xunit; namespace Arcus.Observability.Tests.Unit.Telemetry.Logging { -#if NET6_0 public class HttpRequestDataDataLoggingTests { private static readonly Faker BogusGenerator = new Faker(); @@ -398,6 +395,27 @@ public void LogRequestWithStatusCodeDurationStartTime_WithOperationNameWithNegat Assert.ThrowsAny(() => logger.LogRequest(stubRequest, statusCode, operationName, startTime, duration, context)); } + [Fact] + public void LogRequest_WithContext_DoesNotAlterContext() + { + // Arrange + var logger = new TestLogger(); + var statusCode = BogusGenerator.PickRandom(); + var path = $"/{BogusGenerator.Lorem.Word()}"; + string host = BogusGenerator.Lorem.Word(); + var scheme = "https"; + HttpMethod method = HttpMethod.Post; + HttpRequestData stubRequest = CreateStubRequest(method, host, path, scheme); + using var measurement = DurationMeasurement.Start(); + var context = new Dictionary(); + + // Act + logger.LogRequest(stubRequest, statusCode, measurement, context); + + // Assert + Assert.Empty(context); + } + private static HttpRequestData CreateStubRequest(HttpMethod method, string host, string path, string scheme) { var context = Mock.Of(); @@ -409,5 +427,4 @@ private static HttpRequestData CreateStubRequest(HttpMethod method, string host, return stub.Object; } } -#endif } diff --git a/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/HttpRequestLoggingTests.cs b/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/HttpRequestLoggingTests.cs index 89526832..cb4e8aeb 100644 --- a/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/HttpRequestLoggingTests.cs +++ b/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/HttpRequestLoggingTests.cs @@ -1375,6 +1375,30 @@ public void LogRequestMessageWithStatusCodeWithOperationNameWithStartTime_WithNe Assert.ThrowsAny(() => logger.LogRequest(request, statusCode, operationName, startTime, duration)); } + [Fact] + public void LogRequestMessage_WithContext_DoesNotAlterContext() + { + // Arrange + var logger = new TestLogger(); + var scheme = "https"; + var host = _bogusGenerator.Lorem.Word(); + var path = _bogusGenerator.Lorem.Word(); + var request = new HttpRequestMessage(HttpMethod.Post, $"{scheme}://{host}/{path}"); + + var statusCode = _bogusGenerator.PickRandom(); + string operationName = _bogusGenerator.Lorem.Word(); + + TimeSpan duration = _bogusGenerator.Date.Timespan(); + DateTimeOffset startTime = _bogusGenerator.Date.RecentOffset(); + var context = new Dictionary(); + + // Act + logger.LogRequest(request, statusCode, operationName, startTime, duration, context); + + // Assert + Assert.Empty(context); + } + private static HttpResponse CreateStubResponse(int statusCode) { var stubResponse = new Mock(); diff --git a/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/IoTHubDependencyLoggingTests.cs b/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/IoTHubDependencyLoggingTests.cs index 319fe267..64a9cf8d 100644 --- a/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/IoTHubDependencyLoggingTests.cs +++ b/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/IoTHubDependencyLoggingTests.cs @@ -559,5 +559,47 @@ public void LogIotHubDependencyConnectionStringWithDependencyMeasurement_ValidAr string dependencyName = iotHubName; Assert.Contains("Azure IoT Hub " + dependencyName, logMessage); } + + [Fact] + public void LogIoTHubDependency_WithContext_DoesNotAlterContext() + { + // Arrange + var logger = new TestLogger(); + string iotHubName = BogusGenerator.Commerce.ProductName().Replace(" ", String.Empty); + bool isSuccessful = BogusGenerator.Random.Bool(); + string dependencyId = BogusGenerator.Random.Guid().ToString(); + + DateTimeOffset startTime = BogusGenerator.Date.RecentOffset(); + TimeSpan duration = BogusGenerator.Date.Timespan(); + var context = new Dictionary(); + + // Act + logger.LogIotHubDependency(iotHubName: iotHubName, isSuccessful, startTime, duration, dependencyId, context); + + // Assert + Assert.Empty(context); + } + + [Fact] + public void LogIotHubDependencyConnectionString_WithContext_DoesNotAlterContext() + { + // Arrange + var logger = new TestLogger(); + string iotHubName = BogusGenerator.Commerce.ProductName().Replace(" ", String.Empty); + string deviceId = BogusGenerator.Internet.Ip(); + string sharedAccessKey = BogusGenerator.Random.Hash(); + var iotHubConnectionString = $"HostName={iotHubName}.;DeviceId={deviceId};SharedAccessKey={sharedAccessKey}"; + bool isSuccessful = BogusGenerator.Random.Bool(); + string dependencyId = BogusGenerator.Random.Guid().ToString(); + + using var measurement = DurationMeasurement.Start(); + var context = new Dictionary(); + + // Act + logger.LogIotHubDependencyWithConnectionString(iotHubConnectionString, isSuccessful: isSuccessful, measurement, dependencyId, context); + + // Assert + Assert.Empty(context); + } } } diff --git a/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/MetricLoggingTests.cs b/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/MetricLoggingTests.cs index 28125b2e..5a4d630d 100644 --- a/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/MetricLoggingTests.cs +++ b/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/MetricLoggingTests.cs @@ -196,5 +196,21 @@ public void LogCustomMetric_NoMetricNameWasSpecified_ThrowsException() // Act & Arrange Assert.Throws(() => logger.LogCustomMetric(metricName, metricValue)); } + + [Fact] + public void LogCustomMetric_WithContext_DoesNotAlterContext() + { + // Arrange + var logger = new TestLogger(); + string metricName = _bogusGenerator.Random.Word(); + double metricValue = _bogusGenerator.Random.Double(); + var context = new Dictionary(); + + // Act + logger.LogCustomMetric(metricName, metricValue, context); + + // Assert + Assert.Empty(context); + } } } diff --git a/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/SecurityEventLoggingTests.cs b/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/SecurityEventLoggingTests.cs index aefc7065..da9b6bef 100644 --- a/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/SecurityEventLoggingTests.cs +++ b/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/SecurityEventLoggingTests.cs @@ -58,5 +58,19 @@ public void LogSecurityEvent_WithNoEventName_ThrowsException() // Act & Assert Assert.Throws(() => logger.LogSecurityEvent(eventName)); } + + [Fact] + public void LogSecurityEvent_WithContext_DoesNotAlterContext() + { + var logger = new TestLogger(); + const string message = "something was invalidated wrong"; + var context = new Dictionary(); + + // Act + logger.LogSecurityEvent(message, context); + + // Assert + Assert.Empty(context); + } } } diff --git a/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/SqlDependencyLoggingTests.cs b/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/SqlDependencyLoggingTests.cs index 47c67fa5..ccc30d7f 100644 --- a/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/SqlDependencyLoggingTests.cs +++ b/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/SqlDependencyLoggingTests.cs @@ -850,5 +850,93 @@ public void LogSqlDependencyWithConnectionStringWithDurationMeasurement_WithoutD Assert.ThrowsAny( () => logger.LogSqlDependencyWithConnectionString(connectionString, sqlCommand, operationName, isSuccessful, measurement: null, dependencyId)); } + + [Fact] + public void LogSqlDependencyWithDurationMeasurement_WithContext_DoesNotAlterContext() + { + // Arrange + var logger = new TestLogger(); + string serverName = BogusGenerator.Name.FullName(); + string databaseName = BogusGenerator.Name.FullName(); + string sqlCommand = "GET something FROM something"; + string operationName = BogusGenerator.Name.FullName(); + bool isSuccessful = BogusGenerator.Random.Bool(); + var dependencyId = BogusGenerator.Random.Guid().ToString(); + using var measurement = DurationMeasurement.Start(); + var context = new Dictionary(); + + // Act + logger.LogSqlDependency(serverName, databaseName, sqlCommand, operationName, isSuccessful, measurement, dependencyId, context); + + // Assert + Assert.Empty(context); + } + + [Fact] + public void LogSqlDependencyWithStartDuration_WithContext_DoesNotAlterContext() + { + // Arrange + var logger = new TestLogger(); + string serverName = BogusGenerator.Name.FullName(); + string databaseName = BogusGenerator.Name.FullName(); + string sqlCommand = "GET something FROM something"; + string operationName = BogusGenerator.Name.FullName(); + bool isSuccessful = BogusGenerator.Random.Bool(); + var dependencyId = BogusGenerator.Random.Guid().ToString(); + var startTime = BogusGenerator.Date.RecentOffset(); + var duration = BogusGenerator.Date.Timespan(); + var context = new Dictionary(); + + // Act + logger.LogSqlDependency(serverName, databaseName, sqlCommand, operationName, isSuccessful, startTime, duration, dependencyId, context); + + // Assert + Assert.Empty(context); + } + + [Fact] + public void LogSqlDependencyWithConnectionStringWithDurationMeasurement_WithContext_DoesNotAlterContext() + { + // Arrange + var logger = new TestLogger(); + string serverName = BogusGenerator.Name.FullName(); + string databaseName = BogusGenerator.Name.FullName(); + var connectionString = $"Server={serverName};Database={databaseName};User=admin;Password=123"; + string sqlCommand = "GET something FROM something"; + string operationName = BogusGenerator.Name.FullName(); + bool isSuccessful = BogusGenerator.Random.Bool(); + var dependencyId = BogusGenerator.Random.Guid().ToString(); + using var measurement = DurationMeasurement.Start(); + var context = new Dictionary(); + + // Act + logger.LogSqlDependencyWithConnectionString(connectionString, sqlCommand, operationName, isSuccessful, measurement, dependencyId, context); + + // Assert + Assert.Empty(context); + } + + [Fact] + public void LogSqlDependencyWithConnectionStringWithStartDuration_WithContext_DoesNotAlterContext() + { + // Arrange + var logger = new TestLogger(); + string serverName = BogusGenerator.Name.FullName(); + string databaseName = BogusGenerator.Name.FullName(); + var connectionString = $"Server={serverName};Database={databaseName};User=admin;Password=123"; + string sqlCommand = "GET something FROM something"; + string operationName = BogusGenerator.Name.FullName(); + bool isSuccessful = BogusGenerator.Random.Bool(); + var dependencyId = BogusGenerator.Random.Guid().ToString(); + var startTime = BogusGenerator.Date.RecentOffset(); + var duration = BogusGenerator.Date.Timespan(); + var context = new Dictionary(); + + // Act + logger.LogSqlDependencyWithConnectionString(connectionString, sqlCommand, operationName, isSuccessful, startTime, duration, dependencyId, context); + + // Assert + Assert.Empty(context); + } } }