> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/iii-hq/sdk/llms.txt
> Use this file to discover all available pages before exploring further.

# Context

> Access context, logging, and tracing in function handlers

Every III function handler has access to a context object that provides logging, tracing, and request metadata.

## getContext()

Get the current context within a function handler.

```typescript theme={null}
import { getContext } from 'iii-sdk'

const context = getContext()
```

<ResponseField name="context" type="Context">
  Current execution context

  <Expandable title="Context properties">
    <ResponseField name="logger" type="Logger" required>
      Logger instance for structured logging
    </ResponseField>

    <ResponseField name="trace" type="Span">
      Active OpenTelemetry span for custom tracing (undefined if OTel is disabled)
    </ResponseField>
  </Expandable>
</ResponseField>

### Example: Basic Usage

```typescript theme={null}
import { init, getContext } from 'iii-sdk'

const iii = init('ws://localhost:49199')

iii.registerFunction(
  { id: 'users::create' },
  async (data: { email: string; name: string }) => {
    const { logger, trace } = getContext()
    
    // Log with structured data
    logger.info('Creating user', { email: data.email })
    
    // Add trace attributes
    trace?.setAttribute('user.email', data.email)
    
    const user = {
      id: crypto.randomUUID(),
      email: data.email,
      name: data.name,
      created_at: new Date().toISOString()
    }
    
    logger.info('User created', { userId: user.id })
    trace?.addEvent('User created successfully')
    
    return user
  }
)
```

## Logger

The Logger provides structured logging with automatic trace correlation.

### Methods

#### info()

Log an informational message.

```typescript theme={null}
logger.info(message, data?)
```

<ParamField path="message" type="string" required>
  Log message
</ParamField>

<ParamField path="data" type="unknown">
  Optional structured data to include in the log
</ParamField>

#### warn()

Log a warning message.

```typescript theme={null}
logger.warn(message, data?)
```

<ParamField path="message" type="string" required>
  Warning message
</ParamField>

<ParamField path="data" type="unknown">
  Optional structured data
</ParamField>

#### error()

Log an error message.

```typescript theme={null}
logger.error(message, data?)
```

<ParamField path="message" type="string" required>
  Error message
</ParamField>

<ParamField path="data" type="unknown">
  Optional error details or structured data
</ParamField>

#### debug()

Log a debug message.

```typescript theme={null}
logger.debug(message, data?)
```

<ParamField path="message" type="string" required>
  Debug message
</ParamField>

<ParamField path="data" type="unknown">
  Optional debug data
</ParamField>

### Example: Structured Logging

```typescript theme={null}
import { init, getContext } from 'iii-sdk'

const iii = init('ws://localhost:49199')

iii.registerFunction(
  { id: 'orders::process' },
  async (data: { order_id: string; items: any[] }) => {
    const { logger } = getContext()
    
    logger.info('Processing order', {
      order_id: data.order_id,
      item_count: data.items.length
    })
    
    try {
      // Validate order
      if (data.items.length === 0) {
        logger.warn('Order has no items', { order_id: data.order_id })
        throw new Error('Order must contain at least one item')
      }
      
      // Process items
      for (const item of data.items) {
        logger.debug('Processing item', {
          order_id: data.order_id,
          item_id: item.id,
          quantity: item.quantity
        })
      }
      
      logger.info('Order processed successfully', {
        order_id: data.order_id
      })
      
      return { success: true, order_id: data.order_id }
      
    } catch (error) {
      logger.error('Failed to process order', {
        order_id: data.order_id,
        error: error.message
      })
      throw error
    }
  }
)
```

### Automatic Trace Correlation

Logs are automatically correlated with traces:

```typescript theme={null}
import { init, getContext } from 'iii-sdk'

const iii = init('ws://localhost:49199')

iii.registerFunction(
  { id: 'service_a::handler' },
  async (data) => {
    const { logger } = getContext()
    
    logger.info('Service A: Processing request')
    // Log includes trace_id and span_id automatically
    
    // Call another service
    const result = await iii.call('service_b::handler', data)
    
    logger.info('Service A: Received response from B')
    
    return result
  }
)

iii.registerFunction(
  { id: 'service_b::handler' },
  async (data) => {
    const { logger } = getContext()
    
    logger.info('Service B: Processing request')
    // This log has the same trace_id, allowing correlation
    
    return { processed: true }
  }
)
```

All logs from both services share the same `trace_id`, making it easy to trace requests across services.

## Trace Span

The trace span allows adding custom attributes, events, and status to the current trace.

### setAttribute()

Add a custom attribute to the span.

```typescript theme={null}
trace?.setAttribute(key, value)
```

<ParamField path="key" type="string" required>
  Attribute key
</ParamField>

<ParamField path="value" type="string | number | boolean" required>
  Attribute value
</ParamField>

### addEvent()

Add a timestamped event to the span.

```typescript theme={null}
trace?.addEvent(name, attributes?)
```

<ParamField path="name" type="string" required>
  Event name
</ParamField>

<ParamField path="attributes" type="Record<string, any>">
  Optional event attributes
</ParamField>

### setStatus()

Set the span status.

```typescript theme={null}
import { SpanStatusCode } from 'iii-sdk/telemetry'

trace?.setStatus({ code: SpanStatusCode.ERROR, message: 'Operation failed' })
```

### recordException()

Record an exception in the span.

```typescript theme={null}
try {
  // risky operation
} catch (error) {
  trace?.recordException(error as Error)
  throw error
}
```

### Example: Rich Tracing

