Skip to content

Commit 5318e4a

Browse files
feat: Xray compliant ids (#840)
* Fixing XRay propagator null exception * Add test for missing header * Adding trace id generation to be compatible with aws xray * Fix rubocop * Moving xray trace to propagator gem * Moving so it includes * Adding some documentation and a couple of tests * Feedback changes * renaming file to match module * Fixing include * Move location * rename var
1 parent e479109 commit 5318e4a

File tree

4 files changed

+107
-0
lines changed

4 files changed

+107
-0
lines changed

propagator/xray/README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,23 @@ gem install opentelemetry-propagator-xray
2323

2424
Or, if you use [bundler][bundler-home], include `opentelemetry-propagator-xray` in your `Gemfile`.
2525

26+
In your application:
27+
```
28+
require 'opentelemetry/propagator/xray'
29+
# Optional
30+
ENV['OTEL_PROPAGATORS'] ||= 'xray' # Or you can set this as an environment variable outside of the application
31+
```
32+
33+
## To generate AWS XRay compliant IDs use the 'OpenTelemetry::AWSXRayTrace' module:
34+
```
35+
require 'opentelemetry/propagator/xray'
36+
37+
OpenTelemetry::SDK.configure do |c|
38+
c.id_generator = OpenTelemetry::Propagator::XRay::IDGenerator
39+
end
40+
```
41+
The propagator and ID generation are independent and do not need to be used in conjunction but can be.
42+
2643
## How can I get involved?
2744

2845
The `opentelemetry-propagator-xray` gem source is [on github][repo-github], along with related gems including `opentelemetry-api` and `opentelemetry-sdk`.

propagator/xray/lib/opentelemetry/propagator/xray.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,4 @@ def text_map_propagator
4646
end
4747

4848
require_relative './xray/version'
49+
require_relative './xray/id_generator'
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# frozen_string_literal: true
2+
3+
# Copyright The OpenTelemetry Authors
4+
#
5+
# SPDX-License-Identifier: Apache-2.0
6+
7+
module OpenTelemetry
8+
module Propagator
9+
module XRay
10+
# This module is intended to only be used as an override for how to generate IDs to be compliant with XRay
11+
module IDGenerator
12+
extend self
13+
14+
# Generates a valid trace identifier, a 16-byte string with at least one
15+
# non-zero byte.
16+
# AWS Docs: https://docs.aws.amazon.com/xray/latest/api/API_PutTraceSegments.html
17+
# hi - 4 bytes timestamp, 4 bytes random (Mid)
18+
# low - 8 bytes random.
19+
# Since we include timestamp, impossible to be invalid.
20+
# @return [bytes] a valid trace ID that is compliant with AWS XRay.
21+
def generate_trace_id
22+
time_hi = generate_time_bytes
23+
mid_and_low = RANDOM.bytes(12)
24+
time_hi << mid_and_low
25+
end
26+
27+
# Generates a valid span identifier, an 8-byte string with at least one
28+
# non-zero byte.
29+
#
30+
# @return [bytes] a valid span ID.
31+
def generate_span_id
32+
OpenTelemetry::Trace.generate_span_id
33+
end
34+
35+
private
36+
37+
# Random number generator for generating IDs. This is an object that can
38+
# respond to `#bytes` and uses the system PRNG. The current logic is
39+
# compatible with Ruby 2.5 (which does not implement the `Random.bytes`
40+
# class method) and with Ruby 3.0+ (which deprecates `Random::DEFAULT`).
41+
# When we drop support for Ruby 2.5, this can simply be replaced with
42+
# the class `Random`.
43+
#
44+
# @return [#bytes]
45+
RANDOM = Random.respond_to?(:bytes) ? Random : Random::DEFAULT
46+
47+
# Seconds since epoch converted to 4 bytes in big-endian order.
48+
def generate_time_bytes
49+
[Time.now.to_i].pack('N')
50+
end
51+
end
52+
end
53+
end
54+
end
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# frozen_string_literal: true
2+
3+
require 'date'
4+
require 'test_helper'
5+
6+
describe OpenTelemetry::Trace::SpanContext do
7+
let(:id_generator) { OpenTelemetry::Propagator::XRay::IDGenerator }
8+
9+
describe 'generate trace id in the correct format' do
10+
it 'must generate 16 in length' do
11+
trace_id = id_generator.generate_trace_id
12+
_(trace_id.length).must_equal(16)
13+
end
14+
it 'first 4 bytes should be a valid epoch date' do
15+
trace_id = id_generator.generate_trace_id
16+
# Convert to hex
17+
hex = trace_id[0..3].unpack1('H*')
18+
# Convert to int
19+
time_int = hex.to_i(16)
20+
# Convert to datetime
21+
begin
22+
date = Time.at(time_int).to_datetime
23+
rescue ArgumentError
24+
date = nil
25+
end
26+
# Make sure it's valid
27+
_(date).wont_be_nil
28+
end
29+
it 'generate_span_id still works' do
30+
trace_id = id_generator.generate_span_id
31+
# Make sure it's valid
32+
_(trace_id).wont_be_nil
33+
end
34+
end
35+
end

0 commit comments

Comments
 (0)