Skip to main content

Best Practices for Integrating Netra

Follow these proven patterns to get the most out of Netra’s observability, evaluation, and simulation capabilities — from first setup through production at scale.
Getting Netra running takes minutes. Getting it running well takes intention. This guide distills the patterns that high-performing teams follow when integrating Netra into production AI systems.

Initialization

Initialize Early, Initialize Once

Netra.init() must be the first thing your application does — before importing or using any LLM provider, framework, or vector database client. Netra patches supported libraries at initialization time; if a library is imported first, its calls won’t be captured.
Never call Netra.init() more than once. Multiple initializations can lead to duplicate spans and unexpected behavior.

Always Shut Down Gracefully

Netra batches spans before exporting. If your application exits without calling shutdown(), pending spans may be lost — especially in short-lived processes like serverless functions, scripts, or CLI tools.
For long-running servers (FastAPI, Express, NestJS), hook shutdown() into your framework’s graceful shutdown lifecycle — e.g., @app.on_event("shutdown") in FastAPI or process.on("SIGTERM") in Node.js.

Use Environment Variables for Credentials

Avoid hardcoding API keys in source code. Use environment variables and let the SDK resolve them automatically:
The SDK picks up NETRA_API_KEY and NETRA_OTLP_ENDPOINT automatically, keeping credentials out of your codebase.

Instrumentation Strategy

Follow the Three-Layer Approach

Adopt instrumentation incrementally. Each layer adds visibility without requiring you to rewrite existing code:
1

Start with auto-instrumentation

Enable Netra with default instruments. Every supported LLM call, vector DB query, and framework operation is captured automatically.
2

Add decorators for business context

Annotate your key functions with @workflow, @agent, and @task decorators to create meaningful span hierarchies that map to your application’s domain logic.
3

Use manual spans for edge cases

Add manual spans only where you need custom boundaries, metadata, or lifecycle control that decorators don’t cover.

Be Selective with Instruments

Don’t instrument everything. Noisy traces from HTTP clients, health checks, or internal utilities obscure the signals that matter.
The blockedSpans parameter supports wildcards — "internal.*" blocks all spans starting with internal., and "*.debug" blocks spans ending with .debug.

Context Tracking

Always Set User, Session, and Tenant Context

Context attributes are the foundation of effective filtering, grouping, and analytics in the Netra dashboard. Set them as early as possible in your request lifecycle.

Always Set Root Input and Output

Root input and output are the most important attributes on a trace. They let you see what went in and what came out at a glance — without expanding span trees.

Streaming Responses

For streaming outputs, accumulate chunks and set root output after iteration completes:
Rule of thumb: Use set_root_output_stream (Python) when you can wrap the raw LLM iterable before consuming it. Use manual accumulation + set_root_output / setRootOutput when the handler transforms or formats chunks before sending (SSE, WebSocket frames, custom protocols).

Decorator Best Practices

Map Decorators to Your Domain

Use decorators to create a span hierarchy that mirrors your application’s architecture:
TypeScript users: Decorators require "experimentalDecorators": true in your tsconfig.json.

Manual Span Best Practices

Always End Spans

In TypeScript, manual spans must be ended explicitly. Use try/finally to guarantee cleanup, or prefer startActiveSpan() for automatic lifecycle management.

Environment Configuration

Use Separate Environments

Tag traces by environment to keep production data clean and make it easy to filter in the dashboard:

Add Resource Attributes for Rich Metadata

Attach deployment metadata to every span using resource_attributes / resourceAttributes:

Privacy and Security

Control Content Capture

In production, you may want to disable prompt and response content capture for privacy compliance:
When trace_content is False, prompts and completions are not sent to Netra. You’ll still get latency, token usage, cost, and span structure — but you won’t be able to debug specific prompt/response pairs.

Enable PII Scrubbing (Python)

For applications handling sensitive data, enable automatic PII detection and redaction:
PII scrubbing adds processing overhead. Only enable it when your application handles sensitive user data. Currently available in the Python SDK only.

Common Pitfalls

Avoid these frequently encountered mistakes when integrating Netra:
Problem: LLM calls are not appearing in traces.Cause: Netra.init() was called after importing the provider library. Netra patches libraries at init time — if they’re already imported, the patches don’t apply.Fix: Move Netra.init() to the very top of your entrypoint, before any provider imports.
Problem: Some or all spans are missing.Cause: Netra.init() in TypeScript is async. Without await, instrumentation may not be ready when LLM calls are made.Fix: Always await Netra.init({ ... }).
Problem: Traces appear in the dashboard but show no input/output at the top level.Cause: set_root_input / set_root_output were never called.Fix: Call them at the entry and exit points of your top-level workflow. This is the single most impactful practice for trace readability.
Problem: Traces from scripts, CLI tools, or serverless functions never appear.Cause: The process exits before batched spans are exported.Fix: Call Netra.shutdown() (or await Netra.shutdown() in TypeScript) before the process exits.
Problem: Init call fails or parameters are silently ignored.Cause: Using snake_case in TypeScript (app_name) or camelCase in Python (appName).Fix: Python uses snake_case (app_name, trace_content, set_user_id). TypeScript uses camelCase (appName, traceContent, setUserId). Never mix them.
Problem: Spans appear as infinitely long or never close.Cause: span.end() was not called — typically because it wasn’t in a finally block.Fix: Always call span.end() in a finally block, or use Netra.startActiveSpan() for automatic lifecycle management.

Integration Checklist

Use this checklist to verify your Netra integration is production-ready:
1

SDK installed and up to date

Run pip install --upgrade netra-sdk or npm update netra-sdk to ensure you have the latest version.
2

Environment variables configured

NETRA_API_KEY and NETRA_OTLP_ENDPOINT are set and point to the correct data region.
3

Init called first

Netra.init() is the first SDK call in your entrypoint — before any provider imports or LLM usage.
4

Context is set per request

userId, sessionId, and tenantId are set at the start of each request for proper grouping.
5

Root input and output captured

set_root_input is called at the entry point, and set_root_output (or the streaming equivalent) is called before returning.
6

Environment tag is set

The environment parameter distinguishes development, staging, and production traces.
7

Noisy instruments filtered

blocked_spans and block_instruments exclude health checks, internal HTTP, and other non-AI noise.
8

Shutdown is called on exit

Netra.shutdown() is hooked into your application’s graceful shutdown lifecycle.

What’s Next?

Auto Instrumentation

See all supported libraries and frameworks

Decorators

Add semantic context with @workflow, @agent, @task

Manual Tracing

Create custom spans for fine-grained control

Evaluations

Measure and track AI quality with automated test suites

Simulations

Test agents with realistic multi-turn conversations

Alert Rules

Get notified about cost spikes and performance regressions
Last modified on September 7, 2026