From b63f5cf909aa1bab28c5598ef4e90cb6abaf6231 Mon Sep 17 00:00:00 2001 From: Nicholas Hulston Date: Thu, 6 Mar 2025 09:46:06 -0500 Subject: [PATCH 1/7] S3 Span Pointers (#6655) --- .../build/Datadog.Trace.Trimming.xml | 4 + .../AWS/S3/IS3EtagResponse.cs | 22 +++ ...CompleteMultipartUploadAsyncIntegration.cs | 12 +- .../CompleteMultipartUploadIntegration.cs | 12 +- .../CopyObjectAsyncIntegration.cs | 12 +- .../ObjectManagement/CopyObjectIntegration.cs | 12 +- .../PutObjectAsyncIntegration.cs | 12 +- .../ObjectManagement/PutObjectIntegration.cs | 12 +- .../AWS/Shared/SpanPointers.cs | 147 ++++++++++++++++++ .../Configuration/ConfigurationKeys.cs | 6 + .../Configuration/TracerSettings.cs | 8 + tracer/src/Datadog.Trace/SpanContext.cs | 12 ++ .../AWS/Shared/SpanPointersTests.cs | 93 +++++++++++ ...sHaveNotChanged.netcoreapp3.1.verified.txt | 1 + .../Telemetry/config_norm_rules.json | 1 + .../AwsS3Tests.NetCore.SchemaV0.verified.txt | 62 ++++++-- .../AwsS3Tests.NetCore.SchemaV1.verified.txt | 62 ++++++-- ...S3Tests.NetFramework.SchemaV0.verified.txt | 62 ++++++-- ...S3Tests.NetFramework.SchemaV1.verified.txt | 62 ++++++-- 19 files changed, 544 insertions(+), 70 deletions(-) create mode 100644 tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/S3/IS3EtagResponse.cs create mode 100644 tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/Shared/SpanPointers.cs create mode 100644 tracer/test/Datadog.Trace.ClrProfiler.Managed.Tests/AutoInstrumentation/AWS/Shared/SpanPointersTests.cs diff --git a/tracer/src/Datadog.Trace.Trimming/build/Datadog.Trace.Trimming.xml b/tracer/src/Datadog.Trace.Trimming/build/Datadog.Trace.Trimming.xml index e3491cc9cace..1d16d3f9e304 100644 --- a/tracer/src/Datadog.Trace.Trimming/build/Datadog.Trace.Trimming.xml +++ b/tracer/src/Datadog.Trace.Trimming/build/Datadog.Trace.Trimming.xml @@ -131,6 +131,9 @@ + + + @@ -496,6 +499,7 @@ + diff --git a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/S3/IS3EtagResponse.cs b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/S3/IS3EtagResponse.cs new file mode 100644 index 000000000000..7a49841306a3 --- /dev/null +++ b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/S3/IS3EtagResponse.cs @@ -0,0 +1,22 @@ +// +// 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. +// +#nullable enable + +using Datadog.Trace.DuckTyping; + +namespace Datadog.Trace.ClrProfiler.AutoInstrumentation.AWS.S3; + +/// +/// Shared interface for ducktyping for PutObjectResponse, CopyObjectResponse, and +/// CompleteMultipartUploadResponse. +/// +internal interface IS3EtagResponse : IDuckType +{ + /// + /// Gets the S3 response eTag, which is usually wrapped in quotes. + /// + [DuckField(Name = "eTag")] + string ETag { get; } +} diff --git a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/S3/MultipartUploadManagement/CompleteMultipartUploadAsyncIntegration.cs b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/S3/MultipartUploadManagement/CompleteMultipartUploadAsyncIntegration.cs index 6359bb1965af..80791333cee4 100644 --- a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/S3/MultipartUploadManagement/CompleteMultipartUploadAsyncIntegration.cs +++ b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/S3/MultipartUploadManagement/CompleteMultipartUploadAsyncIntegration.cs @@ -7,6 +7,7 @@ using System; using System.ComponentModel; using System.Threading; +using Datadog.Trace.ClrProfiler.AutoInstrumentation.AWS.Shared; using Datadog.Trace.ClrProfiler.CallTarget; namespace Datadog.Trace.ClrProfiler.AutoInstrumentation.AWS.S3.MultipartUploadManagement; @@ -40,11 +41,20 @@ internal static CallTargetState OnMethodBegin(TTarget instanc var scope = AwsS3Common.CreateScope(Tracer.Instance, Operation, out var tags); AwsS3Common.SetTags(tags, request.BucketName, request.ObjectKey); - return new CallTargetState(scope); + return new CallTargetState(scope, request); } internal static TReturn? OnAsyncMethodEnd(TTarget instance, TReturn? returnValue, Exception exception, in CallTargetState state) + where TReturn : IS3EtagResponse { + if (Tracer.Instance.Settings.SpanPointersEnabled && state.Scope is not null && state.State is ICompleteMultipartUploadRequest request && returnValue is not null) + { + var bucketName = request.BucketName; + var key = request.ObjectKey; + var eTag = returnValue.ETag; + SpanPointers.AddS3SpanPointer(state.Scope.Span, bucketName, key, eTag); + } + state.Scope.DisposeWithException(exception); return returnValue; } diff --git a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/S3/MultipartUploadManagement/CompleteMultipartUploadIntegration.cs b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/S3/MultipartUploadManagement/CompleteMultipartUploadIntegration.cs index 6a92b12b2bc2..551fe8077dc9 100644 --- a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/S3/MultipartUploadManagement/CompleteMultipartUploadIntegration.cs +++ b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/S3/MultipartUploadManagement/CompleteMultipartUploadIntegration.cs @@ -6,6 +6,7 @@ using System; using System.ComponentModel; +using Datadog.Trace.ClrProfiler.AutoInstrumentation.AWS.Shared; using Datadog.Trace.ClrProfiler.CallTarget; namespace Datadog.Trace.ClrProfiler.AutoInstrumentation.AWS.S3.MultipartUploadManagement; @@ -39,11 +40,20 @@ internal static CallTargetState OnMethodBegin(TTarget instanc var scope = AwsS3Common.CreateScope(Tracer.Instance, Operation, out var tags); AwsS3Common.SetTags(tags, request.BucketName, request.ObjectKey); - return new CallTargetState(scope); + return new CallTargetState(scope, request); } internal static CallTargetReturn OnMethodEnd(TTarget instance, TReturn? returnValue, Exception? exception, in CallTargetState state) + where TReturn : IS3EtagResponse { + if (Tracer.Instance.Settings.SpanPointersEnabled && state.Scope is not null && state.State is ICompleteMultipartUploadRequest request && returnValue is not null) + { + var bucketName = request.BucketName; + var key = request.ObjectKey; + var eTag = returnValue.ETag; + SpanPointers.AddS3SpanPointer(state.Scope.Span, bucketName, key, eTag); + } + state.Scope.DisposeWithException(exception); return new CallTargetReturn(returnValue); } diff --git a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/S3/ObjectManagement/CopyObjectAsyncIntegration.cs b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/S3/ObjectManagement/CopyObjectAsyncIntegration.cs index bc7f03f059eb..f7e16f414ecf 100644 --- a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/S3/ObjectManagement/CopyObjectAsyncIntegration.cs +++ b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/S3/ObjectManagement/CopyObjectAsyncIntegration.cs @@ -7,6 +7,7 @@ using System; using System.ComponentModel; using System.Threading; +using Datadog.Trace.ClrProfiler.AutoInstrumentation.AWS.Shared; using Datadog.Trace.ClrProfiler.CallTarget; namespace Datadog.Trace.ClrProfiler.AutoInstrumentation.AWS.S3.ObjectManagement; @@ -40,11 +41,20 @@ internal static CallTargetState OnMethodBegin(TTarget instanc var scope = AwsS3Common.CreateScope(Tracer.Instance, Operation, out var tags); AwsS3Common.SetTags(tags, request.DestinationBucketName, request.DestinationObjectKey); - return new CallTargetState(scope); + return new CallTargetState(scope, request); } internal static TReturn? OnAsyncMethodEnd(TTarget instance, TReturn? returnValue, Exception exception, in CallTargetState state) + where TReturn : IS3EtagResponse { + if (Tracer.Instance.Settings.SpanPointersEnabled && state.Scope is not null && state.State is ICopyObjectRequest request && returnValue is not null) + { + var bucketName = request.DestinationBucketName; + var key = request.DestinationObjectKey; + var eTag = returnValue.ETag; + SpanPointers.AddS3SpanPointer(state.Scope.Span, bucketName, key, eTag); + } + state.Scope.DisposeWithException(exception); return returnValue; } diff --git a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/S3/ObjectManagement/CopyObjectIntegration.cs b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/S3/ObjectManagement/CopyObjectIntegration.cs index f42fd1bc99b6..77a0873dea86 100644 --- a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/S3/ObjectManagement/CopyObjectIntegration.cs +++ b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/S3/ObjectManagement/CopyObjectIntegration.cs @@ -6,6 +6,7 @@ using System; using System.ComponentModel; +using Datadog.Trace.ClrProfiler.AutoInstrumentation.AWS.Shared; using Datadog.Trace.ClrProfiler.CallTarget; namespace Datadog.Trace.ClrProfiler.AutoInstrumentation.AWS.S3.ObjectManagement; @@ -39,11 +40,20 @@ internal static CallTargetState OnMethodBegin(TTarget instanc var scope = AwsS3Common.CreateScope(Tracer.Instance, Operation, out var tags); AwsS3Common.SetTags(tags, request.DestinationBucketName, request.DestinationObjectKey); - return new CallTargetState(scope); + return new CallTargetState(scope, request); } internal static CallTargetReturn OnMethodEnd(TTarget instance, TReturn? returnValue, Exception? exception, in CallTargetState state) + where TReturn : IS3EtagResponse { + if (Tracer.Instance.Settings.SpanPointersEnabled && state.Scope is not null && state.State is ICopyObjectRequest request && returnValue is not null) + { + var bucketName = request.DestinationBucketName; + var key = request.DestinationObjectKey; + var eTag = returnValue.ETag; + SpanPointers.AddS3SpanPointer(state.Scope.Span, bucketName, key, eTag); + } + state.Scope.DisposeWithException(exception); return new CallTargetReturn(returnValue); } diff --git a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/S3/ObjectManagement/PutObjectAsyncIntegration.cs b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/S3/ObjectManagement/PutObjectAsyncIntegration.cs index 4daf574eeebb..f90a5e51c11e 100644 --- a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/S3/ObjectManagement/PutObjectAsyncIntegration.cs +++ b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/S3/ObjectManagement/PutObjectAsyncIntegration.cs @@ -7,6 +7,7 @@ using System; using System.ComponentModel; using System.Threading; +using Datadog.Trace.ClrProfiler.AutoInstrumentation.AWS.Shared; using Datadog.Trace.ClrProfiler.CallTarget; namespace Datadog.Trace.ClrProfiler.AutoInstrumentation.AWS.S3.ObjectManagement; @@ -40,11 +41,20 @@ internal static CallTargetState OnMethodBegin(TTarget instanc var scope = AwsS3Common.CreateScope(Tracer.Instance, Operation, out var tags); AwsS3Common.SetTags(tags, request.BucketName, request.ObjectKey); - return new CallTargetState(scope); + return new CallTargetState(scope, request); } internal static TReturn? OnAsyncMethodEnd(TTarget instance, TReturn? returnValue, Exception exception, in CallTargetState state) + where TReturn : IS3EtagResponse { + if (Tracer.Instance.Settings.SpanPointersEnabled && state.Scope is not null && state.State is IPutObjectRequest request && returnValue is not null) + { + var bucketName = request.BucketName; + var key = request.ObjectKey; + var eTag = returnValue.ETag; + SpanPointers.AddS3SpanPointer(state.Scope.Span, bucketName, key, eTag); + } + state.Scope.DisposeWithException(exception); return returnValue; } diff --git a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/S3/ObjectManagement/PutObjectIntegration.cs b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/S3/ObjectManagement/PutObjectIntegration.cs index 917af91ac39f..cf07f1714970 100644 --- a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/S3/ObjectManagement/PutObjectIntegration.cs +++ b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/S3/ObjectManagement/PutObjectIntegration.cs @@ -6,6 +6,7 @@ using System; using System.ComponentModel; +using Datadog.Trace.ClrProfiler.AutoInstrumentation.AWS.Shared; using Datadog.Trace.ClrProfiler.CallTarget; namespace Datadog.Trace.ClrProfiler.AutoInstrumentation.AWS.S3.ObjectManagement; @@ -39,11 +40,20 @@ internal static CallTargetState OnMethodBegin(TTarget instanc var scope = AwsS3Common.CreateScope(Tracer.Instance, Operation, out var tags); AwsS3Common.SetTags(tags, request.BucketName, request.ObjectKey); - return new CallTargetState(scope); + return new CallTargetState(scope, request); } internal static CallTargetReturn OnMethodEnd(TTarget instance, TReturn? returnValue, Exception? exception, in CallTargetState state) + where TReturn : IS3EtagResponse { + if (Tracer.Instance.Settings.SpanPointersEnabled && state.Scope is not null && state.State is IPutObjectRequest request && returnValue is not null) + { + var bucketName = request.BucketName; + var key = request.ObjectKey; + var eTag = returnValue.ETag; + SpanPointers.AddS3SpanPointer(state.Scope.Span, bucketName, key, eTag); + } + state.Scope.DisposeWithException(exception); return new CallTargetReturn(returnValue); } diff --git a/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/Shared/SpanPointers.cs b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/Shared/SpanPointers.cs new file mode 100644 index 000000000000..1b443569de05 --- /dev/null +++ b/tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/AWS/Shared/SpanPointers.cs @@ -0,0 +1,147 @@ +// +// 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. +// + +#nullable enable + +using System.Collections.Generic; +using System.Security.Cryptography; +using System.Text; +using Datadog.Trace.Util; + +#if NETCOREAPP3_1_OR_GREATER +using System; +using System.Buffers; +#else +using Datadog.Trace.VendoredMicrosoftCode.System.Buffers; +#endif + +namespace Datadog.Trace.ClrProfiler.AutoInstrumentation.AWS.Shared; + +/// +/// SpanPointer helper methods +/// +internal static class SpanPointers +{ + // The pointer direction will always be down. The serverless agent handles cases where the + // direction is up. + private const string DownDirection = "d"; + private const string LinkKind = "span-pointer"; + private const int SpanPointerHashSizeBytes = 16; + private const string S3PtrKind = "aws.s3.object"; + + // S3 hashing rules: https://github.com/DataDog/dd-span-pointer-rules/blob/main/AWS/S3/Object/README.md + public static void AddS3SpanPointer(Span span, string bucketName, string key, string? eTag) + { + if (eTag == null) + { + return; + } + + var components = ConcatenateComponents(bucketName, key, eTag); + var hash = GeneratePointerHash(components); + + var spanLinkAttributes = new List>(4) + { + new("ptr.kind", S3PtrKind), + new("ptr.dir", DownDirection), + new("ptr.hash", hash), + new("link.kind", LinkKind) + }; + + var spanLink = new SpanLink(SpanContext.Zero, spanLinkAttributes); + span.AddLink(spanLink); + } + + internal static string ConcatenateComponents(string bucketName, string key, string eTag) + { + var builder = StringBuilderCache.Acquire(); + builder.Append(bucketName); + builder.Append('|'); + builder.Append(key); + builder.Append('|'); + + // ReSharper disable once MergeIntoPattern + // ReSharper disable once UseIndexFromEndExpression + if (eTag.Length >= 2 && eTag[0] == '"' && eTag[eTag.Length - 1] == '"') + { + // trim double-quotes around eTag if both leading and trailing quotes are present + // and there is at least one more character between them + // (avoid allocating a new string with String.Substring()) + builder.Append(eTag, 1, eTag.Length - 2); + } + else + { + builder.Append(eTag); + } + + return StringBuilderCache.GetStringAndRelease(builder); + } + + // Hashing rules: https://github.com/DataDog/dd-span-pointer-rules/tree/main?tab=readme-ov-file#general-hashing-rules + internal static string GeneratePointerHash(string components) + { + // compute max buffer size for UTF-8 bytes + // (faster than computing the actual byte count and good enough for the buffer size) + var maxByteCount = Encoding.UTF8.GetMaxByteCount(components.Length); + +#if NETCOREAPP3_1_OR_GREATER + // in .NET Core 3.1 and above, we can allocate the buffer + // for the UTF-8 bytes on the stack if it's small enough + if (maxByteCount < 256) + { + Span stackBuffer = stackalloc byte[maxByteCount]; + return ComputeHash(components, stackBuffer); + } +#endif + // rent a buffer for the UTF-8 bytes + var buffer = ArrayPool.Shared.Rent(minimumLength: maxByteCount); + + try + { + return ComputeHash(components, buffer); + } + finally + { + ArrayPool.Shared.Return(buffer); + } + } + +#if NETCOREAPP3_1_OR_GREATER + // .NET Core 3.1 and above have Encoding.UTF8.GetBytes() overload that writes to a Span buffer + internal static string ComputeHash(string components, Span buffer) + { + var byteCount = Encoding.UTF8.GetBytes(components, buffer); + Span fullHash = stackalloc byte[32]; // SHA256 produces 32 bytes + +#if NET6_0_OR_GREATER + // .NET 6 has a static TryHashData() method that avoids the allocation of a SHA256 instance + SHA256.TryHashData(buffer[..byteCount], fullHash, out _); +#else + using var sha256 = SHA256.Create(); + sha256.TryComputeHash(buffer[..byteCount], fullHash, out _); +#endif + + var truncatedHash = fullHash[..SpanPointerHashSizeBytes]; + return HexString.ToHexString(truncatedHash); + } +#else + // .NET Framework and .NET Standard 2.0 do not have Encoding.UTF8.GetBytes() overload + // that writes to a Span, so we fall back to a rented byte[] + internal static string ComputeHash(string components, byte[] buffer) + { + var byteCount = Encoding.UTF8.GetBytes( + components, + charIndex: 0, + charCount: components.Length, + bytes: buffer, + byteIndex: 0); + + using var sha256 = SHA256.Create(); + var fullHash = sha256.ComputeHash(buffer, offset: 0, count: byteCount); + var truncatedHash = fullHash.AsSpan(0, SpanPointerHashSizeBytes); + return HexString.ToHexString(truncatedHash); + } +#endif +} diff --git a/tracer/src/Datadog.Trace/Configuration/ConfigurationKeys.cs b/tracer/src/Datadog.Trace/Configuration/ConfigurationKeys.cs index 3c2a2dd008f9..54a7eb0890ab 100644 --- a/tracer/src/Datadog.Trace/Configuration/ConfigurationKeys.cs +++ b/tracer/src/Datadog.Trace/Configuration/ConfigurationKeys.cs @@ -539,6 +539,12 @@ internal static partial class ConfigurationKeys /// public const string DisabledAdoNetCommandTypes = "DD_TRACE_DISABLED_ADONET_COMMAND_TYPES"; + /// + /// Configuration key for toggling span pointers on AWS requests. + /// Default value is true + /// + public const string SpanPointersEnabled = "DD_TRACE_AWS_ADD_SPAN_POINTERS"; + /// /// String constants for CI Visibility configuration keys. /// diff --git a/tracer/src/Datadog.Trace/Configuration/TracerSettings.cs b/tracer/src/Datadog.Trace/Configuration/TracerSettings.cs index 7adec0fed3c7..17ce9c4cf230 100644 --- a/tracer/src/Datadog.Trace/Configuration/TracerSettings.cs +++ b/tracer/src/Datadog.Trace/Configuration/TracerSettings.cs @@ -307,6 +307,9 @@ _ when x.ToBoolean() is { } boolean => boolean, RemoveClientServiceNamesEnabled = config .WithKeys(ConfigurationKeys.RemoveClientServiceNamesEnabled) .AsBool(defaultValue: false); + SpanPointersEnabled = config + .WithKeys(ConfigurationKeys.SpanPointersEnabled) + .AsBool(defaultValue: true); PeerServiceNameMappings = InitializeServiceNameMappings(config, ConfigurationKeys.PeerServiceNameMappings); @@ -1125,6 +1128,11 @@ public bool DiagnosticSourceEnabled /// internal bool RemoveClientServiceNamesEnabled { get; } + /// + /// Gets a value indicating whether to add span pointers on AWS requests. + /// + internal bool SpanPointersEnabled { get; } + /// /// Gets the metadata schema version /// diff --git a/tracer/src/Datadog.Trace/SpanContext.cs b/tracer/src/Datadog.Trace/SpanContext.cs index 07dbf526c401..4873389bcbc0 100644 --- a/tracer/src/Datadog.Trace/SpanContext.cs +++ b/tracer/src/Datadog.Trace/SpanContext.cs @@ -48,6 +48,11 @@ public partial class SpanContext : ISpanContext, IReadOnlyDictionary public static readonly ISpanContext None = new ReadOnlySpanContext(traceId: Trace.TraceId.Zero, spanId: 0, serviceName: null); + /// + /// A SpanContext with all fields set to zero or empty values, for span pointers. + /// + public static readonly SpanContext Zero = new(); + private string _rawTraceId; private string _rawSpanId; private string _origin; @@ -173,6 +178,13 @@ private SpanContext(TraceId traceId, string serviceName) } } + // Constructor for creating an empty span context. + private SpanContext() + { + TraceId128 = Trace.TraceId.Zero; // Directly set zero without the random generation + SpanId = 0; + } + /// /// Gets the parent context. /// diff --git a/tracer/test/Datadog.Trace.ClrProfiler.Managed.Tests/AutoInstrumentation/AWS/Shared/SpanPointersTests.cs b/tracer/test/Datadog.Trace.ClrProfiler.Managed.Tests/AutoInstrumentation/AWS/Shared/SpanPointersTests.cs new file mode 100644 index 000000000000..0d8dac3cbf5f --- /dev/null +++ b/tracer/test/Datadog.Trace.ClrProfiler.Managed.Tests/AutoInstrumentation/AWS/Shared/SpanPointersTests.cs @@ -0,0 +1,93 @@ +// +// 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. +// + +#nullable enable + +using System.Collections.Specialized; +using Datadog.Trace.Agent; +using Datadog.Trace.ClrProfiler.AutoInstrumentation.AWS.S3; +using Datadog.Trace.ClrProfiler.AutoInstrumentation.AWS.Shared; +using Datadog.Trace.Configuration; +using Datadog.Trace.Sampling; +using FluentAssertions; +using Moq; +using Xunit; + +namespace Datadog.Trace.ClrProfiler.Managed.Tests.AutoInstrumentation.AWS.Shared; + +public class SpanPointersTests +{ + [Theory] + [InlineData("some-bucket-a", "some-key.data", "ab12ef34", "some-bucket-a|some-key.data|ab12ef34")] + [InlineData("some-bucket-b", "some-key.data", "\"ab12ef34\"", "some-bucket-b|some-key.data|ab12ef34")] // eTag should be trimmed + [InlineData("some-bucket-c", "some-key.你好", "é🐶", "some-bucket-c|some-key.你好|é🐶")] // Unicode + public void ConcatenateComponents(string bucket, string key, string eTag, string expectedHash) + { + var components = SpanPointers.ConcatenateComponents(bucket, key, eTag); + + components.Should().Be(expectedHash); + } + + [Theory] + [InlineData("some-bucket", "some-key.data", "ab12ef34", "e721375466d4116ab551213fdea08413")] + [InlineData("some-bucket", "some-key.data", "\"ab12ef34\"", "e721375466d4116ab551213fdea08413")] // eTag should be trimmed + [InlineData("some-bucket", "some-key.你好", "ab12ef34", "d1333a04b9928ab462b5c6cadfa401f4")] // Unicode + [InlineData("some-bucket", "some-key.data", "ab12ef34-5", "2b90dffc37ebc7bc610152c3dc72af9f")] + public void GeneratePointerHash_ShouldGenerateValidHash(string bucket, string key, string eTag, string expectedHash) + { + var components = SpanPointers.ConcatenateComponents(bucket, key, eTag); + var hash = SpanPointers.GeneratePointerHash(components); + + hash.Should().Be(expectedHash); + } + + [Fact] + public void AddS3SpanPointer_ShouldAddCorrectSpanLink() + { + var tracer = GetTracer(); + var scope = AwsS3Common.CreateScope(tracer, "PutObject", out _); + var span = scope!.Span; + const string bucket = "test-bucket"; + const string key = "test-key"; + const string eTag = "\"test-etag\""; + SpanPointers.AddS3SpanPointer(span, bucket, key, eTag); + + span.SpanLinks.Should().ContainSingle("Should have exactly one span link"); + var link = span.SpanLinks[0]; + + link.Context.Should().Equal(SpanContext.Zero); + + // we can use Contain(key, value) because Attributes is "dictionary-like" + link.Attributes.Should().Contain("ptr.kind", "aws.s3.object"); + link.Attributes.Should().Contain("ptr.dir", "d"); + link.Attributes.Should().Contain("link.kind", "span-pointer"); + link.Attributes.Should().Contain("ptr.hash", "b7b8ca30a2b7a33d8412d7ca62bcad36"); + } + + [Fact] + public void AddS3SpanPointer_ShouldSkipMissingEtag() + { + var tracer = GetTracer(); + var scope = AwsS3Common.CreateScope(tracer, "PutObject", out _); + var span = scope!.Span; + const string bucket = "test-bucket"; + const string key = "test-key"; + const string? eTag = null; + SpanPointers.AddS3SpanPointer(span, bucket, key, eTag); + + span.SpanLinks.Should().BeNull(); + } + + private static Tracer GetTracer() + { + var collection = new NameValueCollection { { ConfigurationKeys.MetadataSchemaVersion, "v1" } }; + IConfigurationSource source = new NameValueConfigurationSource(collection); + var settings = new TracerSettings(source); + var writerMock = new Mock(); + var samplerMock = new Mock(); + + return new Tracer(settings, writerMock.Object, samplerMock.Object, scopeManager: null, statsd: null); + } +} diff --git a/tracer/test/Datadog.Trace.Tests/Snapshots/PublicApiTests.Datadog.Trace.AssemblyReferencesHaveNotChanged.netcoreapp3.1.verified.txt b/tracer/test/Datadog.Trace.Tests/Snapshots/PublicApiTests.Datadog.Trace.AssemblyReferencesHaveNotChanged.netcoreapp3.1.verified.txt index a0a9ee5f90bd..8232d4f20a02 100644 --- a/tracer/test/Datadog.Trace.Tests/Snapshots/PublicApiTests.Datadog.Trace.AssemblyReferencesHaveNotChanged.netcoreapp3.1.verified.txt +++ b/tracer/test/Datadog.Trace.Tests/Snapshots/PublicApiTests.Datadog.Trace.AssemblyReferencesHaveNotChanged.netcoreapp3.1.verified.txt @@ -7,6 +7,7 @@ Microsoft.AspNetCore.Routing.Abstractions, Version=2.0.0.0, Culture=neutral, Pub Microsoft.Extensions.Primitives, Version=2.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 Microsoft.Net.Http.Headers, Version=2.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 Microsoft.Win32.Primitives, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a +System.Buffers, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51 System.Collections, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a System.Collections.Concurrent, Version=4.0.15.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a System.Collections.NonGeneric, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a diff --git a/tracer/test/Datadog.Trace.Tests/Telemetry/config_norm_rules.json b/tracer/test/Datadog.Trace.Tests/Telemetry/config_norm_rules.json index a7e50fd3c7bc..3a8c68243711 100644 --- a/tracer/test/Datadog.Trace.Tests/Telemetry/config_norm_rules.json +++ b/tracer/test/Datadog.Trace.Tests/Telemetry/config_norm_rules.json @@ -309,6 +309,7 @@ "dbm_propagation_mode": "dbm_propagation_mode", "trace.remove_root_span_laravel_queue": "trace_remove_root_span_laravel_queue_enabled", "trace.remove_autoinstrumentation_orphans": "trace_remove_auto_instrumentation_orphans_enabled", + "DD_TRACE_AWS_ADD_SPAN_POINTERS": "trace_aws_add_span_pointers", "DD_TRACE_CONFIG_FILE": "trace_config_file", "DD_DOTNET_TRACER_CONFIG_FILE": "trace_config_file", "DD_ENV": "env", diff --git a/tracer/test/snapshots/AwsS3Tests.NetCore.SchemaV0.verified.txt b/tracer/test/snapshots/AwsS3Tests.NetCore.SchemaV0.verified.txt index 5363da441c20..b26a0069de3f 100644 --- a/tracer/test/snapshots/AwsS3Tests.NetCore.SchemaV0.verified.txt +++ b/tracer/test/snapshots/AwsS3Tests.NetCore.SchemaV0.verified.txt @@ -74,7 +74,17 @@ }, Metrics: { _dd.top_level: 1.0 - } + }, + SpanLinks: [ + { + Attributes: { + link.kind: span-pointer, + ptr.dir: d, + ptr.hash: Guid_4, + ptr.kind: aws.s3.object + } + } + ] }, { TraceId: Id_1, @@ -87,7 +97,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: GetObject, - aws.requestId: Guid_4, + aws.requestId: Guid_5, aws.service: S3, aws_service: S3, bucketname: my-bucket, @@ -117,7 +127,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: CopyObject, - aws.requestId: Guid_5, + aws.requestId: Guid_6, aws.service: S3, aws_service: S3, bucketname: my-bucket, @@ -134,7 +144,17 @@ }, Metrics: { _dd.top_level: 1.0 - } + }, + SpanLinks: [ + { + Attributes: { + link.kind: span-pointer, + ptr.dir: d, + ptr.hash: Guid_7, + ptr.kind: aws.s3.object + } + } + ] }, { TraceId: Id_1, @@ -147,7 +167,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: ListObjectsV2, - aws.requestId: Guid_6, + aws.requestId: Guid_8, aws.service: S3, aws_service: S3, bucketname: my-bucket, @@ -176,7 +196,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: DeleteObject, - aws.requestId: Guid_7, + aws.requestId: Guid_9, aws.service: S3, aws_service: S3, bucketname: my-bucket, @@ -206,7 +226,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: DeleteObjects, - aws.requestId: Guid_8, + aws.requestId: Guid_10, aws.service: S3, aws_service: S3, bucketname: my-bucket, @@ -235,7 +255,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: InitiateMultipartUpload, - aws.requestId: Guid_9, + aws.requestId: Guid_11, aws.service: S3, aws_service: S3, bucketname: my-bucket, @@ -265,7 +285,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: UploadPart, - aws.requestId: Guid_10, + aws.requestId: Guid_12, aws.service: S3, aws_service: S3, bucketname: my-bucket, @@ -295,7 +315,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: UploadPart, - aws.requestId: Guid_11, + aws.requestId: Guid_13, aws.service: S3, aws_service: S3, bucketname: my-bucket, @@ -325,7 +345,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: CompleteMultipartUpload, - aws.requestId: Guid_12, + aws.requestId: Guid_14, aws.service: S3, aws_service: S3, bucketname: my-bucket, @@ -342,7 +362,17 @@ }, Metrics: { _dd.top_level: 1.0 - } + }, + SpanLinks: [ + { + Attributes: { + link.kind: span-pointer, + ptr.dir: d, + ptr.hash: Guid_15, + ptr.kind: aws.s3.object + } + } + ] }, { TraceId: Id_1, @@ -355,7 +385,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: ListBuckets, - aws.requestId: Guid_13, + aws.requestId: Guid_16, aws.service: S3, aws_service: S3, component: aws-sdk, @@ -383,7 +413,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: ListObjectsV2, - aws.requestId: Guid_14, + aws.requestId: Guid_17, aws.service: S3, aws_service: S3, bucketname: my-bucket, @@ -412,7 +442,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: DeleteObject, - aws.requestId: Guid_15, + aws.requestId: Guid_18, aws.service: S3, aws_service: S3, bucketname: my-bucket, @@ -442,7 +472,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: DeleteBucket, - aws.requestId: Guid_16, + aws.requestId: Guid_19, aws.service: S3, aws_service: S3, bucketname: my-bucket, diff --git a/tracer/test/snapshots/AwsS3Tests.NetCore.SchemaV1.verified.txt b/tracer/test/snapshots/AwsS3Tests.NetCore.SchemaV1.verified.txt index ec4e780ec8f7..4fc3635d9aae 100644 --- a/tracer/test/snapshots/AwsS3Tests.NetCore.SchemaV1.verified.txt +++ b/tracer/test/snapshots/AwsS3Tests.NetCore.SchemaV1.verified.txt @@ -68,7 +68,17 @@ peer.service: my-bucket, span.kind: client, _dd.peer.service.source: my-bucket - } + }, + SpanLinks: [ + { + Attributes: { + link.kind: span-pointer, + ptr.dir: d, + ptr.hash: Guid_4, + ptr.kind: aws.s3.object + } + } + ] }, { TraceId: Id_1, @@ -81,7 +91,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: GetObject, - aws.requestId: Guid_4, + aws.requestId: Guid_5, aws.service: S3, aws_service: S3, bucketname: my-bucket, @@ -108,7 +118,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: CopyObject, - aws.requestId: Guid_5, + aws.requestId: Guid_6, aws.service: S3, aws_service: S3, bucketname: my-bucket, @@ -122,7 +132,17 @@ peer.service: my-bucket, span.kind: client, _dd.peer.service.source: my-bucket - } + }, + SpanLinks: [ + { + Attributes: { + link.kind: span-pointer, + ptr.dir: d, + ptr.hash: Guid_7, + ptr.kind: aws.s3.object + } + } + ] }, { TraceId: Id_1, @@ -135,7 +155,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: ListObjectsV2, - aws.requestId: Guid_6, + aws.requestId: Guid_8, aws.service: S3, aws_service: S3, bucketname: my-bucket, @@ -161,7 +181,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: DeleteObject, - aws.requestId: Guid_7, + aws.requestId: Guid_9, aws.service: S3, aws_service: S3, bucketname: my-bucket, @@ -188,7 +208,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: DeleteObjects, - aws.requestId: Guid_8, + aws.requestId: Guid_10, aws.service: S3, aws_service: S3, bucketname: my-bucket, @@ -214,7 +234,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: InitiateMultipartUpload, - aws.requestId: Guid_9, + aws.requestId: Guid_11, aws.service: S3, aws_service: S3, bucketname: my-bucket, @@ -241,7 +261,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: UploadPart, - aws.requestId: Guid_10, + aws.requestId: Guid_12, aws.service: S3, aws_service: S3, bucketname: my-bucket, @@ -268,7 +288,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: UploadPart, - aws.requestId: Guid_11, + aws.requestId: Guid_13, aws.service: S3, aws_service: S3, bucketname: my-bucket, @@ -295,7 +315,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: CompleteMultipartUpload, - aws.requestId: Guid_12, + aws.requestId: Guid_14, aws.service: S3, aws_service: S3, bucketname: my-bucket, @@ -309,7 +329,17 @@ peer.service: my-bucket, span.kind: client, _dd.peer.service.source: my-bucket - } + }, + SpanLinks: [ + { + Attributes: { + link.kind: span-pointer, + ptr.dir: d, + ptr.hash: Guid_15, + ptr.kind: aws.s3.object + } + } + ] }, { TraceId: Id_1, @@ -322,7 +352,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: ListBuckets, - aws.requestId: Guid_13, + aws.requestId: Guid_16, aws.service: S3, aws_service: S3, component: aws-sdk, @@ -345,7 +375,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: ListObjectsV2, - aws.requestId: Guid_14, + aws.requestId: Guid_17, aws.service: S3, aws_service: S3, bucketname: my-bucket, @@ -371,7 +401,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: DeleteObject, - aws.requestId: Guid_15, + aws.requestId: Guid_18, aws.service: S3, aws_service: S3, bucketname: my-bucket, @@ -398,7 +428,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: DeleteBucket, - aws.requestId: Guid_16, + aws.requestId: Guid_19, aws.service: S3, aws_service: S3, bucketname: my-bucket, diff --git a/tracer/test/snapshots/AwsS3Tests.NetFramework.SchemaV0.verified.txt b/tracer/test/snapshots/AwsS3Tests.NetFramework.SchemaV0.verified.txt index 8e6d2975eba6..25ed6efea0c0 100644 --- a/tracer/test/snapshots/AwsS3Tests.NetFramework.SchemaV0.verified.txt +++ b/tracer/test/snapshots/AwsS3Tests.NetFramework.SchemaV0.verified.txt @@ -74,7 +74,17 @@ }, Metrics: { _dd.top_level: 1.0 - } + }, + SpanLinks: [ + { + Attributes: { + link.kind: span-pointer, + ptr.dir: d, + ptr.hash: Guid_4, + ptr.kind: aws.s3.object + } + } + ] }, { TraceId: Id_1, @@ -87,7 +97,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: GetObject, - aws.requestId: Guid_4, + aws.requestId: Guid_5, aws.service: S3, aws_service: S3, bucketname: my-bucket, @@ -117,7 +127,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: CopyObject, - aws.requestId: Guid_5, + aws.requestId: Guid_6, aws.service: S3, aws_service: S3, bucketname: my-bucket, @@ -134,7 +144,17 @@ }, Metrics: { _dd.top_level: 1.0 - } + }, + SpanLinks: [ + { + Attributes: { + link.kind: span-pointer, + ptr.dir: d, + ptr.hash: Guid_7, + ptr.kind: aws.s3.object + } + } + ] }, { TraceId: Id_1, @@ -147,7 +167,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: ListObjectsV2, - aws.requestId: Guid_6, + aws.requestId: Guid_8, aws.service: S3, aws_service: S3, bucketname: my-bucket, @@ -176,7 +196,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: DeleteObject, - aws.requestId: Guid_7, + aws.requestId: Guid_9, aws.service: S3, aws_service: S3, bucketname: my-bucket, @@ -206,7 +226,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: DeleteObjects, - aws.requestId: Guid_8, + aws.requestId: Guid_10, aws.service: S3, aws_service: S3, bucketname: my-bucket, @@ -235,7 +255,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: InitiateMultipartUpload, - aws.requestId: Guid_9, + aws.requestId: Guid_11, aws.service: S3, aws_service: S3, bucketname: my-bucket, @@ -265,7 +285,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: UploadPart, - aws.requestId: Guid_10, + aws.requestId: Guid_12, aws.service: S3, aws_service: S3, bucketname: my-bucket, @@ -295,7 +315,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: UploadPart, - aws.requestId: Guid_11, + aws.requestId: Guid_13, aws.service: S3, aws_service: S3, bucketname: my-bucket, @@ -325,7 +345,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: CompleteMultipartUpload, - aws.requestId: Guid_12, + aws.requestId: Guid_14, aws.service: S3, aws_service: S3, bucketname: my-bucket, @@ -342,7 +362,17 @@ }, Metrics: { _dd.top_level: 1.0 - } + }, + SpanLinks: [ + { + Attributes: { + link.kind: span-pointer, + ptr.dir: d, + ptr.hash: Guid_15, + ptr.kind: aws.s3.object + } + } + ] }, { TraceId: Id_1, @@ -355,7 +385,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: ListBuckets, - aws.requestId: Guid_13, + aws.requestId: Guid_16, aws.service: S3, aws_service: S3, component: aws-sdk, @@ -383,7 +413,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: ListObjectsV2, - aws.requestId: Guid_14, + aws.requestId: Guid_17, aws.service: S3, aws_service: S3, bucketname: my-bucket, @@ -412,7 +442,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: DeleteObject, - aws.requestId: Guid_15, + aws.requestId: Guid_18, aws.service: S3, aws_service: S3, bucketname: my-bucket, @@ -442,7 +472,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: DeleteBucket, - aws.requestId: Guid_16, + aws.requestId: Guid_19, aws.service: S3, aws_service: S3, bucketname: my-bucket, diff --git a/tracer/test/snapshots/AwsS3Tests.NetFramework.SchemaV1.verified.txt b/tracer/test/snapshots/AwsS3Tests.NetFramework.SchemaV1.verified.txt index 4fbf14ee66bc..b9b9cfd94710 100644 --- a/tracer/test/snapshots/AwsS3Tests.NetFramework.SchemaV1.verified.txt +++ b/tracer/test/snapshots/AwsS3Tests.NetFramework.SchemaV1.verified.txt @@ -68,7 +68,17 @@ peer.service: my-bucket, span.kind: client, _dd.peer.service.source: my-bucket - } + }, + SpanLinks: [ + { + Attributes: { + link.kind: span-pointer, + ptr.dir: d, + ptr.hash: Guid_4, + ptr.kind: aws.s3.object + } + } + ] }, { TraceId: Id_1, @@ -81,7 +91,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: GetObject, - aws.requestId: Guid_4, + aws.requestId: Guid_5, aws.service: S3, aws_service: S3, bucketname: my-bucket, @@ -108,7 +118,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: CopyObject, - aws.requestId: Guid_5, + aws.requestId: Guid_6, aws.service: S3, aws_service: S3, bucketname: my-bucket, @@ -122,7 +132,17 @@ peer.service: my-bucket, span.kind: client, _dd.peer.service.source: my-bucket - } + }, + SpanLinks: [ + { + Attributes: { + link.kind: span-pointer, + ptr.dir: d, + ptr.hash: Guid_7, + ptr.kind: aws.s3.object + } + } + ] }, { TraceId: Id_1, @@ -135,7 +155,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: ListObjectsV2, - aws.requestId: Guid_6, + aws.requestId: Guid_8, aws.service: S3, aws_service: S3, bucketname: my-bucket, @@ -161,7 +181,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: DeleteObject, - aws.requestId: Guid_7, + aws.requestId: Guid_9, aws.service: S3, aws_service: S3, bucketname: my-bucket, @@ -188,7 +208,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: DeleteObjects, - aws.requestId: Guid_8, + aws.requestId: Guid_10, aws.service: S3, aws_service: S3, bucketname: my-bucket, @@ -214,7 +234,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: InitiateMultipartUpload, - aws.requestId: Guid_9, + aws.requestId: Guid_11, aws.service: S3, aws_service: S3, bucketname: my-bucket, @@ -241,7 +261,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: UploadPart, - aws.requestId: Guid_10, + aws.requestId: Guid_12, aws.service: S3, aws_service: S3, bucketname: my-bucket, @@ -268,7 +288,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: UploadPart, - aws.requestId: Guid_11, + aws.requestId: Guid_13, aws.service: S3, aws_service: S3, bucketname: my-bucket, @@ -295,7 +315,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: CompleteMultipartUpload, - aws.requestId: Guid_12, + aws.requestId: Guid_14, aws.service: S3, aws_service: S3, bucketname: my-bucket, @@ -309,7 +329,17 @@ peer.service: my-bucket, span.kind: client, _dd.peer.service.source: my-bucket - } + }, + SpanLinks: [ + { + Attributes: { + link.kind: span-pointer, + ptr.dir: d, + ptr.hash: Guid_15, + ptr.kind: aws.s3.object + } + } + ] }, { TraceId: Id_1, @@ -322,7 +352,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: ListBuckets, - aws.requestId: Guid_13, + aws.requestId: Guid_16, aws.service: S3, aws_service: S3, component: aws-sdk, @@ -345,7 +375,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: ListObjectsV2, - aws.requestId: Guid_14, + aws.requestId: Guid_17, aws.service: S3, aws_service: S3, bucketname: my-bucket, @@ -371,7 +401,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: DeleteObject, - aws.requestId: Guid_15, + aws.requestId: Guid_18, aws.service: S3, aws_service: S3, bucketname: my-bucket, @@ -398,7 +428,7 @@ Tags: { aws.agent: dotnet-aws-sdk, aws.operation: DeleteBucket, - aws.requestId: Guid_16, + aws.requestId: Guid_19, aws.service: S3, aws_service: S3, bucketname: my-bucket, From dc4e660f167eb009a8e3ddb0402491ac05d74b6b Mon Sep 17 00:00:00 2001 From: Kevin Gosse Date: Thu, 6 Mar 2025 16:33:45 +0100 Subject: [PATCH 2/7] [Profiler] Properly initialize appDomainId (#6630) ## Summary of changes The contention profiler and the allocation profiler don't set the appDomainId if the managed thread can't be found (it can happen, for instance, if it has exited). Because the `RawSample` isn't zero'd at construction, this causes the field to contain garbage, which can cause crashes down the line. Also, some error paths set the appDomainId to -1. I changed it to 0 because it's the value expected by the code that uses it and by the CLR. ## Reason for change This was found thanks to a crash dump in the CI, but there has been crash reports that we failed to understand until now. --- .../Datadog.Profiler.Native/AllocationsProvider.cpp | 8 +++----- .../Datadog.Profiler.Native/ContentionProvider.cpp | 6 ++---- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/profiler/src/ProfilerEngine/Datadog.Profiler.Native/AllocationsProvider.cpp b/profiler/src/ProfilerEngine/Datadog.Profiler.Native/AllocationsProvider.cpp index 312143739832..93b0f4dc498b 100644 --- a/profiler/src/ProfilerEngine/Datadog.Profiler.Native/AllocationsProvider.cpp +++ b/profiler/src/ProfilerEngine/Datadog.Profiler.Native/AllocationsProvider.cpp @@ -232,7 +232,7 @@ void AllocationsProvider::OnAllocation(std::chrono::nanoseconds timestamp, // TODO: we need to check that threads are not jumping from one AppDomain to the other too frequently // because we might be receiving this event 1 second after it has been emitted - // It this is the case, we should simply set the AppDomainId to -1 all the time. + // It this is the case, we should simply set the AppDomainId to 0 all the time. AppDomainID appDomainId; if (SUCCEEDED(_pCorProfilerInfo->GetThreadAppDomain(threadInfo->GetClrThreadId(), &appDomainId))) { @@ -240,15 +240,13 @@ void AllocationsProvider::OnAllocation(std::chrono::nanoseconds timestamp, } else { - rawSample.AppDomainId = -1; + rawSample.AppDomainId = 0; } } else // create a fake IThreadInfo that wraps the OS thread id (no name, no profiler thread id) { rawSample.ThreadInfo = std::make_shared(threadId); - - // TODO: do we need to set to -1? - // rawSample.AppDomainId = -1; + rawSample.AppDomainId = 0; } // rawSample.AllocationSize = objectSize; diff --git a/profiler/src/ProfilerEngine/Datadog.Profiler.Native/ContentionProvider.cpp b/profiler/src/ProfilerEngine/Datadog.Profiler.Native/ContentionProvider.cpp index 20b63f858cc0..8b234bb937ec 100644 --- a/profiler/src/ProfilerEngine/Datadog.Profiler.Native/ContentionProvider.cpp +++ b/profiler/src/ProfilerEngine/Datadog.Profiler.Native/ContentionProvider.cpp @@ -214,15 +214,13 @@ void ContentionProvider::AddContentionSample(std::chrono::nanoseconds timestamp, } else { - rawSample.AppDomainId = -1; + rawSample.AppDomainId = 0; } } else // create a fake IThreadInfo that wraps the OS thread id (no name, no profiler thread id) { rawSample.ThreadInfo = std::make_shared(threadId); - - // TODO: do we need to set to -1? - //rawSample.AppDomainId = -1; + rawSample.AppDomainId = 0; } } From 211f2676280abbb9a059f7feddcc1d83c9df6bb1 Mon Sep 17 00:00:00 2001 From: chrisnas Date: Thu, 6 Mar 2025 16:54:51 +0100 Subject: [PATCH 3/7] [Profiler] Add logs for the different profilers configuration (#6739) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary of changes Log the value of env vars used to configure the different profilers ## Reason for change This should help during investigations when samples are missing ## Implementation details Log specific env var retrieval; focusing on public ones (just ETW is not documented) ## Test coverage New tests are added ## Other details --- .../Datadog.Profiler.Native/Configuration.cpp | 45 +++- .../Datadog.Profiler.Native/Configuration.h | 2 +- .../Datadog.Profiler.Native/CpuProfilerType.h | 2 +- .../Datadog.Profiler.Native/DeploymentMode.h | 2 +- .../Configuration/ConfigurationTest.cs | 205 ++++++++++++++++++ 5 files changed, 241 insertions(+), 15 deletions(-) create mode 100644 profiler/test/Datadog.Profiler.IntegrationTests/Configuration/ConfigurationTest.cs diff --git a/profiler/src/ProfilerEngine/Datadog.Profiler.Native/Configuration.cpp b/profiler/src/ProfilerEngine/Datadog.Profiler.Native/Configuration.cpp index 98622ac3b7c2..485b9f7f709d 100644 --- a/profiler/src/ProfilerEngine/Datadog.Profiler.Native/Configuration.cpp +++ b/profiler/src/ProfilerEngine/Datadog.Profiler.Native/Configuration.cpp @@ -8,6 +8,7 @@ #include #include "EnvironmentVariables.h" +#include "Log.h" #include "OpSysTools.h" #include "shared/src/native-src/dd_filesystem.hpp" @@ -33,13 +34,13 @@ Configuration::Configuration() _pprofDirectory = ExtractPprofDirectory(); _isOperationalMetricsEnabled = GetEnvironmentValue(EnvironmentVariables::OperationalMetricsEnabled, false); _isNativeFrameEnabled = GetEnvironmentValue(EnvironmentVariables::NativeFramesEnabled, false); - _isCpuProfilingEnabled = GetEnvironmentValue(EnvironmentVariables::CpuProfilingEnabled, true); - _isWallTimeProfilingEnabled = GetEnvironmentValue(EnvironmentVariables::WallTimeProfilingEnabled, true); - _isExceptionProfilingEnabled = GetEnvironmentValue(EnvironmentVariables::ExceptionProfilingEnabled, true); - _isAllocationProfilingEnabled = GetEnvironmentValue(EnvironmentVariables::AllocationProfilingEnabled, false); + _isCpuProfilingEnabled = GetEnvironmentValue(EnvironmentVariables::CpuProfilingEnabled, true, true); + _isWallTimeProfilingEnabled = GetEnvironmentValue(EnvironmentVariables::WallTimeProfilingEnabled, true, true); + _isExceptionProfilingEnabled = GetEnvironmentValue(EnvironmentVariables::ExceptionProfilingEnabled, true, true); + _isAllocationProfilingEnabled = GetEnvironmentValue(EnvironmentVariables::AllocationProfilingEnabled, false, true); _isContentionProfilingEnabled = GetContention(); - _isGarbageCollectionProfilingEnabled = GetEnvironmentValue(EnvironmentVariables::GCProfilingEnabled, true); - _isHeapProfilingEnabled = GetEnvironmentValue(EnvironmentVariables::HeapProfilingEnabled, false); + _isGarbageCollectionProfilingEnabled = GetEnvironmentValue(EnvironmentVariables::GCProfilingEnabled, true, true); + _isHeapProfilingEnabled = GetEnvironmentValue(EnvironmentVariables::HeapProfilingEnabled, false, true); _uploadPeriod = ExtractUploadInterval(); _userTags = ExtractUserTags(); _version = GetEnvironmentValue(EnvironmentVariables::Version, DefaultVersion); @@ -50,7 +51,7 @@ Configuration::Configuration() _agentPort = GetEnvironmentValue(EnvironmentVariables::AgentPort, DefaultAgentPort); _site = ExtractSite(); _apiKey = GetEnvironmentValue(EnvironmentVariables::ApiKey, DefaultEmptyString); - _serviceName = GetEnvironmentValue(EnvironmentVariables::ServiceName, OpSysTools::GetProcessName()); + _serviceName = GetEnvironmentValue(EnvironmentVariables::ServiceName, OpSysTools::GetProcessName(), true); _isAgentLess = GetEnvironmentValue(EnvironmentVariables::Agentless, false); _exceptionSampleLimit = GetEnvironmentValue(EnvironmentVariables::ExceptionSampleLimit, 500); _allocationSampleLimit = GetEnvironmentValue(EnvironmentVariables::AllocationSampleLimit, 2000); @@ -90,7 +91,7 @@ Configuration::Configuration() _cpuProfilingInterval = ExtractCpuProfilingInterval(1ms); } - _isEtwEnabled = GetEnvironmentValue(EnvironmentVariables::EtwEnabled, true); + _isEtwEnabled = GetEnvironmentValue(EnvironmentVariables::EtwEnabled, true, true); _deploymentMode = GetEnvironmentValue(EnvironmentVariables::SsiDeployed, DeploymentMode::Manual); _isEtwLoggingEnabled = GetEnvironmentValue(EnvironmentVariables::EtwLoggingEnabled, false); _etwReplayEndpoint = GetEnvironmentValue(EnvironmentVariables::EtwReplayEndpoint, DefaultEmptyString); @@ -517,11 +518,12 @@ bool Configuration::GetContention() // first look at the supported env var if (IsEnvironmentValueSet(EnvironmentVariables::LockContentionProfilingEnabled, lockContentionEnabled)) { + Log::Info("Configuration: ", EnvironmentVariables::LockContentionProfilingEnabled, " env var is set - lock contention is enabled"); return lockContentionEnabled; } // if not there, look at the deprecated one - return GetEnvironmentValue(EnvironmentVariables::DeprecatedContentionProfilingEnabled, lockContentionEnabled); + return GetEnvironmentValue(EnvironmentVariables::DeprecatedContentionProfilingEnabled, lockContentionEnabled, true); } bool Configuration::GetDefaultDebugLogEnabled() @@ -668,13 +670,32 @@ static bool convert_to(shared::WSTRING const& s, DeploymentMode& result) template -T Configuration::GetEnvironmentValue(shared::WSTRING const& name, T const& defaultValue) +T Configuration::GetEnvironmentValue(shared::WSTRING const& name, T const& defaultValue, bool shouldLog) { - if (!shared::EnvironmentExist(name)) return defaultValue; + if (!shared::EnvironmentExist(name)) + { + if (shouldLog) + { + Log::Info("Configuration: ", name, " env var is not set - '", defaultValue, "' is used as default value"); + } + return defaultValue; + } T result{}; auto r = shared::GetEnvironmentValue(name); - if (!convert_to(r, result)) return defaultValue; + if (!convert_to(r, result)) + { + if (shouldLog) + { + Log::Info("Configuration: ", name, " env var is set to '", r,"' that cannot be converted - '", defaultValue, "' is used as default value"); + } + return defaultValue; + } + + if (shouldLog) + { + Log::Info("Configuration: ", name, " env var is set to '", r, "'"); + } return result; } diff --git a/profiler/src/ProfilerEngine/Datadog.Profiler.Native/Configuration.h b/profiler/src/ProfilerEngine/Datadog.Profiler.Native/Configuration.h index ff24843bc966..bdb64186319b 100644 --- a/profiler/src/ProfilerEngine/Datadog.Profiler.Native/Configuration.h +++ b/profiler/src/ProfilerEngine/Datadog.Profiler.Native/Configuration.h @@ -98,7 +98,7 @@ class Configuration final : public IConfiguration static std::chrono::seconds GetDefaultUploadInterval(); static bool GetDefaultDebugLogEnabled(); template - static T GetEnvironmentValue(shared::WSTRING const& name, T const& defaultValue); + static T GetEnvironmentValue(shared::WSTRING const& name, T const& defaultValue, bool shouldLog = false); template static bool IsEnvironmentValueSet(shared::WSTRING const& name, T& value); static std::chrono::nanoseconds ExtractCpuWallTimeSamplingRate(int minimum = 5); diff --git a/profiler/src/ProfilerEngine/Datadog.Profiler.Native/CpuProfilerType.h b/profiler/src/ProfilerEngine/Datadog.Profiler.Native/CpuProfilerType.h index 401024bd0207..d5a13cfdf5a7 100644 --- a/profiler/src/ProfilerEngine/Datadog.Profiler.Native/CpuProfilerType.h +++ b/profiler/src/ProfilerEngine/Datadog.Profiler.Native/CpuProfilerType.h @@ -5,7 +5,7 @@ #include "shared/src/native-src/string.h" -enum class CpuProfilerType +enum CpuProfilerType : int { ManualCpuTime, #ifdef LINUX diff --git a/profiler/src/ProfilerEngine/Datadog.Profiler.Native/DeploymentMode.h b/profiler/src/ProfilerEngine/Datadog.Profiler.Native/DeploymentMode.h index 9f714d2d0958..8c6639be2e65 100644 --- a/profiler/src/ProfilerEngine/Datadog.Profiler.Native/DeploymentMode.h +++ b/profiler/src/ProfilerEngine/Datadog.Profiler.Native/DeploymentMode.h @@ -5,7 +5,7 @@ #include -enum class DeploymentMode +enum DeploymentMode : int { Manual, SingleStepInstrumentation diff --git a/profiler/test/Datadog.Profiler.IntegrationTests/Configuration/ConfigurationTest.cs b/profiler/test/Datadog.Profiler.IntegrationTests/Configuration/ConfigurationTest.cs new file mode 100644 index 000000000000..60201daf34c1 --- /dev/null +++ b/profiler/test/Datadog.Profiler.IntegrationTests/Configuration/ConfigurationTest.cs @@ -0,0 +1,205 @@ +// +// 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 2022 Datadog, Inc. +// + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using Datadog.Profiler.IntegrationTests.Helpers; +using FluentAssertions; +using Xunit; +using Xunit.Abstractions; + +namespace Datadog.Profiler.IntegrationTests.Exceptions +{ + public class ConfigurationTest + { + private const string Scenario1 = "--scenario 18"; + + private readonly ITestOutputHelper _output; + + public ConfigurationTest(ITestOutputHelper output) + { + _output = output; + } + + // NOTE: we don't need to validate ALL runtimes but just one + // + + [TestAppFact("Samples.Computer01", new[] { "net9.0" })] + public void CheckEnvVarsInLogWithDefaultProfilers(string appName, string framework, string appAssembly) + { + var runner = new TestApplicationRunner(appName, framework, appAssembly, _output, commandLine: Scenario1); + // EnvironmentHelper.DisableDefaultProfilers(runner); + + using var agent = MockDatadogAgent.CreateHttpAgent(runner.XUnitLogger); + runner.Run(agent); + + bool cpuIsLogged = false; + bool walltimeIsLogged = false; + bool exceptionIsLogged = false; + bool allocationIsLogged = false; + bool lockIsLogged = false; + bool gcIsLogged = false; + bool heapIsLogged = false; + bool serviceIsLogged = false; + bool etwIsLogged = false; + + var logFile = Directory.GetFiles(runner.Environment.LogDir) + .Single(f => Path.GetFileName(f).StartsWith("DD-DotNet-Profiler-Native-")); + + foreach (var line in File.ReadLines(logFile)) + { + if (line.Contains("DD_PROFILING_CPU_ENABLED")) + { + cpuIsLogged = true; + } + else + if (line.Contains("DD_PROFILING_WALLTIME_ENABLED")) + { + walltimeIsLogged = true; + } + else + if (line.Contains("DD_PROFILING_EXCEPTION_ENABLED")) + { + exceptionIsLogged = true; + } + else + if (line.Contains("DD_PROFILING_ALLOCATION_ENABLED")) + { + allocationIsLogged = true; + } + else + if (line.Contains("DD_PROFILING_CONTENTION_ENABLED")) + { + lockIsLogged = true; + } + else + if (line.Contains("DD_PROFILING_GC_ENABLED")) + { + gcIsLogged = true; + } + else + if (line.Contains("DD_PROFILING_HEAP_ENABLED")) + { + heapIsLogged = true; + } + else + if (line.Contains("DD_SERVICE")) + { + serviceIsLogged = true; + } + else + if (line.Contains("DD_INTERNAL_PROFILING_ETW_ENABLED")) + { + etwIsLogged = true; + } + else if (line.Contains("] Configuration: DD_")) + { + // This is the default value + Assert.Fail($"unexpected configuration log - {line}"); + } + } + + cpuIsLogged.Should().BeTrue(); + walltimeIsLogged.Should().BeTrue(); + exceptionIsLogged.Should().BeTrue(); + allocationIsLogged.Should().BeTrue(); + lockIsLogged.Should().BeTrue(); + gcIsLogged.Should().BeTrue(); + heapIsLogged.Should().BeTrue(); + serviceIsLogged.Should().BeTrue(); + etwIsLogged.Should().BeTrue(); + } + + [TestAppFact("Samples.Computer01", new[] { "net9.0" })] + public void CheckEnvVarsInLogWithDisabledProfilers(string appName, string framework, string appAssembly) + { + var runner = new TestApplicationRunner(appName, framework, appAssembly, _output, commandLine: Scenario1); + EnvironmentHelper.DisableDefaultProfilers(runner); + + using var agent = MockDatadogAgent.CreateHttpAgent(runner.XUnitLogger); + runner.Run(agent); + + bool cpuIsLogged = false; + bool walltimeIsLogged = false; + bool exceptionIsLogged = false; + bool allocationIsLogged = false; + bool lockIsLogged = false; + bool gcIsLogged = false; + bool heapIsLogged = false; + bool serviceIsLogged = false; + bool etwIsLogged = false; + + var logFile = Directory.GetFiles(runner.Environment.LogDir) + .Single(f => Path.GetFileName(f).StartsWith("DD-DotNet-Profiler-Native-")); + + foreach (var line in File.ReadLines(logFile)) + { + if (line.Contains("DD_PROFILING_CPU_ENABLED")) + { + cpuIsLogged = true; + } + else + if (line.Contains("DD_PROFILING_WALLTIME_ENABLED")) + { + walltimeIsLogged = true; + } + else + if (line.Contains("DD_PROFILING_EXCEPTION_ENABLED")) + { + exceptionIsLogged = true; + } + else + if (line.Contains("DD_PROFILING_ALLOCATION_ENABLED")) + { + allocationIsLogged = true; + } + else + if (line.Contains("DD_PROFILING_LOCK_ENABLED")) + { + lockIsLogged = true; + } + else + if (line.Contains("DD_PROFILING_GC_ENABLED")) + { + gcIsLogged = true; + } + else + if (line.Contains("DD_PROFILING_HEAP_ENABLED")) + { + heapIsLogged = true; + } + else + if (line.Contains("DD_SERVICE")) + { + serviceIsLogged = true; + } + else + if (line.Contains("DD_INTERNAL_PROFILING_ETW_ENABLED")) + { + etwIsLogged = true; + } + else if (line.Contains("] Configuration: DD_")) + { + // This is the default value + Assert.Fail($"unexpected configuration log - {line}"); + } + } + + cpuIsLogged.Should().BeTrue(); + walltimeIsLogged.Should().BeTrue(); + exceptionIsLogged.Should().BeTrue(); + allocationIsLogged.Should().BeTrue(); + lockIsLogged.Should().BeTrue(); + gcIsLogged.Should().BeTrue(); + heapIsLogged.Should().BeTrue(); + serviceIsLogged.Should().BeTrue(); + etwIsLogged.Should().BeTrue(); + } + } +} From 6df72ed0151c27adb95deb77dad9dc63eb13b8b6 Mon Sep 17 00:00:00 2001 From: Zach Montoya Date: Thu, 6 Mar 2025 08:58:57 -0800 Subject: [PATCH 4/7] [Tracing] Update DD_TAGS behavior through a feature flag to better align with Datadog Agent tags parsing logic (#6728) Uses the new `DD_TRACE_EXPERIMENTAL_FEATURES_ENABLED` flag via #6727 to expose new parsing behavior for `DD_TAGS` which aligns more closely to the Datadog Agent tags parsing logic and aligns with the other tracing libraries. This PR also adds a new internal API in `IConfigurationSource` so the caller can define a delegate for mapping a configuration value string into a dictionary, which enables the new, non-obvious parsing rules for `DD_TAGS` --- .../CompositeConfigurationSource.cs | 6 + .../DictionaryObjectConfigurationSource.cs | 5 +- .../IConfigurationSource.cs | 14 +- .../JsonConfigurationSource.cs | 62 +++++++ .../NullConfigurationSource.cs | 3 + .../StringConfigurationSource.cs | 25 +++ .../Telemetry/ConfigurationBuilder.cs | 24 +++ .../Configuration/TracerSettings.cs | 77 ++++++++- .../Configuration/ConfigurationSourceTests.cs | 157 +++++++++++------- 9 files changed, 307 insertions(+), 66 deletions(-) diff --git a/tracer/src/Datadog.Trace/Configuration/ConfigurationSources/CompositeConfigurationSource.cs b/tracer/src/Datadog.Trace/Configuration/ConfigurationSources/CompositeConfigurationSource.cs index 1df489f402f2..5da97e8c09f2 100644 --- a/tracer/src/Datadog.Trace/Configuration/ConfigurationSources/CompositeConfigurationSource.cs +++ b/tracer/src/Datadog.Trace/Configuration/ConfigurationSources/CompositeConfigurationSource.cs @@ -105,6 +105,12 @@ public ConfigurationResult> GetDictionary(string key .Select(source => source.GetDictionary(key, telemetry, validator, allowOptionalMappings, separator)) .FirstOrDefault(value => value.IsValid, ConfigurationResult>.NotFound()); + /// + public ConfigurationResult> GetDictionary(string key, IConfigurationTelemetry telemetry, Func, bool>? validator, Func> parser) + => _sources + .Select(source => source.GetDictionary(key, telemetry, validator, parser)) + .FirstOrDefault(value => value.IsValid, ConfigurationResult>.NotFound()); + /// public ConfigurationResult GetAs(string key, IConfigurationTelemetry telemetry, Func> converter, Func? validator, bool recordValue) => _sources diff --git a/tracer/src/Datadog.Trace/Configuration/ConfigurationSources/DictionaryObjectConfigurationSource.cs b/tracer/src/Datadog.Trace/Configuration/ConfigurationSources/DictionaryObjectConfigurationSource.cs index e25059a0abe5..a639b572df6f 100644 --- a/tracer/src/Datadog.Trace/Configuration/ConfigurationSources/DictionaryObjectConfigurationSource.cs +++ b/tracer/src/Datadog.Trace/Configuration/ConfigurationSources/DictionaryObjectConfigurationSource.cs @@ -1,4 +1,4 @@ -// +// // 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. // @@ -154,6 +154,9 @@ public ConfigurationResult> GetDictionary(string key return ConfigurationResult>.NotFound(); } + public ConfigurationResult> GetDictionary(string key, IConfigurationTelemetry telemetry, Func, bool>? validator, Func> parser) + => GetDictionary(key, telemetry, validator, allowOptionalMappings: false, separator: ':'); + public ConfigurationResult GetAs(string key, IConfigurationTelemetry telemetry, Func> converter, Func? validator, bool recordValue) { if (TryGetValue(key, out var objValue) && objValue is not null) diff --git a/tracer/src/Datadog.Trace/Configuration/ConfigurationSources/IConfigurationSource.cs b/tracer/src/Datadog.Trace/Configuration/ConfigurationSources/IConfigurationSource.cs index b7944b898a83..0e02827773da 100644 --- a/tracer/src/Datadog.Trace/Configuration/ConfigurationSources/IConfigurationSource.cs +++ b/tracer/src/Datadog.Trace/Configuration/ConfigurationSources/IConfigurationSource.cs @@ -1,4 +1,4 @@ -// +// // 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. // @@ -98,6 +98,18 @@ ConfigurationResult GetString( /// The value of the setting, or null if not found. ConfigurationResult> GetDictionary(string key, IConfigurationTelemetry telemetry, Func, bool>? validator, bool allowOptionalMappings, char separator); + /// + /// Gets the value of + /// the setting with the specified key. + /// + /// The key that identifies the setting. + /// The context for recording telemetry. + /// An optional validation function that must be applied to + /// a successfully extracted value to determine if it should be accepted + /// A user-provided parser that converts the input string into a dictionary + /// The value of the setting, or null if not found. + ConfigurationResult> GetDictionary(string key, IConfigurationTelemetry telemetry, Func, bool>? validator, Func> parser); + /// /// Gets the value of /// the setting with the specified key. diff --git a/tracer/src/Datadog.Trace/Configuration/ConfigurationSources/JsonConfigurationSource.cs b/tracer/src/Datadog.Trace/Configuration/ConfigurationSources/JsonConfigurationSource.cs index ef1b4695c04b..9d50a36d016c 100644 --- a/tracer/src/Datadog.Trace/Configuration/ConfigurationSources/JsonConfigurationSource.cs +++ b/tracer/src/Datadog.Trace/Configuration/ConfigurationSources/JsonConfigurationSource.cs @@ -336,6 +336,68 @@ ConfigurationResult> Validate(IDictionary> GetDictionary(string key, IConfigurationTelemetry telemetry, Func, bool>? validator, Func> parser) + { + var token = SelectToken(key); + if (token == null) + { + return ConfigurationResult>.NotFound(); + } + + if (!TreatNullDictionaryAsEmpty && !token.HasValues) + { + return ConfigurationResult>.NotFound(); + } + + var tokenAsString = token.ToString(); + + try + { + if (token.Type == JTokenType.Object || token.Type == JTokenType.Array) + { + try + { + var dictionary = ConvertToDictionary(key, token); + if (dictionary is null) + { + // AFAICT this should never return null in practice - we + // already checked the token is not null, and it will throw + // if parsing fails, so using parsing failure here for safety + return ConfigurationResult>.ParseFailure(); + } + + return Validate(dictionary); + } + catch (Exception e) + { + Log.Error(e, "Unable to parse configuration value for {ConfigurationKey} as key-value pairs of strings.", key); + telemetry.Record(key, tokenAsString, recordValue: true, _origin, TelemetryErrorCode.JsonStringError); + return ConfigurationResult>.ParseFailure(); + } + } + + var result = parser(tokenAsString); + return Validate(result); + } + catch (InvalidCastException) + { + telemetry.Record(key, tokenAsString, recordValue: true, _origin, TelemetryErrorCode.JsonStringError); + throw; // Exising behaviour + } + + ConfigurationResult> Validate(IDictionary dictionary) + { + if (validator is null || validator(dictionary)) + { + telemetry.Record(key, tokenAsString, recordValue: true, _origin); + return ConfigurationResult>.Valid(dictionary); + } + + telemetry.Record(key, tokenAsString, recordValue: true, _origin, TelemetryErrorCode.FailedValidation); + return ConfigurationResult>.Invalid(dictionary); + } + } + private protected virtual JToken? SelectToken(string key) => _configuration?.SelectToken(key, errorWhenNoMatch: false); private protected virtual IDictionary? ConvertToDictionary(string key, JToken token) diff --git a/tracer/src/Datadog.Trace/Configuration/ConfigurationSources/NullConfigurationSource.cs b/tracer/src/Datadog.Trace/Configuration/ConfigurationSources/NullConfigurationSource.cs index 62a142611bcc..8ff1e644d1b3 100644 --- a/tracer/src/Datadog.Trace/Configuration/ConfigurationSources/NullConfigurationSource.cs +++ b/tracer/src/Datadog.Trace/Configuration/ConfigurationSources/NullConfigurationSource.cs @@ -36,6 +36,9 @@ public ConfigurationResult> GetDictionary(string key public ConfigurationResult> GetDictionary(string key, IConfigurationTelemetry telemetry, Func, bool>? validator, bool allowOptionalMappings, char separator) => ConfigurationResult>.NotFound(); + public ConfigurationResult> GetDictionary(string key, IConfigurationTelemetry telemetry, Func, bool>? validator, Func> parser) + => ConfigurationResult>.NotFound(); + public ConfigurationResult GetAs(string key, IConfigurationTelemetry telemetry, Func> converter, Func? validator, bool recordValue) => ConfigurationResult.NotFound(); } diff --git a/tracer/src/Datadog.Trace/Configuration/ConfigurationSources/StringConfigurationSource.cs b/tracer/src/Datadog.Trace/Configuration/ConfigurationSources/StringConfigurationSource.cs index 848e87383fdc..b4b29ad83be4 100644 --- a/tracer/src/Datadog.Trace/Configuration/ConfigurationSources/StringConfigurationSource.cs +++ b/tracer/src/Datadog.Trace/Configuration/ConfigurationSources/StringConfigurationSource.cs @@ -276,5 +276,30 @@ public ConfigurationResult> GetDictionary(string key telemetry.Record(key, value, recordValue: true, Origin, TelemetryErrorCode.FailedValidation); return ConfigurationResult>.Invalid(result); } + + /// + public ConfigurationResult> GetDictionary(string key, IConfigurationTelemetry telemetry, Func, bool>? validator, Func> parser) + { + var value = GetString(key); + + if (value is null) + { + return ConfigurationResult>.NotFound(); + } + + // We record the original dictionary value here instead of serializing the _parsed_ value + // Currently we have no validation of the dictionary values during parsing, so there's no way to get + // a validation error that needs recording at this stage + var result = parser(value); + + if (validator is null || validator(result)) + { + telemetry.Record(key, value, recordValue: true, Origin); + return ConfigurationResult>.Valid(result); + } + + telemetry.Record(key, value, recordValue: true, Origin, TelemetryErrorCode.FailedValidation); + return ConfigurationResult>.Invalid(result); + } } } diff --git a/tracer/src/Datadog.Trace/Configuration/ConfigurationSources/Telemetry/ConfigurationBuilder.cs b/tracer/src/Datadog.Trace/Configuration/ConfigurationSources/Telemetry/ConfigurationBuilder.cs index 0c796dd510c9..c75ebb3386ee 100644 --- a/tracer/src/Datadog.Trace/Configuration/ConfigurationSources/Telemetry/ConfigurationBuilder.cs +++ b/tracer/src/Datadog.Trace/Configuration/ConfigurationSources/Telemetry/ConfigurationBuilder.cs @@ -371,6 +371,9 @@ public ClassConfigurationResultWithKey> AsDictionary public ClassConfigurationResultWithKey> AsDictionaryResult(bool allowOptionalMappings, char separator) => new(Telemetry, Key, recordValue: true, configurationResult: GetDictionaryResult(allowOptionalMappings, separator)); + public ClassConfigurationResultWithKey> AsDictionaryResult(Func> parser) + => new(Telemetry, Key, recordValue: true, configurationResult: GetDictionaryResult(parser)); + private ConfigurationResult GetStringResult(Func? validator, Func>? converter, bool recordValue) => converter is null ? GetResult(AsStringSelector, validator, recordValue) @@ -477,6 +480,27 @@ private ConfigurationResult> GetDictionaryResult(boo return result; } + + private ConfigurationResult> GetDictionaryResult(Func> parser) + { + var result = Source.GetDictionary(Key, Telemetry, validator: null, parser); + if (result.ShouldFallBack && FallbackKey1 is not null) + { + result = Source.GetDictionary(FallbackKey1, Telemetry, validator: null, parser); + } + + if (result.ShouldFallBack && FallbackKey2 is not null) + { + result = Source.GetDictionary(FallbackKey2, Telemetry, validator: null, parser); + } + + if (result.ShouldFallBack && FallbackKey3 is not null) + { + result = Source.GetDictionary(FallbackKey3, Telemetry, validator: null, parser); + } + + return result; + } } internal readonly struct StructConfigurationResultWithKey(IConfigurationTelemetry telemetry, string key, bool recordValue, ConfigurationResult configurationResult) diff --git a/tracer/src/Datadog.Trace/Configuration/TracerSettings.cs b/tracer/src/Datadog.Trace/Configuration/TracerSettings.cs index 17ce9c4cf230..486b03ea1bd9 100644 --- a/tracer/src/Datadog.Trace/Configuration/TracerSettings.cs +++ b/tracer/src/Datadog.Trace/Configuration/TracerSettings.cs @@ -6,6 +6,7 @@ #nullable enable using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics.CodeAnalysis; @@ -37,7 +38,10 @@ namespace Datadog.Trace.Configuration public record TracerSettings { private static readonly IDatadogLogger Log = DatadogLogging.GetLoggerFor(); - private static readonly HashSet DefaultExperimentalFeatures = new HashSet(); + private static readonly HashSet DefaultExperimentalFeatures = new HashSet() + { + "DD_TAGS" + }; private readonly IConfigurationTelemetry _telemetry; // we cached the static instance here, because is being used in the hotpath @@ -149,7 +153,71 @@ _ when x.ToBoolean() is { } boolean => boolean, .WithKeys(ConfigurationKeys.OpenTelemetry.ResourceAttributes) .AsDictionaryResult(separator: '='); - var globalTags = config + Dictionary? globalTags = default; + if (ExperimentalFeaturesEnabled.Contains("DD_TAGS")) + { + // New behavior: If ExperimentalFeaturesEnabled configures DD_TAGS, we want to change DD_TAGS parsing to do the following: + // 1. If a comma is in the value, split on comma as before. Otherwise, split on space + // 2. Key-value pairs with empty values are allowed, instead of discarded + // 3. Key-value pairs without values (i.e. no `:` separator) are allowed and treated as key-value pairs with empty values, instead of discarded + Func> updatedTagsParser = (data) => + { + var dictionary = new ConcurrentDictionary(); + if (string.IsNullOrWhiteSpace(data)) + { + // return empty collection + return dictionary; + } + + char[] separatorChars = data.Contains(',') ? [','] : [' ']; + var entries = data.Split(separatorChars, StringSplitOptions.RemoveEmptyEntries); + + foreach (var entry in entries) + { + // we need Trim() before looking forthe separator so we can skip entries with no key + // (that is, entries with a leading separator, like ":value") + var trimmedEntry = entry.Trim(); + if (trimmedEntry.Length == 0 || trimmedEntry[0] == ':') + { + continue; + } + + var separatorIndex = trimmedEntry.IndexOf(':'); + if (separatorIndex < 0) + { + // entries with no separator are allowed (e.g. key1 and key3 in "key1, key2:value2, key3"), + // it's a key with no value. + var key = trimmedEntry; + dictionary[key] = string.Empty; + } + else if (separatorIndex > 0) + { + // if a separator is present with no value, we take the value to be empty (e.g. "key1:, key2: "). + // note we already did Trim() on the entire entry, so the key portion only needs TrimEnd(). + var key = trimmedEntry.Substring(0, separatorIndex).TrimEnd(); + var value = trimmedEntry.Substring(separatorIndex + 1).Trim(); + dictionary[key] = value; + } + } + + return dictionary; + }; + + globalTags = config + .WithKeys(ConfigurationKeys.GlobalTags, "DD_TRACE_GLOBAL_TAGS") + .AsDictionaryResult(parser: updatedTagsParser) + .OverrideWith( + RemapOtelTags(in otelTags), + ErrorLog, + () => new DefaultResult>(new Dictionary(), string.Empty)) + + // Filter out tags with empty keys, and trim whitespace + .Where(kvp => !string.IsNullOrWhiteSpace(kvp.Key)) + .ToDictionary(kvp => kvp.Key.Trim(), kvp => kvp.Value?.Trim() ?? string.Empty); + } + else + { + globalTags = config .WithKeys(ConfigurationKeys.GlobalTags, "DD_TRACE_GLOBAL_TAGS") .AsDictionaryResult() .OverrideWith( @@ -157,16 +225,17 @@ _ when x.ToBoolean() is { } boolean => boolean, ErrorLog, () => new DefaultResult>(new Dictionary(), string.Empty)) - // Filter out tags with empty keys or empty values, and trim whitespace + // Filter out tags with empty keys or empty values, and trim whitespace .Where(kvp => !string.IsNullOrWhiteSpace(kvp.Key) && !string.IsNullOrWhiteSpace(kvp.Value)) .ToDictionary(kvp => kvp.Key.Trim(), kvp => kvp.Value.Trim()); + } Environment = config .WithKeys(ConfigurationKeys.Environment) .AsString(); // DD_ENV has precedence over DD_TAGS - Environment = GetExplicitSettingOrTag(Environment, globalTags, Tags.Env, ConfigurationKeys.Environment); + Environment = GetExplicitSettingOrTag(Environment, globalTags!, Tags.Env, ConfigurationKeys.Environment); var otelServiceName = config.WithKeys(ConfigurationKeys.OpenTelemetry.ServiceName).AsStringResult(); var serviceName = config diff --git a/tracer/test/Datadog.Trace.Tests/Configuration/ConfigurationSourceTests.cs b/tracer/test/Datadog.Trace.Tests/Configuration/ConfigurationSourceTests.cs index 2bda0475d86d..ce00248960a4 100644 --- a/tracer/test/Datadog.Trace.Tests/Configuration/ConfigurationSourceTests.cs +++ b/tracer/test/Datadog.Trace.Tests/Configuration/ConfigurationSourceTests.cs @@ -22,7 +22,9 @@ public class ConfigurationSourceTests : IDisposable { private static readonly Dictionary TagsK1V1K2V2 = new() { { "k1", "v1" }, { "k2", "v2" } }; private static readonly Dictionary TagsK2V2 = new() { { "k2", "v2" } }; + private static readonly Dictionary TagsKey1Key2 = new() { { "key1", string.Empty }, { "key2", string.Empty } }; private static readonly Dictionary TagsWithColonsInValue = new() { { "k1", "v1" }, { "k2", "v2:with:colons" }, { "trailing", "colon:good:" } }; + private static readonly Dictionary TagsWithSpacesInValue = new() { { "key", "val" }, { "aKey", "aVal bKey:bVal cKey:" } }; private static readonly Dictionary HeaderTagsWithOptionalMappings = new() { { "header1", "tag1" }, { "header2", "Content-Type" }, { "header3", "Content-Type" }, { "header4", "C!!!ont_____ent----tYp!/!e" }, { "validheaderwithoutcolon", string.Empty } }; private static readonly Dictionary HeaderTagsWithDots = new() { { "header3", "my.header.with.dot" }, { "my.new.header.with.dot", string.Empty } }; private static readonly Dictionary HeaderTagsSameTag = new() { { "header1", "tag1" }, { "header2", "tag1" } }; @@ -34,6 +36,8 @@ public ConfigurationSourceTests() _envVars = GetTestData() .Select(allArgs => allArgs.Key) .Concat(GetGlobalTestData().Select(allArgs => allArgs.Key)) + .Concat(GetBreakingChangeTestData().Select(allArgs => allArgs.Key)) + .Concat([ConfigurationKeys.ExperimentalFeaturesEnabled]) .Distinct() .ToDictionary(key => key, key => Environment.GetEnvironmentVariable(key)); } @@ -89,6 +93,15 @@ public ConfigurationSourceTests() yield return (s => s.TraceId128BitLoggingEnabled, false); } + public static IEnumerable<(string Key, string Value, Func Getter, object Expected)> GetBreakingChangeTestData() + { + // Test edge cases that expose various discrepenacies with the Agent DD_TAGS parsing algorithm that we would like to support + yield return (ConfigurationKeys.GlobalTags, "k1:v1 k2:v2", s => s.GlobalTags, TagsK1V1K2V2); + yield return (ConfigurationKeys.GlobalTags, "key1,key2", s => s.GlobalTags, TagsKey1Key2); + yield return (ConfigurationKeys.GlobalTags, "key1,key2:", s => s.GlobalTags, TagsKey1Key2); + yield return (ConfigurationKeys.GlobalTags, "key :val, aKey : aVal bKey:bVal cKey:", s => s.GlobalTags, TagsWithSpacesInValue); + } + public static IEnumerable<(string Key, string Value, Func Getter, object Expected)> GetTestData() { yield return (ConfigurationKeys.TraceEnabled, "true", s => s.TraceEnabled, true); @@ -112,6 +125,12 @@ public ConfigurationSourceTests() yield return (ConfigurationKeys.GlobalTags, "k1:v1,k1:v2", s => s.GlobalTags.Count, 1); yield return (ConfigurationKeys.GlobalTags, "k1:v1, k2:v2:with:colons, :leading:colon:bad, trailing:colon:good:", s => s.GlobalTags, TagsWithColonsInValue); + // Test edge cases that expose various discrepenacies with the Agent DD_TAGS parsing algorithm that we would like to support + yield return (ConfigurationKeys.GlobalTags, "k1:v1 k2:v2", s => s.GlobalTags, new Dictionary() { { "k1", "v1 k2:v2" } }); + yield return (ConfigurationKeys.GlobalTags, "key1,key2", s => s.GlobalTags.Count, 0); + yield return (ConfigurationKeys.GlobalTags, "key1,key2:", s => s.GlobalTags.Count, 0); + yield return (ConfigurationKeys.GlobalTags, "key :val, aKey : aVal bKey:bVal cKey:", s => s.GlobalTags, TagsWithSpacesInValue); + #pragma warning disable 618 // App Analytics is deprecated but still supported yield return (ConfigurationKeys.GlobalAnalyticsEnabled, "true", s => s.AnalyticsEnabled, true); yield return (ConfigurationKeys.GlobalAnalyticsEnabled, "false", s => s.AnalyticsEnabled, false); @@ -166,73 +185,22 @@ public void DefaultSetting() } [Fact] - public void NameValueConfigurationSource() - { - foreach (var (key, value, settingGetter, expectedValue) in GetTestData()) - { - var collection = new NameValueCollection { { key, value } }; - IConfigurationSource source = new NameValueConfigurationSource(collection); - var settings = new TracerSettings(source); - object actualValue = settingGetter(settings); - // Assert.Equal(expectedValue, actualValue); - actualValue.Should().BeEquivalentTo(expectedValue); - } - } + public void NameValueConfigurationSource() => AssertNameValueConfigurationSource(GetTestData()); [Fact] - public void EnvironmentConfigurationSource() - { - foreach (var (key, value, settingGetter, expectedValue) in GetTestData()) - { - TracerSettings settings; - - if (key == "DD_SERVICE_NAME") - { - // We need to ensure DD_SERVICE is empty. - Environment.SetEnvironmentVariable(ConfigurationKeys.ServiceName, null, EnvironmentVariableTarget.Process); - settings = GetTracerSettings(key, value); - } - else if (key == ConfigurationKeys.AgentHost || key == ConfigurationKeys.AgentPort) - { - // We need to ensure all the agent URLs are empty. - Environment.SetEnvironmentVariable(ConfigurationKeys.AgentHost, null, EnvironmentVariableTarget.Process); - Environment.SetEnvironmentVariable(ConfigurationKeys.AgentPort, null, EnvironmentVariableTarget.Process); - Environment.SetEnvironmentVariable(ConfigurationKeys.AgentUri, null, EnvironmentVariableTarget.Process); + public void BreakingChanges_NameValueConfigurationSource() => AssertNameValueConfigurationSource(GetBreakingChangeTestData(), setExperimentalFeaturesEnabled: "all"); - settings = GetTracerSettings(key, value); - } - else - { - settings = GetTracerSettings(key, value); - } - - var actualValue = settingGetter(settings); - actualValue.Should().BeEquivalentTo(expectedValue, $"{key} should have correct value"); - ResetEnvironment(); - } + [Fact] + public void EnvironmentConfigurationSource() => AssertEnvironmentConfigurationSource(GetTestData()); - static TracerSettings GetTracerSettings(string key, string value) - { - Environment.SetEnvironmentVariable(key, value, EnvironmentVariableTarget.Process); - IConfigurationSource source = new EnvironmentConfigurationSource(); - return new TracerSettings(source); - } - } + [Fact] + public void BreakingChanges_EnvironmentConfigurationSource() => AssertEnvironmentConfigurationSource(GetBreakingChangeTestData(), setExperimentalFeaturesEnabled: "all"); [Fact] - public void JsonConfigurationSource() - { - foreach (var (key, value, settingGetter, expectedValue) in GetTestData()) - { - var config = new Dictionary { [key] = value }; - string json = JsonConvert.SerializeObject(config); - IConfigurationSource source = new JsonConfigurationSource(json); - var settings = new TracerSettings(source); + public void JsonConfigurationSource() => AssertJsonConfigurationSource(GetTestData()); - object actualValue = settingGetter(settings); - Assert.Equal(expectedValue, actualValue); - } - } + [Fact] + public void BreakingChanges_JsonConfigurationSource() => AssertJsonConfigurationSource(GetBreakingChangeTestData(), setExperimentalFeaturesEnabled: "all"); [Fact] public void GlobalDefaultSetting() @@ -335,6 +303,75 @@ public void TestHeaderTagsNormalization(bool headerTagsNormalizationFixEnabled, Assert.Equal(expectedValue, settings.HeaderTags); } + private void AssertNameValueConfigurationSource(IEnumerable<(string Key, string Value, Func Getter, object Expected)> testData, string setExperimentalFeaturesEnabled = "") + { + foreach (var (key, value, settingGetter, expectedValue) in testData) + { + var collection = new NameValueCollection { { key, value } }; + collection.Add(ConfigurationKeys.ExperimentalFeaturesEnabled, setExperimentalFeaturesEnabled); + IConfigurationSource source = new NameValueConfigurationSource(collection); + var settings = new TracerSettings(source); + object actualValue = settingGetter(settings); + // Assert.Equal(expectedValue, actualValue); + actualValue.Should().BeEquivalentTo(expectedValue); + } + } + + private void AssertEnvironmentConfigurationSource(IEnumerable<(string Key, string Value, Func Getter, object Expected)> testData, string setExperimentalFeaturesEnabled = "") + { + foreach (var (key, value, settingGetter, expectedValue) in testData) + { + TracerSettings settings; + + if (key == "DD_SERVICE_NAME") + { + // We need to ensure DD_SERVICE is empty. + Environment.SetEnvironmentVariable(ConfigurationKeys.ServiceName, null, EnvironmentVariableTarget.Process); + settings = GetTracerSettings(key, value, setExperimentalFeaturesEnabled); + } + else if (key == ConfigurationKeys.AgentHost || key == ConfigurationKeys.AgentPort) + { + // We need to ensure all the agent URLs are empty. + Environment.SetEnvironmentVariable(ConfigurationKeys.AgentHost, null, EnvironmentVariableTarget.Process); + Environment.SetEnvironmentVariable(ConfigurationKeys.AgentPort, null, EnvironmentVariableTarget.Process); + Environment.SetEnvironmentVariable(ConfigurationKeys.AgentUri, null, EnvironmentVariableTarget.Process); + + settings = GetTracerSettings(key, value, setExperimentalFeaturesEnabled); + } + else + { + settings = GetTracerSettings(key, value, setExperimentalFeaturesEnabled); + } + + var actualValue = settingGetter(settings); + actualValue.Should().BeEquivalentTo(expectedValue, $"{key} should have correct value"); + ResetEnvironment(); + } + + static TracerSettings GetTracerSettings(string key, string value, string setExperimentalFeaturesEnabled) + { + Environment.SetEnvironmentVariable(key, value, EnvironmentVariableTarget.Process); + Environment.SetEnvironmentVariable(ConfigurationKeys.ExperimentalFeaturesEnabled, setExperimentalFeaturesEnabled, EnvironmentVariableTarget.Process); + IConfigurationSource source = new EnvironmentConfigurationSource(); + return new TracerSettings(source); + } + } + + private void AssertJsonConfigurationSource(IEnumerable<(string Key, string Value, Func Getter, object Expected)> testData, string setExperimentalFeaturesEnabled = "") + { + foreach (var (key, value, settingGetter, expectedValue) in testData) + { + var config = new Dictionary { [key] = value }; + config.Add(ConfigurationKeys.ExperimentalFeaturesEnabled, setExperimentalFeaturesEnabled); + string json = JsonConvert.SerializeObject(config); + IConfigurationSource source = new JsonConfigurationSource(json); + var settings = new TracerSettings(source); + + object actualValue = settingGetter(settings); + Assert.Equal(expectedValue, actualValue); + } + } + private void ResetEnvironment() { foreach (var envVar in _envVars) From 87271dd6410f364105d07b717e2201845127a1ee Mon Sep 17 00:00:00 2001 From: Dudi Keleti Date: Thu, 6 Mar 2025 22:26:28 +0100 Subject: [PATCH 5/7] [Dynamic Instrumentation] DEBUG-3572 Check for valid gzip content (#6687) ## Reason for change There are cases where we have invalid gzip files, we want to avoid upload them and log those cases for further investigation ## Implementation details Check that the gzip content incliudes at least valid header and footer --- .../Debugger/Upload/SymbolUploadApi.cs | 52 +++++++++++++++---- 1 file changed, 42 insertions(+), 10 deletions(-) diff --git a/tracer/src/Datadog.Trace/Debugger/Upload/SymbolUploadApi.cs b/tracer/src/Datadog.Trace/Debugger/Upload/SymbolUploadApi.cs index 762d6f13faa4..283af7e41b49 100644 --- a/tracer/src/Datadog.Trace/Debugger/Upload/SymbolUploadApi.cs +++ b/tracer/src/Datadog.Trace/Debugger/Upload/SymbolUploadApi.cs @@ -42,7 +42,7 @@ private SymbolUploadApi( discoveryService.SubscribeToChanges(c => Endpoint = c.SymbolDbEndpoint); } - public static IBatchUploadApi Create( + internal static IBatchUploadApi Create( IApiRequestFactory apiRequestFactory, IDiscoveryService discoveryService, IGitMetadataTagsProvider gitMetadataTagsProvider, @@ -90,18 +90,13 @@ public override async Task SendBatchAsync(ArraySegment symbols) } else { - using var memoryStream = new MemoryStream(); -#if NETFRAMEWORK - using (var gzipStream = new Vendors.ICSharpCode.SharpZipLib.GZip.GZipOutputStream(memoryStream)) -#else - using (var gzipStream = new GZipStream(memoryStream, CompressionMode.Compress)) -#endif + var compressedSymbols = await CompressDataAsync(symbols).ConfigureAwait(false); + if (compressedSymbols == null) { - await gzipStream.WriteAsync(symbols.Array, 0, symbols.Array.Length).ConfigureAwait(false); - await gzipStream.FlushAsync().ConfigureAwait(false); + return false; } - symbolsItem = new MultipartFormItem("file", MimeTypes.Gzip, "file.gz", new ArraySegment(memoryStream.ToArray())); + symbolsItem = new MultipartFormItem("file", MimeTypes.Gzip, "file.gz", compressedSymbols.Value); } var items = new[] { symbolsItem, new MultipartFormItem("event", MimeTypes.Json, "event.json", _eventMetadata) }; @@ -130,5 +125,42 @@ public override async Task SendBatchAsync(ArraySegment symbols) return false; } + + internal async Task?> CompressDataAsync(ArraySegment data) + { + using var memoryStream = new MemoryStream(); + +#if NETFRAMEWORK + using (var gzipStream = new Vendors.ICSharpCode.SharpZipLib.GZip.GZipOutputStream(memoryStream)) +#else + using (var gzipStream = new GZipStream(memoryStream, CompressionMode.Compress)) +#endif + { + await gzipStream.WriteAsync(data.Array!, data.Offset, data.Count).ConfigureAwait(false); + await gzipStream.FlushAsync().ConfigureAwait(false); + } + + var compressedData = memoryStream.ToArray(); + + // see here about the following validation: https://forensics.wiki/gzip/ + // minimum size for header + footer + if (compressedData.Length < 18) + { + Log.Error("Compression produced invalid data: size {Size} bytes is below minimum valid GZip size", property: compressedData.Length); + return null; + } + + // header magic numbers + if (compressedData[0] != 0x1F || compressedData[1] != 0x8B) + { + Log.Error( + "Compression produced invalid data: invalid GZip header {Header}", + BitConverter.ToString(System.Linq.Enumerable.ToArray(System.Linq.Enumerable.Take(compressedData, 2)))); + + return null; + } + + return new ArraySegment(compressedData); + } } } From 1aff83b07d39000504d6078a92cb4a98c29b8d61 Mon Sep 17 00:00:00 2001 From: Lucas Pimentel Date: Thu, 6 Mar 2025 20:09:10 -0500 Subject: [PATCH 6/7] [tracing] add null checks when iterating headers in propagators (#6460) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary of changes Add null checks in `ParseUtility` to avoid a `NullReferenceException`. ## Reason for change If a user passes a delegate to `SpanContextExtractor` which returns `null` enumerables, the methods in `ParseUtility` will throw a `NullReferenceException` when they try to iterate over the values with `foreach`. For example, `Dictionary.GetValueOrDefault(TKey)` can return null if `TValue` is nullable: ```csharp var dict = new Dictionary>(); SpanContextExtractor.Extract(headers, (dict, key) => dict.GetValueOrDefault(key)) ``` I noticed this while using manual instrumentation for system tests. The workaround I used at the time was to add a null-coalescing operator: ```csharp SpanContextExtractor.Extract(headers, (dict, key) => dict.GetValueOrDefault(key) ?? []) ``` ## Implementation details Add nullability annotations and the missing check for `null`. ## Test coverage Expanded existing tests: - add test with null enumerable (confirmed that test failed before the fix and passed after) - unrelated to this change: add test with multiple values, ensure we use the first valid value ## Other details n/a --- .../Datadog.Trace/Propagators/ParseUtility.cs | 33 ++++- .../Propagators/ParseUtilityTests.cs | 120 ++++++++++-------- 2 files changed, 91 insertions(+), 62 deletions(-) diff --git a/tracer/src/Datadog.Trace/Propagators/ParseUtility.cs b/tracer/src/Datadog.Trace/Propagators/ParseUtility.cs index da74da6a21ef..01c61935016f 100644 --- a/tracer/src/Datadog.Trace/Propagators/ParseUtility.cs +++ b/tracer/src/Datadog.Trace/Propagators/ParseUtility.cs @@ -5,13 +5,10 @@ #nullable enable -using System; using System.Collections.Generic; -using System.Diagnostics.Contracts; using System.Globalization; using Datadog.Trace.Headers; using Datadog.Trace.Logging; -using Datadog.Trace.Util; namespace Datadog.Trace.Propagators { @@ -67,9 +64,15 @@ internal class ParseUtility return null; // IEnumerable version (different method to avoid try/finally in the caller) - static bool TryParse(IEnumerable headerValues, ref bool hasValue, out ulong result) + static bool TryParse(IEnumerable? headerValues, ref bool hasValue, out ulong result) { result = 0; + + if (headerValues is null) + { + return false; + } + foreach (string? headerValue in headerValues) { if (ulong.TryParse(headerValue, NumberStyles.Integer, CultureInfo.InvariantCulture, out result)) @@ -133,9 +136,15 @@ static bool TryParse(IEnumerable headerValues, ref bool hasValue, out u return null; // IEnumerable version (different method to avoid try/finally in the caller) - static bool TryParse(IEnumerable headerValues, ref bool hasValue, out int result) + static bool TryParse(IEnumerable? headerValues, ref bool hasValue, out int result) { result = 0; + + if (headerValues is null) + { + return false; + } + foreach (string? headerValue in headerValues) { if (int.TryParse(headerValue, out result)) @@ -175,8 +184,13 @@ static bool TryParse(IEnumerable headerValues, ref bool hasValue, out i return ParseStringIEnumerable(headerValues); // IEnumerable version (different method to avoid try/finally in the caller) - static string? ParseStringIEnumerable(IEnumerable headerValues) + static string? ParseStringIEnumerable(IEnumerable? headerValues) { + if (headerValues is null) + { + return null; + } + foreach (string? headerValue in headerValues) { if (!string.IsNullOrEmpty(headerValue)) @@ -211,8 +225,13 @@ static bool TryParse(IEnumerable headerValues, ref bool hasValue, out i return ParseStringIEnumerable(headerValues); // IEnumerable version (different method to avoid try/finally in the caller) - static string? ParseStringIEnumerable(IEnumerable headerValues) + static string? ParseStringIEnumerable(IEnumerable? headerValues) { + if (headerValues is null) + { + return null; + } + foreach (string? headerValue in headerValues) { if (!string.IsNullOrEmpty(headerValue)) diff --git a/tracer/test/Datadog.Trace.Tests/Propagators/ParseUtilityTests.cs b/tracer/test/Datadog.Trace.Tests/Propagators/ParseUtilityTests.cs index be7ba09b5766..e4dac05ee80c 100644 --- a/tracer/test/Datadog.Trace.Tests/Propagators/ParseUtilityTests.cs +++ b/tracer/test/Datadog.Trace.Tests/Propagators/ParseUtilityTests.cs @@ -14,86 +14,96 @@ namespace Datadog.Trace.Tests.Propagators { public class ParseUtilityTests { + public static TheoryData, ulong?> UInt64 + => new() + { + { new[] { "42" }, 42 }, + { new[] { "4x" }, null }, + { new[] { "4x", "42" }, 42 }, // return first valid value + { new[] { string.Empty }, null }, + { new[] { (string)null }, null }, + { new List { "42" }, 42 }, + { new List { "4x" }, null }, + { new List { string.Empty }, null }, + { new List { null }, null }, + { null, null }, // null collection returns null + }; + + public static TheoryData, int?> Int32 + => new() + { + { new[] { "42" }, 42 }, + { new[] { "4x" }, null }, + { new[] { "4x", "42" }, 42 }, // return first valid value + { new[] { string.Empty }, null }, + { new[] { (string)null }, null }, + { new List { "42" }, 42 }, + { new List { "4x" }, null }, + { new List { string.Empty }, null }, + { new List { null }, null }, + { null, null }, // null collection returns null + }; + + public static TheoryData, string> String + => new() + { + { new[] { "42" }, "42" }, + { new[] { "4x" }, "4x" }, + { new[] { "4x", "42" }, "4x" }, // return first valid value + { new[] { string.Empty }, null }, // null or empty returns null + { new[] { (string)null }, null }, // null or empty returns null + { new List { "42" }, "42" }, + { new List { "4x" }, "4x" }, + { new List { string.Empty }, null }, // null or empty returns null + { new List { null }, null }, // null or empty returns null + { null, null }, // null collection returns null + }; + [Theory] - [InlineData("42", 42UL)] - [InlineData("4x", null)] - public void ParseUInt64Test(string actual, object expected) + [MemberData(nameof(UInt64))] + public void ParseUInt64Test(IEnumerable values, ulong? expected) { - var actualResult = ParseUtility.ParseUInt64( - (object)null, - new FuncGetter((carrier, name) => new[] { actual }), - string.Empty); - - actualResult.Should().Be((ulong?)expected); - - actualResult = ParseUtility.ParseUInt64( + var result = ParseUtility.ParseUInt64( (object)null, - new FuncGetter((carrier, name) => new List { actual }), + new FuncGetter((_, _) => values), string.Empty); - actualResult.Should().Be((ulong?)expected); + result.Should().Be(expected); } [Theory] - [InlineData("42", 42)] - [InlineData("4x", null)] - public void ParseInt32Test(string actual, object expected) + [MemberData(nameof(Int32))] + public void ParseInt32Test(IEnumerable values, int? expected) { - var actualResult = ParseUtility.ParseInt32( + var result = ParseUtility.ParseInt32( (object)null, - new FuncGetter((carrier, name) => new[] { actual }), + new FuncGetter((_, _) => values), string.Empty); - actualResult.Should().Be((int?)expected); - - actualResult = ParseUtility.ParseInt32( - (object)null, - new FuncGetter((carrier, name) => new List { actual }), - string.Empty); - - actualResult.Should().Be((int?)expected); + result.Should().Be(expected); } [Theory] - [InlineData("42", "42")] - [InlineData("4x", "4x")] - [InlineData("", null)] - [InlineData(null, null)] - public void ParseString(string actual, string expected) + [MemberData(nameof(String))] + public void ParseStringTest(IEnumerable values, string expected) { - var actualResult = ParseUtility.ParseString( + var result = ParseUtility.ParseString( (object)null, - new FuncGetter((carrier, name) => new[] { actual }), + new FuncGetter((_, _) => values), string.Empty); - actualResult.Should().Be(expected); - - actualResult = ParseUtility.ParseString( - (object)null, - new FuncGetter((carrier, name) => new List { actual }), - string.Empty); - - actualResult.Should().Be(expected); + result.Should().Be(expected); } [Theory] - [InlineData("42", "42")] - [InlineData("4x", "4x")] - [InlineData("", null)] - [InlineData(null, null)] - public void ParseStringWithHeaders(string actual, string expected) + [MemberData(nameof(String))] + public void ParseStringWithHeaders(IEnumerable values, string expected) { - var actualResult = ParseUtility.ParseString( - new HeaderStruct(() => new[] { actual }), - string.Empty); - - actualResult.Should().Be(expected); - - actualResult = ParseUtility.ParseString( - new HeaderStruct(() => new List { actual }), + var result = ParseUtility.ParseString( + new HeaderStruct(() => values), string.Empty); - actualResult.Should().Be(expected); + result.Should().Be(expected); } private readonly struct FuncGetter : ICarrierGetter From 999a3aace6c83e4ca719db3703ef8cf11d4c9cf3 Mon Sep 17 00:00:00 2001 From: NachoEchevarria <53266532+NachoEchevarria@users.noreply.github.com> Date: Fri, 7 Mar 2025 12:39:36 +0100 Subject: [PATCH 7/7] [ASM] Add new RASP telemetry tags (#6685) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary of changes This PR adds the new required tags for RASP's telemetry metrics. It adds the tags event_rules_version and block to appsec.rasp.rule.match and event_rules_version to appsec.rasp.rule.eval and appsec.rasp.timeout These rules are defined in [this RFC](https://docs.google.com/document/d/1D4hkC0jwwUyeo0hEQgyKP54kM1LZU98GL8MaP60tQrA/edit?tab=t.0). The common_metrics file has been updated in this PR: https://github.com/DataDog/dd-go/pull/171115 ## Reason for change ## Implementation details ## Test coverage ## Other details --- .../Coordinator/SecurityCoordinator.Core.cs | 3 +- .../SecurityCoordinator.Framework.cs | 3 +- .../Datadog.Trace/AppSec/Rasp/RaspModule.cs | 88 ++++++++++-- ...RaspRuleTypeExtensions_EnumExtensions.g.cs | 20 +-- ...uleTypeMatchExtensions_EnumExtensions.g.cs | 133 ++++++++++++++++++ ...bilityMetricsTelemetryCollector_Count.g.cs | 2 +- .../IMetricsTelemetryCollector_Count.g.cs | 2 +- .../MetricsTelemetryCollector_Count.g.cs | 78 +++++----- .../NullMetricsTelemetryCollector_Count.g.cs | 2 +- ...RaspRuleTypeExtensions_EnumExtensions.g.cs | 20 +-- ...uleTypeMatchExtensions_EnumExtensions.g.cs | 133 ++++++++++++++++++ ...bilityMetricsTelemetryCollector_Count.g.cs | 2 +- .../IMetricsTelemetryCollector_Count.g.cs | 2 +- .../MetricsTelemetryCollector_Count.g.cs | 78 +++++----- .../NullMetricsTelemetryCollector_Count.g.cs | 2 +- ...RaspRuleTypeExtensions_EnumExtensions.g.cs | 20 +-- ...uleTypeMatchExtensions_EnumExtensions.g.cs | 133 ++++++++++++++++++ ...bilityMetricsTelemetryCollector_Count.g.cs | 2 +- .../IMetricsTelemetryCollector_Count.g.cs | 2 +- .../MetricsTelemetryCollector_Count.g.cs | 78 +++++----- .../NullMetricsTelemetryCollector_Count.g.cs | 2 +- ...RaspRuleTypeExtensions_EnumExtensions.g.cs | 20 +-- ...uleTypeMatchExtensions_EnumExtensions.g.cs | 133 ++++++++++++++++++ ...bilityMetricsTelemetryCollector_Count.g.cs | 2 +- .../IMetricsTelemetryCollector_Count.g.cs | 2 +- .../MetricsTelemetryCollector_Count.g.cs | 78 +++++----- .../NullMetricsTelemetryCollector_Count.g.cs | 2 +- .../Datadog.Trace/Telemetry/Metrics/Count.cs | 2 +- .../Telemetry/Metrics/MetricTags.cs | 30 +++- .../SecurityCoordinatorTests.cs | 2 +- .../MetricsTelemetryCollectorTests.cs | 8 +- .../Telemetry/Metrics/common_metrics.json | 6 +- 32 files changed, 878 insertions(+), 212 deletions(-) create mode 100644 tracer/src/Datadog.Trace/Generated/net461/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/RaspRuleTypeMatchExtensions_EnumExtensions.g.cs create mode 100644 tracer/src/Datadog.Trace/Generated/net6.0/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/RaspRuleTypeMatchExtensions_EnumExtensions.g.cs create mode 100644 tracer/src/Datadog.Trace/Generated/netcoreapp3.1/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/RaspRuleTypeMatchExtensions_EnumExtensions.g.cs create mode 100644 tracer/src/Datadog.Trace/Generated/netstandard2.0/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/RaspRuleTypeMatchExtensions_EnumExtensions.g.cs diff --git a/tracer/src/Datadog.Trace/AppSec/Coordinator/SecurityCoordinator.Core.cs b/tracer/src/Datadog.Trace/AppSec/Coordinator/SecurityCoordinator.Core.cs index 8383184bfa0f..59d83a87b2dc 100644 --- a/tracer/src/Datadog.Trace/AppSec/Coordinator/SecurityCoordinator.Core.cs +++ b/tracer/src/Datadog.Trace/AppSec/Coordinator/SecurityCoordinator.Core.cs @@ -97,12 +97,13 @@ internal void BlockAndReport(IResult? result) } } - internal void ReportAndBlock(IResult? result) + internal void ReportAndBlock(IResult? result, Action telemetrySucessReport) { if (result is not null) { Reporter.TryReport(result, result.ShouldBlock); + telemetrySucessReport.Invoke(); if (result.ShouldBlock) { throw new BlockException(result, result.RedirectInfo ?? result.BlockInfo!, true); diff --git a/tracer/src/Datadog.Trace/AppSec/Coordinator/SecurityCoordinator.Framework.cs b/tracer/src/Datadog.Trace/AppSec/Coordinator/SecurityCoordinator.Framework.cs index 89b1b20d681d..b47d5f21d99d 100644 --- a/tracer/src/Datadog.Trace/AppSec/Coordinator/SecurityCoordinator.Framework.cs +++ b/tracer/src/Datadog.Trace/AppSec/Coordinator/SecurityCoordinator.Framework.cs @@ -313,12 +313,13 @@ internal void BlockAndReport(IResult? result) reporting(null, result.ShouldBlock); } - internal void ReportAndBlock(IResult? result) + internal void ReportAndBlock(IResult? result, Action telemetrySucessReport) { if (result is not null) { var reporting = Reporter.MakeReportingFunction(result); reporting(null, result.ShouldBlock); + telemetrySucessReport.Invoke(); if (result.ShouldBlock) { diff --git a/tracer/src/Datadog.Trace/AppSec/Rasp/RaspModule.cs b/tracer/src/Datadog.Trace/AppSec/Rasp/RaspModule.cs index 3055687c4688..8d7ef08e19e0 100644 --- a/tracer/src/Datadog.Trace/AppSec/Rasp/RaspModule.cs +++ b/tracer/src/Datadog.Trace/AppSec/Rasp/RaspModule.cs @@ -23,6 +23,13 @@ internal static class RaspModule private static readonly IDatadogLogger Log = DatadogLogging.GetLoggerFor(typeof(RaspModule)); private static bool _nullContextReported = false; + internal enum BlockType + { + Irrelevant = 0, + Success = 1, + Failure = 2 + } + private static RaspRuleType? TryGetAddressRuleType(string address) => address switch { @@ -34,6 +41,47 @@ internal static class RaspModule _ => null, }; + private static RaspRuleTypeMatch? TryGetAddressRuleTypeMatch(string address, BlockType blockType) + => address switch + { + AddressesConstants.FileAccess => blockType switch + { + BlockType.Success => RaspRuleTypeMatch.LfiSuccess, + BlockType.Failure => RaspRuleTypeMatch.LfiFailure, + BlockType.Irrelevant => RaspRuleTypeMatch.LfiIrrelevant, + _ => null, + }, + AddressesConstants.UrlAccess => blockType switch + { + BlockType.Success => RaspRuleTypeMatch.SsrfSuccess, + BlockType.Failure => RaspRuleTypeMatch.SsrfFailure, + BlockType.Irrelevant => RaspRuleTypeMatch.SsrfIrrelevant, + _ => null, + }, + AddressesConstants.DBStatement => blockType switch + { + BlockType.Success => RaspRuleTypeMatch.SQlISuccess, + BlockType.Failure => RaspRuleTypeMatch.SQlIFailure, + BlockType.Irrelevant => RaspRuleTypeMatch.SQlIIrrelevant, + _ => null, + }, + AddressesConstants.ShellInjection => blockType switch + { + BlockType.Success => RaspRuleTypeMatch.CommandInjectionShellSuccess, + BlockType.Failure => RaspRuleTypeMatch.CommandInjectionShellFailure, + BlockType.Irrelevant => RaspRuleTypeMatch.CommandInjectionShellIrrelevant, + _ => null, + }, + AddressesConstants.CommandInjection => blockType switch + { + BlockType.Success => RaspRuleTypeMatch.CommandInjectionExecSuccess, + BlockType.Failure => RaspRuleTypeMatch.CommandInjectionExecFailure, + BlockType.Irrelevant => RaspRuleTypeMatch.CommandInjectionExecIrrelevant, + _ => null, + }, + _ => null, + }; + internal static void OnLfi(string file) { CheckVulnerability(new Dictionary { [AddressesConstants.FileAccess] = file }, AddressesConstants.FileAccess); @@ -84,7 +132,7 @@ private static void CheckVulnerability(Dictionary arguments, str RunWafRasp(arguments, rootSpan, address); } - private static void RecordRaspTelemetry(string address, bool isMatch, bool timeOut) + private static void RecordRaspTelemetry(string address, bool isMatch, bool timeOut, BlockType matchType) { var ruleType = TryGetAddressRuleType(address); @@ -98,7 +146,15 @@ private static void RecordRaspTelemetry(string address, bool isMatch, bool timeO if (isMatch) { - TelemetryFactory.Metrics.RecordCountRaspRuleMatch(ruleType.Value); + var ruleTypeMatch = TryGetAddressRuleTypeMatch(address, matchType); + + if (ruleTypeMatch is null) + { + Log.Warning("RASP: Rule match type not found for address {Address} {MatchType}", address, matchType); + return; + } + + TelemetryFactory.Metrics.RecordCountRaspRuleMatch(ruleTypeMatch.Value); } if (timeOut) @@ -129,11 +185,6 @@ private static void RunWafRasp(Dictionary arguments, Span rootSp var result = securityCoordinator.Value.RunWaf(arguments, runWithEphemeral: true, isRasp: true); - if (result is not null) - { - RecordRaspTelemetry(address, result.ReturnCode == Waf.WafReturnCode.Match, result.Timeout); - } - try { if (result?.SendStackInfo is not null && Security.Instance.Settings.StackTraceEnabled) @@ -158,9 +209,26 @@ private static void RunWafRasp(Dictionary arguments, Span rootSp AddSpanId(result); - // we want to report first because if we are inside a try{} catch(Exception ex){} block, we will not report - // the blockings, so we report first and then block - securityCoordinator.Value.ReportAndBlock(result); + if (result is not null) + { + // we want to report first because if we are inside a try{} catch(Exception ex){} block, we will not report + // the blockings, so we report first and then block + try + { + var matchSuccesCode = result.ReturnCode == WafReturnCode.Match && result.ShouldBlock ? + BlockType.Success : BlockType.Irrelevant; + + securityCoordinator.Value.ReportAndBlock(result, () => RecordRaspTelemetry(address, result.ReturnCode == Waf.WafReturnCode.Match, result.Timeout, matchSuccesCode)); + } + catch (Exception ex) when (ex is not BlockException) + { + var matchFailureCode = result.ReturnCode == WafReturnCode.Match && result.ShouldBlock ? + BlockType.Failure : BlockType.Irrelevant; + + RecordRaspTelemetry(address, result.ReturnCode == Waf.WafReturnCode.Match, result.Timeout, matchFailureCode); + Log.Error(ex, "RASP: Error while reporting and blocking."); + } + } } private static void AddSpanId(IResult? result) diff --git a/tracer/src/Datadog.Trace/Generated/net461/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/RaspRuleTypeExtensions_EnumExtensions.g.cs b/tracer/src/Datadog.Trace/Generated/net461/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/RaspRuleTypeExtensions_EnumExtensions.g.cs index 4fdc8921fb58..923039e18ff0 100644 --- a/tracer/src/Datadog.Trace/Generated/net461/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/RaspRuleTypeExtensions_EnumExtensions.g.cs +++ b/tracer/src/Datadog.Trace/Generated/net461/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/RaspRuleTypeExtensions_EnumExtensions.g.cs @@ -30,11 +30,11 @@ internal static partial class RaspRuleTypeExtensions public static string ToStringFast(this Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType value) => value switch { - Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType.Lfi => "waf_version;rule_type:lfi", - Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType.Ssrf => "waf_version;rule_type:ssrf", - Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType.SQlI => "waf_version;rule_type:sql_injection", - Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType.CommandInjectionShell => "waf_version;rule_type:command_injection;rule_variant:shell", - Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType.CommandInjectionExec => "waf_version;rule_type:command_injection;rule_variant:exec", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType.Lfi => "waf_version;event_rules_version;rule_type:lfi", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType.Ssrf => "waf_version;event_rules_version;rule_type:ssrf", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType.SQlI => "waf_version;event_rules_version;rule_type:sql_injection", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType.CommandInjectionShell => "waf_version;event_rules_version;rule_type:command_injection;rule_variant:shell", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType.CommandInjectionExec => "waf_version;event_rules_version;rule_type:command_injection;rule_variant:exec", _ => value.ToString(), }; @@ -84,10 +84,10 @@ public static string[] GetNames() public static string[] GetDescriptions() => new [] { - "waf_version;rule_type:lfi", - "waf_version;rule_type:ssrf", - "waf_version;rule_type:sql_injection", - "waf_version;rule_type:command_injection;rule_variant:shell", - "waf_version;rule_type:command_injection;rule_variant:exec", + "waf_version;event_rules_version;rule_type:lfi", + "waf_version;event_rules_version;rule_type:ssrf", + "waf_version;event_rules_version;rule_type:sql_injection", + "waf_version;event_rules_version;rule_type:command_injection;rule_variant:shell", + "waf_version;event_rules_version;rule_type:command_injection;rule_variant:exec", }; } \ No newline at end of file diff --git a/tracer/src/Datadog.Trace/Generated/net461/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/RaspRuleTypeMatchExtensions_EnumExtensions.g.cs b/tracer/src/Datadog.Trace/Generated/net461/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/RaspRuleTypeMatchExtensions_EnumExtensions.g.cs new file mode 100644 index 000000000000..0fdc8d77792a --- /dev/null +++ b/tracer/src/Datadog.Trace/Generated/net461/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/RaspRuleTypeMatchExtensions_EnumExtensions.g.cs @@ -0,0 +1,133 @@ +// +// 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. +// +// + +#nullable enable + +namespace Datadog.Trace.Telemetry.Metrics; + +/// +/// Extension methods for +/// +internal static partial class RaspRuleTypeMatchExtensions +{ + /// + /// The number of members in the enum. + /// This is a non-distinct count of defined names. + /// + public const int Length = 15; + + /// + /// Returns the string representation of the value. + /// If the attribute is decorated with a [Description] attribute, then + /// uses the provided value. Otherwise uses the name of the member, equivalent to + /// calling ToString() on . + /// + /// The value to retrieve the string value for + /// The string representation of the value + public static string ToStringFast(this Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch value) + => value switch + { + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.LfiSuccess => "waf_version;event_rules_version;block:success;rule_type:lfi", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SsrfSuccess => "waf_version;event_rules_version;block:success;rule_type:ssrf", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SQlISuccess => "waf_version;event_rules_version;block:success;rule_type:sql_injection", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionShellSuccess => "waf_version;event_rules_version;block:success;rule_type:command_injection;rule_variant:shell", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionExecSuccess => "waf_version;event_rules_version;block:success;rule_type:command_injection;rule_variant:exec", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.LfiFailure => "waf_version;event_rules_version;block:failure;rule_type:lfi", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SsrfFailure => "waf_version;event_rules_version;block:failure;rule_type:ssrf", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SQlIFailure => "waf_version;event_rules_version;block:failure;rule_type:sql_injection", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionShellFailure => "waf_version;event_rules_version;block:failure;rule_type:command_injection;rule_variant:shell", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionExecFailure => "waf_version;event_rules_version;block:failure;rule_type:command_injection;rule_variant:exec", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.LfiIrrelevant => "waf_version;event_rules_version;block:irrelevant;rule_type:lfi", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SsrfIrrelevant => "waf_version;event_rules_version;block:irrelevant;rule_type:ssrf", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SQlIIrrelevant => "waf_version;event_rules_version;block:irrelevant;rule_type:sql_injection", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionShellIrrelevant => "waf_version;event_rules_version;block:irrelevant;rule_type:command_injection;rule_variant:shell", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionExecIrrelevant => "waf_version;event_rules_version;block:irrelevant;rule_type:command_injection;rule_variant:exec", + _ => value.ToString(), + }; + + /// + /// Retrieves an array of the values of the members defined in + /// . + /// Note that this returns a new array with every invocation, so + /// should be cached if appropriate. + /// + /// An array of the values defined in + public static Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch[] GetValues() + => new [] + { + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.LfiSuccess, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SsrfSuccess, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SQlISuccess, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionShellSuccess, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionExecSuccess, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.LfiFailure, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SsrfFailure, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SQlIFailure, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionShellFailure, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionExecFailure, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.LfiIrrelevant, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SsrfIrrelevant, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SQlIIrrelevant, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionShellIrrelevant, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionExecIrrelevant, + }; + + /// + /// Retrieves an array of the names of the members defined in + /// . + /// Note that this returns a new array with every invocation, so + /// should be cached if appropriate. + /// Ignores [Description] definitions. + /// + /// An array of the names of the members defined in + public static string[] GetNames() + => new [] + { + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.LfiSuccess), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SsrfSuccess), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SQlISuccess), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionShellSuccess), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionExecSuccess), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.LfiFailure), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SsrfFailure), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SQlIFailure), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionShellFailure), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionExecFailure), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.LfiIrrelevant), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SsrfIrrelevant), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SQlIIrrelevant), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionShellIrrelevant), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionExecIrrelevant), + }; + + /// + /// Retrieves an array of the names of the members defined in + /// . + /// Note that this returns a new array with every invocation, so + /// should be cached if appropriate. + /// Uses [Description] definition if available, otherwise uses the name of the property + /// + /// An array of the names of the members defined in + public static string[] GetDescriptions() + => new [] + { + "waf_version;event_rules_version;block:success;rule_type:lfi", + "waf_version;event_rules_version;block:success;rule_type:ssrf", + "waf_version;event_rules_version;block:success;rule_type:sql_injection", + "waf_version;event_rules_version;block:success;rule_type:command_injection;rule_variant:shell", + "waf_version;event_rules_version;block:success;rule_type:command_injection;rule_variant:exec", + "waf_version;event_rules_version;block:failure;rule_type:lfi", + "waf_version;event_rules_version;block:failure;rule_type:ssrf", + "waf_version;event_rules_version;block:failure;rule_type:sql_injection", + "waf_version;event_rules_version;block:failure;rule_type:command_injection;rule_variant:shell", + "waf_version;event_rules_version;block:failure;rule_type:command_injection;rule_variant:exec", + "waf_version;event_rules_version;block:irrelevant;rule_type:lfi", + "waf_version;event_rules_version;block:irrelevant;rule_type:ssrf", + "waf_version;event_rules_version;block:irrelevant;rule_type:sql_injection", + "waf_version;event_rules_version;block:irrelevant;rule_type:command_injection;rule_variant:shell", + "waf_version;event_rules_version;block:irrelevant;rule_type:command_injection;rule_variant:exec", + }; +} \ No newline at end of file diff --git a/tracer/src/Datadog.Trace/Generated/net461/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/CiVisibilityMetricsTelemetryCollector_Count.g.cs b/tracer/src/Datadog.Trace/Generated/net461/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/CiVisibilityMetricsTelemetryCollector_Count.g.cs index 363a5e43830a..7500ae6cf042 100644 --- a/tracer/src/Datadog.Trace/Generated/net461/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/CiVisibilityMetricsTelemetryCollector_Count.g.cs +++ b/tracer/src/Datadog.Trace/Generated/net461/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/CiVisibilityMetricsTelemetryCollector_Count.g.cs @@ -156,7 +156,7 @@ public void RecordCountRaspRuleEval(Datadog.Trace.Telemetry.Metrics.MetricTags.R { } - public void RecordCountRaspRuleMatch(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType tag, int increment = 1) + public void RecordCountRaspRuleMatch(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch tag, int increment = 1) { } diff --git a/tracer/src/Datadog.Trace/Generated/net461/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/IMetricsTelemetryCollector_Count.g.cs b/tracer/src/Datadog.Trace/Generated/net461/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/IMetricsTelemetryCollector_Count.g.cs index 1f009e0918d2..6217252b104c 100644 --- a/tracer/src/Datadog.Trace/Generated/net461/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/IMetricsTelemetryCollector_Count.g.cs +++ b/tracer/src/Datadog.Trace/Generated/net461/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/IMetricsTelemetryCollector_Count.g.cs @@ -81,7 +81,7 @@ internal partial interface IMetricsTelemetryCollector public void RecordCountRaspRuleEval(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType tag, int increment = 1); - public void RecordCountRaspRuleMatch(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType tag, int increment = 1); + public void RecordCountRaspRuleMatch(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch tag, int increment = 1); public void RecordCountRaspTimeout(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType tag, int increment = 1); diff --git a/tracer/src/Datadog.Trace/Generated/net461/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/MetricsTelemetryCollector_Count.g.cs b/tracer/src/Datadog.Trace/Generated/net461/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/MetricsTelemetryCollector_Count.g.cs index 9da1f3508715..37ecde449b32 100644 --- a/tracer/src/Datadog.Trace/Generated/net461/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/MetricsTelemetryCollector_Count.g.cs +++ b/tracer/src/Datadog.Trace/Generated/net461/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/MetricsTelemetryCollector_Count.g.cs @@ -11,7 +11,7 @@ namespace Datadog.Trace.Telemetry; internal partial class MetricsTelemetryCollector { - private const int CountLength = 613; + private const int CountLength = 623; /// /// Creates the buffer for the values. @@ -575,34 +575,44 @@ private static AggregatedMetric[] GetCountBuffer() new(new[] { "truncation_reason:list_or_map_too_large" }), new(new[] { "truncation_reason:object_too_deep" }), // rasp.rule.eval, index = 520 - new(new[] { "waf_version", "rule_type:lfi" }), - new(new[] { "waf_version", "rule_type:ssrf" }), - new(new[] { "waf_version", "rule_type:sql_injection" }), - new(new[] { "waf_version", "rule_type:command_injection", "rule_variant:shell" }), - new(new[] { "waf_version", "rule_type:command_injection", "rule_variant:exec" }), + new(new[] { "waf_version", "event_rules_version", "rule_type:lfi" }), + new(new[] { "waf_version", "event_rules_version", "rule_type:ssrf" }), + new(new[] { "waf_version", "event_rules_version", "rule_type:sql_injection" }), + new(new[] { "waf_version", "event_rules_version", "rule_type:command_injection", "rule_variant:shell" }), + new(new[] { "waf_version", "event_rules_version", "rule_type:command_injection", "rule_variant:exec" }), // rasp.rule.match, index = 525 - new(new[] { "waf_version", "rule_type:lfi" }), - new(new[] { "waf_version", "rule_type:ssrf" }), - new(new[] { "waf_version", "rule_type:sql_injection" }), - new(new[] { "waf_version", "rule_type:command_injection", "rule_variant:shell" }), - new(new[] { "waf_version", "rule_type:command_injection", "rule_variant:exec" }), - // rasp.timeout, index = 530 - new(new[] { "waf_version", "rule_type:lfi" }), - new(new[] { "waf_version", "rule_type:ssrf" }), - new(new[] { "waf_version", "rule_type:sql_injection" }), - new(new[] { "waf_version", "rule_type:command_injection", "rule_variant:shell" }), - new(new[] { "waf_version", "rule_type:command_injection", "rule_variant:exec" }), - // instrum.user_auth.missing_user_id, index = 535 + new(new[] { "waf_version", "event_rules_version", "block:success", "rule_type:lfi" }), + new(new[] { "waf_version", "event_rules_version", "block:success", "rule_type:ssrf" }), + new(new[] { "waf_version", "event_rules_version", "block:success", "rule_type:sql_injection" }), + new(new[] { "waf_version", "event_rules_version", "block:success", "rule_type:command_injection", "rule_variant:shell" }), + new(new[] { "waf_version", "event_rules_version", "block:success", "rule_type:command_injection", "rule_variant:exec" }), + new(new[] { "waf_version", "event_rules_version", "block:failure", "rule_type:lfi" }), + new(new[] { "waf_version", "event_rules_version", "block:failure", "rule_type:ssrf" }), + new(new[] { "waf_version", "event_rules_version", "block:failure", "rule_type:sql_injection" }), + new(new[] { "waf_version", "event_rules_version", "block:failure", "rule_type:command_injection", "rule_variant:shell" }), + new(new[] { "waf_version", "event_rules_version", "block:failure", "rule_type:command_injection", "rule_variant:exec" }), + new(new[] { "waf_version", "event_rules_version", "block:irrelevant", "rule_type:lfi" }), + new(new[] { "waf_version", "event_rules_version", "block:irrelevant", "rule_type:ssrf" }), + new(new[] { "waf_version", "event_rules_version", "block:irrelevant", "rule_type:sql_injection" }), + new(new[] { "waf_version", "event_rules_version", "block:irrelevant", "rule_type:command_injection", "rule_variant:shell" }), + new(new[] { "waf_version", "event_rules_version", "block:irrelevant", "rule_type:command_injection", "rule_variant:exec" }), + // rasp.timeout, index = 540 + new(new[] { "waf_version", "event_rules_version", "rule_type:lfi" }), + new(new[] { "waf_version", "event_rules_version", "rule_type:ssrf" }), + new(new[] { "waf_version", "event_rules_version", "rule_type:sql_injection" }), + new(new[] { "waf_version", "event_rules_version", "rule_type:command_injection", "rule_variant:shell" }), + new(new[] { "waf_version", "event_rules_version", "rule_type:command_injection", "rule_variant:exec" }), + // instrum.user_auth.missing_user_id, index = 545 new(new[] { "framework:aspnetcore_identity", "event_type:login_success" }), new(new[] { "framework:aspnetcore_identity", "event_type:login_failure" }), new(new[] { "framework:aspnetcore_identity", "event_type:signup" }), new(new[] { "framework:unknown", "event_type:signup" }), - // instrum.user_auth.missing_user_login, index = 539 + // instrum.user_auth.missing_user_login, index = 549 new(new[] { "framework:aspnetcore_identity", "event_type:login_success" }), new(new[] { "framework:aspnetcore_identity", "event_type:login_failure" }), new(new[] { "framework:aspnetcore_identity", "event_type:signup" }), new(new[] { "framework:unknown", "event_type:signup" }), - // executed.source, index = 543 + // executed.source, index = 553 new(new[] { "source_type:http.request.body" }), new(new[] { "source_type:http.request.path" }), new(new[] { "source_type:http.request.parameter.name" }), @@ -617,9 +627,9 @@ private static AggregatedMetric[] GetCountBuffer() new(new[] { "source_type:http.request.uri" }), new(new[] { "source_type:grpc.request.body" }), new(new[] { "source_type:sql.row.value" }), - // executed.propagation, index = 557 + // executed.propagation, index = 567 new(null), - // executed.sink, index = 558 + // executed.sink, index = 568 new(new[] { "vulnerability_type:none" }), new(new[] { "vulnerability_type:weak_cipher" }), new(new[] { "vulnerability_type:weak_hash" }), @@ -647,9 +657,9 @@ private static AggregatedMetric[] GetCountBuffer() new(new[] { "vulnerability_type:directory_listing_leak" }), new(new[] { "vulnerability_type:session_timeout" }), new(new[] { "vulnerability_type:email_html_injection" }), - // request.tainted, index = 585 + // request.tainted, index = 595 new(null), - // suppressed.vulnerabilities, index = 586 + // suppressed.vulnerabilities, index = 596 new(new[] { "vulnerability_type:none" }), new(new[] { "vulnerability_type:weak_cipher" }), new(new[] { "vulnerability_type:weak_hash" }), @@ -685,7 +695,7 @@ private static AggregatedMetric[] GetCountBuffer() /// It is equal to the cardinality of the tag combinations (or 1 if there are no tags) /// private static int[] CountEntryCounts { get; } - = new int[]{ 4, 80, 1, 3, 4, 2, 2, 4, 1, 1, 1, 22, 3, 2, 5, 5, 2, 1, 22, 3, 90, 90, 2, 44, 6, 1, 1, 80, 1, 22, 3, 2, 2, 5, 3, 5, 5, 5, 4, 4, 14, 1, 27, 1, 27, }; + = new int[]{ 4, 80, 1, 3, 4, 2, 2, 4, 1, 1, 1, 22, 3, 2, 5, 5, 2, 1, 22, 3, 90, 90, 2, 44, 6, 1, 1, 80, 1, 22, 3, 2, 2, 5, 3, 5, 15, 5, 4, 4, 14, 1, 27, 1, 27, }; public void RecordCountLogCreated(Datadog.Trace.Telemetry.Metrics.MetricTags.LogLevel tag, int increment = 1) { @@ -895,7 +905,7 @@ public void RecordCountRaspRuleEval(Datadog.Trace.Telemetry.Metrics.MetricTags.R Interlocked.Add(ref _buffer.Count[index], increment); } - public void RecordCountRaspRuleMatch(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType tag, int increment = 1) + public void RecordCountRaspRuleMatch(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch tag, int increment = 1) { var index = 525 + (int)tag; Interlocked.Add(ref _buffer.Count[index], increment); @@ -903,47 +913,47 @@ public void RecordCountRaspRuleMatch(Datadog.Trace.Telemetry.Metrics.MetricTags. public void RecordCountRaspTimeout(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType tag, int increment = 1) { - var index = 530 + (int)tag; + var index = 540 + (int)tag; Interlocked.Add(ref _buffer.Count[index], increment); } public void RecordCountMissingUserId(Datadog.Trace.Telemetry.Metrics.MetricTags.AuthenticationFrameworkWithEventType tag, int increment = 1) { - var index = 535 + (int)tag; + var index = 545 + (int)tag; Interlocked.Add(ref _buffer.Count[index], increment); } public void RecordCountMissingUserLogin(Datadog.Trace.Telemetry.Metrics.MetricTags.AuthenticationFrameworkWithEventType tag, int increment = 1) { - var index = 539 + (int)tag; + var index = 549 + (int)tag; Interlocked.Add(ref _buffer.Count[index], increment); } public void RecordCountIastExecutedSources(Datadog.Trace.Telemetry.Metrics.MetricTags.IastSourceType tag, int increment = 1) { - var index = 543 + (int)tag; + var index = 553 + (int)tag; Interlocked.Add(ref _buffer.Count[index], increment); } public void RecordCountIastExecutedPropagations(int increment = 1) { - Interlocked.Add(ref _buffer.Count[557], increment); + Interlocked.Add(ref _buffer.Count[567], increment); } public void RecordCountIastExecutedSinks(Datadog.Trace.Telemetry.Metrics.MetricTags.IastVulnerabilityType tag, int increment = 1) { - var index = 558 + (int)tag; + var index = 568 + (int)tag; Interlocked.Add(ref _buffer.Count[index], increment); } public void RecordCountIastRequestTainted(int increment = 1) { - Interlocked.Add(ref _buffer.Count[585], increment); + Interlocked.Add(ref _buffer.Count[595], increment); } public void RecordCountIastSuppressedVulnerabilities(Datadog.Trace.Telemetry.Metrics.MetricTags.IastVulnerabilityType tag, int increment = 1) { - var index = 586 + (int)tag; + var index = 596 + (int)tag; Interlocked.Add(ref _buffer.Count[index], increment); } } \ No newline at end of file diff --git a/tracer/src/Datadog.Trace/Generated/net461/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/NullMetricsTelemetryCollector_Count.g.cs b/tracer/src/Datadog.Trace/Generated/net461/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/NullMetricsTelemetryCollector_Count.g.cs index eb750e63a8ad..9b6efbd64cec 100644 --- a/tracer/src/Datadog.Trace/Generated/net461/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/NullMetricsTelemetryCollector_Count.g.cs +++ b/tracer/src/Datadog.Trace/Generated/net461/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/NullMetricsTelemetryCollector_Count.g.cs @@ -156,7 +156,7 @@ public void RecordCountRaspRuleEval(Datadog.Trace.Telemetry.Metrics.MetricTags.R { } - public void RecordCountRaspRuleMatch(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType tag, int increment = 1) + public void RecordCountRaspRuleMatch(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch tag, int increment = 1) { } diff --git a/tracer/src/Datadog.Trace/Generated/net6.0/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/RaspRuleTypeExtensions_EnumExtensions.g.cs b/tracer/src/Datadog.Trace/Generated/net6.0/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/RaspRuleTypeExtensions_EnumExtensions.g.cs index 4fdc8921fb58..923039e18ff0 100644 --- a/tracer/src/Datadog.Trace/Generated/net6.0/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/RaspRuleTypeExtensions_EnumExtensions.g.cs +++ b/tracer/src/Datadog.Trace/Generated/net6.0/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/RaspRuleTypeExtensions_EnumExtensions.g.cs @@ -30,11 +30,11 @@ internal static partial class RaspRuleTypeExtensions public static string ToStringFast(this Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType value) => value switch { - Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType.Lfi => "waf_version;rule_type:lfi", - Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType.Ssrf => "waf_version;rule_type:ssrf", - Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType.SQlI => "waf_version;rule_type:sql_injection", - Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType.CommandInjectionShell => "waf_version;rule_type:command_injection;rule_variant:shell", - Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType.CommandInjectionExec => "waf_version;rule_type:command_injection;rule_variant:exec", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType.Lfi => "waf_version;event_rules_version;rule_type:lfi", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType.Ssrf => "waf_version;event_rules_version;rule_type:ssrf", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType.SQlI => "waf_version;event_rules_version;rule_type:sql_injection", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType.CommandInjectionShell => "waf_version;event_rules_version;rule_type:command_injection;rule_variant:shell", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType.CommandInjectionExec => "waf_version;event_rules_version;rule_type:command_injection;rule_variant:exec", _ => value.ToString(), }; @@ -84,10 +84,10 @@ public static string[] GetNames() public static string[] GetDescriptions() => new [] { - "waf_version;rule_type:lfi", - "waf_version;rule_type:ssrf", - "waf_version;rule_type:sql_injection", - "waf_version;rule_type:command_injection;rule_variant:shell", - "waf_version;rule_type:command_injection;rule_variant:exec", + "waf_version;event_rules_version;rule_type:lfi", + "waf_version;event_rules_version;rule_type:ssrf", + "waf_version;event_rules_version;rule_type:sql_injection", + "waf_version;event_rules_version;rule_type:command_injection;rule_variant:shell", + "waf_version;event_rules_version;rule_type:command_injection;rule_variant:exec", }; } \ No newline at end of file diff --git a/tracer/src/Datadog.Trace/Generated/net6.0/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/RaspRuleTypeMatchExtensions_EnumExtensions.g.cs b/tracer/src/Datadog.Trace/Generated/net6.0/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/RaspRuleTypeMatchExtensions_EnumExtensions.g.cs new file mode 100644 index 000000000000..0fdc8d77792a --- /dev/null +++ b/tracer/src/Datadog.Trace/Generated/net6.0/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/RaspRuleTypeMatchExtensions_EnumExtensions.g.cs @@ -0,0 +1,133 @@ +// +// 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. +// +// + +#nullable enable + +namespace Datadog.Trace.Telemetry.Metrics; + +/// +/// Extension methods for +/// +internal static partial class RaspRuleTypeMatchExtensions +{ + /// + /// The number of members in the enum. + /// This is a non-distinct count of defined names. + /// + public const int Length = 15; + + /// + /// Returns the string representation of the value. + /// If the attribute is decorated with a [Description] attribute, then + /// uses the provided value. Otherwise uses the name of the member, equivalent to + /// calling ToString() on . + /// + /// The value to retrieve the string value for + /// The string representation of the value + public static string ToStringFast(this Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch value) + => value switch + { + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.LfiSuccess => "waf_version;event_rules_version;block:success;rule_type:lfi", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SsrfSuccess => "waf_version;event_rules_version;block:success;rule_type:ssrf", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SQlISuccess => "waf_version;event_rules_version;block:success;rule_type:sql_injection", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionShellSuccess => "waf_version;event_rules_version;block:success;rule_type:command_injection;rule_variant:shell", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionExecSuccess => "waf_version;event_rules_version;block:success;rule_type:command_injection;rule_variant:exec", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.LfiFailure => "waf_version;event_rules_version;block:failure;rule_type:lfi", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SsrfFailure => "waf_version;event_rules_version;block:failure;rule_type:ssrf", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SQlIFailure => "waf_version;event_rules_version;block:failure;rule_type:sql_injection", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionShellFailure => "waf_version;event_rules_version;block:failure;rule_type:command_injection;rule_variant:shell", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionExecFailure => "waf_version;event_rules_version;block:failure;rule_type:command_injection;rule_variant:exec", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.LfiIrrelevant => "waf_version;event_rules_version;block:irrelevant;rule_type:lfi", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SsrfIrrelevant => "waf_version;event_rules_version;block:irrelevant;rule_type:ssrf", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SQlIIrrelevant => "waf_version;event_rules_version;block:irrelevant;rule_type:sql_injection", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionShellIrrelevant => "waf_version;event_rules_version;block:irrelevant;rule_type:command_injection;rule_variant:shell", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionExecIrrelevant => "waf_version;event_rules_version;block:irrelevant;rule_type:command_injection;rule_variant:exec", + _ => value.ToString(), + }; + + /// + /// Retrieves an array of the values of the members defined in + /// . + /// Note that this returns a new array with every invocation, so + /// should be cached if appropriate. + /// + /// An array of the values defined in + public static Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch[] GetValues() + => new [] + { + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.LfiSuccess, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SsrfSuccess, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SQlISuccess, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionShellSuccess, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionExecSuccess, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.LfiFailure, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SsrfFailure, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SQlIFailure, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionShellFailure, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionExecFailure, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.LfiIrrelevant, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SsrfIrrelevant, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SQlIIrrelevant, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionShellIrrelevant, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionExecIrrelevant, + }; + + /// + /// Retrieves an array of the names of the members defined in + /// . + /// Note that this returns a new array with every invocation, so + /// should be cached if appropriate. + /// Ignores [Description] definitions. + /// + /// An array of the names of the members defined in + public static string[] GetNames() + => new [] + { + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.LfiSuccess), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SsrfSuccess), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SQlISuccess), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionShellSuccess), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionExecSuccess), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.LfiFailure), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SsrfFailure), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SQlIFailure), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionShellFailure), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionExecFailure), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.LfiIrrelevant), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SsrfIrrelevant), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SQlIIrrelevant), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionShellIrrelevant), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionExecIrrelevant), + }; + + /// + /// Retrieves an array of the names of the members defined in + /// . + /// Note that this returns a new array with every invocation, so + /// should be cached if appropriate. + /// Uses [Description] definition if available, otherwise uses the name of the property + /// + /// An array of the names of the members defined in + public static string[] GetDescriptions() + => new [] + { + "waf_version;event_rules_version;block:success;rule_type:lfi", + "waf_version;event_rules_version;block:success;rule_type:ssrf", + "waf_version;event_rules_version;block:success;rule_type:sql_injection", + "waf_version;event_rules_version;block:success;rule_type:command_injection;rule_variant:shell", + "waf_version;event_rules_version;block:success;rule_type:command_injection;rule_variant:exec", + "waf_version;event_rules_version;block:failure;rule_type:lfi", + "waf_version;event_rules_version;block:failure;rule_type:ssrf", + "waf_version;event_rules_version;block:failure;rule_type:sql_injection", + "waf_version;event_rules_version;block:failure;rule_type:command_injection;rule_variant:shell", + "waf_version;event_rules_version;block:failure;rule_type:command_injection;rule_variant:exec", + "waf_version;event_rules_version;block:irrelevant;rule_type:lfi", + "waf_version;event_rules_version;block:irrelevant;rule_type:ssrf", + "waf_version;event_rules_version;block:irrelevant;rule_type:sql_injection", + "waf_version;event_rules_version;block:irrelevant;rule_type:command_injection;rule_variant:shell", + "waf_version;event_rules_version;block:irrelevant;rule_type:command_injection;rule_variant:exec", + }; +} \ No newline at end of file diff --git a/tracer/src/Datadog.Trace/Generated/net6.0/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/CiVisibilityMetricsTelemetryCollector_Count.g.cs b/tracer/src/Datadog.Trace/Generated/net6.0/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/CiVisibilityMetricsTelemetryCollector_Count.g.cs index 363a5e43830a..7500ae6cf042 100644 --- a/tracer/src/Datadog.Trace/Generated/net6.0/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/CiVisibilityMetricsTelemetryCollector_Count.g.cs +++ b/tracer/src/Datadog.Trace/Generated/net6.0/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/CiVisibilityMetricsTelemetryCollector_Count.g.cs @@ -156,7 +156,7 @@ public void RecordCountRaspRuleEval(Datadog.Trace.Telemetry.Metrics.MetricTags.R { } - public void RecordCountRaspRuleMatch(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType tag, int increment = 1) + public void RecordCountRaspRuleMatch(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch tag, int increment = 1) { } diff --git a/tracer/src/Datadog.Trace/Generated/net6.0/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/IMetricsTelemetryCollector_Count.g.cs b/tracer/src/Datadog.Trace/Generated/net6.0/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/IMetricsTelemetryCollector_Count.g.cs index 1f009e0918d2..6217252b104c 100644 --- a/tracer/src/Datadog.Trace/Generated/net6.0/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/IMetricsTelemetryCollector_Count.g.cs +++ b/tracer/src/Datadog.Trace/Generated/net6.0/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/IMetricsTelemetryCollector_Count.g.cs @@ -81,7 +81,7 @@ internal partial interface IMetricsTelemetryCollector public void RecordCountRaspRuleEval(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType tag, int increment = 1); - public void RecordCountRaspRuleMatch(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType tag, int increment = 1); + public void RecordCountRaspRuleMatch(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch tag, int increment = 1); public void RecordCountRaspTimeout(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType tag, int increment = 1); diff --git a/tracer/src/Datadog.Trace/Generated/net6.0/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/MetricsTelemetryCollector_Count.g.cs b/tracer/src/Datadog.Trace/Generated/net6.0/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/MetricsTelemetryCollector_Count.g.cs index 9da1f3508715..37ecde449b32 100644 --- a/tracer/src/Datadog.Trace/Generated/net6.0/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/MetricsTelemetryCollector_Count.g.cs +++ b/tracer/src/Datadog.Trace/Generated/net6.0/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/MetricsTelemetryCollector_Count.g.cs @@ -11,7 +11,7 @@ namespace Datadog.Trace.Telemetry; internal partial class MetricsTelemetryCollector { - private const int CountLength = 613; + private const int CountLength = 623; /// /// Creates the buffer for the values. @@ -575,34 +575,44 @@ private static AggregatedMetric[] GetCountBuffer() new(new[] { "truncation_reason:list_or_map_too_large" }), new(new[] { "truncation_reason:object_too_deep" }), // rasp.rule.eval, index = 520 - new(new[] { "waf_version", "rule_type:lfi" }), - new(new[] { "waf_version", "rule_type:ssrf" }), - new(new[] { "waf_version", "rule_type:sql_injection" }), - new(new[] { "waf_version", "rule_type:command_injection", "rule_variant:shell" }), - new(new[] { "waf_version", "rule_type:command_injection", "rule_variant:exec" }), + new(new[] { "waf_version", "event_rules_version", "rule_type:lfi" }), + new(new[] { "waf_version", "event_rules_version", "rule_type:ssrf" }), + new(new[] { "waf_version", "event_rules_version", "rule_type:sql_injection" }), + new(new[] { "waf_version", "event_rules_version", "rule_type:command_injection", "rule_variant:shell" }), + new(new[] { "waf_version", "event_rules_version", "rule_type:command_injection", "rule_variant:exec" }), // rasp.rule.match, index = 525 - new(new[] { "waf_version", "rule_type:lfi" }), - new(new[] { "waf_version", "rule_type:ssrf" }), - new(new[] { "waf_version", "rule_type:sql_injection" }), - new(new[] { "waf_version", "rule_type:command_injection", "rule_variant:shell" }), - new(new[] { "waf_version", "rule_type:command_injection", "rule_variant:exec" }), - // rasp.timeout, index = 530 - new(new[] { "waf_version", "rule_type:lfi" }), - new(new[] { "waf_version", "rule_type:ssrf" }), - new(new[] { "waf_version", "rule_type:sql_injection" }), - new(new[] { "waf_version", "rule_type:command_injection", "rule_variant:shell" }), - new(new[] { "waf_version", "rule_type:command_injection", "rule_variant:exec" }), - // instrum.user_auth.missing_user_id, index = 535 + new(new[] { "waf_version", "event_rules_version", "block:success", "rule_type:lfi" }), + new(new[] { "waf_version", "event_rules_version", "block:success", "rule_type:ssrf" }), + new(new[] { "waf_version", "event_rules_version", "block:success", "rule_type:sql_injection" }), + new(new[] { "waf_version", "event_rules_version", "block:success", "rule_type:command_injection", "rule_variant:shell" }), + new(new[] { "waf_version", "event_rules_version", "block:success", "rule_type:command_injection", "rule_variant:exec" }), + new(new[] { "waf_version", "event_rules_version", "block:failure", "rule_type:lfi" }), + new(new[] { "waf_version", "event_rules_version", "block:failure", "rule_type:ssrf" }), + new(new[] { "waf_version", "event_rules_version", "block:failure", "rule_type:sql_injection" }), + new(new[] { "waf_version", "event_rules_version", "block:failure", "rule_type:command_injection", "rule_variant:shell" }), + new(new[] { "waf_version", "event_rules_version", "block:failure", "rule_type:command_injection", "rule_variant:exec" }), + new(new[] { "waf_version", "event_rules_version", "block:irrelevant", "rule_type:lfi" }), + new(new[] { "waf_version", "event_rules_version", "block:irrelevant", "rule_type:ssrf" }), + new(new[] { "waf_version", "event_rules_version", "block:irrelevant", "rule_type:sql_injection" }), + new(new[] { "waf_version", "event_rules_version", "block:irrelevant", "rule_type:command_injection", "rule_variant:shell" }), + new(new[] { "waf_version", "event_rules_version", "block:irrelevant", "rule_type:command_injection", "rule_variant:exec" }), + // rasp.timeout, index = 540 + new(new[] { "waf_version", "event_rules_version", "rule_type:lfi" }), + new(new[] { "waf_version", "event_rules_version", "rule_type:ssrf" }), + new(new[] { "waf_version", "event_rules_version", "rule_type:sql_injection" }), + new(new[] { "waf_version", "event_rules_version", "rule_type:command_injection", "rule_variant:shell" }), + new(new[] { "waf_version", "event_rules_version", "rule_type:command_injection", "rule_variant:exec" }), + // instrum.user_auth.missing_user_id, index = 545 new(new[] { "framework:aspnetcore_identity", "event_type:login_success" }), new(new[] { "framework:aspnetcore_identity", "event_type:login_failure" }), new(new[] { "framework:aspnetcore_identity", "event_type:signup" }), new(new[] { "framework:unknown", "event_type:signup" }), - // instrum.user_auth.missing_user_login, index = 539 + // instrum.user_auth.missing_user_login, index = 549 new(new[] { "framework:aspnetcore_identity", "event_type:login_success" }), new(new[] { "framework:aspnetcore_identity", "event_type:login_failure" }), new(new[] { "framework:aspnetcore_identity", "event_type:signup" }), new(new[] { "framework:unknown", "event_type:signup" }), - // executed.source, index = 543 + // executed.source, index = 553 new(new[] { "source_type:http.request.body" }), new(new[] { "source_type:http.request.path" }), new(new[] { "source_type:http.request.parameter.name" }), @@ -617,9 +627,9 @@ private static AggregatedMetric[] GetCountBuffer() new(new[] { "source_type:http.request.uri" }), new(new[] { "source_type:grpc.request.body" }), new(new[] { "source_type:sql.row.value" }), - // executed.propagation, index = 557 + // executed.propagation, index = 567 new(null), - // executed.sink, index = 558 + // executed.sink, index = 568 new(new[] { "vulnerability_type:none" }), new(new[] { "vulnerability_type:weak_cipher" }), new(new[] { "vulnerability_type:weak_hash" }), @@ -647,9 +657,9 @@ private static AggregatedMetric[] GetCountBuffer() new(new[] { "vulnerability_type:directory_listing_leak" }), new(new[] { "vulnerability_type:session_timeout" }), new(new[] { "vulnerability_type:email_html_injection" }), - // request.tainted, index = 585 + // request.tainted, index = 595 new(null), - // suppressed.vulnerabilities, index = 586 + // suppressed.vulnerabilities, index = 596 new(new[] { "vulnerability_type:none" }), new(new[] { "vulnerability_type:weak_cipher" }), new(new[] { "vulnerability_type:weak_hash" }), @@ -685,7 +695,7 @@ private static AggregatedMetric[] GetCountBuffer() /// It is equal to the cardinality of the tag combinations (or 1 if there are no tags) /// private static int[] CountEntryCounts { get; } - = new int[]{ 4, 80, 1, 3, 4, 2, 2, 4, 1, 1, 1, 22, 3, 2, 5, 5, 2, 1, 22, 3, 90, 90, 2, 44, 6, 1, 1, 80, 1, 22, 3, 2, 2, 5, 3, 5, 5, 5, 4, 4, 14, 1, 27, 1, 27, }; + = new int[]{ 4, 80, 1, 3, 4, 2, 2, 4, 1, 1, 1, 22, 3, 2, 5, 5, 2, 1, 22, 3, 90, 90, 2, 44, 6, 1, 1, 80, 1, 22, 3, 2, 2, 5, 3, 5, 15, 5, 4, 4, 14, 1, 27, 1, 27, }; public void RecordCountLogCreated(Datadog.Trace.Telemetry.Metrics.MetricTags.LogLevel tag, int increment = 1) { @@ -895,7 +905,7 @@ public void RecordCountRaspRuleEval(Datadog.Trace.Telemetry.Metrics.MetricTags.R Interlocked.Add(ref _buffer.Count[index], increment); } - public void RecordCountRaspRuleMatch(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType tag, int increment = 1) + public void RecordCountRaspRuleMatch(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch tag, int increment = 1) { var index = 525 + (int)tag; Interlocked.Add(ref _buffer.Count[index], increment); @@ -903,47 +913,47 @@ public void RecordCountRaspRuleMatch(Datadog.Trace.Telemetry.Metrics.MetricTags. public void RecordCountRaspTimeout(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType tag, int increment = 1) { - var index = 530 + (int)tag; + var index = 540 + (int)tag; Interlocked.Add(ref _buffer.Count[index], increment); } public void RecordCountMissingUserId(Datadog.Trace.Telemetry.Metrics.MetricTags.AuthenticationFrameworkWithEventType tag, int increment = 1) { - var index = 535 + (int)tag; + var index = 545 + (int)tag; Interlocked.Add(ref _buffer.Count[index], increment); } public void RecordCountMissingUserLogin(Datadog.Trace.Telemetry.Metrics.MetricTags.AuthenticationFrameworkWithEventType tag, int increment = 1) { - var index = 539 + (int)tag; + var index = 549 + (int)tag; Interlocked.Add(ref _buffer.Count[index], increment); } public void RecordCountIastExecutedSources(Datadog.Trace.Telemetry.Metrics.MetricTags.IastSourceType tag, int increment = 1) { - var index = 543 + (int)tag; + var index = 553 + (int)tag; Interlocked.Add(ref _buffer.Count[index], increment); } public void RecordCountIastExecutedPropagations(int increment = 1) { - Interlocked.Add(ref _buffer.Count[557], increment); + Interlocked.Add(ref _buffer.Count[567], increment); } public void RecordCountIastExecutedSinks(Datadog.Trace.Telemetry.Metrics.MetricTags.IastVulnerabilityType tag, int increment = 1) { - var index = 558 + (int)tag; + var index = 568 + (int)tag; Interlocked.Add(ref _buffer.Count[index], increment); } public void RecordCountIastRequestTainted(int increment = 1) { - Interlocked.Add(ref _buffer.Count[585], increment); + Interlocked.Add(ref _buffer.Count[595], increment); } public void RecordCountIastSuppressedVulnerabilities(Datadog.Trace.Telemetry.Metrics.MetricTags.IastVulnerabilityType tag, int increment = 1) { - var index = 586 + (int)tag; + var index = 596 + (int)tag; Interlocked.Add(ref _buffer.Count[index], increment); } } \ No newline at end of file diff --git a/tracer/src/Datadog.Trace/Generated/net6.0/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/NullMetricsTelemetryCollector_Count.g.cs b/tracer/src/Datadog.Trace/Generated/net6.0/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/NullMetricsTelemetryCollector_Count.g.cs index eb750e63a8ad..9b6efbd64cec 100644 --- a/tracer/src/Datadog.Trace/Generated/net6.0/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/NullMetricsTelemetryCollector_Count.g.cs +++ b/tracer/src/Datadog.Trace/Generated/net6.0/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/NullMetricsTelemetryCollector_Count.g.cs @@ -156,7 +156,7 @@ public void RecordCountRaspRuleEval(Datadog.Trace.Telemetry.Metrics.MetricTags.R { } - public void RecordCountRaspRuleMatch(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType tag, int increment = 1) + public void RecordCountRaspRuleMatch(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch tag, int increment = 1) { } diff --git a/tracer/src/Datadog.Trace/Generated/netcoreapp3.1/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/RaspRuleTypeExtensions_EnumExtensions.g.cs b/tracer/src/Datadog.Trace/Generated/netcoreapp3.1/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/RaspRuleTypeExtensions_EnumExtensions.g.cs index 4fdc8921fb58..923039e18ff0 100644 --- a/tracer/src/Datadog.Trace/Generated/netcoreapp3.1/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/RaspRuleTypeExtensions_EnumExtensions.g.cs +++ b/tracer/src/Datadog.Trace/Generated/netcoreapp3.1/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/RaspRuleTypeExtensions_EnumExtensions.g.cs @@ -30,11 +30,11 @@ internal static partial class RaspRuleTypeExtensions public static string ToStringFast(this Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType value) => value switch { - Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType.Lfi => "waf_version;rule_type:lfi", - Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType.Ssrf => "waf_version;rule_type:ssrf", - Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType.SQlI => "waf_version;rule_type:sql_injection", - Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType.CommandInjectionShell => "waf_version;rule_type:command_injection;rule_variant:shell", - Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType.CommandInjectionExec => "waf_version;rule_type:command_injection;rule_variant:exec", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType.Lfi => "waf_version;event_rules_version;rule_type:lfi", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType.Ssrf => "waf_version;event_rules_version;rule_type:ssrf", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType.SQlI => "waf_version;event_rules_version;rule_type:sql_injection", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType.CommandInjectionShell => "waf_version;event_rules_version;rule_type:command_injection;rule_variant:shell", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType.CommandInjectionExec => "waf_version;event_rules_version;rule_type:command_injection;rule_variant:exec", _ => value.ToString(), }; @@ -84,10 +84,10 @@ public static string[] GetNames() public static string[] GetDescriptions() => new [] { - "waf_version;rule_type:lfi", - "waf_version;rule_type:ssrf", - "waf_version;rule_type:sql_injection", - "waf_version;rule_type:command_injection;rule_variant:shell", - "waf_version;rule_type:command_injection;rule_variant:exec", + "waf_version;event_rules_version;rule_type:lfi", + "waf_version;event_rules_version;rule_type:ssrf", + "waf_version;event_rules_version;rule_type:sql_injection", + "waf_version;event_rules_version;rule_type:command_injection;rule_variant:shell", + "waf_version;event_rules_version;rule_type:command_injection;rule_variant:exec", }; } \ No newline at end of file diff --git a/tracer/src/Datadog.Trace/Generated/netcoreapp3.1/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/RaspRuleTypeMatchExtensions_EnumExtensions.g.cs b/tracer/src/Datadog.Trace/Generated/netcoreapp3.1/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/RaspRuleTypeMatchExtensions_EnumExtensions.g.cs new file mode 100644 index 000000000000..0fdc8d77792a --- /dev/null +++ b/tracer/src/Datadog.Trace/Generated/netcoreapp3.1/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/RaspRuleTypeMatchExtensions_EnumExtensions.g.cs @@ -0,0 +1,133 @@ +// +// 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. +// +// + +#nullable enable + +namespace Datadog.Trace.Telemetry.Metrics; + +/// +/// Extension methods for +/// +internal static partial class RaspRuleTypeMatchExtensions +{ + /// + /// The number of members in the enum. + /// This is a non-distinct count of defined names. + /// + public const int Length = 15; + + /// + /// Returns the string representation of the value. + /// If the attribute is decorated with a [Description] attribute, then + /// uses the provided value. Otherwise uses the name of the member, equivalent to + /// calling ToString() on . + /// + /// The value to retrieve the string value for + /// The string representation of the value + public static string ToStringFast(this Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch value) + => value switch + { + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.LfiSuccess => "waf_version;event_rules_version;block:success;rule_type:lfi", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SsrfSuccess => "waf_version;event_rules_version;block:success;rule_type:ssrf", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SQlISuccess => "waf_version;event_rules_version;block:success;rule_type:sql_injection", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionShellSuccess => "waf_version;event_rules_version;block:success;rule_type:command_injection;rule_variant:shell", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionExecSuccess => "waf_version;event_rules_version;block:success;rule_type:command_injection;rule_variant:exec", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.LfiFailure => "waf_version;event_rules_version;block:failure;rule_type:lfi", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SsrfFailure => "waf_version;event_rules_version;block:failure;rule_type:ssrf", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SQlIFailure => "waf_version;event_rules_version;block:failure;rule_type:sql_injection", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionShellFailure => "waf_version;event_rules_version;block:failure;rule_type:command_injection;rule_variant:shell", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionExecFailure => "waf_version;event_rules_version;block:failure;rule_type:command_injection;rule_variant:exec", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.LfiIrrelevant => "waf_version;event_rules_version;block:irrelevant;rule_type:lfi", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SsrfIrrelevant => "waf_version;event_rules_version;block:irrelevant;rule_type:ssrf", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SQlIIrrelevant => "waf_version;event_rules_version;block:irrelevant;rule_type:sql_injection", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionShellIrrelevant => "waf_version;event_rules_version;block:irrelevant;rule_type:command_injection;rule_variant:shell", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionExecIrrelevant => "waf_version;event_rules_version;block:irrelevant;rule_type:command_injection;rule_variant:exec", + _ => value.ToString(), + }; + + /// + /// Retrieves an array of the values of the members defined in + /// . + /// Note that this returns a new array with every invocation, so + /// should be cached if appropriate. + /// + /// An array of the values defined in + public static Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch[] GetValues() + => new [] + { + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.LfiSuccess, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SsrfSuccess, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SQlISuccess, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionShellSuccess, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionExecSuccess, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.LfiFailure, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SsrfFailure, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SQlIFailure, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionShellFailure, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionExecFailure, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.LfiIrrelevant, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SsrfIrrelevant, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SQlIIrrelevant, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionShellIrrelevant, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionExecIrrelevant, + }; + + /// + /// Retrieves an array of the names of the members defined in + /// . + /// Note that this returns a new array with every invocation, so + /// should be cached if appropriate. + /// Ignores [Description] definitions. + /// + /// An array of the names of the members defined in + public static string[] GetNames() + => new [] + { + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.LfiSuccess), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SsrfSuccess), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SQlISuccess), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionShellSuccess), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionExecSuccess), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.LfiFailure), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SsrfFailure), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SQlIFailure), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionShellFailure), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionExecFailure), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.LfiIrrelevant), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SsrfIrrelevant), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SQlIIrrelevant), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionShellIrrelevant), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionExecIrrelevant), + }; + + /// + /// Retrieves an array of the names of the members defined in + /// . + /// Note that this returns a new array with every invocation, so + /// should be cached if appropriate. + /// Uses [Description] definition if available, otherwise uses the name of the property + /// + /// An array of the names of the members defined in + public static string[] GetDescriptions() + => new [] + { + "waf_version;event_rules_version;block:success;rule_type:lfi", + "waf_version;event_rules_version;block:success;rule_type:ssrf", + "waf_version;event_rules_version;block:success;rule_type:sql_injection", + "waf_version;event_rules_version;block:success;rule_type:command_injection;rule_variant:shell", + "waf_version;event_rules_version;block:success;rule_type:command_injection;rule_variant:exec", + "waf_version;event_rules_version;block:failure;rule_type:lfi", + "waf_version;event_rules_version;block:failure;rule_type:ssrf", + "waf_version;event_rules_version;block:failure;rule_type:sql_injection", + "waf_version;event_rules_version;block:failure;rule_type:command_injection;rule_variant:shell", + "waf_version;event_rules_version;block:failure;rule_type:command_injection;rule_variant:exec", + "waf_version;event_rules_version;block:irrelevant;rule_type:lfi", + "waf_version;event_rules_version;block:irrelevant;rule_type:ssrf", + "waf_version;event_rules_version;block:irrelevant;rule_type:sql_injection", + "waf_version;event_rules_version;block:irrelevant;rule_type:command_injection;rule_variant:shell", + "waf_version;event_rules_version;block:irrelevant;rule_type:command_injection;rule_variant:exec", + }; +} \ No newline at end of file diff --git a/tracer/src/Datadog.Trace/Generated/netcoreapp3.1/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/CiVisibilityMetricsTelemetryCollector_Count.g.cs b/tracer/src/Datadog.Trace/Generated/netcoreapp3.1/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/CiVisibilityMetricsTelemetryCollector_Count.g.cs index 363a5e43830a..7500ae6cf042 100644 --- a/tracer/src/Datadog.Trace/Generated/netcoreapp3.1/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/CiVisibilityMetricsTelemetryCollector_Count.g.cs +++ b/tracer/src/Datadog.Trace/Generated/netcoreapp3.1/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/CiVisibilityMetricsTelemetryCollector_Count.g.cs @@ -156,7 +156,7 @@ public void RecordCountRaspRuleEval(Datadog.Trace.Telemetry.Metrics.MetricTags.R { } - public void RecordCountRaspRuleMatch(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType tag, int increment = 1) + public void RecordCountRaspRuleMatch(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch tag, int increment = 1) { } diff --git a/tracer/src/Datadog.Trace/Generated/netcoreapp3.1/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/IMetricsTelemetryCollector_Count.g.cs b/tracer/src/Datadog.Trace/Generated/netcoreapp3.1/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/IMetricsTelemetryCollector_Count.g.cs index 1f009e0918d2..6217252b104c 100644 --- a/tracer/src/Datadog.Trace/Generated/netcoreapp3.1/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/IMetricsTelemetryCollector_Count.g.cs +++ b/tracer/src/Datadog.Trace/Generated/netcoreapp3.1/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/IMetricsTelemetryCollector_Count.g.cs @@ -81,7 +81,7 @@ internal partial interface IMetricsTelemetryCollector public void RecordCountRaspRuleEval(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType tag, int increment = 1); - public void RecordCountRaspRuleMatch(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType tag, int increment = 1); + public void RecordCountRaspRuleMatch(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch tag, int increment = 1); public void RecordCountRaspTimeout(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType tag, int increment = 1); diff --git a/tracer/src/Datadog.Trace/Generated/netcoreapp3.1/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/MetricsTelemetryCollector_Count.g.cs b/tracer/src/Datadog.Trace/Generated/netcoreapp3.1/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/MetricsTelemetryCollector_Count.g.cs index 9da1f3508715..37ecde449b32 100644 --- a/tracer/src/Datadog.Trace/Generated/netcoreapp3.1/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/MetricsTelemetryCollector_Count.g.cs +++ b/tracer/src/Datadog.Trace/Generated/netcoreapp3.1/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/MetricsTelemetryCollector_Count.g.cs @@ -11,7 +11,7 @@ namespace Datadog.Trace.Telemetry; internal partial class MetricsTelemetryCollector { - private const int CountLength = 613; + private const int CountLength = 623; /// /// Creates the buffer for the values. @@ -575,34 +575,44 @@ private static AggregatedMetric[] GetCountBuffer() new(new[] { "truncation_reason:list_or_map_too_large" }), new(new[] { "truncation_reason:object_too_deep" }), // rasp.rule.eval, index = 520 - new(new[] { "waf_version", "rule_type:lfi" }), - new(new[] { "waf_version", "rule_type:ssrf" }), - new(new[] { "waf_version", "rule_type:sql_injection" }), - new(new[] { "waf_version", "rule_type:command_injection", "rule_variant:shell" }), - new(new[] { "waf_version", "rule_type:command_injection", "rule_variant:exec" }), + new(new[] { "waf_version", "event_rules_version", "rule_type:lfi" }), + new(new[] { "waf_version", "event_rules_version", "rule_type:ssrf" }), + new(new[] { "waf_version", "event_rules_version", "rule_type:sql_injection" }), + new(new[] { "waf_version", "event_rules_version", "rule_type:command_injection", "rule_variant:shell" }), + new(new[] { "waf_version", "event_rules_version", "rule_type:command_injection", "rule_variant:exec" }), // rasp.rule.match, index = 525 - new(new[] { "waf_version", "rule_type:lfi" }), - new(new[] { "waf_version", "rule_type:ssrf" }), - new(new[] { "waf_version", "rule_type:sql_injection" }), - new(new[] { "waf_version", "rule_type:command_injection", "rule_variant:shell" }), - new(new[] { "waf_version", "rule_type:command_injection", "rule_variant:exec" }), - // rasp.timeout, index = 530 - new(new[] { "waf_version", "rule_type:lfi" }), - new(new[] { "waf_version", "rule_type:ssrf" }), - new(new[] { "waf_version", "rule_type:sql_injection" }), - new(new[] { "waf_version", "rule_type:command_injection", "rule_variant:shell" }), - new(new[] { "waf_version", "rule_type:command_injection", "rule_variant:exec" }), - // instrum.user_auth.missing_user_id, index = 535 + new(new[] { "waf_version", "event_rules_version", "block:success", "rule_type:lfi" }), + new(new[] { "waf_version", "event_rules_version", "block:success", "rule_type:ssrf" }), + new(new[] { "waf_version", "event_rules_version", "block:success", "rule_type:sql_injection" }), + new(new[] { "waf_version", "event_rules_version", "block:success", "rule_type:command_injection", "rule_variant:shell" }), + new(new[] { "waf_version", "event_rules_version", "block:success", "rule_type:command_injection", "rule_variant:exec" }), + new(new[] { "waf_version", "event_rules_version", "block:failure", "rule_type:lfi" }), + new(new[] { "waf_version", "event_rules_version", "block:failure", "rule_type:ssrf" }), + new(new[] { "waf_version", "event_rules_version", "block:failure", "rule_type:sql_injection" }), + new(new[] { "waf_version", "event_rules_version", "block:failure", "rule_type:command_injection", "rule_variant:shell" }), + new(new[] { "waf_version", "event_rules_version", "block:failure", "rule_type:command_injection", "rule_variant:exec" }), + new(new[] { "waf_version", "event_rules_version", "block:irrelevant", "rule_type:lfi" }), + new(new[] { "waf_version", "event_rules_version", "block:irrelevant", "rule_type:ssrf" }), + new(new[] { "waf_version", "event_rules_version", "block:irrelevant", "rule_type:sql_injection" }), + new(new[] { "waf_version", "event_rules_version", "block:irrelevant", "rule_type:command_injection", "rule_variant:shell" }), + new(new[] { "waf_version", "event_rules_version", "block:irrelevant", "rule_type:command_injection", "rule_variant:exec" }), + // rasp.timeout, index = 540 + new(new[] { "waf_version", "event_rules_version", "rule_type:lfi" }), + new(new[] { "waf_version", "event_rules_version", "rule_type:ssrf" }), + new(new[] { "waf_version", "event_rules_version", "rule_type:sql_injection" }), + new(new[] { "waf_version", "event_rules_version", "rule_type:command_injection", "rule_variant:shell" }), + new(new[] { "waf_version", "event_rules_version", "rule_type:command_injection", "rule_variant:exec" }), + // instrum.user_auth.missing_user_id, index = 545 new(new[] { "framework:aspnetcore_identity", "event_type:login_success" }), new(new[] { "framework:aspnetcore_identity", "event_type:login_failure" }), new(new[] { "framework:aspnetcore_identity", "event_type:signup" }), new(new[] { "framework:unknown", "event_type:signup" }), - // instrum.user_auth.missing_user_login, index = 539 + // instrum.user_auth.missing_user_login, index = 549 new(new[] { "framework:aspnetcore_identity", "event_type:login_success" }), new(new[] { "framework:aspnetcore_identity", "event_type:login_failure" }), new(new[] { "framework:aspnetcore_identity", "event_type:signup" }), new(new[] { "framework:unknown", "event_type:signup" }), - // executed.source, index = 543 + // executed.source, index = 553 new(new[] { "source_type:http.request.body" }), new(new[] { "source_type:http.request.path" }), new(new[] { "source_type:http.request.parameter.name" }), @@ -617,9 +627,9 @@ private static AggregatedMetric[] GetCountBuffer() new(new[] { "source_type:http.request.uri" }), new(new[] { "source_type:grpc.request.body" }), new(new[] { "source_type:sql.row.value" }), - // executed.propagation, index = 557 + // executed.propagation, index = 567 new(null), - // executed.sink, index = 558 + // executed.sink, index = 568 new(new[] { "vulnerability_type:none" }), new(new[] { "vulnerability_type:weak_cipher" }), new(new[] { "vulnerability_type:weak_hash" }), @@ -647,9 +657,9 @@ private static AggregatedMetric[] GetCountBuffer() new(new[] { "vulnerability_type:directory_listing_leak" }), new(new[] { "vulnerability_type:session_timeout" }), new(new[] { "vulnerability_type:email_html_injection" }), - // request.tainted, index = 585 + // request.tainted, index = 595 new(null), - // suppressed.vulnerabilities, index = 586 + // suppressed.vulnerabilities, index = 596 new(new[] { "vulnerability_type:none" }), new(new[] { "vulnerability_type:weak_cipher" }), new(new[] { "vulnerability_type:weak_hash" }), @@ -685,7 +695,7 @@ private static AggregatedMetric[] GetCountBuffer() /// It is equal to the cardinality of the tag combinations (or 1 if there are no tags) /// private static int[] CountEntryCounts { get; } - = new int[]{ 4, 80, 1, 3, 4, 2, 2, 4, 1, 1, 1, 22, 3, 2, 5, 5, 2, 1, 22, 3, 90, 90, 2, 44, 6, 1, 1, 80, 1, 22, 3, 2, 2, 5, 3, 5, 5, 5, 4, 4, 14, 1, 27, 1, 27, }; + = new int[]{ 4, 80, 1, 3, 4, 2, 2, 4, 1, 1, 1, 22, 3, 2, 5, 5, 2, 1, 22, 3, 90, 90, 2, 44, 6, 1, 1, 80, 1, 22, 3, 2, 2, 5, 3, 5, 15, 5, 4, 4, 14, 1, 27, 1, 27, }; public void RecordCountLogCreated(Datadog.Trace.Telemetry.Metrics.MetricTags.LogLevel tag, int increment = 1) { @@ -895,7 +905,7 @@ public void RecordCountRaspRuleEval(Datadog.Trace.Telemetry.Metrics.MetricTags.R Interlocked.Add(ref _buffer.Count[index], increment); } - public void RecordCountRaspRuleMatch(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType tag, int increment = 1) + public void RecordCountRaspRuleMatch(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch tag, int increment = 1) { var index = 525 + (int)tag; Interlocked.Add(ref _buffer.Count[index], increment); @@ -903,47 +913,47 @@ public void RecordCountRaspRuleMatch(Datadog.Trace.Telemetry.Metrics.MetricTags. public void RecordCountRaspTimeout(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType tag, int increment = 1) { - var index = 530 + (int)tag; + var index = 540 + (int)tag; Interlocked.Add(ref _buffer.Count[index], increment); } public void RecordCountMissingUserId(Datadog.Trace.Telemetry.Metrics.MetricTags.AuthenticationFrameworkWithEventType tag, int increment = 1) { - var index = 535 + (int)tag; + var index = 545 + (int)tag; Interlocked.Add(ref _buffer.Count[index], increment); } public void RecordCountMissingUserLogin(Datadog.Trace.Telemetry.Metrics.MetricTags.AuthenticationFrameworkWithEventType tag, int increment = 1) { - var index = 539 + (int)tag; + var index = 549 + (int)tag; Interlocked.Add(ref _buffer.Count[index], increment); } public void RecordCountIastExecutedSources(Datadog.Trace.Telemetry.Metrics.MetricTags.IastSourceType tag, int increment = 1) { - var index = 543 + (int)tag; + var index = 553 + (int)tag; Interlocked.Add(ref _buffer.Count[index], increment); } public void RecordCountIastExecutedPropagations(int increment = 1) { - Interlocked.Add(ref _buffer.Count[557], increment); + Interlocked.Add(ref _buffer.Count[567], increment); } public void RecordCountIastExecutedSinks(Datadog.Trace.Telemetry.Metrics.MetricTags.IastVulnerabilityType tag, int increment = 1) { - var index = 558 + (int)tag; + var index = 568 + (int)tag; Interlocked.Add(ref _buffer.Count[index], increment); } public void RecordCountIastRequestTainted(int increment = 1) { - Interlocked.Add(ref _buffer.Count[585], increment); + Interlocked.Add(ref _buffer.Count[595], increment); } public void RecordCountIastSuppressedVulnerabilities(Datadog.Trace.Telemetry.Metrics.MetricTags.IastVulnerabilityType tag, int increment = 1) { - var index = 586 + (int)tag; + var index = 596 + (int)tag; Interlocked.Add(ref _buffer.Count[index], increment); } } \ No newline at end of file diff --git a/tracer/src/Datadog.Trace/Generated/netcoreapp3.1/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/NullMetricsTelemetryCollector_Count.g.cs b/tracer/src/Datadog.Trace/Generated/netcoreapp3.1/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/NullMetricsTelemetryCollector_Count.g.cs index eb750e63a8ad..9b6efbd64cec 100644 --- a/tracer/src/Datadog.Trace/Generated/netcoreapp3.1/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/NullMetricsTelemetryCollector_Count.g.cs +++ b/tracer/src/Datadog.Trace/Generated/netcoreapp3.1/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/NullMetricsTelemetryCollector_Count.g.cs @@ -156,7 +156,7 @@ public void RecordCountRaspRuleEval(Datadog.Trace.Telemetry.Metrics.MetricTags.R { } - public void RecordCountRaspRuleMatch(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType tag, int increment = 1) + public void RecordCountRaspRuleMatch(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch tag, int increment = 1) { } diff --git a/tracer/src/Datadog.Trace/Generated/netstandard2.0/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/RaspRuleTypeExtensions_EnumExtensions.g.cs b/tracer/src/Datadog.Trace/Generated/netstandard2.0/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/RaspRuleTypeExtensions_EnumExtensions.g.cs index 4fdc8921fb58..923039e18ff0 100644 --- a/tracer/src/Datadog.Trace/Generated/netstandard2.0/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/RaspRuleTypeExtensions_EnumExtensions.g.cs +++ b/tracer/src/Datadog.Trace/Generated/netstandard2.0/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/RaspRuleTypeExtensions_EnumExtensions.g.cs @@ -30,11 +30,11 @@ internal static partial class RaspRuleTypeExtensions public static string ToStringFast(this Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType value) => value switch { - Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType.Lfi => "waf_version;rule_type:lfi", - Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType.Ssrf => "waf_version;rule_type:ssrf", - Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType.SQlI => "waf_version;rule_type:sql_injection", - Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType.CommandInjectionShell => "waf_version;rule_type:command_injection;rule_variant:shell", - Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType.CommandInjectionExec => "waf_version;rule_type:command_injection;rule_variant:exec", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType.Lfi => "waf_version;event_rules_version;rule_type:lfi", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType.Ssrf => "waf_version;event_rules_version;rule_type:ssrf", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType.SQlI => "waf_version;event_rules_version;rule_type:sql_injection", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType.CommandInjectionShell => "waf_version;event_rules_version;rule_type:command_injection;rule_variant:shell", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType.CommandInjectionExec => "waf_version;event_rules_version;rule_type:command_injection;rule_variant:exec", _ => value.ToString(), }; @@ -84,10 +84,10 @@ public static string[] GetNames() public static string[] GetDescriptions() => new [] { - "waf_version;rule_type:lfi", - "waf_version;rule_type:ssrf", - "waf_version;rule_type:sql_injection", - "waf_version;rule_type:command_injection;rule_variant:shell", - "waf_version;rule_type:command_injection;rule_variant:exec", + "waf_version;event_rules_version;rule_type:lfi", + "waf_version;event_rules_version;rule_type:ssrf", + "waf_version;event_rules_version;rule_type:sql_injection", + "waf_version;event_rules_version;rule_type:command_injection;rule_variant:shell", + "waf_version;event_rules_version;rule_type:command_injection;rule_variant:exec", }; } \ No newline at end of file diff --git a/tracer/src/Datadog.Trace/Generated/netstandard2.0/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/RaspRuleTypeMatchExtensions_EnumExtensions.g.cs b/tracer/src/Datadog.Trace/Generated/netstandard2.0/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/RaspRuleTypeMatchExtensions_EnumExtensions.g.cs new file mode 100644 index 000000000000..0fdc8d77792a --- /dev/null +++ b/tracer/src/Datadog.Trace/Generated/netstandard2.0/Datadog.Trace.SourceGenerators/EnumExtensionsGenerator/RaspRuleTypeMatchExtensions_EnumExtensions.g.cs @@ -0,0 +1,133 @@ +// +// 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. +// +// + +#nullable enable + +namespace Datadog.Trace.Telemetry.Metrics; + +/// +/// Extension methods for +/// +internal static partial class RaspRuleTypeMatchExtensions +{ + /// + /// The number of members in the enum. + /// This is a non-distinct count of defined names. + /// + public const int Length = 15; + + /// + /// Returns the string representation of the value. + /// If the attribute is decorated with a [Description] attribute, then + /// uses the provided value. Otherwise uses the name of the member, equivalent to + /// calling ToString() on . + /// + /// The value to retrieve the string value for + /// The string representation of the value + public static string ToStringFast(this Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch value) + => value switch + { + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.LfiSuccess => "waf_version;event_rules_version;block:success;rule_type:lfi", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SsrfSuccess => "waf_version;event_rules_version;block:success;rule_type:ssrf", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SQlISuccess => "waf_version;event_rules_version;block:success;rule_type:sql_injection", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionShellSuccess => "waf_version;event_rules_version;block:success;rule_type:command_injection;rule_variant:shell", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionExecSuccess => "waf_version;event_rules_version;block:success;rule_type:command_injection;rule_variant:exec", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.LfiFailure => "waf_version;event_rules_version;block:failure;rule_type:lfi", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SsrfFailure => "waf_version;event_rules_version;block:failure;rule_type:ssrf", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SQlIFailure => "waf_version;event_rules_version;block:failure;rule_type:sql_injection", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionShellFailure => "waf_version;event_rules_version;block:failure;rule_type:command_injection;rule_variant:shell", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionExecFailure => "waf_version;event_rules_version;block:failure;rule_type:command_injection;rule_variant:exec", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.LfiIrrelevant => "waf_version;event_rules_version;block:irrelevant;rule_type:lfi", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SsrfIrrelevant => "waf_version;event_rules_version;block:irrelevant;rule_type:ssrf", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SQlIIrrelevant => "waf_version;event_rules_version;block:irrelevant;rule_type:sql_injection", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionShellIrrelevant => "waf_version;event_rules_version;block:irrelevant;rule_type:command_injection;rule_variant:shell", + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionExecIrrelevant => "waf_version;event_rules_version;block:irrelevant;rule_type:command_injection;rule_variant:exec", + _ => value.ToString(), + }; + + /// + /// Retrieves an array of the values of the members defined in + /// . + /// Note that this returns a new array with every invocation, so + /// should be cached if appropriate. + /// + /// An array of the values defined in + public static Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch[] GetValues() + => new [] + { + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.LfiSuccess, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SsrfSuccess, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SQlISuccess, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionShellSuccess, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionExecSuccess, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.LfiFailure, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SsrfFailure, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SQlIFailure, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionShellFailure, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionExecFailure, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.LfiIrrelevant, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SsrfIrrelevant, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SQlIIrrelevant, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionShellIrrelevant, + Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionExecIrrelevant, + }; + + /// + /// Retrieves an array of the names of the members defined in + /// . + /// Note that this returns a new array with every invocation, so + /// should be cached if appropriate. + /// Ignores [Description] definitions. + /// + /// An array of the names of the members defined in + public static string[] GetNames() + => new [] + { + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.LfiSuccess), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SsrfSuccess), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SQlISuccess), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionShellSuccess), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionExecSuccess), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.LfiFailure), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SsrfFailure), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SQlIFailure), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionShellFailure), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionExecFailure), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.LfiIrrelevant), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SsrfIrrelevant), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.SQlIIrrelevant), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionShellIrrelevant), + nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch.CommandInjectionExecIrrelevant), + }; + + /// + /// Retrieves an array of the names of the members defined in + /// . + /// Note that this returns a new array with every invocation, so + /// should be cached if appropriate. + /// Uses [Description] definition if available, otherwise uses the name of the property + /// + /// An array of the names of the members defined in + public static string[] GetDescriptions() + => new [] + { + "waf_version;event_rules_version;block:success;rule_type:lfi", + "waf_version;event_rules_version;block:success;rule_type:ssrf", + "waf_version;event_rules_version;block:success;rule_type:sql_injection", + "waf_version;event_rules_version;block:success;rule_type:command_injection;rule_variant:shell", + "waf_version;event_rules_version;block:success;rule_type:command_injection;rule_variant:exec", + "waf_version;event_rules_version;block:failure;rule_type:lfi", + "waf_version;event_rules_version;block:failure;rule_type:ssrf", + "waf_version;event_rules_version;block:failure;rule_type:sql_injection", + "waf_version;event_rules_version;block:failure;rule_type:command_injection;rule_variant:shell", + "waf_version;event_rules_version;block:failure;rule_type:command_injection;rule_variant:exec", + "waf_version;event_rules_version;block:irrelevant;rule_type:lfi", + "waf_version;event_rules_version;block:irrelevant;rule_type:ssrf", + "waf_version;event_rules_version;block:irrelevant;rule_type:sql_injection", + "waf_version;event_rules_version;block:irrelevant;rule_type:command_injection;rule_variant:shell", + "waf_version;event_rules_version;block:irrelevant;rule_type:command_injection;rule_variant:exec", + }; +} \ No newline at end of file diff --git a/tracer/src/Datadog.Trace/Generated/netstandard2.0/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/CiVisibilityMetricsTelemetryCollector_Count.g.cs b/tracer/src/Datadog.Trace/Generated/netstandard2.0/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/CiVisibilityMetricsTelemetryCollector_Count.g.cs index 363a5e43830a..7500ae6cf042 100644 --- a/tracer/src/Datadog.Trace/Generated/netstandard2.0/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/CiVisibilityMetricsTelemetryCollector_Count.g.cs +++ b/tracer/src/Datadog.Trace/Generated/netstandard2.0/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/CiVisibilityMetricsTelemetryCollector_Count.g.cs @@ -156,7 +156,7 @@ public void RecordCountRaspRuleEval(Datadog.Trace.Telemetry.Metrics.MetricTags.R { } - public void RecordCountRaspRuleMatch(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType tag, int increment = 1) + public void RecordCountRaspRuleMatch(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch tag, int increment = 1) { } diff --git a/tracer/src/Datadog.Trace/Generated/netstandard2.0/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/IMetricsTelemetryCollector_Count.g.cs b/tracer/src/Datadog.Trace/Generated/netstandard2.0/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/IMetricsTelemetryCollector_Count.g.cs index 1f009e0918d2..6217252b104c 100644 --- a/tracer/src/Datadog.Trace/Generated/netstandard2.0/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/IMetricsTelemetryCollector_Count.g.cs +++ b/tracer/src/Datadog.Trace/Generated/netstandard2.0/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/IMetricsTelemetryCollector_Count.g.cs @@ -81,7 +81,7 @@ internal partial interface IMetricsTelemetryCollector public void RecordCountRaspRuleEval(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType tag, int increment = 1); - public void RecordCountRaspRuleMatch(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType tag, int increment = 1); + public void RecordCountRaspRuleMatch(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch tag, int increment = 1); public void RecordCountRaspTimeout(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType tag, int increment = 1); diff --git a/tracer/src/Datadog.Trace/Generated/netstandard2.0/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/MetricsTelemetryCollector_Count.g.cs b/tracer/src/Datadog.Trace/Generated/netstandard2.0/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/MetricsTelemetryCollector_Count.g.cs index 9da1f3508715..37ecde449b32 100644 --- a/tracer/src/Datadog.Trace/Generated/netstandard2.0/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/MetricsTelemetryCollector_Count.g.cs +++ b/tracer/src/Datadog.Trace/Generated/netstandard2.0/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/MetricsTelemetryCollector_Count.g.cs @@ -11,7 +11,7 @@ namespace Datadog.Trace.Telemetry; internal partial class MetricsTelemetryCollector { - private const int CountLength = 613; + private const int CountLength = 623; /// /// Creates the buffer for the values. @@ -575,34 +575,44 @@ private static AggregatedMetric[] GetCountBuffer() new(new[] { "truncation_reason:list_or_map_too_large" }), new(new[] { "truncation_reason:object_too_deep" }), // rasp.rule.eval, index = 520 - new(new[] { "waf_version", "rule_type:lfi" }), - new(new[] { "waf_version", "rule_type:ssrf" }), - new(new[] { "waf_version", "rule_type:sql_injection" }), - new(new[] { "waf_version", "rule_type:command_injection", "rule_variant:shell" }), - new(new[] { "waf_version", "rule_type:command_injection", "rule_variant:exec" }), + new(new[] { "waf_version", "event_rules_version", "rule_type:lfi" }), + new(new[] { "waf_version", "event_rules_version", "rule_type:ssrf" }), + new(new[] { "waf_version", "event_rules_version", "rule_type:sql_injection" }), + new(new[] { "waf_version", "event_rules_version", "rule_type:command_injection", "rule_variant:shell" }), + new(new[] { "waf_version", "event_rules_version", "rule_type:command_injection", "rule_variant:exec" }), // rasp.rule.match, index = 525 - new(new[] { "waf_version", "rule_type:lfi" }), - new(new[] { "waf_version", "rule_type:ssrf" }), - new(new[] { "waf_version", "rule_type:sql_injection" }), - new(new[] { "waf_version", "rule_type:command_injection", "rule_variant:shell" }), - new(new[] { "waf_version", "rule_type:command_injection", "rule_variant:exec" }), - // rasp.timeout, index = 530 - new(new[] { "waf_version", "rule_type:lfi" }), - new(new[] { "waf_version", "rule_type:ssrf" }), - new(new[] { "waf_version", "rule_type:sql_injection" }), - new(new[] { "waf_version", "rule_type:command_injection", "rule_variant:shell" }), - new(new[] { "waf_version", "rule_type:command_injection", "rule_variant:exec" }), - // instrum.user_auth.missing_user_id, index = 535 + new(new[] { "waf_version", "event_rules_version", "block:success", "rule_type:lfi" }), + new(new[] { "waf_version", "event_rules_version", "block:success", "rule_type:ssrf" }), + new(new[] { "waf_version", "event_rules_version", "block:success", "rule_type:sql_injection" }), + new(new[] { "waf_version", "event_rules_version", "block:success", "rule_type:command_injection", "rule_variant:shell" }), + new(new[] { "waf_version", "event_rules_version", "block:success", "rule_type:command_injection", "rule_variant:exec" }), + new(new[] { "waf_version", "event_rules_version", "block:failure", "rule_type:lfi" }), + new(new[] { "waf_version", "event_rules_version", "block:failure", "rule_type:ssrf" }), + new(new[] { "waf_version", "event_rules_version", "block:failure", "rule_type:sql_injection" }), + new(new[] { "waf_version", "event_rules_version", "block:failure", "rule_type:command_injection", "rule_variant:shell" }), + new(new[] { "waf_version", "event_rules_version", "block:failure", "rule_type:command_injection", "rule_variant:exec" }), + new(new[] { "waf_version", "event_rules_version", "block:irrelevant", "rule_type:lfi" }), + new(new[] { "waf_version", "event_rules_version", "block:irrelevant", "rule_type:ssrf" }), + new(new[] { "waf_version", "event_rules_version", "block:irrelevant", "rule_type:sql_injection" }), + new(new[] { "waf_version", "event_rules_version", "block:irrelevant", "rule_type:command_injection", "rule_variant:shell" }), + new(new[] { "waf_version", "event_rules_version", "block:irrelevant", "rule_type:command_injection", "rule_variant:exec" }), + // rasp.timeout, index = 540 + new(new[] { "waf_version", "event_rules_version", "rule_type:lfi" }), + new(new[] { "waf_version", "event_rules_version", "rule_type:ssrf" }), + new(new[] { "waf_version", "event_rules_version", "rule_type:sql_injection" }), + new(new[] { "waf_version", "event_rules_version", "rule_type:command_injection", "rule_variant:shell" }), + new(new[] { "waf_version", "event_rules_version", "rule_type:command_injection", "rule_variant:exec" }), + // instrum.user_auth.missing_user_id, index = 545 new(new[] { "framework:aspnetcore_identity", "event_type:login_success" }), new(new[] { "framework:aspnetcore_identity", "event_type:login_failure" }), new(new[] { "framework:aspnetcore_identity", "event_type:signup" }), new(new[] { "framework:unknown", "event_type:signup" }), - // instrum.user_auth.missing_user_login, index = 539 + // instrum.user_auth.missing_user_login, index = 549 new(new[] { "framework:aspnetcore_identity", "event_type:login_success" }), new(new[] { "framework:aspnetcore_identity", "event_type:login_failure" }), new(new[] { "framework:aspnetcore_identity", "event_type:signup" }), new(new[] { "framework:unknown", "event_type:signup" }), - // executed.source, index = 543 + // executed.source, index = 553 new(new[] { "source_type:http.request.body" }), new(new[] { "source_type:http.request.path" }), new(new[] { "source_type:http.request.parameter.name" }), @@ -617,9 +627,9 @@ private static AggregatedMetric[] GetCountBuffer() new(new[] { "source_type:http.request.uri" }), new(new[] { "source_type:grpc.request.body" }), new(new[] { "source_type:sql.row.value" }), - // executed.propagation, index = 557 + // executed.propagation, index = 567 new(null), - // executed.sink, index = 558 + // executed.sink, index = 568 new(new[] { "vulnerability_type:none" }), new(new[] { "vulnerability_type:weak_cipher" }), new(new[] { "vulnerability_type:weak_hash" }), @@ -647,9 +657,9 @@ private static AggregatedMetric[] GetCountBuffer() new(new[] { "vulnerability_type:directory_listing_leak" }), new(new[] { "vulnerability_type:session_timeout" }), new(new[] { "vulnerability_type:email_html_injection" }), - // request.tainted, index = 585 + // request.tainted, index = 595 new(null), - // suppressed.vulnerabilities, index = 586 + // suppressed.vulnerabilities, index = 596 new(new[] { "vulnerability_type:none" }), new(new[] { "vulnerability_type:weak_cipher" }), new(new[] { "vulnerability_type:weak_hash" }), @@ -685,7 +695,7 @@ private static AggregatedMetric[] GetCountBuffer() /// It is equal to the cardinality of the tag combinations (or 1 if there are no tags) /// private static int[] CountEntryCounts { get; } - = new int[]{ 4, 80, 1, 3, 4, 2, 2, 4, 1, 1, 1, 22, 3, 2, 5, 5, 2, 1, 22, 3, 90, 90, 2, 44, 6, 1, 1, 80, 1, 22, 3, 2, 2, 5, 3, 5, 5, 5, 4, 4, 14, 1, 27, 1, 27, }; + = new int[]{ 4, 80, 1, 3, 4, 2, 2, 4, 1, 1, 1, 22, 3, 2, 5, 5, 2, 1, 22, 3, 90, 90, 2, 44, 6, 1, 1, 80, 1, 22, 3, 2, 2, 5, 3, 5, 15, 5, 4, 4, 14, 1, 27, 1, 27, }; public void RecordCountLogCreated(Datadog.Trace.Telemetry.Metrics.MetricTags.LogLevel tag, int increment = 1) { @@ -895,7 +905,7 @@ public void RecordCountRaspRuleEval(Datadog.Trace.Telemetry.Metrics.MetricTags.R Interlocked.Add(ref _buffer.Count[index], increment); } - public void RecordCountRaspRuleMatch(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType tag, int increment = 1) + public void RecordCountRaspRuleMatch(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch tag, int increment = 1) { var index = 525 + (int)tag; Interlocked.Add(ref _buffer.Count[index], increment); @@ -903,47 +913,47 @@ public void RecordCountRaspRuleMatch(Datadog.Trace.Telemetry.Metrics.MetricTags. public void RecordCountRaspTimeout(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType tag, int increment = 1) { - var index = 530 + (int)tag; + var index = 540 + (int)tag; Interlocked.Add(ref _buffer.Count[index], increment); } public void RecordCountMissingUserId(Datadog.Trace.Telemetry.Metrics.MetricTags.AuthenticationFrameworkWithEventType tag, int increment = 1) { - var index = 535 + (int)tag; + var index = 545 + (int)tag; Interlocked.Add(ref _buffer.Count[index], increment); } public void RecordCountMissingUserLogin(Datadog.Trace.Telemetry.Metrics.MetricTags.AuthenticationFrameworkWithEventType tag, int increment = 1) { - var index = 539 + (int)tag; + var index = 549 + (int)tag; Interlocked.Add(ref _buffer.Count[index], increment); } public void RecordCountIastExecutedSources(Datadog.Trace.Telemetry.Metrics.MetricTags.IastSourceType tag, int increment = 1) { - var index = 543 + (int)tag; + var index = 553 + (int)tag; Interlocked.Add(ref _buffer.Count[index], increment); } public void RecordCountIastExecutedPropagations(int increment = 1) { - Interlocked.Add(ref _buffer.Count[557], increment); + Interlocked.Add(ref _buffer.Count[567], increment); } public void RecordCountIastExecutedSinks(Datadog.Trace.Telemetry.Metrics.MetricTags.IastVulnerabilityType tag, int increment = 1) { - var index = 558 + (int)tag; + var index = 568 + (int)tag; Interlocked.Add(ref _buffer.Count[index], increment); } public void RecordCountIastRequestTainted(int increment = 1) { - Interlocked.Add(ref _buffer.Count[585], increment); + Interlocked.Add(ref _buffer.Count[595], increment); } public void RecordCountIastSuppressedVulnerabilities(Datadog.Trace.Telemetry.Metrics.MetricTags.IastVulnerabilityType tag, int increment = 1) { - var index = 586 + (int)tag; + var index = 596 + (int)tag; Interlocked.Add(ref _buffer.Count[index], increment); } } \ No newline at end of file diff --git a/tracer/src/Datadog.Trace/Generated/netstandard2.0/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/NullMetricsTelemetryCollector_Count.g.cs b/tracer/src/Datadog.Trace/Generated/netstandard2.0/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/NullMetricsTelemetryCollector_Count.g.cs index eb750e63a8ad..9b6efbd64cec 100644 --- a/tracer/src/Datadog.Trace/Generated/netstandard2.0/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/NullMetricsTelemetryCollector_Count.g.cs +++ b/tracer/src/Datadog.Trace/Generated/netstandard2.0/Datadog.Trace.SourceGenerators/TelemetryMetricGenerator/NullMetricsTelemetryCollector_Count.g.cs @@ -156,7 +156,7 @@ public void RecordCountRaspRuleEval(Datadog.Trace.Telemetry.Metrics.MetricTags.R { } - public void RecordCountRaspRuleMatch(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleType tag, int increment = 1) + public void RecordCountRaspRuleMatch(Datadog.Trace.Telemetry.Metrics.MetricTags.RaspRuleTypeMatch tag, int increment = 1) { } diff --git a/tracer/src/Datadog.Trace/Telemetry/Metrics/Count.cs b/tracer/src/Datadog.Trace/Telemetry/Metrics/Count.cs index 78819e10b067..9f9a84b7e7de 100644 --- a/tracer/src/Datadog.Trace/Telemetry/Metrics/Count.cs +++ b/tracer/src/Datadog.Trace/Telemetry/Metrics/Count.cs @@ -211,7 +211,7 @@ internal enum Count /// /// Counts the number of times a rule type has a match. Note that this can be inferred through the events sent to the backend. /// - [TelemetryMetric("rasp.rule.match", isCommon: true, NS.ASM)] RaspRuleMatch, + [TelemetryMetric("rasp.rule.match", isCommon: true, NS.ASM)] RaspRuleMatch, /// /// Counts the number of times a timeout was hit when evaluating a specific rule type. diff --git a/tracer/src/Datadog.Trace/Telemetry/Metrics/MetricTags.cs b/tracer/src/Datadog.Trace/Telemetry/Metrics/MetricTags.cs index 99ac628c0e09..3d60efb3dbb8 100644 --- a/tracer/src/Datadog.Trace/Telemetry/Metrics/MetricTags.cs +++ b/tracer/src/Datadog.Trace/Telemetry/Metrics/MetricTags.cs @@ -298,11 +298,31 @@ public enum WafStatus [EnumExtensions] public enum RaspRuleType { - [Description("waf_version;rule_type:lfi")] Lfi = 0, - [Description("waf_version;rule_type:ssrf")] Ssrf = 1, - [Description("waf_version;rule_type:sql_injection")] SQlI = 2, - [Description("waf_version;rule_type:command_injection;rule_variant:shell")] CommandInjectionShell = 3, - [Description("waf_version;rule_type:command_injection;rule_variant:exec")] CommandInjectionExec = 4, + [Description("waf_version;event_rules_version;rule_type:lfi")] Lfi = 0, + [Description("waf_version;event_rules_version;rule_type:ssrf")] Ssrf = 1, + [Description("waf_version;event_rules_version;rule_type:sql_injection")] SQlI = 2, + [Description("waf_version;event_rules_version;rule_type:command_injection;rule_variant:shell")] CommandInjectionShell = 3, + [Description("waf_version;event_rules_version;rule_type:command_injection;rule_variant:exec")] CommandInjectionExec = 4, + } + + [EnumExtensions] + public enum RaspRuleTypeMatch + { + [Description("waf_version;event_rules_version;block:success;rule_type:lfi")] LfiSuccess = 0, + [Description("waf_version;event_rules_version;block:success;rule_type:ssrf")] SsrfSuccess = 1, + [Description("waf_version;event_rules_version;block:success;rule_type:sql_injection")] SQlISuccess = 2, + [Description("waf_version;event_rules_version;block:success;rule_type:command_injection;rule_variant:shell")] CommandInjectionShellSuccess = 3, + [Description("waf_version;event_rules_version;block:success;rule_type:command_injection;rule_variant:exec")] CommandInjectionExecSuccess = 4, + [Description("waf_version;event_rules_version;block:failure;rule_type:lfi")] LfiFailure = 5, + [Description("waf_version;event_rules_version;block:failure;rule_type:ssrf")] SsrfFailure = 6, + [Description("waf_version;event_rules_version;block:failure;rule_type:sql_injection")] SQlIFailure = 7, + [Description("waf_version;event_rules_version;block:failure;rule_type:command_injection;rule_variant:shell")] CommandInjectionShellFailure = 8, + [Description("waf_version;event_rules_version;block:failure;rule_type:command_injection;rule_variant:exec")] CommandInjectionExecFailure = 9, + [Description("waf_version;event_rules_version;block:irrelevant;rule_type:lfi")] LfiIrrelevant = 10, + [Description("waf_version;event_rules_version;block:irrelevant;rule_type:ssrf")] SsrfIrrelevant = 11, + [Description("waf_version;event_rules_version;block:irrelevant;rule_type:sql_injection")] SQlIIrrelevant = 12, + [Description("waf_version;event_rules_version;block:irrelevant;rule_type:command_injection;rule_variant:shell")] CommandInjectionShellIrrelevant = 13, + [Description("waf_version;event_rules_version;block:irrelevant;rule_type:command_injection;rule_variant:exec")] CommandInjectionExecIrrelevant = 14, } public enum TruncationReason diff --git a/tracer/test/Datadog.Trace.Security.Unit.Tests/SecurityCoordinatorTests.cs b/tracer/test/Datadog.Trace.Security.Unit.Tests/SecurityCoordinatorTests.cs index cb584537e0d6..8522fcea9e1f 100644 --- a/tracer/test/Datadog.Trace.Security.Unit.Tests/SecurityCoordinatorTests.cs +++ b/tracer/test/Datadog.Trace.Security.Unit.Tests/SecurityCoordinatorTests.cs @@ -155,7 +155,7 @@ public void GivenSecurityCoordinatorInstanceWithResponseHeadersWritten_WheBlock_ try { - securityCoordinator?.ReportAndBlock(resultMock.Object); + securityCoordinator?.ReportAndBlock(resultMock.Object, () => Console.WriteLine("Telemetry reported")); Assert.Fail("Expected BlockException"); } catch (BlockException) diff --git a/tracer/test/Datadog.Trace.Tests/Telemetry/Collectors/MetricsTelemetryCollectorTests.cs b/tracer/test/Datadog.Trace.Tests/Telemetry/Collectors/MetricsTelemetryCollectorTests.cs index efe2d4ad1bb4..c7d60c2678c3 100644 --- a/tracer/test/Datadog.Trace.Tests/Telemetry/Collectors/MetricsTelemetryCollectorTests.cs +++ b/tracer/test/Datadog.Trace.Tests/Telemetry/Collectors/MetricsTelemetryCollectorTests.cs @@ -107,7 +107,7 @@ static void IncrementOpenTelemetryConfigMetrics(MetricsTelemetryCollector collec collector.RecordCountWafInit(MetricTags.WafStatus.Success, 4); collector.RecordCountWafRequests(MetricTags.WafAnalysis.Normal, 5); collector.RecordCountRaspRuleEval(MetricTags.RaspRuleType.Lfi, 5); - collector.RecordCountRaspRuleMatch(MetricTags.RaspRuleType.Lfi, 3); + collector.RecordCountRaspRuleMatch(MetricTags.RaspRuleTypeMatch.LfiSuccess, 3); collector.RecordCountRaspTimeout(MetricTags.RaspRuleType.Lfi, 2); collector.RecordGaugeStatsBuckets(234); collector.RecordDistributionSharedInitTime(MetricTags.InitializationComponent.Total, 23); @@ -261,7 +261,7 @@ static void IncrementOpenTelemetryConfigMetrics(MetricsTelemetryCollector collec Metric = Count.RaspRuleEval.GetName(), Points = new[] { new { Value = 5 } }, Type = TelemetryMetricType.Count, - Tags = new[] { expectedWafTag, "rule_type:lfi" }, + Tags = new[] { expectedWafTag, expectedRulesetTag, "rule_type:lfi" }, Common = true, Namespace = NS.ASM, }, @@ -270,7 +270,7 @@ static void IncrementOpenTelemetryConfigMetrics(MetricsTelemetryCollector collec Metric = Count.RaspRuleMatch.GetName(), Points = new[] { new { Value = 3 } }, Type = TelemetryMetricType.Count, - Tags = new[] { expectedWafTag, "rule_type:lfi" }, + Tags = new[] { expectedWafTag, expectedRulesetTag, "block:success", "rule_type:lfi" }, Common = true, Namespace = NS.ASM, }, @@ -279,7 +279,7 @@ static void IncrementOpenTelemetryConfigMetrics(MetricsTelemetryCollector collec Metric = Count.RaspTimeout.GetName(), Points = new[] { new { Value = 2 } }, Type = TelemetryMetricType.Count, - Tags = new[] { expectedWafTag, "rule_type:lfi" }, + Tags = new[] { expectedWafTag, expectedRulesetTag, "rule_type:lfi" }, Common = true, Namespace = NS.ASM, }, diff --git a/tracer/test/Datadog.Trace.Tests/Telemetry/Metrics/common_metrics.json b/tracer/test/Datadog.Trace.Tests/Telemetry/Metrics/common_metrics.json index 8c5cb75ff461..33f351f54cac 100644 --- a/tracer/test/Datadog.Trace.Tests/Telemetry/Metrics/common_metrics.json +++ b/tracer/test/Datadog.Trace.Tests/Telemetry/Metrics/common_metrics.json @@ -730,6 +730,7 @@ "rasp.rule.eval": { "tags": [ "waf_version", + "event_rules_version", "rule_type", "rule_variant" ], @@ -742,8 +743,10 @@ "rasp.rule.match": { "tags": [ "waf_version", + "event_rules_version", "rule_type", - "rule_variant" + "rule_variant", + "block" ], "metric_type": "count", "data_type": "matches", @@ -754,6 +757,7 @@ "rasp.timeout": { "tags": [ "waf_version", + "event_rules_version", "rule_type", "rule_variant" ],