Skip to content
Docs

    Languages and SDKs

    8 min read · Updated View as Markdown

    Tracix works with the upstream OpenTelemetry agents and SDKs: there is no Tracix SDK or wrapper to install. You point a standard SDK at your workspace, and the Setup page writes the exact commands for your platform, language and service.

    The eight characters that end your workspace's address: in acme-prod-a7k3p2q9.app.tracix.io it is a7k3p2q9. Paste the address to fill it in. Every command on this page uses it.

    Use the Setup page

    In your workspace, open Applications › APM & Traces, then the Setup tab, and answer its questions:

    1. Where does the service run? Host or VM, Docker, Kubernetes or AWS Lambda.
    2. Language. Java, Kotlin, .NET, Node.js, Python, Go, Ruby, PHP, C++, Rust, Swift, Erlang/Elixir, or Other for any SDK that reads the standard OTEL_* variables.
    3. How to instrument. The recommended method is marked Recommended. Methods that can't serve your language stay listed with the reason.
    4. Enter the Service name, an optional Service group and, on Kubernetes, the Cluster name, and pick an Ingest key.

    The commands update as you go, with your endpoint filled in. Ingest keys are shown only once, when you create them: a key you create on the page is filled into the commands until you leave or reload it, and otherwise the commands show YOUR_INGEST_KEY for you to replace with the key you saved. The Verify card beside them shows when the first traces, runtime metrics and logs arrive. If you have no ingest key yet, create one first: see OTLP endpoint and ingest keys.

    Choose a method

    Where the service runsMethods
    Host or VM, DockerYour language's OpenTelemetry agent or SDK in the process (recommended), or zero-code eBPF tracing through the Tracix Collector
    KubernetesThe OpenTelemetry Operator, the SDK built into the image, or zero-code eBPF tracing
    AWS LambdaThe OpenTelemetry Lambda layer for Java, Kotlin, Node.js, Python and Ruby; a handler wrapper or the SDK in your init code for the others

    An agent or SDK inside the process gives you full distributed traces, runtime metrics and logs. eBPF tracing needs no code, image or restart change, but runs on Linux only and doesn't link requests across services by default.

    On Kubernetes, the Operator is recommended for Java, Kotlin, .NET, Node.js and Python. For Go, building the SDK into the image is recommended, because the Operator injects Go as an eBPF sidecar that sends traces only. The Operator can't inject Ruby, PHP, C++, Rust, Swift or Erlang/Elixir, so build the SDK into the image for those.

    What each language collects

    What the Setup page installs, and what you change in your code:

    LanguageWhat Setup installsCode changesRuntime metrics
    Java, KotlinOpenTelemetry Java agentNoneJVM heap, GC, threads, classes and CPU
    .NET.NET automatic instrumentationNoneGC, thread pool, lock contention, exceptions
    Node.jsNode.js auto-instrumentationNoneEvent loop, V8 heap and GC
    PythonPython auto-instrumentationNoneGC, CPU, memory and threads
    GoOpenTelemetry Go SDKA setup function, and wrappers for handlersGoroutines, memory, GC and scheduler latency
    RubyOpenTelemetry Ruby SDKA Gemfile entry and an initializerNot reported yet
    PHPPHP auto-instrumentationA PHP extension and Composer packagesNot reported
    C++OpenTelemetry C++ SDKSpans in your codeNot reported
    RustOpenTelemetry Rust SDKSetup and spans in your codeNot reported
    Swift (server)swift-otelA package and a few lines at startupNot reported
    Erlang/ElixirOpenTelemetry Erlang/Elixir SDKDependencies and a setup callNot reported

    What gets traced, and which logs are sent:

    LanguageTracesLogs
    Java, KotlinSpring, Servlet, JAX-RS, gRPC, JDBC, Kafka, JMS and many more; Ktor for KotlinLogback, Log4j and java.util.logging, with trace IDs
    .NETASP.NET Core, HttpClient, gRPC, SqlClient, Entity Framework CoreILogger, with trace IDs
    Node.jsExpress, Fastify, NestJS, Koa, GraphQL, HTTP, databases and queuesPino and Winston, with trace IDs
    PythonDjango, Flask, FastAPI, requests, httpx, SQLAlchemy, CeleryStandard-library logging, with trace IDs
    Gonet/http, gRPC and database/sql through the contrib wrappersslog, Zap and Logrus, through the OpenTelemetry bridges
    RubyRails, Sinatra, Rack, ActiveRecord, Faraday, RedisStructured stdout, collected by the Tracix Collector
    PHPLaravel, Symfony, Slim, PDO, Guzzle, PSR-18 clientsMonolog, with trace IDs
    C++Spans from the C++ APIAdd a logger provider yourself
    RustSpans from the OpenTelemetry API and the tracing cratetracing events, with trace IDs
    Swift (server)Hummingbird requests and swift-distributed-tracing spansswift-log, with trace IDs
    Erlang/ElixirPhoenix, Bandit, Cowboy, Ecto, Oban, Finch, ReqNot exported yet

    The Ruby, Rust and Erlang/Elixir SDKs mark parts of their own support as experimental or beta upstream. Data from every method lands on the same pages: Services, Traces and each service's Runtime tab.

    Example: run a service on a host

    Install the agent, set the exporter variables and start the service:

    bash
    npm install --save @opentelemetry/api @opentelemetry/auto-instrumentations-node
    
    export OTEL_SERVICE_NAME="checkout-api"
    export OTEL_RESOURCE_ATTRIBUTES="service.version=1.0.0,deployment.environment.name=production"
    export OTEL_EXPORTER_OTLP_ENDPOINT="https://otlp-http-<workspace>.app.tracix.io"
    export OTEL_EXPORTER_OTLP_HEADERS="x-tracix-ingest-key=<ingest key>"
    export OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf"
    export OTEL_TRACES_EXPORTER="otlp"
    export OTEL_METRICS_EXPORTER="otlp"
    export OTEL_LOGS_EXPORTER="otlp"
    export NODE_OPTIONS="--require @opentelemetry/auto-instrumentations-node/register"
    
    node app.js

    For the other languages, the Setup page shows the same steps with your endpoint and key filled in.

    Docker

    On Docker, the Setup page gives you a Dockerfile that builds the agent or SDK into the image, and a docker run command. The endpoint and ingest key are passed at run time, so they never end up in the image:

    bash
    docker run -d --name checkout-api \
    -e OTEL_EXPORTER_OTLP_ENDPOINT="https://otlp-http-<workspace>.app.tracix.io" \
    -e OTEL_EXPORTER_OTLP_HEADERS="x-tracix-ingest-key=<ingest key>" \
    checkout-api:latest

    Kubernetes with the OpenTelemetry Operator

    The OpenTelemetry Operator injects the agent into pods as they start, so you don't change your images. It is upstream software you run in your cluster; Tracix only gives it the endpoint and key.

    1. Install the Operator

      Once per cluster, install it with Helm. Its admission webhook needs cert-manager, or the chart's self-generated certificate. Skip this if the Operator already runs in the cluster.

      bash
      helm repo add open-telemetry https://open-telemetry.github.io/opentelemetry-helm-charts
      helm repo update open-telemetry
      helm install opentelemetry-operator open-telemetry/opentelemetry-operator \
      --namespace opentelemetry-operator-system --create-namespace \
      --set manager.collectorImage.repository=ghcr.io/open-telemetry/opentelemetry-collector-releases/opentelemetry-collector-k8s
    2. Store the ingest key in the application's namespace

      bash
      kubectl create secret generic tracix-apm -n <app-namespace> \
      --from-literal=otlp-headers="x-tracix-ingest-key=<ingest key>"
    3. Create the Instrumentation resource

      The Setup page writes a tracix-apm.yaml with an Instrumentation named tracix-apm. It sends traces, metrics and logs over OTLP/HTTP to your workspace, reads the header from the secret, and sets deployment.environment.name and k8s.cluster.name. Apply it in the application's namespace with kubectl apply -n <app-namespace> -f tracix-apm.yaml.

    4. Opt workloads in

      Annotate the namespace, or one Deployment's pod template, for your language, then restart its pods:

      bash
      kubectl annotate namespace <app-namespace> \
      instrumentation.opentelemetry.io/inject-java=tracix-apm
      kubectl rollout restart deployment -n <app-namespace>

      Use inject-dotnet, inject-nodejs or inject-python for those languages. Alpine-based Python and .NET images need an extra pod annotation, which the Setup page shows.

    Services are named after their Deployment, StatefulSet or DaemonSet. To name one differently, set the resource.opentelemetry.io/service.name annotation on its pod template.

    The Setup page can also give you OpenTelemetry Collectors for the Operator to run, which collect container logs, kubelet metrics and cluster events with the same ingest key. To collect those with the Tracix Collector instead, install it with Helm on a policy with the Kubernetes integration.

    AWS Lambda

    For Java, Kotlin, Node.js, Python and Ruby, add the OpenTelemetry Lambda layer for your runtime and set the function's environment:

    VariableValue
    AWS_LAMBDA_EXEC_WRAPPER/opt/otel-instrument for Python; /opt/otel-handler for the others
    OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_HEADERS, OTEL_EXPORTER_OTLP_PROTOCOLAs on a host

    The OpenTelemetry Lambda project publishes the layer ARNs for each region. For .NET and Go, the Setup page shows the handler wrapper to add; for the other languages, set the SDK up in the function's init code and flush it before each invocation returns. The layer adds some cold-start time.

    Environment variables

    Every in-process setup on the Setup page sets these:

    VariableValue
    OTEL_SERVICE_NAMEThe service's name
    OTEL_RESOURCE_ATTRIBUTESdeployment.environment.name, service.version and, optionally, tracix.service_group.name
    OTEL_EXPORTER_OTLP_ENDPOINThttps://otlp-http-<workspace>.app.tracix.io
    OTEL_EXPORTER_OTLP_HEADERSx-tracix-ingest-key=<ingest key>
    OTEL_EXPORTER_OTLP_PROTOCOLhttp/protobuf
    OTEL_TRACES_EXPORTER, OTEL_METRICS_EXPORTER, OTEL_LOGS_EXPORTERotlp, for the SDKs that read them

    service.version=1.0.0 in the generated commands is a placeholder: set it to the version you release. tracix.service_group.name puts the service in a service group; the key's default group applies when you leave it out.

    Next steps