```typescript theme={null}
import { init, getContext } from 'iii-sdk'
import { SpanStatusCode } from 'iii-sdk/telemetry'

const iii = init('ws://localhost:49199')

iii.registerFunction(
  { id: 'payments::process' },
  async (data: { amount: number; currency: string; user_id: string }) => {
    const { logger, trace } = getContext()
    
    // Add attributes
    trace?.setAttribute('payment.amount', data.amount)
    trace?.setAttribute('payment.currency', data.currency)
    trace?.setAttribute('user.id', data.user_id)
    
    try {
      // Step 1: Validate
      trace?.addEvent('Validating payment details')
      await validatePayment(data)
      
      // Step 2: Charge
      trace?.addEvent('Charging payment', {
        'payment.method': 'stripe'
      })
      const charge = await chargePayment(data)
      
      trace?.setAttribute('payment.charge_id', charge.id)
      trace?.setAttribute('payment.status', 'succeeded')
      
      // Step 3: Record
      trace?.addEvent('Recording transaction')
      await recordTransaction(charge)
      
      logger.info('Payment processed', {
        charge_id: charge.id,
        amount: data.amount
      })
      
      trace?.setStatus({ code: SpanStatusCode.OK })
      
      return {
        success: true,
        charge_id: charge.id
      }
      
    } catch (error) {
      // Record the exception in the trace
      trace?.recordException(error as Error)
      trace?.setStatus({
        code: SpanStatusCode.ERROR,
        message: error.message
      })
      
      logger.error('Payment failed', {
        error: error.message,
        user_id: data.user_id
      })
      
      throw error
    }
  }
)
```

## withContext()

Manually set context for async operations (advanced use case).

```typescript theme={null}
import { withContext } from 'iii-sdk'

await withContext(fn, context)
```

<ParamField path="fn" type="(context: Context) => Promise<T>" required>
  Async function to execute with the context
</ParamField>

<ParamField path="context" type="Context" required>
  Context object to use
</ParamField>

<ResponseField name="result" type="T">
  The function's return value
</ResponseField>

<Warning>
  You typically don't need to use `withContext()` directly. The III SDK manages context automatically for function handlers.
</Warning>

### Example: Custom Context

```typescript theme={null}
import { withContext, Logger } from 'iii-sdk'

// Create a custom logger
const customLogger = new Logger('custom-trace-id', 'my-service')

// Run code with custom context
await withContext(
  async (ctx) => {
    ctx.logger.info('Using custom context')
    // Your code here
  },
  { logger: customLogger }
)
```

## Logger Constructor

Create a standalone logger instance outside of function handlers.

```typescript theme={null}
import { Logger } from 'iii-sdk'

const logger = new Logger(traceId?, serviceName?, spanId?)
```

<ParamField path="traceId" type="string">
  Optional trace ID for correlation
</ParamField>

<ParamField path="serviceName" type="string">
  Optional service name
</ParamField>

<ParamField path="spanId" type="string">
  Optional span ID
</ParamField>

### Example: Standalone Logger

```typescript theme={null}
import { Logger } from 'iii-sdk'

// Logger without trace context
const logger = new Logger()
logger.info('Application starting')

// Logger with trace ID
const traceLogger = new Logger('abc123', 'my-service')
traceLogger.info('Processing request', { request_id: '456' })
```

## Best Practices

<AccordionGroup>
  <Accordion title="Always use structured logging">
    ```typescript theme={null}
    // Good - structured data
    logger.info('User created', { userId: user.id, email: user.email })

    // Avoid - string interpolation
    logger.info(`User ${user.id} created with email ${user.email}`)
    ```
  </Accordion>

  <Accordion title="Add meaningful trace attributes">
    ```typescript theme={null}
    const { trace } = getContext()

    // Business context
    trace?.setAttribute('order.id', order.id)
    trace?.setAttribute('order.total', order.total)
    trace?.setAttribute('user.tier', user.tier)

    // Technical context
    trace?.setAttribute('db.query_count', queries.length)
    trace?.setAttribute('cache.hit', true)
    ```
  </Accordion>

  <Accordion title="Use appropriate log levels">
    ```typescript theme={null}
    // debug: Detailed information for debugging
    logger.debug('Cache miss', { key })

    // info: General informational messages
    logger.info('User logged in', { userId })

    // warn: Warning messages for recoverable issues
    logger.warn('Rate limit approaching', { current, limit })

    // error: Error messages for failures
    logger.error('Payment failed', { error: err.message })
    ```
  </Accordion>

  <Accordion title="Add events for important milestones">
    ```typescript theme={null}
    const { trace } = getContext()

    trace?.addEvent('Order validated')
    // ... validation logic

    trace?.addEvent('Payment processed', {
      'payment.method': 'card',
      'payment.amount': amount
    })
    // ... payment logic

    trace?.addEvent('Order completed')
    ```
  </Accordion>

  <Accordion title="Handle errors with trace context">
    ```typescript theme={null}
    try {
      await riskyOperation()
    } catch (error) {
      const { logger, trace } = getContext()
      
      // Log the error
      logger.error('Operation failed', {
        error: error.message,
        stack: error.stack
      })
      
      // Record in trace
      trace?.recordException(error as Error)
      trace?.setStatus({
        code: SpanStatusCode.ERROR,
        message: error.message
      })
      
      throw error
    }
    ```
  </Accordion>
</AccordionGroup>

## Context Outside Handlers

If you call `getContext()` outside a function handler, you get a default context with a basic logger:

```typescript theme={null}
import { getContext } from 'iii-sdk'

// Outside any function handler
const { logger } = getContext()
logger.info('Application initialized') // Works, but no trace correlation

// Inside a function handler
iii.registerFunction({ id: 'fn' }, async (data) => {
  const { logger, trace } = getContext()
  // Now logger has trace context and trace is available
})
```
