Skip to content

Go Client

View as markdown

Zero external dependencies — stdlib only. Go 1.22+. Non-blocking Track() with automatic batching via a background goroutine. Safe for concurrent use. Designed to never crash the host application.

Install

Terminal window
go get github.com/wirelogai/wirelog-go

Quick start

package main
import "github.com/wirelogai/wirelog-go"
func main() {
client := wirelog.New(wirelog.Config{APIKey: "sk_your_secret_key"})
defer client.Close()
client.Track(wirelog.Event{
EventType: "signup",
UserID: "u_123",
EventProperties: map[string]any{"plan": "free"},
})
}

Config

wirelog.New(wirelog.Config{...})
FieldTypeDefaultNotes
APIKeystringWIRELOG_API_KEY env varpk_, sk_, or aat_
HoststringWIRELOG_HOST env var or https://api.wirelog.aiAPI base URL
BatchSizeint10Max events per batch. Capped at 2000
FlushIntervaltime.Duration2sMax time between automatic flushes
QueueSizeint10000In-memory event buffer capacity
HTTPTimeouttime.Duration30sPer-request HTTP timeout
OnErrorfunc(error)nilBackground error callback (must be goroutine-safe)
DisabledboolfalseDisables tracking. Query/Identify still work

Methods

Track()

client.Track(event wirelog.Event)

Enqueue an event for asynchronous delivery. Never blocks, never returns an error. If the queue is full, the event is dropped and OnError is called.

Auto-generates insert_id and time if not set.

client.Track(wirelog.Event{
EventType: "purchase",
UserID: "u_123",
EventProperties: map[string]any{"plan": "pro", "amount": 49},
})

Flush()

client.Flush(ctx context.Context) error

Block until all buffered events are sent, or the context is cancelled.

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

Close()

client.Close() error

Flush remaining events and stop the background worker. After Close(), Track() calls are silently dropped. Idempotent.

defer client.Close()

Query()

client.Query(ctx context.Context, q string, opts ...wirelog.QueryOption) (any, error)

Run a pipe DSL query. Returns a Markdown string (llm), decoded JSON (json), or CSV string (csv).

OptionTypeDefaultNotes
WithFormat(f)string"llm""llm", "json", "csv"
WithLimit(n)int100Max 10,000
WithOffset(n)int0Pagination offset
// Markdown table (default)
md, err := client.Query(ctx, "* | last 30d | count by event_type | top 10")
// JSON
data, err := client.Query(ctx, "page_view | last 7d | count", wirelog.WithFormat("json"))
// CSV with pagination
csv, err := client.Query(ctx, "* | last 90d | count by event_type",
wirelog.WithFormat("csv"),
wirelog.WithLimit(10000),
)

Identify()

client.Identify(ctx context.Context, params wirelog.IdentifyParams) (*wirelog.IdentifyResult, error)

Bind a device to a user and upsert profile properties.

result, err := client.Identify(ctx, wirelog.IdentifyParams{
UserID: "alice@acme.org",
DeviceID: "dev_abc",
UserProperties: map[string]any{"email": "alice@acme.org"},
UserPropertyOps: &wirelog.UserPropertyOps{
Set: map[string]any{"plan": "enterprise"},
SetOnce: map[string]any{"signup_source": "ads"},
Add: map[string]float64{"login_count": 1},
Unset: []string{"legacy_flag"},
},
})
// result.OK == true

Event struct

type Event struct {
EventType string `json:"event_type"`
UserID string `json:"user_id,omitempty"`
DeviceID string `json:"device_id,omitempty"`
SessionID string `json:"session_id,omitempty"`
EventProperties map[string]any `json:"event_properties,omitempty"`
UserProperties map[string]any `json:"user_properties,omitempty"`
InsertID string `json:"insert_id,omitempty"`
Origin string `json:"origin,omitempty"`
Time string `json:"time,omitempty"`
Library string `json:"library,omitempty"`
}

InsertID, Time, and Library are auto-generated if empty.


Batching and reliability

  • Events are buffered in a channel and flushed by a background goroutine
  • Flush triggers: batch reaches BatchSize (default 10) or FlushInterval elapses (default 2s)
  • Transient failures (429, 5xx) are retried with exponential backoff (up to 3 retries)
  • Permanent failures (4xx) are reported to OnError and not retried
  • Queue overflow: newest events are dropped; ErrQueueFull is reported to OnError
  • The background worker recovers from panics

Error handling

Query() and Identify() return *wirelog.APIError on non-2xx responses.

result, err := client.Query(ctx, "bad query")
if err != nil {
var apiErr *wirelog.APIError
if errors.As(err, &apiErr) {
fmt.Println(apiErr.StatusCode) // HTTP status code
fmt.Println(apiErr.Body) // Response body
}
}

Track() never returns errors. Background errors (failed flushes, dropped events) are reported via the OnError callback:

client := wirelog.New(wirelog.Config{
APIKey: "sk_your_key",
OnError: func(err error) {
log.Printf("wirelog: %v", err)
},
})

Sentinel errors

ErrorWhen
wirelog.ErrClosedOperation attempted on a closed client
wirelog.ErrQueueFullEvent dropped because the queue is at capacity

Source

github.com/wirelogai/wirelog-go