Timber
Timber is the project log trail for Protokol. It shows user-facing platform events emitted by services and accepts custom application logs.
Timber is available as the protokol-timber integration with three tiers:
| Tier | Retention | Custom Logs | Usage Metering |
|---|---|---|---|
| Free | 7 days | No | No |
| Standard | 30 days | Yes | Yes |
| Pro | 90 days | Yes | Yes |
Query Events
Query parameters:
| Parameter | Description |
|---|---|
limit |
Number of events to return (default 50, max 500). |
cursor |
Cursor from meta.next_cursor for pagination. |
source |
system or user. |
level |
debug, info, warn, or error. |
action |
Event action such as create, update, delete, execute, deploy. |
resource_type |
Resource family, for example workflow, media_file, runtime. |
resource_id |
Resource identifier. |
actor_id |
User, API key, or service actor id. |
actor_name |
Actor display name (partial match). |
actor_type |
user, api_key, service, or system. |
request_uuid |
Correlate events to a specific request. |
search |
Text search over message, resource, and actor fields. |
from / to |
RFC3339 time range. |
cURL
curl "https://timber.integration.protokol.cloud/logs?source=system&level=info&limit=50" \
-H "Authorization: Bearer <your-api-token>" \
-H "X-Project-Uuid: <your-project-uuid>"
Platform Functions
const { Timber } = $sdk.version('0.10')
const timber = new Timber()
const result = await timber.query({
source: 'system',
level: 'info',
limit: 50,
})
response.json(result)
SDK
import { Timber } from "@ptkl/sdk/beta"
const timber = new Timber()
const result = await timber.query({
source: 'system',
level: 'error',
from: new Date('2026-05-01'),
to: new Date('2026-05-27'),
limit: 100,
})
// Pagination
if (result.meta.has_more) {
const page2 = await timber.query({ cursor: result.meta.next_cursor })
}
Response
{
"data": [
{
"id": "01J...",
"timestamp": "2026-05-24T12:00:00Z",
"source": "system",
"level": "info",
"service": "workflow",
"project_uuid": "project-uuid",
"actor": { "type": "user", "id": "user-uuid", "name": "John" },
"action": "execute",
"resource_type": "workflow",
"resource_id": "workflow-uuid",
"message": "Workflow executed"
}
],
"meta": {
"limit": 50,
"has_more": false,
"next_cursor": ""
}
}
Write Custom Logs
Custom logs require Timber Standard or Pro. Payloads must be 64 KB or smaller.
| Field | Required | Description |
|---|---|---|
message |
yes | Log body. Maximum 10,000 characters. |
level |
no | debug, info, warn, or error. Defaults to info. |
service |
no | Service name. Defaults to user-app. |
resource_type |
no | Resource family. |
resource_id |
no | Resource identifier. |
resource_name |
no | Human-readable name. |
attributes |
no | Up to 64 custom key-value pairs. |
trace_id, span_id, request_id |
no | Correlation identifiers. |
cURL
curl "https://timber.integration.protokol.cloud/logs" \
-X POST \
-H "Authorization: Bearer <your-api-token>" \
-H "X-Project-Uuid: <your-project-uuid>" \
-H "Content-Type: application/json" \
-d '{
"level": "info",
"service": "checkout",
"message": "Order confirmation sent",
"resource_type": "order",
"resource_id": "ord_123",
"attributes": {
"channel": "email"
}
}'
Platform Functions
const { Timber } = $sdk.version('0.10')
const timber = new Timber()
// Convenience methods — debug(), info(), warn(), error()
await timber.info('Order confirmation sent', {
service: 'checkout',
resource_type: 'order',
resource_id: $input.body.order_id,
attributes: { channel: 'email' },
})
// Or use write() with an explicit level
await timber.write({
level: 'warn',
message: 'Payment retry scheduled',
service: 'billing',
attributes: { attempt: 3 },
})
response.json({ ok: true })
SDK
import { Timber } from "@ptkl/sdk/beta"
const timber = new Timber()
await timber.info('User exported report', {
service: 'reports',
resource_type: 'report',
resource_id: 'rpt_456',
attributes: { format: 'pdf', pages: 42 },
})
await timber.error('Payment failed', {
service: 'billing',
attributes: { reason: 'card_declined', provider: 'stripe' },
})
Usage
Returns current Timber tier and metered custom log bytes for the project.
Platform Functions
const { Timber } = $sdk.version('0.10')
const timber = new Timber()
const usage = await timber.usage()
response.json(usage)
Response
{
"tier": "standard",
"period": "2026-05",
"bytes_ingested": 32768,
"gb_ingested": 0.000030517578125
}
CLI
Timber is available via the Protokol Toolkit CLI as the typed ptkl integration timber
interface — query/write/usage, mapping 1:1 onto the SDK client above:
ptkl integration timber query --level error --search "payment failed" --limit 50
ptkl integration timber write --message "Order confirmation sent" --level info --service checkout
ptkl integration timber usage
| Flag (query) | Description |
|---|---|
--source <source> |
Filter by system or user. |
--level <level> |
Filter by debug, info, warn, or error. |
--action <action> |
Filter by action. |
--resource-type <type> |
Filter by resource type. |
-s, --search <text> |
Search messages, actors, or resources. |
-l, --limit <n> |
Number of logs to fetch (default 50). |
-c, --cursor <cursor> |
Pagination cursor from a previous response. |
See ptkl integration timber for the
full subcommand reference, including write's attribute/trace fields.
ptkl logs back-compat alias
The pre-existing top-level ptkl logs command is a thin alias of integration timber query
(same underlying call, same filter flags), kept for backward compatibility:
OpenTelemetry (OTLP)
Timber accepts logs in the OTLP JSON format, so you can point any OpenTelemetry SDK or Collector at Timber for log ingestion.
Requires Timber Standard or Pro. Maximum payload size is 1 MB.
The endpoint accepts the standard OTLP Logs JSON structure. Timber maps the fields as follows:
| OTLP field | Timber field |
|---|---|
resource.attributes["service.name"] |
service |
body.stringValue |
message |
severityNumber / severityText |
level |
attributes |
attributes |
traceId |
trace_id |
spanId |
span_id |
timeUnixNano |
timestamp |
Example
curl "https://timber.integration.protokol.cloud/logs/otlp" \
-X POST \
-H "Authorization: Bearer <your-api-token>" \
-H "X-Project-Uuid: <your-project-uuid>" \
-H "Content-Type: application/json" \
-d '{
"resourceLogs": [{
"resource": {
"attributes": [
{ "key": "service.name", "value": { "stringValue": "checkout" } }
]
},
"scopeLogs": [{
"logRecords": [
{
"timeUnixNano": "1716825600000000000",
"severityNumber": 9,
"body": { "stringValue": "Order confirmed" },
"attributes": [
{ "key": "order_id", "value": { "stringValue": "ord_123" } }
],
"traceId": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4",
"spanId": "1a2b3c4d5e6f7a8b"
}
]
}]
}]
}'
OpenTelemetry SDK Configuration
To send logs from an OTEL-instrumented application, configure the OTLP exporter to point at Timber:
export OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=https://timber.integration.protokol.cloud/logs/otlp
export OTEL_EXPORTER_OTLP_LOGS_HEADERS="Authorization=Bearer <your-api-token>,X-Project-Uuid=<your-project-uuid>"
export OTEL_EXPORTER_OTLP_LOGS_PROTOCOL=http/json
Only log collection is supported. Traces and metrics should be sent to your own observability backend.
Retention
Expired events are automatically cleaned up daily based on your project tier. No manual action is needed — events older than the retention window are permanently deleted.