Skip to content

Commit 1282c6d

Browse files
committed
feat: add data in tls for trace to profile correlation
* BUILD.bazel * include/datadog/tls_storage.h * include/datadog/trace_segment.h * include/datadog/tracer.h * src/datadog/trace_segment.cpp * src/datadog/tracer.cpp
1 parent 8daec00 commit 1282c6d

File tree

6 files changed

+76
-0
lines changed

6 files changed

+76
-0
lines changed

BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ cc_library(
111111
"include/datadog/span_matcher.h",
112112
"include/datadog/span_sampler_config.h",
113113
"include/datadog/string_view.h",
114+
"include/datadog/tls_storage.h",
114115
"include/datadog/tracer.h",
115116
"include/datadog/tracer_config.h",
116117
"include/datadog/tracer_signature.h",

include/datadog/tls_storage.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#pragma once
2+
3+
#include <datadog/trace_id.h>
4+
5+
#include <array>
6+
#include <cstdint>
7+
8+
// Global struct used to exposed thread-specific information.
9+
// https://github.com/elastic/apm/blob/149cd3e39a77a58002344270ed2ad35357bdd02d/specs/agents/universal-profiling-integration.md#thread-local-storage-layout
10+
11+
namespace datadog {
12+
namespace tracing {
13+
struct __attribute__((packed)) TLSStorage {
14+
uint16_t layout_minor_version;
15+
uint8_t valid;
16+
uint8_t trace_present;
17+
uint8_t trace_flags;
18+
uint64_t trace_id_low;
19+
uint64_t trace_id_high;
20+
uint64_t span_id;
21+
uint64_t transaction_id;
22+
};
23+
24+
} // namespace tracing
25+
} // namespace datadog

include/datadog/trace_segment.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ class TraceSegment {
102102
const Optional<std::string>& origin() const;
103103
Optional<SamplingDecision> sampling_decision() const;
104104

105+
uint64_t local_root_id() const;
106+
105107
Logger& logger() const;
106108

107109
// Inject trace context for the specified `span` into the specified `writer`.

include/datadog/tracer.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
// obtained from a `TracerConfig` via the `finalize_config` function. See
1111
// `tracer_config.h`.
1212

13+
#ifdef __linux__
14+
#include <datadog/tls_storage.h>
15+
#endif
16+
1317
#include <cstddef>
1418
#include <memory>
1519

@@ -25,6 +29,8 @@
2529

2630
#ifdef __linux__
2731
extern const void* elastic_apm_profiling_correlation_process_storage_v1;
32+
extern thread_local struct datadog::tracing::TLSStorage*
33+
elastic_apm_profiling_correlation_tls_v1;
2834
#endif
2935

3036
namespace datadog {
@@ -109,6 +115,9 @@ class Tracer {
109115
std::string config() const;
110116

111117
private:
118+
#ifdef __linux__
119+
void correlate(const Span& span);
120+
#endif
112121
void store_config();
113122
};
114123

src/datadog/trace_segment.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,8 @@ Optional<SamplingDecision> TraceSegment::sampling_decision() const {
139139
return sampling_decision_;
140140
}
141141

142+
uint64_t TraceSegment::local_root_id() const { return spans_.front()->span_id; }
143+
142144
Logger& TraceSegment::logger() const { return *logger_; }
143145

144146
void TraceSegment::register_span(std::unique_ptr<SpanData> span) {

src/datadog/tracer.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@
3434

3535
#ifdef __linux__
3636
const void* elastic_apm_profiling_correlation_process_storage_v1 = nullptr;
37+
thread_local struct datadog::tracing::TLSStorage*
38+
elastic_apm_profiling_correlation_tls_v1 = nullptr;
39+
thread_local std::unique_ptr<datadog::tracing::TLSStorage> tls_info_holder =
40+
nullptr;
3741
#endif
3842

3943
namespace datadog {
@@ -117,6 +121,33 @@ Tracer::Tracer(const FinalizedTracerConfig& config,
117121
store_config();
118122
}
119123

124+
#ifdef __linux__
125+
void Tracer::correlate(const Span& span) {
126+
// See Layout:
127+
// https://github.com/elastic/apm/blob/149cd3e39a77a58002344270ed2ad35357bdd02d/specs/agents/universal-profiling-integration.md#thread-local-storage-layout
128+
tls_info_holder = std::make_unique<datadog::tracing::TLSStorage>();
129+
elastic_apm_profiling_correlation_tls_v1 = tls_info_holder.get();
130+
131+
struct TLSStorage* tls_data = elastic_apm_profiling_correlation_tls_v1;
132+
tls_data->valid = 0;
133+
134+
tls_data->layout_minor_version = 1;
135+
tls_data->trace_present = 1; // We are in a span so no errors
136+
tls_data->trace_flags =
137+
span.trace_segment().sampling_decision().has_value() &&
138+
span.trace_segment().sampling_decision().value().priority > 0
139+
? 1
140+
: 0;
141+
auto trace_id = span.trace_id();
142+
tls_data->trace_id_low = trace_id.low;
143+
tls_data->trace_id_high = trace_id.high;
144+
tls_data->span_id = span.id();
145+
tls_data->transaction_id = span.trace_segment().local_root_id();
146+
147+
tls_data->valid = 1;
148+
}
149+
#endif
150+
120151
std::string Tracer::config() const {
121152
// clang-format off
122153
auto config = nlohmann::json::object({
@@ -207,6 +238,9 @@ Span Tracer::create_span(const SpanConfig& config) {
207238
Span span{span_data_ptr, segment,
208239
[generator = generator_]() { return generator->span_id(); },
209240
clock_};
241+
#ifdef __linux__
242+
correlate(span);
243+
#endif
210244
return span;
211245
}
212246

@@ -409,6 +443,9 @@ Expected<Span> Tracer::extract_span(const DictReader& reader,
409443
Span span{span_data_ptr, segment,
410444
[generator = generator_]() { return generator->span_id(); },
411445
clock_};
446+
#ifdef __linux__
447+
correlate(span);
448+
#endif
412449
return span;
413450
}
414451

0 commit comments

Comments
 (0)