Skip to content

Commit abe79b2

Browse files
authored
Various smaller improvements (#37)
* Eliminate use of math/rand outside of pkg/random All random calls are protected by mutex * Migrate to math/rand/v2 * Move rand.Rand and it's mutex into a single struct * Remove dependency github.com/pkg/errors * Use gotestsum to run tests * Make target to format code
1 parent 7cd1a7a commit abe79b2

File tree

8 files changed

+171
-47
lines changed

8 files changed

+171
-47
lines changed

.github/workflows/lint-test.yml

+3
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ jobs:
1515
go-version: ^1.22
1616
cache: true
1717

18+
- name: Format
19+
run: make check-fmt
20+
1821
- name: Lint
1922
uses: golangci/[email protected]
2023
with:

Makefile

+9-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ IMAGE ?= ghcr.io/grafana/xk6-client-tracing
33
IMAGE_TAG ?= latest
44

55
GO_MODULE := $(shell head -n1 go.mod | cut -d' ' -f2)
6-
GO_TEST_OPTS := -race -count=1 -cover
6+
GO_TEST_OPTS := -race -count=1 -cover -v
77
GO_LINT_OPTS := --config ./golangci.yml
88
XK6_BUILD_OPTS := --output ./$(BINARY)
99

@@ -13,12 +13,19 @@ build:
1313

1414
.PHONY: test
1515
test:
16-
go test $(GO_TEST_OPTS) ./...
16+
go tool gotestsum --format=testname -- $(GO_TEST_OPTS) ./...
1717

1818
.PHONY: lint
1919
lint:
2020
golangci-lint run $(GO_LINT_OPTS) ./...
2121

22+
.PHONY: fmt
23+
fmt:
24+
go tool goimports -w ./
25+
26+
check-fmt: fmt
27+
@git diff --exit-code
28+
2229
.PHONY: docker
2330
docker:
2431
docker build . -t $(IMAGE):$(IMAGE_TAG)

go.mod

+13-1
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,13 @@ go 1.23.0
44

55
toolchain go1.24.0
66

7+
tool (
8+
golang.org/x/tools/cmd/goimports
9+
gotest.tools/gotestsum
10+
)
11+
712
require (
813
github.com/grafana/sobek v0.0.0-20250219104821-ed22af7a8d6c
9-
github.com/pkg/errors v0.9.1
1014
github.com/stretchr/testify v1.10.0
1115
go.k6.io/k6 v0.57.0
1216
go.opentelemetry.io/collector/component v0.120.0
@@ -25,9 +29,11 @@ require (
2529
)
2630

2731
require (
32+
github.com/bitfield/gotestdox v0.2.2 // indirect
2833
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
2934
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
3035
github.com/dlclark/regexp2 v1.11.5 // indirect
36+
github.com/dnephin/pflag v1.0.7 // indirect
3137
github.com/evanw/esbuild v0.25.0 // indirect
3238
github.com/fatih/color v1.18.0 // indirect
3339
github.com/felixge/httpsnoop v1.0.4 // indirect
@@ -38,6 +44,7 @@ require (
3844
github.com/gogo/protobuf v1.3.2 // indirect
3945
github.com/golang/snappy v0.0.4 // indirect
4046
github.com/google/pprof v0.0.0-20250302191652-9094ed2288e7 // indirect
47+
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
4148
github.com/google/uuid v1.6.0 // indirect
4249
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 // indirect
4350
github.com/hashicorp/go-version v1.7.0 // indirect
@@ -90,14 +97,19 @@ require (
9097
go.opentelemetry.io/proto/otlp v1.5.0 // indirect
9198
go.uber.org/multierr v1.11.0 // indirect
9299
golang.org/x/crypto v0.35.0 // indirect
100+
golang.org/x/mod v0.17.0 // indirect
93101
golang.org/x/net v0.35.0 // indirect
102+
golang.org/x/sync v0.11.0 // indirect
94103
golang.org/x/sys v0.30.0 // indirect
104+
golang.org/x/term v0.29.0 // indirect
95105
golang.org/x/text v0.22.0 // indirect
96106
golang.org/x/time v0.10.0 // indirect
107+
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
97108
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb // indirect
98109
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb // indirect
99110
google.golang.org/grpc v1.70.0 // indirect
100111
google.golang.org/protobuf v1.36.5 // indirect
101112
gopkg.in/guregu/null.v3 v3.5.0 // indirect
102113
gopkg.in/yaml.v3 v3.0.1 // indirect
114+
gotest.tools/gotestsum v1.12.0 // indirect
103115
)

go.sum

+91-2
Large diffs are not rendered by default.

pkg/random/random.go

+40-26
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ package random
22

33
import (
44
crand "crypto/rand"
5+
"encoding/binary"
56
"fmt"
6-
"math/big"
7-
"math/rand"
7+
"math/rand/v2"
88
"net/http"
99
"sync"
1010
"time"
@@ -25,25 +25,38 @@ var (
2525
"order", "payment", "customer", "product", "stock", "inventory",
2626
"shipping", "billing", "checkout", "cart", "search", "analytics"}
2727

28-
rnd *rand.Rand
29-
randMtx = sync.Mutex{}
28+
// rnd contains rand.Rand instance protected by a mutex
29+
rnd = struct {
30+
sync.Mutex
31+
*rand.Rand
32+
}{}
3033
)
3134

3235
func init() {
33-
seed, _ := crand.Int(crand.Reader, big.NewInt(int64(^uint64(0)>>1)))
34-
rnd = rand.New(rand.NewSource(seed.Int64()))
36+
var seed [32]byte
37+
_, err := crand.Read(seed[:])
38+
if err != nil {
39+
panic(err)
40+
}
41+
rnd.Rand = rand.New(rand.NewChaCha8(seed))
3542
}
3643

3744
func Float32() float32 {
38-
randMtx.Lock()
39-
defer randMtx.Unlock()
45+
rnd.Lock()
46+
defer rnd.Unlock()
4047
return rnd.Float32()
4148
}
4249

50+
func IntN(n int) int {
51+
rnd.Lock()
52+
defer rnd.Unlock()
53+
return rnd.IntN(n)
54+
}
55+
4356
func SelectElement[T any](elements []T) T {
44-
randMtx.Lock()
45-
defer randMtx.Unlock()
46-
return elements[rnd.Intn(len(elements))]
57+
rnd.Lock()
58+
defer rnd.Unlock()
59+
return elements[rnd.IntN(len(elements))]
4760
}
4861

4962
func String(n int) string {
@@ -59,23 +72,23 @@ func K6String(n int) string {
5972
}
6073

6174
func IntBetween(min, max int) int {
62-
randMtx.Lock()
63-
defer randMtx.Unlock()
64-
n := rnd.Intn(max - min)
75+
rnd.Lock()
76+
defer rnd.Unlock()
77+
n := rnd.IntN(max - min)
6578
return min + n
6679
}
6780

6881
func Duration(min, max time.Duration) time.Duration {
69-
randMtx.Lock()
70-
defer randMtx.Unlock()
71-
n := rnd.Int63n(int64(max) - int64(min))
82+
rnd.Lock()
83+
defer rnd.Unlock()
84+
n := rnd.Int64N(int64(max) - int64(min))
7285
return min + time.Duration(n)
7386
}
7487

7588
func IPAddr() string {
76-
randMtx.Lock()
77-
defer randMtx.Unlock()
78-
return fmt.Sprintf("192.168.%d.%d", rnd.Intn(255), rnd.Intn(255))
89+
rnd.Lock()
90+
defer rnd.Unlock()
91+
return fmt.Sprintf("192.168.%d.%d", rnd.IntN(255), rnd.IntN(255))
7992
}
8093

8194
func Port() int {
@@ -127,20 +140,21 @@ func OperationForResource(resource string) string {
127140
}
128141

129142
func TraceID() pcommon.TraceID {
130-
randMtx.Lock()
131-
defer randMtx.Unlock()
143+
rnd.Lock()
144+
defer rnd.Unlock()
132145

133146
var b [16]byte
134-
_, _ = rnd.Read(b[:]) // always returns nil error
147+
binary.BigEndian.PutUint64(b[:8], rnd.Uint64())
148+
binary.BigEndian.PutUint64(b[8:], rnd.Uint64())
135149
return b
136150
}
137151

138152
func SpanID() pcommon.SpanID {
139-
randMtx.Lock()
140-
defer randMtx.Unlock()
153+
rnd.Lock()
154+
defer rnd.Unlock()
141155

142156
var b [8]byte
143-
_, _ = rnd.Read(b[:]) // always returns nil error
157+
binary.BigEndian.PutUint64(b[:], rnd.Uint64())
144158
return b
145159
}
146160

pkg/tracegen/parameterized.go

+3-4
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package tracegen
33
import (
44
"encoding/hex"
55
"fmt"
6-
"math/rand"
76
"strconv"
87
"time"
98
"unsafe"
@@ -99,7 +98,7 @@ func (g *ParameterizedGenerator) Traces() ptrace.Traces {
9998

10099
func (g *ParameterizedGenerator) generateSpan(t *TraceParams, dest ptrace.Span) {
101100
endTime := time.Now().Round(time.Second)
102-
startTime := endTime.Add(-time.Duration(rand.Intn(500)+10) * time.Millisecond)
101+
startTime := endTime.Add(-time.Duration(random.IntN(500)+10) * time.Millisecond)
103102

104103
var traceID pcommon.TraceID
105104
b, _ := hex.DecodeString(t.ID)
@@ -151,8 +150,8 @@ func (g *ParameterizedGenerator) generateSpan(t *TraceParams, dest ptrace.Span)
151150
break
152151
}
153152

154-
rKey := random.K6String(rand.Intn(15))
155-
rVal := random.K6String(rand.Intn(15))
153+
rKey := random.K6String(random.IntN(15) + 1)
154+
rVal := random.K6String(random.IntN(15) + 1)
156155
attrs.PutStr(rKey, rVal)
157156

158157
size += int64(unsafe.Sizeof(rKey)) + int64(unsafe.Sizeof(rVal))

pkg/tracegen/templated.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package tracegen
22

33
import (
4+
"errors"
45
"fmt"
56
"net/http"
67
"net/url"
@@ -10,7 +11,6 @@ import (
1011

1112
"github.com/grafana/xk6-client-tracing/pkg/random"
1213
"github.com/grafana/xk6-client-tracing/pkg/util"
13-
"github.com/pkg/errors"
1414
"go.opentelemetry.io/collector/pdata/pcommon"
1515
"go.opentelemetry.io/collector/pdata/ptrace"
1616
)
@@ -147,7 +147,7 @@ func NewTemplatedGenerator(template *TraceTemplate) (*TemplatedGenerator, error)
147147
gen := &TemplatedGenerator{}
148148
err := gen.initialize(template)
149149
if err != nil {
150-
return nil, errors.Wrap(err, "fail to create new templated generator")
150+
return nil, fmt.Errorf("fail to create new templated generator: %w", err)
151151
}
152152
return gen, nil
153153
}
@@ -609,7 +609,7 @@ func initializeSpanKind(parent *internalSpanTemplate, tmpl, child *SpanTemplate)
609609
if k, found := tmpl.Attributes["span.kind"]; found {
610610
kindStr, ok := k.(string)
611611
if !ok {
612-
return ptrace.SpanKindUnspecified, errors.Errorf("attribute %s expected to be a string, but was %T", "span.kind", k)
612+
return ptrace.SpanKindUnspecified, fmt.Errorf("attribute span.kind expected to be a string, but was %T", k)
613613
}
614614
kind = spanKindFromString(kindStr)
615615
} else {

tracing.go

+9-9
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ package clienttracing
33
import (
44
"context"
55
"encoding/base64"
6+
"fmt"
67
"os"
78
"sync"
89

910
"github.com/grafana/sobek"
10-
"github.com/pkg/errors"
1111
"go.k6.io/k6/js/common"
1212
"go.k6.io/k6/js/modules"
1313
"go.opentelemetry.io/collector/component"
@@ -85,13 +85,13 @@ func (ct *TracingModule) newClient(g sobek.ConstructorCall, rt *sobek.Runtime) *
8585
var cfg ClientConfig
8686
err := rt.ExportTo(g.Argument(0), &cfg)
8787
if err != nil {
88-
common.Throw(rt, errors.Wrap(err, "unable to create client: constructor expects first argument to be ClientConfig"))
88+
common.Throw(rt, fmt.Errorf("unable to create client: constructor expects first argument to be ClientConfig: %w", err))
8989
}
9090

9191
if ct.client == nil {
9292
ct.client, err = NewClient(&cfg, ct.vu)
9393
if err != nil {
94-
common.Throw(rt, errors.Wrap(err, "unable to create client"))
94+
common.Throw(rt, fmt.Errorf("unable to create client: %w", err))
9595
}
9696
}
9797

@@ -107,7 +107,7 @@ func (ct *TracingModule) newParameterizedGenerator(g sobek.ConstructorCall, rt *
107107
var param []*tracegen.TraceParams
108108
err := rt.ExportTo(paramVal, &param)
109109
if err != nil {
110-
common.Throw(rt, errors.Wrap(err, "the ParameterizedGenerator constructor expects first argument to be []TraceParams"))
110+
common.Throw(rt, fmt.Errorf("the ParameterizedGenerator constructor expects first argument to be []TraceParams: %w", err))
111111
}
112112

113113
generator = tracegen.NewParameterizedGenerator(param)
@@ -126,12 +126,12 @@ func (ct *TracingModule) newTemplatedGenerator(g sobek.ConstructorCall, rt *sobe
126126
var tmpl tracegen.TraceTemplate
127127
err := rt.ExportTo(tmplVal, &tmpl)
128128
if err != nil {
129-
common.Throw(rt, errors.Wrap(err, "the TemplatedGenerator constructor expects first argument to be TraceTemplate"))
129+
common.Throw(rt, fmt.Errorf("the TemplatedGenerator constructor expects first argument to be TraceTemplate: %w", err))
130130
}
131131

132132
generator, err = tracegen.NewTemplatedGenerator(&tmpl)
133133
if err != nil {
134-
common.Throw(rt, errors.Wrap(err, "unable to generate TemplatedGenerator"))
134+
common.Throw(rt, fmt.Errorf("unable to generate TemplatedGenerator: %w", err))
135135
}
136136

137137
ct.templatedGenerators[tmplObj] = generator
@@ -208,7 +208,7 @@ func NewClient(cfg *ClientConfig, vu modules.VU) (*Client, error) {
208208
}, cfg.Headers),
209209
}
210210
default:
211-
return nil, errors.Errorf("failed to init exporter: unknown exporter type %s", cfg.Exporter)
211+
return nil, fmt.Errorf("failed to init exporter: unknown exporter type %s", cfg.Exporter)
212212
}
213213

214214
exporter, err := factory.CreateTraces(
@@ -224,12 +224,12 @@ func NewClient(cfg *ClientConfig, vu modules.VU) (*Client, error) {
224224
exporterCfg,
225225
)
226226
if err != nil {
227-
return nil, errors.Wrap(err, "failed create exporter")
227+
return nil, fmt.Errorf("failed create exporter: %w", err)
228228
}
229229

230230
err = exporter.Start(vu.Context(), componenttest.NewNopHost())
231231
if err != nil {
232-
return nil, errors.Wrap(err, "failed to start exporter")
232+
return nil, fmt.Errorf("failed to start exporter: %w", err)
233233
}
234234

235235
return &Client{

0 commit comments

Comments
 (0)