Skip to content

Commit

Permalink
Roll the dice for ruby (#2655)
Browse files Browse the repository at this point in the history
Signed-off-by: svrnm <[email protected]>
Co-authored-by: Patrice Chalin <[email protected]>
  • Loading branch information
svrnm and chalin authored May 10, 2023
1 parent 182750e commit 1c65eb5
Show file tree
Hide file tree
Showing 3 changed files with 286 additions and 67 deletions.
125 changes: 125 additions & 0 deletions content/en/docs/instrumentation/ruby/exporters.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
---
title: Exporters
weight: 5
spelling: cSpell:ignore Zipkin jaegertracing openzipkin zipkin
---

In order to visualize and analyze your traces, you will need to export them to a
backend such as [Jaeger](https://www.jaegertracing.io/) or
[Zipkin](https://zipkin.io/). OpenTelemetry Ruby provides exporters for some
common open source backends.

Below you will find some introductions on how to set up backends and the
matching exporters.

## OTLP endpoint

To send trace data to a OTLP endpoint (like the [collector](/docs/collector) or
Jaeger) you'll want to use an exporter package, such as
`opentelemetry-exporter-otlp`:

{{< tabpane lang=shell persistLang=false >}}

{{< tab bundler >}} bundle add opentelemetry-exporter-otlp {{< /tab >}}

{{< tab gem >}} gem install opentelemetry-exporter-otlp {{< /tab >}}

{{< /tabpane>}}

Next, configure the exporter to point at an OTLP endpoint. For example you can
update `config/initializers/opentelemetry.rb` from the
[Getting Started](../getting-started/) by adding
`require 'opentelemetry-exporter-otlp'` to the code:

```ruby
# config/initializers/opentelemetry.rb
require 'opentelemetry/sdk'
require 'opentelemetry/instrumentation/all'
require 'opentelemetry-exporter-otlp'
OpenTelemetry::SDK.configure do |c|
c.service_name = 'dice-ruby'
c.use_all() # enables all instrumentation!
end
```

If you now run your application it will use OTLP to export traces:

```sh
rails server -p 8080
```

By default traces are sent to an OTLP endpoint listening on localhost:4318. You
can change the endpoint by setting the `OTEL_EXPORTER_OTLP_ENDPOINT`
accordingly:

```sh
env OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4318/v1/traces" rails server -p 8080
```

To try out the OTLP exporter quickly and see your traces visualized at the
receiving end, you can run Jaeger in a docker container:

```shell
docker run -d --name jaeger \
-e COLLECTOR_ZIPKIN_HOST_PORT=:9411 \
-e COLLECTOR_OTLP_ENABLED=true \
-p 6831:6831/udp \
-p 6832:6832/udp \
-p 5778:5778 \
-p 16686:16686 \
-p 4317:4317 \
-p 4318:4318 \
-p 14250:14250 \
-p 14268:14268 \
-p 14269:14269 \
-p 9411:9411 \
jaegertracing/all-in-one:latest
```

## Zipkin

To set up Zipkin as quickly as possible, run it in a docker container:

```shell
docker run --rm -d -p 9411:9411 --name zipkin openzipkin/zipkin
```

Install the exporter package as a dependency for your application:

{{< tabpane lang=shell persistLang=false >}}

{{< tab bundle >}} bundle add opentelemetry-exporter-zipkin {{< /tab >}}

{{< tab gem >}} gem install opentelemetry-exporter-zipkin {{< /tab >}}

{{< /tabpane>}}

Update your OpenTelemetry configuration to use the exporter and to send data to
your Zipkin backend:

```ruby
# config/initializers/opentelemetry.rb
require 'opentelemetry/sdk'
require 'opentelemetry/instrumentation/all'

require 'opentelemetry-exporter-zipkin'
OpenTelemetry::SDK.configure do |c|
c.service_name = 'dice-ruby'
c.use_all() # enables all instrumentation!
end
```

If you now run your application, set the environment variable
`OTEL_TRACES_EXPORTER` to zipkin:

```sh
env OTEL_TRACES_EXPORTER=zipkin rails server
```

By default traces are sent to a Zipkin endpoint listening on port
localhost:9411. You can change the endpoint by setting the
`OTEL_EXPORTER_ZIPKIN_ENDPOINT` accordingly:

```sh
env OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:9411" rails server
```
212 changes: 145 additions & 67 deletions content/en/docs/instrumentation/ruby/getting-started.md
Original file line number Diff line number Diff line change
@@ -1,58 +1,122 @@
---
title: Getting Started
description: Get telemetry from your app in less than 5 minutes!
aliases: [/docs/instrumentation/ruby/getting_started]
spelling: cSpell:ignore truffleruby sinatra rolldice struct darwin Tracestate
spelling: cSpell:ignore tracestate
weight: 1
---

[OpenTelemetry for Ruby][repository] can be used to add automatic and manual
instrumentation to your applications. Automatic instrumentation is enabled by
adding [instrumentation packages][auto]. Manual instrumentation can be added
using the [OpenTelemetry API][manual].
This page will show you how to get started with OpenTelemetry in Ruby.

### Requirements
You will learn how you can instrument a simple application automatically, in
such a way that [traces][], [metrics][] and [logs][] are emitted to the console.

These instructions will explain how to set up automatic and manual
instrumentation for a Ruby service. In order to follow along, you will need:
## Prerequisites

Ensure that you have the following installed locally:

- MRI Ruby >= `3.0`, jruby >= `9.3.2.0`, or truffleruby >= 22.1
- Docker Compose
- [Bundler](https://bundler.io/)

{{% alert title="Warning" color="warning" %}} `jruby` only targets
compatibility with MRI Ruby 2.6.8, which is EOL. This project does not
officially support MRI Ruby 2.6.8, and provides `jruby` support on a best-effort
basis until the `jruby` project supports compatibility with more modern Ruby
runtimes.

While tested, support for `truffleruby` is on a best-effort basis at this time.
{{% /alert %}}

## Example Application

The following example uses a basic [Rails](https://rubyonrails.org/)
application. If you are not using Sinatra, that's ok — you can use OpenTelemetry
Ruby with other web frameworks as well, such as Sinatra and Rack. For a complete
list of libraries for supported frameworks, see the
[registry](/ecosystem/registry/?component=instrumentation&language=ruby).

For more elaborate examples, see
[examples](/docs/instrumentation/ruby/examples/).

### Dependencies

To begin, install rails:

```sh
gem install rails
```

### Create the application

Create a new api-only application called `dice-ruby` and change into the newly
created folder `dice-ruby`

```sh
rails new --api dice-ruby
cd dice-ruby
```

Create a controller for rolling a dice:

```sh
rails generate controller dice
```

This will create a file called `app/controllers/dice_controller.rb`. Open that
file in your preferred editor and update it with the following code:

> jruby only targets compatibility with MRI Ruby 2.6.8; which is EOL. This
> project does not officially support MRI Ruby 2.6.8, and provides jruby support
> on a best-effort basis until the jruby project supports compatibility with
> more modern Ruby runtimes.
>
> truffleruby is tested, but support is best-effort at this time.
```ruby
class DiceController < ApplicationController
def roll
render json: (rand(6) + 1).to_s
end
end
```

### Installation
Next, open the `config/routes.rb` file and add the following code:

The first step is to add these gems to your Gemfile:
```ruby
Rails.application.routes.draw do
get 'rolldice', to: 'dice#roll'
end
```

Run the application with the following command and open
<http://localhost:8080/rolldice> in your web browser to ensure it is working.

```sh
gem 'opentelemetry-sdk'
gem 'opentelemetry-exporter-otlp'
gem 'opentelemetry-instrumentation-all'
rails server -p 8080
```

If everything works fine you should see a number between 1 and 6 returned to
you. You can now stop the application and instrument it using OpenTelemetry.

### Instrumentation

Install the `opentelemetry-sdk` and `opentelemetry-instrumentation-all`
packages:

```sh
bundle add opentelemetry-sdk opentelemetry-instrumentation-all
```

The inclusion of `opentelemetry-instrumentation-all` provides
[instrumentations][auto] for Rails, Sinatra, several HTTP libraries, and more.

### Initialization

The OpenTelemetry initialization needs to happen early in your application
lifecycle. For Rails applications, the usual way to initialize OpenTelemetry is
in a Rails initializer. For other Ruby services, perform this initialization as
early as possible in the start-up process.
For Rails applications, the usual way to initialize OpenTelemetry is in a Rails
initializer. For other Ruby services, perform this initialization as early as
possible in the start-up process.

OpenTelemetry initialization:
Create a file named `config/initializers/opentelemetry.rb` with the following
code:

```ruby
# config/initializers/opentelemetry.rb
require 'opentelemetry/sdk'
require 'opentelemetry/exporter/otlp'
require 'opentelemetry/instrumentation/all'
OpenTelemetry::SDK.configure do |c|
c.service_name = '<YOUR_SERVICE_NAME>'
c.service_name = 'dice-ruby'
c.use_all() # enables all instrumentation!
end
```
Expand All @@ -61,52 +125,65 @@ The call `c.use_all()` enables all instrumentations in the `instrumentation/all`
package. If you have more advanced configuration needs, see [configuring
specific instrumentation libraries][config].

Now that you have setup your application to perform tracing, you'll need to
configure the SDK to export the traces somewhere. Our example loaded the `OTLP`
exporter, which the SDK tries to use by default. Next, we'll use the
OpenTelemetry Collector to receive these traces and visualize them using Jaeger
and Zipkin!

### Exporting Traces

The following section assumes you are new to OpenTelemetry or do not currently
use a vendor that supports distributed tracing using OTLP. Please refer to your
vendor's product documentation if you would like to export your traces to a
vendor for analysis and visualization.
### Run the instrumented app

For the purposes of this tutorial you will configure an OpenTelemetry collector
that will receive the traces and visualize them using Jaeger or Zipkin UI.

First, start up an example system:
You can now run your instrumented app and have it print to the console for now:

```sh
git clone [email protected]:open-telemetry/opentelemetry-ruby.git; \
cd opentelemetry-ruby/examples/otel-collector; \
docker-compose up -d
env OTEL_TRACES_EXPORTER=console rails server -p 8080
```

Next, you'll have to let the SDK know where the collector endpoint is to receive
traces. Set the [`OTEL_EXPORTER_OTLP_ENDPOINT`][sdk-env] environment variable to
`http://0.0.0.0:4318`:
Open <http://localhost:8080/rolldice> in your web browser and reload the page a
few times. You should see the spans printed in the console, such as the
following:

```sh
export OTEL_EXPORTER_OTLP_ENDPOINT=http://0.0.0.0:4318
```ruby
#<struct OpenTelemetry::SDK::Trace::SpanData
name="DiceController#roll",
kind=:server,
status=#<OpenTelemetry::Trace::Status:0x000000010587fc48 @code=1, @description="">,
parent_span_id="\x00\x00\x00\x00\x00\x00\x00\x00",
total_recorded_attributes=8,
total_recorded_events=0,
total_recorded_links=0,
start_timestamp=1683555544407294000,
end_timestamp=1683555544464308000,
attributes=
{"http.method"=>"GET",
"http.host"=>"localhost:8080",
"http.scheme"=>"http",
"http.target"=>"/rolldice",
"http.user_agent"=>"curl/7.87.0",
"code.namespace"=>"DiceController",
"code.function"=>"roll",
"http.status_code"=>200},
links=nil,
events=nil,
resource=
#<OpenTelemetry::SDK::Resources::Resource:0x000000010511d1f8
@attributes=
{"service.name"=>"<YOUR_SERVICE_NAME>",
"process.pid"=>83900,
"process.command"=>"bin/rails",
"process.runtime.name"=>"ruby",
"process.runtime.version"=>"3.2.2",
"process.runtime.description"=>"ruby 3.2.2 (2023-03-30 revision e51014f9c0) [arm64-darwin22]",
"telemetry.sdk.name"=>"opentelemetry",
"telemetry.sdk.language"=>"ruby",
"telemetry.sdk.version"=>"1.2.0"}>,
instrumentation_scope=#<struct OpenTelemetry::SDK::InstrumentationScope name="OpenTelemetry::Instrumentation::Rack", version="0.23.0">,
span_id="\xA7\xF0\x9B#\b[\xE4I",
trace_id="\xF3\xDC\b8\x91h\xB0\xDF\xDEn*CH\x9Blf",
trace_flags=#<OpenTelemetry::Trace::TraceFlags:0x00000001057b7b08 @flags=1>,
tracestate=#<OpenTelemetry::Trace::Tracestate:0x00000001057b67f8 @hash={}>>
```

Now, start up your application and perform a few operations to generate tracing
data, e.g. navigate around your web app or kick off background tasks.

Lastly, open a browser and navigate to the [Jaeger UI](http://localhost:16686)
or [Zipkin UI](http://localhost:9411) and search for traces related to your
service, which were generated by the auto-instrumentation features of
OpenTelemetry!

### What next?
## What next?

Adding tracing to a single service is a great first step and although
auto-instrumentation provides quite a bit of insight on its own, OpenTelemetry
provides a few more features that will allow you gain even deeper insights!
Adding tracing to a single service is a great first step. OpenTelemetry provides
a few more features that will allow you gain even deeper insights!

- [Exporters][] allow you to export your data to a preferred backend.
- [Context propagation][] is perhaps one of the most powerful concepts in
OpenTelemetry because it will upgrade your single service trace into a
_distributed trace_, which makes it possible for OpenTelemetry vendors to
Expand All @@ -116,12 +193,13 @@ provides a few more features that will allow you gain even deeper insights!
- [Manual instrumentation][manual] will give provide you the ability to enrich
your traces with domain specific data.

[traces]: /docs/concepts/signals/traces/
[metrics]: /docs/concepts/signals/metrics/
[logs]: /docs/concepts/signals/logs/
[auto]:
https://github.com/open-telemetry/opentelemetry-ruby#instrumentation-libraries
[config]: ../automatic/#configuring-specific-instrumentation-libraries
[exporters]: ../exporters/
[context propagation]: ../manual/#context-propagation
[manual]: ../manual/
[repository]: https://github.com/open-telemetry/opentelemetry-ruby
[sdk-env]:
/docs/reference/specification/protocol/exporter/#configuration-options
[span events]: ../manual/#add-span-events
Loading

0 comments on commit 1c65eb5

Please sign in to comment.