Skip to content

Commit

Permalink
feat: OTel Railtie (#1111)
Browse files Browse the repository at this point in the history
* feat: OTel Railtie

This gem provides a minimal Railtie to use in lieu of manual configuration.

Operators may customize SDK settings using environment variables but this gem will provide some defaults:

Sets a minimal set of values for OTEL_SERVICE_NAME and OTEL_RESOURCE_ATTRIBUTES when left unset
Users may override SDK configurations using standard OTel SDK environment variables
Users may override Instrumentation libraries are configurable using OTEL_RUBY_*_CONFIG_OPTS
  • Loading branch information
arielvalentin authored Mar 23, 2022
1 parent f551fe4 commit dc25f73
Show file tree
Hide file tree
Showing 44 changed files with 619 additions and 13 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,5 @@ instrumentation/active_record/db

# rbenv configuration
.ruby-version

tags
8 changes: 8 additions & 0 deletions instrumentation/rails/.rubocop.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
inherit_from: ../.rubocop-examples.yml

AllCops:
Exclude:
- test/railtie/dummy/**/*
- gemfiles/*.gemfilqe

Metrics/BlockLength:
Enabled: false
Naming/FileName:
Exclude:
- "lib/opentelemetry-instrumentation-rails.rb"
Style/ClassAndModuleChildren:
Exclude:
- test/railtie/**/*
20 changes: 13 additions & 7 deletions instrumentation/rails/Appraisals
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,22 @@ if RUBY_VERSION < '3'
end
end

appraise 'rails-6.0' do
gem 'rails', '~> 6.0.0'
end
if Gem::Requirement.new('>= 2.7.0', '< 3.1').satisfied_by?(Gem::Version.new(RUBY_VERSION))
appraise 'rails-6.0' do
gem 'rails', '~> 6.0.0'
end

appraise 'rails-6.1' do
gem 'rails', '~> 6.1.0'
end
appraise 'rails-6.1' do
gem 'rails', '~> 6.1.0'
end

if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.7.0')
appraise 'rails-7.0' do
gem 'rails', '~> 7.0.0'
end
end

if Gem::Requirement.new('>= 3.1').satisfied_by?(Gem::Version.new(RUBY_VERSION))
appraise 'rails-7.0.ruby.3.1' do
gem 'rails', '~> 7.0.1'
end
end
19 changes: 15 additions & 4 deletions instrumentation/rails/Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,23 @@ require 'rubocop/rake_task'

RuboCop::RakeTask.new

Rake::TestTask.new :test do |t|
t.libs << 'test'
t.libs << 'lib'
t.test_files = FileList['test/**/*_test.rb']
namespace :test do
Rake::TestTask.new :instrumentation do |t|
t.libs << 'lib'
t.libs << 'test/instrumentation'
t.test_files = FileList['test/instrumentation/**/*_test.rb']
end

Rake::TestTask.new :railtie do |t|
t.libs << 'lib'
t.libs << 'test/railtie'
t.test_files = FileList['test/railtie/**/*_test.rb']
end
end

desc 'Run all tests'
task test: %i[test:instrumentation test:railtie]

YARD::Rake::YardocTask.new do |t|
t.stats_options = ['--list-undoc']
end
Expand Down
1 change: 1 addition & 0 deletions instrumentation/rails/gemfiles/rails_5.2.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ group :test do
gem "opentelemetry-instrumentation-action_pack", path: "../../../instrumentation/action_pack"
gem "opentelemetry-instrumentation-action_view", path: "../../../instrumentation/action_view"
gem "opentelemetry-instrumentation-active_record", path: "../../../instrumentation/active_record"
gem "opentelemetry-instrumentation-active_support", path: "../../../instrumentation/active_support"
gem "opentelemetry-instrumentation-rack", path: "../../../instrumentation/rack"
gem "opentelemetry-sdk", path: "../../../sdk"
gem "opentelemetry-semantic_conventions", path: "../../../semantic_conventions"
Expand Down
1 change: 1 addition & 0 deletions instrumentation/rails/gemfiles/rails_6.0.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ group :test do
gem "opentelemetry-instrumentation-action_pack", path: "../../../instrumentation/action_pack"
gem "opentelemetry-instrumentation-action_view", path: "../../../instrumentation/action_view"
gem "opentelemetry-instrumentation-active_record", path: "../../../instrumentation/active_record"
gem "opentelemetry-instrumentation-active_support", path: "../../../instrumentation/active_support"
gem "opentelemetry-instrumentation-rack", path: "../../../instrumentation/rack"
gem "opentelemetry-sdk", path: "../../../sdk"
gem "opentelemetry-semantic_conventions", path: "../../../semantic_conventions"
Expand Down
1 change: 1 addition & 0 deletions instrumentation/rails/gemfiles/rails_6.1.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ group :test do
gem "opentelemetry-instrumentation-action_pack", path: "../../../instrumentation/action_pack"
gem "opentelemetry-instrumentation-action_view", path: "../../../instrumentation/action_view"
gem "opentelemetry-instrumentation-active_record", path: "../../../instrumentation/active_record"
gem "opentelemetry-instrumentation-active_support", path: "../../../instrumentation/active_support"
gem "opentelemetry-instrumentation-rack", path: "../../../instrumentation/rack"
gem "opentelemetry-sdk", path: "../../../sdk"
gem "opentelemetry-semantic_conventions", path: "../../../semantic_conventions"
Expand Down
3 changes: 2 additions & 1 deletion instrumentation/rails/gemfiles/rails_7.0.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ source "https://rubygems.org"

gem "opentelemetry-api", path: "../../../api"
gem "opentelemetry-instrumentation-base", path: "../../base"
gem "rails", "~> 7.0.0.alpha2"
gem "rails", "~> 7.0.0"

group :test do
gem "byebug"
gem "opentelemetry-common", path: "../../../common"
gem "opentelemetry-instrumentation-action_pack", path: "../../../instrumentation/action_pack"
gem "opentelemetry-instrumentation-action_view", path: "../../../instrumentation/action_view"
gem "opentelemetry-instrumentation-active_record", path: "../../../instrumentation/active_record"
gem "opentelemetry-instrumentation-active_support", path: "../../../instrumentation/active_support"
gem "opentelemetry-instrumentation-rack", path: "../../../instrumentation/rack"
gem "opentelemetry-sdk", path: "../../../sdk"
gem "opentelemetry-semantic_conventions", path: "../../../semantic_conventions"
Expand Down
22 changes: 22 additions & 0 deletions instrumentation/rails/gemfiles/rails_7.0.ruby.3.1.gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# This file was generated by Appraisal

source "https://rubygems.org"

gem "opentelemetry-api", path: "../../../api"
gem "opentelemetry-instrumentation-base", path: "../../base"
gem "rails", "~> 7.0.1"

group :test do
gem "byebug"
gem "opentelemetry-common", path: "../../../common"
gem "opentelemetry-instrumentation-action_pack", path: "../../../instrumentation/action_pack"
gem "opentelemetry-instrumentation-action_view", path: "../../../instrumentation/action_view"
gem "opentelemetry-instrumentation-active_record", path: "../../../instrumentation/active_record"
gem "opentelemetry-instrumentation-active_support", path: "../../../instrumentation/active_support"
gem "opentelemetry-instrumentation-rack", path: "../../../instrumentation/rack"
gem "opentelemetry-sdk", path: "../../../sdk"
gem "opentelemetry-semantic_conventions", path: "../../../semantic_conventions"
gem "pry-byebug"
end

gemspec path: "../"
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# frozen_string_literal: true

# Copyright The OpenTelemetry Authors
#
# SPDX-License-Identifier: Apache-2.0
module OpenTelemetry
module Instrumentation
module Rails
# Railtie automatically configure the OpentTelemetry SDK
#
# This railtie will set defaults for the following environment variables:
# `OTEL_SERVICE_NAME` - if unset, will default to the Rails application name
# `OTEL_RESOURCE_ATTRIBUTES` - if unset, will set the deployment environment to the current Rails environment
#
# This will also set the `OpenTelemetry.logger` to the Rails logger.
class Railtie < ::Rails::Railtie
railtie_name :opentelemetry
initializer 'opentelemetry.configure' do |app|
# See https://api.rubyonrails.org/classes/Rails/Generators/NamedBase.html#method-i-application_name
ENV['OTEL_SERVICE_NAME'] ||= app.class.name.split('::').first.underscore

::OpenTelemetry::SDK.configure do |c|
c.logger = ::Rails.logger
c.use_all
end
end
end
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@
require 'rack/test'
require 'test_helpers/app_config.rb'

require_relative '../lib/opentelemetry/instrumentation'
require_relative '../../lib/opentelemetry/instrumentation'

# Global opentelemetry-sdk setup
EXPORTER = OpenTelemetry::SDK::Trace::Export::InMemorySpanExporter.new
span_processor = OpenTelemetry::SDK::Trace::Export::SimpleSpanProcessor.new(EXPORTER)

OpenTelemetry::SDK.configure do |c|
c.logger = ::Logger.new(File::NULL)
c.use_all
c.add_span_processor span_processor
end
Expand Down
6 changes: 6 additions & 0 deletions instrumentation/rails/test/railtie/dummy/Rakefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Add your own tasks in files placed in lib/tasks ending in .rake,
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.

require_relative "config/application"

Rails.application.load_tasks
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
class ApplicationController < ActionController::API
end
Empty file.
4 changes: 4 additions & 0 deletions instrumentation/rails/test/railtie/dummy/bin/rails
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env ruby
APP_PATH = File.expand_path("../config/application", __dir__)
require_relative "../config/boot"
require "rails/commands"
4 changes: 4 additions & 0 deletions instrumentation/rails/test/railtie/dummy/bin/rake
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env ruby
require_relative "../config/boot"
require "rake"
Rake.application.run
33 changes: 33 additions & 0 deletions instrumentation/rails/test/railtie/dummy/bin/setup
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/usr/bin/env ruby
require "fileutils"

# path to your application root.
APP_ROOT = File.expand_path("..", __dir__)

def system!(*args)
system(*args) || abort("\n== Command #{args} failed ==")
end

FileUtils.chdir APP_ROOT do
# This script is a way to set up or update your development environment automatically.
# This script is idempotent, so that you can run it at any time and get an expectable outcome.
# Add necessary setup steps to this file.

puts "== Installing dependencies =="
system! "gem install bundler --conservative"
system("bundle check") || system!("bundle install")

# puts "\n== Copying sample files =="
# unless File.exist?("config/database.yml")
# FileUtils.cp "config/database.yml.sample", "config/database.yml"
# end

puts "\n== Preparing database =="
system! "bin/rails db:prepare"

puts "\n== Removing old logs and tempfiles =="
system! "bin/rails log:clear tmp:clear"

puts "\n== Restarting application server =="
system! "bin/rails restart"
end
6 changes: 6 additions & 0 deletions instrumentation/rails/test/railtie/dummy/config.ru
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# This file is used by Rack-based servers to start the application.

require_relative "config/environment"

run Rails.application
Rails.application.load_server
37 changes: 37 additions & 0 deletions instrumentation/rails/test/railtie/dummy/config/application.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
require_relative "boot"

require "rails"
# Pick the frameworks you want:
require "active_model/railtie"
require "active_job/railtie"
# require "active_record/railtie"
# require "active_storage/engine"
require "action_controller/railtie"
# require "action_mailer/railtie"
# require "action_mailbox/engine"
# require "action_text/engine"
require "action_view/railtie"
# require "action_cable/engine"
# require "sprockets/railtie"
require "rails/test_unit/railtie"

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)
require "opentelemetry/instrumentation/rails/railtie"

