Skip to content

Commit

Permalink
examples: add ruby span profiling (#3780)
Browse files Browse the repository at this point in the history
  • Loading branch information
marcsanmi authored Dec 16, 2024
1 parent 98b1d05 commit 6f0a6cf
Show file tree
Hide file tree
Showing 16 changed files with 501 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -76,5 +76,5 @@ Refer to the [data source configuration documentation](https://grafana.com/docs/
## Examples

Check out these demo applications for span profiles:
- [Python example](https://github.com/grafana/pyroscope/tree/main/examples/tracing/tempo/python)
- [Python example](https://github.com/grafana/pyroscope/tree/main/examples/tracing/python)
- [Other examples](https://github.com/grafana/pyroscope/tree/main/examples/tracing/tempo) in multiple languages
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,9 @@ The profile type or app must be selected for the query to be valid. Grafana does
## Examples

Check out the [examples](https://github.com/grafana/pyroscope/tree/main/examples/tracing/tempo) directory for a complete demo application that shows tracing integration features.

## Examples

Check out these demo applications for span profiles:
- [Ruby example](https://github.com/grafana/pyroscope/tree/main/examples/tracing/ruby)
- [Other examples](https://github.com/grafana/pyroscope/tree/main/examples/tracing/tempo) in multiple languages
1 change: 1 addition & 0 deletions examples/tracing/ruby/.ruby-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.2.2
12 changes: 12 additions & 0 deletions examples/tracing/ruby/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
FROM ruby:3.2.2

WORKDIR /opt/app

COPY Gemfile ./Gemfile
COPY Gemfile.lock ./Gemfile.lock
# RUN bundle config set --local deployment true
RUN bundle install

COPY lib ./lib

CMD [ "ruby", "lib/server.rb" ]
12 changes: 12 additions & 0 deletions examples/tracing/ruby/Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# frozen_string_literal: true

source "https://rubygems.org"

git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }

gem 'pyroscope', '= 0.5.12'
gem "sinatra", "~> 2.1"
gem "thin", "~> 1.8"
gem 'pyroscope-otel'
gem 'opentelemetry-sdk'
gem 'opentelemetry-exporter-otlp'
113 changes: 113 additions & 0 deletions examples/tracing/ruby/Gemfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
GEM
remote: https://rubygems.org/
specs:
bigdecimal (3.1.8)
daemons (1.4.1)
eventmachine (1.2.7)
ffi (1.17.0)
ffi (1.17.0-aarch64-linux-gnu)
ffi (1.17.0-aarch64-linux-musl)
ffi (1.17.0-arm-linux-gnu)
ffi (1.17.0-arm-linux-musl)
ffi (1.17.0-arm64-darwin)
ffi (1.17.0-x86-linux-gnu)
ffi (1.17.0-x86-linux-musl)
ffi (1.17.0-x86_64-darwin)
ffi (1.17.0-x86_64-linux-gnu)
ffi (1.17.0-x86_64-linux-musl)
google-protobuf (4.29.1)
bigdecimal
rake (>= 13)
google-protobuf (4.29.1-aarch64-linux)
bigdecimal
rake (>= 13)
google-protobuf (4.29.1-arm64-darwin)
bigdecimal
rake (>= 13)
google-protobuf (4.29.1-x86-linux)
bigdecimal
rake (>= 13)
google-protobuf (4.29.1-x86_64-darwin)
bigdecimal
rake (>= 13)
google-protobuf (4.29.1-x86_64-linux)
bigdecimal
rake (>= 13)
googleapis-common-protos-types (1.16.0)
google-protobuf (>= 3.18, < 5.a)
mustermann (2.0.2)
ruby2_keywords (~> 0.0.1)
opentelemetry-api (1.1.0)
opentelemetry-common (0.21.0)
opentelemetry-api (~> 1.0)
opentelemetry-exporter-otlp (0.29.1)
google-protobuf (>= 3.18)
googleapis-common-protos-types (~> 1.3)
opentelemetry-api (~> 1.1)
opentelemetry-common (~> 0.20)
opentelemetry-sdk (~> 1.2)
opentelemetry-semantic_conventions
opentelemetry-registry (0.3.1)
opentelemetry-api (~> 1.1)
opentelemetry-sdk (1.6.0)
opentelemetry-api (~> 1.1)
opentelemetry-common (~> 0.20)
opentelemetry-registry (~> 0.2)
opentelemetry-semantic_conventions
opentelemetry-semantic_conventions (1.10.1)
opentelemetry-api (~> 1.0)
pyroscope (0.5.12)
ffi
pyroscope (0.5.12-aarch64-linux)
ffi
pyroscope (0.5.12-arm64-darwin)
ffi
pyroscope (0.5.12-x86_64-darwin)
ffi
pyroscope (0.5.12-x86_64-linux)
ffi
pyroscope-otel (0.1.1)
opentelemetry-api (~> 1.1.0)
pyroscope (~> 0.5.1)
rack (2.2.10)
rack-protection (2.2.4)
rack
rake (13.2.1)
ruby2_keywords (0.0.5)
sinatra (2.2.4)
mustermann (~> 2.0)
rack (~> 2.2)
rack-protection (= 2.2.4)
tilt (~> 2.0)
thin (1.8.2)
daemons (~> 1.0, >= 1.0.9)
eventmachine (~> 1.0, >= 1.0.4)
rack (>= 1, < 3)
tilt (2.4.0)

PLATFORMS
aarch64-linux
aarch64-linux-gnu
aarch64-linux-musl
arm-linux-gnu
arm-linux-musl
arm64-darwin
ruby
x86-linux
x86-linux-gnu
x86-linux-musl
x86_64-darwin
x86_64-linux
x86_64-linux-gnu
x86_64-linux-musl

DEPENDENCIES
opentelemetry-exporter-otlp
opentelemetry-sdk
pyroscope (= 0.5.12)
pyroscope-otel
sinatra (~> 2.1)
thin (~> 1.8)

BUNDLED WITH
2.5.23
56 changes: 56 additions & 0 deletions examples/tracing/ruby/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Span Profiles with Grafana Tempo and Pyroscope

The docker compose consists of:
- Three Ruby Rideshare App instances (us-east, eu-north, ap-south regions)
- Tempo for trace collection
- Pyroscope for continuous profiling
- Grafana for visualization
- Load Generator for simulating traffic

For a detailed guide about Ruby span profiles configuration, refer to the docs [Pyroscope documentation](https://grafana.com/docs/pyroscope/latest/configure-client/trace-span-profiles/ruby-span-profiles/).

The `rideshare` app generates traces and profiling data that should be available in Grafana.
Pyroscope and Tempo datasources are provisioned automatically.

### Build and run

The project can be run locally with the following commands:

```shell
# Pull latest pyroscope and grafana images:
docker pull grafana/pyroscope:latest
docker pull grafana/grafana:latest

bundle install

docker compose up
```
The load generator will automatically start sending requests to all regional instances.

### Viewing Traces and Profiles

Navigate to the [Explore page](http://localhost:3000/explore?schemaVersion=1&panes=%7B%22yM9%22:%7B%22datasource%22:%22tempo%22,%22queries%22:%5B%7B%22refId%22:%22A%22,%22datasource%22:%7B%22type%22:%22tempo%22,%22uid%22:%22tempo%22%7D,%22queryType%22:%22traceqlSearch%22,%22limit%22:20,%22tableType%22:%22traces%22,%22filters%22:%5B%7B%22id%22:%22e73a615e%22,%22operator%22:%22%3D%22,%22scope%22:%22span%22%7D,%7B%22id%22:%22service-name%22,%22tag%22:%22service.name%22,%22operator%22:%22%3D%22,%22scope%22:%22resource%22,%22value%22:%5B%22rideshare.ruby.push.app%22%5D,%22valueType%22:%22string%22%7D%5D%7D%5D,%22range%22:%7B%22from%22:%22now-6h%22,%22to%22:%22now%22%7D%7D%7D&orgId=1), select a trace and click on a span that has a linked profile:

![image](https://github.com/grafana/otel-profiling-go/assets/12090599/31e33cd1-818b-4116-b952-c9ec7b1fb593)

By default, only the root span gets labeled (the first span created locally): such spans are marked with the link icon
and have `pyroscope.profile.id` attribute set to the corresponding span ID.
Please note that presence of the attribute does not necessarily
indicate that the span has a profile: stack trace samples might not be collected, if the utilized CPU time is
less than the sample interval (10ms).

### Grafana Tempo configuration

In order to correlate trace spans with profiling data, the Tempo datasource should have the following configured:
- The profiling data source
- Tags to use when making profiling queries

![image](https://github.com/grafana/pyroscope/assets/12090599/380ac574-a298-440d-acfb-7bc0935a3a7c)

While tags are optional, configuring them is highly recommended for optimizing query performance.
In our example, we configured the `service.name` tag for use in Pyroscope queries as the `service_name` label.
This configuration restricts the data set for lookup, ensuring that queries remain
consistently fast. Note that the tags you configure must be present in the span attributes or resources
for a trace to profiles span link to appear.

Please refer to our [documentation](https://grafana.com/docs/grafana/next/datasources/tempo/configure-tempo-data-source/#trace-to-profiles) for more details.
87 changes: 87 additions & 0 deletions examples/tracing/ruby/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
services:
pyroscope:
image: grafana/pyroscope
ports:
- "4040:4040"

us-east:
ports:
- "5000"
hostname: us-east
environment: &env
OTLP_URL: tempo:4318
OTLP_INSECURE: 1
DEBUG_LOGGER: 1
OTEL_LOG_LEVEL: debug
OTEL_TRACES_EXPORTER: otlp
OTEL_EXPORTER_OTLP_ENDPOINT: "http://tempo:4318"
OTEL_EXPORTER_OTLP_PROTOCOL: "http/protobuf"
OTEL_SDK_DEBUG: "true"
OTEL_SERVICE_NAME: rideshare.ruby.push.app
OTEL_METRICS_EXPORTER: none
OTEL_TRACES_SAMPLER: always_on
OTEL_PROPAGATORS: tracecontext
REGION: us-east
PYROSCOPE_LABELS: hostname=us-east
PYROSCOPE_SERVER_ADDRESS: http://pyroscope:4040
build:
context: .

eu-north:
ports:
- "5000"
hostname: eu-north
environment:
<<: *env
REGION: eu-north
PYROSCOPE_LABELS: hostname=eu-north
build:
context: .

ap-south:
ports:
- "5000"
hostname: ap-south
environment:
<<: *env
REGION: ap-south
PYROSCOPE_LABELS: hostname=ap-south
build:
context: .

load-generator:
environment: *env
build:
context: ../../language-sdk-instrumentation/golang-push/rideshare
dockerfile: Dockerfile.load-generator
command:
- ./loadgen
- http://us-east:5000
- http://eu-north:5000
- http://ap-south:5000

grafana:
image: grafana/grafana:latest
environment:
- GF_INSTALL_PLUGINS=grafana-pyroscope-app
- GF_AUTH_ANONYMOUS_ENABLED=true
- GF_AUTH_ANONYMOUS_ORG_ROLE=Admin
- GF_AUTH_DISABLE_LOGIN_FORM=true
- GF_FEATURE_TOGGLES_ENABLE=traceToProfiles tracesEmbeddedFlameGraph
volumes:
- ./grafana-provisioning:/etc/grafana/provisioning
ports:
- "3000:3000"

tempo:
image: grafana/tempo:latest
command: [ "-config.file=/etc/tempo.yml" ]
volumes:
- ./tempo/tempo.yml:/etc/tempo.yml
ports:
- "14268:14268" # jaeger ingest
- "3200:3200" # tempo
- "9095:9095" # tempo grpc
- "4317:4317" # otlp grpc
- "4318:4318" # otlp http
- "9411:9411" # zipkin
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
apiVersion: 1
datasources:
- name: Tempo
type: tempo
access: proxy
orgId: 1
url: http://tempo:3200
basicAuth: false
isDefault: true
version: 1
editable: false
apiVersion: 1
uid: tempo
jsonData:
httpMethod: GET
serviceMap:
datasourceUid: prometheus
tracesToProfiles:
customQuery: false
datasourceUid: "pyroscope"
profileTypeId: "process_cpu:cpu:nanoseconds:cpu:nanoseconds"
tags:
- key: "service.name"
value: "service_name"
- uid: pyroscope
type: grafana-pyroscope-datasource
name: Pyroscope
url: http://pyroscope:4040
jsonData:
keepCookies: [pyroscope_git_session]
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
apiVersion: 1
apps:
- type: grafana-pyroscope-app
jsonData:
backendUrl: http://pyroscope:4040
secureJsonData:
5 changes: 5 additions & 0 deletions examples/tracing/ruby/lib/bike/bike.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
require_relative '../utility/utility'

def order_bike(search_radius)
find_nearest_vehicle(search_radius, "bike")
end
5 changes: 5 additions & 0 deletions examples/tracing/ruby/lib/car/car.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
require_relative '../utility/utility'

def order_car(search_radius)
find_nearest_vehicle(search_radius, "car")
end
5 changes: 5 additions & 0 deletions examples/tracing/ruby/lib/scooter/scooter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
require_relative '../utility/utility'

def order_scooter(search_radius)
find_nearest_vehicle(search_radius, "scooter")
end
Loading

0 comments on commit 6f0a6cf

Please sign in to comment.