Skip to content

Commit

Permalink
feat(fxtrace): Provided module (#28)
Browse files Browse the repository at this point in the history
  • Loading branch information
ekkinox committed Jan 11, 2024
1 parent 70888a2 commit 6757f8e
Show file tree
Hide file tree
Showing 13 changed files with 1,391 additions and 0 deletions.
1 change: 1 addition & 0 deletions .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ jobs:
- "fxconfig"
- "fxgenerate"
- "fxlog"
- "fxtrace"
steps:
- name: Checkout
uses: actions/checkout@v3
Expand Down
31 changes: 31 additions & 0 deletions .github/workflows/fxtrace-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: "fxtrace-ci"

on:
push:
branches:
- "feat**"
- "fix**"
- "hotfix**"
- "chore**"
paths:
- "fxtrace/**.go"
- "fxtrace/go.mod"
- "fxtrace/go.sum"
pull_request:
types:
- opened
- synchronize
- reopened
branches:
- main
paths:
- "fxtrace/**.go"
- "fxtrace/go.mod"
- "fxtrace/go.sum"

jobs:
ci:
uses: ./.github/workflows/common-ci.yml
secrets: inherit
with:
module: "fxtrace"
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Yokai's `Fx modules` are the plugins for your Yokai application.
| [fxconfig](fxconfig) | Fx module for [config](config) |
| [fxgenerate](fxgenerate) | Fx module for [generate](generate) |
| [fxlog](fxlog) | Fx module for [log](log) |
| [fxtrace](fxtrace) | Fx module for [trace](trace) |

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

Expand Down
64 changes: 64 additions & 0 deletions fxtrace/.golangci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
run:
timeout: 5m
concurrency: 8

linters:
enable:
- asasalint
- asciicheck
- bidichk
- bodyclose
- containedctx
- contextcheck
- decorder
- dogsled
- dupl
- durationcheck
- errcheck
- errchkjson
- errname
- errorlint
- forbidigo
- forcetypeassert
- gocognit
- goconst
- gocritic
- gocyclo
- godot
- godox
- gofmt
- goheader
- gomoddirectives
- gomodguard
- goprintffuncname
- gosec
- gosimple
- govet
- grouper
- importas
- ineffassign
- interfacebloat
- logrlint
- maintidx
- makezero
- misspell
- nestif
- nilerr
- nilnil
- nlreturn
- nolintlint
- nosprintfhostport
- prealloc
- predeclared
- promlinter
- reassign
- staticcheck
- tenv
- thelper
- tparallel
- typecheck
- unconvert
- unparam
- unused
- usestdlibvars
- whitespace
225 changes: 225 additions & 0 deletions fxtrace/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
# Fx Trace Module

[![ci](https://github.com/ankorstore/yokai/actions/workflows/fxtrace-ci.yml/badge.svg)](https://github.com/ankorstore/yokai/actions/workflows/fxtrace-ci.yml)
[![go report](https://goreportcard.com/badge/github.com/ankorstore/yokai/fxtrace)](https://goreportcard.com/report/github.com/ankorstore/yokai/fxtrace)
[![codecov](https://codecov.io/gh/ankorstore/yokai/graph/badge.svg?token=ghUBlFsjhR&flag=fxtrace)](https://app.codecov.io/gh/ankorstore/yokai/tree/main/fxtrace)
[![Deps](https://img.shields.io/badge/osi-deps-blue)](https://deps.dev/go/github.com%2Fankorstore%2Fyokai%2Ffxtrace)
[![PkgGoDev](https://pkg.go.dev/badge/github.com/ankorstore/yokai/fxtrace)](https://pkg.go.dev/github.com/ankorstore/yokai/fxtrace)

> [Fx](https://uber-go.github.io/fx/) module for [trace](https://github.com/ankorstore/yokai/tree/main/trace).
<!-- TOC -->
* [Installation](#installation)
* [Documentation](#documentation)
* [Dependencies](#dependencies)
* [Loading](#loading)
* [Configuration](#configuration)
* [Override](#override)
* [Testing](#testing)
<!-- TOC -->

## Installation

```shell
go get github.com/ankorstore/yokai/fxtrace
```

## Documentation

### Dependencies

This module is intended to be used alongside the [fxconfig](https://github.com/ankorstore/yokai/tree/main/fxconfig)
module.

### Loading

To load the module in your Fx application:

```go
package main

import (
"context"

"github.com/ankorstore/yokai/config"
"github.com/ankorstore/yokai/fxconfig"
"github.com/ankorstore/yokai/fxtrace"
oteltrace "go.opentelemetry.io/otel/trace"
"go.uber.org/fx"
)

func main() {
fx.New(
fxconfig.FxConfigModule, // load the module dependency
fxtrace.FxTraceModule, // load the module
fx.Invoke(func(tracerProvider oteltrace.TracerProvider) {
// invoke the tracer provider to create a span
_, span := tracerProvider.Tracer("some tracer").Start(context.Background(), "some span")
defer span.End()
}),
).Run()
}
```

### Configuration

This module provides the possibility to configure the `processor`:

- `noop`: to async void traces (default and fallback)
- `stdout`: to async print traces to stdout
- `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.)
- `test`: to sync store traces in memory (for testing assertions)

If an error occurs while creating the processor (for example failing OTLP/gRPC connection), the `noop` processor will be
used as safety fallback (to prevent outages).

This module also provides possibility to configure the `sampler`:

- `parent-based-always-on`: always on depending on parent (default)
- `parent-based-always-off`: always off depending on parent
- `parent-based-trace-id-ratio`: trace id ratio based depending on parent
- `always-on`: always on
- `always-off`: always off
- `trace-id-ratio`: trace id ratio based

Example with `stdout` processor (with pretty print) and `parent-based-trace-id-ratio` sampler (ratio=0.5):

```yaml
# ./configs/config.yaml
app:
name: app
env: dev
version: 0.1.0
debug: false
modules:
trace:
processor:
type: stdout
options:
pretty: true
sampler:
type: parent-based-trace-id-ratio
options:
ratio: 0.5
```

Another example with `otlp-grpc` processor (on jaeger:4317 host) and `always-on` sampler:

```yaml
# ./configs/config.yaml
app:
name: app
env: dev
version: 0.1.0
debug: false
modules:
trace:
processor:
type: otlp-grpc
options:
host: jaeger:4317
sampler:
type: always-on
```

### Override

By default, the `oteltrace.TracerProvider` is created by the [DefaultTracerProviderFactory](https://github.com/ankorstore/yokai/blob/main/trace/factory.go).

If needed, you can provide your own factory and override the module:

```go
package main

import (
"context"

"github.com/ankorstore/yokai/fxconfig"
"github.com/ankorstore/yokai/fxtrace"
"github.com/ankorstore/yokai/trace"
otelsdktrace "go.opentelemetry.io/otel/sdk/trace"
oteltrace "go.opentelemetry.io/otel/trace"
"go.uber.org/fx"
)

type CustomTracerProviderFactory struct{}

func NewCustomTracerProviderFactory() trace.TracerProviderFactory {
return &CustomTracerProviderFactory{}
}

func (f *CustomTracerProviderFactory) Create(options ...trace.TracerProviderOption) (*otelsdktrace.TracerProvider, error) {
return &otelsdktrace.TracerProvider{...}, nil
}

func main() {
fx.New(
fxconfig.FxConfigModule, // load the module dependency
fxtrace.FxTraceModule, // load the module
fx.Decorate(NewCustomTracerProviderFactory), // override the module with a custom factory
fx.Invoke(func(tracerProvider oteltrace.TracerProvider) { // invoke the custom tracer provider
_, span := tracerProvider.Tracer("custom tracer").Start(context.Background(), "custom span")
defer span.End()
}),
).Run()
}
```

### Testing

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`.

```yaml
# ./configs/config.test.yaml
modules:
trace:
processor:
type: test # to send traces to test buffer
```

You can then test:

```go
package main_test

import (
"context"
"testing"

"github.com/ankorstore/yokai/fxconfig"
"github.com/ankorstore/yokai/fxtrace"
"github.com/ankorstore/yokai/trace/tracetest"
"go.opentelemetry.io/otel/attribute"
oteltrace "go.opentelemetry.io/otel/trace"
"go.uber.org/fx"
"go.uber.org/fx/fxtest"
)

func TestTracerProvider(t *testing.T) {
t.Setenv("APP_NAME", "test")
t.Setenv("APP_ENV", "test")

var exporter tracetest.TestTraceExporter

fxtest.New(
t,
fx.NopLogger,
fxconfig.FxConfigModule,
fxtrace.FxTraceModule,
fx.Invoke(func(tracerProvider oteltrace.TracerProvider) {
_, span := tracerProvider.Tracer("some tracer").Start(
context.Background(),
"some span",
oteltrace.WithAttributes(attribute.String("some attribute name", "some attribute value")),
)
defer span.End()
}),
fx.Populate(&exporter), // extracts the TestTraceExporter from the Fx container
).RequireStart().RequireStop()

// assertion success
tracetest.AssertHasTraceSpan(t, exporter, "some span", attribute.String("some attribute name", "some attribute value"))
}
```

See the `trace` module testing [documentation](https://github.com/ankorstore/yokai/tree/main/trace#test-span-processor) for more details.
57 changes: 57 additions & 0 deletions fxtrace/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
module github.com/ankorstore/yokai/fxtrace

go 1.20

require (
github.com/ankorstore/yokai/config v1.1.0
github.com/ankorstore/yokai/fxconfig v1.0.0
github.com/ankorstore/yokai/trace v1.0.0
github.com/stretchr/testify v1.8.4
go.opentelemetry.io/otel v1.16.0
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0
go.opentelemetry.io/otel/sdk v1.16.0
go.opentelemetry.io/otel/trace v1.16.0
go.uber.org/fx v1.20.1
)

require (
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/go-logr/logr v1.2.4 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/pelletier/go-toml/v2 v2.1.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.6.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.18.2 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0 // indirect
go.opentelemetry.io/otel/metric v1.16.0 // indirect
go.opentelemetry.io/proto/otlp v0.19.0 // indirect
go.uber.org/dig v1.17.1 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.26.0 // indirect
golang.org/x/exp v0.0.0-20240110193028-0dcbfd608b1e // indirect
golang.org/x/net v0.19.0 // indirect
golang.org/x/sys v0.16.0 // indirect
golang.org/x/text v0.14.0 // indirect
google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f // indirect
google.golang.org/grpc v1.59.0 // indirect
google.golang.org/protobuf v1.31.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
Loading

0 comments on commit 6757f8e

Please sign in to comment.