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

Add http client/server example #131

Merged
merged 4 commits into from
Nov 12, 2019
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
5 changes: 5 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ services:
context: .
working_dir: /app

ex-http:
<<: *base
command: ./start_server.sh
working_dir: /app/examples/http

sdk:
<<: *base
working_dir: /app/sdk
Expand Down
8 changes: 8 additions & 0 deletions examples/http/Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# frozen_string_literal: true

source "https://rubygems.org"

gem "faraday", "~> 0.16.1"
gem "opentelemetry-api", path: "../../api"
gem "opentelemetry-sdk", path: "../../sdk"
gem "sinatra", "~> 2.0"
39 changes: 39 additions & 0 deletions examples/http/Gemfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
PATH
remote: ../../api
specs:
opentelemetry-api (0.0.0)

PATH
remote: ../../sdk
specs:
opentelemetry-sdk (0.0.0)
opentelemetry-api (~> 0.0)

GEM
remote: https://rubygems.org/
specs:
faraday (0.16.2)
multipart-post (>= 1.2, < 3)
multipart-post (2.1.1)
mustermann (1.0.3)
rack (2.0.7)
rack-protection (2.0.7)
rack
sinatra (2.0.7)
mustermann (~> 1.0)
rack (~> 2.0)
rack-protection (= 2.0.7)
tilt (~> 2.0)
tilt (2.0.10)

PLATFORMS
ruby

DEPENDENCIES
faraday (~> 0.16.1)
opentelemetry-api!
opentelemetry-sdk!
sinatra (~> 2.0)

BUNDLED WITH
2.0.2
21 changes: 21 additions & 0 deletions examples/http/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# OpenTelemetry Ruby Example

## HTTP

This is a simple example that demonstrates tracing an HTTP request from client to server. The example shows several aspects of tracing, such as:

* Using the `TracerFactory`
* Span Attributes
* Using the console exporter

### Running the example

The example uses Docker Compose to make it a bit easier to get things up and running.

1. Follow the `Developer Setup` instructions in [the main README](../../README.md)
1. Run the server using the `ex-http` compose service
* `docker-compose run ex-http`
1. After a few seconds, an interactive shell should appear
1. Run the client
* `./client.rb`
1. You should see console exporter output for both the client and server sessions
49 changes: 49 additions & 0 deletions examples/http/client.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#!/usr/bin/env ruby
# frozen_string_literal: true

# Copyright 2019 OpenTelemetry Authors
#
# SPDX-License-Identifier: Apache-2.0
require 'rubygems'
require 'bundler/setup'
require 'faraday'
# Require otel-ruby
require 'opentelemetry/sdk'

# Allow setting the host from the ENV
host = ENV.fetch('HTTP_EXAMPLE_HOST', '0.0.0.0')

SDK = OpenTelemetry::SDK
OpenTelemetry.tracer_factory = SDK::Trace::TracerFactory.new
elskwid marked this conversation as resolved.
Show resolved Hide resolved

# Configure tracer
exporter = SDK::Trace::Export::ConsoleSpanExporter.new
processor = SDK::Trace::Export::SimpleSpanProcessor.new(exporter)
OpenTelemetry.tracer_factory.add_span_processor(processor)
tracer = OpenTelemetry.tracer_factory.tracer('faraday', 'semver:1.0')
formatter = OpenTelemetry.tracer_factory.http_text_format

connection = Faraday.new("http://#{host}:4567")
url = '/hello'

# For attribute naming, see:
# https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/data-semantic-conventions.md#http-client

# Span name should be set to URI path value:
tracer.in_span(
url,
attributes: {
'component' => 'http',
'http.method' => 'GET',
},
kind: :client
) do |span|
response = connection.get(url) do |request|
# Inject context into request headers
formatter.inject(span.context, request.headers)
end

span.set_attribute('http.url', response.env.url.to_s)
span.set_attribute('http.status_code', response.status)
span.set_attribute('http.status_text', response.reason_phrase)
end
73 changes: 73 additions & 0 deletions examples/http/server.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#!/usr/bin/env ruby
# frozen_string_literal: true

# Copyright 2019 OpenTelemetry Authors
#
# SPDX-License-Identifier: Apache-2.0

require 'rubygems'
require 'bundler/setup'
require 'sinatra/base'
# Require otel-ruby
require 'opentelemetry/sdk'

SDK = OpenTelemetry::SDK
OpenTelemetry.tracer_factory = SDK::Trace::TracerFactory.new

exporter = SDK::Trace::Export::ConsoleSpanExporter.new
processor = SDK::Trace::Export::SimpleSpanProcessor.new(exporter)
OpenTelemetry.tracer_factory.add_span_processor(processor)

# Rack middleware to extract span context, create child span, and add
# attributes/events to the span
class OpenTelemetryMiddleware
def initialize(app)
@app = app
@formatter = OpenTelemetry.tracer_factory.http_text_format
@tracer = OpenTelemetry.tracer_factory.tracer('sinatra', 'semver:1.0')
end

def call(env)
# Extract context from request headers
context = @formatter.extract(env)

status, headers, response_body = 200, {}, ''

# Span name SHOULD be set to route:
span_name = env['PATH_INFO']

# For attribute naming, see
# https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/data-semantic-conventions.md#http-server

# Span kind MUST be `:server` for a HTTP server span
@tracer.in_span(
span_name,
attributes: {
'component' => 'http',
'http.method' => env['REQUEST_METHOD'],
'http.route' => env['PATH_INFO'],
'http.url' => env['REQUEST_URI'],
},
kind: :server,
with_parent_context: context
) do |span|
# Run application stack
status, headers, response_body = @app.call(env)

span.set_attribute('http.status_code', status)
end

[status, headers, response_body]
end
end

class App < Sinatra::Base
set :bind, '0.0.0.0'
use OpenTelemetryMiddleware

get '/hello' do
'Hello World!'
fbogsany marked this conversation as resolved.
Show resolved Hide resolved
end

run! if app_file == $0
end
4 changes: 4 additions & 0 deletions examples/http/start_server.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#! /bin/bash

# Start the server, wait a bit, and provide a command line to run the client
./server.rb & (sleep 5; /bin/bash)
2 changes: 1 addition & 1 deletion sdk/lib/opentelemetry/sdk/trace/tracer_factory.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ module OpenTelemetry
module SDK
module Trace
# {TracerFactory} is the SDK implementation of {OpenTelemetry::Trace::TracerFactory}.
class TracerFactory
class TracerFactory < OpenTelemetry::Trace::TracerFactory
elskwid marked this conversation as resolved.
Show resolved Hide resolved
Key = Struct.new(:name, :version)
private_constant(:Key)

Expand Down