Skip to content

Commit 6757f8e

Browse files
authored
feat(fxtrace): Provided module (#28)
1 parent 70888a2 commit 6757f8e

File tree

13 files changed

+1391
-0
lines changed

13 files changed

+1391
-0
lines changed

.github/workflows/coverage.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ jobs:
3232
- "fxconfig"
3333
- "fxgenerate"
3434
- "fxlog"
35+
- "fxtrace"
3536
steps:
3637
- name: Checkout
3738
uses: actions/checkout@v3

.github/workflows/fxtrace-ci.yml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
name: "fxtrace-ci"
2+
3+
on:
4+
push:
5+
branches:
6+
- "feat**"
7+
- "fix**"
8+
- "hotfix**"
9+
- "chore**"
10+
paths:
11+
- "fxtrace/**.go"
12+
- "fxtrace/go.mod"
13+
- "fxtrace/go.sum"
14+
pull_request:
15+
types:
16+
- opened
17+
- synchronize
18+
- reopened
19+
branches:
20+
- main
21+
paths:
22+
- "fxtrace/**.go"
23+
- "fxtrace/go.mod"
24+
- "fxtrace/go.sum"
25+
26+
jobs:
27+
ci:
28+
uses: ./.github/workflows/common-ci.yml
29+
secrets: inherit
30+
with:
31+
module: "fxtrace"

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ Yokai's `Fx modules` are the plugins for your Yokai application.
2525
| [fxconfig](fxconfig) | Fx module for [config](config) |
2626
| [fxgenerate](fxgenerate) | Fx module for [generate](generate) |
2727
| [fxlog](fxlog) | Fx module for [log](log) |
28+
| [fxtrace](fxtrace) | Fx module for [trace](trace) |
2829

2930
They can also be used in any [Fx](https://github.com/uber-go/fx) based Go application.
3031

fxtrace/.golangci.yml

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
run:
2+
timeout: 5m
3+
concurrency: 8
4+
5+
linters:
6+
enable:
7+
- asasalint
8+
- asciicheck
9+
- bidichk
10+
- bodyclose
11+
- containedctx
12+
- contextcheck
13+
- decorder
14+
- dogsled
15+
- dupl
16+
- durationcheck
17+
- errcheck
18+
- errchkjson
19+
- errname
20+
- errorlint
21+
- forbidigo
22+
- forcetypeassert
23+
- gocognit
24+
- goconst
25+
- gocritic
26+
- gocyclo
27+
- godot
28+
- godox
29+
- gofmt
30+
- goheader
31+
- gomoddirectives
32+
- gomodguard
33+
- goprintffuncname
34+
- gosec
35+
- gosimple
36+
- govet
37+
- grouper
38+
- importas
39+
- ineffassign
40+
- interfacebloat
41+
- logrlint
42+
- maintidx
43+
- makezero
44+
- misspell
45+
- nestif
46+
- nilerr
47+
- nilnil
48+
- nlreturn
49+
- nolintlint
50+
- nosprintfhostport
51+
- prealloc
52+
- predeclared
53+
- promlinter
54+
- reassign
55+
- staticcheck
56+
- tenv
57+
- thelper
58+
- tparallel
59+
- typecheck
60+
- unconvert
61+
- unparam
62+
- unused
63+
- usestdlibvars
64+
- whitespace

fxtrace/README.md

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
# Fx Trace Module
2+
3+
[![ci](https://github.com/ankorstore/yokai/actions/workflows/fxtrace-ci.yml/badge.svg)](https://github.com/ankorstore/yokai/actions/workflows/fxtrace-ci.yml)
4+
[![go report](https://goreportcard.com/badge/github.com/ankorstore/yokai/fxtrace)](https://goreportcard.com/report/github.com/ankorstore/yokai/fxtrace)
5+
[![codecov](https://codecov.io/gh/ankorstore/yokai/graph/badge.svg?token=ghUBlFsjhR&flag=fxtrace)](https://app.codecov.io/gh/ankorstore/yokai/tree/main/fxtrace)
6+
[![Deps](https://img.shields.io/badge/osi-deps-blue)](https://deps.dev/go/github.com%2Fankorstore%2Fyokai%2Ffxtrace)
7+
[![PkgGoDev](https://pkg.go.dev/badge/github.com/ankorstore/yokai/fxtrace)](https://pkg.go.dev/github.com/ankorstore/yokai/fxtrace)
8+
9+
> [Fx](https://uber-go.github.io/fx/) module for [trace](https://github.com/ankorstore/yokai/tree/main/trace).
10+
11+
<!-- TOC -->
12+
* [Installation](#installation)
13+
* [Documentation](#documentation)
14+
* [Dependencies](#dependencies)
15+
* [Loading](#loading)
16+
* [Configuration](#configuration)
17+
* [Override](#override)
18+
* [Testing](#testing)
19+
<!-- TOC -->
20+
21+
## Installation
22+
23+
```shell
24+
go get github.com/ankorstore/yokai/fxtrace
25+
```
26+
27+
## Documentation
28+
29+
### Dependencies
30+
31+
This module is intended to be used alongside the [fxconfig](https://github.com/ankorstore/yokai/tree/main/fxconfig)
32+
module.
33+
34+
### Loading
35+
36+
To load the module in your Fx application:
37+
38+
```go
39+
package main
40+
41+
import (
42+
"context"
43+
44+
"github.com/ankorstore/yokai/config"
45+
"github.com/ankorstore/yokai/fxconfig"
46+
"github.com/ankorstore/yokai/fxtrace"
47+
oteltrace "go.opentelemetry.io/otel/trace"
48+
"go.uber.org/fx"
49+
)
50+
51+
func main() {
52+
fx.New(
53+
fxconfig.FxConfigModule, // load the module dependency
54+
fxtrace.FxTraceModule, // load the module
55+
fx.Invoke(func(tracerProvider oteltrace.TracerProvider) {
56+
// invoke the tracer provider to create a span
57+
_, span := tracerProvider.Tracer("some tracer").Start(context.Background(), "some span")
58+
defer span.End()
59+
}),
60+
).Run()
61+
}
62+
```
63+
64+
### Configuration
65+
66+
This module provides the possibility to configure the `processor`:
67+
68+
- `noop`: to async void traces (default and fallback)
69+
- `stdout`: to async print traces to stdout
70+
- `otlp-grpc`: to async send traces to [OTLP/gRPC](https://opentelemetry.io/docs/specs/otlp/#otlpgrpc) collectors (ex: [Jaeger](https://www.jaegertracing.io/), [Grafana](https://grafana.com/docs/tempo/latest/configuration/grafana-agent/#grafana-agent), etc.)
71+
- `test`: to sync store traces in memory (for testing assertions)
72+
73+
If an error occurs while creating the processor (for example failing OTLP/gRPC connection), the `noop` processor will be
74+
used as safety fallback (to prevent outages).
75+
76+
This module also provides possibility to configure the `sampler`:
77+
78+
- `parent-based-always-on`: always on depending on parent (default)
79+
- `parent-based-always-off`: always off depending on parent
80+
- `parent-based-trace-id-ratio`: trace id ratio based depending on parent
81+
- `always-on`: always on
82+
- `always-off`: always off
83+
- `trace-id-ratio`: trace id ratio based
84+
85+
Example with `stdout` processor (with pretty print) and `parent-based-trace-id-ratio` sampler (ratio=0.5):
86+
87+
```yaml
88+
# ./configs/config.yaml
89+
app:
90+
name: app
91+
env: dev
92+
version: 0.1.0
93+
debug: false
94+
modules:
95+
trace:
96+
processor:
97+
type: stdout
98+
options:
99+
pretty: true
100+
sampler:
101+
type: parent-based-trace-id-ratio
102+
options:
103+
ratio: 0.5
104+
```
105+
106+
Another example with `otlp-grpc` processor (on jaeger:4317 host) and `always-on` sampler:
107+
108+
```yaml
109+
# ./configs/config.yaml
110+
app:
111+
name: app
112+
env: dev
113+
version: 0.1.0
114+
debug: false
115+
modules:
116+
trace:
117+
processor:
118+
type: otlp-grpc
119+
options:
120+
host: jaeger:4317
121+
sampler:
122+
type: always-on
123+
```
124+
125+
### Override
126+
127+
By default, the `oteltrace.TracerProvider` is created by the [DefaultTracerProviderFactory](https://github.com/ankorstore/yokai/blob/main/trace/factory.go).
128+
129+
If needed, you can provide your own factory and override the module:
130+
131+
```go
132+
package main
133+
134+
import (
135+
"context"
136+
137+
"github.com/ankorstore/yokai/fxconfig"
138+
"github.com/ankorstore/yokai/fxtrace"
139+
"github.com/ankorstore/yokai/trace"
140+
otelsdktrace "go.opentelemetry.io/otel/sdk/trace"
141+
oteltrace "go.opentelemetry.io/otel/trace"
142+
"go.uber.org/fx"
143+
)
144+
145+
type CustomTracerProviderFactory struct{}
146+
147+
func NewCustomTracerProviderFactory() trace.TracerProviderFactory {
148+
return &CustomTracerProviderFactory{}
149+
}
150+
151+
func (f *CustomTracerProviderFactory) Create(options ...trace.TracerProviderOption) (*otelsdktrace.TracerProvider, error) {
152+
return &otelsdktrace.TracerProvider{...}, nil
153+
}
154+
155+
func main() {
156+
fx.New(
157+
fxconfig.FxConfigModule, // load the module dependency
158+
fxtrace.FxTraceModule, // load the module
159+
fx.Decorate(NewCustomTracerProviderFactory), // override the module with a custom factory
160+
fx.Invoke(func(tracerProvider oteltrace.TracerProvider) { // invoke the custom tracer provider
161+
_, span := tracerProvider.Tracer("custom tracer").Start(context.Background(), "custom span")
162+
defer span.End()
163+
}),
164+
).Run()
165+
}
166+
```
167+
168+
### Testing
169+
170+
This module provides the possibility to easily test your trace spans, using the [TestTraceExporter](https://github.com/ankorstore/yokai/blob/main/trace/tracetest/exporter.go) with `modules.trace.processor.type=test`.
171+
172+
```yaml
173+
# ./configs/config.test.yaml
174+
modules:
175+
trace:
176+
processor:
177+
type: test # to send traces to test buffer
178+
```
179+
180+
You can then test:
181+
182+
```go
183+
package main_test
184+
185+
import (
186+
"context"
187+
"testing"
188+
189+
"github.com/ankorstore/yokai/fxconfig"
190+
"github.com/ankorstore/yokai/fxtrace"
191+
"github.com/ankorstore/yokai/trace/tracetest"
192+
"go.opentelemetry.io/otel/attribute"
193+
oteltrace "go.opentelemetry.io/otel/trace"
194+
"go.uber.org/fx"
195+
"go.uber.org/fx/fxtest"
196+
)
197+
198+
func TestTracerProvider(t *testing.T) {
199+
t.Setenv("APP_NAME", "test")
200+
t.Setenv("APP_ENV", "test")
201+
202+
var exporter tracetest.TestTraceExporter
203+
204+
fxtest.New(
205+
t,
206+
fx.NopLogger,
207+
fxconfig.FxConfigModule,
208+
fxtrace.FxTraceModule,
209+
fx.Invoke(func(tracerProvider oteltrace.TracerProvider) {
210+
_, span := tracerProvider.Tracer("some tracer").Start(
211+
context.Background(),
212+
"some span",
213+
oteltrace.WithAttributes(attribute.String("some attribute name", "some attribute value")),
214+
)
215+
defer span.End()
216+
}),
217+
fx.Populate(&exporter), // extracts the TestTraceExporter from the Fx container
218+
).RequireStart().RequireStop()
219+
220+
// assertion success
221+
tracetest.AssertHasTraceSpan(t, exporter, "some span", attribute.String("some attribute name", "some attribute value"))
222+
}
223+
```
224+
225+
See the `trace` module testing [documentation](https://github.com/ankorstore/yokai/tree/main/trace#test-span-processor) for more details.

fxtrace/go.mod

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
module github.com/ankorstore/yokai/fxtrace
2+
3+
go 1.20
4+
5+
require (
6+
github.com/ankorstore/yokai/config v1.1.0
7+
github.com/ankorstore/yokai/fxconfig v1.0.0
8+
github.com/ankorstore/yokai/trace v1.0.0
9+
github.com/stretchr/testify v1.8.4
10+
go.opentelemetry.io/otel v1.16.0
11+
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0
12+
go.opentelemetry.io/otel/sdk v1.16.0
13+
go.opentelemetry.io/otel/trace v1.16.0
14+
go.uber.org/fx v1.20.1
15+
)
16+
17+
require (
18+
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
19+
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
20+
github.com/fsnotify/fsnotify v1.7.0 // indirect
21+
github.com/go-logr/logr v1.2.4 // indirect
22+
github.com/go-logr/stdr v1.2.2 // indirect
23+
github.com/golang/protobuf v1.5.3 // indirect
24+
github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect
25+
github.com/hashicorp/hcl v1.0.0 // indirect
26+
github.com/magiconair/properties v1.8.7 // indirect
27+
github.com/mitchellh/mapstructure v1.5.0 // indirect
28+
github.com/pelletier/go-toml/v2 v2.1.1 // indirect
29+
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
30+
github.com/sagikazarmark/locafero v0.4.0 // indirect
31+
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
32+
github.com/sourcegraph/conc v0.3.0 // indirect
33+
github.com/spf13/afero v1.11.0 // indirect
34+
github.com/spf13/cast v1.6.0 // indirect
35+
github.com/spf13/pflag v1.0.5 // indirect
36+
github.com/spf13/viper v1.18.2 // indirect
37+
github.com/subosito/gotenv v1.6.0 // indirect
38+
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0 // indirect
39+
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0 // indirect
40+
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0 // indirect
41+
go.opentelemetry.io/otel/metric v1.16.0 // indirect
42+
go.opentelemetry.io/proto/otlp v0.19.0 // indirect
43+
go.uber.org/dig v1.17.1 // indirect
44+
go.uber.org/multierr v1.11.0 // indirect
45+
go.uber.org/zap v1.26.0 // indirect
46+
golang.org/x/exp v0.0.0-20240110193028-0dcbfd608b1e // indirect
47+
golang.org/x/net v0.19.0 // indirect
48+
golang.org/x/sys v0.16.0 // indirect
49+
golang.org/x/text v0.14.0 // indirect
50+
google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 // indirect
51+
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 // indirect
52+
google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f // indirect
53+
google.golang.org/grpc v1.59.0 // indirect
54+
google.golang.org/protobuf v1.31.0 // indirect
55+
gopkg.in/ini.v1 v1.67.0 // indirect
56+
gopkg.in/yaml.v3 v3.0.1 // indirect
57+
)

0 commit comments

Comments
 (0)