/// <summary>
        /// Retrieves the secret value, based on the given name
        /// </summary>
        /// <param name="secretName">The name of the secret</param>
        /// <returns>Returns a <see cref="Secret"/> that contains the secret</returns>
        /// <exception cref="ArgumentException">The <paramref name="secretName"/> must not be empty</exception>
        /// <exception cref="ArgumentNullException">The <paramref name="secretName"/> must not be null</exception>
        /// <exception cref="SecretNotFoundException">The secret was not found, using the given name</exception>
        /// <exception cref="KeyVaultErrorException">The call for a secret resulted in an invalid response</exception>
        public virtual async Task <Secret> GetSecretAsync(string secretName)
        {
            Guard.NotNullOrWhitespace(secretName, nameof(secretName), "Requires a non-blank secret name to request a secret in Azure Key Vault");
            Guard.For <FormatException>(() => !SecretNameRegex.IsMatch(secretName), "Requires a secret name in the correct format to request a secret in Azure Key Vault, see https://docs.microsoft.com/en-us/azure/key-vault/general/about-keys-secrets-certificates#objects-identifiers-and-versioning");

            var isSuccessful = false;

            using (DependencyMeasurement measurement = DependencyMeasurement.Start())
            {
                try
                {
                    Secret secret = await GetSecretCoreAsync(secretName);

                    isSuccessful = true;

                    return(secret);
                }
                finally
                {
                    if (_options.TrackDependency)
                    {
                        Logger.LogDependency(DependencyName, secretName, VaultUri, isSuccessful, measurement);
                    }
                }
            }
        }
Exemplo n.º 2
0
        private async Task <SecretData> GetTrackedSecretAsync(string secretName)
        {
            var context = new Dictionary <string, object>
            {
                ["SecretEngine Type"]    = "KeyValue",
                ["SecretEngine Version"] = _options.KeyValueVersion
            };

            var isSuccessful = false;

            using (DependencyMeasurement measurement = DependencyMeasurement.Start())
            {
                try
                {
                    _logger.LogTrace("Getting a secret {SecretName} from HashiCorp Vault {VaultUri}...", secretName, _vaultClient.Settings.VaultServerUriWithPort);
                    SecretData result = await ReadSecretDataAsync(_secretPath);

                    isSuccessful = true;
                    return(result);
                }
                finally
                {
                    _logger.LogTrace("{Result} secret from HashiCorp Vault {VaultUri}", isSuccessful ? "Got" : "Couldn't get", _vaultClient.Settings.VaultServerUriWithPort);
                    if (_options.TrackDependency)
                    {
                        _logger.LogDependency(DependencyName, secretName, _vaultClient.Settings.VaultServerUriWithPort, isSuccessful, measurement, context);
                    }
                }
            }
        }
Exemplo n.º 3
0
        /// <summary>
        /// Retrieves the secret value, based on the given name
        /// </summary>
        /// <param name="secretName">The name of the secret</param>
        /// <returns>Returns a <see cref="Secret"/> that contains the secret</returns>
        /// <exception cref="ArgumentException">The <paramref name="secretName"/> must not be empty</exception>
        /// <exception cref="ArgumentNullException">The <paramref name="secretName"/> must not be null</exception>
        /// <exception cref="SecretNotFoundException">The secret was not found, using the given name</exception>
        /// <exception cref="KeyVaultErrorException">The call for a secret resulted in an invalid response</exception>
        public virtual async Task <Secret> GetSecretAsync(string secretName)
        {
            Guard.NotNullOrWhitespace(secretName, nameof(secretName), "Requires a non-blank secret name to request a secret in Azure Key Vault");

            var isSuccessful = false;

#if NET6_0
            using (DurationMeasurement measurement = DurationMeasurement.Start())
#else
            using (DependencyMeasurement measurement = DependencyMeasurement.Start())
#endif
            {
                try
                {
                    Secret secret = await GetSecretCoreAsync(secretName);

                    isSuccessful = true;

                    return(secret);
                }
                finally
                {
                    if (_options.TrackDependency)
                    {
                        Logger.LogDependency(DependencyName, secretName, VaultUri, isSuccessful, measurement);
                    }
                }
            }
        }
