> ## 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.

# Go SDK

> Track events and logs from Go services.

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

```bash theme={null}
go get github.com/tell-rs/tell-go
```

Requires Go 1.24+.

## Quick start

```go theme={null}
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.

```go theme={null}
// 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:

```go theme={null}
client, err := tell.Development("a1b2c3d4e5f60718293a4b5c6d7e8f90",
    func(e error) { fmt.Println("[Tell]", e) },
)
```

For custom settings:

```go theme={null}
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`.

```go theme={null}
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:

```go theme={null}
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:

```go theme={null}
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:

```go theme={null}
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.

```go theme={null}
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:

```go theme={null}
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

```go theme={null}
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:

```go theme={null}
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:

```go theme={null}
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:

```go theme={null}
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   |

### Performance

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     |
