Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

examples: add ruby span profiling #3780

Merged
merged 1 commit into from
Dec 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading