OpenTelemetry Beta

The OpenTelemetry beta involves more installation steps than usual. Please ensure you follow all the steps carefully to set it up correctly.

Create a new application

To report data to AppSignal the following three config options are required:

  • Application name: the name of the application as it appears on AppSignal.com.
  • Application environment: the environment of the application as it appears on AppSignal.com.
  • Push API key: The key used to authenticate with the AppSignal Push API.

Before proceeding to the next steps, ensure you have the above required option values to hand.

If you already have an application that uses the same name and environment, reported by one of our existing language integration packages, please use another name and/or environment. This beta introduces new UI elements and pages that are not compatible with the data reported by our integration packages. We recommend reporting the application OpenTelemetry data to a new AppSignal application so the UI will not be so confusing.

Install the AppSignal agent

To report data to AppSignal, we need to install the AppSignal standalone agent. Either the standalone Linux package or Docker image will work.

When configuring the standalone agent, use the configuration options you wrote down before.

appsignal-agent.conf
Docker
appsignal-agent.conf
# /etc/appsignal-agent.conf app_name = "My app name" environment = "production" push_api_key = "0000-0000-0000-000" hostname = "hostname" enable_opentelemetry_http = true
Docker
docker run \ --env APPSIGNAL_APP_NAME="My app name" \ --env APPSIGNAL_APP_ENV=production \ --env APPSIGNAL_PUSH_API_KEY="0000-0000-0000-000" \ --publish "8125:8125" \ --publish "27649:27649" \ --publish "8099:8099" \ appsignal/agent

If multiple applications report to the same AppSignal standalone agent, such as in a Kubernetes cluster, configure each application with a unique name and environment. This ensures that data remains separate and does not get mixed between applications.

Install the OpenTelemetry packages

To install the OpenTelemetry packages in your app follow the OpenTelemetry installation instructions for the language your app uses.

Below are links to OpenTelemetry getting started guides for some popular languages:

  • Ruby, the "Instrumentation" section.
  • Elixir, the "Dependencies" section.
  • Node.js, the "Instrumentation" section.
  • Python, the "Setup" section.
  • Go, the "Add OpenTelemetry Instrumentation" section.
  • Rust, the "Instrumentation" section.
  • PHP, the "Add zero-code instrumentation" or "Add manual instrumentation" section.
  • Java, the "Instrumentation" section.

Also follow any additional steps needed to have OpenTelemetry instrument your application, instrument specific libraries, and setting up a tracer and creating spans where needed.

Below are examples for a couple languages:

Ruby
Elixir
JavaScript
Python
Ruby
# Run Bundler add to add OpenTelemetry packages to your app's bundle bundle add opentelemetry-sdk opentelemetry-exporter-otlp opentelemetry-instrumentation-all
Elixir
# mix.exs def deps do [ # other default deps... {:opentelemetry, "~> 1.3"}, {:opentelemetry_api, "~> 1.2"}, {:opentelemetry_exporter, "~> 1.6"}, # Add any other instrumentation packages for libraries you use {:opentelemetry_phoenix, "~> 1.1"}, {:opentelemetry_cowboy, "~> 0.2"}, {:opentelemetry_ecto, "~> 1.2"} # if using ecto ] end
JavaScript
# Node.js example only npm install @opentelemetry/sdk-node \ @opentelemetry/api \ @opentelemetry/sdk-trace-node \ @opentelemetry/exporter-trace-otlp-http \ @opentelemetry/auto-instrumentations-node
Python
# requirements.txt opentelemetry-api opentelemetry-sdk opentelemetry-exporter-otlp-proto-http # Add any other instrumentation packages for libraries you use # For example: # opentelemetry-instrumentation-aiopg # opentelemetry-instrumentation-asgi # opentelemetry-instrumentation-asyncpg # opentelemetry-instrumentation-celery # opentelemetry-instrumentation-django # opentelemetry-instrumentation-fastapi # opentelemetry-instrumentation-flask # opentelemetry-instrumentation-jinja2 # opentelemetry-instrumentation-mysql # opentelemetry-instrumentation-mysqlclient # opentelemetry-instrumentation-pika # opentelemetry-instrumentation-psycopg # opentelemetry-instrumentation-psycopg2 # opentelemetry-instrumentation-pymysql # opentelemetry-instrumentation-redis # opentelemetry-instrumentation-requests # opentelemetry-instrumentation-sqlalchemy # opentelemetry-instrumentation-sqlite3 # opentelemetry-instrumentation-starlette # opentelemetry-instrumentation-wsgi

Configure OpenTelemetry in your app

Configure OpenTelemetry in your application with the application details you wrote down before: application name, environment and Push API key. We will also configure the service name in OpenTelemetry and set up an HTTP exporter that exports OpenTelemetry tracing data to the AppSignal standalone agent.

This configuration is different than the configuration used by the standalone agent and is not optional. It will fall back on the standalone agent's configuration if no configuration is specified as documented in this step.

Configure the OpenTelemetry Resource with the SDK with the following required attributes:

  • appsignal.config.app_name: The application's name.
  • appsignal.config.app_environment: The application's environment.
  • appsignal.config.push_api_key: The application's Push API key.
  • service.name: The service's name as it should show up on AppSignal.com. See the Customize the service name in OpenTelemetry section for more details.

Additionally, configure the following config options to get a better experience:

  • appsignal.config.revision: Automatically create deploys in AppSignal by specifying the app revision.
  • appsignal.config.language_integration: Set the programming language name to help us recognize what programming language the app data is from so we can optimize the tracing data. Example values: "python", "rust", "ruby", "elixir", "go", "node.js", etc.
  • appsignal.config.app_path: Specify the app's root directory. We'll use this to clean up backtraces and recognize which lines are from the application and which are from other libraries.

See also our configuration options page for a list of all supported config options.

Ruby
Elixir
JavaScript
Python
Ruby
# opentelemetry.rb # Place this in an opentelemetry.rb file and require it in your app require "socket" require "opentelemetry/sdk" require "opentelemetry/instrumentation/all" require "opentelemetry-exporter-otlp" revision = `git rev-parse --short HEAD`.strip OpenTelemetry::SDK.configure do |c| # Add AppSignal and app configuration c.resource = OpenTelemetry::SDK::Resources::Resource.create( "appsignal.config.app_name" => "app name", "appsignal.config.app_environment" => "app environment", "appsignal.config.push_api_key" => "push-api-key", "appsignal.config.revision" => revision, "appsignal.config.language_integration" => "ruby", "appsignal.config.app_path" => Dir.pwd, "appsignal.config.hostname" => Socket.gethostname, ) # Customize the service name c.service_name = "My service name" # Configure the OpenTelemetry HTTP exporter c.add_span_processor( OpenTelemetry::SDK::Trace::Export::BatchSpanProcessor.new( OpenTelemetry::Exporter::OTLP::Exporter.new( :endpoint => "http://localhost:8099/enriched", :protocol => :http_protobuf ) ) ) end
Elixir
# config/config.exs # Add AppSignal and app configuration {:ok, hostname} = :inet.gethostname() {revision, _exitcode} = System.cmd("git", ["log", "--pretty=format:%h", "-n 1"]) config :opentelemetry, span_processor: :batch, traces_exporter: :otlp, resource: [ {"appsignal.config.app_name", "app name"}, {"appsignal.config.app_environment", "app environment"}, {"appsignal.config.push_api_key", "push-api-key"}, {"appsignal.config.revision", revision}, {"appsignal.config.language_integration", "elixir"}, {"appsignal.config.app_path", File.cwd()}, {"appsignal.config.hostname", hostname}, # Customize the service name {"service.name", "Phoenix"} ] # Configure the OpenTelemetry HTTP exporter config :opentelemetry_exporter, otlp_protocol: :http_protobuf, otlp_endpoint: "http://appsignal-agent:8099/enriched"
JavaScript
// opentelemetry.js // Node.js example only // Place this in an opentelemetry.js file and require it in your app const os = require("os"); const childProcess = require("child_process"); const { NodeTracerProvider } = require("@opentelemetry/sdk-trace-node"); const { Resource } = require("@opentelemetry/resources"); const { SemanticResourceAttributes, } = require("@opentelemetry/semantic-conventions"); const { OTLPTraceExporter, } = require("@opentelemetry/exporter-trace-otlp-http"); // Add AppSignal and app configuration const revision = childProcess.execSync("git rev-parse --short HEAD").toString(); const resource = new Resource({ "appsignal.config.app_name": "app name", "appsignal.config.app_environment": "app environment", "appsignal.config.push_api_key": "push-api-key", "appsignal.config.revision": revision, "appsignal.config.language_integration": "node.js", "appsignal.config.app_path": process.cwd(), "appsignal.config.hostname": os.hostname(), // Customize the service name [SemanticResourceAttributes.SERVICE_NAME]: "My service name", }); // Configure the OpenTelemetry HTTP exporter const exporter = new OTLPTraceExporter({ url: "http://localhost:8099/enriched/v1/traces", }); const sdk = new NodeSDK({ resource, traceExporter: exporter, instrumentations: [getNodeAutoInstrumentations()], }); sdk.start();
Python
# opentelemetry.py # Place this in an opentelemetry.py file and require it in your app. # For Django apps, the settings.py file will also work. import os import subprocess import socket from opentelemetry import trace from opentelemetry.sdk.resources import Resource from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import BatchSpanProcessor from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter revision = subprocess.check_output( "git rev-parse --short HEAD", shell=True, text=True ).strip() # Add AppSignal and app configuration resource = Resource(attributes={ "appsignal.config.app_name": "app name", "appsignal.config.app_environment": "app environment", "appsignal.config.push_api_key": "push-api-key", "appsignal.config.revision": revision, "appsignal.config.language_integration": "python", "appsignal.config.app_path": os.getcwd(), "appsignal.config.hostname": socket.gethostname(), # Customize the service name "service.name": "My service name", }) trace.set_tracer_provider(TracerProvider(resource=resource)) # Configure the OpenTelemetry HTTP exporter span_processor = BatchSpanProcessor(OTLPSpanExporter(endpoint="http://localhost:8099/enriched/v1/traces")) trace.get_tracer_provider().add_span_processor(span_processor)

Customize the service name in OpenTelemetry

Choose a service name for your app that makes each component or service easily recognizable. This service name will be used to group namespaces by service.

The resulting namespaces are formatted like so: <service name>/<namespace>

If the service name is "My service name" and the namespace is "admin", the resulting namespace on AppSignal.com becomes: "My service namespace/admin"

The important part of naming is that it makes sense to you and your team.

Some examples of service names:

  • Rails server
  • Sidekiq worker
  • Authentication API
  • Loadbalancer
  • Or whatever internal name each service has in your infrastructure

Below is an example of how to configure it in Ruby. See the previous steps code example for the language your app is using on where to modify the service_name field or service.name attribute.

Ruby
# opentelemetry.rb # ... OpenTelemetry::SDK.configure do |c| # Example: c.service_name = "My service name" # If you have Sidekiq in your app, you may want to configure it like so: c.service_name = if Sidekiq.server? "Sidekiq worker" else "Web server" end # ... end

Customize the exporter

When OpenTelemetry is instrumenting your application, it's necessary to export the data to our standalone agent so that it can then be sent to our API.

In the code examples shown earlier, an OpenTelemetry HTTP traces exporter is already configured to send data to this endpoint on the standalone agent: http://localhost:8099/enriched/v1/traces

Port 8099 is different than OpenTelemetry's default port, so it's required to specify to export data to our standalone agent. We recommend using the standalone agent's default 8099 port, but if this is not possible, the port can be changed with the opentelemetry_port config option. Ensure that you also update the ports definition in the Install the AppSignal agent step for the Docker command if you've chosen to install the standalone agent using the Docker image.

Most OpenTelemetry exporter packages automatically append the /v1/traces part if you specify /enriched as the path, but for some languages (like Python and Node.js) it may be needed to specify the entire path: http://localhost:8099/enriched/v1/traces

If your app is using the standalone agent's Docker container, change localhost to the container's (host) name to send the data to the correct host on the internal network, like http://appsignal-agent:8099/enriched/v1/traces

Test the app!

Now that all the components are connected, start your app and test if you see data arrive in AppSignal. Check the "Errors > Issue list" and "Performance > Traces" page specifically.

If after following our installation instructions you still don't see data in AppSignal, let us know and we'll help you finalize your OpenTelemetry installation!