Exemplo n.º 4
0
        private async Task <HttpResponseMessage> SendRequestToApiAsync(HttpRequestMessage request)
        {
            using (var dependencyMeasurement = DependencyMeasurement.Start())
            {
                HttpResponseMessage response = null;
                try
                {
                    response = await _httpClient.SendAsync(request);

                    _logger.LogRequest(request, response, dependencyMeasurement.Elapsed);

                    return(response);
                }
                finally
                {
                    try
                    {
                        var statusCode = response?.StatusCode ?? HttpStatusCode.InternalServerError;
                        _logger.LogHttpDependency(request, statusCode, dependencyMeasurement);
                    }
                    catch (Exception ex)
                    {
                        _logger.LogWarning("Failed to log HTTP dependency. Reason: {Message}", ex.Message);
                    }
                }
            }
        }
        public async Task DependencyMeasurement_StartMeasuringAction_HoldsStartAndElapsedTime()
        {
            // Act
            using (var measurement = DependencyMeasurement.Start())
            {
                // Assert
                await Task.Delay(TimeSpan.FromMilliseconds(100));

                Assert.NotNull(measurement);
                Assert.True(DateTimeOffset.UtcNow > measurement.StartTime, "Measurement should have lesser start time");
                Assert.True(TimeSpan.Zero < measurement.Elapsed, "Measurement should be running");
            }
        }
        public async Task DependencyMeasurement_StopsMeasuringAction_WhenDisposed()
        {
            // Arrange
            var measurement = DependencyMeasurement.Start();
            await Task.Delay(TimeSpan.FromMilliseconds(100));

            measurement.Dispose();
            var elapsed = measurement.Elapsed;

            // Act
            await Task.Delay(TimeSpan.FromMilliseconds(100));

            // Assert
            Assert.NotNull(measurement);
            Assert.Equal(elapsed, measurement.Elapsed);
        }
Exemplo n.º 7
0
        /// <summary>
        /// Retrieves the secret value in the HashiCorp KeyValue Vault on given <paramref name="secretName"/>
        /// while tracking the dependency interaction call with the vault.
        /// </summary>
        /// <param name="secretName">The name of the HashiCorp secret.</param>
        /// <returns>
        ///     The HashiCorp <see cref="SecretData"/> concrete instance that contains the secret value.
        /// </returns>
        /// <exception cref="ArgumentException">Thrown when the <paramref name="secretName"/> is blank.</exception>
        /// <exception cref="ArgumentOutOfRangeException">
        ///     Thrown when the <see cref="Options"/>'s <see cref="HashiCorpVaultOptions.KeyValueVersion"/> represents an unknown secret engine version.
        /// </exception>
        protected async Task <SecretData> GetTrackedSecretAsync(string secretName)
        {
            Guard.NotNullOrWhitespace(secretName, nameof(secretName),
                                      $"Requires a non-blank secret name to look up the secret in the HashiCorp Vault {Options.KeyValueVersion} KeyValue secret engine");

            var context = new Dictionary <string, object>
            {
                ["SecretEngine Type"]    = "KeyValue",
                ["SecretEngine Version"] = Options.KeyValueVersion
            };

            var isSuccessful = false;

#if NET6_0
            using (DurationMeasurement measurement = DurationMeasurement.Start())
#else
            using (DependencyMeasurement measurement = DependencyMeasurement.Start())
#endif
            {
                try
                {
                    Logger.LogTrace("Getting a secret {SecretName} from HashiCorp Vault {VaultUri}...", secretName, VaultClient.Settings.VaultServerUriWithPort);
                    SecretData result = await ReadSecretDataAsync();

                    Logger.LogTrace("Secret '{SecretName}' was successfully retrieved from HashiCorp Vault {VaultUri}", secretName, VaultClient.Settings.VaultServerUriWithPort);

                    isSuccessful = true;
                    return(result);
                }
                catch (Exception exception)
                {
                    Logger.LogError(exception, "Secret '{SecretName}' was not successfully retrieved from HashiCorp Vault {VaultUri}, cause: {Message}",
                                    secretName, VaultClient.Settings.VaultServerUriWithPort, exception.Message);

                    throw;
                }
                finally
                {
                    if (Options.TrackDependency)
                    {
                        Logger.LogDependency(DependencyName, secretName, VaultClient.Settings.VaultServerUriWithPort, isSuccessful, measurement, context);
                    }
                }
            }
        }
Exemplo n.º 8
0
        private async Task <HttpResponseMessage> SendRequestToApiAsync(HttpRequestMessage request)
        {
            using (var dependencyMeasurement = DependencyMeasurement.Start())
            {
                HttpResponseMessage response = null;
                try
                {
                    _httpClient.BaseAddress = new Uri($"http://{_configuration.CurrentValue.Host}:{_configuration.CurrentValue.Port}");
                    response = await _httpClient.SendAsync(request);

                    _logger.LogRequest(request, response, dependencyMeasurement.Elapsed);

                    return(response);
                }
                finally
                {
                    var statusCode = response?.StatusCode ?? HttpStatusCode.InternalServerError;
                    _logger.LogHttpDependency(request, statusCode, dependencyMeasurement);
                }
            }
        }
        /// <summary>
        ///     Logs an Azure Key Vault dependency.
        /// </summary>
        /// <param name="logger">The logger to use.</param>
        /// <param name="vaultUri">The URI pointing to the Azure Key Vault resource.</param>
        /// <param name="secretName">The secret that is being used within the Azure Key Vault resource.</param>
        /// <param name="isSuccessful">Indication whether or not the operation was successful</param>
        /// <param name="measurement">Measuring the latency to call the dependency</param>
        /// <param name="context">Context that provides more insights on the dependency that was measured</param>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="logger"/> is <c>null</c>.</exception>
        /// <exception cref="ArgumentException">Thrown when the <paramref name="vaultUri"/> or <paramref name="secretName"/> is blank.</exception>
        /// <exception cref="FormatException">Thrown when the <paramref name="secretName"/> is not in the correct format.</exception>
        /// <exception cref="UriFormatException">Thrown when the <paramref name="vaultUri"/> is not in the correct format.</exception>
        public static void LogAzureKeyVaultDependency(
            this ILogger logger,
            string vaultUri,
            string secretName,
            bool isSuccessful,
            DependencyMeasurement measurement,
            Dictionary <string, object> context = null)
        {
            Guard.NotNull(logger, nameof(logger), "Requires an logger instance to write the Azure Key Vault dependency");
            Guard.NotNullOrWhitespace(vaultUri, nameof(vaultUri), "Requires a non-blank URI for the Azure Key Vault");
            Guard.NotNullOrWhitespace(secretName, nameof(secretName), "Requires a non-blank secret name for the Azure Key Vault");
            Guard.For <FormatException>(
                () => !SecretNameRegex.IsMatch(secretName),
                "Requires a Azure Key Vault secret name in the correct format, see https://docs.microsoft.com/en-us/azure/key-vault/general/about-keys-secrets-certificates#objects-identifiers-and-versioning");
            Guard.For <UriFormatException>(
                () => !KeyVaultUriRegex.IsMatch(vaultUri),
                "Requires the Azure Key Vault host to be in the right format, see https://docs.microsoft.com/en-us/azure/key-vault/general/about-keys-secrets-certificates#objects-identifiers-and-versioning");

            context = context ?? new Dictionary <string, object>();
            LogAzureKeyVaultDependency(logger, vaultUri, secretName, isSuccessful, measurement.StartTime, measurement.Elapsed, context);
        }
Exemplo n.º 10
0
        private async Task <HttpResponseMessage> SendRequestToApiAsync(HttpRequestMessage request)
        {
            var client = CreateHttpClient();

            using (var dependencyMeasurement = DependencyMeasurement.Start())
            {
                HttpResponseMessage response = null;
                try
                {
                    response = await client.SendAsync(request);

                    _logger.LogRequest(request, response, dependencyMeasurement.Elapsed);

                    return(response);
                }
                finally
                {
                    var statusCode = response?.StatusCode ?? HttpStatusCode.InternalServerError;
                    _logger.LogHttpDependency(request, statusCode, dependencyMeasurement);
                }
            }
        }
Exemplo n.º 11
0
        /// <summary>
        ///     Logs a SQL dependency
        /// </summary>
        /// <param name="logger">Logger to use</param>
        /// <param name="connectionString">SQL connection string</param>
        /// <param name="tableName">Name of table</param>
        /// <param name="operationName">Name of the operation that was performed</param>
        /// <param name="isSuccessful">Indication whether or not the operation was successful</param>
        /// <param name="measurement">Measuring the latency to call the SQL dependency</param>
        /// <param name="context">Context that provides more insights on the dependency that was measured</param>
        public static void LogSqlDependency(this ILogger logger, string connectionString, string tableName, string operationName, DependencyMeasurement measurement, bool isSuccessful, Dictionary <string, object> context = null)
        {
            Guard.NotNull(logger, nameof(logger));
            Guard.NotNull(measurement, nameof(measurement));

            LogSqlDependency(logger, connectionString, tableName, operationName, measurement.StartTime, measurement.Elapsed, isSuccessful, context);
        }
        /// <summary>
        ///     Logs an Azure Search Dependency.
        /// </summary>
        /// <param name="logger">Logger to use</param>
        /// <param name="searchServiceName">Name of the Azure Search service</param>
        /// <param name="operationName">Name of the operation to execute on the Azure Search service</param>
        /// <param name="isSuccessful">Indication whether or not the operation was successful</param>
        /// <param name="measurement">Measuring the latency to call the dependency</param>
        /// <param name="context">Context that provides more insights on the dependency that was measured</param>
        public static void LogAzureSearchDependency(this ILogger logger, string searchServiceName, string operationName, bool isSuccessful, DependencyMeasurement measurement, Dictionary <string, object> context = null)
        {
            Guard.NotNullOrWhitespace(searchServiceName, nameof(searchServiceName));
            Guard.NotNullOrWhitespace(operationName, nameof(operationName));

            context = context ?? new Dictionary <string, object>();

            LogAzureSearchDependency(logger, searchServiceName, operationName, isSuccessful, measurement.StartTime, measurement.Elapsed, context);
        }
        /// <summary>
        ///     Logs an Azure Service Bus Dependency.
        /// </summary>
        /// <param name="logger">Logger to use</param>
        /// <param name="topicName">Name of the Service Bus topic</param>
        /// <param name="isSuccessful">Indication whether or not the operation was successful</param>
        /// <param name="measurement">Measuring the latency to call the Service Bus dependency</param>
        /// <param name="context">Context that provides more insights on the dependency that was measured</param>
        public static void LogServiceBusTopicDependency(this ILogger logger, string topicName, bool isSuccessful, DependencyMeasurement measurement, Dictionary <string, object> context = null)
        {
            Guard.NotNull(logger, nameof(logger));
            Guard.NotNull(measurement, nameof(measurement));

            LogServiceBusTopicDependency(logger, topicName, isSuccessful, measurement.StartTime, measurement.Elapsed, context);
        }
        /// <summary>
        ///     Logs an Azure Service Bus Dependency.
        /// </summary>
        /// <param name="logger">Logger to use</param>
        /// <param name="entityName">Name of the Service Bus entity</param>
        /// <param name="isSuccessful">Indication whether or not the operation was successful</param>
        /// <param name="measurement">Measuring the latency to call the Service Bus dependency</param>
        /// <param name="entityType">Type of the Service Bus entity</param>
        /// <param name="context">Context that provides more insights on the dependency that was measured</param>
        public static void LogServiceBusDependency(this ILogger logger, string entityName, bool isSuccessful, DependencyMeasurement measurement, ServiceBusEntityType entityType = ServiceBusEntityType.Unknown, Dictionary <string, object> context = null)
        {
            Guard.NotNull(logger, nameof(logger));
            Guard.NotNull(measurement, nameof(measurement));

            LogServiceBusDependency(logger, entityName, isSuccessful, measurement.StartTime, measurement.Elapsed, entityType, context);
        }
Exemplo n.º 15
0
        public async Task <List <Resource> > QueryAsync(string query, List <string> targetSubscriptions)
        {
            Guard.NotNullOrWhitespace(query, nameof(query));

            var graphClient = await GetOrCreateClient();

            bool isSuccessfulDependency = false;

            using (var dependencyMeasurement = DependencyMeasurement.Start())
            {
                try
                {
                    var queryRequest = new QueryRequest(targetSubscriptions, query);
                    var response     = await graphClient.ResourcesAsync(queryRequest);

                    isSuccessfulDependency = true;

                    var foundResources = ParseQueryResults(response);

                    return(foundResources);
                }
                catch (ErrorResponseException responseException)
                {
                    if (responseException.Response != null)
                    {
                        if (responseException.Response.StatusCode == HttpStatusCode.Forbidden)
                        {
                            var unauthorizedException = new UnauthorizedException(QueryApplicationId, targetSubscriptions);
                            _logger.LogCritical(unauthorizedException, "Unable to query Azure Resource Graph");
                            throw unauthorizedException;
                        }

                        if (responseException.Response.StatusCode == HttpStatusCode.BadRequest)
                        {
                            var response     = JToken.Parse(responseException.Response.Content);
                            var errorDetails = response["error"]?["details"];
                            if (errorDetails != null)
                            {
                                var errorCodes = new List <string>();
                                foreach (var detailEntry in errorDetails)
                                {
                                    errorCodes.Add(detailEntry["code"]?.ToString());
                                }

                                if (errorCodes.Any(errorCode => errorCode.Equals("NoValidSubscriptionsInQueryRequest", StringComparison.InvariantCultureIgnoreCase)))
                                {
                                    var invalidSubscriptionException = new QueryContainsInvalidSubscriptionException(targetSubscriptions);
                                    _logger.LogCritical(invalidSubscriptionException, "Unable to query Azure Resource Graph");
                                    throw invalidSubscriptionException;
                                }
                            }
                        }
                    }

                    throw;
                }
                finally
                {
                    var contextualInformation = new Dictionary <string, object>
                    {
                        { "Query", query },
                        { "Subscriptions", targetSubscriptions }
                    };

                    _logger.LogDependency("Azure Resource Graph", query, "Query", isSuccessfulDependency, dependencyMeasurement, contextualInformation);
                }
            }
        }
