Go SDK for Tell — product analytics and structured logging.
- Fire & forget. Synchronous API, async background batching. Zero I/O blocking.
- Thread-safe. Share the client across goroutines.
- FlatBuffers + TCP. Binary protocol, length-prefixed frames, zero-copy serialization.
go get github.com/tell-rs/tell-gopackage main
import (
"context"
"fmt"
"github.com/tell-rs/tell-go"
)
func main() {
client, err := tell.Production("feed1e11feed1e11feed1e11feed1e11", "my-backend")
if err != nil {
panic(err)
}
defer client.Close(context.Background())
ctx := context.Background()
// Track events
client.Track(ctx, "user_123", "Page Viewed", tell.Properties{
"url": "/home",
"referrer": "google",
})
// Identify users
client.Identify(ctx, "user_123", tell.Properties{
"name": "Jane",
"plan": "pro",
})
// Revenue
client.Revenue(ctx, "user_123", 49.99, "USD", "order_456", nil)
// Structured logging
client.LogError(ctx, "DB connection failed", tell.Ptr("api"), tell.Properties{
"host": "db.internal",
})
client.Flush(ctx)
}// Production — collect.tell.rs:50000, batch=100, flush=10s
client, err := tell.Production("feed1e11feed1e11feed1e11feed1e11", "my-backend")
// Development — 127.0.0.1:50000, batch=10, flush=2s
client, err := tell.Development("feed1e11feed1e11feed1e11feed1e11", "my-backend")
// Custom
client, err := tell.NewClient("feed1e11feed1e11feed1e11feed1e11", tell.Config{
Service: "my-backend", // stamped on every event and log
Endpoint: "collect.internal:50000",
BatchSize: 200,
FlushInterval: 5 * time.Second,
CloseTimeout: 10 * time.Second,
NetworkTimeout: 30 * time.Second,
OnError: func(e error) { fmt.Println("[Tell]", e) },
})client, err := tell.NewClient(apiKey, config)
// Events — userID is always the first parameter
client.Track(ctx, userID, eventName, properties)
client.Identify(ctx, userID, traits)
client.Group(ctx, userID, groupID, properties)
client.Revenue(ctx, userID, amount, currency, orderID, properties)
client.Alias(ctx, previousID, userID)
// Super properties — merged into every track/group/revenue call
client.Register(tell.Properties{"app_version": "2.0"})
client.Unregister("app_version")
// Logging
client.Log(ctx, entry)
client.LogInfo(ctx, message, service, data)
client.LogError(ctx, message, service, data)
// + LogEmergency, LogAlert, LogCritical, LogWarning,
// LogNotice, LogDebug, LogTrace
// Lifecycle
client.ResetSession()
client.Flush(ctx)
client.Close(ctx)Properties accept tell.Properties (map[string]interface{}) or nil.
The optional service parameter on log methods is *string — use tell.Ptr("myservice") or nil.
Apple M4 Pro. go test -bench . -benchmem ./tests/
Caller latency — serialize, encode, and enqueue (no I/O on the calling goroutine):
| Operation | ns/op | allocs/op |
|---|---|---|
track (no properties) |
320 | 2 |
track (2 properties) |
494 | 2 |
track (14 properties) |
1,061 | 2 |
identify |
511 | 2 |
revenue |
554 | 3 |
log (with data) |
421 | 3 |
log (no data) |
358 | 3 |
Delivery throughput — batched, serialized to FlatBuffers, and sent over TCP:
| Batch Size | events/sec |
|---|---|
| 10 | 1.2 M/s |
| 100 | 1.9 M/s |
| 500 | 2.2 M/s |
Run benchmarks:
# Hot path (caller latency)
go test -bench='Benchmark(Track|Identify|Revenue|Log)' -benchmem ./tests/
# Pipeline (end-to-end with TCP)
go test -bench=BenchmarkPipeline -benchmem ./tests/
# Throughput (100K events)
go test -bench=BenchmarkThroughput -benchmem -timeout 120s ./tests/- Go: 1.24+
MIT