Official Go SDK for LogTide with automatic batching, retry logic, circuit breaker pattern, Hub/Scope context isolation, and native OpenTelemetry integration.
Installation
go get github.com/logtide-dev/logtide-sdk-go Requires Go 1.23 or later.
Quick Start
Global singleton (recommended)
package main
import (
"context"
logtide "github.com/logtide-dev/logtide-sdk-go"
)
func main() {
flush := logtide.Init(logtide.ClientOptions{
DSN: "https://[email protected]",
Service: "my-service",
Environment: "production",
Release: "v1.2.3",
})
defer flush()
ctx := context.Background()
logtide.Info(ctx, "Server started", map[string]any{"port": 8080})
logtide.Error(ctx, "Connection failed", map[string]any{"host": "db.example.com"})
} Explicit client
opts := logtide.NewClientOptions()
opts.DSN = "https://[email protected]"
opts.Service = "my-service"
client, err := logtide.NewClient(opts)
if err != nil {
log.Fatal(err)
}
defer client.Close()
client.Info(context.Background(), "Hello LogTide!", nil) Configuration
opts := logtide.NewClientOptions()
// Identity
opts.DSN = "https://[email protected]" // required
opts.Service = "my-service" // required
opts.Release = "v1.2.3"
opts.Environment = "production"
opts.Tags = map[string]string{"region": "eu-west-1"}
// Batching
opts.BatchSize = 100 // entries per HTTP batch (default: 100)
opts.FlushInterval = 5 * time.Second // (default: 5s)
opts.FlushTimeout = 10 * time.Second // (default: 10s)
// Reliability
opts.MaxRetries = 3
opts.RetryMinBackoff = 1 * time.Second
opts.RetryMaxBackoff = 60 * time.Second
opts.CircuitBreakerThreshold = 5 // failures before open (default: 5)
opts.CircuitBreakerTimeout = 30 * time.Second
// Stack traces
opts.AttachStacktrace = logtide.Bool(true) // default: true Logging Methods
All methods return an EventID (empty string if the entry was dropped).
ctx := context.Background()
client.Debug(ctx, "cache miss", map[string]any{"key": "user:42"})
client.Info(ctx, "request handled", map[string]any{"status": 200, "ms": 12})
client.Warn(ctx, "rate limit approaching", nil)
client.Error(ctx, "db query failed", map[string]any{"query": "SELECT ..."})
client.Critical(ctx, "out of memory", nil) Hub & Scope
The Hub/Scope model lets you attach tags, breadcrumbs, and user info to all log entries within a logical unit of work — without passing extra parameters everywhere.
Global scope
logtide.ConfigureScope(func(s *logtide.Scope) {
s.SetTag("region", "eu-west-1")
s.SetUser(logtide.User{ID: "u123", Email: "[email protected]"})
}) Per-request isolation
logtide.PushScope()
defer logtide.PopScope()
logtide.ConfigureScope(func(s *logtide.Scope) {
s.SetTag("request_id", requestID)
s.AddBreadcrumb(&logtide.Breadcrumb{
Category: "auth",
Message: "user authenticated",
Level: logtide.LevelInfo,
Timestamp: time.Now(),
}, nil)
})
// All log calls here include request_id tag + breadcrumb
logtide.Info(ctx, "processing order", nil) Per-request with explicit Hub
hub := logtide.CurrentHub().Clone()
hub.ConfigureScope(func(s *logtide.Scope) {
s.SetTag("request_id", r.Header.Get("X-Request-ID"))
})
// Inject into context for use downstream
ctx := logtide.SetHubOnContext(r.Context(), hub)
hub.Info(ctx, "request received", nil) Error Capture
result, err := db.Query(ctx, "SELECT ...")
if err != nil {
// Captures the error with full stack trace automatically
client.CaptureError(ctx, err, map[string]any{
"query": "SELECT ...",
"user": userID,
})
} OpenTelemetry Integration
Automatic trace context
tracer := otel.Tracer("my-service")
func handleRequest(ctx context.Context) {
ctx, span := tracer.Start(ctx, "handle-request")
defer span.End()
// trace_id and span_id are included automatically
client.Info(ctx, "Processing request", map[string]any{"user_id": 123})
} Span exporter
import "github.com/logtide-dev/logtide-sdk-go/integrations/otelexport"
integration := otelexport.New()
flush := logtide.Init(logtide.ClientOptions{
DSN: "https://[email protected]",
Service: "my-service",
Integrations: func(defaults []logtide.Integration) []logtide.Integration {
return append(defaults, integration)
},
})
defer flush()
tp := sdktrace.NewTracerProvider(
sdktrace.WithBatcher(integration.Exporter()),
) HTTP Middleware
The built-in middleware automatically isolates scope per request, sets HTTP tags,
parses Traceparent headers, and adds request/response breadcrumbs.
import lnethttp "github.com/logtide-dev/logtide-sdk-go/integrations/nethttp"
mux := http.NewServeMux()
mux.HandleFunc("/users", usersHandler)
// Wrap with LogTide middleware
http.ListenAndServe(":8080", lnethttp.Middleware(mux)) Best Practices
1. Always defer flush/Close
Use
defer flush() (global) or
defer client.Close() (explicit client)
immediately after initialisation to guarantee buffered entries are delivered on shutdown.
2. Clone the Hub per request
Never share a Hub across goroutines with different lifecycles.
Call
hub.Clone() at the start of each
request or goroutine to get an isolated scope.
3. Use CaptureError for Go errors
CaptureError attaches a full stack trace automatically.
Use it instead of Error whenever you have a Go
error value.
4. Use the net/http middleware
nethttp.Middleware handles scope isolation,
HTTP tagging, and breadcrumbs automatically — no boilerplate needed.