Skip to content

Commit

Permalink
add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
dudikeleti committed Oct 31, 2024
1 parent 00e46cb commit 2aa42bb
Show file tree
Hide file tree
Showing 5 changed files with 204 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ internal static class Debugger
/// Default value is <c>8</c>.
/// </summary>
/// <seealso cref="DebuggerSettings.CodeOriginMaxUserFrames"/>
public const string CodeOriginMaxUserFrames = "DD_CODE_ORIGIN_MAX_USER_FRAMES";
public const string CodeOriginMaxUserFrames = "DD_CODE_ORIGIN_FOR_SPANS_MAX_USER_FRAMES";
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,33 +7,52 @@
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Threading;
using Datadog.Trace.Debugger.Symbols;
using Datadog.Trace.Logging;
using Datadog.Trace.VendoredMicrosoftCode.System.Buffers;
using Datadog.Trace.VendoredMicrosoftCode.System.Collections.Immutable;

namespace Datadog.Trace.Debugger.SpanCodeOrigin
{
internal class SpanCodeOriginManager
{
private const string CodeOriginTag = "_dd.code_origin";

private const string FramesPrefix = "frames";
private static readonly DebuggerSettings Settings = LiveDebugger.Instance?.Settings ?? DebuggerSettings.FromDefaultSource();

private static readonly IDatadogLogger Log = DatadogLogging.GetLoggerFor(typeof(SpanCodeOriginManager));

private static object _globalInstanceLock = new();

private static bool _globalInstanceInitialized;

#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.
private static SpanCodeOriginManager _instance;
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.

private readonly DebuggerSettings _settings = LiveDebugger.Instance?.Settings ?? DebuggerSettings.FromDefaultSource();

internal static SpanCodeOriginManager Instance =>
LazyInitializer.EnsureInitialized(
ref _instance,
ref _globalInstanceInitialized,
ref _globalInstanceLock);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void SetCodeOrigin(Span? span)
internal void SetCodeOrigin(Span? span)
{
if (span == null || !Settings.CodeOriginForSpansEnabled)
if (span == null || !this._settings.CodeOriginForSpansEnabled)
{
return;
}

AddExitSpanTag(span);
Instance.AddExitSpanTag(span);
}

private static void AddExitSpanTag(Span span)
private void AddExitSpanTag(Span span)
{
var frames = ArrayPool<FrameInfo>.Shared.Rent(Settings.CodeOriginMaxUserFrames);
var frames = ArrayPool<FrameInfo>.Shared.Rent(this._settings.CodeOriginMaxUserFrames);
try
{
var framesLength = PopulateUserFrames(frames);
Expand Down Expand Up @@ -94,7 +113,7 @@ private static void AddExitSpanTag(Span span)
}
}

private static int PopulateUserFrames(FrameInfo[] frames)
private int PopulateUserFrames(FrameInfo[] frames)
{
var stackTrace = new StackTrace(true);
var stackFrames = stackTrace.GetFrames();
Expand All @@ -106,7 +125,7 @@ private static int PopulateUserFrames(FrameInfo[] frames)
}

var count = 0;
for (var walkIndex = 0; walkIndex < stackFrames.Length && count < Settings.CodeOriginMaxUserFrames; walkIndex++)
for (var walkIndex = 0; walkIndex < stackFrames.Length && count < this._settings.CodeOriginMaxUserFrames; walkIndex++)
{
var frame = stackFrames[walkIndex];

Expand All @@ -116,7 +135,7 @@ private static int PopulateUserFrames(FrameInfo[] frames)
continue;
}

if (AssemblyFilter.ShouldSkipAssembly(assembly, LiveDebugger.Instance.Settings.ThirdPartyDetectionExcludes, LiveDebugger.Instance.Settings.ThirdPartyDetectionIncludes))
if (AssemblyFilter.ShouldSkipAssembly(assembly, _settings.ThirdPartyDetectionExcludes, _settings.ThirdPartyDetectionIncludes))
{
// use cache when this will be merged: https://github.com/DataDog/dd-trace-dotnet/pull/6093
continue;
Expand Down
2 changes: 1 addition & 1 deletion tracer/src/Datadog.Trace/Tracer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -550,7 +550,7 @@ internal Span StartSpan(string operationName, ITags tags = null, ISpanContext pa
// write them directly to the <see cref="TraceChunkModel"/>.
TracerManager.GitMetadataTagsProvider.TryExtractGitMetadata(out _);

SpanCodeOriginManager.SetCodeOrigin(span);
SpanCodeOriginManager.Instance.SetCodeOrigin(span);

return span;
}
Expand Down
56 changes: 56 additions & 0 deletions tracer/test/Datadog.Trace.Tests/Debugger/DebuggerSettingsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -141,5 +141,61 @@ public void InvalidUploadFlushInterval_DefaultUsed(string value)

settings.UploadFlushIntervalMilliseconds.Should().Be(0);
}

[Theory]
[InlineData("")]
[InlineData("False")]
[InlineData("false")]
[InlineData("0")]
[InlineData("2")]
[InlineData(null)]
public void CodeOriginEnabled_False(string value)
{
var settings = new DebuggerSettings(
new NameValueConfigurationSource(new() { { ConfigurationKeys.Debugger.CodeOriginForSpansEnabled, value }, }),
NullConfigurationTelemetry.Instance);

settings.CodeOriginForSpansEnabled.Should().BeFalse();
}

[Theory]
[InlineData("True")]
[InlineData("true")]
[InlineData("1")]
public void CodeOriginEnabled_True(string value)
{
var settings = new DebuggerSettings(
new NameValueConfigurationSource(new() { { ConfigurationKeys.Debugger.CodeOriginForSpansEnabled, value }, }),
NullConfigurationTelemetry.Instance);

settings.CodeOriginForSpansEnabled.Should().BeTrue();
}

[Theory]
[InlineData("8")]
[InlineData("1")]
[InlineData("1000")]
public void CodeOriginMaxUserFrames(string value)
{
var settings = new DebuggerSettings(
new NameValueConfigurationSource(new() { { ConfigurationKeys.Debugger.CodeOriginMaxUserFrames, value }, }),
NullConfigurationTelemetry.Instance);

settings.CodeOriginMaxUserFrames.Should().Be(int.Parse(value));
}

[Theory]
[InlineData("-1")]
[InlineData("0")]
[InlineData("")]
[InlineData(null)]
public void InvalidCodeOriginMaxUserFrames_DefaultUsed(string value)
{
var settings = new DebuggerSettings(
new NameValueConfigurationSource(new() { { ConfigurationKeys.Debugger.CodeOriginMaxUserFrames, value }, }),
NullConfigurationTelemetry.Instance);

settings.CodeOriginMaxUserFrames.Should().Be(8);
}
}
}
118 changes: 118 additions & 0 deletions tracer/test/Datadog.Trace.Tests/Debugger/SpanCodeOriginTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
// <copyright file="SpanCodeOriginTests.cs" company="Datadog">
// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2 License.
// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2017 Datadog, Inc.
// </copyright>

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Datadog.Trace.Configuration;
using Datadog.Trace.Configuration.Telemetry;
using Datadog.Trace.Debugger;
using Datadog.Trace.Debugger.SpanCodeOrigin;
using Datadog.Trace.VendoredMicrosoftCode.System.Collections.Immutable;
using Xunit;

namespace Datadog.Trace.Tests.Debugger
{
public class SpanCodeOriginTests
{
private const string CodeOriginTag = "_dd.code_origin";

[Fact]
public void SetCodeOrigin_WhenSpanIsNull_DoesNotThrow()
{
// Should not throw
SpanCodeOriginManager.Instance.SetCodeOrigin(null);
}

[Fact]
public void SetCodeOrigin_WhenDisabled_DoesNotSetTags()
{
// Arrange
CreateCodeOriginManager();

var span = new Span(new SpanContext(1, 2, SamplingPriority.UserKeep), DateTimeOffset.UtcNow);

// Act
SpanCodeOriginManager.Instance.SetCodeOrigin(span);

// Assert
Assert.Null(span.Tags.GetTag(CodeOriginTag + ".type"));
}

[Fact]
public void SetCodeOrigin_WhenEnabled_SetsCorrectTags()
{
// Arrange
CreateCodeOriginManager(true);

var span = new Span(new SpanContext(1, 2, SamplingPriority.UserKeep), DateTimeOffset.UtcNow);

// Act
TestMethod(span);

// Assert
Assert.NotNull(span.Tags.GetTag($"{CodeOriginTag}.type"));
Assert.Equal("exit", span.Tags.GetTag($"{CodeOriginTag}.type"));

Assert.NotNull(span.Tags.GetTag($"{CodeOriginTag}.frames.0.method"));
Assert.Equal(nameof(TestMethod), span.Tags.GetTag($"{CodeOriginTag}.frames.0.method"));
Assert.NotNull(span.Tags.GetTag($"{CodeOriginTag}.frames.0.type"));
Assert.Contains(nameof(SpanCodeOriginTests), span.Tags.GetTag($"{CodeOriginTag}.frames.0.type"));
}

[Fact]
public void SetCodeOrigin_WithMaxFramesLimit_RespectsLimit()
{
// Arrange
CreateCodeOriginManager(true, 2);

var span = new Span(new SpanContext(1, 2, SamplingPriority.UserKeep), DateTimeOffset.UtcNow);

// Act
DeepTestMethod1(span);

// Assert
var tags = ((List<KeyValuePair<string, string>>)(typeof(Datadog.Trace.Tagging.TagsList).GetField("_tags", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(span.Tags))).Select(i => i.Key).ToList();
Assert.Contains(tags, s => s.StartsWith($"{CodeOriginTag}.frames.0"));
Assert.Contains(tags, s => s.StartsWith($"{CodeOriginTag}.frames.1"));
Assert.DoesNotContain(tags, s => s.StartsWith($"{CodeOriginTag}.frames.2"));
}

private static void CreateCodeOriginManager(bool isEnable = false, int numberOfFrames = 8, string excludeFromFilter = "Datadog.Trace.Tests")
{
var overrideSettings = DebuggerSettings.FromSource(
new NameValueConfigurationSource(new()
{
{ ConfigurationKeys.Debugger.CodeOriginForSpansEnabled, isEnable.ToString() },
{ ConfigurationKeys.Debugger.CodeOriginMaxUserFrames, numberOfFrames.ToString() },
{ ConfigurationKeys.Debugger.ThirdPartyDetectionExcludes, excludeFromFilter }
}),
NullConfigurationTelemetry.Instance);
var instance = SpanCodeOriginManager.Instance;
instance.GetType().GetField("_settings", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(instance, overrideSettings);
}

private void TestMethod(Span span)
{
SpanCodeOriginManager.Instance.SetCodeOrigin(span);
}

private void DeepTestMethod1(Span span)
{
DeepTestMethod2(span);
}

private void DeepTestMethod2(Span span)
{
DeepTestMethod3(span);
}

private void DeepTestMethod3(Span span)
{
SpanCodeOriginManager.Instance.SetCodeOrigin(span);
}
}
}

0 comments on commit 2aa42bb

Please sign in to comment.