diff --git a/CHANGELOG.md b/CHANGELOG.md index be6a42d1..ce439b1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,9 +13,9 @@ This release includes the following features: * OTLP trace and metric exporter are the now default exporters for swo backend * NH-103815: Added resource detectors for Kubernetes and UAMS client * Added Lambda instrumentation for 6.1.2 -* Update tag_sql section by @cheempz in https://github.com/solarwinds/apm-ruby/pull/176 -* NH-103804: reverselab scan gem by @xuan-cao-swi in https://github.com/solarwinds/apm-ruby/pull/179 -* Bump DavidAnson/markdownlint-cli2-action from 19 to 20 by @dependabot in https://github.com/solarwinds/apm-ruby/pull/193 +* Update tag_sql section by @cheempz in +* NH-103804: reverselab scan gem by @xuan-cao-swi in +* Bump DavidAnson/markdownlint-cli2-action from 19 to 20 by @dependabot in ## solarwinds_apm 6.1.2 (02/28/2025) diff --git a/CONFIGURATION.md b/CONFIGURATION.md index 66ded776..dc1448f7 100644 --- a/CONFIGURATION.md +++ b/CONFIGURATION.md @@ -1,188 +1,286 @@ -# Configuration +# SolarWinds APM Ruby Configuration Guide -By default all applicable instrumentations are enabled. The only required configuration is the service key, so a minimal example to get started is: +This guide covers all configuration options for the SolarWinds APM Ruby gem, an OpenTelemetry-based distribution that provides automatic instrumentation and observability features for Ruby applications. + +## Quick Start + +To get started quickly, you only need to set your service key: ```bash -export SW_APM_SERVICE_KEY= +export SW_APM_SERVICE_KEY=: +``` + +By default, all applicable instrumentations are enabled and the gem works out-of-the-box with sensible defaults. + +### Minimal Example + +```ruby +# Set the service key (required) +ENV['SW_APM_SERVICE_KEY'] = 'your-api-token:my-ruby-app' + +# Require the gem (typically done automatically by Bundler) +require 'solarwinds_apm' + +# Your application code here ``` -Configuration can be set several ways, with the following precedence: +## Configuration Precedence -`environment variable > programmatic > configuration file > default` +Configuration can be set in multiple ways with the following precedence order (highest to lowest): + +1. **Environment Variables** - Highest priority +2. **Programmatic Configuration** - Set in Ruby code +3. **Configuration Files** - Rails initializer or config file +4. **Default Values** - Built-in defaults ## Environment Variables -Settings specific to `solarwinds_apm` are prefixed by `SW_APM_` and described in the [Reference](#reference) section. Standard OpenTelemetry environment variables that impact this library's functionality are noted below. +Environment variables are the most flexible way to configure the SolarWinds APM gem, especially in containerized or cloud environments. All SolarWinds APM-specific settings are prefixed with `SW_APM_`. Standard [OpenTelemetry environment variables](https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/) are also supported where applicable. + +**Required Configuration** + +| Variable | Description | Example | +|----------|-------------|---------| +| `SW_APM_SERVICE_KEY` | API token and service name (required) | `your-token:my-service` | + +**Common Configuration** + +| Variable | Description | Default | Example | +|----------|-------------|---------|---------| +| `SW_APM_ENABLED` | Enable/disable the entire library | `true` | `false` | +| `SW_APM_DEBUG_LEVEL` | Logging verbosity (-1 to 6) | `3` | `5` | +| `SW_APM_COLLECTOR` | Collector endpoint override | `apm.collector.na-01.cloud.solarwinds.com:443` | `apm.collector.eu-01.cloud.solarwinds.com:443` | -### Exporter +More configuration option see [Configuration Reference](#configuration-reference) -The default `solarwinds` exporter which communicates with the SolarWinds Observability backend is always configured as OTLP Exporter. Additional exporters can be configured via the `OTEL_TRACES_EXPORTER` environment variable. For example, console exporter is part of standard installation and can be enabled via: +### OpenTelemetry Integration + +#### Exporters + +The SolarWinds backend uses the OTLP exporter by default. You can configure additional exporters for debugging or multi-backend scenarios: ```bash -export OTEL_TRACES_EXPORTER=console +export OTEL_TRACES_EXPORTER=console # Console Exporter (for debugging) +export OTEL_TRACES_EXPORTER=otlp,console # Multiple Exporters +export OTEL_TRACES_EXPORTER=jaeger # Third-party Exporters (e.g. jaeger, add gem opentelemetry-exporter-jaeger before solarwinds_apm) ``` -Other exporters (e.g. Jaeger) must first be installed and required before loading `solarwinds_apm`. For example, if dependencies are loaded by `Bundler.require`, add the OTLP exporter to the Gemfile: +#### Service Name -```ruby -# application dependencies, eg -# gem "rails", "~> 7.0.5", ">= 7.0.5.1" +By default the service name portion of the service key is used, e.g. `my-service` if the service key is `SW_APM_SERVICE_KEY=api-token:my-service`. If the `OTEL_SERVICE_NAME` or `OTEL_RESOURCE_ATTRIBUTES` environment variable is used to specify a service name, it will take precedence over the default. The precedence is as follows: -gem 'opentelemetry-exporter-jaeger' +`OTEL_SERVICE_NAME` > `OTEL_RESOURCE_ATTRIBUTES` > `SW_APM_SERVICE_KEY` > `SolarWindsAPM::Config[:service_key]` -# end of Gemfile -gem 'solarwinds_apm' +Service key format: + +```bash +export SW_APM_SERVICE_KEY=: ``` -And set the environment variable: +Override with OpenTelemetry variables: ```bash -export OTEL_TRACES_EXPORTER=jaeger +# Service name will be 'production-api', not 'my-service' +export SW_APM_SERVICE_KEY=:my-service +export OTEL_SERVICE_NAME=production-api ``` -### Service Name - -By default the service name portion of the service key is used, e.g. `my-service` if the service key is `SW_APM_SERVICE_KEY=api-token:my-service`. If the `OTEL_SERVICE_NAME` or `OTEL_RESOURCE_ATTRIBUTES` environment variable is used to specify a service name, it will take precedence over the default. +Resource attributes: ```bash -# service name for instrumented app will be 'bar', not 'foo' -export SW_APM_SERVICE_KEY=:foo -export OTEL_SERVICE_NAME=bar +export OTEL_RESOURCE_ATTRIBUTES=service.name=production-api,service.version=1.2.3 ``` -### Instrumentation Libraries +#### Instrumentation Control -You can use OpenTelemetry Ruby instrumentation environment variables to [disable](https://opentelemetry.io/docs/languages/ruby/libraries/#overriding-configuration-for-specific-instrumentation-libraries-with-environment-variables) or [configure](https://opentelemetry.io/docs/languages/ruby/libraries/#configuring-specific-instrumentation-libraries-with-environment-variables) certain instrumentation, see the [OpenTelemetry Docs](https://opentelemetry.io/docs/languages/ruby/libraries/#use-instrumentation-libraries) for details. +Fine-tune individual instrumentation libraries using OpenTelemetry environment variables: -For example, to disable sinatra instrumentation and disable mysql2 instrumentation's obfuscation of db.statement: +Disable specific instrumentation: ```bash export OTEL_RUBY_INSTRUMENTATION_SINATRA_ENABLED=false +export OTEL_RUBY_INSTRUMENTATION_REDIS_ENABLED=false +``` + +Configure instrumentation options: + +```bash +# Include full SQL statements (disable obfuscation) export OTEL_RUBY_INSTRUMENTATION_MYSQL2_CONFIG_OPTS='db_statement=include;' + +# Configure HTTP instrumentation +export OTEL_RUBY_INSTRUMENTATION_NET_HTTP_CONFIG_OPTS='untraced_hosts=localhost,internal.service;' ``` -or in your initialization step: +Set inside file through ENV hash: ```ruby -ENV['OTEL_RUBY_INSTRUMENTATION_SINATRA_ENABLED'] = 'false' +# Set before requiring solarwinds_apm ENV['OTEL_RUBY_INSTRUMENTATION_MYSQL2_CONFIG_OPTS'] = 'db_statement=include;' +ENV['OTEL_RUBY_INSTRUMENTATION_NET_HTTP_CONFIG_OPTS'] = 'untraced_hosts=localhost,internal.service;' ``` +> See the [OpenTelemetry Ruby instrumentation documentation](https://opentelemetry.io/docs/languages/ruby/libraries/) for all available options. + ## Programmatic Configuration -Many OpenTelemetry instrumentation library configurations can be set within the `SolarWindsAPM::OTelConfig.initialize_with_config ... end` block, please consult the individual [instrumentation](https://github.com/open-telemetry/opentelemetry-ruby-contrib/tree/main/instrumentation) README pages for the options available. Note this takes lower precedence than the [environment varable](#instrumentation-libraries) settings. +For advanced use cases, you can configure OpenTelemetry instrumentation libraries programmatically using the `SolarWindsAPM::OTelConfig.initialize_with_config` block. + +### Prerequisites -> [!IMPORTANT] -> this feature is only enabled if auto-config is disabled via `SW_APM_AUTO_CONFIGURE=false`. +> **⚠️ Important:** Programmatic configuration requires disabling auto-configuration: + +```bash +export SW_APM_AUTO_CONFIGURE=false +``` + +### Basic Example Below is an example that disables Dalli instrumentation and sets the Rack instrumentation to capture certain headers as Span attributes: ```ruby -# note auto-configure must be disabled, e.g. -# export SW_APM_AUTO_CONFIGURE=false - +# note auto-configure must be disabled, e.g. export SW_APM_AUTO_CONFIGURE=false require 'solarwinds_apm' - SolarWindsAPM::OTelConfig.initialize_with_config do |config| config["OpenTelemetry::Instrumentation::Dalli"] = {:enabled => false} config["OpenTelemetry::Instrumentation::Rack"] = {:allowed_request_headers => ['header1', 'header2']} end ``` -## Configuration File +Advanced Configuration + +```ruby +SolarWindsAPM::OTelConfig.initialize_with_config do |config| + # HTTP client configuration + config["OpenTelemetry::Instrumentation::Net::HTTP"] = { + untraced_hosts: ['localhost', 'internal.service.com'], + untraced_requests: ->(uri, req) { uri.path == '/health' } + } + + # Rails configuration + config["OpenTelemetry::Instrumentation::Rails"] = { + enable_recognize_route: true, + enable_dependency_tracking: true + } + + # Redis configuration + config["OpenTelemetry::Instrumentation::Redis"] = { + peer_service: 'redis-cluster', + db_statement_serializer: ->(stmt) { stmt.truncate(100) } + } +end +``` + +> **Reference:** Consult individual [instrumentation README files](https://github.com/open-telemetry/opentelemetry-ruby-contrib/tree/main/instrumentation) for complete configuration options. -On startup, the library looks for the configuration file in the following locations under the application's current working directory: +## Configuration Files -* `config/initializers/solarwinds_apm.rb` for Rails applications, which can be created by running the provided generator: +The configuration file should be Ruby code that sets key/values in the hash exposed by `SolarWindsAPM::Config`. The bundled [Rails generator template file](https://github.com/solarwinds/apm-ruby/blob/main/lib/rails/generators/solarwinds_apm/templates/solarwinds_apm_initializer.rb) serves as an example of the supported values, see also the [Configuration Reference](#configuration-reference) section. - ```bash - bundle exec rails generate solarwinds_apm:install - ``` +### How to install the file -* `solarwinds_apm_config.rb` for non-Rails applications +#### Rails Applications -The default location can be overridden via environment variable `SW_APM_CONFIG_RUBY`: +For Rails applications, use the built-in generator to create a configuration file: ```bash -export SW_APM_CONFIG_RUBY=config/file/location.rb +bundle exec rails generate solarwinds_apm:install +``` + +This creates `config/initializers/solarwinds_apm.rb` with documented configuration options. + +#### Non-Rails Applications + +Create a file named `solarwinds_apm_config.rb` in your application's root directory: + +```ruby +# solarwinds_apm_config.rb +SolarWindsAPM::Config[:service_key] = 'your-token:your-service' +SolarWindsAPM::Config[:debug_level] = 3 +SolarWindsAPM::Config[:tag_sql] = true ``` -The configuration file should be Ruby code that sets key/values in the hash exposed by `SolarWindsAPM::Config`. The bundled [Rails generator template file](https://github.com/solarwinds/apm-ruby/blob/main/lib/rails/generators/solarwinds_apm/templates/solarwinds_apm_initializer.rb) serves as an example of the supported values, see also the [Reference](#reference) section. +#### Custom Location -## Reference +Override the default configuration file location: -Environment Variable | Config File Key | Description | Default --------------------- | --------------- | ----------- | ------- -`SW_APM_AUTO_CONFIGURE` | N/A | By default the library is configured to work out-of-the-box with all automatic instrumentation libraries enabled. Set this to `false` to custom initialize the library with configuration options for instrumentation, see [Programmatic Configuration](#programmatic-configuration) for details. | `true` -`SW_APM_COLLECTOR` | N/A | Override the default collector endpoint to which the library connects and exports data. It should be defined using the format host:port. | `apm.collector.na-01.cloud.solarwinds.com:443` -`SW_APM_CONFIG_RUBY` | N/A | Override the default location for the configuration file. This can be an absolute or relative filename, or the directory under which the `solarwinds_apm_config.rb` file would be looked for. | None -`SW_APM_DEBUG_LEVEL` | `:debug_level` | Set the library's logging level, valid values are -1 through 6 (least to most verbose).
Setting -1 disables logging from the library. | 3 -`SW_APM_ENABLED` | N/A | Enable/disable the library, setting `false` is an alternative to uninstalling `solarwinds_apm` since it will prevent the library from loading. | `true` -`SW_APM_SERVICE_KEY` | `:service_key` | API token and service name in the form of `token:service_name`, **required**. | None -`SW_APM_TAG_SQL` | `:tag_sql` | Enable/disable injecting trace context into supported SQL statements. Set to boolean true or (or string `true` in env var) to enable, see [Tag Query with Trace Context](#tag-query-with-trace-context) for details.| `false` -`SW_APM_TRIGGER_TRACING_MODE` | `:trigger_tracing_mode` | Enable/disable trigger tracing for the service. Setting to `disabled` may impact DEM visibility into the service. | `enabled` -`SW_APM_LAMBDA_PRELOAD_DEPS` | N/A | This option only takes effect in the AWS Lambda runtime. Set to `false` to disable the attempt to preload function dependencies and install instrumentations. | `true` -`SW_APM_TRANSACTION_NAME` | N/A | Customize the transaction name for all traces, typically used to target specific instrumented lambda functions. _Precedence order_: custom SDK > `SW_APM_TRANSACTION_NAME` > automatic naming | None -N/A | `:log_traceId` | Configure the insertion of trace context into application logs, setting `:traced` would include the available context fields such as trace_id, span_id into log messages. | `:never` -N/A | `:tracing_mode` | Enable/disable the tracing mode for this service, setting `:disabled` would suppress all trace spans and metrics. | `:enabled` -N/A | `:transaction_settings` | Configure tracing mode per transaction, aka transaction filtering. See [Transaction Filtering](#transaction-filtering) for details.| None +```bash +export SW_APM_CONFIG_RUBY=/path/to/your/config.rb +``` + +## Configuration Topics ### Transaction Filtering -Specific transactions can be disabled from tracing (suppressing both spans and metrics) using the `:transaction_settings` configuration. An example that filters out static assets and a message consumer: +Specific transactions can be disabled from tracing (suppressing both spans and metrics) using the `:transaction_settings` configuration. An example that filters out static assets, health check requests, and a background job consumer: ```ruby SolarWindsAPM::Config[:transaction_settings] = [ { - regexp: '\.(css|js|png)$', + regexp: '\.(css|js|png|jpg|gif|ico|woff2?)$', opts: Regexp::IGNORECASE, tracing: :disabled }, { - regexp: 'CONSUMER:mytopic process', + regexp: '/health|/status|/ping', + tracing: :disabled + }, + { + regexp: 'CONSUMER:.*process', # Background job patterns tracing: :disabled } ] ``` -### Tag Query with Trace Context - -You can set the environment variable `SW_APM_TAG_SQL` or configuration file option `:tag_sql` to true to enable appending the current trace context into a database query as a SQL comment. For example: +### SQL Query Tagging -```console -# query without tag sql -SELECT * FROM SAMPLE_TABLE WHERE user_id = 1; +Append trace context to database queries as SQL comments for correlation between traces and database logs. -# query with tag sql -SELECT * FROM SAMPLE_TABLE WHERE user_id = 1; /* traceparent=7435a9fe510ae4533414d425dadf4e18-49e60702469db05f-01 */ +```bash +export SW_APM_TAG_SQL=true # Enable SQL tagging ``` -#### Limitation +Output: -> [!NOTE] -> This feature currently does not support prepared statements. For `mysql2` the `query` operation is supported, for `pg` the "[exec-ish](https://github.com/solarwinds/apm-ruby/blob/main/lib/solarwinds_apm/patch/tag_sql/sw_pg_patch.rb#L15)" operations like `exec` and `query` are supported. +```sql +-- Before (without tagging) +SELECT * FROM users WHERE id = 1; + +-- After (with tagging) +SELECT * FROM users WHERE id = 1; /* traceparent=7435a9fe510ae4533414d425dadf4e18-49e60702469db05f-01 */ +``` -### Background Jobs +Supported Operations: -#### Resque +- **MySQL2**: `query` operations +- **PostgreSQL**: the "[exec-ish](https://github.com/solarwinds/apm-ruby/blob/main/lib/solarwinds_apm/patch/tag_sql/sw_pg_patch.rb#L15)" operations like `exec` and `query` are supported. -[Resque](https://github.com/resque/resque) is a Redis-backed library for creating background jobs, queuing them on multiple queues, and processing them later. +> **⚠️ Limitation:** Currently does not support prepared statements. -When starting the Resque worker, it is necessary to set: `RUN_AT_EXIT_HOOKS=1`. +### Log Trace Context Integration -For example: +Include trace context in your application logs for better correlation: -```console -RUN_AT_EXIT_HOOKS=1 QUEUE=${QUEUE_NAME} ${EXTRA_OPTIONS} bundle exec rake resque:work +```ruby +SolarWindsAPM::Config[:log_traceId] = :traced ``` -Explanation: +This adds trace and span IDs to log entries when using supported logging frameworks. + +### Background Job Configuration: Resque + +When starting the Resque worker, it is necessary to set `RUN_AT_EXIT_HOOKS=1`. For example: + +```bash +RUN_AT_EXIT_HOOKS=1 QUEUE=myqueue bundle exec rake resque:work +``` -* `RUN_AT_EXIT_HOOKS`: This option, provided by Resque, ensures that the forked processes shut down gracefully (i.e., no immediate `exit!`). This allows the background processes that handle signal (trace, metrics, etc.) transmission to complete their tasks. +The `RUN_AT_EXIT_HOOKS=1` ensures background processes complete before worker shutdown. This allows the background processes that handle signal (trace, metrics, etc.) transmission to complete their tasks. -### Proxy +### Proxy Configuration -Starting with version 7.0.0, the environment variable `SW_APM_PROXY` and configuration file option `:http_proxy` are deprecated since telemetry is exported with standard OTLP exporters. These exporters use Ruby's `Net::HTTP`, which supports configuring an [HTTP proxy](https://docs.ruby-lang.org/en/master/Net/HTTP.html#class-Net::HTTPSession-label-Proxy+Server). The examples below set the `http_proxy` environment variable for the Ruby process to configure the proxy: +Starting with version 7.0.0, the environment variable `SW_APM_PROXY` and configuration file option `:http_proxy` are deprecated since telemetry is exported with standard OTLP exporters. These exporters use Ruby +'s `Net::HTTP`, which supports configuring an [HTTP proxy](https://docs.ruby-lang.org/en/master/Net/HTTP.html#class-Net::HTTPSession-label-Proxy+Server). The examples below set the `http_proxy` environment variable for the Ruby process to configure the proxy: ```bash # proxy server with no authentication @@ -190,4 +288,69 @@ http_proxy=http://: ruby my.app # proxy server that requires basic authentication http_proxy=http://:@: ruby my.app -``` \ No newline at end of file +``` + +> **Note:** Starting with version 7.0.0, `SW_APM_PROXY` is deprecated in favor of standard HTTP proxy environment variables. + +### Lambda Configuration + +For AWS Lambda deployments: + +```bash +# Disable dependency preloading if needed +export SW_APM_LAMBDA_PRELOAD_DEPS=false + +# Set custom transaction names +export SW_APM_TRANSACTION_NAME=my-lambda-function +``` + +## Configuration Reference + +| Environment Variable | Config File Key | Description | Default | +| -------------------- | --------------- | ----------- | ------- | +| `SW_APM_AUTO_CONFIGURE` | N/A | By default the library is configured to work out-of-the-box with all automatic instrumentation libraries enabled. Set this to `false` to custom initialize the library with configuration options for instrumentation, see [Programmatic Configuration](#programmatic-configuration) for details. | `true` | +| `SW_APM_COLLECTOR` | N/A | Override the default collector endpoint to which the library connects and exports data. It should be defined using the format host:port. | `apm.collector.na-01.cloud.solarwinds.com:443` | +| `SW_APM_CONFIG_RUBY` | N/A | Override the default location for the configuration file. This can be an absolute or relative filename, or the directory under which the `solarwinds_apm_config.rb` file would be looked for. | None | +| `SW_APM_DEBUG_LEVEL` | `:debug_level` | Set the library's logging level, valid values are -1 through 6 (least to most verbose).
Setting -1 disables logging from the library. | 3 | +| `SW_APM_ENABLED` | N/A | Enable/disable the library, setting `false` is an alternative to uninstalling `solarwinds_apm` since it will prevent the library from loading. | `true` | +| `SW_APM_SERVICE_KEY` | `:service_key` | API token and service name in the form of `token:service_name`, **required**. | None | +| `SW_APM_TAG_SQL` | `:tag_sql` | Enable/disable injecting trace context into supported SQL statements. Set to boolean true or (or string `true` in env var) to enable, see [Tag Query with Trace Context](#sql-query-tagging) for details.| `false` | +| `SW_APM_TRIGGER_TRACING_MODE` | `:trigger_tracing_mode` | Enable/disable trigger tracing for the service. Setting to `disabled` may impact DEM visibility into the service. | `enabled` | +| `SW_APM_LAMBDA_PRELOAD_DEPS` | N/A | This option only takes effect in the AWS Lambda runtime. Set to `false` to disable the attempt to preload function dependencies and install instrumentations. | `true` | +| `SW_APM_TRANSACTION_NAME` | N/A | Customize the transaction name for all traces, typically used to target specific instrumented lambda functions. _Precedence order_: custom SDK > `SW_APM_TRANSACTION_NAME` > automatic naming | None | +| N/A | `:log_traceId` | Configure the insertion of trace context into application logs, setting `:traced` would include the available context fields such as trace_id, span_id into log messages. | `:never` | +| N/A | `:tracing_mode` | Enable/disable the tracing mode for this service, setting `:disabled` would suppress all trace spans and metrics. | `:enabled` | +| N/A | `:transaction_settings` | Configure tracing mode per transaction, aka transaction filtering. See [Transaction Filtering](#transaction-filtering) for details.| None | + +### Debug Levels + +| Level | Description | +|-------|-------------| +| `-1` | Logging disabled | +| `0` | Fatal errors only | +| `1` | Errors | +| `2` | Warnings | +| `3` | Info (default) | +| `4` | Debug | +| `5` | Verbose | +| `6` | Maximum verbosity | + +## Troubleshooting + +### Log Analysis + +Enable debug logging and look for: + +- Service key validation +- Collector connection status +- Instrumentation loading +- Span creation and export + +```bash +# Enable detailed logging +export SW_APM_DEBUG_LEVEL=5 +# Or use otel debug level +export OTEL_LOG_LEVEL=debug +``` + +For additional help, see the [SolarWinds documentation](https://documentation.solarwinds.com/en/success_center/observability/content/configure/services/ruby/install.htm) or contact support. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 70fa25aa..ccc6d97e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,172 +1,162 @@ -# Contributing +# Contributing to SolarWinds APM Ruby -## Requirements +Thank you for your interest in contributing to the SolarWinds APM Ruby gem! This document provides guidelines and instructions for contributing to this OpenTelemetry-based Ruby distribution. -The descriptions below assume you are in the locally cloned project root directory, i.e. `apm-ruby`. +## How to Contribute -Prerequisites +We welcome various types of contributions: -* Docker -* Docker Compose +- **Bug reports**: Help us identify and fix issues +- **Feature requests**: Suggest new functionality or improvements +- **Documentation**: Improve our docs, guides, and examples +- **Code contributions**: Bug fixes, new features, performance improvements +- **Testing**: Add test coverage or improve existing tests -## Host Machine Setup +## Development Environment Setup -You'll need a host environment that can run the various Rake tasks to spin up development and testing containers. The following describes how to do this with [rbenv](https://github.com/rbenv/rbenv). +### Prerequisites -### 1. Install rbenv +Before you begin, ensure you have the following installed: -Mac +- **Git** - For version control +- **rbenv** - For Ruby version management (see [rbenv installation guide](https://github.com/rbenv/rbenv#installation)) +- **Ruby** - Install via rbenv +- **Docker** - (Optional) -```bash -brew install rbenv ruby-build -``` +### Getting Started -Linux +1. **Fork the repository** on GitHub +2. **Clone your fork** locally: -```bash -sudo apt install rbenv -``` + ```bash + git clone https://github.com/YOUR_USERNAME/apm-ruby.git + cd apm-ruby + ``` -Built from source (github) +3. **Add the upstream remote**: -```bash -git clone https://github.com/rbenv/rbenv.git ~/.rbenv -echo 'eval "$(~/.rbenv/bin/rbenv init - bash)"' >> ~/.bashrc # for bash -echo 'eval "$(~/.rbenv/bin/rbenv init - zsh)"' >> ~/.zshrc # for zsh -``` + ```bash + git remote add upstream https://github.com/solarwinds/apm-ruby.git + ``` -### 2. Install and Set Ruby Runtime +### Setup Ruby Environment -Install ruby from rbenv: +1. **Install Ruby** using rbenv (install appropriate version as needed): -```bash -# list latest stable versions: -rbenv install -l + ```bash + rbenv install 3.1.2 + rbenv local 3.1.2 # or rbenv global 3.1.2 + ``` -# list all local versions: -rbenv install -L +2. **Install dependencies** with isolated vendoring: -# install a Ruby version: -rbenv install 3.1.2 -``` + ```bash + gem install bundler + bundle install --path vendor/bundle + ``` -Enable rbenv by following the instructions printed by this command: +3. **Verify setup** by listing available rake tasks: -```bash -rbenv init -``` + ```bash + bundle exec rake -T + ``` -Set ruby version to use. Set this at the global level to prevent `.ruby-version` conflicts within the development container which bind mounts the working tree: + You should see various available tasks for building, testing, and linting. -```bash -rbenv global 3.1.2 # set the default Ruby version for this machine -``` +## Development Workflow -### 3. Install Minimal Project Dependencies +### Making Changes -Install bundler, configure it to skip unneeded groups, then install the project dependencies to allow working with Rake tasks: +1. **Create a feature branch**: -```bash -gem install bundler -bundle config set --local without development test -bundle install -``` + ```bash + git checkout -b feature/your-feature-name + ``` -Should now be able to list the Rake tasks: +2. **Make your changes** in the appropriate files under `lib/` -```bash -bundle exec rake -T -``` +3. **Write or update tests** in the `test/` directory -## Run Development Container +### Testing Your Changes -The `solarwinds_apm` gem requires a Linux run time environment. To work on the codebase we set up an Ubuntu container with the tools needed to build, install and work with the project. +#### Load Changes Interactively -Starting the container: +Test your changes without building a gem: ```bash -bundle exec rake docker_dev +bundle exec irb -Ilib -r solarwinds_apm ``` -In the container, set up the environment and project dependencies: +This loads your source code changes directly for quick testing and debugging. -```bash -# choose the ruby version to use, setting it at the global level -rbenv versions -rbenv global +#### Running Tests -# install project gem dependencies -bundle install -``` +> **Note:** Some tests require the `APM_RUBY_TEST_KEY` environment variable. Contact the maintainers if you need access to a test key. + +**Single test file:** -### Building the Gem +```bash +bundle exec ruby -I test test/opentelemetry/solarwinds_propagator_test.rb +``` -The gem can be built, installed, and run inside the development container: +**Single test case:** ```bash -# build the gem -bundle exec rake build_gem +bundle exec ruby -I test test/opentelemetry/solarwinds_propagator_test.rb -n /trace_state_header/ +``` -# install the built gem -gem install builds/solarwinds_apm-.gem +**Local test suite (run all test file):** -# load the gem -SW_APM_SERVICE_KEY= irb -r solarwinds_apm +```bash +APM_RUBY_TEST_KEY=your_service_key test/run_tests.sh ``` -### Linting +#### Code Quality -Use this Rake task to run rubocop inside the development container: +Run RuboCop for code style enforcement: ```bash bundle exec rake rubocop ``` -It will produce the file `rubocop_result.txt`. Issues found should be addressed prior to commit. - -## Run Test Containers +All linting issues must be resolved before submitting a pull request. -On the host machine, you can use the `docker_tests` Rake task to run the test suite, or launch an interactive shell session into the test container to run specific tests or to debug. +## Advanced Setup (Optional) -### Run Test Suite +### Development Environment inside Container -Run the test suite (some test cases rely on env `APM_RUBY_TEST_KEY`): +For complex debugging or if you prefer working in a containerized environment, you can use Ubuntu containers with all necessary tools: ```bash -# run tests in a ruby:3.1.0-bullseye container -bundle exec rake 'docker_tests[,,,APM_RUBY_TEST_KEY=your_service_key]' - -# run tests in a ruby:3.2-alpine linux/amd64 container -bundle exec rake 'docker_tests[3.2-alpine,,linux/amd64,APM_RUBY_TEST_KEY=your_service_key]' +bundle exec rake docker_dev ``` -Test logs are written to the project's `log` directory, which is bind mounted and available on the host machine. - -### Launch Interactive Shell - -Start an interactive session in the container: +Once inside the container: ```bash -bundle exec rake 'docker_tests[,false]' +rbenv global # Set Ruby version +bundle install # Install dependencies ``` -In the container, set up the environment: +The development container provides a complete isolated environment with all source code mounted from your host machine. -```bash -test/test_setup.sh -``` +### Full Regression Testing -To run the full suite (some test cases rely on env `APM_RUBY_TEST_KEY`): +Run the complete test suite in containers (from host machine): ```bash -APM_RUBY_TEST_KEY=your_service_key test/run_tests.sh +# Run tests in Ruby 3.1.0 bullseye container +bundle exec rake 'docker_tests[,,,APM_RUBY_TEST_KEY=your_service_key]' + +# Run tests in Ruby 3.2 Alpine container for ARM64 +bundle exec rake 'docker_tests[3.2-alpine,,linux/amd64,APM_RUBY_TEST_KEY=your_service_key]' ``` -To run a single test file or single test case: +Test logs are written to the `log/` directory. -```bash -# most tests require just the unit.gemfile dependencies -bundle update -bundle exec ruby -I test test/opentelemetry/solarwinds_propagator_test.rb -bundle exec ruby -I test test/opentelemetry/solarwinds_propagator_test.rb -n /trace_state_header/ -``` +## Additional Resources + +- [OpenTelemetry Ruby Documentation](https://opentelemetry.io/docs/instrumentation/ruby/) +- [SolarWinds Observability Documentation](https://documentation.solarwinds.com/en/success_center/observability/default.htm) + +Thank you for contributing to SolarWinds APM Ruby! diff --git a/README.md b/README.md index 19cb22cc..276e871e 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ The `solarwinds_apm` gem starting from version 6.0.0 is an [OpenTelemetry Ruby](https://opentelemetry.io/docs/instrumentation/ruby/) distribution. It provides automatic instrumentation and custom SolarWinds Observability features for Ruby applications. ## Requirements +> > [!NOTE] > Versions before 7.0.0 only support Linux and will go into no-op mode on other platforms.