---
name: Timberlogs
description: Use when building logging infrastructure, sending structured logs from applications, querying logs via API or CLI, tracking user flows across multi-step operations, or integrating logging into TypeScript, Python, or Rust services.
metadata:
    mintlify-proj: timberlogs
    version: "1.0"
---

# Timberlogs Skill

## Product Summary

Timberlogs is a structured logging service that captures log data as key-value fields rather than plain text strings. Send logs from any application using the REST API or official SDKs (TypeScript, Python, Rust), search and filter with full-text search, and track user flows across multi-step operations. The service is built on Cloudflare Workers for global low-latency ingestion. Primary documentation: https://docs.timberlogs.dev

**Key files and endpoints:**
- REST API endpoint: `https://timberlogs-ingest.enaboapps.workers.dev/v1/logs`
- TypeScript SDK: `npm install timberlogs-client`
- Python SDK: `pip install timberlogs-client`
- Rust SDK: Add `timberlogs = "1"` to `Cargo.toml`
- CLI: `npm install -g timberlogs-cli`
- Configuration: API key (format: `tb_live_*` or `tb_test_*`), source, environment

## When to Use

Reach for this skill when:
- **Sending logs from an application** — You need to instrument TypeScript, Python, or Rust code with structured logging
- **Querying logs programmatically** — You're building features that search, filter, or analyze logs via the REST API
- **Tracking user journeys** — You need to correlate related logs across a multi-step operation (checkout, API request, background job) using flows
- **Integrating with external log sources** — You're forwarding logs from syslog daemons, CSV exports, or other systems via raw format ingestion
- **Debugging from the terminal** — You need to search and filter logs without leaving your shell using the CLI
- **Setting up log routing** — You're organizing logs into datasets for access control or retention policies

## Quick Reference

### SDK Initialization

| Language | Code |
|----------|------|
| **TypeScript** | `const timber = createTimberlogs({ source: 'my-app', environment: 'production', apiKey: process.env.TIMBER_API_KEY })` |
| **Python** | `timber = create_timberlogs(source='my-app', environment='production', api_key=os.getenv('TIMBER_API_KEY'))` |
| **Rust** | `let timber = TimberlogsClient::new(TimberlogsConfig { source: "my-app".into(), environment: Environment::Production, api_key: env::var("TIMBER_API_KEY").unwrap(), ..Default::default() })` |

### Logging Methods (All SDKs)

```
timber.debug(message, data?, options?)    # Detailed diagnostic info
timber.info(message, data?, options?)     # Normal operations
timber.warn(message, data?, options?)     # Warning conditions
timber.error(message, errorOrData?, options?)  # Errors (accepts Error objects)
```

### Essential Configuration Options

| Option | Type | Required | Notes |
|--------|------|----------|-------|
| `source` | string | Yes | App/service name (1-100 chars) |
| `environment` | string | Yes | `development`, `staging`, or `production` |
| `apiKey` | string | Yes | Format: `tb_live_*` or `tb_test_*` |
| `dataset` | string | No | Default dataset for log routing |
| `batchSize` | number | No | Logs to batch before sending (default: 10) |
| `flushInterval` | number | No | Auto-flush interval in ms (default: 5000) |
| `minLevel` | string | No | Minimum level to send: `debug`, `info`, `warn`, `error` |
| `userId` | string | No | Default user ID for all logs |
| `sessionId` | string | No | Default session ID for all logs |

### CLI Commands

```bash
timberlogs login                              # Authenticate via OAuth
timberlogs logs --level error --from 1h       # Query logs
timberlogs logs --search "payment"            # Full-text search
timberlogs logs --flow-id checkout-abc        # Logs for a flow
timberlogs flows show <flow-id>               # View flow timeline
timberlogs stats --from 7d --group-by source  # Aggregate stats
timberlogs config list                        # Show config
```

### Log Entry Fields

| Field | Type | Required | Notes |
|-------|------|----------|-------|
| `level` | string | Yes | `debug`, `info`, `warn`, `error` |
| `message` | string | Yes | 1-10,000 characters |
| `source` | string | Yes | 1-100 characters |
| `environment` | string | Yes | `development`, `staging`, `production` |
| `data` | object | No | Arbitrary JSON object |
| `userId` | string | No | Max 100 characters |
| `sessionId` | string | No | Max 100 characters |
| `flowId` | string | No | Max 50 characters |
| `stepIndex` | number | No | 0-1000 |
| `tags` | array | No | Max 20 items, 50 chars each |

### Supported Ingestion Formats

| Format | Content-Type | Use Case |
|--------|-------------|----------|
| JSON | `application/json` | Default; structured logs |
| JSONL | `application/x-ndjson` | Streaming logs, one per line |
| Syslog | `application/x-syslog` | RFC 5424/3164 forwarding |
| Text | `text/plain` | Plain text logs (auto-extracts level/timestamp) |
| CSV | `text/csv` | Tabular data with headers |
| OBL | `application/x-obl` | AAC device logs |

## Decision Guidance

### When to Use Flows vs. Tags

| Scenario | Use Flows | Use Tags |
|----------|-----------|----------|
| Tracking a multi-step operation (checkout, API request) | ✓ | - |
| Categorizing logs for filtering (payments, auth, errors) | - | ✓ |
| Correlating logs across services | ✓ | - |
| Grouping related events with ordered steps | ✓ | - |
| Simple categorization without ordering | - | ✓ |

### When to Use Each SDK

| Scenario | SDK |
|----------|-----|
| Node.js/TypeScript/JavaScript backend | TypeScript SDK |
| Python FastAPI, Django, or async apps | Python SDK |
| Rust/Actix/Tokio applications | Rust SDK |
| Any language (no SDK available) | REST API |
| Forwarding logs from external systems | REST API with raw format ingestion |

### When to Use Each Ingestion Format

| Format | When to Use |
|--------|------------|
| JSON | Default for structured logs from SDKs |
| JSONL | Streaming logs, one per line (efficient for large batches) |
| Syslog | Forwarding from syslog daemons, rsyslog, syslog-ng |
| Text | Legacy plain-text logs, nginx/Apache access logs |
| CSV | Exporting logs from databases or spreadsheets |
| OBL | AAC (Augmentative and Alternative Communication) device logs |

## Workflow

### 1. Send Logs from an Application

1. **Get API key** — Sign up at app.timberlogs.dev, navigate to Settings > API Keys, create a key
2. **Install SDK** — `npm install timberlogs-client` (or Python/Rust equivalent)
3. **Initialize client** — Create a client with `source`, `environment`, and `apiKey`
4. **Add logging calls** — Use `timber.info()`, `timber.error()`, etc. throughout your code
5. **Flush on exit** — Call `timber.flush()` or `timber.disconnect()` before process shutdown
6. **Verify** — Check app.timberlogs.dev dashboard to see logs appear within seconds

### 2. Track a Multi-Step Operation with Flows

1. **Create a flow** — Call `const flow = await timber.flow('operation-name')`
2. **Log each step** — Call `flow.info()`, `flow.warn()`, `flow.error()` for each step
3. **Include context** — Add relevant data (user ID, order ID, amounts) to the first log
4. **Log completion** — Always log the final outcome (success or failure)
5. **View in dashboard** — Go to Flows tab to see the complete timeline with ordered steps

### 3. Query Logs via CLI

1. **Authenticate** — Run `timberlogs login` (opens browser for OAuth)
2. **Query** — Use `timberlogs logs --level error --from 1h` to search
3. **Filter** — Add flags like `--source api-server`, `--search "payment"`, `--flow-id checkout-abc`
4. **Export** — Use `--format json` or `--format csv` to export results
5. **View flows** — Run `timberlogs flows show <flow-id>` to see the complete timeline

### 4. Ingest Logs from External Systems

1. **Prepare data** — Export logs in JSON, JSONL, syslog, text, or CSV format
2. **Set defaults** — Use query parameters (`?source=nginx&environment=production`) for required fields
3. **Send via API** — POST to `/v1/logs` with appropriate `Content-Type` header
4. **Handle errors** — Implement retry logic with exponential backoff (SDKs do this automatically)
5. **Verify** — Check dashboard to confirm logs appear

## Common Gotchas

- **Forgetting to flush** — Logs are batched for efficiency. Always call `timber.flush()` or `timber.disconnect()` before process exit, or logs will be lost. Use context managers (Python) or try/finally blocks for automatic cleanup.

- **API key format** — Keys must start with `tb_live_*` (production) or `tb_test_*` (test). If you see "Invalid API key" errors, verify the key was copied correctly and hasn't been revoked.

- **Missing required fields** — Every log must have `level`, `message`, `source`, and `environment`. The API will reject logs missing these fields with a 400 error.

- **Exceeding batch limits** — The ingestion endpoint accepts 1-100 logs per request. Sending more than 100 will fail. SDKs handle this automatically; if using the raw API, batch manually.

- **Flow step indices with level filtering** — When `minLevel` is set, filtered logs don't increment the step index. This is intentional (to avoid gaps), but can be confusing. Debug logs won't appear in the flow if `minLevel: 'info'`.

- **Timestamp precision** — Timestamps should be Unix milliseconds (not seconds). If your timestamps are in seconds, multiply by 1000.

- **Data object size** — While the API doesn't enforce a strict limit, keep the `data` object reasonable (< 10KB per log). Very large objects may cause performance issues.

- **Tags vs. message** — Don't embed searchable data in the message string. Use the `data` object instead. For example, use `data: { userId: '123' }` instead of `message: "User 123 did X"`.

- **Cross-service flow correlation** — To continue a flow in another service, pass the `flowId` between services (via job queue, HTTP header, etc.). Both services must log with the same `flowId` to maintain the timeline.

- **CLI config location** — The CLI stores session tokens at `~/.config/timberlogs/config.json`. If you get "not authenticated" errors, check that this file exists and is readable.

## Verification Checklist

Before submitting work with Timberlogs:

- [ ] **API key is valid** — Key format is `tb_live_*` or `tb_test_*` and hasn't been revoked
- [ ] **Required fields present** — All logs have `level`, `message`, `source`, `environment`
- [ ] **Flush called** — Code calls `timber.flush()` or `timber.disconnect()` before shutdown
- [ ] **Data is structured** — Searchable fields are in the `data` object, not interpolated into `message`
- [ ] **Batch size reasonable** — Not sending more than 100 logs per request (SDKs handle this)
- [ ] **Timestamps correct** — Using Unix milliseconds, not seconds
- [ ] **Flow IDs consistent** — If tracking across services, same `flowId` is used everywhere
- [ ] **Tags are consistent** — Using the same tag names across logs for reliable filtering
- [ ] **Error handling** — Errors from the SDK are logged or handled (via `onError` callback)
- [ ] **Logs appear in dashboard** — Verified that logs show up in app.timberlogs.dev within seconds

## Resources

- **Complete page navigation** — https://docs.timberlogs.dev/llms.txt
- **Getting Started guide** — https://docs.timberlogs.dev/getting-started
- **API Reference** — https://docs.timberlogs.dev/api-reference/ingestion
- **Flows documentation** — https://docs.timberlogs.dev/concepts/flows

---

> For additional documentation and navigation, see: https://docs.timberlogs.dev/llms.txt