Recommended: OpenTelemetry SDK
Use the official Go OTel SDK to send traces and error spans to Squasher.1. Install
go get go.opentelemetry.io/otel \
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp \
go.opentelemetry.io/otel/sdk/trace
2. Configure
package main
import (
"context"
"log"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
"go.opentelemetry.io/otel/sdk/resource"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
semconv "go.opentelemetry.io/otel/semconv/v1.24.0"
)
func initTracer() func() {
exporter, err := otlptracehttp.New(
context.Background(),
otlptracehttp.WithEndpoint("ingest.squasher.ai"),
otlptracehttp.WithHeaders(map[string]string{
"x-squasher-key": "sq_pk_your_api_key",
}),
)
if err != nil {
log.Fatalf("failed to create exporter: %v", err)
}
tp := sdktrace.NewTracerProvider(
sdktrace.WithBatcher(exporter),
sdktrace.WithResource(resource.NewWithAttributes(
semconv.SchemaURL,
semconv.ServiceName("my-go-service"),
semconv.DeploymentEnvironment("production"),
)),
)
otel.SetTracerProvider(tp)
return func() { tp.Shutdown(context.Background()) }
}
3. Use
func main() {
shutdown := initTracer()
defer shutdown()
tracer := otel.Tracer("my-app")
ctx, span := tracer.Start(context.Background(), "process-order")
defer span.End()
if err := processOrder(ctx); err != nil {
span.RecordError(err) // Squasher captures this as an error event
span.SetStatus(codes.Error, err.Error())
}
}
Alternative: Direct HTTP API
Send errors directly without OpenTelemetry:package squasher
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"runtime"
"time"
)
type Event struct {
Message string `json:"message"`
Type string `json:"type,omitempty"`
Level string `json:"level"`
Stack string `json:"stack,omitempty"`
Environment string `json:"environment,omitempty"`
Release string `json:"release,omitempty"`
Tags map[string]string `json:"tags,omitempty"`
Timestamp string `json:"timestamp,omitempty"`
}
var (
ProjectID = "YOUR_PROJECT_ID"
APIKey = "sq_pk_your_api_key"
Endpoint = "https://ingest.squasher.ai"
)
func CaptureError(err error, tags map[string]string) {
buf := make([]byte, 4096)
n := runtime.Stack(buf, false)
event := Event{
Message: err.Error(),
Type: fmt.Sprintf("%T", err),
Level: "error",
Stack: string(buf[:n]),
Environment: "production",
Tags: tags,
Timestamp: time.Now().UTC().Format(time.RFC3339),
}
body, _ := json.Marshal(event)
req, _ := http.NewRequest("POST",
fmt.Sprintf("%s/v1/ingest/%s", Endpoint, ProjectID),
bytes.NewReader(body))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("x-squasher-key", APIKey)
go http.DefaultClient.Do(req)
}
func Log(level, message string, tags map[string]string) {
event := Event{
Message: message,
Level: level,
Tags: tags,
Timestamp: time.Now().UTC().Format(time.RFC3339),
}
body, _ := json.Marshal(event)
req, _ := http.NewRequest("POST",
fmt.Sprintf("%s/v1/ingest/%s", Endpoint, ProjectID),
bytes.NewReader(body))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("x-squasher-key", APIKey)
go http.DefaultClient.Do(req)
}
Usage
func main() {
// Capture errors
if err := doWork(); err != nil {
squasher.CaptureError(err, map[string]string{"job": "data-sync"})
}
// Send structured logs
squasher.Log("info", "Job completed", map[string]string{
"duration_ms": "1234",
"records": "500",
})
}
First-party SDK
If the service already useslog/slog, use the Go SDK for a smaller logging-handler integration.
Agent handoff
For Go, prefer the Squasher Go SDK when slog logging is enough and OpenTelemetry when the service already emits traces. Keep SQUASHER_API_KEY and SQUASHER_PROJECT_ID in env, call shutdown/flush paths, and verify with one error event.