Instrument
Record LLM calls
Capture model, token, latency, error, and cost data and attach it to the customer who caused it.
Anectico represents an LLM call as a trace span using OpenTelemetry gen_ai.* attributes. When customer
identity is active, the call and its cost appear in the same customer story as errors and application
activity.
Use an SDK wrapper
The JavaScript wrapper covers non-streaming OpenAI and Anthropic calls. The Go wrapper covers OpenAI unary and Chat Completion streams plus non-streaming Anthropic calls. Python covers non-streaming OpenAI/Anthropic calls and OpenAI Chat Completion streams.
JavaScript / TypeScript
import OpenAI from 'openai';
import { wrapOpenAI } from '@anectico/sdk/openai';
const openai = wrapOpenAI(new OpenAI(), anectico);
const response = await openai.chat.completions.create({
model: process.env.OPENAI_MODEL!,
messages,
});
Python
import os
from openai import OpenAI
from anectico.integrations.openai import wrap_openai
openai = wrap_openai(OpenAI(), client)
response = openai.chat.completions.create(
model=os.environ['OPENAI_MODEL'],
messages=messages,
)
For Python streaming, request the final usage chunk and consume the iterator:
stream = openai.chat.completions.create(
model=os.environ['OPENAI_MODEL'],
messages=messages,
stream=True,
stream_options={"include_usage": True},
)
for chunk in stream:
consume(chunk)
Go
import (
"github.com/openai/openai-go"
"github.com/openai/openai-go/option"
anecticoopenai "github.com/anectico/anectico/sdks/go/instrumentation/openai"
)
real := openai.NewClient(option.WithAPIKey(os.Getenv("OPENAI_API_KEY")))
openaiClient := anecticoopenai.WrapClient(anecticoClient, &real)
response, err := openaiClient.Chat.Completions.New(
ctx,
openai.ChatCompletionNewParams{
Model: os.Getenv("OPENAI_MODEL"),
Messages: messages,
},
)
stream := openaiClient.Chat.Completions.NewStreaming(
ctx,
openai.ChatCompletionNewParams{
Model: os.Getenv("OPENAI_MODEL"),
Messages: messages,
},
)
defer stream.Close()
for stream.Next() {
consume(stream.Current())
}
if err := stream.Err(); err != nil {
return err
}
Call identify or establish request-scoped identity before the model request.
Use existing OpenTelemetry instrumentation
Anectico reads standard gen_ai span attributes from any OTLP source. At minimum, record the provider,
model, input tokens, output tokens, duration, and error status. Anectico can calculate cost for recognized
models when token counts are present.
Prompt and completion content
Content capture is off by default. Leave it off unless the debugging value outweighs the privacy and security cost. If you enable it, review retention, user consent, PII handling, and access controls before production rollout.
The Python and Go OpenAI wrappers record one call as a stream reaches its terminal usage chunk or exhaustion. Closing early records an error-status call; without the final usage chunk, latency and status remain useful but token/cost fields are unavailable. JavaScript and Anthropic streaming calls currently pass through; add an explicit span when those streams need model-call telemetry.
Verify
Open Explore → Traces and select LLM Costs, then open the customer who made the request. The same call should appear in both views with matching model, token, and cost values.