otelmuxsampler

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 3, 2023 License: MIT Imports: 5 Imported by: 1

README

OpenTelemetry Multiplexed Sampler for Go

Go Reference Go Report Card MIT License

Overview

github.com/mashiike/otelmuxsampler is a Go package for advanced sampling control in applications using OpenTelemetry's Go implementation. It supports complex sampling rules and allows you to combine them to create flexible sampling strategies. By using this package, you can effectively manage the collection of trace data and optimize your application's performance.

Installation

You can install the github.com/mashiike/otelmuxsampler package using the following command:

go get github.com/mashiike/otelmuxsampler

Usage

for example, you can use it like this:

package main

import (
	"context"
	"fmt"
	"log"
	"math/rand"
	"net/http"
	"os"
	"time"

	"github.com/mashiike/otelmuxsampler"
	"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/attribute"
	"go.opentelemetry.io/otel/exporters/stdout/stdouttrace"
	sdktrace "go.opentelemetry.io/otel/sdk/trace"
	"go.opentelemetry.io/otel/trace"
)

func main() {
	cleanup, err := setupTraceProvider()
	if err != nil {
		log.Fatal(err)
	}
	defer cleanup()

	mux := http.NewServeMux()
	mux.HandleFunc("/critical", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("critical"))
	})
	mux.HandleFunc("/high", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("high"))
	})
	mux.HandleFunc("/medium", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("medium"))
	})
	mux.HandleFunc("/low", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("low"))
	})
	paths := []string{"/critical", "/high", "/medium", "/low"}
	rnd := rand.New(rand.NewSource(time.Now().UnixNano()))
	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		redirectTo := paths[rnd.Intn(len(paths))]
		http.Redirect(w, r, redirectTo, http.StatusFound)
	})
	middleware := func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			log.Println("[info] request:", r.URL.Path)
			otelhttp.NewHandler(otelhttp.WithRouteTag(r.URL.Path, next), r.URL.Path, otelhttp.WithSpanOptions(
				trace.WithAttributes(attribute.String("server.request.class", getRequestClass(r))),
			)).ServeHTTP(w, r)
		})
	}
	log.Println("[info] start server, access to http://localhost:8080/")
	if err := http.ListenAndServe(":8080", middleware(mux)); err != nil {
		log.Fatal("[error]", err)
	}
}

func getRequestClass(r *http.Request) string {
	switch r.URL.Path {
	case "/critical":
		return "critical"
	case "/high":
		return "high"
	case "/medium":
		return "medium"
	default:
		return "low"
	}
}

func setupTraceProvider() (func(), error) {
	exporter, err := stdouttrace.New(
		stdouttrace.WithPrettyPrint(),
		stdouttrace.WithWriter(os.Stdout),
	)
	if err != nil {
		return func() {}, fmt.Errorf("failed to create stdout exporter: %w", err)
	}
	mux := otelmuxsampler.Multiplexed(sdktrace.NeverSample())
	mux.AttributeEqual(attribute.String("server.request.class", "critical"), sdktrace.AlwaysSample())
	mux.AttributeEqual(attribute.String("server.request.class", "high"), sdktrace.TraceIDRatioBased(0.5))
	mux.AttributeEqual(attribute.String("server.request.class", "medium"), sdktrace.TraceIDRatioBased(0.01))
	mux.AttributeEqual(attribute.String("server.request.class", "low"), sdktrace.NeverSample())

	tp := sdktrace.NewTracerProvider(
		sdktrace.WithBatcher(exporter),
		sdktrace.WithSampler(sdktrace.ParentBased(mux)),
	)
	otel.SetTracerProvider(tp)
	log.Println("[info] setup trace provider")
	return func() {
		ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
		defer cancel()
		if err := tp.Shutdown(ctx); err != nil {
			log.Println("[error] failed to shutdown:", err)
		}
	}, nil
}

License

github.com/mashiike/otelmuxsampler is licensed under the MIT License. See LICENSE for the full license text.

Documentation

Overview

Example
package main

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

	"github.com/mashiike/otelmuxsampler"
	"go.opentelemetry.io/otel/attribute"
	sdktrace "go.opentelemetry.io/otel/sdk/trace"
	"go.opentelemetry.io/otel/trace"
)

type onMemoryExporter struct {
	mu    sync.Mutex
	spans []sdktrace.ReadOnlySpan
}

func (e *onMemoryExporter) ExportSpans(ctx context.Context, spans []sdktrace.ReadOnlySpan) error {
	e.mu.Lock()
	defer e.mu.Unlock()
	e.spans = append(e.spans, spans...)
	return nil
}

func (e *onMemoryExporter) Shutdown(ctx context.Context) error {
	return nil
}

func main() {
	exporter := &onMemoryExporter{}
	// only priority=high span is sampled
	mux := otelmuxsampler.Multiplexed(sdktrace.NeverSample())
	mux.AttributeEqual(attribute.String("priority", "high"), sdktrace.AlwaysSample())
	tp := sdktrace.NewTracerProvider(
		sdktrace.WithBatcher(exporter),
		sdktrace.WithSampler(sdktrace.ParentBased(mux)),
	)
	// operation1 is priority=high, operation2 is priority=low
	tr := tp.Tracer("example")
	func() {
		_, span := tr.Start(nil, "operation1", trace.WithAttributes(
			attribute.String("priority", "high"),
		))
		defer span.End()
	}()
	func() {
		_, span := tr.Start(nil, "operation2", trace.WithAttributes(
			attribute.String("priority", "low"),
		))
		defer span.End()
	}()
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	if err := tp.Shutdown(ctx); err != nil {
		log.Fatal("failed to shutdown:", err)
	}

	// stdout to span names
	for _, span := range exporter.spans {
		fmt.Println(span.Name())
	}
}
Output:

operation1

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Handler

type Handler interface {
	Match(sdktrace.SamplingParameters) bool
	sdktrace.Sampler
}

func NewHandler

func NewHandler(matcher func(sdktrace.SamplingParameters) bool, sampler sdktrace.Sampler) Handler

type Multiplexer

type Multiplexer struct {
	// contains filtered or unexported fields
}

Multiplexer is a Sampler that multiplexes sampling decisions

func Multiplexed

func Multiplexed(sampler sdktrace.Sampler) *Multiplexer

Multiplexed returns a new Multiplexer

func (*Multiplexer) AttributeEqual

func (mux *Multiplexer) AttributeEqual(attr attribute.KeyValue, sampler sdktrace.Sampler)

func (*Multiplexer) AttributeExists

func (mux *Multiplexer) AttributeExists(attrKey attribute.Key, sampler sdktrace.Sampler)

func (*Multiplexer) Description

func (mux *Multiplexer) Description() string

func (*Multiplexer) Handle

func (mux *Multiplexer) Handle(name string, handler Handler)

func (*Multiplexer) HandleFunc

func (mux *Multiplexer) HandleFunc(name string, matcher func(sdktrace.SamplingParameters) bool, sampler sdktrace.Sampler)

func (*Multiplexer) ShouldSample

Directories

Path Synopsis
example module

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL