Skip to content

Commit

Permalink
feat: diff request & other correlation assignments (#411)
Browse files Browse the repository at this point in the history
* feat: diff request & other correlation assignments

* pr-fix: revert unn test changes

* pr-fix: update with correct correlation assertions

* pr-fix: update with more stable exception integration tests

* pr-fix: rm req id assert in az func docker test

* pr-fix: exceptoin property format determination with both options
  • Loading branch information
stijnmoreels committed Jun 22, 2022
1 parent ec05b7a commit 3b9c3a3
Show file tree
Hide file tree
Showing 20 changed files with 642 additions and 433 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,21 @@ public class ApplicationInsightsTelemetryConverter : TelemetryConverterBase
{
private readonly RequestTelemetryConverter _requestTelemetryConverter;
private readonly ExceptionTelemetryConverter _exceptionTelemetryConverter;
private readonly TraceTelemetryConverter _traceTelemetryConverter = new TraceTelemetryConverter();
private readonly EventTelemetryConverter _eventTelemetryConverter = new EventTelemetryConverter();
private readonly MetricTelemetryConverter _metricTelemetryConverter = new MetricTelemetryConverter();
private readonly DependencyTelemetryConverter _dependencyTelemetryConverter = new DependencyTelemetryConverter();
private readonly TraceTelemetryConverter _traceTelemetryConverter;
private readonly EventTelemetryConverter _eventTelemetryConverter;
private readonly MetricTelemetryConverter _metricTelemetryConverter;
private readonly DependencyTelemetryConverter _dependencyTelemetryConverter;

private ApplicationInsightsTelemetryConverter(ApplicationInsightsSinkOptions options)
{
Guard.NotNull(options, nameof(options), "Requires a set of options to influence how to track to Application Insights");
_requestTelemetryConverter = new RequestTelemetryConverter(options.Request);
_exceptionTelemetryConverter = new ExceptionTelemetryConverter(options.Exception);

_requestTelemetryConverter = new RequestTelemetryConverter(options);
_exceptionTelemetryConverter = new ExceptionTelemetryConverter(options);
_traceTelemetryConverter = new TraceTelemetryConverter(options);
_eventTelemetryConverter = new EventTelemetryConverter(options);
_metricTelemetryConverter = new MetricTelemetryConverter(options);
_dependencyTelemetryConverter = new DependencyTelemetryConverter(options);
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using Arcus.Observability.Telemetry.Core;
using Arcus.Observability.Telemetry.Serilog.Sinks.ApplicationInsights.Configuration;
using GuardNet;
using Microsoft.ApplicationInsights.Channel;
using Microsoft.ApplicationInsights.DataContracts;
Expand All @@ -16,9 +17,35 @@ namespace Arcus.Observability.Telemetry.Serilog.Sinks.ApplicationInsights.Conver
public abstract class CustomTelemetryConverter<TEntry> : TelemetryConverterBase
where TEntry : ITelemetry, ISupportProperties
{
private readonly OperationContextConverter _operationContextConverter = new OperationContextConverter();
private readonly OperationContextConverter _operationContextConverter;
private readonly CloudContextConverter _cloudContextConverter = new CloudContextConverter();

/// <summary>
/// Initializes a new instance of the <see cref="CustomTelemetryConverter{TEntry}" /> class.
/// </summary>
[Obsolete("Use the constructor overload with the Application Insights options instead")]
protected CustomTelemetryConverter() : this(new ApplicationInsightsSinkOptions())
{
}

/// <summary>
/// Initializes a new instance of the <see cref="CustomTelemetryConverter{TEntry}" /> class.
/// </summary>
/// <param name="options">The user-defined configuration options to influence the behavior of the Application Insights Serilog sink.</param>
/// <exception cref="ArgumentNullException">Thrown when the <paramref name="options"/> is <c>null</c>.</exception>
protected CustomTelemetryConverter(ApplicationInsightsSinkOptions options)
{
Guard.NotNull(options, nameof(options), "Requires a set of options to influence the behavior of the Application Insights Serilog sink");

_operationContextConverter = new OperationContextConverter(options);
Options = options;
}

/// <summary>
/// Gets the user-defined configuration options to influence the behavior of the Application Insights Serilog sink.
/// </summary>
protected ApplicationInsightsSinkOptions Options { get; }

/// <summary>
/// Convert the given <paramref name="logEvent"/> to a series of <see cref="ITelemetry"/> instances.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using Arcus.Observability.Telemetry.Core;
using Arcus.Observability.Telemetry.Core.Logging;
using Arcus.Observability.Telemetry.Serilog.Sinks.ApplicationInsights.Configuration;
using GuardNet;
using Microsoft.ApplicationInsights.DataContracts;
using Serilog.Events;
Expand All @@ -13,6 +14,23 @@ namespace Arcus.Observability.Telemetry.Serilog.Sinks.ApplicationInsights.Conver
/// </summary>
public class DependencyTelemetryConverter : CustomTelemetryConverter<DependencyTelemetry>
{
/// <summary>
/// Initializes a new instance of the <see cref="DependencyTelemetryConverter" /> class.
/// </summary>
[Obsolete("Use the constructor overload with the Application Insights options instead")]
public DependencyTelemetryConverter()
{
}

/// <summary>
/// Initializes a new instance of the <see cref="DependencyTelemetryConverter" /> class.
/// </summary>
/// <param name="options">The user-defined configuration options to influence the behavior of the Application Insights Serilog sink.</param>
/// <exception cref="ArgumentNullException">Thrown when the <paramref name="options"/> is <c>null</c>.</exception>
public DependencyTelemetryConverter(ApplicationInsightsSinkOptions options) : base(options)
{
}

/// <summary>
/// Creates a telemetry entry for a given log event
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using Arcus.Observability.Telemetry.Core;
using Arcus.Observability.Telemetry.Core.Logging;
using Arcus.Observability.Telemetry.Serilog.Sinks.ApplicationInsights.Configuration;
using GuardNet;
using Microsoft.ApplicationInsights.DataContracts;
using Serilog.Events;
Expand All @@ -13,6 +14,23 @@ namespace Arcus.Observability.Telemetry.Serilog.Sinks.ApplicationInsights.Conver
/// </summary>
public class EventTelemetryConverter : CustomTelemetryConverter<EventTelemetry>
{
/// <summary>
/// Initializes a new instance of the <see cref="EventTelemetryConverter" /> class.
/// </summary>
[Obsolete("Use the constructor overload with the Application Insights options instead")]
public EventTelemetryConverter()
{
}

/// <summary>
/// Initializes a new instance of the <see cref="EventTelemetryConverter" /> class.
/// </summary>
/// <param name="options">The user-defined configuration options to influence the behavior of the Application Insights Serilog sink.</param>
/// <exception cref="ArgumentNullException">Thrown when the <paramref name="options"/> is <c>null</c>.</exception>
public EventTelemetryConverter(ApplicationInsightsSinkOptions options) : base(options)
{
}

/// <summary>
/// Creates a telemetry entry for a given log event
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,21 @@ public class ExceptionTelemetryConverter : CustomTelemetryConverter<ExceptionTel
/// </summary>
/// <param name="options">The consumer-configurable options to influence how the exception should be tracked.</param>
/// <exception cref="ArgumentNullException">Thrown when the <paramref name="options"/> is <c>null</c>.</exception>
[Obsolete("Use the constructor overload with the Application Insights options instead")]
public ExceptionTelemetryConverter(ApplicationInsightsSinkExceptionOptions options)
{
Guard.NotNull(options, nameof(options), "Requires a set of user-configurable options to influence the behavior of how exceptions are tracked");
_options = options;
}

/// <summary>
/// Initializes a new instance of the <see cref="ExceptionTelemetryConverter" /> class.
/// </summary>
/// <param name="options">The user-defined configuration options to influence the behavior of the Application Insights Serilog sink.</param>
/// <exception cref="ArgumentNullException">Thrown when the <paramref name="options"/> is <c>null</c>.</exception>
public ExceptionTelemetryConverter(ApplicationInsightsSinkOptions options) : base(options)
{
}

/// <summary>
/// Creates a telemetry entry for a given log event
Expand All @@ -40,7 +50,7 @@ protected override ExceptionTelemetry CreateTelemetryEntry(LogEvent logEvent, IF

var exceptionTelemetry = new ExceptionTelemetry(logEvent.Exception);

if (_options.IncludeProperties)
if (Options?.Exception.IncludeProperties == true || _options?.IncludeProperties == true)
{
EnrichWithExceptionProperties(logEvent, exceptionTelemetry);
}
Expand All @@ -55,10 +65,28 @@ private void EnrichWithExceptionProperties(LogEvent logEvent, ExceptionTelemetry

foreach (PropertyInfo exceptionProperty in exceptionProperties)
{
string key = String.Format(_options.PropertyFormat, exceptionProperty.Name);
string propertyFormat = DeterminePropertyFormat();

string key = String.Format(propertyFormat, exceptionProperty.Name);
var value = exceptionProperty.GetValue(logEvent.Exception)?.ToString();
exceptionTelemetry.Properties[key] = value;
}
}

private string DeterminePropertyFormat()
{
if (Options != null)
{
return Options.Exception.PropertyFormat;
}

if (_options != null)
{
return _options.PropertyFormat;
}

throw new InvalidOperationException(
"Could not determine exception property format because the Application Insights exception converter was not initialized with any options");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using Arcus.Observability.Telemetry.Core;
using Arcus.Observability.Telemetry.Core.Logging;
using Arcus.Observability.Telemetry.Serilog.Sinks.ApplicationInsights.Configuration;
using GuardNet;
using Microsoft.ApplicationInsights.DataContracts;
using Serilog.Events;
Expand All @@ -13,6 +14,23 @@ namespace Arcus.Observability.Telemetry.Serilog.Sinks.ApplicationInsights.Conver
/// </summary>
public class MetricTelemetryConverter : CustomTelemetryConverter<MetricTelemetry>
{
/// <summary>
/// Initializes a new instance of the <see cref="MetricTelemetryConverter" /> class.
/// </summary>
[Obsolete("Use the constructor overload with the Application Insights options instead")]
public MetricTelemetryConverter()
{
}

/// <summary>
/// Initializes a new instance of the <see cref="MetricTelemetryConverter" /> class.
/// </summary>
/// <param name="options">The user-defined configuration options to influence the behavior of the Application Insights Serilog sink.</param>
/// <exception cref="ArgumentNullException">Thrown when the <paramref name="options"/> is <c>null</c>.</exception>
public MetricTelemetryConverter(ApplicationInsightsSinkOptions options) : base(options)
{
}

/// <summary>
/// Creates a telemetry entry for a given log event
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
using Microsoft.ApplicationInsights.DataContracts;
using Microsoft.ApplicationInsights.Extensibility.Implementation;
using System;
using Arcus.Observability.Telemetry.Serilog.Sinks.ApplicationInsights.Configuration;
using GuardNet;

namespace Arcus.Observability.Telemetry.Serilog.Sinks.ApplicationInsights.Converters
{
Expand All @@ -11,6 +13,27 @@ namespace Arcus.Observability.Telemetry.Serilog.Sinks.ApplicationInsights.Conver
/// </summary>
public class OperationContextConverter
{
private readonly ApplicationInsightsSinkOptions _options;

/// <summary>
/// Initializes a new instance of the <see cref="OperationContextConverter" /> class.
/// </summary>
[Obsolete("Use the constructor overload with the Application Insights options instead")]
public OperationContextConverter()
{
}

/// <summary>
/// Initializes a new instance of the <see cref="OperationContextConverter" /> class.
/// </summary>
/// <param name="options">The user-defined configuration options to influence the behavior of the Application Insights Serilog sink.</param>
/// <exception cref="ArgumentNullException">Thrown when the <paramref name="options"/> is <c>null</c>.</exception>
public OperationContextConverter(ApplicationInsightsSinkOptions options)
{
Guard.NotNull(options, nameof(options), "Requires a set of options to influence the behavior of the Application Insights Serilog sink");
_options = options;
}

/// <summary>
/// Enrich the given <paramref name="telemetryEntry"/> with the Operation-related information.
/// </summary>
Expand All @@ -22,14 +45,39 @@ public void EnrichWithCorrelationInfo<TEntry>(TEntry telemetryEntry) where TEntr
return;
}

if (telemetryEntry.Properties.TryGetValue(ContextProperties.Correlation.OperationId, out string operationId))
if (telemetryEntry is RequestTelemetry requestTelemetry)
{
telemetryEntry.Context.Operation.Id = operationId;
}
if (telemetryEntry.Properties.TryGetValue(ContextProperties.Correlation.OperationId, out string operationId))
{
if (operationId is null || operationId is "null")
{
operationId = _options.Request.GenerateId();
}

if (telemetryEntry.Properties.TryGetValue(ContextProperties.Correlation.OperationParentId, out string operationParentId))
requestTelemetry.Id = operationId;
}

if (telemetryEntry.Properties.TryGetValue(ContextProperties.Correlation.TransactionId, out string transactionId))
{
telemetryEntry.Context.Operation.Id = transactionId;
}

if (telemetryEntry.Properties.TryGetValue(ContextProperties.Correlation.OperationParentId, out string operationParentId))
{
telemetryEntry.Context.Operation.ParentId = operationParentId;
}
}
else
{
telemetryEntry.Context.Operation.ParentId = operationParentId;
if (telemetryEntry.Properties.TryGetValue(ContextProperties.Correlation.TransactionId, out string transactionId))
{
telemetryEntry.Context.Operation.Id = transactionId;
}

if (telemetryEntry.Properties.TryGetValue(ContextProperties.Correlation.OperationId, out string operationId))
{
telemetryEntry.Context.Operation.ParentId = operationId;
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public class RequestTelemetryConverter : CustomTelemetryConverter<RequestTelemet
/// <summary>
/// Initializes a new instance of the <see cref="RequestTelemetryConverter" /> class.
/// </summary>
[Obsolete("Use the constructor overload with the Application Insights options instead")]
public RequestTelemetryConverter()
: this(new ApplicationInsightsSinkRequestOptions())
{
Expand All @@ -29,12 +30,22 @@ public RequestTelemetryConverter()
/// </summary>
/// <param name="options">The user-defined configuration options to tracking requests.</param>
/// <exception cref="ArgumentNullException">Thrown when the <paramref name="options" /> is <c>null</c>.</exception>
[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;
}


/// <summary>
/// Initializes a new instance of the <see cref="RequestTelemetryConverter" /> class.
/// </summary>
/// <param name="options">The user-defined configuration options to influence the behavior of the Application Insights Serilog sink.</param>
/// <exception cref="ArgumentNullException">Thrown when the <paramref name="options"/> is <c>null</c>.</exception>
public RequestTelemetryConverter(ApplicationInsightsSinkOptions options) : base(options)
{
}

/// <summary>
/// Creates a telemetry entry for a given log event
/// </summary>
Expand All @@ -57,8 +68,6 @@ protected override RequestTelemetry CreateTelemetryEntry(LogEvent logEvent, IFor
IDictionary<string, string> context = logEntry.Properties.GetAsDictionary(nameof(RequestLogEntry.Context));
var sourceSystem = logEntry.Properties.GetAsObject<RequestSourceSystem>(nameof(RequestLogEntry.SourceSystem));

string id = _options.GenerateId();

string sourceName = DetermineSourceName(sourceSystem, requestMethod, requestUri, operationName);
bool isSuccessfulRequest = DetermineRequestOutcome(responseStatusCode);
Uri url = DetermineUrl(sourceSystem, requestHost, requestUri);
Expand All @@ -67,12 +76,16 @@ protected override RequestTelemetry CreateTelemetryEntry(LogEvent logEvent, IFor

var requestTelemetry = new RequestTelemetry(sourceName, requestTime, requestDuration, responseStatusCode, isSuccessfulRequest)
{
Id = id,
Url = url,
Source = source,
Context = { Operation = { Name = requestOperationName } }
};

if (_options != null)
{
requestTelemetry.Id = _options.GenerateId();
}

requestTelemetry.Properties.AddRange(context);
return requestTelemetry;
}
Expand Down
Loading

0 comments on commit 3b9c3a3

Please sign in to comment.