Skip to content

logtide-dev/logtide-go

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

17 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

LogTide Logo

LogTide Go SDK

Go Reference Go Report Card License Release

Official Go SDK for LogTide — structured logging with automatic batching, retry, circuit breaker, and OpenTelemetry integration.


Features

  • Leveled logging — Debug, Info, Warn, Error, Critical, CaptureError
  • Hub / Scope model — per-request context isolation with breadcrumbs, tags, and user metadata
  • Automatic batching — configurable batch size and flush interval
  • Retry with backoff — exponential backoff with jitter
  • Circuit breaker — prevents cascading failures
  • OpenTelemetry — trace/span IDs extracted automatically; span and metric exporters included
  • log/slog handler — route existing slog logging to LogTide with no code changes
  • net/http middleware — per-request scope isolation out of the box
  • Thread-safe — safe for concurrent use

Requirements

  • Go 1.23 or later
  • A LogTide account and DSN

Installation

go get github.com/logtide-dev/logtide-sdk-go

Quick Start

Global singleton (recommended for most apps)

package main

import (
    "context"
    logtide "github.com/logtide-dev/logtide-sdk-go"
)

func main() {
    flush := logtide.Init(logtide.ClientOptions{
        DSN:         "https://lp_your_api_key@api.logtide.dev",
        Service:     "my-service",
        Environment: "production",
        Release:     "v1.2.3",
    })
    defer flush()

    logtide.Info(context.Background(), "Hello LogTide!", nil)
    logtide.Error(context.Background(), "Something went wrong", map[string]any{
        "user_id": 42,
    })
}

Explicit client

opts := logtide.NewClientOptions()
opts.DSN     = "https://lp_your_api_key@api.logtide.dev"
opts.Service = "my-service"

client, err := logtide.NewClient(opts)
if err != nil {
    log.Fatal(err)
}
defer client.Close()

id := client.Info(context.Background(), "Hello", nil)
fmt.Println("event id:", id)

DSN format

https://{api_key}@{host}

Example: https://lp_abc123@api.logtide.dev


Configuration

opts := logtide.NewClientOptions()
opts.DSN                    = "https://lp_abc@api.logtide.dev"
opts.Service                = "my-service"       // required
opts.Release                = "v1.2.3"
opts.Environment            = "production"
opts.Tags                   = map[string]string{"region": "eu-west-1"}
opts.BatchSize              = 100                // entries per HTTP batch
opts.FlushInterval          = 5 * time.Second
opts.FlushTimeout           = 10 * time.Second
opts.MaxRetries             = 3
opts.RetryMinBackoff        = 1 * time.Second
opts.RetryMaxBackoff        = 60 * time.Second
opts.CircuitBreakerThreshold = 5               // consecutive failures before open
opts.CircuitBreakerTimeout  = 30 * time.Second
opts.AttachStacktrace       = logtide.Bool(true)

Logging

All log methods return the EventID assigned to the entry, or "" 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)

// Capture an error with full stack trace
if err := doSomething(); err != nil {
    client.CaptureError(ctx, err, map[string]any{"op": "doSomething"})
}

Hub & Scope

The Hub/Scope model lets you attach contextual data (tags, breadcrumbs, user info, trace context) to all log entries within a logical unit of work.

// Configure the global scope
logtide.ConfigureScope(func(s *logtide.Scope) {
    s.SetTag("region", "eu-west-1")
    s.SetUser(logtide.User{ID: "u123", Email: "alice@example.com"})
})

// Per-request isolation via PushScope / PopScope
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)
})

logtide.Info(ctx, "processing order", nil) // includes request_id tag + breadcrumb

net/http middleware

import lnethttp "github.com/logtide-dev/logtide-sdk-go/integrations/nethttp"

http.Handle("/", lnethttp.Middleware(myHandler))

The middleware automatically:

  • clones the Hub for each request (scope isolation)
  • sets http.method, http.url, http.host, http.client_ip tags
  • parses the Traceparent header and stores trace/span IDs on the scope
  • adds request and response breadcrumbs

OpenTelemetry