module Dummy
class Application < Rails::Application
config.load_defaults Rails::VERSION::STRING.to_f

# Configuration for the application, engines, and railties goes here.
#
# These settings can be overridden in specific environments using the files
# in config/environments, which are processed later.
#
# config.time_zone = "Central Time (US & Canada)"
# config.eager_load_paths << Rails.root.join("extras")
config.logger = ActiveSupport::TaggedLogging.new(ActiveSupport::Logger.new(File::NULL))
config.api_only = true
end
end
5 changes: 5 additions & 0 deletions instrumentation/rails/test/railtie/dummy/config/boot.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Set up gems listed in the Gemfile.
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../../Gemfile", __dir__)

require "bundler/setup" if File.exist?(ENV["BUNDLE_GEMFILE"])
$LOAD_PATH.unshift File.expand_path("../../../lib", __dir__)
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Load the Rails application.
require_relative "application"

# Initialize the Rails application.
Rails.application.initialize!
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
require "active_support/core_ext/integer/time"

Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.

# In the development environment your application's code is reloaded any time
# it changes. This slows down response time but is perfect for development
# since you don't have to restart the web server when you make code changes.
config.cache_classes = false

# Do not eager load code on boot.
config.eager_load = false

# Show full error reports.
config.consider_all_requests_local = true

