> ## Documentation Index
> Fetch the complete documentation index at: https://www.adaline.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Trace

# Trace Class

The `Trace` class represents a high-level operation or workflow in your LLM application. Traces capture the entire lifecycle of a request, batch job, or user interaction, and can contain multiple child spans for granular tracking.

## Overview

A trace is the top-level unit of observability that represents:

* A single user request to your API
* A background job or workflow
* A conversation turn in a chatbot
* A complete RAG pipeline execution
* Any end-to-end operation you want to track

Traces contain:

* **Metadata**: name, status, timestamps, tags, attributes
* **Context**: session ID, reference ID
* **Children**: one or more spans representing sub-operations

## Creation

Create a trace using the `Monitor.logTrace()` method:

```typescript theme={null}
const trace = monitor.logTrace({
  name: 'User Login',
  sessionId: 'session-abc-123',
  tags: ['auth', 'production'],
  attributes: { userId: 'user-456' }
});
```

## Properties

### trace

```typescript theme={null}
trace: CreateLogTraceRequest
```

The underlying trace request object that will be sent to the API. Contains all trace metadata.

**Structure:**

```typescript theme={null}
{
  projectId: string;
  trace: {
    name: string;
    status: TraceStatus;
    sessionId?: string;
    referenceId: string;
    tags?: string[];
    attributes?: Record<string, LogAttributesValue>;  // LogAttributesValue = string | number | boolean
    startedAt: number;     // Unix timestamp in milliseconds
    endedAt?: number;      // Set when trace.end() is called
  }
}
```

### traceId

```typescript theme={null}
traceId: string | undefined
```

The server-assigned trace ID, set after the trace is successfully flushed to the API.

```typescript theme={null}
const trace = monitor.logTrace({ name: 'Operation' });
console.log(trace.traceId); // undefined (not flushed yet)

trace.end();
await monitor.flush();

console.log(trace.traceId); // "trace_abc123xyz" (assigned by server)
```

## Methods

### logSpan()

Create a child span within this trace.

```typescript theme={null}
logSpan(options: LogSpanOptions): Span
```

#### Parameters

<ParamField path="options" type="object" required>
  <Expandable title="properties">
    <ParamField path="name" type="string" required>
      Human-readable name for the span (e.g., "LLM Call", "Database Query").
    </ParamField>

    <ParamField path="status" type="SpanStatus" optional default="unknown">
      Initial [SpanStatus](/docs/reference/sdk/v2/typescript/types/SpanStatus): `'success' | 'failure' | 'aborted' | 'cancelled' | 'unknown'`
    </ParamField>

    <ParamField path="referenceId" type="string" optional>
      Custom reference ID. Auto-generated UUID if not provided.
    </ParamField>

    <ParamField path="promptId" type="string" optional>
      ID of the prompt used in this span (for LLM calls).
    </ParamField>

    <ParamField path="deploymentId" type="string | null" optional>
      ID of the deployment used in this span.
    </ParamField>

    <ParamField path="runEvaluation" type="boolean" optional>
      Whether to run evaluators on this span after completion.
    </ParamField>

    <ParamField path="tags" type="string[]" optional>
      Tags for categorization (e.g., `['llm', 'openai']`).
    </ParamField>

    <ParamField path="attributes" type="Record<string, LogAttributesValue>" optional>
      Additional metadata (e.g., `{ model: 'gpt-4o', tokens: 1500 }`). [LogAttributesValue](/docs/reference/sdk/v2/typescript/types/LogAttributesValue) = `string | number | boolean`
    </ParamField>

    <ParamField path="content" type="LogSpanContent" optional>
      [LogSpanContent](/docs/reference/sdk/v2/typescript/types/LogSpanContent) (input/output data). Defaults to `monitor.defaultContent`.
    </ParamField>
  </Expandable>
</ParamField>

#### Returns

<ResponseField name="span" type="Span">
  A new Span instance. See [Span Class](/docs/reference/sdk/v2/typescript/classes/span) for details.
</ResponseField>

#### Examples

<CodeGroup>
  ```typescript Basic Span theme={null}
  const trace = monitor.logTrace({ name: 'API Request' });

  const span = trace.logSpan({
    name: 'Process Data'
  });

  // Do work...
  await processData();

  span.update({ status: 'success' });
  span.end();
  trace.end();
  ```

  ```typescript LLM Call Span theme={null}
  const trace = monitor.logTrace({
    name: 'Chat Completion',
    sessionId: userId
  });

  const llmSpan = trace.logSpan({
    name: 'OpenAI GPT-4',
    promptId: deployment.promptId,
    deploymentId: deployment.id,
    runEvaluation: true,
    tags: ['llm', 'openai', 'gpt-4o'],
    attributes: {
      model: 'gpt-4o',
      temperature: 0.7
    }
  });

  const response = await openai.chat.completions.create({ /* ... */ });

  llmSpan.update({
    status: 'success',
    content: {
      type: 'Model',
      provider: 'openai',
      model: 'gpt-4o',
      input: JSON.stringify(messages),
      output: JSON.stringify(response.choices[0].message)
    }
  });

  llmSpan.end();
  trace.end();
  ```

  ```typescript Nested Spans theme={null}
  const trace = monitor.logTrace({ name: 'RAG Pipeline' });

  // Parent span
  const ragSpan = trace.logSpan({
    name: 'RAG Operation',
    tags: ['rag']
  });

  // Child spans
  const embeddingSpan = ragSpan.logSpan({
    name: 'Generate Embedding',
    tags: ['embedding']
  });
  embeddingSpan.end();

  const retrievalSpan = ragSpan.logSpan({
    name: 'Vector Search',
    tags: ['retrieval']
  });
  retrievalSpan.end();

  const llmSpan = ragSpan.logSpan({
    name: 'Generate Answer',
    tags: ['llm']
  });
  llmSpan.end();

  ragSpan.end();
  trace.end();
  ```
</CodeGroup>

### update()

Update trace metadata in place.

```typescript theme={null}
update(updates: TraceUpdates): this
```

#### Parameters

<ParamField path="updates" type="object" required>
  Partial updates to apply to the trace.

  <Expandable title="properties">
    <ParamField path="name" type="string" optional>
      Update the trace name.
    </ParamField>

    <ParamField path="status" type="TraceStatus" optional>
      Update the [TraceStatus](/docs/reference/sdk/v2/typescript/types/TraceStatus): `'success' | 'failure' | 'aborted' | 'cancelled' | 'pending' | 'unknown'`
    </ParamField>

    <ParamField path="tags" type="string[]" optional>
      Update tags (replaces existing tags).
    </ParamField>

    <ParamField path="attributes" type="Record<string, LogAttributesValue>" optional>
      Update attributes (merges with existing attributes). [LogAttributesValue](/docs/reference/sdk/v2/typescript/types/LogAttributesValue) = `string | number | boolean`
    </ParamField>
  </Expandable>
</ParamField>

#### Returns

Returns `this` for method chaining.

#### Examples

<CodeGroup>
  ```typescript Update Status theme={null}
  const trace = monitor.logTrace({
    name: 'Process Order',
    status: 'pending'
  });

  try {
    await processOrder();
    trace.update({ status: 'success' });
  } catch (error) {
    trace.update({ status: 'failure' });
  }

  trace.end();
  ```

  ```typescript Add Attributes theme={null}
  const trace = monitor.logTrace({ name: 'User Request' });

  // Add attribute after getting user info
  const userId = await getUserId();
  trace.update({
    attributes: { userId }
  });

  // Add more attributes
  trace.update({
    attributes: { 
      processingTime: Date.now() - startTime,
      itemsProcessed: 42
    }
  });

  trace.end();
  ```

  ```typescript Method Chaining theme={null}
  monitor.logTrace({ name: 'Quick Operation' })
    .update({ status: 'pending' })
    .update({ tags: ['fast', 'important'] })
    .end();
  ```

  ```typescript Update Everything theme={null}
  trace.update({
    name: 'Updated Name',
    status: 'success',
    tags: ['completed', 'verified'],
    attributes: {
      duration: 1234,
      outcome: 'positive'
    }
  });
  ```
</CodeGroup>

### end()

Mark the trace as complete and ready to be flushed.

```typescript theme={null}
end(): string | undefined
```

#### Behavior

1. Sets `endedAt` timestamp if not already set
2. Marks the trace as `ready` in the monitor's buffer
3. Recursively ends all child spans (and their descendants)
4. Returns the trace's reference ID

