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);