# Enable server timing
config.server_timing = true

# Enable/disable caching. By default caching is disabled.
# Run rails dev:cache to toggle caching.
if Rails.root.join("tmp/caching-dev.txt").exist?
config.action_controller.perform_caching = true
config.action_controller.enable_fragment_cache_logging = true

config.cache_store = :memory_store
config.public_file_server.headers = {
"Cache-Control" => "public, max-age=#{2.days.to_i}"
}
else
config.action_controller.perform_caching = false

config.cache_store = :null_store
end

# Store uploaded files on the local file system (see config/storage.yml for options).
config.active_storage.service = :local

# Don't care if the mailer can't send.
config.action_mailer.raise_delivery_errors = false

config.action_mailer.perform_caching = false

# Print deprecation notices to the Rails logger.
config.active_support.deprecation = :log

# Raise exceptions for disallowed deprecations.
config.active_support.disallowed_deprecation = :raise

# Tell Active Support which deprecation messages to disallow.
config.active_support.disallowed_deprecation_warnings = []

# Raise an error on page load if there are pending migrations.
config.active_record.migration_error = :page_load

# Highlight code that triggered database queries in logs.
config.active_record.verbose_query_logs = true


# Raises error for missing translations.
# config.i18n.raise_on_missing_translations = true

# Annotate rendered view with file names.
# config.action_view.annotate_rendered_view_with_filenames = true

# Uncomment if you wish to allow Action Cable access from any origin.
# config.action_cable.disable_request_forgery_protection = true
end
Loading

0 comments on commit dc25f73

Please sign in to comment.