Skip to content

Commit f899260

Browse files
wilguoMrAlias
andauthored
Add AWS X-Ray ID Generator (#459)
* Add ID Generator * Fix sdktrace dependency issue * Add go.mod under aws * Update changelog and add go.mod files * Modify go.sum * Update propagators/aws/go.mod Co-authored-by: Tyler Yahn <[email protected]> * Update propagators/aws/xray/idgenerator_test.go Co-authored-by: Tyler Yahn <[email protected]> * Update propagators/aws/xray/idgenerator_test.go Co-authored-by: Tyler Yahn <[email protected]> * Update propagators/aws/xray/idgenerator_test.go Co-authored-by: Tyler Yahn <[email protected]> * Update propagators/aws/xray/idgenerator_test.go Co-authored-by: Tyler Yahn <[email protected]> * Update propagators/aws/xray/idgenerator_test.go Co-authored-by: Tyler Yahn <[email protected]> * Update propagators/aws/xray/idgenerator_test.go Co-authored-by: Tyler Yahn <[email protected]> * Update propagators/aws/xray/idgenerator_test.go Co-authored-by: Tyler Yahn <[email protected]> Co-authored-by: Tyler Yahn <[email protected]>
1 parent f96a4bd commit f899260

File tree

6 files changed

+228
-0
lines changed

6 files changed

+228
-0
lines changed

.github/dependabot.yml

+10
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,16 @@ updates:
417417
schedule:
418418
interval: "weekly"
419419
day: "sunday"
420+
-
421+
package-ecosystem: "gomod"
422+
directory: "/propagators/aws"
423+
labels:
424+
- dependencies
425+
- go
426+
- "Skip Changelog"
427+
schedule:
428+
interval: "weekly"
429+
day: "sunday"
420430
-
421431
package-ecosystem: "gomod"
422432
directory: "/propagators/opencensus"

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
1818

1919
- A new Amazon EKS resource detector. (#465)
2020
- A new `gcp.CloudRun` detector for detecting resource from a Cloud Run instance. (#455)
21+
- A new AWS X-Ray ID Generator (#459)
2122

2223
## [0.14.0] - 2020-11-20
2324

propagators/aws/go.mod

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
module go.opentelemetry.io/contrib/propagators/aws
2+
3+
go 1.15
4+
5+
require (
6+
github.com/stretchr/testify v1.6.1
7+
go.opentelemetry.io/otel v0.15.0
8+
go.opentelemetry.io/otel/sdk v0.15.0
9+
)

propagators/aws/go.sum

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
github.com/DataDog/sketches-go v0.0.1/go.mod h1:Q5DbzQ+3AkgGwymQO7aZFNP7ns2lZKGtvRBzRXfdi60=
2+
github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
3+
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
4+
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
5+
github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M=
6+
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
7+
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
8+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
9+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
10+
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
11+
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
12+
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
13+
go.opentelemetry.io/otel v0.15.0 h1:CZFy2lPhxd4HlhZnYK8gRyDotksO3Ip9rBweY1vVYJw=
14+
go.opentelemetry.io/otel v0.15.0/go.mod h1:e4GKElweB8W2gWUqbghw0B8t5MCTccc9212eNHnOHwA=
15+
go.opentelemetry.io/otel/sdk v0.15.0 h1:Hf2dl1Ad9Hn03qjcAuAq51GP5Pv1SV5puIkS2nRhdd8=
16+
go.opentelemetry.io/otel/sdk v0.15.0/go.mod h1:Qudkwgq81OcA9GYVlbyZ62wkLieeS1eWxIL0ufxgwoc=
17+
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
18+
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
19+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
20+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
21+
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
22+
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

propagators/aws/xray/idgenerator.go

+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// Copyright The OpenTelemetry Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package xray
16+
17+
import (
18+
"context"
19+
crand "crypto/rand"
20+
"encoding/binary"
21+
"encoding/hex"
22+
"math/rand"
23+
"strconv"
24+
"sync"
25+
"time"
26+
27+
sdktrace "go.opentelemetry.io/otel/sdk/trace"
28+
"go.opentelemetry.io/otel/trace"
29+
)
30+
31+
// IDGenerator is used for generating a new traceID and spanID
32+
type IDGenerator struct {
33+
sync.Mutex
34+
randSource *rand.Rand
35+
}
36+
37+
var _ sdktrace.IDGenerator = &IDGenerator{}
38+
39+
// NewSpanID returns a non-zero span ID from a randomly-chosen sequence.
40+
func (gen *IDGenerator) NewSpanID(ctx context.Context, traceID trace.TraceID) trace.SpanID {
41+
gen.Lock()
42+
defer gen.Unlock()
43+
sid := trace.SpanID{}
44+
gen.randSource.Read(sid[:])
45+
return sid
46+
}
47+
48+
// NewIDs returns a non-zero trace ID and a non-zero span ID.
49+
// trace ID returned is based on AWS X-Ray TraceID format.
50+
// - https://docs.aws.amazon.com/xray/latest/devguide/xray-api-sendingdata.html#xray-api-traceids
51+
// span ID is from a randomly-chosen sequence.
52+
func (gen *IDGenerator) NewIDs(ctx context.Context) (trace.TraceID, trace.SpanID) {
53+
gen.Lock()
54+
defer gen.Unlock()
55+
56+
tid := trace.TraceID{}
57+
currentTime := getCurrentTimeHex()
58+
copy(tid[:4], currentTime)
59+
gen.randSource.Read(tid[4:])
60+
61+
sid := trace.SpanID{}
62+
gen.randSource.Read(sid[:])
63+
return tid, sid
64+
}
65+
66+
// NewIDGenerator returns an IDGenerator reference used for sending traces to AWS X-Ray
67+
func NewIDGenerator() *IDGenerator {
68+
gen := &IDGenerator{}
69+
var rngSeed int64
70+
_ = binary.Read(crand.Reader, binary.LittleEndian, &rngSeed)
71+
gen.randSource = rand.New(rand.NewSource(rngSeed))
72+
return gen
73+
}
74+
75+
func getCurrentTimeHex() []uint8 {
76+
currentTime := time.Now().Unix()
77+
// Ignore error since no expected error should result from this operation
78+
// Odd-length strings and non-hex digits are the only 2 error conditions for hex.DecodeString()
79+
// strconv.FromatInt() do not produce odd-length strings or non-hex digits
80+
currentTimeHex, _ := hex.DecodeString(strconv.FormatInt(currentTime, 16))
81+
return currentTimeHex
82+
}
+104
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
// Copyright The OpenTelemetry Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package xray
16+
17+
import (
18+
"bytes"
19+
"context"
20+
"strconv"
21+
"testing"
22+
"time"
23+
24+
"github.com/stretchr/testify/assert"
25+
"github.com/stretchr/testify/require"
26+
27+
"go.opentelemetry.io/otel/trace"
28+
)
29+
30+
func TestTraceIDIsValidLength(t *testing.T) {
31+
idg := NewIDGenerator()
32+
traceID, _ := idg.NewIDs(context.Background())
33+
34+
expectedTraceIDLength := 32
35+
assert.Equal(t, len(traceID.String()), expectedTraceIDLength, "TraceID has incorrect length.")
36+
}
37+
38+
func TestTraceIDIsUnique(t *testing.T) {
39+
idg := NewIDGenerator()
40+
traceID1, _ := idg.NewIDs(context.Background())
41+
traceID2, _ := idg.NewIDs(context.Background())
42+
43+
assert.NotEqual(t, traceID1.String(), traceID2.String(), "TraceID should be unique")
44+
}
45+
46+
func TestTraceIDTimestampInBounds(t *testing.T) {
47+
48+
idg := NewIDGenerator()
49+
50+
previousTime := time.Now().Unix()
51+
52+
traceID, _ := idg.NewIDs(context.Background())
53+
54+
currentTime, err := strconv.ParseInt(traceID.String()[0:8], 16, 64)
55+
require.NoError(t, err)
56+
57+
nextTime := time.Now().Unix()
58+
59+
assert.LessOrEqual(t, previousTime, currentTime, "TraceID is generated incorrectly with the wrong timestamp.")
60+
assert.LessOrEqual(t, currentTime, nextTime, "TraceID is generated incorrectly with the wrong timestamp.")
61+
}
62+
63+
func TestTraceIDIsNotNil(t *testing.T) {
64+
var nilTraceID trace.TraceID
65+
idg := NewIDGenerator()
66+
traceID, _ := idg.NewIDs(context.Background())
67+
68+
assert.False(t, bytes.Equal(traceID[:], nilTraceID[:]), "TraceID cannot be empty.")
69+
}
70+
71+
func TestSpanIDIsValidLength(t *testing.T) {
72+
idg := NewIDGenerator()
73+
ctx := context.Background()
74+
traceID, spanID1 := idg.NewIDs(ctx)
75+
spanID2 := idg.NewSpanID(context.Background(), traceID)
76+
expectedSpanIDLength := 16
77+
78+
assert.Equal(t, len(spanID1.String()), expectedSpanIDLength, "SpanID has incorrect length")
79+
assert.Equal(t, len(spanID2.String()), expectedSpanIDLength, "SpanID has incorrect length")
80+
}
81+
82+
func TestSpanIDIsUnique(t *testing.T) {
83+
idg := NewIDGenerator()
84+
ctx := context.Background()
85+
traceID, spanID1 := idg.NewIDs(ctx)
86+
_, spanID2 := idg.NewIDs(ctx)
87+
88+
spanID3 := idg.NewSpanID(ctx, traceID)
89+
spanID4 := idg.NewSpanID(ctx, traceID)
90+
91+
assert.NotEqual(t, spanID1.String(), spanID2.String(), "SpanID should be unique")
92+
assert.NotEqual(t, spanID3.String(), spanID4.String(), "SpanID should be unique")
93+
}
94+
95+
func TestSpanIDIsNotNil(t *testing.T) {
96+
var nilSpanID trace.SpanID
97+
idg := NewIDGenerator()
98+
ctx := context.Background()
99+
traceID, spanID1 := idg.NewIDs(ctx)
100+
spanID2 := idg.NewSpanID(ctx, traceID)
101+
102+
assert.False(t, bytes.Equal(spanID1[:], nilSpanID[:]), "SpanID cannot be empty.")
103+
assert.False(t, bytes.Equal(spanID2[:], nilSpanID[:]), "SpanID cannot be empty.")
104+
}

0 commit comments

Comments
 (0)