Telemetry

sdk.telemetry gives your app visibility into three streams of observability data:

Sub-namespaceWhat it tracksBacking store
sdk.telemetry.auditWho did what and when — tamper-evident event logMongoDB + WORM archive
sdk.telemetry.tracesLLM / AI call instrumentation — model, tokens, latency, costClickHouse
sdk.telemetry.eventsCustom app analytics eventsClickHouse

Audit Logs

Auto-instrumented. cPod automatically emits audit events for every EDM mutation (create, update, delete on People, Assets, Licenses, etc.) and every platform service invocation (skill runs, workflow triggers, job submissions). You only need sdk.telemetry.audit.emit() for custom business events not covered by built-in actions — approvals, policy exceptions, manual reviews, exports.

Every audit event is tamper-evident: each record includes a previousHash and a recordHash (HMAC-SHA-256), forming a per-tenant chain. Once written, events cannot be modified or deleted through the API.

Emit a custom audit event

import { CpodClient } from '@cpod/sdk'
const sdk = CpodClient.fromEnv()
 
await sdk.telemetry.audit.emit({
  action: 'export.approved',
  resourceId: 'per-abc123',
  resourceType: 'person',
  outcome: 'success',
  metadata: { approvedBy: 'manager@acme.com', reason: 'GDPR request' },
})

Query audit events

const events = await sdk.telemetry.audit.query({
  resourceType: 'person',
  action: 'person.deleted',
  from: '2026-01-01T00:00:00Z',
  limit: 50,
})
 
for (const event of events.items) {
  console.log(event.actorId, event.action, event.ts)
}
 
// Paginate
if (events.nextCursor) {
  const page2 = await sdk.telemetry.audit.query({ cursor: events.nextCursor, limit: 50 })
}

AuditEvent fields

FieldTypeDescription
idstringaud- prefixed ID
sequenceIdintegerMonotonic per-tenant sequence number
tenantIdstringOwning tenant
appIdstringApp slug that originated the action
actionstringDot-separated action name (e.g. person.created, export.approved)
actorTypestringuser, service, system, or impersonator
actorIdstringUser or service account that triggered the event
impersonatedUserIdstring?Set when an admin acts on behalf of another user
resourceTypestringEDM domain type (e.g. person, license)
resourceIdstringID of the affected entity
outcomestringsuccess, error, or denied
reasonstring?Denial reason or error message
beforeobject?Snapshot of entity state before mutation (auto-populated for EDM ops)
afterobject?Snapshot of entity state after mutation (auto-populated for EDM ops)
changesobject?Computed diff of changed fields
metadataobject?Custom key-value context
ipstring?Source IP of the originating request
requestIdstring?Distributed trace correlation ID
previousHashstringSHA-256 of the prior event in the tenant chain
recordHashstringHMAC-SHA-256 of this record (tamper-detection)
wormRefstring?MinIO Object Lock URL once archived
tsstringISO 8601 datetime
⚠️

Audit events are immutable and cannot be deleted via the API. Retention is governed by your subscription tier — 1 year on Pro, 7 years on Enterprise. Contact support for compliance-driven bulk export.


LLM Traces

Track every AI/LLM call your app makes — model, provider, token usage (including cache hits), latency, and cost. Traces support distributed span parenting so you can reconstruct multi-step agent runs.

Traces are automatically emitted by the cPod Skills runtime for every AI-backed skill execution. Manual instrumentation is only needed if your code calls an LLM directly outside the Skills system.

List traces

const traces = await sdk.telemetry.traces.list({
  model: 'anthropic/claude-opus-4-7',
  from: '2026-01-01T00:00:00Z',
  limit: 20,
})
 
for (const trace of traces.items) {
  const totalTokens = trace.inputTokens + trace.outputTokens
  console.log(trace.model, totalTokens, `${trace.latencyMs}ms`, `$${trace.costUsd}`)
}

Trace fields

FieldTypeDescription
idstringtrc- prefixed ID
tenantIdstringOwning tenant
appIdstringSource app slug
parentSpanIdstring?Distributed-tracing parent span
agentRunIdstring?Agent run this trace belongs to
userIdstring?Initiating user (null for system calls)
modelstringModel identifier (e.g. anthropic/claude-opus-4-7)
providerstringanthropic, openai, azure, etc.
spanKindstringchat, embedding, image, audio, tool_call, or evaluation
inputTokensintegerPrompt token count
outputTokensintegerCompletion token count
cacheReadTokensintegerTokens served from cache
cacheWriteTokensintegerTokens written to cache
latencyMsintegerEnd-to-end latency in milliseconds
cacheHitbooleanWhether the response was served from cache
costUsdnumberEstimated cost in USD
finishReasonstring?stop, length, tool_calls, or error
securityViolationsobject[]?PII/DLP hits caught by the policy engine
tsstringISO 8601 datetime

App Events

Emit custom analytics events for user interactions, feature usage, and business milestones. All events land in ClickHouse and are immediately queryable.

Emit an event

await sdk.telemetry.events.emit('report.exported', {
  format: 'pdf',
  recordCount: 1500,
  triggeredBy: 'scheduled-job',
})

Query events

const events = await sdk.telemetry.events.query({
  eventType: 'report.exported',
  from: '2026-01-01T00:00:00Z',
  limit: 100,
})
 
for (const event of events.items) {
  console.log(event.eventType, event.userId, event.properties)
}

AppEvent fields

FieldTypeDescription
idstringevt- prefixed ID
tenantIdstringOwning tenant
appIdstringSource app slug
userIdstring?Initiating user (null for anonymous events)
sessionIdstring?Browser session identifier
eventTypestringEvent name (e.g. report.exported, page_view)
eventCategorystring?navigation, interaction, mutation, or business_event
entityTypestring?Target entity type if applicable
entityIdstring?Target entity ID
propertiesobjectFree-form event-specific properties
pageUrlstring?URL where the event occurred
geoobject?{ country, region, city }
deviceobject?{ type, os, browser }
tsstringISO 8601 datetime