Back to Docs

Go Integration Guide

Send logs from your Go application to logging.cheap using the OpenTelemetry SDK and OTLP (OpenTelemetry Protocol). This guide uses the otelslog bridge — an adapter that connects Go's standard log/slog to OpenTelemetry. Your existing slog.Info(), slog.Error(), etc. calls automatically send logs to logging.cheap with no API changes in your application code.

How it works: Your app → slog → otelslog bridge → OTLP over HTTP → logging.cheap. No agents to install, no collectors to manage, no YAML to configure.

Prerequisites

Get an API Key

Create an API key from your Settings page. Copy the key — it starts with cl_live_ and is only shown once. If you just signed up, an API key prompt appears on your first login.

Add Dependencies

terminal
go get go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp \
     go.opentelemetry.io/otel/sdk/log \
     go.opentelemetry.io/otel/sdk/resource \
     go.opentelemetry.io/contrib/bridges/otelslog

Set Environment Variables

The OpenTelemetry SDK reads its configuration from standard OTEL_* environment variables — no hardcoded endpoints or secrets in your code. Set these before running your application:

terminal
export OTEL_EXPORTER_OTLP_ENDPOINT="https://logging.cheap"
export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer cl_live_YOUR_API_KEY"
export OTEL_SERVICE_NAME="your-service-name"

# OpenTelemetry supports logs, traces, and metrics.
# logging.cheap only handles logs, so disable the others
# to avoid unnecessary network requests.
export OTEL_TRACES_EXPORTER="none"
export OTEL_METRICS_EXPORTER="none"

Replace cl_live_YOUR_API_KEY with the key you copied earlier, and your-service-name with a name that identifies your application in the log viewer (e.g. api-server, checkout-service). Make sure to include the Bearer prefix — without it, authentication will fail. The key=value format is how OTEL_EXPORTER_OTLP_HEADERS encodes HTTP headers — the SDK sends this as a standard Authorization: Bearer ... header.

Initialize OpenTelemetry Logging

Create a main.go file. The OTLP exporter reads configuration from the environment variables above:

main.go
package main

import (
    "context"
    "fmt"
    "log/slog"
    "os"
    "time"

    "go.opentelemetry.io/contrib/bridges/otelslog"
    "go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp"
    "go.opentelemetry.io/otel/sdk/log"
    "go.opentelemetry.io/otel/sdk/resource"
)

func main() {
    ctx := context.Background()

    // Create an OTLP exporter that sends logs to logging.cheap over HTTP.
    exporter, err := otlploghttp.New(ctx)
    if err != nil {
        slog.Error("Failed to create OTLP log exporter", "error", err)
        os.Exit(1)
    }

    // The batch processor buffers logs and sends them in batches
    // every few seconds for efficiency.
    loggerProvider := log.NewLoggerProvider(
        log.WithProcessor(log.NewBatchProcessor(exporter)),
        log.WithResource(resource.Default()),
    )
    // Flush buffered logs before exit — without this, logs still in the
    // batch buffer may never be sent. Uses a separate context with a
    // timeout so the flush completes even if the main context is cancelled.
    defer func() {
        shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
        defer cancel()
        if err := loggerProvider.Shutdown(shutdownCtx); err != nil {
            fmt.Fprintf(os.Stderr, "logger shutdown error: %v\n", err)
        }
    }()

    // Create an slog logger backed by OpenTelemetry. The first argument
    // is the instrumentation scope name — use your module path or app name.
    logger := slog.New(otelslog.NewHandler("my-app",
        otelslog.WithLoggerProvider(loggerProvider),
    ))
    slog.SetDefault(logger)

    // Send a test log
    slog.Info("Hello from logging.cheap!",
        "environment", "production",
        "version", "1.0.0",
    )
}

Run It

terminal
go run .

Logs are buffered and sent in batches. The batch processor flushes automatically every few seconds and on shutdown, so your test log will arrive within about 5 seconds.

Verify in the Log Viewer

Navigate to the log viewer, select a time range that covers the last few minutes, and search for your test message. You should see your "Hello from logging.cheap!" log entry.

If logs don't appear immediately, wait a few seconds for the batch processor to flush, then refresh the page.

Troubleshooting

Next Steps

Your Go application is now sending logs to logging.cheap. In a production application, initialize the logger provider once at startup and call Shutdown() during graceful shutdown (e.g. on SIGTERM). All slog calls throughout your codebase will be sent automatically.

Head to the log viewer to search and explore your logs. For more on the OpenTelemetry Go SDK, see the official OpenTelemetry Go documentation.