diff --git a/src/Arcus.Observability.Telemetry.AspNetCore/Extensions/ILoggerRequestExtensions.cs b/src/Arcus.Observability.Telemetry.AspNetCore/Extensions/ILoggerRequestExtensions.cs index c0a1579b..6e6b5f4e 100644 --- a/src/Arcus.Observability.Telemetry.AspNetCore/Extensions/ILoggerRequestExtensions.cs +++ b/src/Arcus.Observability.Telemetry.AspNetCore/Extensions/ILoggerRequestExtensions.cs @@ -14,37 +14,6 @@ namespace Microsoft.Extensions.Logging // ReSharper disable once InconsistentNaming public static class ILoggerRequestExtensions { - /// - /// Logs an HTTP request - /// - /// Logger to use - /// Request that was done - /// Response that will be sent out - /// Duration of the operation - /// Context that provides more insights on the HTTP request that was tracked - /// Thrown when the , , or is null - /// - /// Thrown when the 's scheme contains whitespace, the 's host is missing or contains whitespace. - /// - /// Thrown when the is a negative time range. - [Obsolete("Use the method overload with either an " + nameof(DurationMeasurement) + " instance or a " + nameof(DateTimeOffset) + " start time")] - public static void LogRequest(this ILogger logger, HttpRequest request, HttpResponse response, TimeSpan duration, Dictionary context = null) - { - Guard.NotNull(logger, nameof(logger), "Requires a logger instance to track telemetry"); - Guard.NotNull(request, nameof(request), "Requires a HTTP request instance to track a HTTP request"); - Guard.NotNull(response, nameof(response), "Requires a HTTP response instance to track a HTTP request"); - Guard.For(() => !request.Path.HasValue, new ArgumentException("Requires a HTTP request with a path", nameof(request))); - Guard.For(() => request.Method is null, new ArgumentException("Requires a HTTP request with a HTTP method", nameof(request))); - Guard.For(() => request.Scheme?.Contains(" ") == true, new ArgumentException("Requires a HTTP request scheme without whitespace to track a HTTP request", nameof(request))); - Guard.For(() => !request.Host.HasValue, new ArgumentException("Requires a HTTP request with a host value to track a HTTP request", nameof(request))); - Guard.For(() => request.Host.ToString()?.Contains(" ") == true, new ArgumentException("Requires a HTTP request host name without whitespace to track a HTTP request", nameof(request))); - Guard.NotLessThan(response.StatusCode, 0, nameof(response), "Requires a HTTP response status code that's within the 0-999 range to track a HTTP request"); - Guard.NotGreaterThan(response.StatusCode, 999, nameof(response), "Requires a HTTP response status code that's within the 0-999 range to track a HTTP request"); - Guard.NotLessThan(duration, TimeSpan.Zero, nameof(duration), "Requires a positive time duration of the Azure Blob storage operation"); - - LogRequest(logger, request, response.StatusCode, duration, context); - } - /// /// Logs an HTTP request. /// @@ -104,38 +73,6 @@ public static void LogRequest( LogRequest(logger, request, response.StatusCode, operationName: null, startTime, duration, context); } - /// - /// Logs an HTTP request - /// - /// Logger to use - /// Request that was done - /// Response that will be sent out - /// The name of the operation of the request. - /// Duration of the operation - /// Context that provides more insights on the HTTP request that was tracked - /// Thrown when the , , or is null - /// - /// Thrown when the 's scheme contains whitespace, the 's host is missing or contains whitespace. - /// - /// Thrown when the is a negative time range. - [Obsolete("Use the method overload with either an " + nameof(DurationMeasurement) + " instance or a " + nameof(DateTimeOffset) + " start time")] - public static void LogRequest(this ILogger logger, HttpRequest request, HttpResponse response, string operationName, TimeSpan duration, Dictionary context = null) - { - Guard.NotNull(logger, nameof(logger), "Requires a logger instance to track telemetry"); - Guard.NotNull(request, nameof(request), "Requires a HTTP request instance to track a HTTP request"); - Guard.NotNull(response, nameof(response), "Requires a HTTP response instance to track a HTTP request"); - Guard.For(() => !request.Path.HasValue, new ArgumentException("Requires a HTTP request with a path", nameof(request))); - Guard.For(() => request.Method is null, new ArgumentException("Requires a HTTP request with a HTTP method", nameof(request))); - Guard.For(() => request.Scheme?.Contains(" ") == true, new ArgumentException("Requires a HTTP request scheme without whitespace to track a HTTP request", nameof(request))); - Guard.For(() => !request.Host.HasValue, new ArgumentException("Requires a HTTP request with a host value to track a HTTP request", nameof(request))); - Guard.For(() => request.Host.ToString()?.Contains(" ") == true, new ArgumentException("Requires a HTTP request host name without whitespace to track a HTTP request", nameof(request))); - Guard.NotLessThan(response.StatusCode, 0, nameof(response), "Requires a HTTP response status code that's within the 0-999 range to track a HTTP request"); - Guard.NotGreaterThan(response.StatusCode, 999, nameof(response), "Requires a HTTP response status code that's within the 0-999 range to track a HTTP request"); - Guard.NotLessThan(duration, TimeSpan.Zero, nameof(duration), "Requires a positive time duration of the Azure Blob storage operation"); - - LogRequest(logger, request, response.StatusCode, operationName, duration, context); - } - /// /// Logs an HTTP request. /// @@ -196,41 +133,6 @@ public static void LogRequest( LogRequest(logger, request, response.StatusCode, operationName, startTime, duration, context); } - /// - /// Logs an HTTP request - /// - /// Logger to use - /// Request that was done - /// HTTP status code returned by the service - /// Duration of the operation - /// Context that provides more insights on the HTTP request that was tracked - /// Thrown when the or is null - /// - /// Thrown when the 's scheme contains whitespace, the 's host is missing or contains whitespace. - /// - /// Thrown when the is a negative time range. - [Obsolete("Use the method overload with either an " + nameof(DurationMeasurement) + " instance or a " + nameof(DateTimeOffset) + " start time")] - public static void LogRequest(this ILogger logger, HttpRequest request, int responseStatusCode, TimeSpan duration, Dictionary context = null) - { - Guard.NotNull(logger, nameof(logger), "Requires a logger instance to track telemetry"); - Guard.NotNull(request, nameof(request), "Requires a HTTP request instance to track a HTTP request"); - Guard.For(() => !request.Path.HasValue, new ArgumentException("Requires a HTTP request with a path", nameof(request))); - Guard.For(() => request.Method is null, new ArgumentException("Requires a HTTP request with a HTTP method", nameof(request))); - Guard.For(() => request.Scheme?.Contains(" ") == true, new ArgumentException("Requires a HTTP request scheme without whitespace to track a HTTP request", nameof(request))); - Guard.For(() => !request.Host.HasValue, new ArgumentException("Requires a HTTP request with a host value to track a HTTP request", nameof(request))); - Guard.For(() => request.Host.ToString()?.Contains(" ") == true, new ArgumentException("Requires a HTTP request host name without whitespace to track a HTTP request", nameof(request))); - Guard.NotLessThan(responseStatusCode, 0, nameof(responseStatusCode), "Requires a HTTP response status code that's within the 0-999 range to track a HTTP request"); - Guard.NotGreaterThan(responseStatusCode, 999, nameof(responseStatusCode), "Requires a HTTP response status code that's within the 0-999 range to track a HTTP request"); - Guard.NotLessThan(duration, TimeSpan.Zero, nameof(duration), "Requires a positive time duration of the HTTP request"); - - context = context ?? new Dictionary(); - - PathString resourcePath = request.Path; - var host = $"{request.Scheme}://{request.Host}"; - - logger.LogWarning(MessageFormats.RequestFormat, new RequestLogEntry(request.Method, host, resourcePath, responseStatusCode, duration, context)); - } - /// /// Logs an HTTP request. /// @@ -292,42 +194,6 @@ public static void LogRequest( LogRequest(logger, request, responseStatusCode, operationName: null, startTime, duration, context); } - /// - /// Logs an HTTP request - /// - /// Logger to use - /// Request that was done - /// HTTP status code returned by the service - /// The name of the operation of the request. - /// Duration of the operation - /// Context that provides more insights on the HTTP request that was tracked - /// Thrown when the or is null - /// - /// Thrown when the 's scheme contains whitespace, the 's host is missing or contains whitespace. - /// - /// Thrown when the is a negative time range. - [Obsolete("Use the method overload with either an " + nameof(DurationMeasurement) + " instance or a " + nameof(DateTimeOffset) + " start time")] - public static void LogRequest(this ILogger logger, HttpRequest request, int responseStatusCode, string operationName, TimeSpan duration, Dictionary context = null) - { - Guard.NotNull(logger, nameof(logger), "Requires a logger instance to track telemetry"); - Guard.NotNull(request, nameof(request), "Requires a HTTP request instance to track a HTTP request"); - Guard.For(() => !request.Path.HasValue, new ArgumentException("Requires a HTTP request with a path", nameof(request))); - Guard.For(() => request.Method is null, new ArgumentException("Requires a HTTP request with a HTTP method", nameof(request))); - Guard.For(() => request.Scheme?.Contains(" ") == true, new ArgumentException("Requires a HTTP request scheme without whitespace to track a HTTP request", nameof(request))); - Guard.For(() => !request.Host.HasValue, new ArgumentException("Requires a HTTP request with a host value to track a HTTP request", nameof(request))); - Guard.For(() => request.Host.ToString()?.Contains(" ") == true, new ArgumentException("Requires a HTTP request host name without whitespace to track a HTTP request", nameof(request))); - Guard.NotLessThan(responseStatusCode, 0, nameof(responseStatusCode), "Requires a HTTP response status code that's within the 0-999 range to track a HTTP request"); - Guard.NotGreaterThan(responseStatusCode, 999, nameof(responseStatusCode), "Requires a HTTP response status code that's within the 0-999 range to track a HTTP request"); - Guard.NotLessThan(duration, TimeSpan.Zero, nameof(duration), "Requires a positive time duration of the HTTP request"); - - context = context ?? new Dictionary(); - - PathString resourcePath = request.Path; - var host = $"{request.Scheme}://{request.Host}"; - - logger.LogWarning(MessageFormats.RequestFormat, new RequestLogEntry(request.Method, host, resourcePath, operationName, responseStatusCode, duration, context)); - } - /// /// Logs an HTTP request. /// diff --git a/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerRequestExtensions.cs b/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerRequestExtensions.cs index a414c417..6b4208f4 100644 --- a/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerRequestExtensions.cs +++ b/src/Arcus.Observability.Telemetry.Core/Extensions/ILoggerRequestExtensions.cs @@ -15,45 +15,6 @@ namespace Microsoft.Extensions.Logging // ReSharper disable once InconsistentNaming public static partial class ILoggerExtensions { - /// - /// Logs an HTTP request - /// - /// The logger to track the telemetry. - /// Request that was done - /// Response that will be sent out - /// Duration of the operation - /// Context that provides more insights on the HTTP request that was tracked - /// Thrown when the , , or is null. - /// - /// Thrown when the 's URI is blank, - /// the 's scheme contains whitespace, - /// the 's host contains whitespace, - /// - /// - /// Thrown when the 's status code is outside the 0-999 inclusively, - /// the is a negative time range. - /// - [Obsolete("Use the method overload with either an " + nameof(DurationMeasurement) + " instance or a " + nameof(DateTimeOffset) + " start time")] - public static void LogRequest( - this ILogger logger, - HttpRequestMessage request, - HttpResponseMessage response, - TimeSpan duration, - Dictionary context = null) - { - Guard.NotNull(logger, nameof(logger), "Requires a logger instance to track telemetry"); - Guard.NotNull(request, nameof(request), "Requires a HTTP request instance to track a HTTP request"); - Guard.NotNull(response, nameof(response), "Requires a HTTP response instance to track a HTTP request"); - Guard.NotNull(request.RequestUri, nameof(request.RequestUri), "Requires a request URI to track a HTTP request"); - Guard.For(() => request.RequestUri.Scheme?.Contains(" ") == true, "Requires a HTTP request scheme without whitespace"); - Guard.For(() => request.RequestUri.Host?.Contains(" ") == true, "Requires a HTTP request host name without whitespace"); - Guard.NotLessThan((int)response.StatusCode, 0, nameof(response), "Requires a HTTP response status code that's within the 0-999 range to track a HTTP request"); - Guard.NotGreaterThan((int)response.StatusCode, 999, nameof(response), "Requires a HTTP response status code that's within the 0-999 range to track a HTTP request"); - Guard.NotLessThan(duration, TimeSpan.Zero, nameof(duration), "Requires a positive time duration of the request operation"); - - LogRequest(logger, request, response.StatusCode, duration, context); - } - /// /// Logs an HTTP request. /// @@ -123,47 +84,6 @@ public static void LogRequest( LogRequest(logger, request, response.StatusCode, startTime, duration, context); } - /// - /// Logs an HTTP request - /// - /// The logger to track the telemetry. - /// Request that was done - /// Response that will be sent out - /// The name of the operation of the request. - /// Duration of the operation - /// Context that provides more insights on the HTTP request that was tracked - /// Thrown when the , , or is null. - /// - /// Thrown when the 's URI is blank, - /// the 's scheme contains whitespace, - /// the 's host contains whitespace, - /// - /// - /// Thrown when the 's status code is outside the 0-999 inclusively, - /// the is a negative time range. - /// - [Obsolete("Use the method overload with either an " + nameof(DurationMeasurement) + " instance or a " + nameof(DateTimeOffset) + " start time")] - public static void LogRequest( - this ILogger logger, - HttpRequestMessage request, - HttpResponseMessage response, - string operationName, - TimeSpan duration, - Dictionary context = null) - { - Guard.NotNull(logger, nameof(logger), "Requires a logger instance to track telemetry"); - Guard.NotNull(request, nameof(request), "Requires a HTTP request instance to track a HTTP request"); - Guard.NotNull(response, nameof(response), "Requires a HTTP response instance to track a HTTP request"); - Guard.NotNull(request.RequestUri, nameof(request.RequestUri), "Requires a request URI to track a HTTP request"); - Guard.For(() => request.RequestUri.Scheme?.Contains(" ") == true, "Requires a HTTP request scheme without whitespace"); - Guard.For(() => request.RequestUri.Host?.Contains(" ") == true, "Requires a HTTP request host name without whitespace"); - Guard.NotLessThan((int)response.StatusCode, 0, nameof(response), "Requires a HTTP response status code that's within the 0-999 range to track a HTTP request"); - Guard.NotGreaterThan((int)response.StatusCode, 999, nameof(response), "Requires a HTTP response status code that's within the 0-999 range to track a HTTP request"); - Guard.NotLessThan(duration, TimeSpan.Zero, nameof(duration), "Requires a positive time duration of the request operation"); - - LogRequest(logger, request, response.StatusCode, operationName, duration, context); - } - /// /// Logs an HTTP request. /// @@ -235,50 +155,6 @@ public static void LogRequest( LogRequest(logger, request, response.StatusCode, operationName, startTime, duration, context); } - /// - /// Logs an HTTP request - /// - /// The logger to track the telemetry. - /// Request that was done - /// HTTP status code returned by the service - /// Duration of the operation - /// Context that provides more insights on the HTTP request that was tracked - /// Thrown when the or is null. - /// - /// Thrown when the 's URI is blank, - /// the 's scheme contains whitespace, - /// the 's host contains whitespace, - /// - /// - /// Thrown when the 's status code is outside the 0-999 inclusively, - /// the is a negative time range. - /// - [Obsolete("Use the method overload with either an " + nameof(DurationMeasurement) + " instance or a " + nameof(DateTimeOffset) + " start time")] - public static void LogRequest( - this ILogger logger, - HttpRequestMessage request, - HttpStatusCode responseStatusCode, - TimeSpan duration, - Dictionary context = null) - { - Guard.NotNull(logger, nameof(logger), "Requires a logger instance to track telemetry"); - Guard.NotNull(request, nameof(request), "Requires a HTTP request instance to track a HTTP request"); - Guard.NotNull(request.RequestUri, nameof(request.RequestUri), "Requires a request URI to track a HTTP request"); - Guard.For(() => request.RequestUri.Scheme?.Contains(" ") == true, "Requires a HTTP request scheme without whitespace"); - Guard.For(() => request.RequestUri.Host?.Contains(" ") == true, "Requires a HTTP request host name without whitespace"); - Guard.NotLessThan((int)responseStatusCode, 0, nameof(responseStatusCode), "Requires a HTTP response status code that's within the 0-999 range to track a HTTP request"); - Guard.NotGreaterThan((int)responseStatusCode, 999, nameof(responseStatusCode), "Requires a HTTP response status code that's within the 0-999 range to track a HTTP request"); - Guard.NotLessThan(duration, TimeSpan.Zero, nameof(duration), "Requires a positive time duration of the request operation"); - - context = context ?? new Dictionary(); - - var statusCode = (int)responseStatusCode; - string resourcePath = request.RequestUri.AbsolutePath; - string host = $"{request.RequestUri.Scheme}://{request.RequestUri.Host}"; - - logger.LogWarning(MessageFormats.RequestFormat, new RequestLogEntry(request.Method.ToString(), host, resourcePath, statusCode, duration, context)); - } - /// /// Logs an HTTP request. /// @@ -345,52 +221,6 @@ public static void LogRequest( LogRequest(logger, request, responseStatusCode, operationName: null, startTime, duration, context); } - /// - /// Logs an HTTP request - /// - /// The logger to track the telemetry. - /// Request that was done - /// HTTP status code returned by the service - /// The name of the operation of the request. - /// Duration of the operation - /// Context that provides more insights on the HTTP request that was tracked - /// Thrown when the or is null. - /// - /// Thrown when the 's URI is blank, - /// the 's scheme contains whitespace, - /// the 's host contains whitespace, - /// - /// - /// Thrown when the 's status code is outside the 0-999 inclusively, - /// the is a negative time range. - /// - [Obsolete("Use the method overload with either an " + nameof(DurationMeasurement) + " instance or a " + nameof(DateTimeOffset) + " start time")] - public static void LogRequest( - this ILogger logger, - HttpRequestMessage request, - HttpStatusCode responseStatusCode, - string operationName, - TimeSpan duration, - Dictionary context = null) - { - Guard.NotNull(logger, nameof(logger), "Requires a logger instance to track telemetry"); - Guard.NotNull(request, nameof(request), "Requires a HTTP request instance to track a HTTP request"); - Guard.NotNull(request.RequestUri, nameof(request.RequestUri), "Requires a request URI to track a HTTP request"); - Guard.For(() => request.RequestUri.Scheme?.Contains(" ") == true, "Requires a HTTP request scheme without whitespace"); - Guard.For(() => request.RequestUri.Host?.Contains(" ") == true, "Requires a HTTP request host name without whitespace"); - Guard.NotLessThan((int)responseStatusCode, 0, nameof(responseStatusCode), "Requires a HTTP response status code that's within the 0-999 range to track a HTTP request"); - Guard.NotGreaterThan((int)responseStatusCode, 999, nameof(responseStatusCode), "Requires a HTTP response status code that's within the 0-999 range to track a HTTP request"); - Guard.NotLessThan(duration, TimeSpan.Zero, nameof(duration), "Requires a positive time duration of the request operation"); - - context = context ?? new Dictionary(); - - var statusCode = (int)responseStatusCode; - string resourcePath = request.RequestUri.AbsolutePath; - string host = $"{request.RequestUri.Scheme}://{request.RequestUri.Host}"; - - logger.LogWarning(MessageFormats.RequestFormat, new RequestLogEntry(request.Method.ToString(), host, resourcePath, operationName, statusCode, duration, context)); - } - /// /// Logs an HTTP request. /// @@ -455,6 +285,7 @@ public static void LogRequest( { Guard.NotNull(logger, nameof(logger), "Requires a logger instance to track telemetry"); Guard.NotNull(request, nameof(request), "Requires a HTTP request instance to track a HTTP request"); + Guard.NotNull(request.RequestUri, nameof(request), "Requires a request URI to retrieve the necessary request information"); Guard.NotLessThan(duration, TimeSpan.Zero, nameof(duration), "Requires a positive time duration of the request operation"); context = context ?? new Dictionary(); diff --git a/src/Arcus.Observability.Telemetry.Core/Logging/RequestLogEntry.cs b/src/Arcus.Observability.Telemetry.Core/Logging/RequestLogEntry.cs index fcca95d8..35f9132c 100644 --- a/src/Arcus.Observability.Telemetry.Core/Logging/RequestLogEntry.cs +++ b/src/Arcus.Observability.Telemetry.Core/Logging/RequestLogEntry.cs @@ -10,77 +10,6 @@ namespace Arcus.Observability.Telemetry.Core.Logging /// public class RequestLogEntry { - /// - /// Initializes a new instance of the class. - /// - /// The HTTP method of the request. - /// The host that was requested. - /// The URI of the request. - /// The HTTP status code returned by the service. - /// The duration of the processing of the request. - /// The context that provides more insights on the HTTP request that was tracked. - /// Thrown when the is null. - /// - /// Thrown when the 's URI is blank, - /// the contains whitespace, - /// - /// - /// Thrown when the 's status code is outside the 100-599 inclusively, - /// the is a negative time range. - /// - [Obsolete("Create a HTTP request log entry with '" + nameof(RequestLogEntry) + "." + nameof(CreateForHttpRequest) + "' instead")] - public RequestLogEntry( - string method, - string host, - string uri, - int statusCode, - TimeSpan duration, - IDictionary context) - : this(method, host, uri, operationName: $"{method} {uri}", statusCode, duration, context) - { - Guard.For(() => host?.Contains(" ") is true, "Requires a HTTP request host name without whitespace"); - Guard.NotLessThan(statusCode, 100, nameof(statusCode), "Requires a HTTP response status code that's within the 100-599 range to track a HTTP request"); - Guard.NotGreaterThan(statusCode, 599, nameof(statusCode), "Requires a HTTP response status code that's within the 100-599 range to track a HTTP request"); - Guard.NotLessThan(duration, TimeSpan.Zero, nameof(duration), "Requires a positive time duration of the request operation"); - } - - /// - /// Initializes a new instance of the class. - /// - /// The HTTP method of the request. - /// The host that was requested. - /// The URI of the request. - /// The name of the operation of the request. - /// The HTTP status code returned by the service. - /// The duration of the processing of the request. - /// The context that provides more insights on the HTTP request that was tracked. - /// Thrown when the is null. - /// - /// Thrown when the 's URI is blank, - /// the contains whitespace, - /// - /// - /// Thrown when the 's status code is outside the 100-599 inclusively, - /// the is a negative time range. - /// - [Obsolete("Create a HTTP request log entry with '" + nameof(RequestLogEntry) + "." + nameof(CreateForHttpRequest) + "' instead")] - public RequestLogEntry( - string method, - string host, - string uri, - string operationName, - int statusCode, - TimeSpan duration, - IDictionary context) - : this(method, host, uri, operationName, statusCode, sourceSystem: RequestSourceSystem.Http, requestTime: DateTimeOffset.UtcNow.ToString(FormatSpecifiers.InvariantTimestampFormat), duration: duration, context: context) - { - Guard.For(() => host?.Contains(" ") is true, "Requires a HTTP request host name without whitespace"); - Guard.NotNullOrWhitespace(operationName, nameof(operationName), "Requires an operation name that is not null or whitespace"); - Guard.NotLessThan(statusCode, 100, nameof(statusCode), "Requires a HTTP response status code that's within the 100-599 range to track a HTTP request"); - Guard.NotGreaterThan(statusCode, 599, nameof(statusCode), "Requires a HTTP response status code that's within the 100-599 range to track a HTTP request"); - Guard.NotLessThan(duration, TimeSpan.Zero, nameof(duration), "Requires a positive time duration of the request operation"); - } - private RequestLogEntry( string method, string host, diff --git a/src/Arcus.Observability.Telemetry.Serilog.Sinks.ApplicationInsights/Converters/RequestTelemetryConverter.cs b/src/Arcus.Observability.Telemetry.Serilog.Sinks.ApplicationInsights/Converters/RequestTelemetryConverter.cs index 8e1ca8e8..0212043f 100644 --- a/src/Arcus.Observability.Telemetry.Serilog.Sinks.ApplicationInsights/Converters/RequestTelemetryConverter.cs +++ b/src/Arcus.Observability.Telemetry.Serilog.Sinks.ApplicationInsights/Converters/RequestTelemetryConverter.cs @@ -14,29 +14,6 @@ namespace Arcus.Observability.Telemetry.Serilog.Sinks.ApplicationInsights.Conver /// public class RequestTelemetryConverter : CustomTelemetryConverter { - private readonly ApplicationInsightsSinkRequestOptions _options; - - /// - /// Initializes a new instance of the class. - /// - [Obsolete("Use the constructor overload with the Application Insights options instead")] - public RequestTelemetryConverter() - : this(new ApplicationInsightsSinkRequestOptions()) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The user-defined configuration options to tracking requests. - /// Thrown when the is null. - [Obsolete("Use the constructor overload with the Application Insights options instead")] - public RequestTelemetryConverter(ApplicationInsightsSinkRequestOptions options) - { - Guard.NotNull(options, nameof(options), "Requires a set of user-configurable options to influence the behavior of how requests are tracked"); - _options = options; - } - /// /// Initializes a new instance of the class. /// @@ -82,11 +59,6 @@ protected override RequestTelemetry CreateTelemetryEntry(LogEvent logEvent, IFor Context = { Operation = { Name = requestOperationName } } }; - if (_options != null) - { - requestTelemetry.Id = _options.GenerateId(); - } - requestTelemetry.Properties.AddRange(context); return requestTelemetry; } diff --git a/src/Arcus.Observability.Tests.Integration/Serilog/TelemetryTypeFilterTests.cs b/src/Arcus.Observability.Tests.Integration/Serilog/TelemetryTypeFilterTests.cs index c0ce3bb7..ef14f7fb 100644 --- a/src/Arcus.Observability.Tests.Integration/Serilog/TelemetryTypeFilterTests.cs +++ b/src/Arcus.Observability.Tests.Integration/Serilog/TelemetryTypeFilterTests.cs @@ -338,167 +338,6 @@ public void LogCustomMetric_WithTelemetryTypeFilterOnDifferentTyp_DoesNotFilterO } } - [Fact] - public void LogRequest_WithTelemetryTypeFilter_FilersInRequest() - { - // Arrange - var statusCode = (int)_bogusGenerator.PickRandom(); - var path = $"/{_bogusGenerator.Lorem.Word()}"; - string host = _bogusGenerator.Lorem.Word(); - HttpMethod method = HttpMethod.Head; - var stubbedRequest = new Mock(); - stubbedRequest.Setup(request => request.Method).Returns(method.ToString()); - stubbedRequest.Setup(request => request.Host).Returns(new HostString(host)); - stubbedRequest.Setup(request => request.Path).Returns(path); - var stubbedResponse = new Mock(); - stubbedResponse.Setup(response => response.StatusCode).Returns(statusCode); - TimeSpan duration = _bogusGenerator.Date.Timespan(); - string propertyName = _bogusGenerator.Random.Word(); - string propertyValue = _bogusGenerator.Random.Word(); - var properties = new Dictionary { [propertyName] = propertyValue }; - - var spySink = new InMemoryLogSink(); - Logger serilogLogger = new LoggerConfiguration() - .Filter.With(TelemetryTypeFilter.On(TelemetryType.Request)) - .WriteTo.Sink(spySink) - .CreateLogger(); - - using (var factory = new SerilogLoggerFactory(serilogLogger)) - { - ILogger logger = factory.CreateLogger(); - - // Act - logger.LogRequest(stubbedRequest.Object, stubbedResponse.Object, duration, properties); - - // Assert - Assert.Empty(spySink.CurrentLogEmits); - } - } - - [Theory] - [MemberData(nameof(TelemetryTypesWithoutRequest))] - public void LogRequest_WithTelemetryTypeFilterOnDifferentTelemetryType_DoesNotFilterOutEntry(TelemetryType telemetryType) - { - // Arrange - var statusCode = (int)_bogusGenerator.PickRandom(); - var path = $"/{_bogusGenerator.Lorem.Word()}"; - string host = _bogusGenerator.Lorem.Word(); - HttpMethod method = HttpMethod.Head; - var stubbedRequest = new Mock(); - stubbedRequest.Setup(request => request.Method).Returns(method.ToString()); - stubbedRequest.Setup(request => request.Host).Returns(new HostString(host)); - stubbedRequest.Setup(request => request.Path).Returns(path); - var stubbedResponse = new Mock(); - stubbedResponse.Setup(response => response.StatusCode).Returns(statusCode); - TimeSpan duration = _bogusGenerator.Date.Timespan(); - string propertyName = _bogusGenerator.Random.Word(); - string propertyValue = _bogusGenerator.Random.Word(); - var properties = new Dictionary { [propertyName] = propertyValue }; - - var spySink = new InMemoryLogSink(); - Logger serilogLogger = new LoggerConfiguration() - .Filter.With(TelemetryTypeFilter.On(telemetryType)) - .WriteTo.Sink(spySink) - .CreateLogger(); - - using (var factory = new SerilogLoggerFactory(serilogLogger)) - { - ILogger logger = factory.CreateLogger(); - - // Act - logger.LogRequest(stubbedRequest.Object, stubbedResponse.Object, duration, properties); - - // Assert - LogEvent logEvent = Assert.Single(spySink.CurrentLogEmits); - Assert.NotNull(logEvent); - string writtenMessage = logEvent.RenderMessage(); - Assert.Contains(path, writtenMessage); - Assert.Contains(host, writtenMessage); - Assert.Contains(statusCode.ToString(), writtenMessage); - Assert.Contains(method.ToString(), writtenMessage); - Assert.Contains(propertyName, writtenMessage); - Assert.Contains(propertyValue, writtenMessage); - Assert.Contains(TelemetryType.Request.ToString(), writtenMessage); - } - } - - [Fact] - public void LogRequestMessage_WithTelemetryTypeFilter_IgnoresRequestMessage() - { - // Arrange - var statusCode = _bogusGenerator.PickRandom(); - var path = $"/{_bogusGenerator.Name.FirstName().ToLower()}"; - string host = _bogusGenerator.Name.FirstName().ToLower(); - HttpMethod method = HttpMethod.Head; - var request = new HttpRequestMessage(method, new Uri("https://" + host + path)); - var response = new HttpResponseMessage(statusCode); - TimeSpan duration = _bogusGenerator.Date.Timespan(); - string propertyName = _bogusGenerator.Random.Word(); - string propertyValue = _bogusGenerator.Random.Word(); - var properties = new Dictionary { [propertyName] = propertyValue }; - - var spySink = new InMemoryLogSink(); - Logger serilogLogger = new LoggerConfiguration() - .Filter.With(TelemetryTypeFilter.On(TelemetryType.Request)) - .WriteTo.Sink(spySink) - .CreateLogger(); - - using (var factory = new SerilogLoggerFactory(serilogLogger)) - { - ILogger logger = factory.CreateLogger(); - - // Act - logger.LogRequest(request, response, duration, properties); - - // Assert - Assert.Empty(spySink.CurrentLogEmits); - } - } - - [Theory] - [MemberData(nameof(TelemetryTypesWithoutRequest))] - public void LogRequestMessage_WithTelemetryTypeFilter_DoesNotFilterOutEntry(TelemetryType telemetryType) - { - // Arrange - var statusCode = _bogusGenerator.PickRandom(); - var path = $"/{_bogusGenerator.Lorem.Word().ToLower()}"; - string host = _bogusGenerator.Lorem.Word().ToLower(); - HttpMethod method = HttpMethod.Head; - var request = new HttpRequestMessage(method, new Uri("https://" + host + path)); - var response = new HttpResponseMessage(statusCode); - TimeSpan duration = _bogusGenerator.Date.Timespan(); - string propertyName = _bogusGenerator.Random.Word(); - string propertyValue = _bogusGenerator.Random.Word(); - var properties = new Dictionary { [propertyName] = propertyValue }; - - var spySink = new InMemoryLogSink(); - Logger serilogLogger = new LoggerConfiguration() - .Filter.With(TelemetryTypeFilter.On(telemetryType)) - .WriteTo.Sink(spySink) - .CreateLogger(); - - using (var factory = new SerilogLoggerFactory(serilogLogger)) - { - ILogger logger = factory.CreateLogger(); - - // Act - logger.LogRequest(request, response, duration, properties); - - // Assert - LogEvent logEvent = Assert.Single(spySink.CurrentLogEmits); - Assert.NotNull(logEvent); - string writtenMessage = logEvent.RenderMessage(); - Assert.Contains(TelemetryType.Request.ToString(), writtenMessage); - Assert.Contains(path, writtenMessage); - Assert.Contains(host, writtenMessage); - Assert.Contains(((int)statusCode).ToString(), writtenMessage); - Assert.Contains(method.ToString(), writtenMessage); - Assert.Contains(propertyName, writtenMessage); - Assert.Contains(propertyValue, writtenMessage); - Assert.Contains(TelemetryType.Request.ToString(), writtenMessage); - } - } - [Fact] public void LogHttpDependency_WithTelemetryTypeFilter_IgnoresHttpDependency() { diff --git a/src/Arcus.Observability.Tests.Unit/Serilog/ApplicationInsightsTelemetryConverterTests.cs b/src/Arcus.Observability.Tests.Unit/Serilog/ApplicationInsightsTelemetryConverterTests.cs index 2e626eb3..22f99f6e 100644 --- a/src/Arcus.Observability.Tests.Unit/Serilog/ApplicationInsightsTelemetryConverterTests.cs +++ b/src/Arcus.Observability.Tests.Unit/Serilog/ApplicationInsightsTelemetryConverterTests.cs @@ -35,434 +35,6 @@ public class ApplicationInsightsTelemetryConverterTests { private readonly Faker _bogusGenerator = new Faker(); - [Fact] - public void LogRequestMessage_WithRequestAndResponse_CreatesRequestTelemetry() - { - // Arrange - var spySink = new InMemoryLogSink(); - string operationId = $"operation-id-{Guid.NewGuid()}"; - string transactionId = $"transaction-{Guid.NewGuid()}"; - string operationParentId = $"parent-{Guid.NewGuid()}"; - ILogger logger = CreateLogger( - spySink, config => config.Enrich.WithProperty(ContextProperties.Correlation.OperationId, operationId) - .Enrich.WithProperty(ContextProperties.Correlation.TransactionId, transactionId) - .Enrich.WithProperty(ContextProperties.Correlation.OperationParentId, operationParentId)); - - Order order = OrderGenerator.Generate(); - string json = JsonSerializer.Serialize(order); - var telemetryContext = new Dictionary - { - ["Client"] = "https://localhost", - ["ContentType"] = "application/json", - ["RequestBody"] = json - }; - var request = new HttpRequestMessage(System.Net.Http.HttpMethod.Get, new Uri("https://" + "localhost" + "/api/v1/health")); - var statusCode = HttpStatusCode.OK; - var response = new HttpResponseMessage(statusCode); - TimeSpan duration = TimeSpan.FromSeconds(5); - logger.LogRequest(request, response, duration, telemetryContext); - - LogEvent logEvent = Assert.Single(spySink.CurrentLogEmits); - Assert.NotNull(logEvent); - - var converter = ApplicationInsightsTelemetryConverter.Create(); - - // Act - IEnumerable telemetries = converter.Convert(logEvent, formatProvider: null); - - // Assert - AssertDoesContainLogProperty(logEvent, RequestTracking.RequestLogEntry); - Assert.Collection(telemetries, telemetry => - { - var requestTelemetry = Assert.IsType(telemetry); - Assert.Equal("GET /api/v1/health", requestTelemetry.Name); - Assert.Equal(duration, requestTelemetry.Duration); - Assert.Equal(((int)statusCode).ToString(), requestTelemetry.ResponseCode); - Assert.True(requestTelemetry.Success); - Assert.Equal(new Uri("https://localhost/api/v1/health"), requestTelemetry.Url); - AssertOperationContextForRequest(requestTelemetry, operationId, transactionId, operationParentId); - - AssertContainsTelemetryProperty(requestTelemetry, "Client", "https://localhost"); - AssertContainsTelemetryProperty(requestTelemetry, "ContentType", "application/json"); - }); - } - - [Fact] - public void LogRequestMessage_WithRequestAndResponseWithCustomId_CreatesRequestTelemetry() - { - // Arrange - var spySink = new InMemoryLogSink(); - string transactionId = $"transaction-{Guid.NewGuid()}"; - string operationParentId = $"parent-{Guid.NewGuid()}"; - ILogger logger = CreateLogger( - spySink, config => config.Enrich.WithProperty(ContextProperties.Correlation.OperationId, null) - .Enrich.WithProperty(ContextProperties.Correlation.TransactionId, transactionId) - .Enrich.WithProperty(ContextProperties.Correlation.OperationParentId, operationParentId)); - - Order order = OrderGenerator.Generate(); - string json = JsonSerializer.Serialize(order); - var telemetryContext = new Dictionary - { - ["Client"] = "https://localhost", - ["ContentType"] = "application/json", - ["RequestBody"] = json - }; - var request = new HttpRequestMessage(System.Net.Http.HttpMethod.Get, new Uri("https://" + "localhost" + "/api/v1/health")); - var statusCode = HttpStatusCode.OK; - var response = new HttpResponseMessage(statusCode); - TimeSpan duration = TimeSpan.FromSeconds(5); - logger.LogRequest(request, response, duration, telemetryContext); - - LogEvent logEvent = Assert.Single(spySink.CurrentLogEmits); - Assert.NotNull(logEvent); - - var requestId = Guid.NewGuid().ToString(); - var converter = ApplicationInsightsTelemetryConverter.Create(new ApplicationInsightsSinkOptions - { - Request = { GenerateId = () => requestId } - }); - - // Act - IEnumerable telemetries = converter.Convert(logEvent, formatProvider: null); - - // Assert - AssertDoesContainLogProperty(logEvent, RequestTracking.RequestLogEntry); - Assert.Collection(telemetries, telemetry => - { - var requestTelemetry = Assert.IsType(telemetry); - Assert.Equal("GET /api/v1/health", requestTelemetry.Name); - Assert.Equal(duration, requestTelemetry.Duration); - Assert.Equal(((int) statusCode).ToString(), requestTelemetry.ResponseCode); - Assert.True(requestTelemetry.Success); - Assert.Equal(new Uri("https://localhost/api/v1/health"), requestTelemetry.Url); - AssertOperationContextForRequest(requestTelemetry, requestId, transactionId, operationParentId); - - AssertContainsTelemetryProperty(requestTelemetry, "Client", "https://localhost"); - AssertContainsTelemetryProperty(requestTelemetry, "ContentType", "application/json"); - AssertContainsTelemetryProperty(requestTelemetry, "RequestBody", json); - }); - } - - [Fact] - public void LogRequestMessage_WithRequestAndResponseStatusCode_CreatesRequestTelemetry() - { - // Arrange - var spySink = new InMemoryLogSink(); - string operationId = $"operation-id-{Guid.NewGuid()}"; - string transactionId = $"transaction-{Guid.NewGuid()}"; - string operationParentId = $"parent-{Guid.NewGuid()}"; - ILogger logger = CreateLogger( - spySink, config => config.Enrich.WithProperty(ContextProperties.Correlation.OperationId, operationId) - .Enrich.WithProperty(ContextProperties.Correlation.TransactionId, transactionId) - .Enrich.WithProperty(ContextProperties.Correlation.OperationParentId, operationParentId)); - - Order order = OrderGenerator.Generate(); - string json = JsonSerializer.Serialize(order); - var telemetryContext = new Dictionary - { - ["Client"] = "https://localhost", - ["ContentType"] = "application/json", - ["RequestBody"] = json - }; - var request = new HttpRequestMessage(System.Net.Http.HttpMethod.Get, new Uri("https://" + "localhost" + "/api/v1/health")); - var statusCode = HttpStatusCode.OK; - TimeSpan duration = TimeSpan.FromSeconds(5); - logger.LogRequest(request, statusCode, duration, telemetryContext); - - LogEvent logEvent = Assert.Single(spySink.CurrentLogEmits); - Assert.NotNull(logEvent); - - var converter = ApplicationInsightsTelemetryConverter.Create(); - - // Act - IEnumerable telemetries = converter.Convert(logEvent, formatProvider: null); - - // Assert - AssertDoesContainLogProperty(logEvent, RequestTracking.RequestLogEntry); - Assert.Collection(telemetries, telemetry => - { - var requestTelemetry = Assert.IsType(telemetry); - Assert.Equal("GET /api/v1/health", requestTelemetry.Name); - Assert.Equal(duration, requestTelemetry.Duration); - Assert.Equal(((int) statusCode).ToString(), requestTelemetry.ResponseCode); - Assert.True(requestTelemetry.Success); - Assert.Equal(new Uri("https://localhost/api/v1/health"), requestTelemetry.Url); - AssertOperationContextForRequest(requestTelemetry, operationId, transactionId, operationParentId); - - AssertContainsTelemetryProperty(requestTelemetry, "Client", "https://localhost"); - AssertContainsTelemetryProperty(requestTelemetry, "ContentType", "application/json"); - }); - } - - [Fact] - public void LogRequestMessage_WithRequestAndResponseStatusCodeWithCustomId_CreatesRequestTelemetry() - { - // Arrange - var spySink = new InMemoryLogSink(); - string transactionId = $"transaction-{Guid.NewGuid()}"; - string operationParentId = $"parent-{Guid.NewGuid()}"; - ILogger logger = CreateLogger( - spySink, config => config.Enrich.WithProperty(ContextProperties.Correlation.OperationId, null) - .Enrich.WithProperty(ContextProperties.Correlation.TransactionId, transactionId) - .Enrich.WithProperty(ContextProperties.Correlation.OperationParentId, operationParentId)); - - Order order = OrderGenerator.Generate(); - string json = JsonSerializer.Serialize(order); - var telemetryContext = new Dictionary - { - ["Client"] = "https://localhost", - ["ContentType"] = "application/json", - ["RequestBody"] = json - }; - var request = new HttpRequestMessage(System.Net.Http.HttpMethod.Get, new Uri("https://" + "localhost" + "/api/v1/health")); - var statusCode = HttpStatusCode.OK; - TimeSpan duration = TimeSpan.FromSeconds(5); - logger.LogRequest(request, statusCode, duration, telemetryContext); - - LogEvent logEvent = Assert.Single(spySink.CurrentLogEmits); - Assert.NotNull(logEvent); - - var requestId = Guid.NewGuid().ToString(); - var converter = ApplicationInsightsTelemetryConverter.Create(new ApplicationInsightsSinkOptions - { - Request = { GenerateId = () => requestId } - }); - - // Act - IEnumerable telemetries = converter.Convert(logEvent, formatProvider: null); - - // Assert - AssertDoesContainLogProperty(logEvent, RequestTracking.RequestLogEntry); - Assert.Collection(telemetries, telemetry => - { - var requestTelemetry = Assert.IsType(telemetry); - Assert.Equal("GET /api/v1/health", requestTelemetry.Name); - Assert.Equal(duration, requestTelemetry.Duration); - Assert.Equal(((int) statusCode).ToString(), requestTelemetry.ResponseCode); - Assert.True(requestTelemetry.Success); - Assert.Equal(new Uri("https://localhost/api/v1/health"), requestTelemetry.Url); - AssertOperationContextForRequest(requestTelemetry, requestId, transactionId, operationParentId); - - AssertContainsTelemetryProperty(requestTelemetry, "Client", "https://localhost"); - AssertContainsTelemetryProperty(requestTelemetry, "ContentType", "application/json"); - AssertContainsTelemetryProperty(requestTelemetry, "RequestBody", json); - }); - } - - [Fact] - public void LogRequest_WithRequestAndResponse_CreatesRequestTelemetry() - { - // Arrange - var spySink = new InMemoryLogSink(); - string operationId = $"operation-id-{Guid.NewGuid()}"; - string transactionId = $"transaction={Guid.NewGuid()}"; - string operationParentId = $"parent-{Guid.NewGuid()}"; - ILogger logger = CreateLogger( - spySink, config => config.Enrich.WithProperty(ContextProperties.Correlation.OperationId, operationId) - .Enrich.WithProperty(ContextProperties.Correlation.TransactionId, transactionId) - .Enrich.WithProperty(ContextProperties.Correlation.OperationParentId, operationParentId)); - - Order order = OrderGenerator.Generate(); - string json = JsonSerializer.Serialize(order); - var telemetryContext = new Dictionary - { - ["Client"] = "https://localhost", - ["ContentType"] = "application/json", - ["RequestBody"] = json - }; - var statusCode = HttpStatusCode.OK; - HttpRequest request = CreateStubRequest(HttpMethod.Get, "https", "localhost", "/api/v1/health"); - HttpResponse response = CreateStubResponse(statusCode); - TimeSpan duration = TimeSpan.FromSeconds(5); - logger.LogRequest(request, response, duration, telemetryContext); - - LogEvent logEvent = Assert.Single(spySink.CurrentLogEmits); - Assert.NotNull(logEvent); - - var converter = ApplicationInsightsTelemetryConverter.Create(); - - // Act - IEnumerable telemetries = converter.Convert(logEvent, formatProvider: null); - - // Assert - AssertDoesContainLogProperty(logEvent, RequestTracking.RequestLogEntry); - Assert.Collection(telemetries, telemetry => - { - var requestTelemetry = Assert.IsType(telemetry); - Assert.Equal("GET /api/v1/health", requestTelemetry.Name); - Assert.Equal(duration, requestTelemetry.Duration); - Assert.Equal(((int) statusCode).ToString(), requestTelemetry.ResponseCode); - Assert.True(requestTelemetry.Success); - Assert.Equal(new Uri("https://localhost/api/v1/health"), requestTelemetry.Url); - AssertOperationContextForRequest(requestTelemetry, operationId, transactionId, operationParentId); - - AssertContainsTelemetryProperty(requestTelemetry, "Client", "https://localhost"); - AssertContainsTelemetryProperty(requestTelemetry, "ContentType", "application/json"); - }); - } - - [Fact] - public void LogRequest_WithRequestAndResponseWithCustomId_CreatesRequestTelemetry() - { - // Arrange - var spySink = new InMemoryLogSink(); - string transactionId = $"transaction={Guid.NewGuid()}"; - string operationParentId = $"parent-{Guid.NewGuid()}"; - ILogger logger = CreateLogger( - spySink, config => config.Enrich.WithProperty(ContextProperties.Correlation.OperationId, null) - .Enrich.WithProperty(ContextProperties.Correlation.TransactionId, transactionId) - .Enrich.WithProperty(ContextProperties.Correlation.OperationParentId, operationParentId)); - - Order order = OrderGenerator.Generate(); - string json = JsonSerializer.Serialize(order); - var telemetryContext = new Dictionary - { - ["Client"] = "https://localhost", - ["ContentType"] = "application/json", - ["RequestBody"] = json - }; - var statusCode = HttpStatusCode.OK; - HttpRequest request = CreateStubRequest(HttpMethod.Get, "https", "localhost", "/api/v1/health"); - HttpResponse response = CreateStubResponse(statusCode); - TimeSpan duration = TimeSpan.FromSeconds(5); - logger.LogRequest(request, response, duration, telemetryContext); - - LogEvent logEvent = Assert.Single(spySink.CurrentLogEmits); - Assert.NotNull(logEvent); - - var requestId = Guid.NewGuid().ToString(); - var converter = ApplicationInsightsTelemetryConverter.Create(new ApplicationInsightsSinkOptions - { - Request = { GenerateId = () => requestId } - }); - - // Act - IEnumerable telemetries = converter.Convert(logEvent, formatProvider: null); - - // Assert - AssertDoesContainLogProperty(logEvent, RequestTracking.RequestLogEntry); - Assert.Collection(telemetries, telemetry => - { - var requestTelemetry = Assert.IsType(telemetry); - Assert.Equal("GET /api/v1/health", requestTelemetry.Name); - Assert.Equal(duration, requestTelemetry.Duration); - Assert.Equal(((int) statusCode).ToString(), requestTelemetry.ResponseCode); - Assert.True(requestTelemetry.Success); - Assert.Equal(new Uri("https://localhost/api/v1/health"), requestTelemetry.Url); - AssertOperationContextForRequest(requestTelemetry, requestId, transactionId, operationParentId); - - AssertContainsTelemetryProperty(requestTelemetry, "Client", "https://localhost"); - AssertContainsTelemetryProperty(requestTelemetry, "ContentType", "application/json"); - AssertContainsTelemetryProperty(requestTelemetry, "RequestBody", json); - }); - } - - [Fact] - public void LogRequest_WithRequestAndResponseStatusCode_CreatesRequestTelemetry() - { - // Arrange - var spySink = new InMemoryLogSink(); - string operationId = $"operation-id-{Guid.NewGuid()}"; - string transactionId = $"transaction={Guid.NewGuid()}"; - string operationParentId = $"parent-{Guid.NewGuid()}"; - ILogger logger = CreateLogger( - spySink, config => config.Enrich.WithProperty(ContextProperties.Correlation.OperationId, operationId) - .Enrich.WithProperty(ContextProperties.Correlation.TransactionId, transactionId) - .Enrich.WithProperty(ContextProperties.Correlation.OperationParentId, operationParentId)); - - Order order = OrderGenerator.Generate(); - string json = JsonSerializer.Serialize(order); - var telemetryContext = new Dictionary - { - ["Client"] = "https://localhost", - ["ContentType"] = "application/json", - ["RequestBody"] = json - }; - var statusCode = (int) HttpStatusCode.OK; - HttpRequest request = CreateStubRequest(HttpMethod.Get, "https", "localhost", "/api/v1/health"); - TimeSpan duration = TimeSpan.FromSeconds(5); - logger.LogRequest(request, statusCode, duration, telemetryContext); - - LogEvent logEvent = Assert.Single(spySink.CurrentLogEmits); - Assert.NotNull(logEvent); - - var converter = ApplicationInsightsTelemetryConverter.Create(); - - // Act - IEnumerable telemetries = converter.Convert(logEvent, formatProvider: null); - - // Assert - AssertDoesContainLogProperty(logEvent, RequestTracking.RequestLogEntry); - Assert.Collection(telemetries, telemetry => - { - var requestTelemetry = Assert.IsType(telemetry); - Assert.Equal("GET /api/v1/health", requestTelemetry.Name); - Assert.Equal(duration, requestTelemetry.Duration); - Assert.Equal(statusCode.ToString(), requestTelemetry.ResponseCode); - Assert.True(requestTelemetry.Success); - Assert.Equal(new Uri("https://localhost/api/v1/health"), requestTelemetry.Url); - AssertOperationContextForRequest(requestTelemetry, operationId, transactionId, operationParentId); - - AssertContainsTelemetryProperty(requestTelemetry, "Client", "https://localhost"); - AssertContainsTelemetryProperty(requestTelemetry, "ContentType", "application/json"); - }); - } - - [Fact] - public void LogRequest_WithRequestAndResponseStatusCodeWithCustomId_CreatesRequestTelemetry() - { - // Arrange - var spySink = new InMemoryLogSink(); - string transactionId = $"transaction={Guid.NewGuid()}"; - string operationParentId = $"parent-{Guid.NewGuid()}"; - ILogger logger = CreateLogger( - spySink, config => config.Enrich.WithProperty(ContextProperties.Correlation.OperationId, null) - .Enrich.WithProperty(ContextProperties.Correlation.TransactionId, transactionId) - .Enrich.WithProperty(ContextProperties.Correlation.OperationParentId, operationParentId)); - - Order order = OrderGenerator.Generate(); - string json = JsonSerializer.Serialize(order); - var telemetryContext = new Dictionary - { - ["Client"] = "https://localhost", - ["ContentType"] = "application/json", - ["RequestBody"] = json - }; - var statusCode = (int) HttpStatusCode.OK; - HttpRequest request = CreateStubRequest(HttpMethod.Get, "https", "localhost", "/api/v1/health"); - TimeSpan duration = TimeSpan.FromSeconds(5); - logger.LogRequest(request, statusCode, duration, telemetryContext); - - LogEvent logEvent = Assert.Single(spySink.CurrentLogEmits); - Assert.NotNull(logEvent); - - var requestId = Guid.NewGuid().ToString(); - var converter = ApplicationInsightsTelemetryConverter.Create(new ApplicationInsightsSinkOptions() - { - Request = { GenerateId = () => requestId } - }); - - // Act - IEnumerable telemetries = converter.Convert(logEvent, formatProvider: null); - - // Assert - AssertDoesContainLogProperty(logEvent, RequestTracking.RequestLogEntry); - Assert.Collection(telemetries, telemetry => - { - var requestTelemetry = Assert.IsType(telemetry); - Assert.Equal("GET /api/v1/health", requestTelemetry.Name); - Assert.Equal(duration, requestTelemetry.Duration); - Assert.Equal(statusCode.ToString(), requestTelemetry.ResponseCode); - Assert.True(requestTelemetry.Success); - Assert.Equal(new Uri("https://localhost/api/v1/health"), requestTelemetry.Url); - AssertOperationContextForRequest(requestTelemetry, requestId, transactionId, operationParentId); - - AssertContainsTelemetryProperty(requestTelemetry, "Client", "https://localhost"); - AssertContainsTelemetryProperty(requestTelemetry, "ContentType", "application/json"); - AssertContainsTelemetryProperty(requestTelemetry, "RequestBody", json); - }); - } - [Fact] public void LogDependency_WithDependency_CreatesDependencyTelemetry() { diff --git a/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/HttpRequestLoggingTests.cs b/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/HttpRequestLoggingTests.cs index 89526832..9b0b0e3c 100644 --- a/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/HttpRequestLoggingTests.cs +++ b/src/Arcus.Observability.Tests.Unit/Telemetry/Logging/HttpRequestLoggingTests.cs @@ -1393,336 +1393,5 @@ private static HttpRequest CreateStubRequest(HttpMethod method, string host, str return stubRequest.Object; } - - [Fact] - public void LogRequestObsolete_ValidArgumentsIncludingResponse_Succeeds() - { - // Arrange - var logger = new TestLogger(); - var statusCode = (int)_bogusGenerator.PickRandom(); - var path = $"/{_bogusGenerator.Lorem.Word()}"; - var host = _bogusGenerator.Lorem.Word(); - var method = HttpMethod.Head; - var mockRequest = new Mock(); - mockRequest.Setup(request => request.Method).Returns(method.ToString()); - mockRequest.Setup(request => request.Host).Returns(new HostString(host)); - mockRequest.Setup(request => request.Path).Returns(path); - var mockResponse = new Mock(); - mockResponse.Setup(response => response.StatusCode).Returns(statusCode); - var duration = _bogusGenerator.Date.Timespan(); - - // Act - logger.LogRequest(mockRequest.Object, mockResponse.Object, duration); - - // Assert - var logMessage = logger.WrittenMessage; - Assert.Contains(TelemetryType.Request.ToString(), logMessage); - Assert.Contains(path, logMessage); - Assert.Contains(host, logMessage); - Assert.Contains(statusCode.ToString(), logMessage); - Assert.Contains(method.ToString(), logMessage); - } - - [Fact] - public void LogRequest_ValidArgumentsIncludingResponseStatusCode_Succeeds() - { - // Arrange - var logger = new TestLogger(); - var statusCode = (int)_bogusGenerator.PickRandom(); - var path = $"/{_bogusGenerator.Lorem.Word()}"; - var host = _bogusGenerator.Lorem.Word(); - var method = HttpMethod.Head; - var mockRequest = new Mock(); - mockRequest.Setup(request => request.Method).Returns(method.ToString()); - mockRequest.Setup(request => request.Host).Returns(new HostString(host)); - mockRequest.Setup(request => request.Path).Returns(path); - var duration = _bogusGenerator.Date.Timespan(); - - // Act - logger.LogRequest(mockRequest.Object, statusCode, duration); - - // Assert - var logMessage = logger.WrittenMessage; - Assert.Contains(TelemetryType.Request.ToString(), logMessage); - Assert.Contains(path, logMessage); - Assert.Contains(host, logMessage); - Assert.Contains(statusCode.ToString(), logMessage); - Assert.Contains(method.ToString(), logMessage); - } - - [Fact] - public void LogRequest_WithNegativeDuration_Fails() - { - // Arrange - var logger = new TestLogger(); - var statusCode = (int)_bogusGenerator.PickRandom(); - var path = $"/{_bogusGenerator.Lorem.Word()}"; - var host = _bogusGenerator.Lorem.Word(); - var method = HttpMethod.Head; - var mockRequest = new Mock(); - mockRequest.Setup(request => request.Method).Returns(method.ToString()); - mockRequest.Setup(request => request.Host).Returns(new HostString(host)); - mockRequest.Setup(request => request.Path).Returns(path); - var mockResponse = new Mock(); - mockResponse.Setup(response => response.StatusCode).Returns(statusCode); - TimeSpan duration = TimeSpanGenerator.GeneratePositiveDuration().Negate(); - - // Act / Assert - Assert.ThrowsAny(() => logger.LogRequest(mockRequest.Object, mockResponse.Object, duration)); - } - - [Fact] - public void LogRequest_RequestWithSchemeWithWhitespaceWasSpecified_ThrowsException() - { - // Arrange - var logger = new TestLogger(); - var saboteurRequest = new Mock(); - saboteurRequest.Setup(r => r.Host).Returns(new HostString("hostname")); - saboteurRequest.Setup(r => r.Scheme).Returns("scheme with spaces"); - var stubResponse = new Mock(); - var statusCode = (int)_bogusGenerator.PickRandom(); - stubResponse.Setup(response => response.StatusCode).Returns(statusCode); - TimeSpan duration = _bogusGenerator.Date.Timespan(); - - // Act & Assert - Assert.Throws(() => logger.LogRequest(saboteurRequest.Object, stubResponse.Object, duration)); - } - - [Fact] - public void LogRequest_RequestWithoutHostWasSpecified_ThrowsException() - { - // Arrange - var logger = new TestLogger(); - var saboteurRequest = new Mock(); - saboteurRequest.Setup(r => r.Host).Returns(new HostString()); - var stubResponse = new Mock(); - var statusCode = (int)_bogusGenerator.PickRandom(); - stubResponse.Setup(response => response.StatusCode).Returns(statusCode); - TimeSpan duration = _bogusGenerator.Date.Timespan(); - - // Act & Assert - Assert.Throws(() => logger.LogRequest(saboteurRequest.Object, stubResponse.Object, duration)); - } - - [Fact] - public void LogRequest_RequestWithHostWithWhitespaceWasSpecified_ThrowsException() - { - // Arrange - var logger = new TestLogger(); - var saboteurRequest = new Mock(); - saboteurRequest.Setup(r => r.Host).Returns(new HostString("host with spaces")); - var stubResponse = new Mock(); - var statusCode = (int)_bogusGenerator.PickRandom(); - stubResponse.Setup(response => response.StatusCode).Returns(statusCode); - TimeSpan duration = _bogusGenerator.Date.Timespan(); - - // Act & Assert - Assert.Throws(() => logger.LogRequest(saboteurRequest.Object, stubResponse.Object, duration)); - } - - [Fact] - public void LogRequest_NoRequestWasSpecified_ThrowsException() - { - // Arrange - var logger = new TestLogger(); - var statusCode = (int)_bogusGenerator.PickRandom(); - HttpRequest request = null; - var mockResponse = new Mock(); - mockResponse.Setup(response => response.StatusCode).Returns(statusCode); - var duration = _bogusGenerator.Date.Timespan(); - - // Act & Arrange - Assert.ThrowsAny(() => logger.LogRequest(request, mockResponse.Object, duration)); - } - - [Fact] - public void LogRequest_OutsideResponseStatusCodeRange_ThrowsException() - { - // Arrange - var logger = new TestLogger(); - var statusCode = _bogusGenerator.PickRandom( - _bogusGenerator.Random.Int(max: -1), - _bogusGenerator.Random.Int(min: 1000)); - HttpRequest request = null; - var mockResponse = new Mock(); - mockResponse.Setup(response => response.StatusCode).Returns(statusCode); - var duration = _bogusGenerator.Date.Timespan(); - - // Act & Arrange - Assert.ThrowsAny(() => logger.LogRequest(request, mockResponse.Object, duration)); - } - - [Fact] - public void LogRequest_RequestWithSchemeWithWhitespaceWasSpecifiedWhenPassingResponseStatusCode_ThrowsException() - { - // Arrange - var logger = new TestLogger(); - var saboteurRequest = new Mock(); - saboteurRequest.Setup(r => r.Host).Returns(new HostString("hostname")); - saboteurRequest.Setup(r => r.Scheme).Returns("scheme with spaces"); - var statusCode = (int)_bogusGenerator.PickRandom(); - TimeSpan duration = _bogusGenerator.Date.Timespan(); - - // Act & Assert - Assert.Throws(() => logger.LogRequest(saboteurRequest.Object, statusCode, duration)); - } - - [Fact] - public void LogRequest_RequestWithoutHostWasSpecifiedWhenPassingResponseStatusCode_ThrowsException() - { - // Arrange - var logger = new TestLogger(); - var saboteurRequest = new Mock(); - saboteurRequest.Setup(r => r.Host).Returns(new HostString()); - var statusCode = (int)_bogusGenerator.PickRandom(); - TimeSpan duration = _bogusGenerator.Date.Timespan(); - - // Act & Assert - Assert.Throws(() => logger.LogRequest(saboteurRequest.Object, statusCode, duration)); - } - - [Fact] - public void LogRequest_RequestWithHostWithWhitespaceWasSpecifiedWhenPassingResponseStatusCode_ThrowsException() - { - // Arrange - var logger = new TestLogger(); - var saboteurRequest = new Mock(); - saboteurRequest.Setup(r => r.Host).Returns(new HostString("host with spaces")); - var statusCode = (int)_bogusGenerator.PickRandom(); - TimeSpan duration = _bogusGenerator.Date.Timespan(); - - // Act & Assert - Assert.ThrowsAny(() => logger.LogRequest(saboteurRequest.Object, statusCode, duration)); - } - - [Fact] - public void LogRequest_NoRequestWasSpecifiedWhenPassingResponseStatusCode_ThrowsException() - { - // Arrange - var logger = new TestLogger(); - var statusCode = (int)_bogusGenerator.PickRandom(); - HttpRequest request = null; - var duration = _bogusGenerator.Date.Timespan(); - - // Act & Arrange - Assert.ThrowsAny(() => logger.LogRequest(request, statusCode, duration)); - } - - [Fact] - public void LogRequest_OutsideResponseStatusCodeRangeWhenPassingResponseStatusCode_Fails() - { - // Arrange - var logger = new TestLogger(); - var request = new Mock(); - var statusCode = _bogusGenerator.PickRandom( - _bogusGenerator.Random.Int(max: -1), - _bogusGenerator.Random.Int(min: 1000)); - TimeSpan duration = _bogusGenerator.Date.Timespan(); - - // Act & Assert - Assert.Throws(() => logger.LogRequest(request.Object, statusCode, duration)); - } - - [Fact] - public void LogRequest_NoResponseWasSpecified_ThrowsException() - { - // Arrange - var logger = new TestLogger(); - var path = $"/{_bogusGenerator.Name.FirstName()}"; - var host = _bogusGenerator.Name.FirstName(); - var method = HttpMethod.Head; - var mockRequest = new Mock(); - mockRequest.Setup(request => request.Method).Returns(method.ToString()); - mockRequest.Setup(request => request.Host).Returns(new HostString(host)); - mockRequest.Setup(request => request.Path).Returns(path); - HttpResponse response = null; - var duration = _bogusGenerator.Date.Timespan(); - - // Act & Arrange - Assert.ThrowsAny(() => logger.LogRequest(mockRequest.Object, response, duration)); - } - - [Fact] - public void LogRequestMessage_ValidArgumentsIncludingResponse_Succeeds() - { - // Arrange - var logger = new TestLogger(); - var statusCode = _bogusGenerator.PickRandom(); - var path = $"/{_bogusGenerator.Name.FirstName().ToLower()}"; - var host = _bogusGenerator.Name.FirstName().ToLower(); - var method = HttpMethod.Head; - var request = new HttpRequestMessage(method, new Uri("https://" + host + path)); - var response = new HttpResponseMessage(statusCode); - var duration = _bogusGenerator.Date.Timespan(); - - // Act - logger.LogRequest(request, response, duration); - - // Assert - var logMessage = logger.WrittenMessage; - Assert.Contains(TelemetryType.Request.ToString(), logMessage); - Assert.Contains(path, logMessage); - Assert.Contains(host, logMessage); - Assert.Contains(((int)statusCode).ToString(), logMessage); - Assert.Contains(method.ToString(), logMessage); - } - - [Fact] - public void LogRequestMessage_ValidArgumentsIncludingResponseStatusCode_Succeeds() - { - // Arrange - var logger = new TestLogger(); - var statusCode = _bogusGenerator.PickRandom(); - var path = $"/{_bogusGenerator.Name.FirstName().ToLower()}"; - var host = _bogusGenerator.Name.FirstName().ToLower(); - var method = HttpMethod.Head; - var request = new HttpRequestMessage(method, new Uri("https://" + host + path)); - var duration = _bogusGenerator.Date.Timespan(); - - // Act; - logger.LogRequest(request, statusCode, duration); - - // Assert - var logMessage = logger.WrittenMessage; - Assert.Contains(TelemetryType.Request.ToString(), logMessage); - Assert.Contains(path, logMessage); - Assert.Contains(host, logMessage); - Assert.Contains(((int)statusCode).ToString(), logMessage); - Assert.Contains(method.ToString(), logMessage); - } - - [Fact] - public void LogRequestMessage_WithNegativeDuration_Fails() - { - // Arrange - var logger = new TestLogger(); - var statusCode = _bogusGenerator.PickRandom(); - var path = $"/{_bogusGenerator.Name.FirstName().ToLower()}"; - var host = _bogusGenerator.Name.FirstName().ToLower(); - var method = HttpMethod.Head; - var request = new HttpRequestMessage(method, new Uri("https://" + host + path)); - TimeSpan duration = TimeSpanGenerator.GeneratePositiveDuration().Negate(); - - // Act / Assert - Assert.ThrowsAny(() => logger.LogRequest(request, statusCode, duration)); - } - - [Fact] - public void LogRequestMessage_OutsideResponseStatusCodeRange_Fails() - { - // Arrange - var logger = new TestLogger(); - var statusCode = (HttpStatusCode)_bogusGenerator.PickRandom( - _bogusGenerator.Random.Int(max: -1), - _bogusGenerator.Random.Int(min: 1000)); - var path = $"/{_bogusGenerator.Name.FirstName().ToLower()}"; - var host = _bogusGenerator.Name.FirstName().ToLower(); - var method = HttpMethod.Head; - var request = new HttpRequestMessage(method, new Uri("https://" + host + path)); - TimeSpan duration = _bogusGenerator.Date.Timespan(); - - // Act & Assert - Assert.ThrowsAny(() => logger.LogRequest(request, statusCode, duration)); - } } }