Ruby performance integration guide

Step-by-step instructions for adding performance monitoring and distributed tracing to your Ruby projects.

BugSnag’s serverside performance monitoring leverages OpenTelemetry. With the wealth of open source OpenTelemetry instrumentation available for Ruby, you can easily send spans and traces from your service to BugSnag by installing the OpenTelemetry SDK and completing some simple configuration.

OpenTelemetry SDK installation

First install the core SDK gem, along with the instrumentation gem and the OTLP exporter:

bundle add opentelemetry-sdk opentelemetry-instrumentation-all opentelemetry-exporter-otlp

To send the generated spans to your BugSnag dashboard you need to install and configure an Exporter. A BugSnag plugin is provided to make this as straightforward as possible and allows you to use our managed sampling functionality. Alternatively, if you have more advanced requirements, you can configure the built-in HTTP or gRPC exporters directly – see OpenTelemetry SDK configuration.

BugSnag plugin configuration

The bugsnag_performance gem is a plugin for the OpenTelemetry SDK to make it simple to send your spans to your BugSnag dashboard:

bundle install bugsnag_performance

The latest available version of bugsnag-ruby-performance is v1.0.0.

Then configure the OpenTelemetry SDK through BugSnag Performance as early as possible in your application:

require "bugsnag_performance"
require "opentelemetry/instrumentation/all"

BugsnagPerformance.configure do |configuration|
  configuration.api_key = "YOUR_API_KEY_HERE"

  # configure the Open Telemetry SDK using the 'configure_open_telemetry' block
  # this should replace the existing call to 'OpenTelemetry.configure' if you
  # are already using the Open Telemetry SDK
  configuration.configure_open_telemetry do |open_telemetry_configurator|
    open_telemetry_configurator.use_all
  end
end

Most configuration options can also be set as environment variables. The bugsnag_performance library shares these variable names with the BugSnag Error Monitoring library.

We also recommend you set OTEL_SERVICE_NAME to the same name as your BugSnag project name to identify spans on the dashboard if Distributed Tracing is used.

For details on the configuration options available for the BugSnag plugin, please see our Plugin configuration options page.

Running your app and requesting a page should now result in spans arriving in BugSnag Performance.

OpenTelemetry SDK configuration

This guide provides a basic example of how to get traces sent to BugSnag and discusses some of the ways it can be configured. For more detailed instructions and advanced use cases, please see the OpenTelemetry documentation for Ruby.

Add the SDK initialization code as early as possible in your app’s startup. In Rails this would be in a Rails initializer.

require 'opentelemetry/sdk'
require 'opentelemetry/instrumentation/all'

OpenTelemetry::SDK.configure do |c|
  c.use_all() # enables all instrumentation!
end

Next you need to set some configuration:

export OTEL_EXPORTER_OTLP_ENDPOINT=https://<PROJECT_API_KEY>.otlp.bugsnag.com:4318
export OTEL_TRACES_EXPORTER=otlp,console
export OTEL_SERVICE_NAME="your-service-name" 
export OTEL_RESOURCE_ATTRIBUTES="deployment.environment=<RELEASE_STAGE>,service.version=<APP_VERSION>" 
  • <PROJECT_API_KEY> can be found in project settings in the BugSnag dashboard.
  • OTEL_SERVICE_NAME should uniquely identify your service. We recommend using the same name as your project name.
  • <RELEASE_STAGE> and <APP_VERSION> must be the same as you are passing to your BugSnag Error SDK. They are case sensitive.

Traces can be received by BugSnag via either gRPC or HTTP (protobuf or JSON). In most cases the simplest way to send traces to BugSnag is to export an environment variable with your BugSnag project’s dedicated OpenTelemetry endpoint before running your OpenTelemetry instrumented app:

export OTEL_EXPORTER_OTLP_PROTOCOL="grpc"
export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT="https://<PROJECT_API_KEY>.otlp.bugsnag.com:4317"
export OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf"
export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT="https://<PROJECT_API_KEY>.otlp.bugsnag.com:4318/v1/traces"

Running your app and requesting a page should now result in spans arriving in BugSnag Performance.

If you are using BugSnag On-premise see the OpenTelemetry SDKs Configuration page for more information.

Sampling

If you are using the BugSnag plugin, a BugSnag Sampler is used to spread your managed span quota in your plan over a month with a constantly adjusted probability that a given trace will be sampled.

Unless sent by the BugSnag Sampler, spans use up your unmanaged quota. No spans will be ingested by BugSnag once your daily quota is exhausted. To ensure you have span coverage throughout the day, we recommend you use sampling. This section explains how to control sampling if you are not using the BugSnag Sampler.

By default the OpenTelemetry SDK will use the parentbased_always_on sampler, which will sample according to the sample decision from the incoming network request if there is one, and always sample if there is not. To use this requires clients of your Ruby server be instrumented in such a way that they pass their sampling information.

To apply a fixed sampling rate to all your Ruby spans, you can use the traceidratio sampler:

export OTEL_TRACES_SAMPLER="traceidratio"
export OTEL_TRACES_SAMPLER_ARG="0.25" # 25% of your traces will be sampled

bin/rails server

Alternatively you can use the parentbased_traceidratio sampler. This will sample at a constant rate, unless the trace context was propagated from a client, in which case it will use the same sample decision that the client used:

export OTEL_TRACES_SAMPLER="parentbased_traceidratio"
export OTEL_TRACES_SAMPLER_ARG="0.25" # 25% of traces not started in a client will be sampled

bin/rails server

The BugSnag Performance SDKs for client-side apps can be configured to propagate trace context and sampling decisions to assist with distributed tracing. Read our Distributed Tracing documentation for more information.

Collectors

An OpenTelemetry Collector is an open source component that OpenTelemetry users can host on their own infrastructure. It can receive telemetry data from multiple sources, process it in various ways, and send it on to multiple telemetry back-ends, including BugSnag.

An important use of Collectors is to enable tail-based sampling, where a trace can be inspected in its entirety before making a sampling decision, for example looking to see whether it contained any errors.

To learn about using a collector with BugSnag, see our dedicated page on using a collector.

Span batch size

The maximum payload size for BugSnag’s OpenTelemetry trace endpoints is 1MB. OpenTelemetry payload sizes can be controlled via the batch size in the SDK or collector configuration.

The appropriate batch size will largely depend on the number of attributes getting added to your spans and therefore you may need to experiment to find the appropriate setting. The batch size can be controlled by setting an environment variable; we generally recommend 200 as a good starting point, which is lower than the default of 512 spans per batch.

export OTEL_BSP_MAX_EXPORT_BATCH_SIZE=200

The number of payloads that are rejected for being oversize can be found under Settings > Span usage > Unmanaged.

Custom spans

For higher resolution information into the performance of your application, you can create your own spans whenever you like. To do this, get a tracer:

require 'opentelemetry/sdk'

MyTracer = OpenTelemetry.tracer_provider.tracer('myapp')

Then wrap some work in a span:

MyTracer.in_span('my_operation') do |span|
  puts 'some interesting work'
  # span closes at end of block, timing the operation
end

For more information see the Ruby OpenTelemetry instrumentation documentation.

If you would like BugSnag to aggregate your custom span to provide you with summary statistics on its performance, then you need to set a bugsnag.span.first_class attribute on the span. BugSnag will then automatically create a grouping for that span based on its name. This will appear under the ‘Custom Spans’ tab of your Performance dashboard.

span.set_attribute("bugsnag.span.first_class", true);