Odigos will automatically instrument your services and record semantic spans from popular modules. Many users find the automatic instrumentation data sufficient for their needs.

However, if there is anything specific to your application that you want to record, you can enrich the data by adding custom spans to your code.

This is sometimes referred to as manual instrumentation.

Use Cases

Examples of custom spans you might want to add to your code include:

  • Spans for the execution of some potentially heavy or slow computation in you service.
  • Tracing for internal or third party libraries for which you don’t have automatic or integrated instrumentation.
  • Spans to describe some logical operations in your business logic that are meaningful in your domain.

Required Dependencies

Add the following npm packages to your service by running:

npm install @opentelemetry/api@1.9.0

Odigos agent implements OpenTelemetry API version 1.9.0. Any version greater than 1.9.0 may not be compatible with Odigos agent and fail to produce data.

Please do not use caret range @opentelemetry/api@^1.9.0 for this dependency in your package.json to avoid pulling in incompatible version.

Creating Spans

To enhance your traces with spans for your custom business logic operations, you need to create a span in your code and wrap the operation you want to observe.

The tracer object is the entry point for the OpenTelemetry API.

You can create a tracer object using the getTracer method from the @opentelemetry/api package.

const opentelemetry = require('@opentelemetry/api');

const tracer = opentelemetry.trace.getTracer(
   'instrumentation-scope-name',
   'instrumentation-scope-version',
);

function myFunction() {
   const span = tracer.startSpan('myFunction');
   // Your code here
   span.end();
}

Make sure to replace instrumentation-scope-name and instrumentation-scope-version with the name and version of your instrumented file.

Important Notes:

  1. Always End a span: Ensure that every span is ended to appear in your trace. Defer the End method of the span to guarantee that the span is always ended, even with multiple return paths in the function.
  2. Propagate and use a valid context object: When calling tracer.Start, use a valid context object instead of context.Background(). This makes the new span a child of the active span, ensuring it appears correctly in the trace.
  3. Pass the context object downstream: When calling downstream functions, pass the context object returned from tracer.Start() to ensure any spans created within these functions are children of the current span. This maintains the hierarchical relationship between spans and provides a clear trace of the request flow.
  4. Assign meaningful names to spans: Use descriptive names for spans, (such as the function name) to clearly describe the operations they represent. This helps anyone examining the trace to easily understand the span’s purpose and context.
  5. Avoid dynamic, high cardinality data in span names: Do not include dynamic data such as IDs in the span name, as this can cause performance issues and make the trace harder to read. Instead, use static, descriptive names for spans and record dynamic information in span attributes. This ensures better performance and readability of the trace.

Additional Information

For more use cases, see the OpenTelemetry JavaScript API documentation.