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

build: Github CI #1

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* @signalfx/gdi-ruby-maintainers @signalfx/gdi-ruby-approvers
50 changes: 50 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: Continuous Integration
on:
pull_request:
push:
branches:
- main
permissions: read-all

jobs:
unit-tests:
runs-on: ubuntu-latest
permissions: read-all
strategy:
fail-fast: false
matrix:
ruby: ['2.2.10', '2.5.9', '2.6.7', '2.7.4', '3.0.2']
rack: ['2.2', '2.1', '2.0', '1.6']
steps:
- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 1
- uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
- name: Fix rubygems/bundler # fixes https://github.com/rubygems/rubygems/issues/3284
if: ${{ matrix.ruby != '2.2.10' }}
run: gem update --system
- name: Install dependencies
run: bundle install
- name: Install appraisal dependencies
run: bundle exec appraisal install
- name: Test
run: bundle exec appraisal rack-${{ matrix.rack }} rake spec

# lint:
# if: ${{ github.event_name == 'pull_request' }}
# runs-on: ubuntu-latest
# permissions: read-all
# steps:
# - name: Checkout
# uses: actions/checkout@v2
# with:
# fetch-depth: 1
# - uses: ruby/setup-ruby@v1
# with:
# ruby-version: '3.0'
# bundler-cache: true # runs 'bundle install' and caches installed gems automatically
# - name: Test
# run: bundle exec rake rubocop
28 changes: 28 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,31 @@ Style/FrozenStringLiteralComment:
EnforcedStyle: always
Include:
- 'lib/**/*'

Metrics/CyclomaticComplexity:
Max: 7

Style/RedundantFreeze:
Enabled: no # TODO: reenable

Style/SafeNavigation:
Enabled: no # TODO: reenable

Gemspec/RequiredRubyVersion:
Enabled: no # doesn't apply because we're a library

RSpec/MultipleMemoizedHelpers:
Enabled: no # TODO: reenable

Lint/ConstantDefinitionInBlock:
Enabled: no # TODO: reenable

RSpec/LeakyConstantDeclaration:
Enabled: no # TODO: reenable

Style/StringConcatenation:
Enabled: no # TODO: reenable

Style/StringLiterals:
Exclude:
- 'gemfiles/**/*'
15 changes: 15 additions & 0 deletions Appraisals
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
appraise 'rack-2.2' do
gem 'rack', '~> 2.2.0'
end

appraise 'rack-2.1' do
gem 'rack', '~> 2.1.0'
end

appraise 'rack-2.0' do
gem 'rack', '~> 2.0.0'
end

appraise 'rack-1.6' do
gem 'rack', '~> 1.6.0'
end
7 changes: 4 additions & 3 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
require 'bundler/gem_tasks'
require 'rspec/core/rake_task'
require 'rubocop/rake_task'
# require 'rubocop/rake_task'

RSpec::Core::RakeTask.new(:spec)

RuboCop::RakeTask.new(:rubocop)
# RuboCop::RakeTask.new(:rubocop)

task default: %i[rubocop spec]
# task default: %i[rubocop spec]
task default: %i[spec]
2 changes: 2 additions & 0 deletions gemfiles/.bundle/config
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
BUNDLE_RETRY: "1"
1 change: 1 addition & 0 deletions gemfiles/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.gemfile.lock
7 changes: 7 additions & 0 deletions gemfiles/rack_1.6.gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# This file was generated by Appraisal

source "https://rubygems.org"

gem "rack", "~> 1.6.0"

gemspec path: "../"
7 changes: 7 additions & 0 deletions gemfiles/rack_2.0.gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# This file was generated by Appraisal

source "https://rubygems.org"

gem "rack", "~> 2.0.0"

gemspec path: "../"
7 changes: 7 additions & 0 deletions gemfiles/rack_2.1.gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# This file was generated by Appraisal

source "https://rubygems.org"

gem "rack", "~> 2.1.0"

gemspec path: "../"
7 changes: 7 additions & 0 deletions gemfiles/rack_2.2.gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# This file was generated by Appraisal

source "https://rubygems.org"

gem "rack", "~> 2.2.0"

gemspec path: "../"
40 changes: 35 additions & 5 deletions lib/rack/tracer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ module Rack
class Tracer
REQUEST_URI = 'REQUEST_URI'.freeze
REQUEST_METHOD = 'REQUEST_METHOD'.freeze
CORS_EXPOSE_HEADER = 'Access-Control-Expose-Headers'.freeze

# Create a new Rack Tracer middleware.
#
Expand Down Expand Up @@ -50,12 +51,18 @@ def call(env)

env['rack.span'] = span

@app.call(env).tap do |status_code, _headers, _body|
span.set_tag('http.status_code', status_code)
status_code, headers, body = @app.call(env)

route = route_from_env(env)
span.operation_name = route if route
end
span.set_tag('http.status_code', status_code)
route = route_from_env(env)
span.operation_name = route if route

# TODO: check if it needs to be conditioned on content-type
# TODO: docs
# TODO: config flag
attach_server_timing headers, span.context

[status_code, headers, body]
rescue *@errors => e
route = route_from_env(env)
span.operation_name = route if route
Expand Down Expand Up @@ -89,5 +96,28 @@ def grape_route_from_args(route_args)
rack_route_options[:path]
end
end

def attach_server_timing(headers, active_context)
version = '00'
trace_id = stringify_telemetry_id(active_context.trace_id).rjust(32, '0')
span_id = stringify_telemetry_id(active_context.span_id).rjust(16, '0')
flags = '01' # sampled
trace_parent = [version, trace_id, span_id, flags]
headers['Server-Timing'] = "traceparent;desc=\"#{trace_parent.join('-')}\""

# TODO: check if this needs to be conditioned on CORS
if (headers[CORS_EXPOSE_HEADER] || '').empty?
headers[CORS_EXPOSE_HEADER] = 'Server-Timing'
else
headers[CORS_EXPOSE_HEADER] = headers[CORS_EXPOSE_HEADER] + ', Server-Timing'
end
end

def stringify_telemetry_id(id)
return id.to_s(16) if (id.kind_of? Integer)
return id.to_s if (id.kind_of? Numeric)
return '' if id.nil?
id.to_s
end
end
end
13 changes: 7 additions & 6 deletions rack-tracer.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@ Gem::Specification.new do |spec|

spec.add_dependency 'opentracing', '~> 0.4'

spec.add_development_dependency 'bundler', '~> 2.1'
spec.add_development_dependency 'signalfx_test_tracer', '~> 0.1.3'
spec.add_development_dependency 'appraisal', '~> 2.4.1'
spec.add_development_dependency 'bundler'
spec.add_development_dependency 'rack', '~> 2.0'
spec.add_development_dependency 'rake', '~> 10.0'
spec.add_development_dependency 'rspec', '~> 3.0'
spec.add_development_dependency 'rubocop', '~> 0.54.0'
spec.add_development_dependency 'rubocop-rspec', '~> 1.24.0'
spec.add_development_dependency 'rake', '~> 13.0'
spec.add_development_dependency 'rspec', '~> 3.10'
# spec.add_development_dependency 'rubocop', '~> 1.19.1'
# spec.add_development_dependency 'rubocop-rspec', '~> 2.4.0'
spec.add_development_dependency 'signalfx_test_tracer', '~> 0.1.3'
end
16 changes: 16 additions & 0 deletions spec/rack/tracer_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,19 @@ class RouteInfo
end
end

shared_examples 'trace-parent' do
it 'exposes server-timing' do
_, headers = respond_with do |_env|
ok_response
end

span = tracer.spans.last
trace_id = span.context.trace_id.rjust(32, '0')
span_id = span.context.span_id.rjust(16, '0')
expect(headers['Server-Timing']).to eq "traceparent;desc=\"00-#{trace_id}-#{span_id}-01\""
end
end

context 'when a new request' do
it 'starts a new trace' do
respond_with { ok_response }
Expand Down Expand Up @@ -136,6 +149,7 @@ class RouteInfo
end

include_examples 'calls on_start_span and on_finish_span callbacks'
include_examples 'trace-parent'
end

context 'when already traced request' do
Expand Down Expand Up @@ -173,6 +187,7 @@ class RouteInfo
end

include_examples 'calls on_start_span and on_finish_span callbacks'
include_examples 'trace-parent'
end

context 'when already traced but untrusted request' do
Expand All @@ -195,6 +210,7 @@ class RouteInfo
end

include_examples 'calls on_start_span and on_finish_span callbacks'
include_examples 'trace-parent'
end

context 'when an exception bubbles-up through the middlewares' do
Expand Down