Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(fxtrace): Provided module #28

Merged
merged 1 commit into from
Jan 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading