Skip to content
This repository has been archived by the owner on Jun 12, 2024. It is now read-only.

feat: Add package for the default OpenTelemetry usage #201

Merged
merged 2 commits into from
Jan 9, 2022
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
24 changes: 18 additions & 6 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,9 @@ require (
github.com/go-ozzo/ozzo-validation v3.6.0+incompatible
github.com/go-ozzo/ozzo-validation/v4 v4.3.0
github.com/golang-jwt/jwt/v4 v4.2.0
github.com/golang/protobuf v1.5.2 // indirect
github.com/gorilla/websocket v1.4.2
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0
github.com/lib/pq v1.10.4
github.com/onsi/ginkgo v1.7.0 // indirect
github.com/onsi/gomega v1.4.3 // indirect
github.com/opentracing/opentracing-go v1.2.0
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.11.0
Expand All @@ -29,13 +26,28 @@ require (
github.com/uber/jaeger-client-go v2.30.0+incompatible
github.com/uber/jaeger-lib v2.4.1+incompatible // indirect
github.com/urfave/negroni v1.0.0
go.opentelemetry.io/contrib/detectors/aws/eks v1.3.0
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.28.0
go.opentelemetry.io/contrib/instrumentation/runtime v0.27.0
go.opentelemetry.io/contrib/propagators/aws v1.3.0
go.opentelemetry.io/contrib/propagators/jaeger v1.3.0
go.opentelemetry.io/otel v1.3.0
go.opentelemetry.io/otel/exporters/jaeger v1.3.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.3.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.3.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.3.0
go.opentelemetry.io/otel/exporters/prometheus v0.26.0
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.3.0
go.opentelemetry.io/otel/metric v0.26.0
go.opentelemetry.io/otel/sdk v1.3.0
go.opentelemetry.io/otel/sdk/export/metric v0.26.0
go.opentelemetry.io/otel/sdk/metric v0.26.0
go.opentelemetry.io/otel/trace v1.3.0
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/goleak v1.1.12
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83
golang.org/x/tools v0.1.8
google.golang.org/protobuf v1.27.1
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 // indirect
)

go 1.14
430 changes: 419 additions & 11 deletions go.sum

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions pkg/otel/component/info.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package component

// Info is the component metadata used to configure the OTEL sdks.
type Info struct {
Name string `json:"name"`
Version string `json:"version"`
Commit string `json:"commit"`
}
87 changes: 87 additions & 0 deletions pkg/otel/metrics/prom.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package metrics

import (
"context"
"fmt"
"log"
"time"

"github.com/contiamo/go-base/v4/pkg/otel/component"
prom "github.com/prometheus/client_golang/prometheus"

"go.opentelemetry.io/contrib/instrumentation/runtime"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/exporters/prometheus"
"go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/metric/global"
"go.opentelemetry.io/otel/sdk/export/metric/aggregation"
controller "go.opentelemetry.io/otel/sdk/metric/controller/basic"
processor "go.opentelemetry.io/otel/sdk/metric/processor/basic"
selector "go.opentelemetry.io/otel/sdk/metric/selector/simple"
"go.opentelemetry.io/otel/sdk/resource"
semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
)

// Setup configures the OpenTelemetry Resource and Prometheus metrics exporter.
// Additionally, it configures and sets the component_info metric that allows
// you to monitor the version of the application.
//
// All metrics are registered with the default Prometheus global registry.
func Setup(component component.Info) (*prometheus.Exporter, error) {
baseResource, err := resource.New(
context.Background(),
resource.WithHost(),
resource.WithAttributes(
semconv.ServiceVersionKey.String(component.Version),
semconv.ServiceNameKey.String(component.Name),
),
resource.WithFromEnv(),
)
if err != nil {
return nil, err
}

config := prometheus.Config{
Registerer: prom.DefaultRegisterer,
Gatherer: prom.DefaultGatherer,
}
c := controller.New(
processor.NewFactory(
selector.NewWithHistogramDistribution(),
aggregation.CumulativeTemporalitySelector(),
processor.WithMemory(true),
),
controller.WithResource(baseResource),
)
exporter, err := prometheus.New(config, c)
if err != nil {
return nil, fmt.Errorf("failed to initialize prometheus exporter: %w", err)
}
global.SetMeterProvider(exporter.MeterProvider())

err = runtime.Start(
runtime.WithMinimumReadMemStatsInterval(time.Second),
)
if err != nil {
log.Fatalln("failed to start runtime instrumentation:", err)
}

meter := global.Meter(component.Name)
componentInfo, err := meter.NewInt64UpDownCounter(
"component_info",
metric.WithDescription("version information of the component"),
)
if err != nil {
return nil, fmt.Errorf("failed to create component_info metric: %w", err)
}

componentInfo.Add(
context.Background(),
1,
attribute.Key("version").String(component.Version),
attribute.Key("commit").String(component.Commit),
attribute.Key("name").String(component.Name),
)

return exporter, nil
}
41 changes: 41 additions & 0 deletions pkg/otel/middleware.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package otel

import (
"net/http"

"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/filters"
)

// Middleware configures the otelhttp.NewHandler and returns a middleware is compatible
// with the chi router interface.
//
// Example:
//
// r := chi.NewRouter()
// r.Use(otel.Middleware("Server"))
//
// The most common options to pass will be the otelhttp.WithFilter and otelhttp.WithSpanNameFormatter
//
// When no options are passed a default filter for /metrics and /health is used.
func Middleware(name string, opts ...otelhttp.Option) func(next http.Handler) http.Handler {
if name == "" {
name = "Server"
}
if len(opts) == 0 {
opts = []otelhttp.Option{WithInternalPathFilter}
}

return func(next http.Handler) http.Handler {
return otelhttp.NewHandler(next, name, opts...)
}
}

// WithInternalPathFilter is the default tracing filter passed to the Middleware.
// It filters out /metrics and /health requests.
var WithInternalPathFilter = otelhttp.WithFilter(
filters.None(
filters.Path("/metrics"),
filters.Path("/health"),
),
)
21 changes: 21 additions & 0 deletions pkg/otel/tracing/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package tracing

import (
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/trace"
)

// RecordError is a utility to simplify recording an error to the
// OpenTelemetry span and setting the error status code.
func RecordError(span trace.Span, err error) {
if err == nil {
return
}

if span == nil {
return
}

span.RecordError(err)
span.SetStatus(codes.Error, err.Error())
}
Loading