Go

Send logs from Go services using the standard net/http package — no external dependencies required.

Quick start

No external packages needed — just the standard library:

go
package main

import (
	"bytes"
	"encoding/json"
	"net/http"
	"time"
)

const logflowAPIKey = "lf_YOUR_API_KEY"

type LogEntry struct {
	Level      string            `json:"level"`
	Message    string            `json:"message"`
	Service    string            `json:"service"`
	Attributes map[string]string `json:"attributes,omitempty"`
}

var httpClient = &http.Client{Timeout: 3 * time.Second}

func Log(level, message, service string, attrs map[string]string) error {
	entry := LogEntry{Level: level, Message: message, Service: service, Attributes: attrs}
	body, _ := json.Marshal(entry)

	req, _ := http.NewRequest("POST", "https://api.getlogflow.com/v1/logs", bytes.NewReader(body))
	req.Header.Set("Authorization", "Bearer "+logflowAPIKey)
	req.Header.Set("Content-Type", "application/json")

	resp, err := httpClient.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	return nil
}

func main() {
	Log("info", "Server started", "api", map[string]string{"port": "8080"})
	Log("error", "DB timeout", "api", map[string]string{"host": "db-1"})
}

Logger wrapper

A reusable logger struct with level helpers:

go
package logflow

import (
	"bytes"
	"encoding/json"
	"net/http"
	"os"
	"time"
)

type Logger struct {
	apiKey  string
	service string
	client  *http.Client
}

func New(service string) *Logger {
	return &Logger{
		apiKey:  os.Getenv("LOGFLOW_API_KEY"),
		service: service,
		client:  &http.Client{Timeout: 3 * time.Second},
	}
}

func (l *Logger) send(level, msg string, attrs map[string]string) {
	go func() { // non-blocking
		body, _ := json.Marshal(map[string]any{
			"level": level, "message": msg,
			"service": l.service, "attributes": attrs,
		})
		req, _ := http.NewRequest("POST", "https://api.getlogflow.com/v1/logs", bytes.NewReader(body))
		req.Header.Set("Authorization", "Bearer "+l.apiKey)
		req.Header.Set("Content-Type", "application/json")
		l.client.Do(req) //nolint:errcheck
	}()
}

func (l *Logger) Info(msg string, attrs ...map[string]string)  { l.send("info", msg, merge(attrs)) }
func (l *Logger) Warn(msg string, attrs ...map[string]string)  { l.send("warn", msg, merge(attrs)) }
func (l *Logger) Error(msg string, attrs ...map[string]string) { l.send("error", msg, merge(attrs)) }
func (l *Logger) Fatal(msg string, attrs ...map[string]string) { l.send("fatal", msg, merge(attrs)) }

func merge(maps []map[string]string) map[string]string {
	out := map[string]string{}
	for _, m := range maps {
		for k, v := range m { out[k] = v }
	}
	return out
}

// Usage
// logger := logflow.New("payments-service")
// logger.Info("Payment processed", map[string]string{"order_id": "ord_123"})
// logger.Error("Stripe timeout", map[string]string{"attempt": "2"})
💡
The go func() goroutine makes logging non-blocking — your handlers return immediately even if the LogFlow API is slow.

Batch sending

Buffer logs and flush periodically for high-throughput services:

go
package main

import (
	"bytes"
	"encoding/json"
	"net/http"
	"sync"
	"time"
)

type BatchLogger struct {
	mu      sync.Mutex
	buffer  []map[string]any
	apiKey  string
	service string
}

func NewBatch(service string) *BatchLogger {
	l := &BatchLogger{apiKey: "lf_YOUR_API_KEY", service: service}
	go l.flush()
	return l
}

func (l *BatchLogger) Log(level, msg string) {
	l.mu.Lock()
	l.buffer = append(l.buffer, map[string]any{"level": level, "message": msg, "service": l.service})
	l.mu.Unlock()
}

func (l *BatchLogger) flush() {
	for range time.Tick(2 * time.Second) {
		l.mu.Lock()
		if len(l.buffer) == 0 { l.mu.Unlock(); continue }
		batch := l.buffer
		l.buffer = nil
		l.mu.Unlock()

		body, _ := json.Marshal(map[string]any{"logs": batch})
		req, _ := http.NewRequest("POST", "https://api.getlogflow.com/v1/logs/batch", bytes.NewReader(body))
		req.Header.Set("Authorization", "Bearer "+l.apiKey)
		req.Header.Set("Content-Type", "application/json")
		http.DefaultClient.Do(req) //nolint:errcheck
	}
}

slog integration (Go 1.21+)

Implement slog.Handler to plug into Go's structured logging:

go
// Full slog.Handler implementation coming soon.
// For now, use the Logger wrapper above with your slog middleware.