<Warning>
  Always call `end()` on your traces! Traces that are never ended will never be flushed to the API.
</Warning>

#### Returns

<ResponseField name="referenceId" type="string | undefined">
  The trace's reference ID for correlation with external systems.
</ResponseField>

#### Examples

<CodeGroup>
  ```typescript Basic theme={null}
  const trace = monitor.logTrace({ name: 'Operation' });

  // Do work...

  trace.end(); // Required!
  ```

  ```typescript Try-Finally Pattern theme={null}
  const trace = monitor.logTrace({ name: 'Critical Operation' });

  try {
    await doWork();
    trace.update({ status: 'success' });
  } catch (error) {
    trace.update({ status: 'failure' });
    throw error;
  } finally {
    trace.end(); // Always called, even if error thrown
  }
  ```

  ```typescript Get Reference ID theme={null}
  const trace = monitor.logTrace({
    name: 'Async Job',
    referenceId: `job-${jobId}`
  });

  // Do work...

  const refId = trace.end();
  console.log(`Trace completed: ${refId}`); // "job-123"
  ```

  ```typescript Auto-End Children theme={null}
  const trace = monitor.logTrace({ name: 'Parent' });

  const span1 = trace.logSpan({ name: 'Child 1' });
  const span2 = span1.logSpan({ name: 'Grandchild' });
  const span3 = trace.logSpan({ name: 'Child 2' });

  // Don't need to manually end children
  trace.end(); // Automatically ends span1, span2, span3
  ```
</CodeGroup>

## Complete Examples

### Example 1: Simple API Request

```typescript theme={null}
import { Adaline } from '@adaline/client';
import { Gateway } from '@adaline/gateway';
import { OpenAI } from '@adaline/openai';

const adaline = new Adaline();
const gateway = new Gateway();
const openaiProvider = new OpenAI();
const monitor = adaline.initMonitor({ projectId: 'my-api' });

async function handleChatRequest(userId: string, message: string) {
  // Create trace for this request
  const trace = monitor.logTrace({
    name: 'Chat Request',
    sessionId: userId,
    tags: ['chat', 'api'],
    attributes: {
      userId,
      messageLength: message.length
    }
  });

  try {
    // Log the LLM call
    const llmSpan = trace.logSpan({
      name: 'OpenAI Completion',
      tags: ['llm']
    });

    const model = openaiProvider.chatModel({
      modelName: 'gpt-4o',
      apiKey: process.env.OPENAI_API_KEY!
    });

    const gatewayResponse = await gateway.completeChat({
      model,
      messages: [
        { role: 'user', content: [{ modality: 'text', value: message }] }
      ]
    });

    llmSpan.update({
      status: 'success',
      content: {
        type: 'Model',
        provider: 'openai',
        model: 'gpt-4o',
        input: JSON.stringify(gatewayResponse.provider.request),
        output: JSON.stringify(gatewayResponse.provider.response)
      }
    });
    llmSpan.end();

    trace.update({ status: 'success' });
    return gatewayResponse.response.messages[0].content[0].value;

  } catch (error) {
    trace.update({
      status: 'failure',
      attributes: {
        error: error instanceof Error ? error.message : String(error)
      }
    });
    throw error;

  } finally {
    trace.end();
  }
}
```

### Example 2: Multi-Step Workflow

```typescript theme={null}
async function processUserOnboarding(userId: string) {
  const trace = monitor.logTrace({
    name: 'User Onboarding',
    sessionId: userId,
    status: 'pending',
    tags: ['onboarding', 'workflow'],
    attributes: { userId }
  });

  try {
    // Step 1: Create account
    const createSpan = trace.logSpan({
      name: 'Create Account',
      tags: ['database']
    });
    await createAccount(userId);
    createSpan.update({ status: 'success' });
    createSpan.end();

    // Step 2: Send welcome email
    const emailSpan = trace.logSpan({
      name: 'Send Welcome Email',
      tags: ['email']
    });
    await sendWelcomeEmail(userId);
    emailSpan.update({ status: 'success' });
    emailSpan.end();

    // Step 3: Generate personalized content
    const llmSpan = trace.logSpan({
      name: 'Generate Welcome Message',
      tags: ['llm', 'personalization']
    });
    const welcomeMsg = await generateWelcomeMessage(userId);
    llmSpan.update({
      status: 'success',
      content: {
        type: 'Model',
        provider: 'openai',
        model: 'gpt-4o',
        input: JSON.stringify({ userId }),
        output: JSON.stringify({ message: welcomeMsg })
      }
    });
    llmSpan.end();

    trace.update({ status: 'success' });

  } catch (error) {
    trace.update({
      status: 'failure',
      attributes: { error: String(error) }
    });
    throw error;

  } finally {
    trace.end();
  }
}
```

