package main
import (
"context"
"github.com/go-chi/chi/v5"
"log"
"net/http"
"os"
"time"
"github.com/go-chi/chi/v5/middleware"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
"go.opentelemetry.io/otel/exporters/stdout/stdouttrace"
"go.opentelemetry.io/otel/sdk/resource"
oteltrace "go.opentelemetry.io/otel/sdk/trace"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
"go.opentelemetry.io/otel/trace"
)
var (
tracer trace.Tracer
otlpEndpoint string
)
func init() {
otlpEndpoint = os.Getenv("OTLP_ENDPOINT")
if otlpEndpoint == "" {
otlpEndpoint = "localhost:4318"
}
}
// Console Exporter, only for testing
func newConsoleExporter() (oteltrace.SpanExporter, error) {
return stdouttrace.New()
}
// OTLP Exporter
func newOTLPExporter(ctx context.Context) (oteltrace.SpanExporter, error) {
insecureOpt := otlptracehttp.WithInsecure()
endpointOpt := otlptracehttp.WithEndpoint(otlpEndpoint)
return otlptracehttp.New(ctx, insecureOpt, endpointOpt)
}
func newTraceProvider(exp sdktrace.SpanExporter) *sdktrace.TracerProvider {
r, err := resource.Merge(
resource.Default(),
resource.NewWithAttributes(
semconv.SchemaURL,
semconv.ServiceName("myapp"),
),
)
if err != nil {
panic(err)
}
return sdktrace.NewTracerProvider(
sdktrace.WithBatcher(exp),
sdktrace.WithResource(r),
)
}
func main() {
ctx := context.Background()
// For testing to print out traces to the console
exp, err := newConsoleExporter()
//exp, err := newOTLPExporter(ctx)
if err != nil {
log.Fatalf("failed to initialize exporter: %v", err)
}
tp := newTraceProvider(exp)
defer func() { _ = tp.Shutdown(ctx) }()
otel.SetTracerProvider(tp)
tracer = tp.Tracer("myapp")
r := chi.NewRouter()
r.Use(middleware.Logger)
r.Get("/devices", getDevices)
http.ListenAndServe(":8080", r)
log.Println("okay")
}
func getDevices(w http.ResponseWriter, r *http.Request) {
ctx, span := tracer.Start(r.Context(), "HTTP GET /devices")
defer span.End()
// Simulate Database call to fetch connected devices.
db(ctx)
// Add additional delay to simulate HTTP request.
time.Sleep(1 * time.Second)
// Return devices
w.Write([]byte("ok"))
}
func db(ctx context.Context) {
_, span := tracer.Start(ctx, "SQL SELECT")
defer span.End()
// Simulate Database call to SELECT connected devices.
time.Sleep(2 * time.Second)
}