diff --git a/tracer/build/_build/Build.Steps.cs b/tracer/build/_build/Build.Steps.cs index 031fd7ead97c..11bdbffa506a 100644 --- a/tracer/build/_build/Build.Steps.cs +++ b/tracer/build/_build/Build.Steps.cs @@ -624,7 +624,7 @@ async Task DownloadWafVersion(string libddwafVersion = null, string uncompressFo .SetConfiguration(BuildConfiguration) .SetTargetPlatformAnyCPU() .EnableNoBuild() - .EnableNoRestore() + //.EnableNoRestore() .CombineWith(targetFrameworks, (p, framework) => p .SetFramework(framework) .SetOutput(MonitoringHomeDirectory / framework)) @@ -1365,7 +1365,7 @@ _ when path.Contains("dependency-libs") => false, .Where(project => Solution.GetProject(project).GetTargetFrameworks().Contains(Framework)) ; - DotnetBuild(projects, framework: Framework); + DotnetBuild(projects, framework: Framework, noRestore: false); }); Target CompileSamplesWindows => _ => _ @@ -1567,8 +1567,8 @@ _ when exclude.Contains(x.project.Path) => false, .SetFramework(Framework) //.WithMemoryDumpAfter(timeoutInMinutes: 30) .EnableCrashDumps() - .EnableNoRestore() - .EnableNoBuild() + // .EnableNoRestore() + // .EnableNoBuild() .SetTestTargetPlatform(TargetPlatform) .SetIsDebugRun(isDebugRun) .SetProcessEnvironmentVariable("MonitoringHomeDirectory", MonitoringHomeDirectory) @@ -1590,8 +1590,8 @@ _ when exclude.Contains(x.project.Path) => false, .SetTargetPlatformAnyCPU() .SetFramework(Framework) //.WithMemoryDumpAfter(timeoutInMinutes: 30) - .EnableNoRestore() - .EnableNoBuild() + // .EnableNoRestore() + // .EnableNoBuild() .SetFilter(string.IsNullOrWhiteSpace(Filter) ? "(RunOnWindows=True)&(LoadFromGAC!=True)&(IIS!=True)&(Category!=AzureFunctions)&(SkipInCI!=True)" : Filter) .SetTestTargetPlatform(TargetPlatform) .SetIsDebugRun(isDebugRun) @@ -2104,8 +2104,8 @@ var name when multiPackageProjects.Contains(name) => false, // Run these ones in parallel DotNetTest(config => config .SetConfiguration(BuildConfiguration) - .EnableNoRestore() - .EnableNoBuild() + // .EnableNoRestore() + // .EnableNoBuild() .SetFramework(Framework) //.WithMemoryDumpAfter(timeoutInMinutes: 30) .EnableCrashDumps() @@ -2127,8 +2127,8 @@ var name when multiPackageProjects.Contains(name) => false, // Run this one separately so we can tail output DotNetTest(config => config .SetConfiguration(BuildConfiguration) - .EnableNoRestore() - .EnableNoBuild() + // .EnableNoRestore() + // .EnableNoBuild() .SetFramework(Framework) //.WithMemoryDumpAfter(timeoutInMinutes: 30) .EnableCrashDumps() @@ -2185,8 +2185,8 @@ var name when multiPackageProjects.Contains(name) => false, // Run these ones in parallel DotNetTest(config => config .SetConfiguration(BuildConfiguration) - .EnableNoRestore() - .EnableNoBuild() + // .EnableNoRestore() + // .EnableNoBuild() .SetFramework(Framework) //.WithMemoryDumpAfter(timeoutInMinutes: 30) .EnableCrashDumps() @@ -2209,8 +2209,8 @@ var name when multiPackageProjects.Contains(name) => false, // Run this one separately so we can tail output DotNetTest(config => config .SetConfiguration(BuildConfiguration) - .EnableNoRestore() - .EnableNoBuild() + // .EnableNoRestore() + // .EnableNoBuild() .SetFramework(Framework) //.WithMemoryDumpAfter(timeoutInMinutes: 30) .EnableCrashDumps() diff --git a/tracer/missing-nullability-files.csv b/tracer/missing-nullability-files.csv index 7d88c7389565..a434975dbfd3 100644 --- a/tracer/missing-nullability-files.csv +++ b/tracer/missing-nullability-files.csv @@ -141,6 +141,15 @@ src/Datadog.Trace/HttpOverStreams/IHttpContent.cs src/Datadog.Trace/Iast/Iast.cs src/Datadog.Trace/Iast/ITaintedMap.cs src/Datadog.Trace/Iast/SourceType.cs +src/Datadog.Trace/LibDatadog/AgentResponseCallback.cs +src/Datadog.Trace/LibDatadog/ByteSlice.cs +src/Datadog.Trace/LibDatadog/CharSlice.cs +src/Datadog.Trace/LibDatadog/ErrorTag.cs +src/Datadog.Trace/LibDatadog/LibDatadogException.cs +src/Datadog.Trace/LibDatadog/MaybeError.cs +src/Datadog.Trace/LibDatadog/TraceExporter.cs +src/Datadog.Trace/LibDatadog/TraceExporterInputFormat.cs +src/Datadog.Trace/LibDatadog/TraceExporterOutputFormat.cs src/Datadog.Trace/PlatformHelpers/AspNetCoreHttpRequestHandler.cs src/Datadog.Trace/PlatformHelpers/AzureContext.cs src/Datadog.Trace/PlatformHelpers/ContainerMetadata.cs diff --git a/tracer/src/Datadog.Trace/Agent/AgentWriter.cs b/tracer/src/Datadog.Trace/Agent/AgentWriter.cs index b72bf50d3a07..ea0693ddad74 100644 --- a/tracer/src/Datadog.Trace/Agent/AgentWriter.cs +++ b/tracer/src/Datadog.Trace/Agent/AgentWriter.cs @@ -97,6 +97,14 @@ internal AgentWriter(IApi api, IStatsAggregator statsAggregator, IDogStatsd stat _appsecStandaloneEnabled = appsecStandaloneEnabled; } + ~AgentWriter() + { + if (_api is IDisposable disposableApi) + { + disposableApi.Dispose(); + } + } + internal event Action Flushed; internal SpanBuffer ActiveBuffer => _activeBuffer; diff --git a/tracer/src/Datadog.Trace/Configuration/ConfigurationKeys.cs b/tracer/src/Datadog.Trace/Configuration/ConfigurationKeys.cs index 02e24ec12ad8..bcd5a3254eb6 100644 --- a/tracer/src/Datadog.Trace/Configuration/ConfigurationKeys.cs +++ b/tracer/src/Datadog.Trace/Configuration/ConfigurationKeys.cs @@ -253,6 +253,12 @@ internal static partial class ConfigurationKeys /// public const string RuntimeMetricsEnabled = "DD_RUNTIME_METRICS_ENABLED"; + /// + /// Use libdatadog data pipeline to send traces. + /// Default value is false (disabled). + /// + public const string DataPipelineEnabled = "DD_DATA_PIPELINE_ENABLED"; + /// /// Configuration key for when a standalone instance of the Trace Agent needs to be started. /// diff --git a/tracer/src/Datadog.Trace/Configuration/TracerSettings.cs b/tracer/src/Datadog.Trace/Configuration/TracerSettings.cs index 3e548c8c8413..9f9bba031d4e 100644 --- a/tracer/src/Datadog.Trace/Configuration/TracerSettings.cs +++ b/tracer/src/Datadog.Trace/Configuration/TracerSettings.cs @@ -52,6 +52,7 @@ public record TracerSettings private readonly double? _globalSamplingRate; private readonly bool _runtimeMetricsEnabled; private readonly string? _customSamplingRules; + private readonly bool _dataPipelineEnabled; /// /// Initializes a new instance of the class with default values. @@ -329,7 +330,11 @@ _ when x.ToBoolean() is { } boolean => boolean, _runtimeMetricsEnabled = config .WithKeys(ConfigurationKeys.RuntimeMetricsEnabled) .AsBoolResult() - .OverrideWith(in otelRuntimeMetricsEnabled, ErrorLog, defaultValue: false); + .OverrideWith(in otelRuntimeMetricsEnabled, ErrorLog, defaultValue: true); + + _dataPipelineEnabled = config + .WithKeys(ConfigurationKeys.DataPipelineEnabled) + .AsBool(defaultValue: false); // We should also be writing telemetry for OTEL_LOGS_EXPORTER similar to OTEL_METRICS_EXPORTER, but we don't have a corresponding Datadog config // When we do, we can insert that here @@ -915,6 +920,12 @@ public bool DiagnosticSourceEnabled /// internal bool RuntimeMetricsEnabled => DynamicSettings.RuntimeMetricsEnabled ?? _runtimeMetricsEnabled; + /// + /// Gets a value indicating whether libdatadog data pipeline + /// is enabled. + /// + internal bool DataPipelineEnabled => _dataPipelineEnabled; + /// /// Gets the comma separated list of url patterns to skip tracing. /// diff --git a/tracer/src/Datadog.Trace/Datadog.Trace.csproj b/tracer/src/Datadog.Trace/Datadog.Trace.csproj index 55b4e4b986e6..200d021855b2 100644 --- a/tracer/src/Datadog.Trace/Datadog.Trace.csproj +++ b/tracer/src/Datadog.Trace/Datadog.Trace.csproj @@ -54,6 +54,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/tracer/src/Datadog.Trace/LibDatadog/ByteSlice.cs b/tracer/src/Datadog.Trace/LibDatadog/ByteSlice.cs new file mode 100644 index 000000000000..208def42e4af --- /dev/null +++ b/tracer/src/Datadog.Trace/LibDatadog/ByteSlice.cs @@ -0,0 +1,26 @@ +// +// 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. +// + +using System; +using System.Runtime.InteropServices; + +namespace Datadog.Trace.LibDatadog; + +/// +/// Represents a slice of a byte array in memory. +/// +[StructLayout(LayoutKind.Sequential)] +internal struct ByteSlice +{ + /// + /// Pointer to the start of the slice. + /// + internal IntPtr Ptr; + + /// + /// Length of the slice. + /// + internal UIntPtr Len; +} diff --git a/tracer/src/Datadog.Trace/LibDatadog/CharSlice.cs b/tracer/src/Datadog.Trace/LibDatadog/CharSlice.cs new file mode 100644 index 000000000000..b1450a0569ce --- /dev/null +++ b/tracer/src/Datadog.Trace/LibDatadog/CharSlice.cs @@ -0,0 +1,53 @@ +// +// 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. +// + +using System; +using System.Runtime.InteropServices; + +namespace Datadog.Trace.LibDatadog; + +/// +/// Represents a slice of a UTF-8 encoded string in memory. +/// +[StructLayout(LayoutKind.Sequential)] +internal struct CharSlice +{ + /// + /// Represents an empty slice. + /// + internal static CharSlice Empty = new(string.Empty); + + /// + /// Pointer to the start of the slice. + /// + internal IntPtr Ptr; + + /// + /// Length of the slice. + /// + internal UIntPtr Len; + + /// + /// Initializes a new instance of the struct. + /// This can be further optimized if we can avoid copying the string to unmanaged memory. + /// + /// The string to copy into memory. + internal CharSlice(string str) + { + // copy over str to unmanaged memory + if (str == null) + { + Ptr = IntPtr.Zero; + Len = UIntPtr.Zero; + } + else + { + var bytes = System.Text.Encoding.UTF8.GetBytes(str); + Ptr = Marshal.AllocHGlobal(bytes.Length); + Marshal.Copy(bytes, 0, Ptr, bytes.Length); + Len = (UIntPtr)bytes.Length; + } + } +} diff --git a/tracer/src/Datadog.Trace/LibDatadog/ErrorCode.cs b/tracer/src/Datadog.Trace/LibDatadog/ErrorCode.cs new file mode 100644 index 000000000000..644493d4e675 --- /dev/null +++ b/tracer/src/Datadog.Trace/LibDatadog/ErrorCode.cs @@ -0,0 +1,32 @@ +// +// 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. +// + +namespace Datadog.Trace.LibDatadog; + +/// +/// Represents error codes that can occur when exporting traces. +/// +internal enum ErrorCode +{ + AddressInUse = 0, + ConnectionAborted = 1, + ConnectionRefused = 2, + ConnectionReset = 3, + HttpBodyFormat = 4, + HttpBodyTooLong = 5, + HttpClient = 6, + HttpParse = 7, + HttpServer = 8, + HttpUnknown = 9, + HttpWrongStatus = 10, + InvalidArgument = 11, + InvalidData = 12, + InvalidInput = 13, + InvalidUrl = 14, + IoError = 15, + NetworkUnknown = 16, + Serde = 17, + TimedOut = 18, +} diff --git a/tracer/src/Datadog.Trace/LibDatadog/ErrorHandle.cs b/tracer/src/Datadog.Trace/LibDatadog/ErrorHandle.cs new file mode 100644 index 000000000000..3435dbc4cc51 --- /dev/null +++ b/tracer/src/Datadog.Trace/LibDatadog/ErrorHandle.cs @@ -0,0 +1,44 @@ +// +// 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. +// + +using System; +using System.Runtime.InteropServices; + +namespace Datadog.Trace.LibDatadog; + +internal class ErrorHandle : SafeHandle +{ + public ErrorHandle() + : base(IntPtr.Zero, true) + { + } + + public ErrorHandle(IntPtr handle) + : base(handle, true) + { + SetHandle(handle); + } + + public override bool IsInvalid => handle == IntPtr.Zero; + + protected override bool ReleaseHandle() + { + TraceExporterNative.ddog_trace_exporter_error_free(handle); + return true; + } + + public TraceExporterException ToException() + { + return new TraceExporterException(Marshal.PtrToStructure(handle)); + } + + public void ThrowIfError() + { + if (!IsInvalid) + { + throw ToException(); + } + } +} diff --git a/tracer/src/Datadog.Trace/LibDatadog/TraceExporter.cs b/tracer/src/Datadog.Trace/LibDatadog/TraceExporter.cs new file mode 100644 index 000000000000..7c947519ead7 --- /dev/null +++ b/tracer/src/Datadog.Trace/LibDatadog/TraceExporter.cs @@ -0,0 +1,57 @@ +// +// 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. +// + +using System; +using System.Runtime.InteropServices; +using System.Threading.Tasks; +using Datadog.Trace.Agent; + +namespace Datadog.Trace.LibDatadog; + +internal class TraceExporter : SafeHandle, IApi +{ + private readonly TraceExporterConfiguration _configuration; + + public TraceExporter(TraceExporterConfiguration configuration) + : base(IntPtr.Zero, true) + { + _configuration = configuration; + var errPtr = TraceExporterNative.ddog_trace_exporter_new(out var ptr, configuration); + errPtr.ThrowIfError(); + SetHandle(ptr); + } + + public override bool IsInvalid => handle == IntPtr.Zero; + + public Task SendTracesAsync(ArraySegment traces, int numberOfTraces, bool statsComputationEnabled, long numberOfDroppedP0Traces, long numberOfDroppedP0Spans, bool appsecStandaloneEnabled) + { + // Pin the array to get a pointer to the data + // This is recommended if using UnsafeAddrOfPinnedArrayElement to avoid the GC moving the array + var tracesHandle = GCHandle.Alloc(traces.Array, GCHandleType.Pinned); + var tracesSlice = new ByteSlice + { + Ptr = Marshal.UnsafeAddrOfPinnedArrayElement(traces.Array, traces.Offset), + Len = (UIntPtr)traces.Count + }; + + var responsePtr = IntPtr.Zero; + using var error = TraceExporterNative.ddog_trace_exporter_send(this, tracesSlice, (UIntPtr)numberOfTraces, ref responsePtr); + tracesHandle.Free(); + error.ThrowIfError(); + + return Task.FromResult(true); + } + + public Task SendStatsAsync(StatsBuffer stats, long bucketDuration) + { + return Task.FromResult(true); + } + + protected override bool ReleaseHandle() + { + TraceExporterNative.ddog_trace_exporter_free(handle); + return true; + } +} diff --git a/tracer/src/Datadog.Trace/LibDatadog/TraceExporterConfiguration.cs b/tracer/src/Datadog.Trace/LibDatadog/TraceExporterConfiguration.cs new file mode 100644 index 000000000000..5f8c2602d9dc --- /dev/null +++ b/tracer/src/Datadog.Trace/LibDatadog/TraceExporterConfiguration.cs @@ -0,0 +1,139 @@ +// +// 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. +// + +using System; +using System.Runtime.InteropServices; + +namespace Datadog.Trace.LibDatadog; + +/// +/// Represents a configuration for the trace exporter. +/// +internal class TraceExporterConfiguration : SafeHandle +{ + private string _url; + private string _traceVersion; + private string _language; + private string _languageVersion; + private string _languageInterpreter; + private string _hostname; + private string _env; + private string _version; + private string _service; + + public TraceExporterConfiguration() + : base(IntPtr.Zero, true) + { + TraceExporterNative.ddog_trace_exporter_config_new(out var ptr); + SetHandle(ptr); + } + + public override bool IsInvalid => handle == IntPtr.Zero; + + public string Url + { + get => _url; + set + { + _url = value; + using var error = TraceExporterNative.ddog_trace_exporter_config_set_url(this, new CharSlice(value)); + error.ThrowIfError(); + } + } + + public string TraceVersion + { + get => _traceVersion; + set + { + _traceVersion = value; + using var error = TraceExporterNative.ddog_trace_exporter_config_set_tracer_version(this, new CharSlice(value)); + error.ThrowIfError(); + } + } + + public string Language + { + get => _language; + set + { + _language = value; + using var error = TraceExporterNative.ddog_trace_exporter_config_set_language(this, new CharSlice(value)); + error.ThrowIfError(); + } + } + + public string LanguageVersion + { + get => _languageVersion; + set + { + _languageVersion = value; + using var error = TraceExporterNative.ddog_trace_exporter_config_set_lang_version(this, new CharSlice(value)); + error.ThrowIfError(); + } + } + + public string LanguageInterpreter + { + get => _languageInterpreter; + set + { + _languageInterpreter = value; + using var error = TraceExporterNative.ddog_trace_exporter_config_set_lang_interpreter(this, new CharSlice(value)); + error.ThrowIfError(); + } + } + + public string Hostname + { + get => _hostname; + set + { + _hostname = value; + using var error = TraceExporterNative.ddog_trace_exporter_config_set_hostname(this, new CharSlice(value)); + error.ThrowIfError(); + } + } + + public string Env + { + get => _env; + set + { + _env = value; + using var error = TraceExporterNative.ddog_trace_exporter_config_set_env(this, new CharSlice(value)); + error.ThrowIfError(); + } + } + + public string Version + { + get => _version; + set + { + _version = value; + using var error = TraceExporterNative.ddog_trace_exporter_config_set_version(this, new CharSlice(value)); + error.ThrowIfError(); + } + } + + public string Service + { + get => _service; + set + { + _service = value; + using var error = TraceExporterNative.ddog_trace_exporter_config_set_service(this, new CharSlice(value)); + error.ThrowIfError(); + } + } + + protected override bool ReleaseHandle() + { + TraceExporterNative.ddog_trace_exporter_config_free(handle); + return true; + } +} diff --git a/tracer/src/Datadog.Trace/LibDatadog/TraceExporterError.cs b/tracer/src/Datadog.Trace/LibDatadog/TraceExporterError.cs new file mode 100644 index 000000000000..e0d1406ba076 --- /dev/null +++ b/tracer/src/Datadog.Trace/LibDatadog/TraceExporterError.cs @@ -0,0 +1,27 @@ +// +// 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. +// + +using System; +using System.Runtime.InteropServices; + +namespace Datadog.Trace.LibDatadog; + +/// +/// Represents errors that can occur when exporting traces. +/// +[StructLayout(LayoutKind.Sequential)] +internal struct TraceExporterError +{ + /// + /// The error code representing the domain of the error. + /// Consumers can use this to determine how to handle the error. + /// + internal ErrorCode Code; + + /// + /// Human-readable error message describing the error. + /// + internal IntPtr Msg; +} diff --git a/tracer/src/Datadog.Trace/LibDatadog/TraceExporterException.cs b/tracer/src/Datadog.Trace/LibDatadog/TraceExporterException.cs new file mode 100644 index 000000000000..4e2497b86955 --- /dev/null +++ b/tracer/src/Datadog.Trace/LibDatadog/TraceExporterException.cs @@ -0,0 +1,23 @@ +// +// 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. +// + +using System; +using System.Runtime.InteropServices; + +namespace Datadog.Trace.LibDatadog; + +/// +/// Represents an exception thrown by the libdatadog library. +/// +internal class TraceExporterException : Exception +{ + public TraceExporterException(TraceExporterError exporterError) + : base(Marshal.PtrToStringAnsi(exporterError.Msg)) + { + ErrorCode = exporterError.Code; + } + + public ErrorCode ErrorCode { get; } +} diff --git a/tracer/src/Datadog.Trace/LibDatadog/TraceExporterInputFormat.cs b/tracer/src/Datadog.Trace/LibDatadog/TraceExporterInputFormat.cs new file mode 100644 index 000000000000..25c4baf6dd04 --- /dev/null +++ b/tracer/src/Datadog.Trace/LibDatadog/TraceExporterInputFormat.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. +// + +namespace Datadog.Trace.LibDatadog; + +/// +/// Represents the format of the input traces, as expected by the trace exporter. +/// +internal enum TraceExporterInputFormat +{ + /// + /// Used when the traces are sent to the agent without processing. The whole payload is sent as is to the agent. + /// + Proxy = 0, + + /// + /// Version 0.4 of the trace exporter format. + /// + V04 = 1, +} diff --git a/tracer/src/Datadog.Trace/LibDatadog/TraceExporterNative.cs b/tracer/src/Datadog.Trace/LibDatadog/TraceExporterNative.cs new file mode 100644 index 000000000000..0dda346653ab --- /dev/null +++ b/tracer/src/Datadog.Trace/LibDatadog/TraceExporterNative.cs @@ -0,0 +1,61 @@ +// +// 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. +// + +using System; +using System.Runtime.InteropServices; + +namespace Datadog.Trace.LibDatadog; + +#pragma warning disable SA1300 +internal class TraceExporterNative +{ + private const string DllName = "datadog_profiling_ffi"; + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + internal static extern ErrorHandle ddog_trace_exporter_new(out IntPtr outHandle, SafeHandle config); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void ddog_trace_exporter_error_free(IntPtr error); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void ddog_trace_exporter_free(IntPtr handle); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + internal static extern ErrorHandle ddog_trace_exporter_send(SafeHandle handle, ByteSlice trace, UIntPtr traceCount, ref IntPtr response); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void ddog_trace_exporter_config_new(out IntPtr outHandle); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + internal static extern void ddog_trace_exporter_config_free(IntPtr handle); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + internal static extern ErrorHandle ddog_trace_exporter_config_set_url(SafeHandle config, CharSlice url); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + internal static extern ErrorHandle ddog_trace_exporter_config_set_tracer_version(SafeHandle config, CharSlice version); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + internal static extern ErrorHandle ddog_trace_exporter_config_set_language(SafeHandle config, CharSlice lang); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + internal static extern ErrorHandle ddog_trace_exporter_config_set_lang_version(SafeHandle config, CharSlice version); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + internal static extern ErrorHandle ddog_trace_exporter_config_set_lang_interpreter(SafeHandle config, CharSlice interpreter); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + internal static extern ErrorHandle ddog_trace_exporter_config_set_hostname(SafeHandle config, CharSlice hostname); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + internal static extern ErrorHandle ddog_trace_exporter_config_set_env(SafeHandle config, CharSlice env); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + internal static extern ErrorHandle ddog_trace_exporter_config_set_version(SafeHandle config, CharSlice version); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + internal static extern ErrorHandle ddog_trace_exporter_config_set_service(SafeHandle config, CharSlice service); +} +#pragma warning restore SA1300 diff --git a/tracer/src/Datadog.Trace/LibDatadog/TraceExporterOutputFormat.cs b/tracer/src/Datadog.Trace/LibDatadog/TraceExporterOutputFormat.cs new file mode 100644 index 000000000000..3cee7f3dd2e9 --- /dev/null +++ b/tracer/src/Datadog.Trace/LibDatadog/TraceExporterOutputFormat.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. +// + +namespace Datadog.Trace.LibDatadog; + +/// +/// Represents the format of the output traces, as expected by the trace exporter. +/// +internal enum TraceExporterOutputFormat +{ + /// + /// Version 0.4 of the trace exporter format. + /// + V04 = 0, + + /// + /// Version 0.7 of the trace exporter format. + /// + V07 = 1, +} diff --git a/tracer/src/Datadog.Trace/TracerManagerFactory.cs b/tracer/src/Datadog.Trace/TracerManagerFactory.cs index 74cb7cbc0b5f..b1910564b8ac 100644 --- a/tracer/src/Datadog.Trace/TracerManagerFactory.cs +++ b/tracer/src/Datadog.Trace/TracerManagerFactory.cs @@ -14,6 +14,7 @@ using Datadog.Trace.ContinuousProfiler; using Datadog.Trace.DataStreamsMonitoring; using Datadog.Trace.DogStatsd; +using Datadog.Trace.LibDatadog; using Datadog.Trace.Logging; using Datadog.Trace.Logging.DirectSubmission; using Datadog.Trace.Logging.TracerFlare; @@ -342,13 +343,35 @@ protected virtual ISpanSampler GetSpanSampler(TracerSettings settings) protected virtual IAgentWriter GetAgentWriter(TracerSettings settings, IDogStatsd statsd, Action> updateSampleRates, IDiscoveryService discoveryService) { var apiRequestFactory = TracesTransportStrategy.Get(settings.Exporter); - var api = new Api(apiRequestFactory, statsd, updateSampleRates, settings.Exporter.PartialFlushEnabled); + var api = GetApi(settings, statsd, updateSampleRates, apiRequestFactory, settings.Exporter.PartialFlushEnabled); var statsAggregator = StatsAggregator.Create(api, settings, discoveryService); return new AgentWriter(api, statsAggregator, statsd, maxBufferSize: settings.TraceBufferSize, batchInterval: settings.TraceBatchInterval, appsecStandaloneEnabled: settings.AppsecStandaloneEnabledInternal); } + private IApi GetApi(TracerSettings settings, IDogStatsd statsd, Action> updateSampleRates, IApiRequestFactory apiRequestFactory, bool partialFlushEnabled) + { + if (settings.DataPipelineEnabled) + { + var configuration = new TraceExporterConfiguration + { + Url = settings.Exporter.AgentUri.ToString(), + TraceVersion = TracerConstants.AssemblyVersion, + Env = settings.Environment, + Version = settings.ServiceVersion, + Service = settings.ServiceName, + Hostname = settings.Exporter.AgentUri.ToString(), + Language = ".NET", + LanguageVersion = FrameworkDescription.Instance.ProductVersion, + LanguageInterpreter = ".NET" + }; + return new TraceExporter(configuration); + } + + return new Api(apiRequestFactory, statsd, updateSampleRates, partialFlushEnabled); + } + protected virtual IDiscoveryService GetDiscoveryService(TracerSettings settings) => DiscoveryService.Create(settings.Exporter); diff --git a/tracer/test/Datadog.Trace.IntegrationTests/LibDatadog/TraceExporterTests.cs b/tracer/test/Datadog.Trace.IntegrationTests/LibDatadog/TraceExporterTests.cs new file mode 100644 index 000000000000..84a056fc55ca --- /dev/null +++ b/tracer/test/Datadog.Trace.IntegrationTests/LibDatadog/TraceExporterTests.cs @@ -0,0 +1,62 @@ +// +// 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. +// + +using System; +using System.Threading.Tasks; +using Datadog.Trace.Agent.DiscoveryService; +using Datadog.Trace.Configuration; +using Datadog.Trace.TestHelpers; +using Xunit; + +namespace Datadog.Trace.IntegrationTests.LibDatadog; + +public class TraceExporterTests +{ + [Fact] + public async Task SendsTracesUsingDataPipeline() + { + using var agent = MockTracerAgent.Create(null, TcpPortProvider.GetOpenPort()); + + agent.CustomResponses[MockTracerResponseType.Traces] = new MockTracerResponse + { + StatusCode = 200, + ContentType = "application/msgpack", + Response = """ + { + "rate_by_service": { + "service:default-service,env:test": 1.0, + "service:,env:": 0.8 + } + } + """ + }; + + var settings = TracerSettings.Create(new() + { + { ConfigurationKeys.StatsComputationEnabled, true }, + { ConfigurationKeys.ServiceName, "default-service" }, + { ConfigurationKeys.ServiceVersion, "v1" }, + { ConfigurationKeys.Environment, "test" }, + { ConfigurationKeys.AgentUri, $"http://localhost:{agent.Port}" }, + }); + + var discovery = DiscoveryService.Create(settings.Exporter); + var tracer = new Tracer(settings, agentWriter: null, sampler: null, scopeManager: null, statsd: null, discoveryService: discovery); + + using var span = tracer.StartSpan("operationName"); + span.ResourceName = "resourceName"; + span.Type = "test"; + span.Finish(); + + await tracer.TracerManager.ShutdownAsync(); + var recordedSpans = agent.WaitForSpans(1); + Assert.Equal(1, recordedSpans.Count); + + var recordedSpan = recordedSpans[0]; + Assert.Equal("operationName", recordedSpan.Name); + Assert.Equal("resourceName", recordedSpan.Resource); + Assert.Equal("default-service", recordedSpan.Service); + } +} diff --git a/tracer/test/Datadog.Trace.IntegrationTests/StatsTests.cs b/tracer/test/Datadog.Trace.IntegrationTests/StatsTests.cs index 9f80ad3aa5d0..33b7628c3a31 100644 --- a/tracer/test/Datadog.Trace.IntegrationTests/StatsTests.cs +++ b/tracer/test/Datadog.Trace.IntegrationTests/StatsTests.cs @@ -54,6 +54,7 @@ public async Task SendsStatsWithProcessing_Normalizer() { ConfigurationKeys.ServiceVersion, "v1" }, { ConfigurationKeys.Environment, "test" }, { ConfigurationKeys.AgentUri, $"http://localhost:{agent.Port}" }, + { ConfigurationKeys.DataPipelineEnabled, "false" }, }); var discovery = DiscoveryService.Create(settings.Exporter); @@ -198,6 +199,7 @@ public async Task SendsStatsWithProcessing_Obfuscator() { ConfigurationKeys.ServiceVersion, "v1" }, { ConfigurationKeys.Environment, "test" }, { ConfigurationKeys.AgentUri, $"http://localhost:{agent.Port}" }, + { ConfigurationKeys.DataPipelineEnabled, "false" }, }); var discovery = DiscoveryService.Create(settings.Exporter); @@ -356,6 +358,7 @@ private async Task SendStatsHelper(bool statsComputationEnabled, bool expectStat { ConfigurationKeys.ServiceVersion, "V" }, { ConfigurationKeys.Environment, "Test" }, { ConfigurationKeys.AgentUri, $"http://localhost:{agent.Port}" }, + { ConfigurationKeys.DataPipelineEnabled, "false" }, })); var discovery = DiscoveryService.Create(settings.Exporter);