### Example 3: Nested Operations (RAG Pipeline)

```typescript theme={null}
async function answerQuestion(sessionId: string, question: string) {
  const trace = monitor.logTrace({
    name: 'RAG Question Answering',
    sessionId,
    tags: ['rag', 'qa'],
    attributes: { questionLength: question.length }
  });

  try {
    // Parent span for entire RAG operation
    const ragSpan = trace.logSpan({
      name: 'RAG Pipeline',
      tags: ['pipeline']
    });

    // Step 1: Generate embedding (child of ragSpan)
    const embedSpan = ragSpan.logSpan({
      name: 'Generate Query Embedding',
      tags: ['embedding']
    });
    const embedding = await generateEmbedding(question);
    embedSpan.update({
      status: 'success',
      content: {
        type: 'Embeddings',
        input: JSON.stringify({ query: question }),
        output: JSON.stringify({ dimensions: embedding.length })
      }
    });
    embedSpan.end();

    // Step 2: Retrieve documents (child of ragSpan)
    const retrieveSpan = ragSpan.logSpan({
      name: 'Vector Search',
      tags: ['retrieval', 'vector-db']
    });
    const docs = await retrieveDocuments(embedding);
    retrieveSpan.update({
      status: 'success',
      content: {
        type: 'Retrieval',
        input: JSON.stringify({ embedding: 'vector', topK: 5 }),
        output: JSON.stringify({ documentIds: docs.map(d => d.id) })
      },
      attributes: { documentsFound: docs.length }
    });
    retrieveSpan.end();

    // Step 3: Generate answer (child of ragSpan)
    const llmSpan = ragSpan.logSpan({
      name: 'Generate Answer',
      tags: ['llm', 'answer-generation'],
      runEvaluation: true
    });
    const answer = await generateAnswer(question, docs);
    llmSpan.update({
      status: 'success',
      content: {
        type: 'Model',
        provider: 'openai',
        model: 'gpt-4o',
        input: JSON.stringify({ question, context: docs }),
        output: JSON.stringify({ answer })
      }
    });
    llmSpan.end();

    ragSpan.update({ status: 'success' });
    ragSpan.end();

    trace.update({ status: 'success' });
    return answer;

  } catch (error) {
    trace.update({ status: 'failure' });
    throw error;

  } finally {
    trace.end();
  }
}
```

### Example 4: Long-Running Background Job

```typescript theme={null}
async function processBatch(batchId: string) {
  const trace = monitor.logTrace({
    name: 'Batch Processing',
    referenceId: `batch-${batchId}`,
    status: 'pending',
    tags: ['batch', 'background'],
    attributes: {
      batchId,
      startTime: Date.now()
    }
  });

  const items = await getBatchItems(batchId);
  
  trace.update({
    attributes: { itemCount: items.length }
  });

  let successCount = 0;
  let failureCount = 0;

  for (const item of items) {
    const itemSpan = trace.logSpan({
      name: `Process Item ${item.id}`,
      tags: ['item'],
      attributes: { itemId: item.id }
    });

    try {
      await processItem(item);
      itemSpan.update({ status: 'success' });
      successCount++;
    } catch (error) {
      itemSpan.update({
        status: 'failure',
        attributes: { error: String(error) }
      });
      failureCount++;
    }

    itemSpan.end();
  }

  trace.update({
    status: failureCount === 0 ? 'success' : 'failure',
    attributes: {
      successCount,
      failureCount,
      duration: Date.now() - trace.trace.trace.startedAt
    }
  });

  trace.end();
}
```

## Type Definitions

```typescript theme={null}
type LogAttributesValue = string | number | boolean;

type TraceStatus = 
  | 'success'
  | 'failure'
  | 'aborted'
  | 'cancelled'
  | 'pending'
  | 'unknown';

interface LogTraceOptions {
  name: string;
  status?: TraceStatus;
  sessionId?: string;
  referenceId?: string;
  tags?: string[];
  attributes?: Record<string, LogAttributesValue>;
}

interface TraceUpdates {
  name?: string;
  status?: TraceStatus;
  tags?: string[];
  attributes?: Record<string, LogAttributesValue>;
}

interface CreateLogTraceRequest {
  projectId: string;
  trace: {
    name: string;
    status: TraceStatus;
    sessionId?: string;
    referenceId: string;
    tags?: string[];
    attributes?: Record<string, LogAttributesValue>;  // LogAttributesValue = string | number | boolean
    startedAt: number;
    endedAt?: number;
  };
}
```

## Best Practices

### 1. Always Use Try-Finally

```typescript theme={null}
// ✅ Good: trace.end() always called
const trace = monitor.logTrace({ name: 'Operation' });
try {
  await doWork();
  trace.update({ status: 'success' });
} finally {
  trace.end();
}
```

```typescript theme={null}
// ❌ Bad: trace.end() might not be called
const trace = monitor.logTrace({ name: 'Operation' });
await doWork();
trace.end(); // Skipped if doWork() throws!
```

### 2. Use Meaningful Names

```typescript theme={null}
// ✅ Good: Descriptive names
const trace = monitor.logTrace({ name: 'User Registration Flow' });
const trace = monitor.logTrace({ name: 'PDF Processing Pipeline' });
const trace = monitor.logTrace({ name: 'RAG Question Answering' });
```

```typescript theme={null}
// ❌ Bad: Generic names
const trace = monitor.logTrace({ name: 'Request' });
const trace = monitor.logTrace({ name: 'Function' });
const trace = monitor.logTrace({ name: 'Process' });
```

### 3. Add Context with Attributes

```typescript theme={null}
// ✅ Good: Rich context
const trace = monitor.logTrace({
  name: 'API Request',
  sessionId: userId,
  tags: ['api', 'production', 'premium-tier'],
  attributes: {
    userId,
    endpoint: '/api/chat',
    method: 'POST',
    clientVersion: '2.1.0',
    region: 'us-east-1'
  }
});
```

### 4. Update Status Based on Outcome

```typescript theme={null}
// ✅ Good: Accurate status tracking
const trace = monitor.logTrace({ name: 'Operation', status: 'pending' });
try {
  await doWork();
  trace.update({ status: 'success' });
} catch (error) {
  trace.update({ status: 'failure' });
  throw error;
} finally {
  trace.end();
}
```

### 5. Use Sessions for Related Traces

```typescript theme={null}
// ✅ Good: Group related traces
const sessionId = `user-${userId}-${Date.now()}`;

// First trace
const trace1 = monitor.logTrace({
  name: 'Login',
  sessionId
});

// Later traces in same session
const trace2 = monitor.logTrace({
  name: 'Chat Message 1',
  sessionId
});

const trace3 = monitor.logTrace({
  name: 'Chat Message 2',
  sessionId
});
```

## Common Patterns

### Pattern 1: Request Handler

```typescript theme={null}
async function handleRequest(req: Request) {
  const trace = monitor.logTrace({
    name: `${req.method} ${req.url}`,
    sessionId: req.headers.get('session-id') || undefined,
    tags: ['api', 'http'],
    attributes: {
      method: req.method,
      path: req.url,
      userAgent: req.headers.get('user-agent') || 'unknown'
    }
  });

  try {
    const result = await processRequest(req);
    trace.update({ status: 'success' });
    return result;
  } catch (error) {
    trace.update({ status: 'failure' });
    throw error;
  } finally {
    trace.end();
  }
}
```

### Pattern 2: Background Job

```typescript theme={null}
async function runJob(jobId: string) {
  const trace = monitor.logTrace({
    name: 'Background Job',
    referenceId: jobId,
    status: 'pending',
    tags: ['job', 'async']
  });

  try {
    // Job logic with spans...
    trace.update({ status: 'success' });
  } catch (error) {
    trace.update({ status: 'failure' });
  } finally {
    trace.end();
  }
}
```
