SDKs
JS/TS SDK
TypeScript SDK - Instrumentation
8 min
to instrument your application to send traces to abv, you can use typescript sdk instrumentation docid\ mncioxz2ar176rewhcuzp methods for fine grained control context manager startactiveobservation wrapper observe manual startobservation these components are interoperable please refer to this api route handler, which powers interactive abv demo docid\ yns1sgwawnviosbzzsoxt , as an example of how to combine the auto instrumentation of the ai sdk v5 with custom instrumentation this approach captures more details and groups multiple llm calls into a single trace instrumentation you can add custom instrumentations to your application via the observe wrapper startactiveobservation context managers manually managing the observation lifecycle and its nesting with the startobservation function for an end to end example, see the cookbook abv js/ts sdk docid\ oz7ihyirza93rkj0uo7sx context management with callbacks to simplify nesting and context management, you can use startactiveobservation these functions take a callback and automatically manage the observation's lifecycle and the opentelemetry context any observation created inside the callback will automatically be nested under the active observation, and the observation will be ended when the callback finishes this is the recommended approach for most use cases as it prevents context leakage and ensures observations are properly ended import { startactiveobservation, startobservation } from "@abvdev/tracing"; await startactiveobservation( // name "user request", // callback async (span) => { span update({ input { query "what is the capital of france?" }, }); // example child, could also use startactiveobservation // this manually created generation (see docs below) will automatically be a child of "user request" const generation = startobservation( "llm call", { model "gpt 4", input \[{ role "user", content "what is the capital of france?" }], }, { astype "generation" } ); generation update({ usagedetails { input 10, output 5 }, output { content "the capital of france is paris " }, }); generation end(); span update({ output "successfully answered " }); } ); observe wrapper the observe wrapper is a powerful tool for tracing existing functions without modifying their internal logic it acts as a decorator that automatically creates a span or generation around the function call you can use the updateactiveobservation function to add attributes to the observation from within the wrapped function import { observe, updateactiveobservation } from "@abvdev/tracing"; // an existing function async function fetchdata(source string) { updateactiveobservation({ metadata { source "api" } }); // logic to fetch data return { data `some data from ${source}` }; } // wrap the function to trace it const tracedfetchdata = observe( // method fetchdata, // options, optional, see below {} ); // now, every time you call tracedfetchdata, a span is created // its input and output are automatically populated with the // function's arguments and return value const result = await tracedfetchdata("api"); you can configure the observe wrapper by passing an options object as the second argument option description default name the name of the observation the original function's name astype the type of observation to create (e g span , generation ) "span" captureinput whether to capture the function's arguments as the input of the observation true captureoutput whether to capture the function's return value or thrown error as the output of the observation true manual observations the core tracing function ( startobservation ) gives you full control over creating observations you can pass the astype option to specify the type of observation to create when you call one of these functions, the new observation is automatically linked as a child of the currently active operation in the opentelemetry context however, it does not make this new observation the active one this means any further operations you trace will still be linked to the original parent, not the one you just created to create nested observations manually, use the methods on the returned object (e g , parentspan startobservation( ) ) import { startobservation } from "@abvdev/tracing"; // start a root span for a user request const span = startobservation( // name "user request", // params { input { query "what is the capital of france?" }, } ); // create a nested span for a e g tool call const toolcall = span startobservation( // name "fetch weather", // params { input { city "paris" }, }, // specify observation type in astype // this will type the attributes argument accordingly // default is 'span' { astype "tool" } ); // simulate work and end the tool call span await new promise((resolve) => settimeout(resolve, 100)); toolcall update({ output { temperature "15°c" } }) end(); // create a nested generation for the llm call const generation = span startobservation( "llm call", { model "gpt 4", input \[{ role "user", content "what is the capital of france?" }], }, { astype "generation" } ); generation update({ usagedetails { input 10, output 5 }, output { content "the capital of france is paris " }, }); generation end(); // end the root span span update({ output "successfully answered user request " }) end(); updating traces often, you might not have all the information about a trace (like a userid or sessionid ) when you start it the sdk lets you add or update trace level attributes at any point during its execution updatetrace() on an observation when you create an observation manually with startobservation , the returned object has an updatetrace() method you can call this at any time before the root span ends to apply attributes to the entire trace import { startobservation } from "@abvdev/tracing"; // start a trace without knowing the user yet const rootspan = startobservation("data processing"); // some initial steps // later, once the user is authenticated, update the trace const userid = "user 123"; const sessionid = "session abc"; rootspan updatetrace({ userid userid, sessionid sessionid, tags \["authenticated user"], metadata { plan "premium" }, }); // continue with the rest of the trace const generation = rootspan startobservation( "llm call", {}, { astype "generation" } ); generation end(); rootspan end(); updateactivetrace() when you're inside a callback from startactiveobservation , or a function wrapped with observe , you might not have a direct reference to an observation object in these cases, use the updateactivetrace() function it automatically finds the currently active trace in the context and applies the new attributes import { startactiveobservation, updateactivetrace } from "@abvdev/tracing"; await startactiveobservation("user request", async (span) => { // initial part of the request span update({ input { path "/api/process" } }); // simulate fetching user data await new promise((resolve) => settimeout(resolve, 50)); const user = { id "user 5678", name "jane doe" }; // update the active trace with the user's information updateactivetrace({ userid user id, metadata { username user name }, }); // continue logic span update({ output { status "success" } }) end(); });