diff --git a/docs/preview/features/writing-different-telemetry-types.md b/docs/preview/features/writing-different-telemetry-types.md
index 186dc0f5..48b0aef2 100644
--- a/docs/preview/features/writing-different-telemetry-types.md
+++ b/docs/preview/features/writing-different-telemetry-types.md
@@ -103,6 +103,8 @@ _logger.LogEventHubsDependency(namespaceName: "be.sensors.contoso", eventHubName
We allow you to measure Azure IoT Hub dependencies.
+**Example**
+
Here is how you can report a dependency call:
```csharp
@@ -116,6 +118,31 @@ _logger.logger.LogIotHubDependency(iotHubName: "sensors", isSuccessful: true, st
// Output: "Dependency Azure IoT Hub named sensors in 00:00:00.2521801 at 03/23/2020 09:56:31 +00:00 (Successful: True - Context: )"
```
+Or, alternatively you can pass allong the IoT connection string itself so the host name will be selected for you.
+
+**Installation**
+
+This feature requires to install our NuGet package
+
+```shell
+PM > Install-Package Arcus.Observability.Telemetry.IoT
+```
+
+**Example**
+
+Here is how you can report a dependency call:
+
+```csharp
+var durationMeasurement = new Stopwatch();
+
+// Start measuring
+durationMeasurement.Start();
+var startTime = DateTimeOffset.UtcNow;
+
+_logger.logger.LogIotHubDependency(iotHubConnectionString: "Hostname=sensors;", isSuccessful: true, startTime: startTime, duration: durationMeasurement.Elapsed);
+// Output: "Dependency Azure IoT Hub named sensors in 00:00:00.2521801 at 03/23/2020 09:56:31 +00:00 (Successful: True - Context: )"
+```
+
### Measuring Azure Service Bus dependencies
We allow you to measure Azure Service Bus dependencies for both queues & topics.
diff --git a/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerExtensions.cs b/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerExtensions.cs
index 726d853e..f538f0c4 100644
--- a/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerExtensions.cs
+++ b/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerExtensions.cs
@@ -557,17 +557,18 @@ public static void LogHttpDependency(this ILogger logger, HttpRequestMessage req
logger.LogInformation(HttpDependencyFormat, targetName, dependencyName, (int) statusCode, duration, startTime.ToString(CultureInfo.InvariantCulture), isSuccessful, context);
}
- ///
- /// Logs a SQL dependency
- ///
- /// Logger to use
- /// SQL connection string
- /// Name of table
- /// Name of the operation that was performed
- /// Indication whether or not the operation was successful
- /// Measuring the latency to call the SQL dependency
+ ///
+ /// Logs a SQL dependency
+ ///
+ /// Logger to use
+ /// SQL connection string
+ /// Name of table
+ /// Name of the operation that was performed
+ /// Indication whether or not the operation was successful
+ /// Measuring the latency to call the SQL dependency
/// Context that provides more insights on the dependency that was measured
- public static void LogSqlDependency(this ILogger logger, string connectionString, string tableName, string operationName, DependencyMeasurement measurement, bool isSuccessful, Dictionary context = null)
+ [Obsolete("Will be moved to separate package 'Arcus.Observability.Telemetry.Sql' in the future")]
+ public static void LogSqlDependency(this ILogger logger, string connectionString, string tableName, string operationName, DependencyMeasurement measurement, bool isSuccessful, Dictionary context = null)
{
Guard.NotNull(logger, nameof(logger));
Guard.NotNull(measurement, nameof(measurement));
@@ -575,18 +576,19 @@ public static void LogSqlDependency(this ILogger logger, string connectionString
LogSqlDependency(logger, connectionString, tableName, operationName, measurement.StartTime, measurement.Elapsed, isSuccessful, context);
}
- ///
- /// Logs a SQL dependency
- ///
- /// Logger to use
- /// SQL connection string
- /// Name of table
- /// Name of the operation that was performed
- /// Point in time when the interaction with the HTTP dependency was started
- /// Duration of the operation
- /// Indication whether or not the operation was successful
+ ///
+ /// Logs a SQL dependency
+ ///
+ /// Logger to use
+ /// SQL connection string
+ /// Name of table
+ /// Name of the operation that was performed
+ /// Point in time when the interaction with the HTTP dependency was started
+ /// Duration of the operation
+ /// Indication whether or not the operation was successful
/// Context that provides more insights on the dependency that was measured
- public static void LogSqlDependency(this ILogger logger, string connectionString, string tableName, string operationName, DateTimeOffset startTime, TimeSpan duration, bool isSuccessful, Dictionary context = null)
+ [Obsolete("Will be moved to separate package 'Arcus.Observability.Telemetry.Sql' in the future")]
+ public static void LogSqlDependency(this ILogger logger, string connectionString, string tableName, string operationName, DateTimeOffset startTime, TimeSpan duration, bool isSuccessful, Dictionary context = null)
{
Guard.NotNullOrEmpty(connectionString, nameof(connectionString));
var connection = new SqlConnectionStringBuilder(connectionString);
diff --git a/src/Arcus.Observability.Telemetry.IoT/Arcus.Observability.Telemetry.IoT.csproj b/src/Arcus.Observability.Telemetry.IoT/Arcus.Observability.Telemetry.IoT.csproj
new file mode 100644
index 00000000..932bec97
--- /dev/null
+++ b/src/Arcus.Observability.Telemetry.IoT/Arcus.Observability.Telemetry.IoT.csproj
@@ -0,0 +1,31 @@
+
+
+
+ netstandard2.0
+ Arcus.Observability.Telemetry.IoT
+ Arcus
+ Arcus
+ Provides capability to improve IoT telemetry with Serilog in applications
+ Copyright (c) Arcus
+ https://github.com/arcus-azure/arcus.observability/blob/master/LICENSE
+ https://github.com/arcus-azure/arcus.observability
+ https://raw.githubusercontent.com/arcus-azure/arcus/master/media/arcus.png
+ https://github.com/arcus-azure/arcus.observability
+ Git
+ Azure;Observability;Telemetry;Serilog;IoT
+ true
+ true
+ Arcus.Observability.Telemetry.IoT
+ Arcus.Observability.Telemetry.IoT
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Arcus.Observability.Telemetry.IoT/Extensions/ILoggerExtensions.cs b/src/Arcus.Observability.Telemetry.IoT/Extensions/ILoggerExtensions.cs
new file mode 100644
index 00000000..ea25fd7f
--- /dev/null
+++ b/src/Arcus.Observability.Telemetry.IoT/Extensions/ILoggerExtensions.cs
@@ -0,0 +1,52 @@
+using System;
+using System.Collections.Generic;
+using Arcus.Observability.Telemetry.Core;
+using GuardNet;
+using Microsoft.Azure.Devices.Client;
+
+// ReSharper disable once CheckNamespace
+namespace Microsoft.Extensions.Logging
+{
+ ///
+ /// Extensions on the related to tracking IoT dependencies.
+ ///
+ // ReSharper disable once InconsistentNaming
+ public static class ILoggerExtensions
+ {
+ ///
+ /// Logs an Azure Iot Hub Dependency.
+ ///
+ /// Logger to use
+ /// Name of the IoT Hub resource
+ /// Indication whether or not the operation was successful
+ /// Measuring the latency to call the dependency
+ /// Context that provides more insights on the dependency that was measured
+ public static void LogIotHubDependency(this ILogger logger, string iotHubConnectionString, bool isSuccessful, DependencyMeasurement measurement, Dictionary context = null)
+ {
+ Guard.NotNull(logger, nameof(logger));
+ Guard.NotNullOrWhitespace(iotHubConnectionString, nameof(iotHubConnectionString));
+
+ LogIotHubDependency(logger, iotHubConnectionString, isSuccessful, measurement.StartTime, measurement.Elapsed, context);
+ }
+
+ ///
+ /// Logs an Azure Iot Hub Dependency.
+ ///
+ /// Logger to use
+ /// Name of the Event 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
+ public static void LogIotHubDependency(this ILogger logger, string iotHubConnectionString, bool isSuccessful, DateTimeOffset startTime, TimeSpan duration, Dictionary context = null)
+ {
+ Guard.NotNull(logger, nameof(logger));
+ Guard.NotNullOrWhitespace(iotHubConnectionString, nameof(iotHubConnectionString));
+
+ context = context ?? new Dictionary();
+
+ var iotHubConnection = IotHubConnectionStringBuilder.Create(iotHubConnectionString);
+ logger.LogIotHubDependency(iotHubName: iotHubConnection.HostName, isSuccessful: isSuccessful, startTime: startTime, duration: duration, context: context);
+ }
+ }
+}
diff --git a/src/Arcus.Observability.Tests.Unit/Arcus.Observability.Tests.Unit.csproj b/src/Arcus.Observability.Tests.Unit/Arcus.Observability.Tests.Unit.csproj
index 2b0f5c5d..0ab86175 100644
--- a/src/Arcus.Observability.Tests.Unit/Arcus.Observability.Tests.Unit.csproj
+++ b/src/Arcus.Observability.Tests.Unit/Arcus.Observability.Tests.Unit.csproj
@@ -17,6 +17,7 @@
+
diff --git a/src/Arcus.Observability.Tests.Unit/Serilog/ApplicationInsightsTelemetryConverterTests.cs b/src/Arcus.Observability.Tests.Unit/Serilog/ApplicationInsightsTelemetryConverterTests.cs
index 89acb867..5bb53b5f 100644
--- a/src/Arcus.Observability.Tests.Unit/Serilog/ApplicationInsightsTelemetryConverterTests.cs
+++ b/src/Arcus.Observability.Tests.Unit/Serilog/ApplicationInsightsTelemetryConverterTests.cs
@@ -481,7 +481,7 @@ public void LogIoTHubDependency_WithTableStorageDependency_CreatesDependencyTele
{
["DeviceName"] = "Sensor #102"
};
- logger.LogIotHubDependency(iotHubName, isSuccessful: true, startTime: startTime, duration: duration, context: telemetryContext);
+ logger.LogIotHubDependency(iotHubName: iotHubName, isSuccessful: true, startTime: startTime, duration: duration, context: telemetryContext);
LogEvent logEvent = Assert.Single(spySink.CurrentLogEmits);
Assert.NotNull(logEvent);
diff --git a/src/Arcus.Observability.Tests.Unit/Telemetry/ILoggerExtensionsTests.cs b/src/Arcus.Observability.Tests.Unit/Telemetry/ILoggerExtensionsTests.cs
index 9ed840e9..73f2d15e 100644
--- a/src/Arcus.Observability.Tests.Unit/Telemetry/ILoggerExtensionsTests.cs
+++ b/src/Arcus.Observability.Tests.Unit/Telemetry/ILoggerExtensionsTests.cs
@@ -536,7 +536,7 @@ public void LogIotHubDependency_ValidArguments_Succeeds()
TimeSpan duration = _bogusGenerator.Date.Timespan();
// Act
- logger.LogIotHubDependency(iotHubName, isSuccessful, startTime, duration);
+ logger.LogIotHubDependency(iotHubName: iotHubName, isSuccessful: isSuccessful, startTime: startTime, duration: duration);
// Assert
var logMessage = logger.WrittenMessage;
@@ -562,7 +562,62 @@ public void LogIotHubDependencyWithDependencyMeasurement_ValidArguments_Succeeds
TimeSpan duration = measurement.Elapsed;
// Act
- logger.LogIotHubDependency(iotHubName, isSuccessful, measurement);
+ logger.LogIotHubDependency(iotHubName: iotHubName, isSuccessful: isSuccessful, measurement: measurement);
+
+ // Assert
+ var logMessage = logger.WrittenMessage;
+ Assert.StartsWith(MessagePrefixes.Dependency, logMessage);
+ Assert.Contains(iotHubName, logMessage);
+ Assert.Contains(iotHubName, logMessage);
+ Assert.Contains(isSuccessful.ToString(), logMessage);
+ Assert.Contains(startTime.ToString(CultureInfo.InvariantCulture), logMessage);
+ Assert.Contains(duration.ToString(), logMessage);
+ }
+
+ [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 iotHubConnectionString = $"HostName={iotHubName}.;DeviceId={deviceId};SharedAccessKey={sharedAccessKey}";
+ 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);
+
+ // Assert
+ var logMessage = logger.WrittenMessage;
+ Assert.StartsWith(MessagePrefixes.Dependency, logMessage);
+ Assert.Contains(iotHubName, logMessage);
+ Assert.Contains(iotHubName, logMessage);
+ Assert.Contains(isSuccessful.ToString(), logMessage);
+ Assert.Contains(startTime.ToString(CultureInfo.InvariantCulture), logMessage);
+ Assert.Contains(duration.ToString(), logMessage);
+ }
+
+ [Fact]
+ public void LogIotHubDependencyConnectionStringWithDependencyMeasurement_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 iotHubConnectionString = $"HostName={iotHubName}.;DeviceId={deviceId};SharedAccessKey={sharedAccessKey}";
+ bool isSuccessful = _bogusGenerator.Random.Bool();
+
+ var measurement = DependencyMeasurement.Start();
+ DateTimeOffset startTime = measurement.StartTime;
+ measurement.Dispose();
+ TimeSpan duration = measurement.Elapsed;
+
+ // Act
+ logger.LogIotHubDependency(iotHubConnectionString: iotHubConnectionString, isSuccessful: isSuccessful, measurement: measurement);
// Assert
var logMessage = logger.WrittenMessage;
diff --git a/src/Arcus.Observability.sln b/src/Arcus.Observability.sln
index cb131aeb..2dbdeab2 100644
--- a/src/Arcus.Observability.sln
+++ b/src/Arcus.Observability.sln
@@ -19,7 +19,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Arcus.Observability.Telemet
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Arcus.Observability.Telemetry.Serilog.Filters", "Arcus.Observability.Telemetry.Serilog.Filters\Arcus.Observability.Telemetry.Serilog.Filters.csproj", "{ED747983-87B8-47B5-AAF8-DDFCB69E98EF}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Arcus.Observability.Tests.Core", "Arcus.Observability.Tests.Core\Arcus.Observability.Tests.Core.csproj", "{DC18426F-4D03-4DBD-8D92-224C026BFADC}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Arcus.Observability.Tests.Core", "Arcus.Observability.Tests.Core\Arcus.Observability.Tests.Core.csproj", "{DC18426F-4D03-4DBD-8D92-224C026BFADC}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Arcus.Observability.Telemetry.IoT", "Arcus.Observability.Telemetry.IoT\Arcus.Observability.Telemetry.IoT.csproj", "{E4A6624B-C1A4-4956-9FC2-E77D6C634717}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -59,6 +61,10 @@ Global
{DC18426F-4D03-4DBD-8D92-224C026BFADC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DC18426F-4D03-4DBD-8D92-224C026BFADC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DC18426F-4D03-4DBD-8D92-224C026BFADC}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E4A6624B-C1A4-4956-9FC2-E77D6C634717}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E4A6624B-C1A4-4956-9FC2-E77D6C634717}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E4A6624B-C1A4-4956-9FC2-E77D6C634717}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E4A6624B-C1A4-4956-9FC2-E77D6C634717}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE