From 9818cb5c788cc9052576e2680d18e15ca06b9a08 Mon Sep 17 00:00:00 2001 From: Stijn Moreels <9039753+stijnmoreels@users.noreply.github.com> Date: Mon, 30 May 2022 16:15:19 +0200 Subject: [PATCH 1/3] docs: update w better metric value (#377) --- .../02-Features/writing-different-telemetry-types.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/preview/02-Features/writing-different-telemetry-types.md b/docs/preview/02-Features/writing-different-telemetry-types.md index ec7756f0..d38709b5 100644 --- a/docs/preview/02-Features/writing-different-telemetry-types.md +++ b/docs/preview/02-Features/writing-different-telemetry-types.md @@ -483,13 +483,13 @@ loger.LogSecurityEvent("Invalid Order"); Metrics allow you to report custom metrics which allow you to give insights on application-specific metrics. -Here is how you can report an `Invoice Received` metric: +Here is how you can report an `Invoices Received` metric: ```csharp using Microsoft.Extensions.Logging; -logger.LogMetric("Invoice Received", 133.37, telemetryContext); -// Output: {"MetricName": "Invoice Received", "MetricValue": 133.37, "Timestamp": "03/23/2020 09:32:02 +00:00", "Context: {}} +logger.LogMetric("Invoices Received", 133); +// Output: {"MetricName": "Invoices Received", "MetricValue": 133, "Timestamp": "03/23/2020 09:32:02 +00:00", "Context: {[TelemetryType, Metric]}} ``` ## Requests From 9afa0931b5fe434701234cc4b216e005f9bdfa23 Mon Sep 17 00:00:00 2001 From: Stijn Moreels <9039753+stijnmoreels@users.noreply.github.com> Date: Mon, 30 May 2022 16:16:31 +0200 Subject: [PATCH 2/3] feat: add dependency id to sql dep tracking (#376) * feat: add dependency id to sql dep tracking * pr-style: remove blank line --- .../ILoggerSqlDependencyExtensions.cs | 140 ++++ .../Extensions/ILoggerExtensions.cs | 114 ++- ...cus.Observability.Tests.Integration.csproj | 1 + .../ApplicationInsights/SqlDependencyTests.cs | 83 +- .../Logging/SqlDependencyLoggingTests.cs | 721 +++++++++++++++--- 5 files changed, 919 insertions(+), 140 deletions(-) diff --git a/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerSqlDependencyExtensions.cs b/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerSqlDependencyExtensions.cs index 6b975af0..053196ef 100644 --- a/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerSqlDependencyExtensions.cs +++ b/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerSqlDependencyExtensions.cs @@ -79,6 +79,66 @@ public static void LogSqlDependency( LogSqlDependency(logger, serverName, databaseName, tableName, operationName, isSuccessful, measurement.StartTime, measurement.Elapsed, context); } + /// + /// Logs a SQL dependency. + /// + /// The logger to track the telemetry. + /// The name of server hosting the database. + /// The name of database. + /// The pseudo SQL command information that gets executed against the SQL dependency. + /// The indication whether or not the operation was successful. + /// The measuring the latency to call the SQL dependency. + /// The context that provides more insights on the dependency that was measured. + /// Thrown when the or is null. + /// Thrown when the or is blank. + public static void LogSqlDependency( + this ILogger logger, + string serverName, + string databaseName, + string sqlCommand, + bool isSuccessful, + DurationMeasurement measurement, + Dictionary context = null) + { + Guard.NotNull(logger, nameof(logger), "Requires a logger instance to track telemetry"); + Guard.NotNullOrWhitespace(serverName, nameof(serverName), "Requires a non-blank SQL server name to track a SQL dependency"); + 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"); + + LogSqlDependency(logger, serverName, databaseName, sqlCommand, isSuccessful, measurement.StartTime, measurement.Elapsed, context); + } + + /// + /// Logs a SQL dependency. + /// + /// The logger to track the telemetry. + /// The name of server hosting the database. + /// The name of database. + /// The pseudo SQL command information that gets executed against the SQL dependency. + /// The indication whether or not the operation was successful. + /// The measuring the latency to call the SQL dependency. + /// The ID of the dependency to link as parent ID. + /// The context that provides more insights on the dependency that was measured. + /// Thrown when the or is null. + /// Thrown when the or is blank. + public static void LogSqlDependency( + this ILogger logger, + string serverName, + string databaseName, + string sqlCommand, + bool isSuccessful, + DurationMeasurement measurement, + string dependencyId, + Dictionary context = null) + { + Guard.NotNull(logger, nameof(logger), "Requires a logger instance to track telemetry"); + Guard.NotNullOrWhitespace(serverName, nameof(serverName), "Requires a non-blank SQL server name to track a SQL dependency"); + 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"); + + LogSqlDependency(logger, serverName, databaseName, sqlCommand, isSuccessful, measurement.StartTime, measurement.Elapsed, dependencyId, context); + } + /// /// Logs a SQL dependency /// @@ -129,5 +189,85 @@ public static void LogSqlDependency( isSuccessful: isSuccessful, context: context)); } + + /// + /// Logs a SQL dependency. + /// + /// The logger to track the telemetry. + /// The name of server hosting the database. + /// The name of database. + /// The pseudo SQL command information that gets executed against the SQL dependency. + /// The indication whether or not the operation was successful. + /// The point in time when the interaction with the SQL dependency was started. + /// The duration of the operation. + /// The context that provides more insights on the dependency that was measured. + /// Thrown when the is null. + /// Thrown when the or is blank. + /// Thrown when the is a negative time range. + public static void LogSqlDependency( + this ILogger logger, + string serverName, + string databaseName, + string sqlCommand, + bool isSuccessful, + DateTimeOffset startTime, + TimeSpan duration, + Dictionary context = null) + { + Guard.NotNull(logger, nameof(logger), "Requires a logger instance to track telemetry"); + Guard.NotNullOrWhitespace(serverName, nameof(serverName), "Requires a non-blank SQL server name to track a SQL dependency"); + 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(); + + LogSqlDependency(logger, serverName, databaseName, sqlCommand, isSuccessful, startTime, duration, dependencyId: null, context); + } + + /// + /// Logs a SQL dependency. + /// + /// The logger to track the telemetry. + /// The name of server hosting the database. + /// The name of database. + /// The pseudo SQL command information that gets executed against the SQL dependency. + /// The indication whether or not the operation was successful. + /// The point in time when the interaction with the SQL dependency was started. + /// The duration of the operation. + /// The ID of the dependency to link as parent ID. + /// The context that provides more insights on the dependency that was measured. + /// Thrown when the is null. + /// Thrown when the or is blank. + /// Thrown when the is a negative time range. + public static void LogSqlDependency( + this ILogger logger, + string serverName, + string databaseName, + string sqlCommand, + bool isSuccessful, + DateTimeOffset startTime, + TimeSpan duration, + string dependencyId, + Dictionary context = null) + { + Guard.NotNull(logger, nameof(logger), "Requires a logger instance to track telemetry"); + Guard.NotNullOrWhitespace(serverName, nameof(serverName), "Requires a non-blank SQL server name to track a SQL dependency"); + 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(); + + logger.LogWarning(MessageFormats.SqlDependencyFormat, new DependencyLogEntry( + dependencyType: "Sql", + targetName: serverName, + dependencyName: databaseName, + dependencyData: sqlCommand, + duration: duration, + startTime: startTime, + dependencyId: dependencyId, + resultCode: null, + isSuccessful: isSuccessful, + context: context)); + } } } diff --git a/src/Arcus.Observability.Telemetry.Sql/Extensions/ILoggerExtensions.cs b/src/Arcus.Observability.Telemetry.Sql/Extensions/ILoggerExtensions.cs index dc617057..c24c4f91 100644 --- a/src/Arcus.Observability.Telemetry.Sql/Extensions/ILoggerExtensions.cs +++ b/src/Arcus.Observability.Telemetry.Sql/Extensions/ILoggerExtensions.cs @@ -69,7 +69,61 @@ public static void LogSqlDependency( } /// - /// Logs a SQL dependency + /// Logs a SQL dependency. + /// + /// The logger instance to track the SQL dependency. + /// The SQL connection string. + /// The pseudo SQL command information that gets executed against the SQL dependency. + /// The indication whether or not the operation was successful. + /// The measuring the latency to call the SQL dependency. + /// The context that provides more insights on the dependency that was measured. + /// Thrown when the or the is null. + /// Thrown when the is blank. + public static void LogSqlDependency( + this ILogger logger, + string connectionString, + string sqlCommand, + bool isSuccessful, + DurationMeasurement measurement, + Dictionary context = null) + { + Guard.NotNull(logger, nameof(logger), "Requires a logger instance to track telemetry"); + Guard.NotNullOrWhitespace(connectionString, nameof(connectionString), "Requires a SQL connection string to retrieve database information while tracking the SQL dependency"); + Guard.NotNull(measurement, nameof(measurement)); + + LogSqlDependency(logger, connectionString, sqlCommand, isSuccessful, measurement.StartTime, measurement.Elapsed, context); + } + + /// + /// Logs a SQL dependency. + /// + /// The logger instance to track the SQL dependency. + /// The SQL connection string. + /// The pseudo SQL command information that gets executed against the SQL dependency. + /// The indication whether or not the operation was successful. + /// The measuring the latency to call the SQL dependency. + /// The ID of the dependency to link as parent ID. + /// The context that provides more insights on the dependency that was measured. + /// Thrown when the or the is null. + /// Thrown when the is blank. + public static void LogSqlDependency( + this ILogger logger, + string connectionString, + string sqlCommand, + bool isSuccessful, + DurationMeasurement measurement, + string dependencyId, + Dictionary context = null) + { + Guard.NotNull(logger, nameof(logger), "Requires a logger instance to track telemetry"); + Guard.NotNullOrWhitespace(connectionString, nameof(connectionString), "Requires a SQL connection string to retrieve database information while tracking the SQL dependency"); + Guard.NotNull(measurement, nameof(measurement)); + + LogSqlDependency(logger, connectionString, sqlCommand, isSuccessful, measurement.StartTime, measurement.Elapsed, dependencyId, context); + } + + /// + /// Logs a SQL dependency. /// /// The logger to track the SQL dependency. /// The SQL connection string. @@ -98,5 +152,63 @@ public static void LogSqlDependency( var connection = new SqlConnectionStringBuilder(connectionString); logger.LogSqlDependency(connection.DataSource, connection.InitialCatalog, tableName, operationName, isSuccessful, startTime, duration, context); } + + /// + /// Logs a SQL dependency. + /// + /// The logger to track the SQL dependency. + /// The SQL connection string. + /// The pseudo SQL command information that gets executed against the SQL dependency. + /// The indication whether or not the operation was successful. + /// The point in time when the interaction with the HTTP dependency was started + /// The duration of the operation + /// The context that provides more insights on the dependency that was measured. + /// Thrown when the is null. + /// Thrown when the is blank. + public static void LogSqlDependency( + this ILogger logger, + string connectionString, + string sqlCommand, + bool isSuccessful, + DateTimeOffset startTime, + TimeSpan duration, + Dictionary context = null) + { + Guard.NotNull(logger, nameof(logger), "Requires a logger instance to track telemetry"); + Guard.NotNullOrWhitespace(connectionString, nameof(connectionString), "Requires a SQL connection string to retrieve database information while tracking the SQL dependency"); + + var connection = new SqlConnectionStringBuilder(connectionString); + logger.LogSqlDependency(connection.DataSource, connection.InitialCatalog, sqlCommand, isSuccessful, startTime, duration, context); + } + + /// + /// Logs a SQL dependency. + /// + /// The logger to track the SQL dependency. + /// The SQL connection string. + /// The pseudo SQL command information that gets executed against the SQL dependency. + /// The indication whether or not the operation was successful. + /// The point in time when the interaction with the HTTP dependency was started + /// The duration of the operation + /// The ID of the dependency to link as parent ID. + /// The context that provides more insights on the dependency that was measured. + /// Thrown when the is null. + /// Thrown when the is blank. + public static void LogSqlDependency( + this ILogger logger, + string connectionString, + string sqlCommand, + bool isSuccessful, + DateTimeOffset startTime, + TimeSpan duration, + string dependencyId, + Dictionary context = null) + { + Guard.NotNull(logger, nameof(logger), "Requires a logger instance to track telemetry"); + Guard.NotNullOrWhitespace(connectionString, nameof(connectionString), "Requires a SQL connection string to retrieve database information while tracking the SQL dependency"); + + var connection = new SqlConnectionStringBuilder(connectionString); + logger.LogSqlDependency(connection.DataSource, connection.InitialCatalog, sqlCommand, isSuccessful, startTime, duration, dependencyId, context); + } } } diff --git a/src/Arcus.Observability.Tests.Integration/Arcus.Observability.Tests.Integration.csproj b/src/Arcus.Observability.Tests.Integration/Arcus.Observability.Tests.Integration.csproj index df91ac4c..9e609977 100644 --- a/src/Arcus.Observability.Tests.Integration/Arcus.Observability.Tests.Integration.csproj +++ b/src/Arcus.Observability.Tests.Integration/Arcus.Observability.Tests.Integration.csproj @@ -24,6 +24,7 @@ + diff --git a/src/Arcus.Observability.Tests.Integration/Serilog/Sinks/ApplicationInsights/SqlDependencyTests.cs b/src/Arcus.Observability.Tests.Integration/Serilog/Sinks/ApplicationInsights/SqlDependencyTests.cs index e67a7a17..a9b18ea1 100644 --- a/src/Arcus.Observability.Tests.Integration/Serilog/Sinks/ApplicationInsights/SqlDependencyTests.cs +++ b/src/Arcus.Observability.Tests.Integration/Serilog/Sinks/ApplicationInsights/SqlDependencyTests.cs @@ -26,21 +26,20 @@ public async Task LogSqlDependency_SinksToApplicationInsights_ResultsInSqlDepend string dependencyType = "SQL"; string serverName = BogusGenerator.Database.Engine(); string databaseName = BogusGenerator.Database.Collation(); - string tableName = BogusGenerator.Database.Column(); - string dependencyName = $"{databaseName}/{tableName}"; + string sqlCommand = $"SELECT {BogusGenerator.Database.Column()} FROM Some_Table"; + string dependencyId = BogusGenerator.Random.Guid().ToString(); using (ILoggerFactory loggerFactory = CreateLoggerFactory()) { ILogger logger = loggerFactory.CreateLogger(); - string operation = BogusGenerator.PickRandom("GET", "UPDATE", "DELETE", "CREATE"); bool isSuccessful = BogusGenerator.PickRandom(true, false); DateTimeOffset startTime = DateTimeOffset.Now; TimeSpan duration = BogusGenerator.Date.Timespan(); Dictionary telemetryContext = CreateTestTelemetryContext(); // Act - logger.LogSqlDependency(serverName, databaseName, tableName, operation, isSuccessful, startTime, duration, telemetryContext); + logger.LogSqlDependency(serverName, databaseName, sqlCommand, isSuccessful, startTime, duration, dependencyId, telemetryContext); } // Assert @@ -49,29 +48,85 @@ public async Task LogSqlDependency_SinksToApplicationInsights_ResultsInSqlDepend await RetryAssertUntilTelemetryShouldBeAvailableAsync(async () => { EventsResults results = - await client.Events.GetDependencyEventsAsync(ApplicationId, timespan: "PT30M"); + await client.Events.GetDependencyEventsAsync(ApplicationId, PastHalfHourTimeSpan); + Assert.NotEmpty(results.Value); - Assert.Contains(results.Value, result => + AssertX.Any(results.Value, result => { - return result.Dependency.Type == dependencyType - && result.Dependency.Target == serverName - && result.Dependency.Name == $"{dependencyType}: {dependencyName}"; + Assert.Equal(dependencyType, result.Dependency.Type); + Assert.Equal(serverName, result.Dependency.Target); + Assert.Equal($"{dependencyType}: {databaseName}", result.Dependency.Name); + Assert.Equal(dependencyId, result.Dependency.Id); }); }); } - AssertX.Any(GetLogEventsFromMemory(), logEvent => { + AssertSerilogLogEvents(dependencyType, serverName, databaseName); + } + + [Fact] + public async Task LogSqlDependencyWithConnectionString_SinksToApplicationInsights_ResultsInSqlDependencyTelemetry() + { + // Arrange + string dependencyType = "SQL"; + string serverName = BogusGenerator.Database.Engine(); + string databaseName = BogusGenerator.Database.Collation(); + var connectionString = $"Server={serverName};Database={databaseName};User=admin;Password=123"; + string sqlCommand = $"SELECT {BogusGenerator.Database.Column()} FROM Some_Table"; + string dependencyId = BogusGenerator.Random.Guid().ToString(); + + using (ILoggerFactory loggerFactory = CreateLoggerFactory()) + { + ILogger logger = loggerFactory.CreateLogger(); + + bool isSuccessful = BogusGenerator.PickRandom(true, false); + DateTimeOffset startTime = DateTimeOffset.Now; + TimeSpan duration = BogusGenerator.Date.Timespan(); + Dictionary telemetryContext = CreateTestTelemetryContext(); + + // Act + logger.LogSqlDependency(connectionString, sqlCommand, isSuccessful, startTime, duration, dependencyId, telemetryContext); + } + + // Assert + using (ApplicationInsightsDataClient client = CreateApplicationInsightsClient()) + { + await RetryAssertUntilTelemetryShouldBeAvailableAsync(async () => + { + EventsResults results = + await client.Events.GetDependencyEventsAsync(ApplicationId, PastHalfHourTimeSpan); + + Assert.NotEmpty(results.Value); + AssertX.Any(results.Value, result => + { + Assert.Equal(dependencyType, result.Dependency.Type); + Assert.Equal(serverName, result.Dependency.Target); + Assert.Equal($"{dependencyType}: {databaseName}", result.Dependency.Name); + Assert.Equal(dependencyId, result.Dependency.Id); + }); + }); + } + + AssertSerilogLogEvents(dependencyType, serverName, databaseName); + } + + private void AssertSerilogLogEvents(string dependencyType, string serverName, string databaseName) + { + IEnumerable logEvents = GetLogEventsFromMemory(); + AssertX.Any(logEvents, logEvent => + { StructureValue logEntry = logEvent.Properties.GetAsStructureValue(ContextProperties.DependencyTracking.DependencyLogEntry); Assert.NotNull(logEntry); - var actualDependencyType = Assert.Single(logEntry.Properties, prop => prop.Name == nameof(DependencyLogEntry.DependencyType)); + LogEventProperty actualDependencyType = Assert.Single(logEntry.Properties, prop => prop.Name == nameof(DependencyLogEntry.DependencyType)); Assert.Equal(dependencyType, actualDependencyType.Value.ToDecentString(), true); - var actualTargetName = Assert.Single(logEntry.Properties, prop => prop.Name == nameof(DependencyLogEntry.TargetName)); + LogEventProperty actualTargetName = + Assert.Single(logEntry.Properties, prop => prop.Name == nameof(DependencyLogEntry.TargetName)); Assert.Equal(serverName, actualTargetName.Value.ToDecentString()); - var actualDependencyName = Assert.Single(logEntry.Properties, prop => prop.Name == nameof(DependencyLogEntry.DependencyName)); - Assert.Equal(dependencyName, actualDependencyName.Value.ToDecentString()); + LogEventProperty actualDependencyName = Assert.Single(logEntry.Properties, prop => prop.Name == nameof(DependencyLogEntry.DependencyName)); + Assert.Equal(databaseName, actualDependencyName.Value.ToDecentString()); Assert.Single(logEntry.Properties, prop => prop.Name == nameof(DependencyLogEntry.Context)); }); diff --git a/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/SqlDependencyLoggingTests.cs b/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/SqlDependencyLoggingTests.cs index cdb843ba..a6b8b16f 100644 --- a/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/SqlDependencyLoggingTests.cs +++ b/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/SqlDependencyLoggingTests.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using Arcus.Observability.Telemetry.Core; using Arcus.Observability.Telemetry.Core.Logging; using Bogus; @@ -10,20 +11,20 @@ namespace Arcus.Observability.Tests.Unit.Telemetry.Logging [Trait("Category", "Unit")] public class SqlDependencyLoggingTests { - private readonly Faker _bogusGenerator = new Faker(); + private static readonly Faker BogusGenerator = new Faker(); [Fact] public void LogSqlDependency_ValidArguments_Succeeds() { // Arrange var logger = new TestLogger(); - string serverName = _bogusGenerator.Name.FullName(); - string databaseName = _bogusGenerator.Name.FullName(); - string tableName = _bogusGenerator.Name.FullName(); - string operationName = _bogusGenerator.Name.FullName(); - bool isSuccessful = _bogusGenerator.Random.Bool(); - DateTimeOffset startTime = _bogusGenerator.Date.PastOffset(); - var duration = _bogusGenerator.Date.Timespan(); + string serverName = BogusGenerator.Name.FullName(); + string databaseName = BogusGenerator.Name.FullName(); + string tableName = BogusGenerator.Name.FullName(); + string operationName = BogusGenerator.Name.FullName(); + bool isSuccessful = BogusGenerator.Random.Bool(); + DateTimeOffset startTime = BogusGenerator.Date.PastOffset(); + var duration = BogusGenerator.Date.Timespan(); // Act logger.LogSqlDependency(serverName, databaseName, tableName, operationName, isSuccessful, startTime, duration); @@ -42,17 +43,77 @@ public void LogSqlDependency_ValidArguments_Succeeds() Assert.Contains("Sql " + dependencyName, logMessage); } + [Fact] + public void LogSqlDependencyWithSqlCommand_ValidArguments_Succeeds() + { + // Arrange + var logger = new TestLogger(); + string serverName = BogusGenerator.Lorem.Word(); + string databaseName = BogusGenerator.Lorem.Word(); + string sqlCommand = BogusGenerator.Lorem.Word(); + bool isSuccessful = BogusGenerator.Random.Bool(); + DateTimeOffset startTime = BogusGenerator.Date.PastOffset(); + TimeSpan duration = BogusGenerator.Date.Timespan(); + string key = BogusGenerator.Lorem.Word(); + string value = BogusGenerator.Lorem.Word(); + var context = new Dictionary { [key] = value }; + + // Act + logger.LogSqlDependency(serverName, databaseName, sqlCommand, isSuccessful, startTime, duration, context); + + // Assert + DependencyLogEntry dependency = logger.GetMessageAsDependency(); + Assert.Equal(serverName, dependency.TargetName); + Assert.Equal(databaseName, dependency.DependencyName); + Assert.Equal(sqlCommand, dependency.DependencyData); + Assert.Equal(duration, dependency.Duration); + Assert.Equal(startTime.ToString(FormatSpecifiers.InvariantTimestampFormat), dependency.StartTime); + Assert.Equal(isSuccessful, dependency.IsSuccessful); + Assert.Equal(value, Assert.Contains(key, dependency.Context)); + } + + [Fact] + public void LogSqlDependencyWithSqlCommandWithDependencyId_ValidArguments_Succeeds() + { + // Arrange + var logger = new TestLogger(); + string serverName = BogusGenerator.Lorem.Word(); + string databaseName = BogusGenerator.Lorem.Word(); + string sqlCommand = BogusGenerator.Lorem.Word(); + string dependencyId = BogusGenerator.Lorem.Word(); + bool isSuccessful = BogusGenerator.Random.Bool(); + DateTimeOffset startTime = BogusGenerator.Date.PastOffset(); + TimeSpan duration = BogusGenerator.Date.Timespan(); + string key = BogusGenerator.Lorem.Word(); + string value = BogusGenerator.Lorem.Word(); + var context = new Dictionary { [key] = value }; + + // Act + logger.LogSqlDependency(serverName, databaseName, sqlCommand, isSuccessful, startTime, duration, dependencyId, context); + + // Assert + DependencyLogEntry dependency = logger.GetMessageAsDependency(); + Assert.Equal(serverName, dependency.TargetName); + Assert.Equal(databaseName, dependency.DependencyName); + Assert.Equal(sqlCommand, dependency.DependencyData); + Assert.Equal(dependencyId, dependency.DependencyId); + Assert.Equal(duration, dependency.Duration); + Assert.Equal(startTime.ToString(FormatSpecifiers.InvariantTimestampFormat), dependency.StartTime); + Assert.Equal(isSuccessful, dependency.IsSuccessful); + Assert.Equal(value, Assert.Contains(key, dependency.Context)); + } + [Fact] public void LogSqlDependency_WithNegativeDuration_Fails() { // Arrange var logger = new TestLogger(); - string serverName = _bogusGenerator.Name.FullName(); - string databaseName = _bogusGenerator.Name.FullName(); - string tableName = _bogusGenerator.Name.FullName(); - string operationName = _bogusGenerator.Name.FullName(); - bool isSuccessful = _bogusGenerator.Random.Bool(); - DateTimeOffset startTime = _bogusGenerator.Date.PastOffset(); + string serverName = BogusGenerator.Name.FullName(); + string databaseName = BogusGenerator.Name.FullName(); + string tableName = BogusGenerator.Name.FullName(); + string operationName = BogusGenerator.Name.FullName(); + bool isSuccessful = BogusGenerator.Random.Bool(); + DateTimeOffset startTime = BogusGenerator.Date.PastOffset(); TimeSpan duration = TimeSpanGenerator.GeneratePositiveDuration().Negate(); // Act / Assert @@ -64,11 +125,11 @@ public void LogSqlDependencyWithDependencyMeasurement_ValidArguments_Succeeds() { // Arrange var logger = new TestLogger(); - string serverName = _bogusGenerator.Name.FullName(); - string databaseName = _bogusGenerator.Name.FullName(); - string tableName = _bogusGenerator.Name.FullName(); - string operationName = _bogusGenerator.Name.FullName(); - bool isSuccessful = _bogusGenerator.Random.Bool(); + string serverName = BogusGenerator.Name.FullName(); + string databaseName = BogusGenerator.Name.FullName(); + string tableName = BogusGenerator.Name.FullName(); + string operationName = BogusGenerator.Name.FullName(); + bool isSuccessful = BogusGenerator.Random.Bool(); var measurement = DependencyMeasurement.Start(operationName); DateTimeOffset startTime = measurement.StartTime; @@ -98,11 +159,11 @@ public void LogSqlDependencyWithDurationMeasurement_ValidArguments_Succeeds() { // Arrange var logger = new TestLogger(); - string serverName = _bogusGenerator.Lorem.Word(); - string databaseName = _bogusGenerator.Lorem.Word(); - string tableName = _bogusGenerator.Lorem.Word(); - string operationName = _bogusGenerator.Lorem.Word(); - bool isSuccessful = _bogusGenerator.Random.Bool(); + string serverName = BogusGenerator.Lorem.Word(); + string databaseName = BogusGenerator.Lorem.Word(); + string tableName = BogusGenerator.Lorem.Word(); + string operationName = BogusGenerator.Lorem.Word(); + bool isSuccessful = BogusGenerator.Random.Bool(); var measurement = DurationMeasurement.Start(); DateTimeOffset startTime = measurement.StartTime; @@ -123,16 +184,84 @@ public void LogSqlDependencyWithDurationMeasurement_ValidArguments_Succeeds() Assert.Equal(isSuccessful, dependency.IsSuccessful); } + [Fact] + public void LogSqlDependencyWithSqlCommandWithDurationMeasurement_ValidArguments_Succeeds() + { + // Arrange + var logger = new TestLogger(); + string serverName = BogusGenerator.Lorem.Word(); + string databaseName = BogusGenerator.Lorem.Word(); + string sqlCommand = BogusGenerator.Lorem.Word(); + bool isSuccessful = BogusGenerator.Random.Bool(); + + var measurement = DurationMeasurement.Start(); + DateTimeOffset startTime = measurement.StartTime; + measurement.Dispose(); + TimeSpan duration = measurement.Elapsed; + + string key = BogusGenerator.Lorem.Word(); + string value = BogusGenerator.Lorem.Word(); + var context = new Dictionary { [key] = value }; + + // Act + logger.LogSqlDependency(serverName, databaseName, sqlCommand: sqlCommand, isSuccessful, measurement, context); + + // Assert + DependencyLogEntry dependency = logger.GetMessageAsDependency(); + Assert.Equal(serverName, dependency.TargetName); + Assert.Equal(databaseName, dependency.DependencyName); + Assert.Equal(sqlCommand, dependency.DependencyData); + Assert.Equal(duration, dependency.Duration); + Assert.Equal(startTime.ToString(FormatSpecifiers.InvariantTimestampFormat), dependency.StartTime); + Assert.Equal(isSuccessful, dependency.IsSuccessful); + Assert.Equal(value, Assert.Contains(key, dependency.Context)); + } + + [Fact] + public void LogSqlDependencyWithSqlCommandWithDurationMeasurementWithDependencyId_ValidArguments_Succeeds() + { + // Arrange + var logger = new TestLogger(); + string serverName = BogusGenerator.Lorem.Word(); + string databaseName = BogusGenerator.Lorem.Word(); + string sqlCommand = BogusGenerator.Lorem.Word(); + string dependencyId = BogusGenerator.Lorem.Word(); + bool isSuccessful = BogusGenerator.Random.Bool(); + + var measurement = DurationMeasurement.Start(); + DateTimeOffset startTime = measurement.StartTime; + measurement.Dispose(); + TimeSpan duration = measurement.Elapsed; + + string key = BogusGenerator.Lorem.Word(); + string value = BogusGenerator.Lorem.Word(); + var context = new Dictionary { [key] = value }; + + // Act + logger.LogSqlDependency(serverName, databaseName, sqlCommand, isSuccessful, measurement, dependencyId, context); + + // Assert + DependencyLogEntry dependency = logger.GetMessageAsDependency(); + Assert.Equal(serverName, dependency.TargetName); + Assert.Equal(databaseName, dependency.DependencyName); + Assert.Equal(sqlCommand, dependency.DependencyData); + Assert.Equal(dependencyId, dependency.DependencyId); + Assert.Equal(duration, dependency.Duration); + Assert.Equal(startTime.ToString(FormatSpecifiers.InvariantTimestampFormat), dependency.StartTime); + Assert.Equal(isSuccessful, dependency.IsSuccessful); + Assert.Equal(value, Assert.Contains(key, dependency.Context)); + } + [Theory] [ClassData(typeof(Blanks))] public void LogSqlDependencyWithDurationMeasurement_WithoutServerName_Fails(string serverName) { // Arrange var logger = new TestLogger(); - string databaseName = _bogusGenerator.Name.FullName(); - string tableName = _bogusGenerator.Name.FullName(); - string operationName = _bogusGenerator.Name.FullName(); - bool isSuccessful = _bogusGenerator.Random.Bool(); + string databaseName = BogusGenerator.Name.FullName(); + string tableName = BogusGenerator.Name.FullName(); + string operationName = BogusGenerator.Name.FullName(); + bool isSuccessful = BogusGenerator.Random.Bool(); var measurement = DurationMeasurement.Start(); measurement.Dispose(); @@ -142,16 +271,53 @@ public void LogSqlDependencyWithDurationMeasurement_WithoutServerName_Fails(stri () => logger.LogSqlDependency(serverName, databaseName, tableName, operationName, isSuccessful, measurement)); } + [Theory] + [ClassData(typeof(Blanks))] + public void LogSqlDependencyWithSqlCommandWithDurationMeasurement_WithoutServerName_Fails(string serverName) + { + // Arrange + var logger = new TestLogger(); + string databaseName = BogusGenerator.Name.FullName(); + string sqlCommand = BogusGenerator.Name.FullName(); + bool isSuccessful = BogusGenerator.Random.Bool(); + + var measurement = DurationMeasurement.Start(); + measurement.Dispose(); + + // Act / Assert + Assert.ThrowsAny( + () => logger.LogSqlDependency(serverName, databaseName, sqlCommand: sqlCommand, isSuccessful, measurement)); + } + + [Theory] + [ClassData(typeof(Blanks))] + public void LogSqlDependencyWithSqlCommandWithDurationMeasurementWithDependencyId_WithoutServerName_Fails(string serverName) + { + // Arrange + var logger = new TestLogger(); + string databaseName = BogusGenerator.Name.FullName(); + string sqlCommand = BogusGenerator.Name.FullName(); + string dependencyId = BogusGenerator.Name.FullName(); + bool isSuccessful = BogusGenerator.Random.Bool(); + + var measurement = DurationMeasurement.Start(); + measurement.Dispose(); + + // Act / Assert + Assert.ThrowsAny( + () => logger.LogSqlDependency(serverName, databaseName, sqlCommand, isSuccessful, measurement, dependencyId)); + } + [Theory] [ClassData(typeof(Blanks))] public void LogSqlDependencyWithDurationMeasurement_WithoutDatabaseName_Fails(string databaseName) { // Arrange var logger = new TestLogger(); - string serverName = _bogusGenerator.Name.FullName(); - string tableName = _bogusGenerator.Name.FullName(); - string operationName = _bogusGenerator.Name.FullName(); - bool isSuccessful = _bogusGenerator.Random.Bool(); + string serverName = BogusGenerator.Name.FullName(); + string tableName = BogusGenerator.Name.FullName(); + string operationName = BogusGenerator.Name.FullName(); + bool isSuccessful = BogusGenerator.Random.Bool(); var measurement = DurationMeasurement.Start(); measurement.Dispose(); @@ -161,16 +327,53 @@ public void LogSqlDependencyWithDurationMeasurement_WithoutDatabaseName_Fails(st () => logger.LogSqlDependency(serverName, databaseName, tableName, operationName, isSuccessful, measurement)); } + [Theory] + [ClassData(typeof(Blanks))] + public void LogSqlDependencyWithSqlCommandWithDurationMeasurement_WithoutDatabaseName_Fails(string databaseName) + { + // Arrange + var logger = new TestLogger(); + string serverName = BogusGenerator.Name.FullName(); + string sqlCommand = BogusGenerator.Name.FullName(); + bool isSuccessful = BogusGenerator.Random.Bool(); + + var measurement = DurationMeasurement.Start(); + measurement.Dispose(); + + // Act / Assert + Assert.ThrowsAny( + () => logger.LogSqlDependency(serverName, databaseName, sqlCommand: sqlCommand, isSuccessful, measurement)); + } + + [Theory] + [ClassData(typeof(Blanks))] + public void LogSqlDependencyWithSqlCommandWithDurationMeasurementWithDependencyId_WithoutDatabaseName_Fails(string databaseName) + { + // Arrange + var logger = new TestLogger(); + string serverName = BogusGenerator.Name.FullName(); + string sqlCommand = BogusGenerator.Name.FullName(); + string dependencyId = BogusGenerator.Name.FullName(); + bool isSuccessful = BogusGenerator.Random.Bool(); + + var measurement = DurationMeasurement.Start(); + measurement.Dispose(); + + // Act / Assert + Assert.ThrowsAny( + () => logger.LogSqlDependency(serverName, databaseName, sqlCommand, isSuccessful, measurement, dependencyId)); + } + [Theory] [ClassData(typeof(Blanks))] public void LogSqlDependencyWithDurationMeasurement_WithoutTableName_Fails(string tableName) { // Arrange var logger = new TestLogger(); - string serverName = _bogusGenerator.Name.FullName(); - string databaseName = _bogusGenerator.Name.FullName(); - string operationName = _bogusGenerator.Name.FullName(); - bool isSuccessful = _bogusGenerator.Random.Bool(); + string serverName = BogusGenerator.Name.FullName(); + string databaseName = BogusGenerator.Name.FullName(); + string operationName = BogusGenerator.Name.FullName(); + bool isSuccessful = BogusGenerator.Random.Bool(); var measurement = DurationMeasurement.Start(); measurement.Dispose(); @@ -186,10 +389,10 @@ public void LogSqlDependencyWithDurationMeasurement_WithoutOperation_Fails(strin { // Arrange var logger = new TestLogger(); - string serverName = _bogusGenerator.Name.FullName(); - string databaseName = _bogusGenerator.Name.FullName(); - string tableName = _bogusGenerator.Name.FullName(); - bool isSuccessful = _bogusGenerator.Random.Bool(); + string serverName = BogusGenerator.Name.FullName(); + string databaseName = BogusGenerator.Name.FullName(); + string tableName = BogusGenerator.Name.FullName(); + bool isSuccessful = BogusGenerator.Random.Bool(); var measurement = DurationMeasurement.Start(); measurement.Dispose(); @@ -204,30 +407,61 @@ public void LogSqlDependencyWithDurationMeasurement_WithoutMeasurement_Fails() { // Arrange var logger = new TestLogger(); - string serverName = _bogusGenerator.Name.FullName(); - string databaseName = _bogusGenerator.Name.FullName(); - string tableName = _bogusGenerator.Name.FullName(); - string operationName = _bogusGenerator.Name.FullName(); - bool isSuccessful = _bogusGenerator.Random.Bool(); + string serverName = BogusGenerator.Name.FullName(); + string databaseName = BogusGenerator.Name.FullName(); + string tableName = BogusGenerator.Name.FullName(); + string operationName = BogusGenerator.Name.FullName(); + bool isSuccessful = BogusGenerator.Random.Bool(); // Act / Assert Assert.ThrowsAny( () => logger.LogSqlDependency(serverName, databaseName, tableName, operationName, isSuccessful, measurement: (DurationMeasurement)null)); } + [Fact] + public void LogSqlDependencyWithSqlCommandWithDurationMeasurement_WithoutMeasurement_Fails() + { + // Arrange + var logger = new TestLogger(); + string serverName = BogusGenerator.Name.FullName(); + string databaseName = BogusGenerator.Name.FullName(); + string sqlCommand = BogusGenerator.Name.FullName(); + bool isSuccessful = BogusGenerator.Random.Bool(); + + // Act / Assert + Assert.ThrowsAny( + () => logger.LogSqlDependency(serverName, databaseName, sqlCommand: sqlCommand, isSuccessful, measurement: null)); + } + + [Fact] + public void LogSqlDependencyWithSqlCommandWithDurationMeasurementWithDependencyId_WithoutMeasurement_Fails() + { + // Arrange + var logger = new TestLogger(); + string serverName = BogusGenerator.Name.FullName(); + string databaseName = BogusGenerator.Name.FullName(); + string sqlCommand = BogusGenerator.Name.FullName(); + string dependencyId = BogusGenerator.Name.FullName(); + bool isSuccessful = BogusGenerator.Random.Bool(); + + // Act / Assert + Assert.ThrowsAny( + () => logger.LogSqlDependency(serverName, databaseName, sqlCommand, isSuccessful, measurement: null, dependencyId)); + } + [Fact] public void LogSqlDependencyConnectionString_ValidArguments_Succeeds() { // Arrange var logger = new TestLogger(); - string serverName = _bogusGenerator.Name.FullName(); - string databaseName = _bogusGenerator.Name.FullName(); + string serverName = BogusGenerator.Name.FullName(); + string databaseName = BogusGenerator.Name.FullName(); var connectionString = $"Server={serverName};Database={databaseName};User=admin;Password=123"; - string tableName = _bogusGenerator.Name.FullName(); - string operationName = _bogusGenerator.Name.FullName(); - bool isSuccessful = _bogusGenerator.Random.Bool(); - DateTimeOffset startTime = _bogusGenerator.Date.PastOffset(); - var duration = _bogusGenerator.Date.Timespan(); + string tableName = BogusGenerator.Name.FullName(); + string operationName = BogusGenerator.Name.FullName(); + bool isSuccessful = BogusGenerator.Random.Bool(); + DateTimeOffset startTime = BogusGenerator.Date.PastOffset(); + var duration = BogusGenerator.Date.Timespan(); // Act logger.LogSqlDependency(connectionString, tableName, operationName, startTime, duration, isSuccessful); @@ -251,12 +485,12 @@ public void LogSqlDependencyConnectionStringWithDurationMeasurement_ValidArgumen { // Arrange var logger = new TestLogger(); - string serverName = _bogusGenerator.Lorem.Word(); - string databaseName = _bogusGenerator.Lorem.Word(); + string serverName = BogusGenerator.Lorem.Word(); + string databaseName = BogusGenerator.Lorem.Word(); var connectionString = $"Server={serverName};Database={databaseName};User=admin;Password=123"; - string tableName = _bogusGenerator.Lorem.Word(); - string operationName = _bogusGenerator.Lorem.Word(); - bool isSuccessful = _bogusGenerator.Random.Bool(); + string tableName = BogusGenerator.Lorem.Word(); + string operationName = BogusGenerator.Lorem.Word(); + bool isSuccessful = BogusGenerator.Random.Bool(); var measurement = DurationMeasurement.Start(); DateTimeOffset startTime = measurement.StartTime; @@ -264,7 +498,7 @@ public void LogSqlDependencyConnectionStringWithDurationMeasurement_ValidArgumen TimeSpan duration = measurement.Elapsed; // Act - logger.LogSqlDependency(connectionString, tableName, operationName, isSuccessful, measurement); + logger.LogSqlDependency(connectionString, tableName: tableName, operationName, isSuccessful, measurement); // Assert DependencyLogEntry dependency = logger.GetMessageAsDependency(); @@ -277,22 +511,127 @@ public void LogSqlDependencyConnectionStringWithDurationMeasurement_ValidArgumen Assert.Equal(isSuccessful, dependency.IsSuccessful); } + [Fact] + public void LogSqlDependencyConnectionStringWithSqlCommandWithDurationMeasurement_ValidArguments_Succeeds() + { + // Arrange + var logger = new TestLogger(); + string serverName = BogusGenerator.Lorem.Word(); + string databaseName = BogusGenerator.Lorem.Word(); + var connectionString = $"Server={serverName};Database={databaseName};User=admin;Password=123"; + string sqlCommand = BogusGenerator.Lorem.Word(); + bool isSuccessful = BogusGenerator.Random.Bool(); + + var measurement = DurationMeasurement.Start(); + DateTimeOffset startTime = measurement.StartTime; + measurement.Dispose(); + TimeSpan duration = measurement.Elapsed; + + string key = BogusGenerator.Lorem.Word(); + string value = BogusGenerator.Lorem.Word(); + var context = new Dictionary { [key] = value }; + + // Act + logger.LogSqlDependency(connectionString, sqlCommand, isSuccessful, measurement, context); + + // Assert + DependencyLogEntry dependency = logger.GetMessageAsDependency(); + Assert.Equal(serverName, dependency.TargetName); + Assert.Equal(databaseName, dependency.DependencyName); + Assert.Equal(sqlCommand, dependency.DependencyData); + Assert.Equal(startTime.ToString(FormatSpecifiers.InvariantTimestampFormat), dependency.StartTime); + Assert.Equal(duration, dependency.Duration); + Assert.Equal(isSuccessful, dependency.IsSuccessful); + Assert.Equal(value, Assert.Contains(key, dependency.Context)); + } + + [Fact] + public void LogSqlDependencyConnectionStringWithSqlCommandWithDurationMeasurementWithDependencyId_ValidArguments_Succeeds() + { + // Arrange + var logger = new TestLogger(); + string serverName = BogusGenerator.Lorem.Word(); + string databaseName = BogusGenerator.Lorem.Word(); + var connectionString = $"Server={serverName};Database={databaseName};User=admin;Password=123"; + string sqlCommand = BogusGenerator.Lorem.Word(); + string dependencyId = BogusGenerator.Lorem.Word(); + bool isSuccessful = BogusGenerator.Random.Bool(); + + var measurement = DurationMeasurement.Start(); + DateTimeOffset startTime = measurement.StartTime; + measurement.Dispose(); + TimeSpan duration = measurement.Elapsed; + + string key = BogusGenerator.Lorem.Word(); + string value = BogusGenerator.Lorem.Word(); + var context = new Dictionary { [key] = value }; + + // Act + logger.LogSqlDependency(connectionString, sqlCommand, isSuccessful, measurement, dependencyId, context); + + // Assert + DependencyLogEntry dependency = logger.GetMessageAsDependency(); + Assert.Equal(serverName, dependency.TargetName); + Assert.Equal(databaseName, dependency.DependencyName); + Assert.Equal(sqlCommand, dependency.DependencyData); + Assert.Equal(dependencyId, dependency.DependencyId); + Assert.Equal(startTime.ToString(FormatSpecifiers.InvariantTimestampFormat), dependency.StartTime); + Assert.Equal(duration, dependency.Duration); + Assert.Equal(isSuccessful, dependency.IsSuccessful); + Assert.Equal(value, Assert.Contains(key, dependency.Context)); + } + [Theory] [ClassData(typeof(Blanks))] public void LogSqlDependencyConnectionStringWithDurationMeasurement_WithoutConnectionString_Fails(string connectionString) { // Arrange var logger = new TestLogger(); - string tableName = _bogusGenerator.Name.FullName(); - string operationName = _bogusGenerator.Name.FullName(); - bool isSuccessful = _bogusGenerator.Random.Bool(); + string tableName = BogusGenerator.Name.FullName(); + string operationName = BogusGenerator.Name.FullName(); + bool isSuccessful = BogusGenerator.Random.Bool(); + + var measurement = DurationMeasurement.Start(); + measurement.Dispose(); + + // Act / Assert + Assert.ThrowsAny( + () => logger.LogSqlDependency(connectionString, tableName: tableName, operationName, isSuccessful, measurement)); + } + + [Theory] + [ClassData(typeof(Blanks))] + public void LogSqlDependencyConnectionStringWithSqlCommandWithDurationMeasurement_WithoutConnectionString_Fails(string connectionString) + { + // Arrange + var logger = new TestLogger(); + string sqlCommand = BogusGenerator.Name.FullName(); + bool isSuccessful = BogusGenerator.Random.Bool(); + + var measurement = DurationMeasurement.Start(); + measurement.Dispose(); + + // Act / Assert + Assert.ThrowsAny( + () => logger.LogSqlDependency(connectionString, sqlCommand, isSuccessful, measurement)); + } + + [Theory] + [ClassData(typeof(Blanks))] + public void LogSqlDependencyConnectionStringWithSqlCommandWithDurationMeasurementWithDependencyId_WithoutConnectionString_Fails(string connectionString) + { + // Arrange + var logger = new TestLogger(); + string sqlCommand = BogusGenerator.Name.FullName(); + string dependencyId = BogusGenerator.Name.FullName(); + bool isSuccessful = BogusGenerator.Random.Bool(); var measurement = DurationMeasurement.Start(); measurement.Dispose(); // Act / Assert Assert.ThrowsAny( - () => logger.LogSqlDependency(connectionString, tableName, operationName, isSuccessful, measurement)); + () => logger.LogSqlDependency(connectionString, sqlCommand, isSuccessful, measurement, dependencyId)); } [Theory] @@ -301,18 +640,18 @@ public void LogSqlDependencyConnectionStringWithDurationMeasurement_WithoutTable { // Arrange var logger = new TestLogger(); - string serverName = _bogusGenerator.Name.FullName(); - string databaseName = _bogusGenerator.Name.FullName(); + string serverName = BogusGenerator.Name.FullName(); + string databaseName = BogusGenerator.Name.FullName(); var connectionString = $"Server={serverName};Database={databaseName};User=admin;Password=123"; - string operationName = _bogusGenerator.Name.FullName(); - bool isSuccessful = _bogusGenerator.Random.Bool(); + string operationName = BogusGenerator.Name.FullName(); + bool isSuccessful = BogusGenerator.Random.Bool(); var measurement = DurationMeasurement.Start(); measurement.Dispose(); // Act / Assert Assert.ThrowsAny( - () => logger.LogSqlDependency(connectionString, tableName, operationName, isSuccessful, measurement)); + () => logger.LogSqlDependency(connectionString, tableName: tableName, operationName, isSuccessful, measurement)); } [Theory] @@ -321,18 +660,18 @@ public void LogSqlDependencyConnectionStringWithDurationMeasurement_WithoutOpera { // Arrange var logger = new TestLogger(); - string serverName = _bogusGenerator.Name.FullName(); - string databaseName = _bogusGenerator.Name.FullName(); + string serverName = BogusGenerator.Name.FullName(); + string databaseName = BogusGenerator.Name.FullName(); var connectionString = $"Server={serverName};Database={databaseName};User=admin;Password=123"; - string tableName = _bogusGenerator.Name.FullName(); - bool isSuccessful = _bogusGenerator.Random.Bool(); + string tableName = BogusGenerator.Name.FullName(); + bool isSuccessful = BogusGenerator.Random.Bool(); var measurement = DurationMeasurement.Start(); measurement.Dispose(); // Act / Assert Assert.ThrowsAny( - () => logger.LogSqlDependency(connectionString, tableName, operationName, isSuccessful, measurement)); + () => logger.LogSqlDependency(connectionString, tableName: tableName, operationName, isSuccessful, measurement)); } [Fact] @@ -340,16 +679,49 @@ public void LogSqlDependencyConnectionStringWithDurationMeasurement_WithoutMeasu { // Arrange var logger = new TestLogger(); - string serverName = _bogusGenerator.Name.FullName(); - string databaseName = _bogusGenerator.Name.FullName(); + string serverName = BogusGenerator.Name.FullName(); + string databaseName = BogusGenerator.Name.FullName(); + var connectionString = $"Server={serverName};Database={databaseName};User=admin;Password=123"; + string tableName = BogusGenerator.Name.FullName(); + string operationName = BogusGenerator.Name.FullName(); + bool isSuccessful = BogusGenerator.Random.Bool(); + + // Act / Assert + Assert.ThrowsAny( + () => logger.LogSqlDependency(connectionString, tableName: tableName, operationName, isSuccessful, measurement: (DurationMeasurement)null)); + } + + [Fact] + public void LogSqlDependencyConnectionStringWithSqlCommandWithDurationMeasurement_WithoutMeasurement_Fails() + { + // 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 = BogusGenerator.Name.FullName(); + bool isSuccessful = BogusGenerator.Random.Bool(); + + // Act / Assert + Assert.ThrowsAny( + () => logger.LogSqlDependency(connectionString, sqlCommand, isSuccessful, measurement: null)); + } + + [Fact] + public void LogSqlDependencyConnectionStringWithSqlCommandWithDurationMeasurementWithDependencyId_WithoutMeasurement_Fails() + { + // 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 tableName = _bogusGenerator.Name.FullName(); - string operationName = _bogusGenerator.Name.FullName(); - bool isSuccessful = _bogusGenerator.Random.Bool(); + string sqlCommand = BogusGenerator.Name.FullName(); + string dependencyId = BogusGenerator.Name.FullName(); + bool isSuccessful = BogusGenerator.Random.Bool(); // Act / Assert Assert.ThrowsAny( - () => logger.LogSqlDependency(connectionString, tableName, operationName, isSuccessful, measurement: (DurationMeasurement)null)); + () => logger.LogSqlDependency(connectionString, sqlCommand, isSuccessful, measurement: null, dependencyId)); } [Fact] @@ -357,31 +729,65 @@ public void LogSqlDependencyConnectionString_WithNegativeDuration_Fails() { // Arrange var logger = new TestLogger(); - string serverName = _bogusGenerator.Name.FullName(); - string databaseName = _bogusGenerator.Name.FullName(); + string serverName = BogusGenerator.Name.FullName(); + string databaseName = BogusGenerator.Name.FullName(); var connectionString = $"Server={serverName};Database={databaseName};User=admin;Password=123"; - string tableName = _bogusGenerator.Name.FullName(); - string operationName = _bogusGenerator.Name.FullName(); - bool isSuccessful = _bogusGenerator.Random.Bool(); - DateTimeOffset startTime = _bogusGenerator.Date.PastOffset(); + string tableName = BogusGenerator.Name.FullName(); + string operationName = BogusGenerator.Name.FullName(); + bool isSuccessful = BogusGenerator.Random.Bool(); + DateTimeOffset startTime = BogusGenerator.Date.PastOffset(); TimeSpan duration = TimeSpanGenerator.GeneratePositiveDuration().Negate(); // Act / Assert Assert.ThrowsAny(() => logger.LogSqlDependency(connectionString, tableName, operationName, startTime, duration, isSuccessful)); } + [Fact] + public void LogSqlDependencyConnectionStringWithSqlCommand_WithNegativeDuration_Fails() + { + // 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 = BogusGenerator.Name.FullName(); + bool isSuccessful = BogusGenerator.Random.Bool(); + DateTimeOffset startTime = BogusGenerator.Date.PastOffset(); + TimeSpan duration = TimeSpanGenerator.GeneratePositiveDuration().Negate(); + + // Act / Assert + Assert.ThrowsAny(() => logger.LogSqlDependency(connectionString, sqlCommand, isSuccessful, startTime, duration)); + } + + [Fact] + public void LogSqlDependencyConnectionStringWithSqlCommandWithDependencyId_WithNegativeDuration_Fails() + { + // 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 = BogusGenerator.Name.FullName(); + string dependenyId = BogusGenerator.Name.FullName(); + bool isSuccessful = BogusGenerator.Random.Bool(); + DateTimeOffset startTime = BogusGenerator.Date.PastOffset(); + TimeSpan duration = TimeSpanGenerator.GeneratePositiveDuration().Negate(); + + // Act / Assert + Assert.ThrowsAny(() => logger.LogSqlDependency(connectionString, sqlCommand, isSuccessful, startTime, duration, dependenyId)); + } + [Theory] - [InlineData(null)] - [InlineData("")] + [ClassData(typeof(Blanks))] public void LogSqlDependencyConnectionString_EmptyConnectionString_Fails(string connectionString) { // Arrange var logger = new TestLogger(); - string tableName = _bogusGenerator.Name.FullName(); - string operationName = _bogusGenerator.Name.FullName(); - bool isSuccessful = _bogusGenerator.Random.Bool(); - DateTimeOffset startTime = _bogusGenerator.Date.PastOffset(); - var duration = _bogusGenerator.Date.Timespan(); + string tableName = BogusGenerator.Name.FullName(); + string operationName = BogusGenerator.Name.FullName(); + bool isSuccessful = BogusGenerator.Random.Bool(); + DateTimeOffset startTime = BogusGenerator.Date.PastOffset(); + var duration = BogusGenerator.Date.Timespan(); // Act / Assert Assert.Throws( @@ -389,15 +795,14 @@ public void LogSqlDependencyConnectionString_EmptyConnectionString_Fails(string } [Theory] - [InlineData(null)] - [InlineData("")] + [ClassData(typeof(Blanks))] public void LogSqlDependencyWithDependencyMeasurementConnectionString_EmptyConnectionString_Fails(string connectionString) { // Arrange var logger = new TestLogger(); - string tableName = _bogusGenerator.Name.FullName(); - string operationName = _bogusGenerator.Name.FullName(); - bool isSuccessful = _bogusGenerator.Random.Bool(); + string tableName = BogusGenerator.Name.FullName(); + string operationName = BogusGenerator.Name.FullName(); + bool isSuccessful = BogusGenerator.Random.Bool(); using (var measurement = DependencyMeasurement.Start(operationName)) { @@ -413,46 +818,112 @@ public void LogSqlDependency_NoServerNameWasSpecified_ThrowsException() // Arrange var logger = new TestLogger(); string serverName = null; - string databaseName = _bogusGenerator.Name.FullName(); - string tableName = _bogusGenerator.Name.FullName(); - string operationName = _bogusGenerator.Name.FullName(); - bool isSuccessful = _bogusGenerator.Random.Bool(); - DateTimeOffset startTime = _bogusGenerator.Date.PastOffset(); - var duration = _bogusGenerator.Date.Timespan(); + string databaseName = BogusGenerator.Name.FullName(); + string tableName = BogusGenerator.Name.FullName(); + string operationName = BogusGenerator.Name.FullName(); + bool isSuccessful = BogusGenerator.Random.Bool(); + DateTimeOffset startTime = BogusGenerator.Date.PastOffset(); + var duration = BogusGenerator.Date.Timespan(); // Act & Arrange Assert.Throws(() => logger.LogSqlDependency(serverName, databaseName, tableName, operationName, isSuccessful, startTime, duration)); } + [Fact] + public void LogSqlDependencyWithSqlCommand_NoServerNameWasSpecified_ThrowsException() + { + // Arrange + var logger = new TestLogger(); + string serverName = null; + string databaseName = BogusGenerator.Name.FullName(); + string sqlCommand = BogusGenerator.Name.FullName(); + bool isSuccessful = BogusGenerator.Random.Bool(); + DateTimeOffset startTime = BogusGenerator.Date.PastOffset(); + var duration = BogusGenerator.Date.Timespan(); + + // Act & Arrange + Assert.Throws(() => logger.LogSqlDependency(serverName, databaseName, sqlCommand, isSuccessful, startTime, duration)); + } + + [Fact] + public void LogSqlDependencyWithSqlCommandWithDependencyId_NoServerNameWasSpecified_ThrowsException() + { + // Arrange + var logger = new TestLogger(); + string serverName = null; + string databaseName = BogusGenerator.Name.FullName(); + string sqlCommand = BogusGenerator.Name.FullName(); + string dependencyId = BogusGenerator.Name.FullName(); + bool isSuccessful = BogusGenerator.Random.Bool(); + DateTimeOffset startTime = BogusGenerator.Date.PastOffset(); + var duration = BogusGenerator.Date.Timespan(); + + // Act & Arrange + Assert.Throws(() => logger.LogSqlDependency(serverName, databaseName, sqlCommand, isSuccessful, startTime, duration, dependencyId)); + } + [Fact] public void LogSqlDependency_NoDatabaseNameWasSpecified_ThrowsException() { // Arrange var logger = new TestLogger(); - string serverName = _bogusGenerator.Name.FullName(); + string serverName = BogusGenerator.Name.FullName(); string databaseName = null; - string tableName = _bogusGenerator.Name.FullName(); - string operationName = _bogusGenerator.Name.FullName(); - bool isSuccessful = _bogusGenerator.Random.Bool(); - DateTimeOffset startTime = _bogusGenerator.Date.PastOffset(); - var duration = _bogusGenerator.Date.Timespan(); + string tableName = BogusGenerator.Name.FullName(); + string operationName = BogusGenerator.Name.FullName(); + bool isSuccessful = BogusGenerator.Random.Bool(); + DateTimeOffset startTime = BogusGenerator.Date.PastOffset(); + var duration = BogusGenerator.Date.Timespan(); // Act & Arrange Assert.Throws(() => logger.LogSqlDependency(serverName, databaseName, tableName, operationName, isSuccessful, startTime, duration)); } + [Fact] + public void LogSqlDependencyWithSqlCommand_NoDatabaseNameWasSpecified_ThrowsException() + { + // Arrange + var logger = new TestLogger(); + string serverName = BogusGenerator.Name.FullName(); + string databaseName = null; + string sqlCommand = BogusGenerator.Name.FullName(); + bool isSuccessful = BogusGenerator.Random.Bool(); + DateTimeOffset startTime = BogusGenerator.Date.PastOffset(); + var duration = BogusGenerator.Date.Timespan(); + + // Act & Arrange + Assert.Throws(() => logger.LogSqlDependency(serverName, databaseName, sqlCommand, isSuccessful, startTime, duration)); + } + + [Fact] + public void LogSqlDependencyWithSqlCommandWithDependencyId_NoDatabaseNameWasSpecified_ThrowsException() + { + // Arrange + var logger = new TestLogger(); + string serverName = BogusGenerator.Name.FullName(); + string databaseName = null; + string sqlCommand = BogusGenerator.Name.FullName(); + string dependencyId = BogusGenerator.Name.FullName(); + bool isSuccessful = BogusGenerator.Random.Bool(); + DateTimeOffset startTime = BogusGenerator.Date.PastOffset(); + var duration = BogusGenerator.Date.Timespan(); + + // Act & Arrange + Assert.Throws(() => logger.LogSqlDependency(serverName, databaseName, sqlCommand, isSuccessful, startTime, duration, dependencyId)); + } + [Fact] public void LogSqlDependency_NoTableNameWasSpecified_ThrowsException() { // Arrange var logger = new TestLogger(); - string serverName = _bogusGenerator.Name.FullName(); - string databaseName = _bogusGenerator.Name.FullName(); + string serverName = BogusGenerator.Name.FullName(); + string databaseName = BogusGenerator.Name.FullName(); string tableName = null; - string operationName = _bogusGenerator.Name.FullName(); - bool isSuccessful = _bogusGenerator.Random.Bool(); - DateTimeOffset startTime = _bogusGenerator.Date.PastOffset(); - var duration = _bogusGenerator.Date.Timespan(); + string operationName = BogusGenerator.Name.FullName(); + bool isSuccessful = BogusGenerator.Random.Bool(); + DateTimeOffset startTime = BogusGenerator.Date.PastOffset(); + var duration = BogusGenerator.Date.Timespan(); // Act & Arrange Assert.Throws(() => logger.LogSqlDependency(serverName, databaseName, tableName, operationName, isSuccessful, startTime, duration)); @@ -463,13 +934,13 @@ public void LogSqlDependency_NoOperationNameWasSpecified_ThrowsException() { // Arrange var logger = new TestLogger(); - string serverName = _bogusGenerator.Name.FullName(); - string databaseName = _bogusGenerator.Name.FullName(); - string tableName = _bogusGenerator.Name.FullName(); + string serverName = BogusGenerator.Name.FullName(); + string databaseName = BogusGenerator.Name.FullName(); + string tableName = BogusGenerator.Name.FullName(); string operationName = null; - bool isSuccessful = _bogusGenerator.Random.Bool(); - DateTimeOffset startTime = _bogusGenerator.Date.PastOffset(); - var duration = _bogusGenerator.Date.Timespan(); + bool isSuccessful = BogusGenerator.Random.Bool(); + DateTimeOffset startTime = BogusGenerator.Date.PastOffset(); + var duration = BogusGenerator.Date.Timespan(); // Act & Arrange Assert.Throws(() => logger.LogSqlDependency(serverName, databaseName, tableName, operationName, isSuccessful, startTime, duration)); @@ -480,12 +951,12 @@ public void LogSqlDependencyWithDependencyMeasurementConnectionString_ValidArgum { // Arrange var logger = new TestLogger(); - string serverName = _bogusGenerator.Name.FullName(); - string databaseName = _bogusGenerator.Name.FullName(); + string serverName = BogusGenerator.Name.FullName(); + string databaseName = BogusGenerator.Name.FullName(); var connectionString = $"Server={serverName};Database={databaseName};User=admin;Password=123"; - string tableName = _bogusGenerator.Name.FullName(); - string operationName = _bogusGenerator.Name.FullName(); - bool isSuccessful = _bogusGenerator.Random.Bool(); + string tableName = BogusGenerator.Name.FullName(); + string operationName = BogusGenerator.Name.FullName(); + bool isSuccessful = BogusGenerator.Random.Bool(); var measurement = DependencyMeasurement.Start(operationName); DateTimeOffset startTime = measurement.StartTime; From acf566aaa58e60c301cdf8c0582882a5d493233f Mon Sep 17 00:00:00 2001 From: Stijn Moreels <9039753+stijnmoreels@users.noreply.github.com> Date: Wed, 1 Jun 2022 08:23:52 +0200 Subject: [PATCH 3/3] feat: add dependency id to iot hub dep tracking (#379) * feat: add dependency id to iot hub dep tracking * pr-fix: update w corret iot hub name in connection string in unit test * Delete local.settings.json * pr-fix: update with correct iot hub name in connection string in unit tests * pr-style: remove blank line * pr-sug: add better description for duration measurement * pr-sug: remove 'latency' from duration measurement description --- .../ILoggerHttpDependencyExtensions.cs | 4 +- .../Extensions/ILoggerRequestExtensions.cs | 8 +- ...LoggerAzureKeyVaultDependencyExtensions.cs | 4 +- .../ILoggerAzureSearchDependencyExtensions.cs | 4 +- .../ILoggerBlobStorageDependencyExtensions.cs | 4 +- .../ILoggerCustomDependencyExtensions.cs | 16 +- .../ILoggerHttpDependencyExtensions.cs | 4 +- .../ILoggerIotHubDependencyExtensions.cs | 70 +++- .../Extensions/ILoggerRequestExtensions.cs | 8 +- .../ILoggerServiceBusDependencyExtensions.cs | 12 +- .../ILoggerServiceBusRequestExtensions.cs | 12 +- .../ILoggerSqlDependencyExtensions.cs | 2 +- ...ILoggerTableStorageDependencyExtensions.cs | 4 +- .../Extensions/ILoggerExtensions.cs | 65 +++- .../Extensions/ILoggerExtensions.cs | 2 +- .../Sinks/ApplicationInsights/IoTHubTests.cs | 33 +- .../Logging/IoTHubDependencyLoggingTests.cs | 367 ++++++++++++++++-- 17 files changed, 517 insertions(+), 102 deletions(-) diff --git a/src/Arcus.Observability.Telemetry.AspNetCore/Extensions/ILoggerHttpDependencyExtensions.cs b/src/Arcus.Observability.Telemetry.AspNetCore/Extensions/ILoggerHttpDependencyExtensions.cs index 808936b8..21115528 100644 --- a/src/Arcus.Observability.Telemetry.AspNetCore/Extensions/ILoggerHttpDependencyExtensions.cs +++ b/src/Arcus.Observability.Telemetry.AspNetCore/Extensions/ILoggerHttpDependencyExtensions.cs @@ -25,7 +25,7 @@ public static class ILoggerHttpDependencyExtensions /// The logger to track the telemetry. /// The request that started the HTTP communication. /// The status code that was returned by the service for this HTTP communication. - /// The measuring the latency of the HTTP dependency. + /// The measurement of the duration to call the dependency. /// The context that provides more insights on the dependency that was measured. /// Thrown when the , , or is null. /// @@ -53,7 +53,7 @@ public static void LogHttpDependency( /// The logger to track the telemetry. /// The request that started the HTTP communication. /// The status code that was returned by the service for this HTTP communication. - /// The measuring the latency of the HTTP dependency. + /// The measurement of the duration to call the dependency. /// The ID of the dependency to link as parent ID. /// The context that provides more insights on the dependency that was measured. /// Thrown when the , , or is null. diff --git a/src/Arcus.Observability.Telemetry.AspNetCore/Extensions/ILoggerRequestExtensions.cs b/src/Arcus.Observability.Telemetry.AspNetCore/Extensions/ILoggerRequestExtensions.cs index 3c2916f3..c0a1579b 100644 --- a/src/Arcus.Observability.Telemetry.AspNetCore/Extensions/ILoggerRequestExtensions.cs +++ b/src/Arcus.Observability.Telemetry.AspNetCore/Extensions/ILoggerRequestExtensions.cs @@ -51,7 +51,7 @@ public static void LogRequest(this ILogger logger, HttpRequest request, HttpResp /// The logger to track the telemetry. /// The incoming HTTP request that was processed. /// The outgoing HTTP response that was created. - /// The instance to measure the latency duration of the HTTP request. + /// The instance to measure the duration of the HTTP request. /// The context that provides more insights on the tracked HTTP request. /// Thrown when the , , or is null /// Thrown when the 's status code is outside the 0-999 range inclusively. @@ -143,7 +143,7 @@ public static void LogRequest(this ILogger logger, HttpRequest request, HttpResp /// The incoming HTTP request that was processed. /// The outgoing HTTP response that was created. /// The name of the operation of the HTTP request. - /// The instance to measure the latency duration of the HTTP request. + /// The instance to measure the duration of the HTTP request. /// The context that provides more insights on the tracked HTTP request. /// Thrown when the , , or the is null /// Thrown when the 's status code is outside the 0-999 range inclusively. @@ -237,7 +237,7 @@ public static void LogRequest(this ILogger logger, HttpRequest request, int resp /// The logger to track the telemetry. /// The incoming HTTP request that was processed. /// The HTTP status code returned by the service. - /// The instance to measure the latency duration of the HTTP request. + /// The instance to measure the duration of the HTTP request. /// The context that provides more insights on the tracked HTTP request. /// Thrown when the , or is null /// Thrown when the is outside the 0-999 range inclusively. @@ -335,7 +335,7 @@ public static void LogRequest(this ILogger logger, HttpRequest request, int resp /// The incoming HTTP request that was processed. /// The HTTP status code returned by the service. /// The name of the operation of the HTTP request. - /// The instance to measure the latency duration of the HTTP request. + /// The instance to measure the duration of the HTTP request. /// The context that provides more insights on the tracked HTTP request. /// Thrown when the , , or the is null. /// Thrown when the is outside the 0-999 inclusively. diff --git a/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerAzureKeyVaultDependencyExtensions.cs b/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerAzureKeyVaultDependencyExtensions.cs index f0927fb4..603a16f0 100644 --- a/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerAzureKeyVaultDependencyExtensions.cs +++ b/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerAzureKeyVaultDependencyExtensions.cs @@ -51,7 +51,7 @@ public static void LogAzureKeyVaultDependency( /// The URI pointing to the Azure Key Vault resource. /// The secret that is being used within the Azure Key Vault resource. /// The indication whether or not the operation was successful. - /// The measuring the latency to call the dependency. + /// The measurement of the duration to call the dependency. /// The context that provides more insights on the dependency that was measured. /// Thrown when the or is null. /// Thrown when the or is blank. @@ -114,7 +114,7 @@ public static void LogAzureKeyVaultDependency( /// The URI pointing to the Azure Key Vault resource. /// The secret that is being used within the Azure Key Vault resource. /// The indication whether or not the operation was successful. - /// The measuring the latency to call the dependency. + /// The measurement of the duration to call the dependency. /// The ID of the dependency to link as parent ID. /// The context that provides more insights on the dependency that was measured. /// Thrown when the or is null. diff --git a/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerAzureSearchDependencyExtensions.cs b/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerAzureSearchDependencyExtensions.cs index 52167d02..74852dee 100644 --- a/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerAzureSearchDependencyExtensions.cs +++ b/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerAzureSearchDependencyExtensions.cs @@ -50,7 +50,7 @@ public static void LogAzureSearchDependency( /// The name of the Azure Search service. /// The name of the operation to execute on the Azure Search service. /// The indication whether or not the operation was successful. - /// The measuring the latency to call the dependency. + /// The measurement of the duration to call the dependency. /// The context that provides more insights on the dependency that was measured. /// Thrown when the or is null. /// Thrown when the or is blank. @@ -79,7 +79,7 @@ public static void LogAzureSearchDependency( /// The name of the Azure Search service. /// The name of the operation to execute on the Azure Search service. /// The indication whether or not the operation was successful. - /// The measuring the latency to call the dependency. + /// The measurement of the duration to call the dependency. /// The ID of the dependency to link as parent ID. /// The context that provides more insights on the dependency that was measured. /// Thrown when the or is null. diff --git a/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerBlobStorageDependencyExtensions.cs b/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerBlobStorageDependencyExtensions.cs index 6c02c370..24ddb66c 100644 --- a/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerBlobStorageDependencyExtensions.cs +++ b/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerBlobStorageDependencyExtensions.cs @@ -48,7 +48,7 @@ public static void LogBlobStorageDependency( /// The account of the storage resource. /// The name of the Blob Container resource. /// The indication whether or not the operation was successful. - /// The measuring the latency to call the dependency. + /// The measurement of the duration to call the dependency. /// The context that provides more insights on the dependency that was measured. /// Thrown when the or is null. /// Thrown when the or is blank. @@ -75,7 +75,7 @@ public static void LogBlobStorageDependency( /// The account of the storage resource. /// The name of the Blob Container resource. /// The indication whether or not the operation was successful. - /// The measuring the latency to call the dependency. + /// The measurement of the duration to call the dependency. /// The ID of the dependency to link as parent ID. /// The context that provides more insights on the dependency that was measured. /// Thrown when the or is null. diff --git a/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerCustomDependencyExtensions.cs b/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerCustomDependencyExtensions.cs index 6a80e326..989d7c70 100644 --- a/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerCustomDependencyExtensions.cs +++ b/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerCustomDependencyExtensions.cs @@ -50,7 +50,7 @@ public static void LogDependency( /// The custom type of dependency. /// The custom data of dependency. /// The indication whether or not the operation was successful. - /// The measuring the latency to call the dependency. + /// The measurement of the duration to call the dependency. /// The context that provides more insights on the dependency that was measured. /// /// Thrown when the , , is null. @@ -79,7 +79,7 @@ public static void LogDependency( /// The custom type of dependency. /// The custom data of dependency. /// The indication whether or not the operation was successful. - /// The measuring the latency to call the dependency. + /// The measurement of the duration to call the dependency. /// The ID of the dependency to link as parent ID. /// The context that provides more insights on the dependency that was measured. /// @@ -143,7 +143,7 @@ public static void LogDependency( /// The custom data of dependency. /// The indication whether or not the operation was successful. /// The name of the dependency. - /// The measuring the latency to call the dependency. + /// The measurement of the duration to call the dependency. /// The context that provides more insights on the dependency that was measured. /// /// Thrown when the , , is null. @@ -174,7 +174,7 @@ public static void LogDependency( /// The custom data of dependency. /// The indication whether or not the operation was successful. /// The name of the dependency. - /// The measuring the latency to call the dependency. + /// The measurement of the duration to call the dependency. /// The ID of the dependency to link as parent ID. /// The context that provides more insights on the dependency that was measured. /// @@ -375,7 +375,7 @@ public static void LogDependency( /// The custom data of dependency. /// The name of the dependency target. /// The indication whether or not the operation was successful. - /// The measuring the latency to call the dependency. + /// The measurement of the duration to call the dependency. /// The context that provides more insights on the dependency that was measured. /// /// Thrown when the , , is null. @@ -406,7 +406,7 @@ public static void LogDependency( /// The custom data of dependency. /// The name of the dependency target. /// The indication whether or not the operation was successful. - /// The measuring the latency to call the dependency. + /// The measurement of the duration to call the dependency. /// The ID of the dependency to link as parent ID. /// The context that provides more insights on the dependency that was measured. /// @@ -474,7 +474,7 @@ public static void LogDependency( /// The name of the dependency target. /// The indication whether or not the operation was successful. /// The name of the dependency. - /// The measuring the latency to call the dependency. + /// The measurement of the duration to call the dependency. /// The context that provides more insights on the dependency that was measured. /// /// Thrown when the , , is null. @@ -507,7 +507,7 @@ public static void LogDependency( /// The name of the dependency target. /// The indication whether or not the operation was successful. /// The name of the dependency. - /// The measuring the latency to call the dependency. + /// The measurement of the duration to call the dependency. /// The ID of the dependency to link as parent ID. /// The context that provides more insights on the dependency that was measured. /// diff --git a/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerHttpDependencyExtensions.cs b/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerHttpDependencyExtensions.cs index e9b06e66..856239cf 100644 --- a/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerHttpDependencyExtensions.cs +++ b/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerHttpDependencyExtensions.cs @@ -50,7 +50,7 @@ public static void LogHttpDependency( /// The logger to track the telemetry. /// The request that started the HTTP communication. /// The status code that was returned by the service for this HTTP communication. - /// The measuring the latency of the HTTP dependency. + /// The measurement of the duration to call the dependency. /// The context that provides more insights on the dependency that was measured. /// Thrown when the , , or is null. /// @@ -78,7 +78,7 @@ public static void LogHttpDependency( /// The logger to track the telemetry. /// The request that started the HTTP communication. /// The status code that was returned by the service for this HTTP communication. - /// The measuring the latency of the HTTP dependency. + /// The measurement of the duration to call the dependency. /// The ID of the dependency to link as parent ID. /// The context that provides more insights on the dependency that was measured. /// Thrown when the , , or is null. diff --git a/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerIotHubDependencyExtensions.cs b/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerIotHubDependencyExtensions.cs index 7d5f6c91..4b722498 100644 --- a/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerIotHubDependencyExtensions.cs +++ b/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerIotHubDependencyExtensions.cs @@ -44,7 +44,7 @@ public static void LogIotHubDependency( /// The logger to track the telemetry. /// The nme of the IoT Hub resource. /// The indication whether or not the operation was successful. - /// The measuring the latency to call the dependency. + /// The measurement of the duration to call the dependency. /// The context that provides more insights on the dependency that was measured. /// Thrown when the or is null. /// Thrown when the is blank. @@ -66,11 +66,67 @@ public static void LogIotHubDependency( /// Logs an Azure Iot Hub Dependency. /// /// The logger to track the telemetry. - /// Name of the IoT Hub resource - /// Indication whether or not the operation was successful - /// Point in time when the interaction with the dependency was started - /// Duration of the operation - /// Context that provides more insights on the dependency that was measured + /// The nme of the IoT Hub resource. + /// The indication whether or not the operation was successful. + /// The measurement of the duration to call the dependency. + /// The ID of the dependency to link as parent ID. + /// The context that provides more insights on the dependency that was measured. + /// Thrown when the or is null. + /// Thrown when the is blank. + public static void LogIotHubDependency( + this ILogger logger, + string iotHubName, + bool isSuccessful, + DurationMeasurement measurement, + string dependencyId, + Dictionary context = null) + { + Guard.NotNull(logger, nameof(logger), "Requires a logger instance to track telemetry"); + Guard.NotNullOrWhitespace(iotHubName, nameof(iotHubName), "Requires a non-blank resource name of the IoT Hub resource to track a IoT Hub dependency"); + Guard.NotNull(measurement, nameof(measurement), "Requires a dependency measurement instance to track the latency of the IoT Hub resource when tracking a IoT Hub dependency"); + + LogIotHubDependency(logger, iotHubName, isSuccessful, measurement.StartTime, measurement.Elapsed, dependencyId, context); + } + + /// + /// Logs an Azure Iot Hub Dependency. + /// + /// The logger to track the telemetry. + /// The name of the IoT Hub resource. + /// The indication whether or not the operation was successful. + /// The point in time when the interaction with the dependency was started. + /// The duration of the operation. + /// The context that provides more insights on the dependency that was measured. + /// Thrown when the is null. + /// Thrown when the is blank. + /// Thrown when the is a negative time range. + public static void LogIotHubDependency( + this ILogger logger, + string iotHubName, + bool isSuccessful, + DateTimeOffset startTime, + TimeSpan duration, + Dictionary context = null) + { + Guard.NotNull(logger, nameof(logger), "Requires a logger instance to track telemetry"); + 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); + } + + /// + /// Logs an Azure Iot Hub Dependency. + /// + /// The logger to track the telemetry. + /// The name of the IoT Hub resource. + /// The indication whether or not the operation was successful. + /// The point in time when the interaction with the dependency was started. + /// The duration of the operation. + /// The ID of the dependency to link as parent ID. + /// The context that provides more insights on the dependency that was measured. /// Thrown when the is null. /// Thrown when the is blank. /// Thrown when the is a negative time range. @@ -80,6 +136,7 @@ public static void LogIotHubDependency( bool isSuccessful, DateTimeOffset startTime, TimeSpan duration, + string dependencyId, Dictionary context = null) { Guard.NotNull(logger, nameof(logger), "Requires a logger instance to track telemetry"); @@ -95,6 +152,7 @@ public static void LogIotHubDependency( targetName: iotHubName, duration: duration, startTime: startTime, + dependencyId: dependencyId, resultCode: null, isSuccessful: isSuccessful, context: context)); diff --git a/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerRequestExtensions.cs b/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerRequestExtensions.cs index 6c752182..c6c4b22a 100644 --- a/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerRequestExtensions.cs +++ b/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerRequestExtensions.cs @@ -60,7 +60,7 @@ public static void LogRequest( /// The logger to track the telemetry. /// The incoming HTTP request that was processed. /// The outgoing HTTP response that was created. - /// The instance to measure the latency duration of the HTTP request. + /// The instance to measure the duration of the HTTP request. /// The context that provides more insights on the tracked HTTP request. /// /// Thrown when the , , or , or the is null. @@ -171,7 +171,7 @@ public static void LogRequest( /// The incoming HTTP request that was processed. /// The outgoing HTTP response that was created. /// The name of the operation of the request. - /// The instance to measure the latency duration of the HTTP request. + /// The instance to measure the duration of the HTTP request. /// The context that provides more insights on the tracked HTTP request. /// /// Thrown when the , , or , or the is null. @@ -285,7 +285,7 @@ public static void LogRequest( /// The logger to track the telemetry. /// The incoming HTTP request that was processed. /// The HTTP status code returned by the service. - /// The instance to measure the latency duration of the HTTP request. + /// The instance to measure the duration of the HTTP request. /// The context that provides more insights on the tracked HTTP request. /// /// Thrown when the , , or the is null. @@ -401,7 +401,7 @@ public static void LogRequest( /// The incoming HTTP request that was processed. /// The HTTP status code returned by the service. /// The name of the operation of the HTTP request. - /// The instance to measure the latency duration of the HTTP request. + /// The instance to measure the duration of the HTTP request. /// The context that provides more insights on the tracked HTTP request. /// Thrown when the or is null. /// diff --git a/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerServiceBusDependencyExtensions.cs b/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerServiceBusDependencyExtensions.cs index 986006f1..8ffb320c 100644 --- a/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerServiceBusDependencyExtensions.cs +++ b/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerServiceBusDependencyExtensions.cs @@ -42,7 +42,7 @@ public static void LogServiceBusQueueDependency( /// The logger to track the telemetry. /// The name of the Service Bus queue. /// The indication whether or not the operation was successful. - /// The measuring the latency to call the Service Bus dependency. + /// The measurement of the duration to call the dependency. /// The context that provides more insights on the dependency that was measured. /// Thrown when the or is null. /// Thrown when the is blank. @@ -66,7 +66,7 @@ public static void LogServiceBusQueueDependency( /// The logger to track the telemetry. /// The name of the Service Bus queue. /// The indication whether or not the operation was successful. - /// The measuring the latency to call the Service Bus dependency. + /// The measurement of the duration to call the dependency. /// The ID of the dependency to link as parent ID. /// The context that provides more insights on the dependency that was measured. /// Thrown when the or is null. @@ -173,7 +173,7 @@ public static void LogServiceBusTopicDependency( /// The logger to track the telemetry. /// The name of the Service Bus topic. /// The indication whether or not the operation was successful. - /// The measuring the latency to call the Service Bus dependency. + /// The measurement of the duration to call the dependency. /// The context that provides more insights on the dependency that was measured. /// Thrown when the or is null. /// Thrown when the is blank. @@ -197,7 +197,7 @@ public static void LogServiceBusTopicDependency( /// The logger to track the telemetry. /// The name of the Service Bus topic. /// The indication whether or not the operation was successful. - /// The measuring the latency to call the Service Bus dependency. + /// The measurement of the duration to call the dependency. /// The ID of the dependency to link as parent ID. /// The context that provides more insights on the dependency that was measured. /// Thrown when the or is null. @@ -306,7 +306,7 @@ public static void LogServiceBusDependency( /// The logger to track the telemetry. /// The name of the Service Bus entity. /// The indication whether or not the operation was successful. - /// The measuring the latency to call the Service Bus dependency. + /// The measurement of the duration to call the dependency. /// The type of the Service Bus entity. /// The context that provides more insights on the dependency that was measured. /// Thrown when the or is null. @@ -332,7 +332,7 @@ public static void LogServiceBusDependency( /// The logger to track the telemetry. /// The name of the Service Bus entity. /// The indication whether or not the operation was successful. - /// The measuring the latency to call the Service Bus dependency. + /// The measurement of the duration to call the dependency. /// The ID of the dependency to link as parent ID. /// The type of the Service Bus entity. /// The context that provides more insights on the dependency that was measured. diff --git a/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerServiceBusRequestExtensions.cs b/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerServiceBusRequestExtensions.cs index dc3f0307..4d7b6b25 100644 --- a/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerServiceBusRequestExtensions.cs +++ b/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerServiceBusRequestExtensions.cs @@ -23,7 +23,7 @@ public static partial class ILoggerExtensions /// The name of the subscription on the Azure Service Bus topic. /// The optional logical name that can be used to identify the operation that consumes the message. /// The indication whether or not the Azure Service Bus topic request was successfully processed. - /// The instance to measure the latency duration of the Azure Service Bus topic request. + /// The instance to measure the duration of the Azure Service Bus topic request. /// The telemetry context that provides more insights on the Azure Service Bus topic request. /// Thrown when the or the is null. /// @@ -59,7 +59,7 @@ public static void LogServiceBusTopicRequestWithSuffix( /// The name of the subscription on the Azure Service Bus topic. /// The optional logical name that can be used to identify the operation that consumes the message. /// The indication whether or not the Azure Service Bus topic request was successfully processed. - /// The instance to measure the latency duration of the Azure Service Bus topic request. + /// The instance to measure the duration of the Azure Service Bus topic request. /// The telemetry context that provides more insights on the Azure Service Bus topic request. /// Thrown when the or the is null. /// @@ -174,7 +174,7 @@ public static void LogServiceBusTopicRequest( /// The name of the Azure Service Bus queue. /// The optional logical name that can be used to identify the operation that consumes the message. /// The indication whether or not the Azure Service Bus queue request was successfully processed. - /// The instance to measure the latency duration of the Azure Service Bus queue request. + /// The instance to measure the duration of the Azure Service Bus queue request. /// The telemetry context that provides more insights on the Azure Service Bus queue request. /// Thrown when the or the is null. /// Thrown when the or is blank. @@ -205,7 +205,7 @@ public static void LogServiceBusQueueRequestWithSuffix( /// The name of the Azure Service Bus queue. /// The optional logical name that can be used to identify the operation that consumes the message. /// The indication whether or not the Azure Service Bus queue request was successfully processed. - /// The instance to measure the latency duration of the Azure Service Bus queue request. + /// The instance to measure the duration of the Azure Service Bus queue request. /// The telemetry context that provides more insights on the Azure Service Bus queue request. /// Thrown when the or the is null. /// Thrown when the or is blank. @@ -302,7 +302,7 @@ public static void LogServiceBusQueueRequest( /// The name of the Azure Service Bus entity. /// The optional logical name that can be used to identify the operation that consumes the message. /// The indication whether or not the Azure Service Bus request was successfully processed. - /// The instance to measure the latency duration of the Azure Service Bus queue request. + /// The instance to measure the duration of the Azure Service Bus queue request. /// The type of the Azure Service Bus entity. /// The telemetry context that provides more insights on the Azure Service Bus request. /// Thrown when the or the is null. @@ -335,7 +335,7 @@ public static void LogServiceBusRequestWithSuffix( /// The name of the Azure Service Bus entity. /// The optional logical name that can be used to identify the operation that consumes the message. /// The indication whether or not the Azure Service Bus request was successfully processed. - /// The instance to measure the latency duration of the Azure Service Bus queue request. + /// The instance to measure the duration of the Azure Service Bus queue request. /// The type of the Azure Service Bus entity. /// The telemetry context that provides more insights on the Azure Service Bus request. /// Thrown when the or the is null. diff --git a/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerSqlDependencyExtensions.cs b/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerSqlDependencyExtensions.cs index 053196ef..1758f7f2 100644 --- a/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerSqlDependencyExtensions.cs +++ b/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerSqlDependencyExtensions.cs @@ -53,7 +53,7 @@ public static void LogSqlDependency( /// The name of tracked table in the SQL database. /// The name of the operation that was performed on the SQL database. /// The indication whether or not the operation was successful. - /// The measuring the latency to call the SQL dependency. + /// The measurement of the duration to call the dependency. /// The context that provides more insights on the dependency that was measured. /// Thrown when the or is null. /// diff --git a/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerTableStorageDependencyExtensions.cs b/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerTableStorageDependencyExtensions.cs index 444df237..383babeb 100644 --- a/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerTableStorageDependencyExtensions.cs +++ b/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerTableStorageDependencyExtensions.cs @@ -48,7 +48,7 @@ public static void LogTableStorageDependency( /// The account of the storage resource. /// The name of the Table Storage resource. /// The indication whether or not the operation was successful. - /// The measuring the latency to call the Table Storage dependency. + /// The measurement of the duration to call the dependency. /// The context that provides more insights on the dependency that was measured. /// Thrown when the or is null. /// Thrown when the or is blank. @@ -75,7 +75,7 @@ public static void LogTableStorageDependency( /// The account of the storage resource. /// The name of the Table Storage resource. /// The indication whether or not the operation was successful. - /// The measuring the latency to call the Table Storage dependency. + /// The measurement of the duration to call the dependency. /// The ID of the dependency to link as parent ID. /// The context that provides more insights on the dependency that was measured. /// Thrown when the or is null. diff --git a/src/Arcus.Observability.Telemetry.IoT/Extensions/ILoggerExtensions.cs b/src/Arcus.Observability.Telemetry.IoT/Extensions/ILoggerExtensions.cs index 5afd471b..a649da28 100644 --- a/src/Arcus.Observability.Telemetry.IoT/Extensions/ILoggerExtensions.cs +++ b/src/Arcus.Observability.Telemetry.IoT/Extensions/ILoggerExtensions.cs @@ -36,7 +36,7 @@ public static void LogIotHubDependency(this ILogger logger, string iotHubConnect /// The logger instance to track the IoT Hub dependency. /// The connection string to interact with an IoT Hub resource. /// The indication whether or not the operation was successful. - /// The measuring the latency to call the dependency. + /// The measurement of the duration to call the dependency. /// The context that provides more insights on the dependency that was measured. /// Thrown when the is null. /// Thrown when the is blank or is invalid. @@ -54,7 +54,64 @@ public static void LogIotHubDependency( context = context ?? new Dictionary(); - LogIotHubDependency(logger, iotHubConnectionString, isSuccessful, measurement.StartTime, measurement.Elapsed, context); + LogIotHubDependency(logger, iotHubConnectionString, isSuccessful, measurement.StartTime, measurement.Elapsed, dependencyId: null, context); + } + + /// + /// Logs an Azure Iot Hub Dependency. + /// + /// The logger instance to track the IoT Hub dependency. + /// The connection string to interact with an IoT Hub resource. + /// The indication whether or not the operation was successful. + /// The measurement of the duration to call the dependency. + /// The ID of the dependency to link as parent ID. + /// The context that provides more insights on the dependency that was measured. + /// Thrown when the is null. + /// Thrown when the is blank or is invalid. + /// Thrown when the is invalid. + public static void LogIotHubDependency( + this ILogger logger, + string iotHubConnectionString, + bool isSuccessful, + DurationMeasurement measurement, + string dependencyId, + Dictionary context = null) + { + 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"); + Guard.NotNull(measurement, nameof(measurement), "Requires an measurement instance to measure the duration of interaction with the IoT Hub dependency"); + + context = context ?? new Dictionary(); + + LogIotHubDependency(logger, iotHubConnectionString, isSuccessful, measurement.StartTime, measurement.Elapsed, dependencyId, context); + } + + /// + /// Logs an Azure Iot Hub Dependency. + /// + /// The logger instance to track the IoT Hub dependency. + /// The connection string to interact with an IoT Hub resource. + /// The indication whether or not the operation was successful. + /// The point in time when the interaction with the dependency was started. + /// The duration of the operation. + /// The context that provides more insights on the dependency that was measured. + /// Thrown when the is null. + /// Thrown when the is blank or is invalid. + /// Thrown when the is invalid. + public static void LogIotHubDependency( + this ILogger logger, + string iotHubConnectionString, + bool isSuccessful, + DateTimeOffset startTime, + TimeSpan duration, + Dictionary context = null) + { + 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(); + + LogIotHubDependency(logger, iotHubConnectionString, isSuccessful, startTime, duration, dependencyId: null, context); } /// @@ -65,6 +122,7 @@ public static void LogIotHubDependency( /// The indication whether or not the operation was successful. /// The point in time when the interaction with the dependency was started. /// The duration of the operation. + /// The ID of the dependency to link as parent ID. /// The context that provides more insights on the dependency that was measured. /// Thrown when the is null. /// Thrown when the is blank or is invalid. @@ -75,6 +133,7 @@ public static void LogIotHubDependency( bool isSuccessful, DateTimeOffset startTime, TimeSpan duration, + string dependencyId, Dictionary context = null) { Guard.NotNull(logger, nameof(logger), "Requires an logger instance to track the IoT Hub dependency"); @@ -83,7 +142,7 @@ public static void LogIotHubDependency( context = context ?? new Dictionary(); var iotHubConnection = IotHubConnectionStringBuilder.Create(iotHubConnectionString); - logger.LogIotHubDependency(iotHubName: iotHubConnection.HostName, isSuccessful: isSuccessful, startTime: startTime, duration: duration, context: context); + logger.LogIotHubDependency(iotHubName: iotHubConnection.HostName, isSuccessful, startTime, duration, dependencyId, context); } } } diff --git a/src/Arcus.Observability.Telemetry.Sql/Extensions/ILoggerExtensions.cs b/src/Arcus.Observability.Telemetry.Sql/Extensions/ILoggerExtensions.cs index c24c4f91..cac798ba 100644 --- a/src/Arcus.Observability.Telemetry.Sql/Extensions/ILoggerExtensions.cs +++ b/src/Arcus.Observability.Telemetry.Sql/Extensions/ILoggerExtensions.cs @@ -47,7 +47,7 @@ public static void LogSqlDependency( /// The name of tracked table in the SQL database. /// The name of the operation that was performed on the SQL database. /// The indication whether or not the operation was successful. - /// The measuring the latency to call the SQL dependency. + /// The measurement of the duration to call the dependency. /// The context that provides more insights on the dependency that was measured. /// Thrown when the or the is null. /// Thrown when the or is blank. diff --git a/src/Arcus.Observability.Tests.Integration/Serilog/Sinks/ApplicationInsights/IoTHubTests.cs b/src/Arcus.Observability.Tests.Integration/Serilog/Sinks/ApplicationInsights/IoTHubTests.cs index 77be90ed..8a547cf8 100644 --- a/src/Arcus.Observability.Tests.Integration/Serilog/Sinks/ApplicationInsights/IoTHubTests.cs +++ b/src/Arcus.Observability.Tests.Integration/Serilog/Sinks/ApplicationInsights/IoTHubTests.cs @@ -29,18 +29,19 @@ public async Task LogIoTHubDependency_SinksToApplicationInsights_ResultsIEventHu string componentName = BogusGenerator.Commerce.ProductName(); string iotHubName = BogusGenerator.Commerce.ProductName(); string dependencyName = iotHubName; + string dependencyId = BogusGenerator.Random.Guid().ToString(); using (ILoggerFactory loggerFactory = CreateLoggerFactory(config => config.Enrich.WithComponentName(componentName))) { ILogger logger = loggerFactory.CreateLogger(); bool isSuccessful = BogusGenerator.PickRandom(true, false); - DateTimeOffset startTime = BogusGenerator.Date.RecentOffset(days: 0); + DateTimeOffset startTime = DateTimeOffset.Now; TimeSpan duration = BogusGenerator.Date.Timespan(); Dictionary telemetryContext = CreateTestTelemetryContext(); // Act - logger.LogIotHubDependency(iotHubName, isSuccessful, startTime, duration, telemetryContext); + logger.LogIotHubDependency(iotHubName, isSuccessful, startTime, duration, dependencyId, telemetryContext); } // Assert @@ -48,29 +49,37 @@ public async Task LogIoTHubDependency_SinksToApplicationInsights_ResultsIEventHu { await RetryAssertUntilTelemetryShouldBeAvailableAsync(async () => { - EventsResults results = await client.Events.GetDependencyEventsAsync(ApplicationId); + EventsResults results = await client.Events.GetDependencyEventsAsync(ApplicationId, PastHalfHourTimeSpan); Assert.NotEmpty(results.Value); - Assert.Contains(results.Value, result => + AssertX.Any(results.Value, result => { - return result.Dependency.Type == dependencyType - && result.Dependency.Target == iotHubName - && result.Cloud.RoleName == componentName - && result.Dependency.Name == dependencyName; + Assert.Equal(dependencyType, result.Dependency.Type); + Assert.Equal(iotHubName, result.Dependency.Target); + Assert.Equal(componentName, result.Cloud.RoleName); + Assert.Equal(dependencyName, result.Dependency.Name); + Assert.Equal(dependencyId, result.Dependency.Id); }); }); } - AssertX.Any(GetLogEventsFromMemory(), logEvent => { + AssertSerilogLogProperties(dependencyType, iotHubName, dependencyName); + } + + private void AssertSerilogLogProperties(string dependencyType, string iotHubName, string dependencyName) + { + IEnumerable logEvents = GetLogEventsFromMemory(); + AssertX.Any(logEvents, logEvent => + { StructureValue logEntry = logEvent.Properties.GetAsStructureValue(ContextProperties.DependencyTracking.DependencyLogEntry); Assert.NotNull(logEntry); - var actualDependencyType = Assert.Single(logEntry.Properties, prop => prop.Name == nameof(DependencyLogEntry.DependencyType)); + LogEventProperty actualDependencyType = Assert.Single(logEntry.Properties, prop => prop.Name == nameof(DependencyLogEntry.DependencyType)); Assert.Equal(dependencyType, actualDependencyType.Value.ToDecentString(), true); - var actualTargetName = Assert.Single(logEntry.Properties, prop => prop.Name == nameof(DependencyLogEntry.TargetName)); + LogEventProperty actualTargetName = Assert.Single(logEntry.Properties, prop => prop.Name == nameof(DependencyLogEntry.TargetName)); Assert.Equal(iotHubName, actualTargetName.Value.ToDecentString()); - var actualDependencyName = Assert.Single(logEntry.Properties, prop => prop.Name == nameof(DependencyLogEntry.DependencyName)); + LogEventProperty actualDependencyName = Assert.Single(logEntry.Properties, prop => prop.Name == nameof(DependencyLogEntry.DependencyName)); Assert.Equal(dependencyName, actualDependencyName.Value.ToDecentString()); Assert.Single(logEntry.Properties, prop => prop.Name == nameof(DependencyLogEntry.Context)); diff --git a/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/IoTHubDependencyLoggingTests.cs b/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/IoTHubDependencyLoggingTests.cs index 3f1e14ee..319fe267 100644 --- a/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/IoTHubDependencyLoggingTests.cs +++ b/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/IoTHubDependencyLoggingTests.cs @@ -1,8 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Arcus.Observability.Telemetry.Core; using Arcus.Observability.Telemetry.Core.Logging; using Bogus; @@ -14,17 +11,17 @@ namespace Arcus.Observability.Tests.Unit.Telemetry.Logging [Trait("Category", "Unit")] public class IoTHubDependencyLoggingTests { - private readonly Faker _bogusGenerator = new Faker(); + private static readonly Faker BogusGenerator = new Faker(); [Fact] public void LogIotHubDependency_ValidArguments_Succeeds() { // Arrange var logger = new TestLogger(); - string iotHubName = _bogusGenerator.Commerce.ProductName(); - bool isSuccessful = _bogusGenerator.Random.Bool(); - DateTimeOffset startTime = _bogusGenerator.Date.PastOffset(); - TimeSpan duration = _bogusGenerator.Date.Timespan(); + string iotHubName = BogusGenerator.Commerce.ProductName(); + bool isSuccessful = BogusGenerator.Random.Bool(); + DateTimeOffset startTime = BogusGenerator.Date.PastOffset(); + TimeSpan duration = BogusGenerator.Date.Timespan(); // Act logger.LogIotHubDependency(iotHubName: iotHubName, isSuccessful: isSuccessful, startTime: startTime, duration: duration); @@ -41,27 +38,105 @@ public void LogIotHubDependency_ValidArguments_Succeeds() Assert.Contains("Azure IoT Hub " + dependencyName, logMessage); } + [Fact] + public void LogIotHubDependencyWithDependencyId_ValidArguments_Succeeds() + { + // Arrange + var logger = new TestLogger(); + string iotHubName = BogusGenerator.Lorem.Word(); + bool isSuccessful = BogusGenerator.Random.Bool(); + DateTimeOffset startTime = BogusGenerator.Date.PastOffset(); + TimeSpan duration = BogusGenerator.Date.Timespan(); + string dependencyId = BogusGenerator.Lorem.Word(); + + string key = BogusGenerator.Lorem.Word(); + string value = BogusGenerator.Lorem.Word(); + var context = new Dictionary { [key] = value }; + + // Act + logger.LogIotHubDependency(iotHubName: iotHubName, isSuccessful, startTime, duration, dependencyId, context); + + // Assert + DependencyLogEntry dependency = logger.GetMessageAsDependency(); + Assert.Equal(iotHubName, dependency.DependencyName); + Assert.Null(dependency.DependencyData); + Assert.Equal(iotHubName, dependency.TargetName); + Assert.Equal(duration, dependency.Duration); + Assert.Equal(startTime.ToString(FormatSpecifiers.InvariantTimestampFormat), dependency.StartTime); + Assert.Equal(isSuccessful, dependency.IsSuccessful); + Assert.Equal(dependencyId, dependency.DependencyId); + Assert.Equal(value, Assert.Contains(key, dependency.Context)); + } + + [Theory] + [ClassData(typeof(Blanks))] + public void LogIotHubDependency_WithoutIoTHubName_Fails(string iotHubName) + { + // Arrange + var logger = new TestLogger(); + bool isSuccessful = BogusGenerator.Random.Bool(); + + DateTimeOffset startTime = BogusGenerator.Date.PastOffset(); + TimeSpan duration = BogusGenerator.Date.Timespan(); + + // Act / Assert + Assert.ThrowsAny( + () => logger.LogIotHubDependency(iotHubName: iotHubName, isSuccessful, startTime, duration)); + } + + [Theory] + [ClassData(typeof(Blanks))] + public void LogIotHubDependencyWithDependencyId_WithoutIoTHubName_Fails(string iotHubName) + { + // Arrange + var logger = new TestLogger(); + bool isSuccessful = BogusGenerator.Random.Bool(); + + DateTimeOffset startTime = BogusGenerator.Date.PastOffset(); + TimeSpan duration = BogusGenerator.Date.Timespan(); + string dependencyId = BogusGenerator.Lorem.Word(); + + // Act / Assert + Assert.ThrowsAny( + () => logger.LogIotHubDependency(iotHubName: iotHubName, isSuccessful, startTime, duration, dependencyId)); + } + [Fact] public void LogIoTHubDependency_WithNegativeDuration_Fails() { // Arrange var logger = new TestLogger(); - string iotHubName = _bogusGenerator.Commerce.ProductName(); - bool isSuccessful = _bogusGenerator.Random.Bool(); - DateTimeOffset startTime = _bogusGenerator.Date.PastOffset(); + string iotHubName = BogusGenerator.Commerce.ProductName(); + bool isSuccessful = BogusGenerator.Random.Bool(); + DateTimeOffset startTime = BogusGenerator.Date.PastOffset(); TimeSpan duration = TimeSpanGenerator.GeneratePositiveDuration().Negate(); // Act / Assert Assert.ThrowsAny(() => logger.LogIotHubDependency(iotHubName: iotHubName, isSuccessful: isSuccessful, startTime: startTime, duration: duration)); } + [Fact] + public void LogIoTHubDependencyWithDependencyId_WithNegativeDuration_Fails() + { + // Arrange + var logger = new TestLogger(); + string iotHubName = BogusGenerator.Commerce.ProductName(); + bool isSuccessful = BogusGenerator.Random.Bool(); + DateTimeOffset startTime = BogusGenerator.Date.PastOffset(); + TimeSpan duration = TimeSpanGenerator.GeneratePositiveDuration().Negate(); + string dependencyId = BogusGenerator.Lorem.Word(); + + // Act / Assert + Assert.ThrowsAny(() => logger.LogIotHubDependency(iotHubName: iotHubName, isSuccessful, startTime, duration, dependencyId)); + } + [Fact] public void LogIotHubDependencyWithDependencyMeasurement_ValidArguments_Succeeds() { // Arrange var logger = new TestLogger(); - string iotHubName = _bogusGenerator.Commerce.ProductName(); - bool isSuccessful = _bogusGenerator.Random.Bool(); + string iotHubName = BogusGenerator.Commerce.ProductName(); + bool isSuccessful = BogusGenerator.Random.Bool(); var measurement = DependencyMeasurement.Start(); DateTimeOffset startTime = measurement.StartTime; @@ -88,8 +163,8 @@ public void LogIotHubDependencyWithDurationMeasurement_ValidArguments_Succeeds() { // Arrange var logger = new TestLogger(); - string iotHubName = _bogusGenerator.Lorem.Word(); - bool isSuccessful = _bogusGenerator.Random.Bool(); + string iotHubName = BogusGenerator.Lorem.Word(); + bool isSuccessful = BogusGenerator.Random.Bool(); var measurement = DurationMeasurement.Start(); DateTimeOffset startTime = measurement.StartTime; @@ -109,6 +184,39 @@ public void LogIotHubDependencyWithDurationMeasurement_ValidArguments_Succeeds() Assert.Equal(isSuccessful, dependency.IsSuccessful); } + [Fact] + public void LogIotHubDependencyWithDurationMeasurementWithDependencyId_ValidArguments_Succeeds() + { + // Arrange + var logger = new TestLogger(); + string iotHubName = BogusGenerator.Lorem.Word(); + bool isSuccessful = BogusGenerator.Random.Bool(); + + var measurement = DurationMeasurement.Start(); + DateTimeOffset startTime = measurement.StartTime; + measurement.Dispose(); + TimeSpan duration = measurement.Elapsed; + string dependencyId = BogusGenerator.Lorem.Word(); + + string key = BogusGenerator.Lorem.Word(); + string value = BogusGenerator.Lorem.Word(); + var context = new Dictionary { [key] = value }; + + // Act + logger.LogIotHubDependency(iotHubName: iotHubName, isSuccessful, measurement, dependencyId, context); + + // Assert + DependencyLogEntry dependency = logger.GetMessageAsDependency(); + Assert.Equal(iotHubName, dependency.TargetName); + Assert.Equal("Azure IoT Hub", dependency.DependencyType); + Assert.Equal(iotHubName, dependency.DependencyName); + Assert.Equal(startTime.ToString(FormatSpecifiers.InvariantTimestampFormat), dependency.StartTime); + Assert.Equal(duration, dependency.Duration); + Assert.Equal(isSuccessful, dependency.IsSuccessful); + Assert.Equal(dependencyId, dependency.DependencyId); + Assert.Equal(value, Assert.Contains(key, dependency.Context)); + } + [Fact] public void LogIotHubDependencyConnectionStringWithDurationMeasurement_ValidArguments_Succeeds() { @@ -116,7 +224,7 @@ public void LogIotHubDependencyConnectionStringWithDurationMeasurement_ValidArgu var logger = new TestLogger(); var iotHubName = "acme.azure-devices.net"; var iotHubConnectionString = $"HostName={iotHubName};SharedAccessKeyName=AllAccessKey;DeviceId=fake;SharedAccessKey=dGVzdFN0cmluZzE="; - bool isSuccessful = _bogusGenerator.Random.Bool(); + bool isSuccessful = BogusGenerator.Random.Bool(); var measurement = DurationMeasurement.Start(); DateTimeOffset startTime = measurement.StartTime; @@ -136,13 +244,47 @@ public void LogIotHubDependencyConnectionStringWithDurationMeasurement_ValidArgu Assert.Equal(isSuccessful, dependency.IsSuccessful); } + [Fact] + public void LogIotHubDependencyConnectionStringWithDurationMeasurementWithDependencyId_ValidArguments_Succeeds() + { + // Arrange + var logger = new TestLogger(); + var iotHubName = "acme.azure-devices.net"; + var iotHubConnectionString = $"HostName={iotHubName};SharedAccessKeyName=AllAccessKey;DeviceId=fake;SharedAccessKey=dGVzdFN0cmluZzE="; + bool isSuccessful = BogusGenerator.Random.Bool(); + + var measurement = DurationMeasurement.Start(); + DateTimeOffset startTime = measurement.StartTime; + measurement.Dispose(); + TimeSpan duration = measurement.Elapsed; + string dependencyId = BogusGenerator.Lorem.Word(); + + string key = BogusGenerator.Lorem.Word(); + string value = BogusGenerator.Lorem.Word(); + var context = new Dictionary { [key] = value }; + + // Act + logger.LogIotHubDependency(iotHubConnectionString: iotHubConnectionString, isSuccessful, measurement, dependencyId, context); + + // Assert + DependencyLogEntry dependency = logger.GetMessageAsDependency(); + Assert.Equal(iotHubName, dependency.TargetName); + Assert.Equal("Azure IoT Hub", dependency.DependencyType); + Assert.Equal(iotHubName, dependency.DependencyName); + Assert.Equal(startTime.ToString(FormatSpecifiers.InvariantTimestampFormat), dependency.StartTime); + Assert.Equal(duration, dependency.Duration); + Assert.Equal(isSuccessful, dependency.IsSuccessful); + Assert.Equal(dependencyId, dependency.DependencyId); + Assert.Equal(value, Assert.Contains(key, dependency.Context)); + } + [Theory] [ClassData(typeof(Blanks))] public void LogIotHubDependencyWithDurationMeasurement_WithoutIoTHubName_Fails(string iotHubName) { // Arrange var logger = new TestLogger(); - bool isSuccessful = _bogusGenerator.Random.Bool(); + bool isSuccessful = BogusGenerator.Random.Bool(); var measurement = DurationMeasurement.Start(); measurement.Dispose(); @@ -152,26 +294,57 @@ public void LogIotHubDependencyWithDurationMeasurement_WithoutIoTHubName_Fails(s () => logger.LogIotHubDependency(iotHubName: iotHubName, isSuccessful, measurement)); } + [Theory] + [ClassData(typeof(Blanks))] + public void LogIotHubDependencyWithDurationMeasurementWithDependencyId_WithoutIoTHubName_Fails(string iotHubName) + { + // Arrange + var logger = new TestLogger(); + bool isSuccessful = BogusGenerator.Random.Bool(); + + var measurement = DurationMeasurement.Start(); + measurement.Dispose(); + string dependencyId = BogusGenerator.Lorem.Word(); + + // Act / Assert + Assert.ThrowsAny( + () => logger.LogIotHubDependency(iotHubName: iotHubName, isSuccessful, measurement, dependencyId)); + } + [Fact] public void LogIotHubDependencyWithDurationMeasurement_WithoutMeasurement_Fails() { // Arrange var logger = new TestLogger(); - bool isSuccessful = _bogusGenerator.Random.Bool(); - string iotHubName = _bogusGenerator.Commerce.ProductName(); + bool isSuccessful = BogusGenerator.Random.Bool(); + string iotHubName = BogusGenerator.Commerce.ProductName(); // Act / Assert Assert.ThrowsAny( () => logger.LogIotHubDependency(iotHubName: iotHubName, isSuccessful, measurement: (DurationMeasurement)null)); } + [Fact] + public void LogIotHubDependencyWithDurationMeasurementWithDependencyId_WithoutMeasurement_Fails() + { + // Arrange + var logger = new TestLogger(); + bool isSuccessful = BogusGenerator.Random.Bool(); + string iotHubName = BogusGenerator.Commerce.ProductName(); + string dependencyId = BogusGenerator.Lorem.Word(); + + // Act / Assert + Assert.ThrowsAny( + () => logger.LogIotHubDependency(iotHubName: iotHubName, isSuccessful, measurement: null, dependencyId)); + } + [Theory] [ClassData(typeof(Blanks))] public void LogIotHubDependencyConnectionStringWithDurationMeasurement_WithoutConnectionString_Fails(string iotHubConnectionString) { // Arrange var logger = new TestLogger(); - bool isSuccessful = _bogusGenerator.Random.Bool(); + bool isSuccessful = BogusGenerator.Random.Bool(); var measurement = DurationMeasurement.Start(); measurement.Dispose(); @@ -181,34 +354,65 @@ public void LogIotHubDependencyConnectionStringWithDurationMeasurement_WithoutCo () => logger.LogIotHubDependency(iotHubConnectionString: iotHubConnectionString, isSuccessful, measurement)); } + [Theory] + [ClassData(typeof(Blanks))] + public void LogIotHubDependencyConnectionStringWithDurationMeasurementWithDependencyId_WithoutConnectionString_Fails(string iotHubConnectionString) + { + // Arrange + var logger = new TestLogger(); + bool isSuccessful = BogusGenerator.Random.Bool(); + + var measurement = DurationMeasurement.Start(); + measurement.Dispose(); + string dependencyId = BogusGenerator.Lorem.Word(); + + // Act / Assert + Assert.ThrowsAny( + () => logger.LogIotHubDependency(iotHubConnectionString: iotHubConnectionString, isSuccessful, measurement, dependencyId)); + } + [Fact] public void LogIotHubDependencyConnectionStringWithDurationMeasurement_WithoutMeasurement_Fails() { // Arrange var logger = new TestLogger(); - bool isSuccessful = _bogusGenerator.Random.Bool(); - string iotHubConnectionString = _bogusGenerator.Commerce.ProductName(); + bool isSuccessful = BogusGenerator.Random.Bool(); + string iotHubConnectionString = BogusGenerator.Commerce.ProductName(); // Act / Assert Assert.ThrowsAny( () => logger.LogIotHubDependency(iotHubConnectionString: iotHubConnectionString, isSuccessful, measurement: (DurationMeasurement)null)); } + [Fact] + public void LogIotHubDependencyConnectionStringWithDurationMeasurementWithDependencyId_WithoutMeasurement_Fails() + { + // Arrange + var logger = new TestLogger(); + bool isSuccessful = BogusGenerator.Random.Bool(); + string iotHubConnectionString = BogusGenerator.Commerce.ProductName(); + string dependencyId = BogusGenerator.Lorem.Word(); + + // Act / Assert + Assert.ThrowsAny( + () => logger.LogIotHubDependency(iotHubConnectionString: iotHubConnectionString, isSuccessful, measurement: null, dependencyId)); + } + [Fact] public void LogIotHubConnectionStringDependency_ValidArguments_Succeeds() { // Arrange var logger = new TestLogger(); - string iotHubName = _bogusGenerator.Commerce.ProductName().Replace(" ", String.Empty); - string deviceId = _bogusGenerator.Internet.Ip(); - string sharedAccessKey = _bogusGenerator.Random.Hash(); + 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(); - DateTimeOffset startTime = _bogusGenerator.Date.PastOffset(); - TimeSpan duration = _bogusGenerator.Date.Timespan(); + bool isSuccessful = BogusGenerator.Random.Bool(); + DateTimeOffset startTime = BogusGenerator.Date.PastOffset(); + TimeSpan duration = BogusGenerator.Date.Timespan(); // Act - logger.LogIotHubDependency(iotHubConnectionString: iotHubConnectionString, isSuccessful: isSuccessful, startTime: startTime, duration: duration); + logger.LogIotHubDependency(iotHubConnectionString: iotHubConnectionString, isSuccessful, startTime, duration); // Assert var logMessage = logger.WrittenMessage; @@ -222,22 +426,107 @@ public void LogIotHubConnectionStringDependency_ValidArguments_Succeeds() Assert.Contains("Azure IoT Hub " + dependencyName, logMessage); } + [Fact] + public void LogIotHubConnectionStringDependencyWithDependencyId_ValidArguments_Succeeds() + { + // Arrange + var logger = new TestLogger(); + string iotHubName = BogusGenerator.Lorem.Word() + "."; + string deviceId = BogusGenerator.Lorem.Word(); + string sharedAccessKey = BogusGenerator.Random.Hash(); + var iotHubConnectionString = $"HostName={iotHubName};DeviceId={deviceId};SharedAccessKey={sharedAccessKey}"; + bool isSuccessful = BogusGenerator.Random.Bool(); + DateTimeOffset startTime = BogusGenerator.Date.PastOffset(); + TimeSpan duration = BogusGenerator.Date.Timespan(); + string dependencyId = BogusGenerator.Lorem.Word(); + + string key = BogusGenerator.Lorem.Word(); + string value = BogusGenerator.Lorem.Word(); + var context = new Dictionary { [key] = value }; + + // Act + logger.LogIotHubDependency(iotHubConnectionString: iotHubConnectionString, isSuccessful, startTime, duration, dependencyId, context); + + // Assert + DependencyLogEntry dependency = logger.GetMessageAsDependency(); + Assert.Equal("Azure IoT Hub", dependency.DependencyType); + Assert.Equal(iotHubName, dependency.DependencyName); + Assert.Equal(iotHubName, dependency.TargetName); + Assert.Equal(isSuccessful, dependency.IsSuccessful); + Assert.Equal(startTime.ToString(FormatSpecifiers.InvariantTimestampFormat), dependency.StartTime); + Assert.Equal(duration, dependency.Duration); + Assert.Equal(dependencyId, dependency.DependencyId); + Assert.Equal(value, Assert.Contains(key, dependency.Context)); + } + + [Theory] + [ClassData(typeof(Blanks))] + public void LogIotHubDependencyConnectionString_WithoutConnectionString_Fails(string iotHubConnectionString) + { + // Arrange + var logger = new TestLogger(); + bool isSuccessful = BogusGenerator.Random.Bool(); + + DateTimeOffset startTime = BogusGenerator.Date.PastOffset(); + TimeSpan duration = BogusGenerator.Date.Timespan(); + + // Act / Assert + Assert.ThrowsAny( + () => logger.LogIotHubDependency(iotHubConnectionString: iotHubConnectionString, isSuccessful, startTime, duration)); + } + + [Theory] + [ClassData(typeof(Blanks))] + public void LogIotHubDependencyConnectionStringWithDependencyId_WithoutConnectionString_Fails(string iotHubConnectionString) + { + // Arrange + var logger = new TestLogger(); + bool isSuccessful = BogusGenerator.Random.Bool(); + + DateTimeOffset startTime = BogusGenerator.Date.PastOffset(); + TimeSpan duration = BogusGenerator.Date.Timespan(); + string dependencyId = BogusGenerator.Lorem.Word(); + + // Act / Assert + Assert.ThrowsAny( + () => logger.LogIotHubDependency(iotHubConnectionString: iotHubConnectionString, isSuccessful, startTime, duration, dependencyId)); + } + [Fact] public void LogIoTHubConnectionStringDependency_WithNegativeDuration_Fails() { // Arrange var logger = new TestLogger(); - string iotHubName = _bogusGenerator.Commerce.ProductName().Replace(" ", String.Empty); - string deviceId = _bogusGenerator.Internet.Ip(); - string sharedAccessKey = _bogusGenerator.Random.Hash(); + 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(); + DateTimeOffset startTime = BogusGenerator.Date.PastOffset(); + TimeSpan duration = TimeSpanGenerator.GeneratePositiveDuration().Negate(); + + // Act + Assert.ThrowsAny( + () => logger.LogIotHubDependency(iotHubConnectionString: iotHubConnectionString, isSuccessful, startTime, duration)); + } + + [Fact] + public void LogIoTHubConnectionStringDependencyWithDependencyId_WithNegativeDuration_Fails() + { + // 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(); - DateTimeOffset startTime = _bogusGenerator.Date.PastOffset(); + bool isSuccessful = BogusGenerator.Random.Bool(); + DateTimeOffset startTime = BogusGenerator.Date.PastOffset(); TimeSpan duration = TimeSpanGenerator.GeneratePositiveDuration().Negate(); + string dependencyId = BogusGenerator.Lorem.Word(); // Act Assert.ThrowsAny( - () => logger.LogIotHubDependency(iotHubConnectionString: iotHubConnectionString, isSuccessful: isSuccessful, startTime: startTime, duration: duration)); + () => logger.LogIotHubDependency(iotHubConnectionString: iotHubConnectionString, isSuccessful, startTime, duration, dependencyId)); } [Fact] @@ -245,11 +534,11 @@ public void LogIotHubDependencyConnectionStringWithDependencyMeasurement_ValidAr { // Arrange var logger = new TestLogger(); - string iotHubName = _bogusGenerator.Commerce.ProductName().Replace(" ", String.Empty); - string deviceId = _bogusGenerator.Internet.Ip(); - string sharedAccessKey = _bogusGenerator.Random.Hash(); + 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(); + bool isSuccessful = BogusGenerator.Random.Bool(); var measurement = DependencyMeasurement.Start(); DateTimeOffset startTime = measurement.StartTime;