Exemplo n.º 16
0
        private async Task <TResponse> InteractWithAzureResourceGraphAsync <TResponse>(string queryName, string query, List <string> targetSubscriptions, Func <ResourceGraphClient, Task <TResponse> > interactionFunc)
        {
            Guard.NotNullOrWhitespace(query, nameof(query));

            var retryPolicy = Policy.Handle <ErrorResponseException>(ex => ex.Response?.StatusCode == HttpStatusCode.Unauthorized)
                              .RetryAsync(retryCount: 3, OnRetryAsync);

            return(await retryPolicy.ExecuteAsync(async() =>
            {
                var graphClient = await GetOrCreateClient();

                bool isSuccessfulDependency = false;
                using (var dependencyMeasurement = DependencyMeasurement.Start())
                {
                    try
                    {
                        var response = await interactionFunc(graphClient);
                        isSuccessfulDependency = true;

                        return response;
                    }
                    catch (ErrorResponseException responseException)
                    {
                        if (responseException.Response != null)
                        {
                            if (responseException.Response.StatusCode == HttpStatusCode.Forbidden)
                            {
                                var unauthorizedException = CreateUnauthorizedException(targetSubscriptions);

                                throw unauthorizedException;
                            }

                            if (responseException.Response.StatusCode == HttpStatusCode.BadRequest)
                            {
                                var response = JToken.Parse(responseException.Response.Content);
                                var errorDetails = response["error"]?["details"];
                                if (errorDetails != null)
                                {
                                    var errorCodes = new List <string>();
                                    foreach (var detailEntry in errorDetails)
                                    {
                                        errorCodes.Add(detailEntry["code"]?.ToString());
                                    }

                                    if (errorCodes.Any(errorCode => errorCode.Equals("NoValidSubscriptionsInQueryRequest", StringComparison.InvariantCultureIgnoreCase)))
                                    {
                                        var invalidSubscriptionException = new QueryContainsInvalidSubscriptionException(targetSubscriptions);
                                        _logger.LogCritical(invalidSubscriptionException, "Unable to query Azure Resource Graph");
                                        throw invalidSubscriptionException;
                                    }
                                }
                            }
                        }

                        throw;
                    }
                    finally
                    {
                        var contextualInformation = new Dictionary <string, object>
                        {
                            { "Query", query },
                            { "QueryName", queryName },
                            { "Subscriptions", targetSubscriptions }
                        };

                        _logger.LogDependency("Azure Resource Graph", query, "Query", isSuccessfulDependency, dependencyMeasurement, contextualInformation);
                    }
                }
            }));
        }
        /// <summary>
        ///     Logs an Azure Iot Hub Dependency.
        /// </summary>
        /// <param name="logger">Logger to use</param>
        /// <param name="iotHubConnectionString">Name of the IoT Hub resource</param>
        /// <param name="isSuccessful">Indication whether or not the operation was successful</param>
        /// <param name="measurement">Measuring the latency to call the dependency</param>
        /// <param name="context">Context that provides more insights on the dependency that was measured</param>
        public static void LogIotHubDependency(this ILogger logger, string iotHubConnectionString, bool isSuccessful, DependencyMeasurement measurement, Dictionary <string, object> context = null)
        {
            Guard.NotNull(logger, nameof(logger));
            Guard.NotNullOrWhitespace(iotHubConnectionString, nameof(iotHubConnectionString));

            LogIotHubDependency(logger, iotHubConnectionString, isSuccessful, measurement.StartTime, measurement.Elapsed, context);
        }
        /// <summary>
        ///     Logs an Azure Table Storage Dependency.
        /// </summary>
        /// <param name="logger">Logger to use</param>
        /// <param name="accountName">Account of the storage resource</param>
        /// <param name="tableName">Name of the Table Storage resource</param>
        /// <param name="isSuccessful">Indication whether or not the operation was successful</param>
        /// <param name="measurement">Measuring the latency to call the Table Storage dependency</param>
        /// <param name="context">Context that provides more insights on the dependency that was measured</param>
        public static void LogTableStorageDependency(this ILogger logger, string accountName, string tableName, bool isSuccessful, DependencyMeasurement measurement, Dictionary <string, object> context = null)
        {
            Guard.NotNull(logger, nameof(logger));
            Guard.NotNullOrWhitespace(tableName, nameof(tableName));
            Guard.NotNullOrWhitespace(accountName, nameof(accountName));
            Guard.NotNull(measurement, nameof(measurement));

            LogTableStorageDependency(logger, accountName: accountName, tableName: tableName, isSuccessful: isSuccessful, startTime: measurement.StartTime, duration: measurement.Elapsed, context: context);
        }
        /// <summary>
        ///     Logs a Cosmos SQL dependency.
        /// </summary>
        /// <param name="logger">Logger to use</param>
        /// <param name="accountName">Name of the storage resource</param>
        /// <param name="database">Name of the database</param>
        /// <param name="container">Name of the container</param>
        /// <param name="isSuccessful">Indication whether or not the operation was successful</param>
        /// <param name="measurement">Measuring the latency of the dependency</param>
        /// <param name="context">Context that provides more insights on the dependency that was measured</param>
        public static void LogCosmosSqlDependency(this ILogger logger, string accountName, string database, string container, bool isSuccessful, DependencyMeasurement measurement, Dictionary <string, object> context = null)
        {
            Guard.NotNull(logger, nameof(logger));
            Guard.NotNullOrWhitespace(accountName, nameof(accountName));
            Guard.NotNullOrWhitespace(database, nameof(database));
            Guard.NotNullOrWhitespace(container, nameof(container));

            LogCosmosSqlDependency(logger, accountName, database, container, isSuccessful, measurement.StartTime, measurement.Elapsed, context);
        }
        /// <summary>
        ///     Logs an HTTP dependency
        /// </summary>
        /// <param name="logger">Logger to use</param>
        /// <param name="request">Request that started the HTTP communication</param>
        /// <param name="statusCode">Status code that was returned by the service for this HTTP communication</param>
        /// <param name="measurement">Measuring the latency of the HTTP dependency</param>
        /// <param name="context">Context that provides more insights on the dependency that was measured</param>
        public static void LogHttpDependency(this ILogger logger, HttpRequestMessage request, HttpStatusCode statusCode, DependencyMeasurement measurement, Dictionary <string, object> context = null)
        {
            Guard.NotNull(logger, nameof(logger));
            Guard.NotNull(request, nameof(request));
            Guard.NotNull(measurement, nameof(measurement));

            LogHttpDependency(logger, request, statusCode, measurement.StartTime, measurement.Elapsed, context);
        }
        /// <summary>
        ///     Logs an Azure Event Hub Dependency.
        /// </summary>
        /// <param name="logger">Logger to use</param>
        /// <param name="namespaceName">Namespace of the resource</param>
        /// <param name="eventHubName">Name of the Event Hub resource</param>
        /// <param name="isSuccessful">Indication whether or not the operation was successful</param>
        /// <param name="measurement">Measuring the latency to call the dependency</param>
        /// <param name="context">Context that provides more insights on the dependency that was measured</param>
        public static void LogEventHubsDependency(this ILogger logger, string namespaceName, string eventHubName, bool isSuccessful, DependencyMeasurement measurement, Dictionary <string, object> context = null)
        {
            Guard.NotNull(logger, nameof(logger));
            Guard.NotNullOrWhitespace(namespaceName, nameof(namespaceName));
            Guard.NotNullOrWhitespace(eventHubName, nameof(eventHubName));

            LogEventHubsDependency(logger, namespaceName, eventHubName, isSuccessful, measurement.StartTime, measurement.Elapsed, context);
        }
        /// <summary>
        ///     Logs a SQL dependency
        /// </summary>
        /// <param name="logger">Logger to use</param>
        /// <param name="serverName">Name of server hosting the database</param>
        /// <param name="databaseName">Name of database</param>
        /// <param name="tableName">Name of table</param>
        /// <param name="isSuccessful">Indication whether or not the operation was successful</param>
        /// <param name="measurement">Measuring the latency to call the SQL dependency</param>
        /// <param name="context">Context that provides more insights on the dependency that was measured</param>
        public static void LogSqlDependency(this ILogger logger, string serverName, string databaseName, string tableName, bool isSuccessful, DependencyMeasurement measurement, Dictionary <string, object> context = null)
        {
            Guard.NotNull(logger, nameof(logger));
            Guard.NotNullOrWhitespace(serverName, nameof(serverName));
            Guard.NotNullOrWhitespace(databaseName, nameof(databaseName));
            Guard.NotNullOrWhitespace(tableName, nameof(tableName));
            Guard.NotNull(measurement, nameof(measurement));

            LogSqlDependency(logger, serverName, databaseName, tableName, measurement.DependencyData, isSuccessful, measurement.StartTime, measurement.Elapsed, context);
        }
        /// <summary>
        ///     Logs a dependency.
        /// </summary>
        /// <param name="logger">Logger to use</param>
        /// <param name="dependencyType">Custom type of dependency</param>
        /// <param name="dependencyData">Custom data of dependency</param>
        /// <param name="isSuccessful">Indication whether or not the operation was successful</param>
        /// <param name="measurement">Measuring the latency to call the Service Bus dependency</param>
        /// <param name="context">Context that provides more insights on the dependency that was measured</param>
        public static void LogDependency(this ILogger logger, string dependencyType, object dependencyData, bool isSuccessful, DependencyMeasurement measurement, Dictionary <string, object> context = null)
        {
            Guard.NotNull(logger, nameof(logger));
            Guard.NotNullOrWhitespace(dependencyType, nameof(dependencyType));
            Guard.NotNull(dependencyData, nameof(dependencyData));

            LogDependency(logger, dependencyType, dependencyData, isSuccessful, measurement.StartTime, measurement.Elapsed, context);
        }