Implementation of RecordException in TelemetrySpan (#1116)
* Add RecordException method to TelemetrySpan * reusing ToInvariantString already implemented * updating changelog * checking for null * reusing method * Adding activity extension to record exception * adding aggressiveinlining Co-authored-by: Cijo Thomas <cithomas@microsoft.com>
This commit is contained in:
parent
83adf75f01
commit
1b6c39d879
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
## Unreleased
|
||||
|
||||
* Added `RecordException` in `TelemetrySpan`
|
||||
([#1116](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1116))
|
||||
* `PropagationContext` is now used instead of `ActivityContext` in the
|
||||
`ITextFormat` API
|
||||
([#1048](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1048))
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ using System.Diagnostics;
|
|||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Runtime.CompilerServices;
|
||||
using OpenTelemetry.Internal;
|
||||
|
||||
namespace OpenTelemetry.Trace
|
||||
{
|
||||
|
|
@ -84,6 +85,33 @@ namespace OpenTelemetry.Trace
|
|||
SetKindProperty(activity, kind);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Record Exception.
|
||||
/// </summary>
|
||||
/// <param name="activity">Activity instance.</param>
|
||||
/// <param name="ex">Exception to be recorded.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void RecordException(this Activity activity, Exception ex)
|
||||
{
|
||||
if (ex == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var tagsCollection = new ActivityTagsCollection
|
||||
{
|
||||
{ SemanticConventions.AttributeExceptionType, ex.GetType().Name },
|
||||
{ SemanticConventions.AttributeExceptionStacktrace, ex.ToInvariantString() },
|
||||
};
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(ex.Message))
|
||||
{
|
||||
tagsCollection.Add(SemanticConventions.AttributeExceptionMessage, ex.Message);
|
||||
}
|
||||
|
||||
activity?.AddEvent(new ActivityEvent(SemanticConventions.AttributeExceptionEventName, default, tagsCollection));
|
||||
}
|
||||
|
||||
#pragma warning disable SA1201 // Elements should appear in the correct order
|
||||
private static readonly Action<Activity, ActivityKind> SetKindProperty = CreateActivityKindSetter();
|
||||
#pragma warning restore SA1201 // Elements should appear in the correct order
|
||||
|
|
|
|||
|
|
@ -23,7 +23,8 @@ namespace OpenTelemetry.Trace
|
|||
internal static class SemanticConventions
|
||||
{
|
||||
// The set of constants matches the specification as of this commit.
|
||||
// https://github.com/open-telemetry/opentelemetry-specification/tree/709293fe132709705f0e0dd4252992e87a6ec899/specification/trace/semantic_conventions
|
||||
// https://github.com/open-telemetry/opentelemetry-specification/tree/master/specification/trace/semantic_conventions
|
||||
// https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/semantic_conventions/exceptions.md
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
public const string AttributeServiceName = "service.name";
|
||||
public const string AttributeServiceNamespace = "service.namespace";
|
||||
|
|
@ -147,6 +148,11 @@ namespace OpenTelemetry.Trace
|
|||
public const string AttributeMessagingPayloadSize = "messaging.message_payload_size_bytes";
|
||||
public const string AttributeMessagingPayloadCompressedSize = "messaging.message_payload_compressed_size_bytes";
|
||||
public const string AttributeMessagingOperation = "messaging.operation";
|
||||
|
||||
public const string AttributeExceptionEventName = "exception";
|
||||
public const string AttributeExceptionType = "exception.type";
|
||||
public const string AttributeExceptionMessage = "exception.message";
|
||||
public const string AttributeExceptionStacktrace = "exception.stacktrace";
|
||||
#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using OpenTelemetry.Internal;
|
||||
|
||||
namespace OpenTelemetry.Trace
|
||||
{
|
||||
|
|
@ -303,6 +304,56 @@ namespace OpenTelemetry.Trace
|
|||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Record Exception.
|
||||
/// </summary>
|
||||
/// <param name="ex">Exception to be recorded.</param>
|
||||
/// <returns>The <see cref="TelemetrySpan"/> instance for chaining.</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public TelemetrySpan RecordException(Exception ex)
|
||||
{
|
||||
if (ex == null)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
return this.RecordException(ex.GetType().Name, ex.Message, ex.ToInvariantString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Record Exception.
|
||||
/// </summary>
|
||||
/// <param name="type">Type of the exception to be recorded.</param>
|
||||
/// <param name="message">Message of the exception to be recorded.</param>
|
||||
/// <param name="stacktrace">Stacktrace of the exception to be recorded.</param>
|
||||
/// <returns>The <see cref="TelemetrySpan"/> instance for chaining.</returns>
|
||||
public TelemetrySpan RecordException(string type, string message, string stacktrace)
|
||||
{
|
||||
Dictionary<string, object> attributes = new Dictionary<string, object>();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(type))
|
||||
{
|
||||
attributes.Add(SemanticConventions.AttributeExceptionType, type);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(stacktrace))
|
||||
{
|
||||
attributes.Add(SemanticConventions.AttributeExceptionStacktrace, stacktrace);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(message))
|
||||
{
|
||||
attributes.Add(SemanticConventions.AttributeExceptionMessage, message);
|
||||
}
|
||||
|
||||
if (attributes.Count != 0)
|
||||
{
|
||||
this.AddEvent(SemanticConventions.AttributeExceptionEventName, attributes);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Dispose()
|
||||
|
|
|
|||
|
|
@ -14,7 +14,9 @@
|
|||
// limitations under the License.
|
||||
// </copyright>
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using Xunit;
|
||||
|
||||
namespace OpenTelemetry.Trace.Tests
|
||||
|
|
@ -114,5 +116,18 @@ namespace OpenTelemetry.Trace.Tests
|
|||
|
||||
Assert.Equal(inputOutput, activity.Kind);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CheckRecordException()
|
||||
{
|
||||
var message = "message";
|
||||
var exception = new ArgumentNullException(message, new Exception(message));
|
||||
var activity = new Activity("test-activity");
|
||||
activity.RecordException(exception);
|
||||
|
||||
var @event = activity.Events.FirstOrDefault(e => e.Name == SemanticConventions.AttributeExceptionEventName);
|
||||
Assert.Equal(message, @event.Tags.FirstOrDefault(t => t.Key == SemanticConventions.AttributeExceptionMessage).Value);
|
||||
Assert.Equal(exception.GetType().Name, @event.Tags.FirstOrDefault(t => t.Key == SemanticConventions.AttributeExceptionType).Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,72 @@
|
|||
// <copyright file="TelemetrySpanTest.cs" company="OpenTelemetry Authors">
|
||||
// Copyright The OpenTelemetry Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// </copyright>
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using OpenTelemetry.Trace;
|
||||
using Xunit;
|
||||
|
||||
namespace OpenTelemetry.Tests.Trace
|
||||
{
|
||||
public class TelemetrySpanTest
|
||||
{
|
||||
[Fact]
|
||||
public void CheckRecordExceptionData()
|
||||
{
|
||||
string message = "message";
|
||||
|
||||
using Activity activity = new Activity("exception-test");
|
||||
using TelemetrySpan telemetrySpan = new TelemetrySpan(activity);
|
||||
telemetrySpan.RecordException(new ArgumentNullException(message, new Exception("new-exception")));
|
||||
Assert.Single(activity.Events);
|
||||
|
||||
var @event = telemetrySpan.Activity.Events.FirstOrDefault(q => q.Name == SemanticConventions.AttributeExceptionEventName);
|
||||
Assert.Equal(message, @event.Tags.FirstOrDefault(t => t.Key == SemanticConventions.AttributeExceptionMessage).Value);
|
||||
Assert.Equal(typeof(ArgumentNullException).Name, @event.Tags.FirstOrDefault(t => t.Key == SemanticConventions.AttributeExceptionType).Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CheckRecordExceptionData2()
|
||||
{
|
||||
string type = "ArgumentNullException";
|
||||
string message = "message";
|
||||
string stack = "stack";
|
||||
|
||||
using Activity activity = new Activity("exception-test");
|
||||
using TelemetrySpan telemetrySpan = new TelemetrySpan(activity);
|
||||
telemetrySpan.RecordException(type, message, stack);
|
||||
Assert.Single(activity.Events);
|
||||
|
||||
var @event = telemetrySpan.Activity.Events.FirstOrDefault(q => q.Name == SemanticConventions.AttributeExceptionEventName);
|
||||
Assert.Equal(message, @event.Tags.FirstOrDefault(t => t.Key == SemanticConventions.AttributeExceptionMessage).Value);
|
||||
Assert.Equal(type, @event.Tags.FirstOrDefault(t => t.Key == SemanticConventions.AttributeExceptionType).Value);
|
||||
Assert.Equal(stack, @event.Tags.FirstOrDefault(t => t.Key == SemanticConventions.AttributeExceptionStacktrace).Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CheckRecordExceptionEmpty()
|
||||
{
|
||||
using Activity activity = new Activity("exception-test");
|
||||
using TelemetrySpan telemetrySpan = new TelemetrySpan(activity);
|
||||
telemetrySpan.RecordException(string.Empty, string.Empty, string.Empty);
|
||||
Assert.Empty(activity.Events);
|
||||
|
||||
telemetrySpan.RecordException(null);
|
||||
Assert.Empty(activity.Events);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue