Documentation Index
Fetch the complete documentation index at: https://docs.tell.rs/llms.txt
Use this file to discover all available pages before exploring further.
The Go SDK sends events and structured logs from your backend services to Tell. It’s a server SDK — you create a client, pass a user ID on every call, and a background goroutine handles batching and delivery over TCP.
Every method takes a context.Context and returns an error. The calling goroutine does about 320 ns of work (serialize, encode, enqueue) and never touches the network.
Installation
go get github.com/tell-rs/tell-go
Requires Go 1.24+.
Quick start
package main
import (
"context"
"github.com/tell-rs/tell-go"
)
func main() {
client, err := tell.Production("a1b2c3d4e5f60718293a4b5c6d7e8f90")
if err != nil {
panic(err)
}
defer client.Close(context.Background())
client.Track(context.Background(), "user_123", "Page Viewed", tell.Properties{
"url": "/home",
"referrer": "google",
})
}
The client connects to collect.tell.rs:50000, batches up to 100 events, and flushes every 10 seconds or when you call Close.
Configuration
Use one of the two presets, or pass a custom Config struct.
// Production — collect.tell.rs:50000, batch 100, flush 10s
client, err := tell.Production("a1b2c3d4e5f60718293a4b5c6d7e8f90")
// Development — localhost:50000, batch 10, flush 2s
client, err := tell.Development("a1b2c3d4e5f60718293a4b5c6d7e8f90")
Both presets accept an optional error callback:
client, err := tell.Development("a1b2c3d4e5f60718293a4b5c6d7e8f90",
func(e error) { fmt.Println("[Tell]", e) },
)
For custom settings:
client, err := tell.NewClient("a1b2c3d4e5f60718293a4b5c6d7e8f90", tell.Config{
Endpoint: "collect.internal:50000",
BatchSize: 200,
FlushInterval: 5 * time.Second,
MaxRetries: 5,
CloseTimeout: 10 * time.Second,
NetworkTimeout: 60 * time.Second,
OnError: func(e error) { fmt.Println("[Tell]", e) },
})
The API key must be a 32-character hex string. NewClient returns an error if it’s invalid.
Tracking events
Every tracking method takes context.Context and userID as its first parameters. Properties are tell.Properties (map[string]interface{}) or nil.
ctx := context.Background()
// Track a custom event
client.Track(ctx, "user_123", "Feature Used", tell.Properties{
"feature": "dark_mode",
"enabled": true,
})
// Identify a user
client.Identify(ctx, "user_123", tell.Properties{
"name": "Jane",
"email": "jane@example.com",
"plan": "pro",
})
// Associate user with a group
client.Group(ctx, "user_123", "org_456", tell.Properties{
"name": "Acme Corp",
"plan": "enterprise",
})
// Track revenue
client.Revenue(ctx, "user_123", 49.99, "USD", "order_789", tell.Properties{
"product": "pro_annual",
})
// Link two user identities
client.Alias(ctx, "anon_visitor_abc", "user_123")
Pass nil instead of tell.Properties{} when you don’t need properties:
client.Track(ctx, "user_123", "App Opened", nil)
client.Revenue(ctx, "user_123", 9.99, "USD", "order_790", nil)
Standard event names
The SDK provides constants for common events:
client.Track(ctx, "user_123", tell.PageViewed, tell.Properties{"url": "/pricing"})
client.Track(ctx, "user_123", tell.UserSignedUp, tell.Properties{"source": "organic"})
client.Track(ctx, "user_123", tell.OrderCompleted, tell.Properties{"total": 99.00})
client.Track(ctx, "user_123", tell.FeatureUsed, tell.Properties{"feature": "export"})
Constants cover user lifecycle, revenue, subscriptions, trials, shopping, engagement, and communication events. Custom string names are always accepted too.
Super properties
Register properties that get merged into every Track, Group, and Revenue call:
client.Register(tell.Properties{"app_version": "2.1.0", "env": "production"})
// This Track call automatically includes app_version and env
client.Track(ctx, "user_123", "Click", tell.Properties{"button": "submit"})
// Remove a super property
client.Unregister("env")
Event-specific properties override super properties when keys conflict.
Structured logging
Send logs alongside events through the same pipeline. Each log has an RFC 5424 severity level.
client.LogError(ctx, "DB connection failed", tell.Ptr("api"), map[string]interface{}{
"host": "db.internal",
"retries": 3,
})
client.LogInfo(ctx, "Request processed", tell.Ptr("api"), map[string]interface{}{
"status": 200,
"duration_ms": 45,
})
client.LogWarning(ctx, "Rate limit approaching", tell.Ptr("gateway"), nil)
The service parameter is *string — use tell.Ptr("myservice") to pass a value, or nil to default to "app". Convenience methods are available for all nine levels: LogEmergency, LogAlert, LogCritical, LogError, LogWarning, LogNotice, LogInfo, LogDebug, and LogTrace.
For full control, use the Log method with a LogEntry struct:
client.Log(ctx, tell.LogEntry{
Level: tell.LogNoticeLevel,
Message: "Deployment completed",
Service: "deploy",
Data: map[string]interface{}{
"version": "3.1.0",
"commit": "abc123f",
},
})
Properties
tell.Properties is map[string]interface{}. Supported value types:
string
int, int32, int64, float32, float64
bool
time.Time
[]interface{} (arrays)
map[string]interface{} (nested objects)
nil
Lifecycle
ctx := context.Background()
// Force-send all queued events and logs
client.Flush(ctx)
// Rotate session ID
client.ResetSession()
// Flush + shut down the background goroutine
client.Close(ctx)
Always call Close before your process exits to avoid losing buffered events. Use defer client.Close(ctx) right after creating the client.
Goroutine safety
The client is safe to share across goroutines:
client, _ := tell.Production("a1b2c3d4e5f60718293a4b5c6d7e8f90")
go func() { client.Track(ctx, "user_1", "Event A", nil) }()
go func() { client.Track(ctx, "user_2", "Event B", nil) }()
go func() { client.LogInfo(ctx, "Processing", tell.Ptr("worker"), nil) }()
Error handling
Constructor errors are returned directly:
client, err := tell.Production("bad-key")
if err != nil {
// Invalid API key, bad endpoint, etc.
log.Fatal(err)
}
Tracking and logging methods return validation errors for invalid input. Network errors are handled internally with retries and reported via the OnError callback:
client, _ := tell.NewClient("a1b2c3d4e5f60718293a4b5c6d7e8f90", tell.Config{
OnError: func(e error) {
var ve *types.ValidationError
if errors.As(e, &ve) {
log.Printf("Validation: %s - %s", ve.Field, ve.Message)
} else {
log.Printf("Tell error: %v", e)
}
},
})
Advanced
Configuration reference
| Parameter | Default (production) | Default (development) | Description |
|---|
Endpoint | collect.tell.rs:50000 | localhost:50000 | TCP collector address |
BatchSize | 100 | 10 | Events per batch before auto-flush |
FlushInterval | 10s | 2s | Time between auto-flushes |
MaxRetries | 3 | 3 | Retry attempts on send failure |
CloseTimeout | 5s | 5s | Max wait on Close |
NetworkTimeout | 30s | 30s | TCP connect timeout |
OnError | silent | silent | Error callback |
Validation rules
| Field | Rule |
|---|
| API key | 32-character hex string |
| UserID | Non-empty |
| Event name | Non-empty |
| GroupID | Non-empty |
| Revenue amount | Positive number |
| Currency | Non-empty |
| OrderID | Non-empty |
| Log message or data | At least one required |
Caller latency — serialize, encode, and enqueue (Apple M4 Pro):
| Operation | ns/op | allocs/op |
|---|
Track (no props) | 320 | 2 |
Track (2 props) | 494 | 2 |
Track (14 props) | 1,061 | 2 |
Identify | 511 | 2 |
Revenue | 554 | 3 |
Log (with data) | 421 | 3 |
Delivery throughput — batched and sent over TCP:
| Batch size | events/sec |
|---|
| 10 | 1.2M/s |
| 100 | 1.9M/s |
| 500 | 2.2M/s |