Automatic trace context extraction

Trace and span IDs are extracted automatically from any active OTel span in the context:

ctx, span := tracer.Start(ctx, "process-order")
defer span.End()

// trace_id and span_id are included automatically
client.Info(ctx, "order processed", map[string]any{"order_id": 99})

Span exporter

Export completed spans to LogTide:

import "github.com/logtide-dev/logtide-sdk-go/integrations/otelexport"

integration := otelexport.New()

flush := logtide.Init(logtide.ClientOptions{
    DSN:     "https://lp_abc@api.logtide.dev",
    Service: "my-service",
    Integrations: func(defaults []logtide.Integration) []logtide.Integration {
        return append(defaults, integration)
    },
})
defer flush()

tp := sdktrace.NewTracerProvider(
    sdktrace.WithBatcher(integration.Exporter()),
)

Metric exporter

Export OpenTelemetry metrics (counters, gauges, histograms) to LogTide. Each data point becomes a log entry carrying the same service name, environment, tags and resource attributes as your logs and traces. It is opt-in — register it only if you need metrics.

import (
    sdkmetric "go.opentelemetry.io/otel/sdk/metric"

    "github.com/logtide-dev/logtide-sdk-go/integrations/otelmetric"
)

integration := otelmetric.New()

flush := logtide.Init(logtide.ClientOptions{
    DSN:     "https://lp_abc@api.logtide.dev",
    Service: "my-service",
    Integrations: func(defaults []logtide.Integration) []logtide.Integration {
        return append(defaults, integration)
    },
})
defer flush()

mp := sdkmetric.NewMeterProvider(
    sdkmetric.WithReader(sdkmetric.NewPeriodicReader(integration.Exporter())),
)
otel.SetMeterProvider(mp)

When metric exemplars are enabled (an exemplar filter is configured and a sampled span is active during measurement), each linked data point's entry inherits the exemplar's trace_id/span_id, and the full exemplar list is recorded under metadata.metric.exemplars — correlating metrics with the traces that produced them.


log/slog handler

Route existing log/slog logging through LogTide without changing call sites. Records honour the full client pipeline (scope merge, processors, BeforeSend, sampling, batching). Attributes become entry metadata, slog groups become nested metadata objects, and attribute values implementing error are promoted to structured exceptions for server-side error grouping.

import (
    "log/slog"

    "github.com/logtide-dev/logtide-sdk-go/integrations/logtideslog"
)

client, _ := logtide.NewClient(logtide.ClientOptions{
    DSN:     "https://lp_abc@api.logtide.dev",
    Service: "my-service",
})

logger := slog.New(logtideslog.New(client, nil))
slog.SetDefault(logger)

slog.Info("user signed up", "user_id", 42) // flows to LogTide

Pass &logtideslog.Options{Level: slog.LevelDebug} to change the minimum level (defaults to slog.LevelInfo).


Flush & shutdown

// Flush with deadline
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
client.Flush(ctx)

// Close flushes and releases all resources
client.Close()

BeforeSend hook

Inspect or drop entries before they are sent:

opts.BeforeSend = func(entry *logtide.LogEntry, hint *logtide.EventHint) *logtide.LogEntry {
    // drop health-check noise
    if entry.Message == "health check" {
        return nil
    }
    return entry
}

Testing

Use NoopTransport to silence all output in tests:

client, _ := logtide.NewClient(logtide.ClientOptions{
    Service:   "test",
    Transport: logtide.NoopTransport{},
})

Examples

Example Description
examples/basic All log levels, metadata, CaptureError
examples/gin Gin framework integration
examples/echo Echo framework integration
examples/stdlib Standard library net/http
examples/otel OpenTelemetry distributed tracing
examples/otelmetric OpenTelemetry metrics export

API reference

Contributing

See CONTRIBUTING.md.

License

MIT — see LICENSE.

About

Official Go SDK for LogTide - Production-ready logging with automatic batching, circuit breaker, OpenTelemetry integration, and Gin/Echo/Chi middleware support

Topics

Resources

License

Code of conduct

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages