Skip to content

Conversation

@jckw
Copy link

@jckw jckw commented Nov 20, 2025

Adds native support for exporting OpenTelemetry traces to Adaline Trace, the hosted observability platform for LLM applications.

Changes:

  • Add AdalineTraceExporter class (SpanExporter implementation)
  • Add AdalineTracer wrapper class with helper methods
  • Export classes from @adaline/gateway package
  • Add comprehensive but concise documentation to README

Features:

  • Scoped tracing (only Gateway operations, not entire app)
  • Automatic span creation for all LLM calls
  • Built-in trace() helper for grouping workflows
  • Session IDs and tags for categorization
  • Configurable service name, version, and debug mode

Usage:

import { Gateway, AdalineTracer } from "@adaline/gateway";

const adalineTracer = new AdalineTracer({
  apiKey: process.env.ADALINE_API_KEY,
  projectId: process.env.ADALINE_PROJECT_ID,
});

const gateway = new Gateway({
  telemetry: { tracer: adalineTracer.tracer }
});

All Gateway operations are automatically traced with full observability: model names, cache hits, latency, time-to-first-token, and span hierarchies.

Adds native support for exporting OpenTelemetry traces to Adaline Trace,
the hosted observability platform for LLM applications.

Changes:
- Add AdalineTraceExporter class (SpanExporter implementation)
- Add AdalineTracer wrapper class with helper methods
- Export classes from @adaline/gateway package
- Add comprehensive but concise documentation to README

Features:
- Scoped tracing (only Gateway operations, not entire app)
- Automatic span creation for all LLM calls
- Built-in trace() helper for grouping workflows
- Session IDs and tags for categorization
- Configurable service name, version, and debug mode

Usage:
```typescript
import { Gateway, AdalineTracer } from "@adaline/gateway";

const adalineTracer = new AdalineTracer({
  apiKey: process.env.ADALINE_API_KEY,
  projectId: process.env.ADALINE_PROJECT_ID,
});

const gateway = new Gateway({
  telemetry: { tracer: adalineTracer.tracer }
});
```

All Gateway operations are automatically traced with full observability:
model names, cache hits, latency, time-to-first-token, and span hierarchies.
@greptile-apps
Copy link
Contributor

greptile-apps bot commented Nov 20, 2025

Greptile Overview

Greptile Summary

Adds native OpenTelemetry integration for exporting traces to Adaline Trace, a hosted observability platform for LLM applications.

Key Changes:

  • Implements AdalineTraceExporter class that converts OpenTelemetry spans to Adaline Trace API format
  • Adds AdalineTracer wrapper class with helper methods for creating traced workflows
  • Exports new classes from @adaline/gateway package for public API
  • Comprehensive documentation with installation, configuration, usage examples, and troubleshooting

Implementation Quality:

  • Clean architecture with proper separation of concerns
  • Good error handling in the trace() helper method
  • Scoped tracing approach (Gateway only, not global) is the right design choice
  • Well-documented with JSDoc comments and README examples

Issue Found:

  • The timeout option in AdalineTraceExporter constructor is stored but never applied to the fetch call, meaning network requests could hang indefinitely

Confidence Score: 4/5

  • This PR is safe to merge after fixing the timeout implementation issue
  • Score reflects well-structured code with comprehensive documentation, but the missing timeout implementation is a real bug that could cause the exporter to hang on slow/unresponsive API calls. The fix is straightforward and once applied, this would be a 5/5.
  • Pay close attention to core/gateway/src/plugins/telemetry/adaline-trace.exporter.ts - apply the timeout fix to the fetch call

Important Files Changed

File Analysis

Filename Score Overview
core/gateway/src/plugins/telemetry/adaline-trace.exporter.ts 4/5 Adds AdalineTraceExporter implementing OpenTelemetry SpanExporter interface. Converts and exports traces to Adaline Trace API. Missing timeout implementation on fetch call.
core/gateway/src/plugins/telemetry/adaline-tracer.ts 5/5 Adds AdalineTracer wrapper class with helper methods. Clean implementation with proper error handling in trace() method.
core/gateway/src/plugins/telemetry/index.ts 5/5 Exports new Adaline Trace classes. Simple, correct addition.
README.md 5/5 Adds comprehensive documentation for Adaline Trace integration. Includes setup, usage examples, configuration, and troubleshooting.

Sequence Diagram

sequenceDiagram
    participant User
    participant AdalineTracer
    participant Gateway
    participant NodeTracerProvider
    participant BatchSpanProcessor
    participant AdalineTraceExporter
    participant AdalineAPI as Adaline Trace API

    User->>AdalineTracer: new AdalineTracer(options)
    AdalineTracer->>AdalineTraceExporter: new AdalineTraceExporter(options)
    AdalineTracer->>NodeTracerProvider: new NodeTracerProvider(resource)
    AdalineTracer->>BatchSpanProcessor: new BatchSpanProcessor(exporter)
    AdalineTracer->>NodeTracerProvider: addSpanProcessor(processor)
    AdalineTracer->>NodeTracerProvider: getTracer('adaline-gateway')
    NodeTracerProvider-->>AdalineTracer: tracer

    User->>Gateway: new Gateway({ telemetry: { tracer } })
    Gateway->>Gateway: TelemetryManager.setTracer(tracer)

    User->>Gateway: completeChat(request)
    Gateway->>Gateway: tracer.startActiveSpan('complete-chat')
    Gateway->>Gateway: Execute LLM call
    Gateway->>Gateway: span.end()
    Gateway->>BatchSpanProcessor: Queue span
    
    BatchSpanProcessor->>AdalineTraceExporter: export(spans)
    AdalineTraceExporter->>AdalineTraceExporter: groupSpansByTrace(spans)
    AdalineTraceExporter->>AdalineTraceExporter: sendTrace(traceId, spans)
    AdalineTraceExporter->>AdalineTraceExporter: convertSpan(span)
    AdalineTraceExporter->>AdalineAPI: POST /v2/api/logs/trace
    AdalineAPI-->>AdalineTraceExporter: 200 OK
    AdalineTraceExporter-->>BatchSpanProcessor: ExportResultCode.SUCCESS
    
    User->>AdalineTracer: shutdown()
    AdalineTracer->>NodeTracerProvider: shutdown()
    NodeTracerProvider->>BatchSpanProcessor: shutdown()
    BatchSpanProcessor->>AdalineTraceExporter: forceFlush()
Loading

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment on lines +164 to +171
const response = await fetch(this.endpoint, {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(trace),
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: timeout option is not applied to the fetch call

Suggested change
const response = await fetch(this.endpoint, {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(trace),
});
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
try {
const response = await fetch(this.endpoint, {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(trace),
signal: controller.signal,
});
clearTimeout(timeoutId);
Prompt To Fix With AI
This is a comment left during a code review.
Path: core/gateway/src/plugins/telemetry/adaline-trace.exporter.ts
Line: 164:171

Comment:
**logic:** `timeout` option is not applied to the fetch call

```suggestion
    const controller = new AbortController();
    const timeoutId = setTimeout(() => controller.abort(), this.timeout);
    
    try {
      const response = await fetch(this.endpoint, {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${this.apiKey}`,
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(trace),
        signal: controller.signal,
      });
      clearTimeout(timeoutId);
```

How can I resolve this? If you propose a fix, please make it concise.

@jckw
Copy link
Author

jckw commented Nov 20, 2025

A question for this is how we should generally handle the 1MB limit with Adaline trace.

I've ran into this issue before.

@AyushR1
Copy link
Contributor

AyushR1 commented Nov 24, 2025

is this tested? The package doesnt builds with this changes for me!
Can you please check @jckw !

related logs
@adaline/gateway:build: CJS Build start @adaline/gateway:build: ESM Build start @adaline/gateway:build: ✘ [ERROR] No matching export in "../../node_modules/@opentelemetry/sdk-trace-base/build/esm/index.js" for import "ExportResultCode" @adaline/gateway:build: @adaline/gateway:build: src/plugins/telemetry/adaline-trace.exporter.ts:5:2: @adaline/gateway:build: 5 │ ExportResultCode, @adaline/gateway:build: ╵ ~~~~~~~~~~~~~~~~ @adaline/gateway:build: @adaline/gateway:build: ✘ [ERROR] No matching export in "../../node_modules/@opentelemetry/sdk-trace-base/build/esm/index.js" for import "ExportResultCode" @adaline/gateway:build: @adaline/gateway:build: src/plugins/telemetry/adaline-trace.exporter.ts:5:2: @adaline/gateway:build: 5 │ ExportResultCode, @adaline/gateway:build: ╵ ~~~~~~~~~~~~~~~~ @adaline/gateway:build: @adaline/gateway:build: ESM Build failed @adaline/gateway:build: Error: Build failed with 1 error: @adaline/gateway:build: src/plugins/telemetry/adaline-trace.exporter.ts:5:2: ERROR: No matching export in "../../node_modules/@opentelemetry/sdk-trace-base/build/esm/index.js" for import "ExportResultCode" @adaline/gateway:build: at failureErrorWithLog (/Users/ayushr1/Desktop/Work/gateway/node_modules/esbuild/lib/main.js:1476:15)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants