Transactional

TypeScript SDK

Complete guide to using the Observability TypeScript SDK.

Installation

Install the SDK using npm or your preferred package manager:

npm install @transactional/observability

Initialization

Initialize the SDK at your application's entry point:

import { initObservability } from '@transactional/observability';
 
initObservability({
  dsn: process.env.TRANSACTIONAL_OBSERVABILITY_DSN!,
});

Configuration Options

initObservability({
  // Required: Your project DSN
  dsn: 'https://pk_...@api.transactional.dev/observability/42',
 
  // Optional: Disable tracing (useful for development)
  enabled: process.env.NODE_ENV === 'production',
 
  // Optional: Batch size before flushing
  batchSize: 100,
 
  // Optional: Flush interval in milliseconds
  flushInterval: 5000,
 
  // Optional: Enable debug logging
  debug: false,
});

Creating Traces

A trace represents a complete unit of work, like a single API request or user interaction.

import { getObservability } from '@transactional/observability';
 
const obs = getObservability();
 
// Create a new trace
const trace = obs.trace({
  name: 'chat-completion',
  input: { userMessage: 'Hello!' },
  userId: 'user-123',        // Optional
  sessionId: 'session-456',  // Optional
  metadata: {                 // Optional
    environment: 'production',
  },
  tags: ['chat', 'support'], // Optional
});
 
// Do your work...
 
// End the trace with output
await trace.end({
  output: { response: 'Hi there!' },
});
 
// Or end with error
await trace.error(new Error('Something went wrong'));

Trace Parameters

ParameterTypeDescription
namestringRequired. Name of the trace
inputobjectInput data for the trace
userIdstringUser ID for attribution
sessionIdstringSession ID to group traces
metadataobjectArbitrary metadata
tagsstring[]Tags for filtering

Tracking Generations

A generation is an LLM call within a trace. It captures model, tokens, and cost information.

// Create a generation (LLM call)
const generation = obs.generation({
  name: 'summarize',
  modelName: 'gpt-4o',
  input: {
    messages: [
      { role: 'system', content: 'You are a helpful assistant.' },
      { role: 'user', content: 'Summarize this article...' },
    ],
  },
});
 
// Make your LLM call...
 
// End with output and token counts
await generation.end({
  output: { content: 'Here is the summary...' },
  promptTokens: 150,
  completionTokens: 50,
});

Generation Parameters

ParameterTypeDescription
namestringRequired. Name of the generation
modelNamestringModel identifier (e.g., gpt-4o)
inputobjectInput to the LLM
parentObservationIdstringParent span ID for nesting
metadataobjectArbitrary metadata

End Parameters

ParameterTypeDescription
outputobjectLLM output
promptTokensnumberNumber of input tokens
completionTokensnumberNumber of output tokens

Creating Spans

Spans represent intermediate steps within a trace that aren't LLM calls.

// Create a span for a processing step
const span = obs.observation({
  type: 'SPAN',
  name: 'retrieve-documents',
  input: { query: 'user question' },
});
 
// Do your work...
 
// End the span
await span.end({
  output: { documents: [...] },
});

Sessions

Sessions group related traces together, useful for multi-turn conversations:

const trace = obs.trace({
  name: 'chat-turn',
  sessionId: 'conversation-123',  // All traces with this ID are grouped
  input: { message: 'Hello!' },
});

Nested Observations

Create hierarchical traces for complex pipelines:

const trace = obs.trace({ name: 'rag-pipeline' });
 
// Parent span
const retrieval = obs.observation({
  type: 'SPAN',
  name: 'retrieval',
});
 
// Child generation within retrieval
const embedding = obs.generation({
  name: 'embed-query',
  modelName: 'text-embedding-3-small',
  parentObservationId: retrieval.id,
});
 
await embedding.end({ /* ... */ });
await retrieval.end({ /* ... */ });
 
// Another generation
const completion = obs.generation({
  name: 'generate-response',
  modelName: 'gpt-4o',
});
 
await completion.end({ /* ... */ });
await trace.end({ /* ... */ });

Error Handling

Track errors in your traces:

try {
  // Your code...
} catch (error) {
  await trace.error(error as Error);
  throw error;
}

Error Tracking

Capture application errors with rich context for debugging. See the Error Tracking Guide for complete documentation.

Enable Error Tracking

initObservability({
  dsn: 'your-dsn',
  enableErrorTracking: true,
 
  autoCapture: {
    uncaughtExceptions: true,
    unhandledRejections: true,
  },
});

Capture Exceptions

const obs = getObservability();
 
try {
  await riskyOperation();
} catch (error) {
  obs.captureException(error as Error, {
    tags: { feature: 'checkout', provider: 'stripe' },
    user: { id: 'user-123', email: 'user@example.com' },
    extra: { orderId: 'order-456', amount: 99.99 },
  });
}

Capture Messages

// Simple message
obs.captureMessage('User attempted checkout with empty cart');
 
// With severity and context
obs.captureMessage('Payment retry succeeded after 3 attempts', 'warning', {
  tags: { provider: 'stripe' },
  extra: { retryCount: 3 },
});

Add Breadcrumbs

Track user actions leading to errors:

obs.addBreadcrumb({
  type: 'user',
  category: 'checkout',
  message: 'User clicked submit',
  level: 'info',
  data: { cartItems: 3, total: 99.99 },
});

Set User Context

// Set user after authentication
obs.setUser({
  id: 'user-123',
  email: 'user@example.com',
  username: 'johndoe',
});
 
// Clear on logout
obs.setUser(null);

Set Tags

obs.setTags({
  environment: 'production',
  version: '1.2.3',
  team: 'payments',
});

Flushing

The SDK batches events and flushes periodically. Force a flush before shutdown:

const obs = getObservability();
 
// Flush and shutdown
await obs.shutdown();

TypeScript Types

Import types for your application:

import type {
  Trace,
  Observation,
  Session,
  CreateTraceParams,
  CreateObservationParams,
} from '@transactional/observability';

Best Practices

  1. Initialize early - Call initObservability() at application startup
  2. Always end traces - Use try/finally to ensure traces are ended
  3. Use sessions - Group related traces for better debugging
  4. Track token usage - Include token counts for accurate cost tracking
  5. Add metadata - Include useful context for debugging

Next Steps