Skip to content

Commit 4e60b64

Browse files
kzemektsloughter
andauthored
Precompute hex encodings of SpanID and TraceID (#874)
* Use `binary:encode_hex/2` instead of `io_lib:format/2` `io_lib:format/2` has very significant overhead over `binary:encode_hex/2`. * Precompute hex trace and span ids * Prefill hex IDs in remaining span_ctx constructors --------- Co-authored-by: Tristan Sloughter <[email protected]>
1 parent a1b7bee commit 4e60b64

File tree

10 files changed

+59
-19
lines changed

10 files changed

+59
-19
lines changed

apps/opentelemetry/src/otel_span_ets.erl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,9 @@ get_ctx(#span{trace_id=TraceId,
102102
tracestate=TraceState,
103103
is_recording=IsRecording}) ->
104104
#span_ctx{trace_id=TraceId,
105+
hex_trace_id=otel_utils:encode_hex(<<TraceId:128>>),
105106
span_id=SpanId,
107+
hex_span_id=otel_utils:encode_hex(<<SpanId:64>>),
106108
tracestate=TraceState,
107109
is_recording=IsRecording}.
108110

apps/opentelemetry/src/otel_span_utils.erl

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,12 +87,20 @@ new_span_ctx(Ctx, IdGeneratorModule) ->
8787
{root_span_ctx(IdGeneratorModule), undefined, undefined};
8888
ParentSpanCtx=#span_ctx{span_id=ParentSpanId, is_remote=ParentIsRemote} ->
8989
%% keep the rest of the parent span ctx, simply need to update the span_id
90-
{ParentSpanCtx#span_ctx{span_id=IdGeneratorModule:generate_span_id()}, ParentSpanId, ParentIsRemote}
90+
SpanId = IdGeneratorModule:generate_span_id(),
91+
HexSpanId = otel_utils:encode_hex(<<SpanId:64>>),
92+
{ParentSpanCtx#span_ctx{span_id=SpanId, hex_span_id=HexSpanId}, ParentSpanId, ParentIsRemote}
9193
end.
9294

9395
root_span_ctx(IdGeneratorModule) ->
94-
#span_ctx{trace_id=IdGeneratorModule:generate_trace_id(),
95-
span_id=IdGeneratorModule:generate_span_id(),
96+
TraceId = IdGeneratorModule:generate_trace_id(),
97+
HexTraceId = otel_utils:encode_hex(<<TraceId:128>>),
98+
SpanId = IdGeneratorModule:generate_span_id(),
99+
HexSpanId = otel_utils:encode_hex(<<SpanId:64>>),
100+
#span_ctx{trace_id=TraceId,
101+
hex_trace_id=HexTraceId,
102+
span_id=SpanId,
103+
hex_span_id=HexSpanId,
96104
is_valid=true,
97105
trace_flags=0}.
98106

apps/opentelemetry/test/opentelemetry_SUITE.erl

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1101,6 +1101,17 @@ no_exporter(_Config) ->
11011101

11021102
ok.
11031103

1104+
1105+
generate_trace_id() -> 41394.
1106+
generate_span_id() -> 50132.
1107+
pregenerate_hex_ids(_Config) ->
1108+
HexTraceId = <<"0000000000000000000000000000a1b2">>,
1109+
HexSpanId = <<"000000000000c3d4">>,
1110+
SpanCtx = otel_span_utils:root_span_ctx(?MODULE),
1111+
?assertEqual(HexTraceId, SpanCtx#span_ctx.hex_trace_id),
1112+
?assertEqual(HexSpanId, SpanCtx#span_ctx.hex_span_id),
1113+
ok.
1114+
11041115
%%
11051116

11061117
assert_all_exported(Tid, SpanCtxs) ->

apps/opentelemetry_api/include/opentelemetry.hrl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,12 @@
4949
-record(span_ctx, {
5050
%% 128 bit int trace id
5151
trace_id :: opentelemetry:trace_id(),
52+
%% 128 bit int trace id encoded as hex binary string
53+
hex_trace_id :: opentelemetry:hex_trace_id(),
5254
%% 64 bit int span id
5355
span_id :: opentelemetry:span_id(),
56+
%% 64 bit int span id encoded as hex binary string
57+
hex_span_id :: opentelemetry:hex_span_id(),
5458
%% 8-bit integer, lowest bit is if it is sampled
5559
trace_flags = 0 :: integer(),
5660
%% Tracestate represents tracing-system specific context in a list of key-value pairs.

apps/opentelemetry_api/src/otel_span.erl

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -126,22 +126,12 @@ hex_span_ctx(_) ->
126126
#{}.
127127

128128
-spec hex_trace_id(opentelemetry:span_ctx()) -> opentelemetry:hex_trace_id().
129-
hex_trace_id(#span_ctx{trace_id=TraceId}) ->
130-
case otel_utils:format_binary_string("~32.16.0b", [TraceId]) of
131-
{ok, Binary} ->
132-
Binary;
133-
_ ->
134-
<<>>
135-
end.
129+
hex_trace_id(#span_ctx{hex_trace_id=HexTraceId}) ->
130+
HexTraceId.
136131

137132
-spec hex_span_id(opentelemetry:span_ctx()) -> opentelemetry:hex_span_id().
138-
hex_span_id(#span_ctx{span_id=SpanId}) ->
139-
case otel_utils:format_binary_string("~16.16.0b", [SpanId]) of
140-
{ok, Binary} ->
141-
Binary;
142-
_ ->
143-
<<>>
144-
end.
133+
hex_span_id(#span_ctx{hex_span_id=HexSpanId}) ->
134+
HexSpanId.
145135

146136
-spec tracestate(opentelemetry:span_ctx() | undefined) -> otel_tracestate:t().
147137
tracestate(#span_ctx{tracestate=Tracestate}) ->

apps/opentelemetry_api/src/otel_tracer.erl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,9 @@ with_span(Ctx, Tracer={Module, _}, SpanName, Opts, Fun) when is_atom(Module) ->
9090
-> opentelemetry:span_ctx().
9191
non_recording_span(TraceId, SpanId, Traceflags) ->
9292
#span_ctx{trace_id=TraceId,
93+
hex_trace_id=otel_utils:encode_hex(<<TraceId:128>>),
9394
span_id=SpanId,
95+
hex_span_id=otel_utils:encode_hex(<<SpanId:64>>),
9496
is_recording=false,
9597
trace_flags=Traceflags}.
9698

@@ -100,7 +102,9 @@ non_recording_span(TraceId, SpanId, Traceflags) ->
100102
-> opentelemetry:span_ctx().
101103
from_remote_span(TraceId, SpanId, Traceflags) ->
102104
#span_ctx{trace_id=TraceId,
105+
hex_trace_id=otel_utils:encode_hex(<<TraceId:128>>),
103106
span_id=SpanId,
107+
hex_span_id=otel_utils:encode_hex(<<SpanId:64>>),
104108
is_valid=true,
105109
is_recording=false,
106110
is_remote=true,

apps/opentelemetry_api/src/otel_tracer_noop.erl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@
2828
-include("otel_tracer.hrl").
2929

3030
-define(NOOP_SPAN_CTX, #span_ctx{trace_id=0,
31+
hex_trace_id= <<"00000000000000000000000000000000">>,
3132
span_id=0,
33+
hex_span_id= <<"0000000000000000">>,
3234
trace_flags=0,
3335
tracestate=otel_tracestate:new(),
3436
is_valid=false,

apps/opentelemetry_api/src/otel_utils.erl

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
format_binary_string/2,
2121
format_binary_string/3,
2222
assert_to_binary/1,
23-
unicode_to_binary/1]).
23+
unicode_to_binary/1,
24+
encode_hex/1]).
2425

2526
-if(?OTP_RELEASE >= 24).
2627
format_exception(Kind, Reason, StackTrace) ->
@@ -55,3 +56,15 @@ unicode_to_binary(String) ->
5556
_ ->
5657
{error, bad_binary_conversion}
5758
end.
59+
60+
-spec encode_hex(binary()) -> binary().
61+
-if(?OTP_RELEASE >= 26).
62+
encode_hex(Bin) ->
63+
binary:encode_hex(Bin, lowercase).
64+
-elif(?OTP_RELEASE >= 24).
65+
encode_hex(Bin) ->
66+
string:lowercase(binary:encode_hex(Bin)).
67+
-else.
68+
encode_hex(Bin) ->
69+
string:lowercase(<< <<Enc>> || <<HByte:4>> <= Bin, Enc <- integer_to_list(HByte, 16) >>).
70+
-endif.

apps/opentelemetry_api/test/opentelemetry_api_SUITE.erl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ noop_with_span(_Config) ->
249249
hex_trace_ids(_Config) ->
250250
HexTraceId = <<"0000000000000000000000000000a1b2">>,
251251
HexSpanId = <<"000000000000c3d4">>,
252-
SpanCtx=#span_ctx{trace_id=41394, span_id=50132},
252+
SpanCtx=#span_ctx{trace_id=41394, hex_trace_id=HexTraceId, span_id=50132, hex_span_id=HexSpanId},
253253
?assertEqual(HexTraceId, otel_span:hex_trace_id(SpanCtx)),
254254
?assertEqual(HexSpanId, otel_span:hex_span_id(SpanCtx)),
255255
?assertEqual(#{otel_trace_id => HexTraceId,

apps/opentelemetry_api/test/otel_propagators_SUITE.erl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,9 @@ rewrite(_Config) ->
7070
otel_ctx:clear(),
7171

7272
RecordingSpanCtx = #span_ctx{trace_id=21267647932558653966460912964485513216,
73+
hex_trace_id= <<"10000000000000000000000000000000">>,
7374
span_id=1152921504606846976,
75+
hex_span_id= <<"1000000000000000">>,
7476
is_valid=true,
7577
is_recording=true},
7678
otel_tracer:set_current_span(RecordingSpanCtx),
@@ -117,7 +119,9 @@ invalid_span_no_sdk_propagation(_Config) ->
117119
otel_ctx:clear(),
118120

119121
InvalidSpanCtx = #span_ctx{trace_id=0,
122+
hex_trace_id= <<"00000000000000000000000000000000">>,
120123
span_id=0,
124+
hex_span_id= <<"0000000000000000">>,
121125
trace_flags=0,
122126
is_valid=false,
123127
is_recording=false},
@@ -142,7 +146,9 @@ nonrecording_no_sdk_propagation(_Config) ->
142146
otel_ctx:clear(),
143147

144148
NonRecordingSpanCtx = #span_ctx{trace_id=21267647932558653966460912964485513216,
149+
hex_trace_id= <<"10000000000000000000000000000000">>,
145150
span_id=1152921504606846976,
151+
hex_span_id= <<"1000000000000000">>,
146152
is_valid=true,
147153
is_recording=false},
148154
?set_current_span(NonRecordingSpanCtx),

0 commit comments

Comments
 (0)