Skip to content

Commit

Permalink
[AzureMonitorExporter] add Activity Exception demo and test (Azure#…
Browse files Browse the repository at this point in the history
…31764)

* activity exception demo and test

* cleanup usings
  • Loading branch information
TimothyMothra authored Oct 12, 2022
1 parent b7b0fe4 commit 9618cd8
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,19 @@ public void GenerateTraces()
nestedActivity?.SetStatus(ActivityStatusCode.Ok);
}
}

using (var activity = activitySource.StartActivity("ExceptionExample"))
{
try
{
throw new Exception("Test exception");
}
catch (Exception ex)
{
activity?.SetStatus(ActivityStatusCode.Error);
activity?.RecordException(ex);
}
}
}

public void Dispose()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
Expand Down Expand Up @@ -132,14 +133,16 @@ public static void AssertLog_As_ExceptionTelemetry(
Assert.Equal(expectedMessage, telemetryExceptionDetails.Message);
Assert.Equal(expectedTypeName, telemetryExceptionDetails.TypeName);
Assert.True(telemetryExceptionDetails.ParsedStack.Any());
Assert.Null(telemetryExceptionDetails.Stack);
}

public static void AssertActivity_As_DependencyTelemetry(
TelemetryItem telemetryItem,
string expectedName,
string expectedTraceId,
string expectedSpanId,
IDictionary<string, string> expectedProperties)
IDictionary<string, string> expectedProperties,
bool expectedSuccess = true)
{
Assert.Equal("RemoteDependency", telemetryItem.Name); // telemetry type
Assert.Equal("RemoteDependencyData", telemetryItem.Data.BaseType); // telemetry data type
Expand All @@ -155,6 +158,7 @@ public static void AssertActivity_As_DependencyTelemetry(
var remoteDependencyData = (RemoteDependencyData)telemetryItem.Data.BaseData;
Assert.Equal(expectedSpanId, remoteDependencyData.Id);
Assert.Equal(expectedName, remoteDependencyData.Name);
Assert.Equal(expectedSuccess, remoteDependencyData.Success);

if (expectedProperties == null)
{
Expand All @@ -175,7 +179,8 @@ public static void AssertActivity_As_RequestTelemetry(
string expectedName,
string expectedTraceId,
IDictionary<string, string> expectedProperties,
string expectedSpanId)
string expectedSpanId,
bool expectedSuccess = true)
{
Assert.Equal("Request", telemetryItem.Name); // telemetry type
Assert.Equal("RequestData", telemetryItem.Data.BaseType); // telemetry data type
Expand All @@ -201,6 +206,7 @@ public static void AssertActivity_As_RequestTelemetry(
var requestData = (RequestData)telemetryItem.Data.BaseData;
Assert.Equal(expectedName, requestData.Name);
Assert.Equal(expectedSpanId, requestData.Id);
Assert.Equal(expectedSuccess, requestData.Success);

if (expectedProperties == null)
{
Expand All @@ -214,5 +220,38 @@ public static void AssertActivity_As_RequestTelemetry(
}
}
}

internal static void AssertActivity_RecordedException(
TelemetryItem telemetryItem,
string expectedExceptionMessage,
string expectedExceptionTypeName,
string expectedTraceId,
string expectedSpanId)
{
Assert.Equal("Exception", telemetryItem.Name); // telemetry type
Assert.Equal("ExceptionData", telemetryItem.Data.BaseType); // telemetry data type
Assert.Equal(2, telemetryItem.Data.BaseData.Version); // telemetry api version
Assert.Equal("00000000-0000-0000-0000-000000000000", telemetryItem.InstrumentationKey);

Assert.Equal(5, telemetryItem.Tags.Count);
Assert.Equal(expectedSpanId, telemetryItem.Tags["ai.operation.parentId"]);
Assert.Equal(expectedTraceId, telemetryItem.Tags["ai.operation.id"]);
Assert.Contains("ai.cloud.role", telemetryItem.Tags.Keys);
Assert.Contains("ai.cloud.roleInstance", telemetryItem.Tags.Keys);
Assert.Contains("ai.internal.sdkVersion", telemetryItem.Tags.Keys);

var telemetryExceptionData = (TelemetryExceptionData)telemetryItem.Data.BaseData;
Assert.Null(telemetryExceptionData.SeverityLevel);
Assert.Empty(telemetryExceptionData.Properties);

Assert.Equal(1, telemetryExceptionData.Exceptions.Count);

var telemetryExceptionDetails = (TelemetryExceptionDetails)telemetryExceptionData.Exceptions[0];
Assert.Equal(expectedExceptionMessage, telemetryExceptionDetails.Message);
Assert.Equal(expectedExceptionTypeName, telemetryExceptionDetails.TypeName);
Assert.True(telemetryExceptionDetails.HasFullStack);
Assert.Empty(telemetryExceptionDetails.ParsedStack);
Assert.False(string.IsNullOrEmpty(telemetryExceptionDetails.Stack));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,65 @@ public void VerifyTrace_CreatesRequest(ActivityKind activityKind)
expectedProperties: new Dictionary<string, string> { { "integer", "1" }, { "message", "Hello World!" }, { "intArray", "1,2,3" } });
}

[Fact]
public void VerifyExceptionWithinActivity()
{
// SETUP
var uniqueTestId = Guid.NewGuid();

var activitySourceName = $"activitySourceName{uniqueTestId}";
using var activitySource = new ActivitySource(activitySourceName);

var tracerProvider = Sdk.CreateTracerProviderBuilder()
.AddSource(activitySourceName)
.AddAzureMonitorTraceExporterForTest(out ConcurrentBag<TelemetryItem> telemetryItems)
.Build();

// ACT
string spanId = null, traceId = null;

using (var activity = activitySource.StartActivity(name: "ActivityWithException"))
{
traceId = activity.TraceId.ToHexString();
spanId = activity.SpanId.ToHexString();

try
{
throw new Exception("Test exception");
}
catch (Exception ex)
{
activity?.SetStatus(ActivityStatusCode.Error);
activity?.RecordException(ex);
}
}

// CLEANUP
tracerProvider.Dispose();

// ASSERT
Assert.True(telemetryItems.Any(), "Unit test failed to collect telemetry.");
this.telemetryOutput.Write(telemetryItems);
var activityTelemetryItem = telemetryItems.First(x => x.Name == "RemoteDependency"); // TODO: Change to Single(). Still investigating random duplicate export which only repros on build server.

TelemetryItemValidationHelper.AssertActivity_As_DependencyTelemetry(
telemetryItem: activityTelemetryItem,
expectedName: "ActivityWithException",
expectedTraceId: traceId,
expectedSpanId: spanId,
expectedProperties: null,
expectedSuccess: false);

var exceptionTelemetryItem = telemetryItems.First(x => x.Name == "Exception");

TelemetryItemValidationHelper.AssertActivity_RecordedException(
telemetryItem: exceptionTelemetryItem,
expectedExceptionMessage: "Test exception",
expectedExceptionTypeName: "System.Exception",
expectedTraceId: traceId,
expectedSpanId: spanId);
}

[Theory]
[InlineData(LogLevel.Information, "Information")]
[InlineData(LogLevel.Warning, "Warning")]
Expand Down

0 comments on commit 9618cd8

Please sign in to comment.