├── .gitignore ├── .travis.yml ├── Gemfile ├── Gemfile.lock ├── Guardfile ├── LICENSE.txt ├── README.md ├── Rakefile ├── bin ├── console └── setup ├── integration ├── multiverse │ ├── grape-on-rack │ │ ├── .gitignore │ │ ├── .rspec │ │ ├── .rubocop.yml │ │ ├── .rubocop_todo.yml │ │ ├── .travis.yml │ │ ├── Gemfile │ │ ├── Gemfile.lock │ │ ├── Guardfile │ │ ├── LICENSE │ │ ├── README.md │ │ ├── Rakefile │ │ ├── api │ │ │ ├── content_type.rb │ │ │ ├── entities.rb │ │ │ ├── get_json.rb │ │ │ ├── header_versioning.rb │ │ │ ├── path_versioning.rb │ │ │ ├── ping.rb │ │ │ ├── post_json.rb │ │ │ ├── post_put.rb │ │ │ ├── rescue_from.rb │ │ │ ├── upload_file.rb │ │ │ ├── wrap_response.rb │ │ │ └── wrap_response_decorator.rb │ │ ├── app │ │ │ ├── acme_app.rb │ │ │ └── api.rb │ │ ├── config.ru │ │ ├── config │ │ │ ├── application.rb │ │ │ ├── boot.rb │ │ │ ├── environment.rb │ │ │ └── newrelic.yml │ │ ├── public │ │ │ ├── errors │ │ │ │ ├── 404.html │ │ │ │ └── 500.html │ │ │ ├── images │ │ │ │ ├── index.html │ │ │ │ └── rack-logo.png │ │ │ ├── index.html │ │ │ └── scripts │ │ │ │ ├── jquery-1.7.1.min.js │ │ │ │ └── ring.js │ │ └── spec │ │ │ ├── api │ │ │ └── post_put_spec.rb │ │ │ ├── fixtures │ │ │ └── grape_logo.png │ │ │ └── spec_helper.rb │ ├── grape-on-rails │ │ ├── .gitignore │ │ ├── .rspec │ │ ├── .rubocop.yml │ │ ├── .rubocop_todo.yml │ │ ├── .travis.yml │ │ ├── Gemfile │ │ ├── Gemfile.lock │ │ ├── README.md │ │ ├── Rakefile │ │ ├── app │ │ │ ├── api │ │ │ │ ├── acme │ │ │ │ │ ├── ping.rb │ │ │ │ │ ├── post.rb │ │ │ │ │ ├── protected.rb │ │ │ │ │ └── raise.rb │ │ │ │ └── api.rb │ │ │ ├── assets │ │ │ │ ├── images │ │ │ │ │ └── rails.png │ │ │ │ ├── javascripts │ │ │ │ │ ├── application.js │ │ │ │ │ └── welcome.js.coffee │ │ │ │ └── stylesheets │ │ │ │ │ ├── application.css │ │ │ │ │ └── welcome.css.scss │ │ │ ├── controllers │ │ │ │ ├── application_controller.rb │ │ │ │ └── welcome_controller.rb │ │ │ ├── helpers │ │ │ │ ├── application_helper.rb │ │ │ │ └── welcome_helper.rb │ │ │ ├── mailers │ │ │ │ └── .gitkeep │ │ │ ├── models │ │ │ │ └── .gitkeep │ │ │ └── views │ │ │ │ ├── layouts │ │ │ │ └── application.html.erb │ │ │ │ └── welcome │ │ │ │ └── index.html.erb │ │ ├── bin │ │ │ ├── bundle │ │ │ ├── rails │ │ │ └── rake │ │ ├── config.ru │ │ ├── config │ │ │ ├── application.rb │ │ │ ├── boot.rb │ │ │ ├── database.travis.yml │ │ │ ├── database.yml │ │ │ ├── environment.rb │ │ │ ├── environments │ │ │ │ ├── development.rb │ │ │ │ ├── production.rb │ │ │ │ └── test.rb │ │ │ ├── initializers │ │ │ │ ├── backtrace_silencers.rb │ │ │ │ ├── inflections.rb │ │ │ │ ├── mime_types.rb │ │ │ │ ├── reload_api.rb │ │ │ │ ├── secret_token.rb │ │ │ │ ├── session_store.rb │ │ │ │ ├── vitals.rb │ │ │ │ └── wrap_parameters.rb │ │ │ ├── locales │ │ │ │ └── en.yml │ │ │ └── routes.rb │ │ ├── db │ │ │ ├── schema.rb │ │ │ └── seeds.rb │ │ ├── doc │ │ │ └── README_FOR_APP │ │ ├── lib │ │ │ ├── assets │ │ │ │ └── .gitkeep │ │ │ └── tasks │ │ │ │ └── .gitkeep │ │ ├── log │ │ │ └── .gitkeep │ │ ├── public │ │ │ ├── 404.html │ │ │ ├── 422.html │ │ │ ├── 500.html │ │ │ ├── favicon.ico │ │ │ └── robots.txt │ │ ├── script │ │ │ └── rails │ │ └── spec │ │ │ ├── api │ │ │ └── ping_spec.rb │ │ │ └── spec_helper.rb │ └── rails42_app │ │ ├── .gitignore │ │ ├── Gemfile │ │ ├── Gemfile.lock │ │ ├── README.rdoc │ │ ├── Rakefile │ │ ├── app │ │ ├── assets │ │ │ ├── images │ │ │ │ └── .keep │ │ │ ├── javascripts │ │ │ │ ├── application.js │ │ │ │ └── posts.coffee │ │ │ └── stylesheets │ │ │ │ ├── application.css │ │ │ │ ├── posts.scss │ │ │ │ └── scaffolds.scss │ │ ├── controllers │ │ │ ├── application_controller.rb │ │ │ ├── concerns │ │ │ │ └── .keep │ │ │ └── posts_controller.rb │ │ ├── helpers │ │ │ ├── application_helper.rb │ │ │ └── posts_helper.rb │ │ ├── jobs │ │ │ └── foobar_cleanup_job.rb │ │ ├── mailers │ │ │ └── .keep │ │ ├── models │ │ │ ├── .keep │ │ │ ├── concerns │ │ │ │ └── .keep │ │ │ └── post.rb │ │ └── views │ │ │ ├── layouts │ │ │ └── application.html.erb │ │ │ └── posts │ │ │ ├── _form.html.erb │ │ │ ├── edit.html.erb │ │ │ ├── index.html.erb │ │ │ ├── index.json.jbuilder │ │ │ ├── new.html.erb │ │ │ ├── show.html.erb │ │ │ └── show.json.jbuilder │ │ ├── bin │ │ ├── bundle │ │ ├── rails │ │ ├── rake │ │ ├── setup │ │ └── spring │ │ ├── config.ru │ │ ├── config │ │ ├── application.rb │ │ ├── boot.rb │ │ ├── database.yml │ │ ├── environment.rb │ │ ├── environments │ │ │ ├── development.rb │ │ │ ├── production.rb │ │ │ └── test.rb │ │ ├── initializers │ │ │ ├── assets.rb │ │ │ ├── backtrace_silencers.rb │ │ │ ├── cookies_serializer.rb │ │ │ ├── filter_parameter_logging.rb │ │ │ ├── inflections.rb │ │ │ ├── mime_types.rb │ │ │ ├── session_store.rb │ │ │ ├── vitals.rb │ │ │ └── wrap_parameters.rb │ │ ├── locales │ │ │ └── en.yml │ │ ├── routes.rb │ │ └── secrets.yml │ │ ├── db │ │ ├── migrate │ │ │ └── 20160321140358_create_posts.rb │ │ ├── schema.rb │ │ └── seeds.rb │ │ ├── lib │ │ ├── assets │ │ │ └── .keep │ │ └── tasks │ │ │ └── .keep │ │ ├── log │ │ └── .keep │ │ ├── public │ │ ├── 404.html │ │ ├── 422.html │ │ ├── 500.html │ │ ├── favicon.ico │ │ └── robots.txt │ │ └── test │ │ ├── controllers │ │ ├── .keep │ │ └── posts_controller_test.rb │ │ ├── fixtures │ │ ├── .keep │ │ └── posts.yml │ │ ├── helpers │ │ └── .keep │ │ ├── integration │ │ ├── .keep │ │ └── vitals_flow_test.rb │ │ ├── jobs │ │ └── foobar_cleanup_job_test.rb │ │ ├── mailers │ │ └── .keep │ │ ├── models │ │ ├── .keep │ │ └── post_test.rb │ │ └── test_helper.rb ├── multiverse_helper.rb └── multiverse_spec.rb ├── lib ├── vitals.rb └── vitals │ ├── configuration.rb │ ├── formats │ ├── host_last_format.rb │ ├── no_host_format.rb │ └── production_format.rb │ ├── integrations │ ├── notifications │ │ ├── action_controller.rb │ │ ├── active_job.rb │ │ ├── base.rb │ │ └── grape.rb │ └── rack │ │ └── requests.rb │ ├── reporters │ ├── base_reporter.rb │ ├── console_reporter.rb │ ├── dns_resolving_statsd_reporter.rb │ ├── inmem_reporter.rb │ ├── multi_reporter.rb │ └── statsd_reporter.rb │ ├── utils.rb │ └── version.rb ├── spec ├── spec_helper.rb ├── vitals │ ├── configuration_spec.rb │ ├── formats │ │ ├── host_last_format_spec.rb │ │ ├── no_host_format_spec.rb │ │ └── production_format_spec.rb │ ├── integrations │ │ ├── notifications │ │ │ ├── action_controller_spec.rb │ │ │ ├── active_job_spec.rb │ │ │ └── grape_spec.rb │ │ └── rack │ │ │ ├── rails_spec.rb │ │ │ └── requests_spec.rb │ ├── reporters │ │ ├── base_reporter_spec.rb │ │ ├── console_reporter_spec.rb │ │ ├── dns_resolving_statsd_reporter_spec.rb │ │ ├── multi_reporter_spec.rb │ │ └── statsd_reporter_spec.rb │ ├── utils_bench.rb │ └── utils_spec.rb └── vitals_spec.rb └── vitals.gemspec /.gitignore: -------------------------------------------------------------------------------- 1 | .bundle/ 2 | log/*.log 3 | pkg/ 4 | test/dummy/db/*.sqlite3 5 | test/dummy/log/*.log 6 | test/dummy/tmp/coverage/ 7 | coverage/ 8 | .byebug_history 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: ruby 3 | rvm: 4 | - 2.1.0 5 | - 2.2.0 6 | - 2.3.0 7 | # - ruby-head 8 | # use latest bundler because of ruby-head exposing a bundler bug. 9 | # see https://github.com/bundler/bundler/pull/3559 10 | # So, that didn't work. so let's not use ruby-head for a while 11 | before_install: gem install bundler 12 | matrix: 13 | include: 14 | - rvm: 2.3.0 15 | script: bundle exec rake multiverse 16 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in vitals.gemspec 4 | gemspec 5 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: . 3 | specs: 4 | vitals (0.12.0) 5 | statsd-ruby (~> 1.3.0) 6 | 7 | GEM 8 | remote: https://rubygems.org/ 9 | specs: 10 | activesupport (4.2.6) 11 | i18n (~> 0.7) 12 | json (~> 1.7, >= 1.7.7) 13 | minitest (~> 5.1) 14 | thread_safe (~> 0.3, >= 0.3.4) 15 | tzinfo (~> 1.1) 16 | ast (2.2.0) 17 | axiom-types (0.1.1) 18 | descendants_tracker (~> 0.0.4) 19 | ice_nine (~> 0.11.0) 20 | thread_safe (~> 0.3, >= 0.3.1) 21 | benchmark-ips (2.5.0) 22 | benchmark-ipsa (0.2.0) 23 | benchmark-ips (~> 2.5.0) 24 | memory_profiler (~> 0.9.6) 25 | builder (3.2.2) 26 | byebug (8.2.2) 27 | coderay (1.1.1) 28 | coercible (1.0.0) 29 | descendants_tracker (~> 0.0.1) 30 | coveralls (0.8.13) 31 | json (~> 1.8) 32 | simplecov (~> 0.11.0) 33 | term-ansicolor (~> 1.3) 34 | thor (~> 0.19.1) 35 | tins (~> 1.6.0) 36 | descendants_tracker (0.0.4) 37 | thread_safe (~> 0.3, >= 0.3.1) 38 | docile (1.1.5) 39 | equalizer (0.0.11) 40 | ffi (1.9.10) 41 | formatador (0.2.5) 42 | grape (0.15.0) 43 | activesupport 44 | builder 45 | hashie (>= 2.1.0) 46 | multi_json (>= 1.3.2) 47 | multi_xml (>= 0.5.2) 48 | rack (>= 1.3.0) 49 | rack-accept 50 | rack-mount 51 | virtus (>= 1.0.0) 52 | guard (2.13.0) 53 | formatador (>= 0.2.4) 54 | listen (>= 2.7, <= 4.0) 55 | lumberjack (~> 1.0) 56 | nenv (~> 0.1) 57 | notiffany (~> 0.0) 58 | pry (>= 0.9.12) 59 | shellany (~> 0.0) 60 | thor (>= 0.18.1) 61 | guard-compat (1.2.1) 62 | guard-minitest (2.4.4) 63 | guard-compat (~> 1.2) 64 | minitest (>= 3.0) 65 | guard-rubocop (1.2.0) 66 | guard (~> 2.0) 67 | rubocop (~> 0.20) 68 | hashie (3.4.3) 69 | i18n (0.7.0) 70 | ice_nine (0.11.2) 71 | json (1.8.3) 72 | listen (3.0.6) 73 | rb-fsevent (>= 0.9.3) 74 | rb-inotify (>= 0.9.7) 75 | lumberjack (1.0.10) 76 | memory_profiler (0.9.6) 77 | method_source (0.8.2) 78 | minitest (5.8.4) 79 | multi_json (1.11.2) 80 | multi_xml (0.5.5) 81 | nenv (0.3.0) 82 | notiffany (0.0.8) 83 | nenv (~> 0.1) 84 | shellany (~> 0.0) 85 | parser (2.3.0.7) 86 | ast (~> 2.2) 87 | powerpack (0.1.1) 88 | pry (0.10.3) 89 | coderay (~> 1.1.0) 90 | method_source (~> 0.8.1) 91 | slop (~> 3.4) 92 | rack (1.6.4) 93 | rack-accept (0.4.5) 94 | rack (>= 0.4) 95 | rack-mount (0.8.3) 96 | rack (>= 1.0.0) 97 | rack-protection (1.5.3) 98 | rack 99 | rack-test (0.6.3) 100 | rack (>= 1.0) 101 | rainbow (2.1.0) 102 | rake (10.5.0) 103 | rb-fsevent (0.9.7) 104 | rb-inotify (0.9.7) 105 | ffi (>= 0.5.0) 106 | rr (1.1.2) 107 | rubocop (0.39.0) 108 | parser (>= 2.3.0.7, < 3.0) 109 | powerpack (~> 0.1) 110 | rainbow (>= 1.99.1, < 3.0) 111 | ruby-progressbar (~> 1.7) 112 | unicode-display_width (~> 1.0, >= 1.0.1) 113 | ruby-progressbar (1.7.5) 114 | shellany (0.0.1) 115 | simplecov (0.11.2) 116 | docile (~> 1.1.0) 117 | json (~> 1.8) 118 | simplecov-html (~> 0.10.0) 119 | simplecov-html (0.10.0) 120 | sinatra (1.4.7) 121 | rack (~> 1.5) 122 | rack-protection (~> 1.4) 123 | tilt (>= 1.3, < 3) 124 | slop (3.6.0) 125 | statsd-ruby (1.3.0) 126 | term-ansicolor (1.3.2) 127 | tins (~> 1.0) 128 | thor (0.19.1) 129 | thread_safe (0.3.5) 130 | tilt (2.0.2) 131 | tins (1.6.0) 132 | tzinfo (1.2.2) 133 | thread_safe (~> 0.1) 134 | unicode-display_width (1.0.3) 135 | virtus (1.0.5) 136 | axiom-types (~> 0.1) 137 | coercible (~> 1.0) 138 | descendants_tracker (~> 0.0, >= 0.0.3) 139 | equalizer (~> 0.0, >= 0.0.9) 140 | 141 | PLATFORMS 142 | ruby 143 | 144 | DEPENDENCIES 145 | activesupport (~> 4.2.6) 146 | benchmark-ipsa (~> 0.2.0) 147 | bundler (~> 1.11) 148 | byebug (~> 8.2.2) 149 | coveralls (~> 0.8.13) 150 | grape (~> 0.15.0) 151 | guard-minitest (~> 2.4.4) 152 | guard-rubocop (~> 1.2.0) 153 | minitest (~> 5.0) 154 | rack-test (~> 0.6.3) 155 | rake (~> 10.0) 156 | rr (~> 1.1.2) 157 | sinatra (~> 1.4.7) 158 | vitals! 159 | 160 | BUNDLED WITH 161 | 1.13.2 162 | -------------------------------------------------------------------------------- /Guardfile: -------------------------------------------------------------------------------- 1 | guard :minitest do 2 | # with Minitest::Spec 3 | watch(%r{^spec/(.*)_spec\.rb$}) 4 | watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" } 5 | watch(%r{^spec/spec_helper\.rb$}) { 'spec' } 6 | end 7 | 8 | #guard :rubocop do 9 | # watch(%r{.+\.rb$}) 10 | # watch(%r{(?:.+/)?\.rubocop\.yml$}) { |m| File.dirname(m[0]) } 11 | #end 12 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Dotan Nahum 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Vitals 2 | 3 | [![Build Status](https://travis-ci.org/jondot/vitals.svg?branch=master)](https://travis-ci.org/jondot/vitals.svg) 4 | [![Coverage Status](https://coveralls.io/repos/github/jondot/vitals/badge.svg?branch=master)](https://coveralls.io/github/jondot/vitals?branch=master) 5 | 6 | Vitals is your one stop shop for metrics in Ruby and Ruby Web and API 7 | frameworks. It currently support Rails, Rack (Sinatra and any Rack-supported 8 | frameworks), and Grape. 9 | 10 | 11 | ## Installation 12 | 13 | Add this line to your application's Gemfile: 14 | 15 | ```ruby 16 | gem 'vitals' 17 | ``` 18 | 19 | And then execute: 20 | 21 | $ bundle 22 | 23 | Or install it yourself as: 24 | 25 | $ gem install vitals 26 | 27 | ## Usage 28 | 29 | ### Rails or Grape 30 | 31 | Make an `initializers/vitals.rb` initializer, and configure Vitals as you'd like: 32 | ```ruby 33 | require 'vitals' 34 | Vitals.configure! do |c| 35 | c.facility = 'my_service' 36 | c.reporter = Vitals::Reporters::StatsdReporter.new(host: 'statsd-host', port: 8125) 37 | end 38 | 39 | # 40 | # Rails 41 | # 42 | require 'vitals/integrations/notifications/action_controller' 43 | Vitals::Integrations::Notifications::ActionController.subscribe! 44 | 45 | # if you also want ActiveJob metrics 46 | require 'vitals/integrations/notifications/action_job' 47 | Vitals::Integrations::Notifications::ActiveJob.subscribe! 48 | 49 | 50 | # 51 | # Grape 52 | # 53 | require 'vitals/integrations/notifications/grape' 54 | Vitals::Integrations::Notifications::Grape.subscribe! 55 | ``` 56 | 57 | You can shortcircuit the notifications configuration by using `subscribe!` right after configuring: 58 | 59 | ```ruby 60 | require 'vitals' 61 | Vitals.configure! do |c| 62 | c.facility = 'my_service' 63 | c.reporter = Vitals::Reporters::StatsdReporter.new(host: 'statsd-host', port: 8125) 64 | end 65 | # Subscribe to Rails' controllers, background jobs, and grape's API controllers 66 | Vitals.subscribe!(:action_controller, :active_job, :grape) 67 | ``` 68 | 69 | ### Rack 70 | 71 | You can use the `Requests` middleware for pure Rack apps or Sinatra, Rails, and Grape instead of, or 72 | in addition to, using the notification based instrumentation. Here is a sample Sinatra app: 73 | 74 | ```ruby 75 | require 'vitals' 76 | require 'vitals/integrations/rack/requests' 77 | 78 | class SinatraTestAPI < Sinatra::Base 79 | use Vitals::Integrations::Rack::Requests 80 | 81 | get '/foo/bar/baz' do 82 | sleep 0.1 83 | "hello get" 84 | end 85 | 86 | post '/foo/bar/:name' do 87 | sleep 0.1 88 | "hello post" 89 | end 90 | end 91 | ``` 92 | 93 | ### Ruby 94 | 95 | You can emit metrics from anywhere: 96 | 97 | ```ruby 98 | Vitals.inc('my_metric') 99 | 100 | Vitals.count('my_metric', 17) 101 | 102 | Vitals.gauge('my_metric', 42) 103 | 104 | Vitals.timing('my_metric', 500) # milliseconds 105 | 106 | Vitals.time('my_metric'){ 107 | # so something slow 108 | } 109 | 110 | # Use a dot to logically separate segments 111 | 112 | Vitals.timing('category.my_metric', 500) # milliseconds 113 | ``` 114 | 115 | ### Configuration Options 116 | 117 | The Vitals API is extensible. It should resemble the standard `Logger` look and feel, 118 | and it revolves around 3 concepts: 119 | 120 | 1. `Reporter` - the thing that takes your metrics and flushes them to a metrics agent. Use `StatsdReporter` in production 121 | and `ConsoleReporter` in development. `ConsoleReporter` will spit out metrics to `stdout` as they come. You can also 122 | wire them _both_ with `MultiReporter`. Check the [specs](/spec/reporters) for how to do that. 123 | 2. `Format` - takes the contextual information (host, service, environment) and your metric, and formats them in an 124 | order that makes sense for working with Graphite. You have the `ProductionFormat`, `HostLastFormat` and `NoHostFormat`. 125 | 3. `Integrations` - integrations hook things that we're able to instrument with Vitals. Check [integrations](/lib/vitals/integrations) for more. 126 | 127 | Here's what's available to you at configuration time: 128 | 129 | ```ruby 130 | Vitals.configure! do |c| 131 | # Set your service name (default: 'default') 132 | c.facility = 'my_service' 133 | 134 | # Set environment (default: taken from RACK_ENV) 135 | # c.environment = 'env' 136 | 137 | # Set a host (default: taken from hostname) 138 | # c.host = 'foohost' 139 | 140 | # Use a specific reporter (default: InmemReporter) 141 | # c.reporter = Vitals::Reporters::ConsoleReporter.new 142 | 143 | # Use a different format perhaps? (default: ProductionFormat) 144 | # c.format = Vitals::Formats::HostLastFormat 145 | 146 | # Use a different metric path separator, control how hierarcies are generated (default: '.') 147 | # c.path_sep = '__' 148 | end 149 | ``` 150 | 151 | ### Metric Hierarchies 152 | 153 | If you leave the default metric path separator, it will be a dot. This means Graphite will parse 154 | this and generate a branch in the tree when ever it sees a new segment, so: 155 | 156 | ``` 157 | requests.api.status.registration.get.200.host-123 158 | ``` 159 | 160 | Will be created from a `GET /api/status/registration` 161 | 162 | On the other hand, if you choose a non-dot separator, like underscore, then: 163 | 164 | ``` 165 | requests.api_status_registration.get.200.host-123 166 | ``` 167 | 168 | Will be generated from a `GET /api/status/registration`. 169 | 170 | You can pick either of those and the trade-offs are: 171 | 172 | * Nested hierarchy (using a dot): fine-grained control over grouping your metrics efficiently. If you 173 | want to pick and choose a metric, and be able to group based on topics efficiently. You cannot group cross-segments of a path in graphite. 174 | 175 | * Flat hierarchy (using anything other than a dot, like an underscore): grouping over segments can be glob-like, so 176 | quick wins like "graph all errors" can be had like this: `api.*.500.*`. However, every time you want to group metrics, you will need to find 177 | the appropriate glob pattern, which will taxi Graphite for a huge amounts of metrics. 178 | 179 | The default separator is a dot, which makes everything hierarchical. 180 | 181 | 182 | 183 | ## Development 184 | 185 | Tests and benchmarks should be run with at least Ruby 2.1 (because of memory profiling API) 186 | 187 | ``` 188 | $ bundle install && rake spec && rake bench 189 | ``` 190 | 191 | You can use the following to test various web frameworks using their own integration testing stacks: 192 | 193 | ``` 194 | $ rake multiverse 195 | ``` 196 | 197 | # Contributing 198 | 199 | Fork, implement, add tests, pull request, get my everlasting thanks and a respectable place here :). 200 | 201 | # Copyright 202 | 203 | Copyright (c) 2011-2016 [Dotan Nahum](http://gplus.to/dotan) [@jondot](http://twitter.com/jondot). See [LICENSE](LICENSE.txt) for further details. 204 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | require "rake/testtask" 3 | 4 | Rake::TestTask.new(:spec) do |t| 5 | t.libs << "spec" 6 | t.libs << "lib" 7 | t.test_files = FileList['spec/**/*_spec.rb'] 8 | end 9 | 10 | Rake::TestTask.new(:multiverse) do |t| 11 | t.libs << "integration" 12 | t.libs << "spec" 13 | t.libs << "lib" 14 | t.test_files = FileList['integration/multiverse_spec.rb'] 15 | end 16 | 17 | Rake::TestTask.new(:bench) do |t| 18 | t.libs << "spec" 19 | t.libs << "lib" 20 | t.test_files = FileList['spec/**/*_bench.rb'] 21 | end 22 | 23 | task :default => :spec 24 | -------------------------------------------------------------------------------- /bin/console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require "bundler/setup" 4 | require "vitals" 5 | 6 | # You can add fixtures and/or initialization code here to make experimenting 7 | # with your gem easier. You can also use a different console, if you like. 8 | 9 | # (If you use this, don't forget to add pry to your Gemfile!) 10 | # require "pry" 11 | # Pry.start 12 | 13 | require "irb" 14 | IRB.start 15 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | IFS=$'\n\t' 4 | set -vx 5 | 6 | bundle install 7 | 8 | # Do any other automated setup that you need to do here 9 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rack/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .rvmrc 3 | .redcar 4 | .irbrc 5 | .bundle 6 | log 7 | vendor/ 8 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rack/.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | --format=progress 3 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rack/.rubocop.yml: -------------------------------------------------------------------------------- 1 | inherit_from: .rubocop_todo.yml 2 | 3 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rack/.rubocop_todo.yml: -------------------------------------------------------------------------------- 1 | # This configuration was generated by 2 | # `rubocop --auto-gen-config` 3 | # on 2015-08-28 08:52:35 -0400 using RuboCop version 0.33.0. 4 | # The point is for the user to remove these configuration records 5 | # one by one as the offenses are removed from the code base. 6 | # Note that changes in the inspected code, or installation of new 7 | # versions of RuboCop, may require this file to be generated again. 8 | 9 | # Offense count: 1 10 | Metrics/AbcSize: 11 | Max: 19 12 | 13 | # Offense count: 27 14 | # Configuration parameters: AllowURI, URISchemes. 15 | Metrics/LineLength: 16 | Max: 126 17 | 18 | # Offense count: 1 19 | # Configuration parameters: CountComments. 20 | Metrics/MethodLength: 21 | Max: 15 22 | 23 | # Offense count: 15 24 | Style/Documentation: 25 | Exclude: 26 | - 'api/content_type.rb' 27 | - 'api/entities.rb' 28 | - 'api/get_json.rb' 29 | - 'api/header_versioning.rb' 30 | - 'api/path_versioning.rb' 31 | - 'api/ping.rb' 32 | - 'api/post_json.rb' 33 | - 'api/post_put.rb' 34 | - 'api/rescue_from.rb' 35 | - 'api/upload_file.rb' 36 | - 'api/wrap_response.rb' 37 | - 'api/wrap_response_decorator.rb' 38 | - 'app/acme_app.rb' 39 | - 'app/api.rb' 40 | 41 | # Offense count: 1 42 | # Cop supports --auto-correct. 43 | Style/Lambda: 44 | Exclude: 45 | - 'app/acme_app.rb' 46 | 47 | # Offense count: 1 48 | Style/RescueModifier: 49 | Exclude: 50 | - 'api/get_json.rb' 51 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rack/.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | 3 | rvm: 4 | - 2.2.4 5 | 6 | language: ruby 7 | 8 | cache: bundler 9 | 10 | before_install: 11 | - "export DISPLAY=:99.0" 12 | - "sh -e /etc/init.d/xvfb start" 13 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rack/Gemfile: -------------------------------------------------------------------------------- 1 | source 'http://rubygems.org' 2 | 3 | 4 | gem 'grape' 5 | gem 'grape-entity' 6 | gem 'json' 7 | gem 'newrelic_rpm' 8 | gem 'rack-cors' 9 | gem 'grape-swagger' 10 | gem 'mime-types' 11 | gem 'nokogiri' 12 | 13 | group :development do 14 | gem 'rake' 15 | gem 'guard' 16 | gem 'guard-bundler' 17 | gem 'guard-rack' 18 | gem 'rubocop' 19 | end 20 | 21 | group :test do 22 | gem 'rspec' 23 | gem 'rack-test' 24 | gem 'capybara' 25 | gem 'selenium-webdriver' 26 | end 27 | 28 | gem 'vitals', path: '../../../' 29 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rack/Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: ../../../ 3 | specs: 4 | vitals (0.3.0) 5 | statsd-ruby (~> 1.3.0) 6 | 7 | GEM 8 | remote: http://rubygems.org/ 9 | specs: 10 | activesupport (4.2.5.1) 11 | i18n (~> 0.7) 12 | json (~> 1.7, >= 1.7.7) 13 | minitest (~> 5.1) 14 | thread_safe (~> 0.3, >= 0.3.4) 15 | tzinfo (~> 1.1) 16 | addressable (2.4.0) 17 | ast (2.2.0) 18 | axiom-types (0.1.1) 19 | descendants_tracker (~> 0.0.4) 20 | ice_nine (~> 0.11.0) 21 | thread_safe (~> 0.3, >= 0.3.1) 22 | builder (3.2.2) 23 | capybara (2.6.2) 24 | addressable 25 | mime-types (>= 1.16) 26 | nokogiri (>= 1.3.3) 27 | rack (>= 1.0.0) 28 | rack-test (>= 0.5.4) 29 | xpath (~> 2.0) 30 | childprocess (0.5.9) 31 | ffi (~> 1.0, >= 1.0.11) 32 | coderay (1.1.0) 33 | coercible (1.0.0) 34 | descendants_tracker (~> 0.0.1) 35 | descendants_tracker (0.0.4) 36 | thread_safe (~> 0.3, >= 0.3.1) 37 | diff-lcs (1.2.5) 38 | equalizer (0.0.11) 39 | ffi (1.9.10) 40 | formatador (0.2.5) 41 | grape (0.14.0) 42 | activesupport 43 | builder 44 | hashie (>= 2.1.0) 45 | multi_json (>= 1.3.2) 46 | multi_xml (>= 0.5.2) 47 | rack (>= 1.3.0) 48 | rack-accept 49 | rack-mount 50 | virtus (>= 1.0.0) 51 | grape-entity (0.4.8) 52 | activesupport 53 | multi_json (>= 1.3.2) 54 | grape-swagger (0.10.4) 55 | grape (>= 0.8.0) 56 | grape-entity (< 0.5.0) 57 | guard (2.13.0) 58 | formatador (>= 0.2.4) 59 | listen (>= 2.7, <= 4.0) 60 | lumberjack (~> 1.0) 61 | nenv (~> 0.1) 62 | notiffany (~> 0.0) 63 | pry (>= 0.9.12) 64 | shellany (~> 0.0) 65 | thor (>= 0.18.1) 66 | guard-bundler (2.1.0) 67 | bundler (~> 1.0) 68 | guard (~> 2.2) 69 | guard-compat (~> 1.1) 70 | guard-compat (1.2.1) 71 | guard-rack (2.1.1) 72 | ffi 73 | guard (~> 2.3) 74 | spoon 75 | hashie (3.4.3) 76 | i18n (0.7.0) 77 | ice_nine (0.11.2) 78 | json (1.8.3) 79 | listen (3.0.5) 80 | rb-fsevent (>= 0.9.3) 81 | rb-inotify (>= 0.9) 82 | lumberjack (1.0.10) 83 | method_source (0.8.2) 84 | mime-types (3.0) 85 | mime-types-data (~> 3.2015) 86 | mime-types-data (3.2015.1120) 87 | mini_portile2 (2.0.0) 88 | minitest (5.8.4) 89 | multi_json (1.11.2) 90 | multi_xml (0.5.5) 91 | nenv (0.2.0) 92 | newrelic_rpm (3.14.2.312) 93 | nokogiri (1.6.7.2) 94 | mini_portile2 (~> 2.0.0.rc2) 95 | notiffany (0.0.8) 96 | nenv (~> 0.1) 97 | shellany (~> 0.0) 98 | parser (2.3.0.2) 99 | ast (~> 2.2) 100 | powerpack (0.1.1) 101 | pry (0.10.3) 102 | coderay (~> 1.1.0) 103 | method_source (~> 0.8.1) 104 | slop (~> 3.4) 105 | rack (1.6.4) 106 | rack-accept (0.4.5) 107 | rack (>= 0.4) 108 | rack-cors (0.4.0) 109 | rack-mount (0.8.3) 110 | rack (>= 1.0.0) 111 | rack-test (0.6.3) 112 | rack (>= 1.0) 113 | rainbow (2.1.0) 114 | rake (10.5.0) 115 | rb-fsevent (0.9.7) 116 | rb-inotify (0.9.5) 117 | ffi (>= 0.5.0) 118 | rspec (3.4.0) 119 | rspec-core (~> 3.4.0) 120 | rspec-expectations (~> 3.4.0) 121 | rspec-mocks (~> 3.4.0) 122 | rspec-core (3.4.2) 123 | rspec-support (~> 3.4.0) 124 | rspec-expectations (3.4.0) 125 | diff-lcs (>= 1.2.0, < 2.0) 126 | rspec-support (~> 3.4.0) 127 | rspec-mocks (3.4.1) 128 | diff-lcs (>= 1.2.0, < 2.0) 129 | rspec-support (~> 3.4.0) 130 | rspec-support (3.4.1) 131 | rubocop (0.37.0) 132 | parser (>= 2.3.0.2, < 3.0) 133 | powerpack (~> 0.1) 134 | rainbow (>= 1.99.1, < 3.0) 135 | ruby-progressbar (~> 1.7) 136 | unicode-display_width (~> 0.3) 137 | ruby-progressbar (1.7.5) 138 | rubyzip (1.1.7) 139 | selenium-webdriver (2.50.0) 140 | childprocess (~> 0.5) 141 | multi_json (~> 1.0) 142 | rubyzip (~> 1.0) 143 | websocket (~> 1.0) 144 | shellany (0.0.1) 145 | slop (3.6.0) 146 | spoon (0.0.4) 147 | ffi 148 | statsd-ruby (1.3.0) 149 | thor (0.19.1) 150 | thread_safe (0.3.5) 151 | tzinfo (1.2.2) 152 | thread_safe (~> 0.1) 153 | unicode-display_width (0.3.1) 154 | virtus (1.0.5) 155 | axiom-types (~> 0.1) 156 | coercible (~> 1.0) 157 | descendants_tracker (~> 0.0, >= 0.0.3) 158 | equalizer (~> 0.0, >= 0.0.9) 159 | websocket (1.2.2) 160 | xpath (2.0.0) 161 | nokogiri (~> 1.3) 162 | 163 | PLATFORMS 164 | ruby 165 | 166 | DEPENDENCIES 167 | capybara 168 | grape 169 | grape-entity 170 | grape-swagger 171 | guard 172 | guard-bundler 173 | guard-rack 174 | json 175 | mime-types 176 | newrelic_rpm 177 | nokogiri 178 | rack-cors 179 | rack-test 180 | rake 181 | rspec 182 | rubocop 183 | selenium-webdriver 184 | vitals! 185 | 186 | BUNDLED WITH 187 | 1.11.2 188 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rack/Guardfile: -------------------------------------------------------------------------------- 1 | guard 'bundler' do 2 | watch('Gemfile') 3 | end 4 | 5 | guard 'rack' do 6 | watch('Gemfile.lock') 7 | watch(%r{^(config|app|api)/.*}) 8 | end 9 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rack/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Daniel Doubrovkine 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rack/README.md: -------------------------------------------------------------------------------- 1 | Grape API on Rack 2 | ================= 3 | 4 | [![Build Status](https://travis-ci.org/ruby-grape/grape-on-rack.svg?branch=master)](https://travis-ci.org/ruby-grape/grape-on-rack) 5 | [![Dependency Status](https://gemnasium.com/ruby-grape/grape-on-rack.svg)](https://gemnasium.com/ruby-grape/grape-on-rack) 6 | [![Code Climate](https://codeclimate.com/github/ruby-grape/grape-on-rack.svg)](https://codeclimate.com/github/ruby-grape/grape-on-rack) 7 | 8 | A [Grape](http://github.com/ruby-grape/grape) API mounted on Rack. 9 | 10 | * [ping](api/ping.rb): a hello world example that returns a JSON document 11 | * [post_put](api/post_put.rb): a simple `POST` and `PUT` example 12 | * [post_json](api/post_json.rb): an example that shows a `POST` of JSON data 13 | * [get_json](api/get_json.rb): an example that pre-processes params sent as JSON data 14 | * [rescue_from](api/rescue_from.rb): an example of `rescue_from` that wraps all exceptions in an HTTP error code 500 15 | * [path_versioning](api/path_versioning.rb): an example that uses path-based versioning 16 | * [header_versioning](api/header_versioning.rb): an example that uses vendor header-based versioning 17 | * [wrap_response](api/wrap_response.rb): a middleware that wraps all responses and always returns HTTP code 200 18 | * [content_type](api/content_type.rb): an example that overrides the default `Content-Type` or returns data in both JSON and XML formats 19 | * [upload_file](api/upload_file.rb): an example that demonstrates a file upload and download 20 | * [entites](api/entities.rb): an example of using [grape-entity](https://github.com/ruby-grape/grape-entity) 21 | 22 | See 23 | --- 24 | 25 | There's a deployed [grape-on-rack on Heroku](http://grape-on-rack.herokuapp.com/). 26 | 27 | Run 28 | --- 29 | 30 | ``` 31 | $ bundle install 32 | $ rackup 33 | 34 | Loading NewRelic in developer mode ... 35 | [2013-06-20 08:57:58] INFO WEBrick 1.3.1 36 | [2013-06-20 08:57:58] INFO ruby 1.9.3 (2013-02-06) [x86_64-darwin11.4.2] 37 | [2013-06-20 08:57:58] INFO WEBrick::HTTPServer#start: pid=247 port=9292 38 | ``` 39 | 40 | ### Hello World 41 | 42 | Navigate to http://localhost:9292/api/ping with a browser or use `curl`. 43 | 44 | ``` 45 | $ curl http://localhost:9292/api/ping 46 | 47 | {"ping":"pong"} 48 | ``` 49 | 50 | ### Get Plain Text 51 | 52 | ``` 53 | $ curl http://localhost:9292/api/plain_text 54 | 55 | A red brown fox jumped over the road. 56 | ``` 57 | 58 | ### Upload a File 59 | 60 | ``` 61 | $ curl -X POST -i -F image_file=@spec/fixtures/grape_logo.png http://localhost:9292/api/avatar 62 | 63 | {"filename":"grape_logo.png","size":4272} 64 | ``` 65 | 66 | ### Upload and Download a File 67 | 68 | ``` 69 | $ curl -X POST -i -F file=@spec/fixtures/grape_logo.png http://localhost:9292/api/download.png 70 | $ curl -X POST -i -F file=@api/ping.rb http://localhost:9292/api/download.rb 71 | ``` 72 | 73 | List Routes 74 | ----------- 75 | 76 | ``` 77 | rake routes 78 | ``` 79 | 80 | Explore the API 81 | --------------- 82 | 83 | Explore the API using [Swagger UI](http://petstore.swagger.io). Run the application and point the explorer to `http://localhost:9292/api/swagger_doc` or `http://grape-on-rack.herokuapp.com/api/swagger_doc`. 84 | 85 | New Relic 86 | --------- 87 | 88 | The application is setup with NewRelic w/ Developer Mode. Navigate to http://localhost:9292/newrelic after making some API calls. 89 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rack/Rakefile: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'bundler/setup' 3 | 4 | require 'rake' 5 | 6 | require 'rspec/core' 7 | require 'rspec/core/rake_task' 8 | 9 | RSpec::Core::RakeTask.new(:spec) 10 | 11 | task :environment do 12 | ENV['RACK_ENV'] ||= 'development' 13 | require File.expand_path('../config/environment', __FILE__) 14 | end 15 | 16 | task routes: :environment do 17 | Acme::API.routes.each do |route| 18 | method = route.route_method.ljust(10) 19 | path = route.route_path 20 | puts " #{method} #{path}" 21 | end 22 | end 23 | 24 | require 'rubocop/rake_task' 25 | RuboCop::RakeTask.new(:rubocop) 26 | 27 | task default: [:rubocop, :spec] 28 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rack/api/content_type.rb: -------------------------------------------------------------------------------- 1 | module Acme 2 | class ContentType < Grape::API 3 | format :json 4 | content_type :txt, 'text/plain' 5 | content_type :xml, 'application/xml' 6 | 7 | desc 'Returns a plain text file.' 8 | get 'plain_text' do 9 | content_type 'text/plain' 10 | 'A red brown fox jumped over the road.' 11 | end 12 | 13 | desc 'Returns a response in either XML or JSON format.' 14 | get 'mixed' do 15 | { data: 'A red brown fox jumped over the road.' } 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rack/api/entities.rb: -------------------------------------------------------------------------------- 1 | module Acme 2 | module Entities 3 | class Tool < Grape::Entity 4 | root 'tools', 'tool' 5 | expose :id 6 | expose :length, documentation: { type: :string, desc: 'length of the tool' } 7 | expose :weight, documentation: { type: :string, desc: 'weight of the tool' } 8 | expose :foo, documentation: { type: :string, desc: 'foo' }, if: ->(_tool, options) { options[:foo] } do |_tool, options| 9 | options[:foo] 10 | end 11 | end 12 | 13 | class API < Grape::API 14 | format :json 15 | content_type :xml, 'application/xml' 16 | formatter :xml, proc { |object| 17 | object[object.keys.first].to_xml root: object.keys.first 18 | } 19 | desc 'Exposes an entity' 20 | namespace :entities do 21 | desc 'Expose a tool', params: Acme::Entities::Tool.documentation 22 | get ':id' do 23 | present OpenStruct.new(id: params[:id], length: 10, weight: '20kg'), with: Acme::Entities::Tool, foo: params[:foo] 24 | end 25 | end 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rack/api/get_json.rb: -------------------------------------------------------------------------------- 1 | module Acme 2 | class GetJson < Grape::API 3 | format :json 4 | desc 'Flips reticulated in a collection of splines passed as JSON in a query string.' 5 | resource :reticulated_splines do 6 | before do 7 | params.each_pair do |k, v| 8 | params[k] = JSON.parse(v) rescue v 9 | end 10 | end 11 | params do 12 | requires :splines, type: Array do 13 | requires :id, type: Integer 14 | requires :reticulated, type: Boolean 15 | end 16 | end 17 | get do 18 | params[:splines].map do |spline| 19 | spline.merge(reticulated: !spline[:reticulated]) 20 | end 21 | end 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rack/api/header_versioning.rb: -------------------------------------------------------------------------------- 1 | module Acme 2 | class HeaderVersioning < Grape::API 3 | version 'v1', using: :header, vendor: 'acme', format: :json, strict: true 4 | desc 'Returns acme.' 5 | get do 6 | { header: 'acme' } 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rack/api/path_versioning.rb: -------------------------------------------------------------------------------- 1 | module Acme 2 | class PathVersioning < Grape::API 3 | version 'vendor', using: :path, vendor: 'acme', format: :json 4 | desc 'Returns acme.' 5 | get do 6 | { path: 'acme' } 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rack/api/ping.rb: -------------------------------------------------------------------------------- 1 | module Acme 2 | class Ping < Grape::API 3 | format :json 4 | get '/ping' do 5 | { ping: 'pong' } 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rack/api/post_json.rb: -------------------------------------------------------------------------------- 1 | module Acme 2 | class PostJson < Grape::API 3 | format :json 4 | desc 'Creates a spline that can be reticulated.' 5 | resource :spline do 6 | post do 7 | { reticulated: params[:reticulated] } 8 | end 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rack/api/post_put.rb: -------------------------------------------------------------------------------- 1 | module Acme 2 | class PostPut < Grape::API 3 | cattr_accessor :rang 4 | 5 | format :json 6 | desc 'Returns pong.' 7 | get :ring do 8 | { rang: PostPut.rang } 9 | end 10 | post :ring do 11 | result = (PostPut.rang += 1) 12 | { rang: result } 13 | end 14 | params do 15 | requires :count, type: Integer 16 | end 17 | put :ring do 18 | result = (PostPut.rang += params[:count].to_i) 19 | { rang: result } 20 | end 21 | end 22 | end 23 | 24 | Acme::PostPut.rang = 0 25 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rack/api/rescue_from.rb: -------------------------------------------------------------------------------- 1 | module Acme 2 | class RescueFrom < Grape::API 3 | rescue_from :all do |e| 4 | Rack::Response.new([e.message], 500, 'Content-type' => 'text/error').finish 5 | end 6 | desc 'Raises an exception.' 7 | get :raise do 8 | raise 'Unexpected error.' 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rack/api/upload_file.rb: -------------------------------------------------------------------------------- 1 | module Acme 2 | class UploadFile < Grape::API 3 | format :json 4 | 5 | desc 'Upload an image.' 6 | post 'avatar' do 7 | { 8 | filename: params[:image_file][:filename], 9 | size: params[:image_file][:tempfile].size 10 | } 11 | end 12 | 13 | desc 'Upload and download a file of any format.' 14 | post 'download' do 15 | filename = params[:file][:filename] 16 | content_type MIME::Types.type_for(filename)[0].to_s 17 | env['api.format'] = :binary 18 | header 'Content-Disposition', "attachment; filename*=UTF-8''#{URI.escape(filename)}" 19 | params[:file][:tempfile].read 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rack/api/wrap_response.rb: -------------------------------------------------------------------------------- 1 | require 'wrap_response_decorator' 2 | 3 | module Acme 4 | class WrapResponse < Grape::API 5 | use WrapResponseDecorator 6 | format :json 7 | namespace :decorated do 8 | desc 'Returns pong.' 9 | get :ping do 10 | { ping: 'pong' } 11 | end 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rack/api/wrap_response_decorator.rb: -------------------------------------------------------------------------------- 1 | module Acme 2 | class WrapResponseDecorator 3 | def initialize(app) 4 | @app = app 5 | end 6 | 7 | def call(env) 8 | status, headers, body_proxy = @app.call(env) 9 | bodies = body_proxy.body.map do |body| 10 | { body: JSON.parse(body), status: status }.to_json 11 | end 12 | [200, headers, bodies] 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rack/app/acme_app.rb: -------------------------------------------------------------------------------- 1 | module Acme 2 | class App 3 | def initialize 4 | @filenames = ['', '.html', 'index.html', '/index.html'] 5 | @rack_static = ::Rack::Static.new( 6 | lambda { [404, {}, []] }, 7 | root: File.expand_path('../../public', __FILE__), 8 | urls: ['/'] 9 | ) 10 | end 11 | 12 | def self.instance 13 | @instance ||= Rack::Builder.new do 14 | use Rack::Cors do 15 | allow do 16 | origins '*' 17 | resource '*', headers: :any, methods: :get 18 | end 19 | end 20 | 21 | run Acme::App.new 22 | end.to_app 23 | end 24 | 25 | def call(env) 26 | # api 27 | response = Acme::API.call(env) 28 | 29 | # Check if the App wants us to pass the response along to others 30 | if response[1]['X-Cascade'] == 'pass' 31 | # static files 32 | request_path = env['PATH_INFO'] 33 | @filenames.each do |path| 34 | response = @rack_static.call(env.merge('PATH_INFO' => request_path + path)) 35 | return response if response[0] != 404 36 | end 37 | end 38 | 39 | # Serve error pages or respond with API response 40 | case response[0] 41 | when 404, 500 42 | content = @rack_static.call(env.merge('PATH_INFO' => "/errors/#{response[0]}.html")) 43 | [response[0], content[1], content[2]] 44 | else 45 | response 46 | end 47 | end 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rack/app/api.rb: -------------------------------------------------------------------------------- 1 | module Acme 2 | class API < Grape::API 3 | prefix 'api' 4 | format :json 5 | mount ::Acme::Ping 6 | mount ::Acme::RescueFrom 7 | mount ::Acme::PathVersioning 8 | mount ::Acme::HeaderVersioning 9 | mount ::Acme::PostPut 10 | mount ::Acme::WrapResponse 11 | mount ::Acme::PostJson 12 | mount ::Acme::GetJson 13 | mount ::Acme::ContentType 14 | mount ::Acme::UploadFile 15 | mount ::Acme::Entities::API 16 | add_swagger_documentation api_version: 'v1' 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rack/config.ru: -------------------------------------------------------------------------------- 1 | require File.expand_path('../config/environment', __FILE__) 2 | 3 | if ENV['RACK_ENV'] == 'development' 4 | puts 'Loading NewRelic in developer mode ...' 5 | require 'new_relic/rack/developer_mode' 6 | use NewRelic::Rack::DeveloperMode 7 | end 8 | 9 | NewRelic::Agent.manual_start 10 | 11 | run Acme::App.instance 12 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rack/config/application.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'api')) 2 | $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'app')) 3 | $LOAD_PATH.unshift(File.dirname(__FILE__)) 4 | 5 | require 'boot' 6 | 7 | Bundler.require :default, ENV['RACK_ENV'] 8 | 9 | Dir[File.expand_path('../../api/*.rb', __FILE__)].each do |f| 10 | require f 11 | end 12 | 13 | require 'api' 14 | require 'acme_app' 15 | 16 | require 'vitals' 17 | Vitals.configure! do |c| 18 | c.facility = 'grape_app' 19 | end 20 | 21 | require 'vitals/integrations/notifications/grape' 22 | Vitals::Integrations::Notifications::Grape.subscribe! 23 | 24 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rack/config/boot.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'bundler/setup' 3 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rack/config/environment.rb: -------------------------------------------------------------------------------- 1 | ENV['RACK_ENV'] ||= 'test' 2 | 3 | require File.expand_path('../application', __FILE__) 4 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rack/config/newrelic.yml: -------------------------------------------------------------------------------- 1 | # Here are the settings that are common to all environments 2 | common: &default_settings 3 | # ============================== LICENSE KEY =============================== 4 | 5 | # You must specify the license key associated with your New Relic 6 | # account. This key binds your Agent's data to your account in the 7 | # New Relic service. 8 | license_key: '<%= ENV["NEW_RELIC_LICENSE_KEY"] %>' 9 | 10 | # Agent Enabled (Rails Only) 11 | # Use this setting to force the agent to run or not run. 12 | # Default is 'auto' which means the agent will install and run only 13 | # if a valid dispatcher such as Mongrel is running. This prevents 14 | # it from running with Rake or the console. Set to false to 15 | # completely turn the agent off regardless of the other settings. 16 | # Valid values are true, false and auto. 17 | # 18 | # agent_enabled: auto 19 | 20 | # Application Name Set this to be the name of your application as 21 | # you'd like it show up in New Relic. The service will then auto-map 22 | # instances of your application into an "application" on your 23 | # dashboard page. If you want to map this instance into multiple 24 | # apps, like "AJAX Requests" and "All UI" then specify a semicolon 25 | # separated list of up to three distinct names, or a yaml list. 26 | # Defaults to the capitalized RAILS_ENV or RACK_ENV (i.e., 27 | # Production, Staging, etc) 28 | # 29 | # Example: 30 | # 31 | # app_name: 32 | # - Ajax Service 33 | # - All Services 34 | # 35 | app_name: <%= ENV["NEW_RELIC_APP_NAME"] || 'Demo' %> 36 | 37 | # When "true", the agent collects performance data about your 38 | # application and reports this data to the New Relic service at 39 | # newrelic.com. This global switch is normally overridden for each 40 | # environment below. (formerly called 'enabled') 41 | monitor_mode: true 42 | 43 | # Developer mode should be off in every environment but 44 | # development as it has very high overhead in memory. 45 | developer_mode: false 46 | 47 | # The newrelic agent generates its own log file to keep its logging 48 | # information separate from that of your application. Specify its 49 | # log level here. 50 | log_level: info 51 | 52 | # Optionally set the path to the log file This is expanded from the 53 | # root directory (may be relative or absolute, e.g. 'log/' or 54 | # '/var/log/') The agent will attempt to create this directory if it 55 | # does not exist. 56 | # log_file_path: 'log' 57 | 58 | # Optionally set the name of the log file, defaults to 'newrelic_agent.log' 59 | # log_file_name: 'newrelic_agent.log' 60 | 61 | # The newrelic agent communicates with the service via http by 62 | # default. If you want to communicate via https to increase 63 | # security, then turn on SSL by setting this value to true. Note, 64 | # this will result in increased CPU overhead to perform the 65 | # encryption involved in SSL communication, but this work is done 66 | # asynchronously to the threads that process your application code, 67 | # so it should not impact response times. 68 | ssl: false 69 | 70 | # EXPERIMENTAL: enable verification of the SSL certificate sent by 71 | # the server. This setting has no effect unless SSL is enabled 72 | # above. This may block your application. Only enable it if the data 73 | # you send us needs end-to-end verified certificates. 74 | # 75 | # This means we cannot cache the DNS lookup, so each request to the 76 | # service will perform a lookup. It also means that we cannot 77 | # use a non-blocking lookup, so in a worst case, if you have DNS 78 | # problems, your app may block indefinitely. 79 | # verify_certificate: true 80 | 81 | # Set your application's Apdex threshold value with the 'apdex_t' 82 | # setting, in seconds. The apdex_t value determines the buckets used 83 | # to compute your overall Apdex score. 84 | # Requests that take less than apdex_t seconds to process will be 85 | # classified as Satisfying transactions; more than apdex_t seconds 86 | # as Tolerating transactions; and more than four times the apdex_t 87 | # value as Frustrating transactions. 88 | # For more about the Apdex standard, see 89 | # http://newrelic.com/docs/general/apdex 90 | 91 | apdex_t: 0.5 92 | 93 | #============================== Browser Monitoring =============================== 94 | # New Relic Real User Monitoring gives you insight into the performance real users are 95 | # experiencing with your website. This is accomplished by measuring the time it takes for 96 | # your users' browsers to download and render your web pages by injecting a small amount 97 | # of JavaScript code into the header and footer of each page. 98 | browser_monitoring: 99 | # By default the agent automatically injects the monitoring JavaScript 100 | # into web pages. Set this attribute to false to turn off this behavior. 101 | auto_instrument: true 102 | 103 | # Proxy settings for connecting to the service. 104 | # 105 | # If a proxy is used, the host setting is required. Other settings 106 | # are optional. Default port is 8080. 107 | # 108 | # proxy_host: hostname 109 | # proxy_port: 8080 110 | # proxy_user: 111 | # proxy_pass: 112 | 113 | 114 | # Tells transaction tracer and error collector (when enabled) 115 | # whether or not to capture HTTP params. When true, frameworks can 116 | # exclude HTTP parameters from being captured. 117 | # Rails: the RoR filter_parameter_logging excludes parameters 118 | # Java: create a config setting called "ignored_params" and set it to 119 | # a comma separated list of HTTP parameter names. 120 | # ex: ignored_params: credit_card, ssn, password 121 | capture_params: true 122 | 123 | 124 | # Transaction tracer captures deep information about slow 125 | # transactions and sends this to the service once a 126 | # minute. Included in the transaction is the exact call sequence of 127 | # the transactions including any SQL statements issued. 128 | transaction_tracer: 129 | 130 | # Transaction tracer is enabled by default. Set this to false to 131 | # turn it off. This feature is only available at the Professional 132 | # and above product levels. 133 | enabled: true 134 | 135 | # Threshold in seconds for when to collect a transaction 136 | # trace. When the response time of a controller action exceeds 137 | # this threshold, a transaction trace will be recorded and sent to 138 | # the service. Valid values are any float value, or (default) 139 | # "apdex_f", which will use the threshold for an dissatisfying 140 | # Apdex controller action - four times the Apdex T value. 141 | transaction_threshold: apdex_f 142 | 143 | # When transaction tracer is on, SQL statements can optionally be 144 | # recorded. The recorder has three modes, "off" which sends no 145 | # SQL, "raw" which sends the SQL statement in its original form, 146 | # and "obfuscated", which strips out numeric and string literals 147 | record_sql: obfuscated 148 | 149 | # Threshold in seconds for when to collect stack trace for a SQL 150 | # call. In other words, when SQL statements exceed this threshold, 151 | # then capture and send the current stack trace. This is 152 | # helpful for pinpointing where long SQL calls originate from 153 | stack_trace_threshold: 0.500 154 | 155 | # Determines whether the agent will capture query plans for slow 156 | # SQL queries. Only supported in mysql and postgres. Should be 157 | # set to false when using other adapters. 158 | # explain_enabled: true 159 | 160 | # Threshold for query execution time below which query plans will not 161 | # not be captured. Relevant only when `explain_enabled` is true. 162 | # explain_threshold: 0.5 163 | 164 | # Error collector captures information about uncaught exceptions and 165 | # sends them to the service for viewing 166 | error_collector: 167 | 168 | # Error collector is enabled by default. Set this to false to turn 169 | # it off. This feature is only available at the Professional and above 170 | # product levels 171 | enabled: true 172 | 173 | # Rails Only - tells error collector whether or not to capture a 174 | # source snippet around the place of the error when errors are View 175 | # related. 176 | capture_source: true 177 | 178 | # To stop specific errors from reporting to New Relic, set this property 179 | # to comma separated values. Default is to ignore routing errors 180 | # which are how 404's get triggered. 181 | # 182 | ignore_errors: ActionController::RoutingError 183 | 184 | # (Advanced) Uncomment this to ensure the cpu and memory samplers 185 | # won't run. Useful when you are using the agent to monitor an 186 | # external resource 187 | # disable_samplers: true 188 | 189 | # If you aren't interested in visibility in these areas, you can 190 | # disable the instrumentation to reduce overhead. 191 | # 192 | # disable_view_instrumentation: true 193 | # disable_activerecord_instrumentation: true 194 | # disable_memcache_instrumentation: true 195 | # disable_dj: true 196 | 197 | # If you're interested in capturing memcache keys as though they 198 | # were SQL uncomment this flag. Note that this does increase 199 | # overhead slightly on every memcached call, and can have security 200 | # implications if your memcached keys are sensitive 201 | # capture_memcache_keys: true 202 | 203 | # Certain types of instrumentation such as GC stats will not work if 204 | # you are running multi-threaded. Please let us know. 205 | # multi_threaded = false 206 | 207 | # Application Environments 208 | # ------------------------------------------ 209 | # Environment specific settings are in this section. 210 | # For Rails applications, RAILS_ENV is used to determine the environment 211 | # For Java applications, pass -Dnewrelic.environment to set 212 | # the environment 213 | 214 | # NOTE if your application has other named environments, you should 215 | # provide newrelic configuration settings for these environments here. 216 | 217 | development: 218 | <<: *default_settings 219 | # Turn off communication to New Relic service in development mode (also 220 | # 'enabled'). 221 | # NOTE: for initial evaluation purposes, you may want to temporarily 222 | # turn the agent on in development mode. 223 | monitor_mode: false 224 | 225 | # Rails Only - when running in Developer Mode, the New Relic Agent will 226 | # present performance information on the last 100 transactions you have 227 | # executed since starting the mongrel. 228 | # NOTE: There is substantial overhead when running in developer mode. 229 | # Do not use for production or load testing. 230 | developer_mode: true 231 | 232 | # Enable textmate links 233 | # textmate: true 234 | 235 | test: 236 | <<: *default_settings 237 | # It almost never makes sense to turn on the agent when running 238 | # unit, functional or integration tests or the like. 239 | monitor_mode: false 240 | 241 | # Turn on the agent in production for 24x7 monitoring. NewRelic 242 | # testing shows an average performance impact of < 5 ms per 243 | # transaction, you you can leave this on all the time without 244 | # incurring any user-visible performance degradation. 245 | production: 246 | <<: *default_settings 247 | monitor_mode: true 248 | 249 | # Many applications have a staging environment which behaves 250 | # identically to production. Support for that environment is provided 251 | # here. By default, the staging environment has the agent turned on. 252 | staging: 253 | <<: *default_settings 254 | monitor_mode: true 255 | app_name: <%= ENV["NEW_RELIC_APP_NAME"] || 'Demo' %> (Staging) -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rack/public/errors/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Page Not Found 4 | 5 | 6 |

Ooops...

7 | 8 | 9 | 10 |

11 | This page could not be found. 12 |

13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rack/public/errors/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Unexpected Error 4 | 5 | 6 |

Ouch...

7 | 8 | 9 | 10 |

11 | Something went terribly wrong. 12 |

13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rack/public/images/index.html: -------------------------------------------------------------------------------- 1 | This folder contains images. 2 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rack/public/images/rack-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondot/vitals/6248acc31b9c892f2771a46ee46e3f8ec777d8b3/integration/multiverse/grape-on-rack/public/images/rack-logo.png -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rack/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Rack Powers Web APIs 4 | 5 | 6 | 7 | 8 |

Rack Powers Web APIs

9 | 10 | 11 | 12 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rack/public/scripts/ring.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | 3 | var ring = function() { 4 | $.ajax({ 5 | type: "POST", 6 | url: "/api/ring", 7 | success: function(data) { 8 | $('#ring_value').text("rang " + data.rang.toString() + " time(s)"); 9 | $('#ring_action').text("click here to ring again"); 10 | } 11 | }); 12 | }; 13 | 14 | ring(); 15 | 16 | $('#ring_action').click(ring); 17 | }); 18 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rack/spec/api/post_put_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Acme::API do 4 | include Rack::Test::Methods 5 | 6 | def app 7 | Acme::API 8 | end 9 | before do 10 | Vitals.reporter.flush 11 | end 12 | 13 | it 'GET ring' do 14 | get '/api/ring' 15 | expect(JSON.parse(last_response.body)[:rang].to_i).to be >= 0 16 | metrics = %w{ 17 | grape.api.ring.get.200.all 18 | } 19 | assert_timings Vitals.reporter.reports, metrics, [0] 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rack/spec/fixtures/grape_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondot/vitals/6248acc31b9c892f2771a46ee46e3f8ec777d8b3/integration/multiverse/grape-on-rack/spec/fixtures/grape_logo.png -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rack/spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | 3 | ENV['RACK_ENV'] ||= 'test' 4 | 5 | require 'rack/test' 6 | 7 | require File.expand_path('../../config/environment', __FILE__) 8 | 9 | RSpec.configure do |config| 10 | config.color = true 11 | config.formatter = :documentation 12 | 13 | config.mock_with :rspec 14 | config.expect_with :rspec 15 | config.raise_errors_for_deprecations! 16 | end 17 | 18 | require 'capybara/rspec' 19 | Capybara.configure do |config| 20 | config.app = Acme::App.new 21 | config.server_port = 9293 22 | end 23 | 24 | require File.expand_path( '../../../multiverse_helper', File.dirname(__FILE__)) 25 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | # 3 | # If you find yourself ignoring temporary files generated by your text editor 4 | # or operating system, you probably want to add a global ignore instead: 5 | # git config --global core.excludesfile ~/.gitignore_global 6 | 7 | # Ignore bundler config 8 | /.bundle 9 | 10 | # Ignore the default SQLite database. 11 | /db/*.sqlite3 12 | 13 | # Ignore all logfiles and tempfiles. 14 | /log/*.log 15 | /tmp 16 | vendor/ 17 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | --format=progress 3 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/.rubocop.yml: -------------------------------------------------------------------------------- 1 | AllCops: 2 | Exclude: 3 | - vendor/**/* 4 | - bin/**/* 5 | 6 | inherit_from: .rubocop_todo.yml 7 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/.rubocop_todo.yml: -------------------------------------------------------------------------------- 1 | # This configuration was generated by 2 | # `rubocop --auto-gen-config` 3 | # on 2015-08-06 12:27:03 -0400 using RuboCop version 0.33.0. 4 | # The point is for the user to remove these configuration records 5 | # one by one as the offenses are removed from the code base. 6 | # Note that changes in the inspected code, or installation of new 7 | # versions of RuboCop, may require this file to be generated again. 8 | 9 | # Offense count: 30 10 | # Configuration parameters: AllowURI, URISchemes. 11 | Metrics/LineLength: 12 | Max: 129 13 | 14 | # Offense count: 10 15 | Style/Documentation: 16 | Exclude: 17 | - 'app/api/acme/ping.rb' 18 | - 'app/api/acme/post.rb' 19 | - 'app/api/acme/protected.rb' 20 | - 'app/api/acme/raise.rb' 21 | - 'app/api/api.rb' 22 | - 'app/controllers/application_controller.rb' 23 | - 'app/controllers/welcome_controller.rb' 24 | - 'app/helpers/application_helper.rb' 25 | - 'app/helpers/welcome_helper.rb' 26 | - 'config/application.rb' 27 | 28 | # Offense count: 1 29 | # Cop supports --auto-correct. 30 | # Configuration parameters: EnforcedStyle, SupportedStyles, AllowInnerSlashes. 31 | Style/RegexpLiteral: 32 | Exclude: 33 | - 'spec/spec_helper.rb' 34 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | 3 | language: ruby 4 | 5 | cache: bundler 6 | 7 | rvm: 8 | - 2.2.4 9 | 10 | before_install: 11 | - "export DISPLAY=:99.0" 12 | - "sh -e /etc/init.d/xvfb start" 13 | 14 | before_script: 15 | - "cp config/database.travis.yml config/database.yml" 16 | - "RAILS_ENV=test bundle exec rake db:create" 17 | 18 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'rails' 4 | gem 'sass' 5 | gem 'sqlite3' 6 | gem 'sass-rails' 7 | gem 'coffee-rails' 8 | gem 'jquery-rails' 9 | gem 'grape' 10 | gem 'uglifier' 11 | gem 'zip-zip' 12 | 13 | group :development, :test do 14 | gem 'rspec' 15 | gem 'rspec-rails' 16 | gem 'capybara' 17 | gem 'selenium-webdriver' 18 | gem 'rubocop' 19 | gem 'nokogiri' 20 | end 21 | 22 | gem 'vitals', path: '../../../' 23 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: ../../../ 3 | specs: 4 | vitals (0.3.0) 5 | statsd-ruby (~> 1.3.0) 6 | 7 | GEM 8 | remote: https://rubygems.org/ 9 | specs: 10 | actionmailer (4.2.5.1) 11 | actionpack (= 4.2.5.1) 12 | actionview (= 4.2.5.1) 13 | activejob (= 4.2.5.1) 14 | mail (~> 2.5, >= 2.5.4) 15 | rails-dom-testing (~> 1.0, >= 1.0.5) 16 | actionpack (4.2.5.1) 17 | actionview (= 4.2.5.1) 18 | activesupport (= 4.2.5.1) 19 | rack (~> 1.6) 20 | rack-test (~> 0.6.2) 21 | rails-dom-testing (~> 1.0, >= 1.0.5) 22 | rails-html-sanitizer (~> 1.0, >= 1.0.2) 23 | actionview (4.2.5.1) 24 | activesupport (= 4.2.5.1) 25 | builder (~> 3.1) 26 | erubis (~> 2.7.0) 27 | rails-dom-testing (~> 1.0, >= 1.0.5) 28 | rails-html-sanitizer (~> 1.0, >= 1.0.2) 29 | activejob (4.2.5.1) 30 | activesupport (= 4.2.5.1) 31 | globalid (>= 0.3.0) 32 | activemodel (4.2.5.1) 33 | activesupport (= 4.2.5.1) 34 | builder (~> 3.1) 35 | activerecord (4.2.5.1) 36 | activemodel (= 4.2.5.1) 37 | activesupport (= 4.2.5.1) 38 | arel (~> 6.0) 39 | activesupport (4.2.5.1) 40 | i18n (~> 0.7) 41 | json (~> 1.7, >= 1.7.7) 42 | minitest (~> 5.1) 43 | thread_safe (~> 0.3, >= 0.3.4) 44 | tzinfo (~> 1.1) 45 | addressable (2.4.0) 46 | arel (6.0.3) 47 | ast (2.2.0) 48 | axiom-types (0.1.1) 49 | descendants_tracker (~> 0.0.4) 50 | ice_nine (~> 0.11.0) 51 | thread_safe (~> 0.3, >= 0.3.1) 52 | builder (3.2.2) 53 | capybara (2.6.2) 54 | addressable 55 | mime-types (>= 1.16) 56 | nokogiri (>= 1.3.3) 57 | rack (>= 1.0.0) 58 | rack-test (>= 0.5.4) 59 | xpath (~> 2.0) 60 | childprocess (0.5.9) 61 | ffi (~> 1.0, >= 1.0.11) 62 | coercible (1.0.0) 63 | descendants_tracker (~> 0.0.1) 64 | coffee-rails (4.1.1) 65 | coffee-script (>= 2.2.0) 66 | railties (>= 4.0.0, < 5.1.x) 67 | coffee-script (2.4.1) 68 | coffee-script-source 69 | execjs 70 | coffee-script-source (1.10.0) 71 | concurrent-ruby (1.0.0) 72 | descendants_tracker (0.0.4) 73 | thread_safe (~> 0.3, >= 0.3.1) 74 | diff-lcs (1.2.5) 75 | equalizer (0.0.11) 76 | erubis (2.7.0) 77 | execjs (2.6.0) 78 | ffi (1.9.10) 79 | globalid (0.3.6) 80 | activesupport (>= 4.1.0) 81 | grape (0.14.0) 82 | activesupport 83 | builder 84 | hashie (>= 2.1.0) 85 | multi_json (>= 1.3.2) 86 | multi_xml (>= 0.5.2) 87 | rack (>= 1.3.0) 88 | rack-accept 89 | rack-mount 90 | virtus (>= 1.0.0) 91 | hashie (3.4.3) 92 | i18n (0.7.0) 93 | ice_nine (0.11.2) 94 | jquery-rails (4.1.0) 95 | rails-dom-testing (~> 1.0) 96 | railties (>= 4.2.0) 97 | thor (>= 0.14, < 2.0) 98 | json (1.8.3) 99 | loofah (2.0.3) 100 | nokogiri (>= 1.5.9) 101 | mail (2.6.3) 102 | mime-types (>= 1.16, < 3) 103 | mime-types (2.99) 104 | mini_portile2 (2.0.0) 105 | minitest (5.8.4) 106 | multi_json (1.11.2) 107 | multi_xml (0.5.5) 108 | nokogiri (1.6.7.2) 109 | mini_portile2 (~> 2.0.0.rc2) 110 | parser (2.3.0.2) 111 | ast (~> 2.2) 112 | powerpack (0.1.1) 113 | rack (1.6.4) 114 | rack-accept (0.4.5) 115 | rack (>= 0.4) 116 | rack-mount (0.8.3) 117 | rack (>= 1.0.0) 118 | rack-test (0.6.3) 119 | rack (>= 1.0) 120 | rails (4.2.5.1) 121 | actionmailer (= 4.2.5.1) 122 | actionpack (= 4.2.5.1) 123 | actionview (= 4.2.5.1) 124 | activejob (= 4.2.5.1) 125 | activemodel (= 4.2.5.1) 126 | activerecord (= 4.2.5.1) 127 | activesupport (= 4.2.5.1) 128 | bundler (>= 1.3.0, < 2.0) 129 | railties (= 4.2.5.1) 130 | sprockets-rails 131 | rails-deprecated_sanitizer (1.0.3) 132 | activesupport (>= 4.2.0.alpha) 133 | rails-dom-testing (1.0.7) 134 | activesupport (>= 4.2.0.beta, < 5.0) 135 | nokogiri (~> 1.6.0) 136 | rails-deprecated_sanitizer (>= 1.0.1) 137 | rails-html-sanitizer (1.0.3) 138 | loofah (~> 2.0) 139 | railties (4.2.5.1) 140 | actionpack (= 4.2.5.1) 141 | activesupport (= 4.2.5.1) 142 | rake (>= 0.8.7) 143 | thor (>= 0.18.1, < 2.0) 144 | rainbow (2.1.0) 145 | rake (10.5.0) 146 | rspec (3.4.0) 147 | rspec-core (~> 3.4.0) 148 | rspec-expectations (~> 3.4.0) 149 | rspec-mocks (~> 3.4.0) 150 | rspec-core (3.4.2) 151 | rspec-support (~> 3.4.0) 152 | rspec-expectations (3.4.0) 153 | diff-lcs (>= 1.2.0, < 2.0) 154 | rspec-support (~> 3.4.0) 155 | rspec-mocks (3.4.1) 156 | diff-lcs (>= 1.2.0, < 2.0) 157 | rspec-support (~> 3.4.0) 158 | rspec-rails (3.4.2) 159 | actionpack (>= 3.0, < 4.3) 160 | activesupport (>= 3.0, < 4.3) 161 | railties (>= 3.0, < 4.3) 162 | rspec-core (~> 3.4.0) 163 | rspec-expectations (~> 3.4.0) 164 | rspec-mocks (~> 3.4.0) 165 | rspec-support (~> 3.4.0) 166 | rspec-support (3.4.1) 167 | rubocop (0.37.0) 168 | parser (>= 2.3.0.2, < 3.0) 169 | powerpack (~> 0.1) 170 | rainbow (>= 1.99.1, < 3.0) 171 | ruby-progressbar (~> 1.7) 172 | unicode-display_width (~> 0.3) 173 | ruby-progressbar (1.7.5) 174 | rubyzip (1.1.7) 175 | sass (3.4.21) 176 | sass-rails (5.0.4) 177 | railties (>= 4.0.0, < 5.0) 178 | sass (~> 3.1) 179 | sprockets (>= 2.8, < 4.0) 180 | sprockets-rails (>= 2.0, < 4.0) 181 | tilt (>= 1.1, < 3) 182 | selenium-webdriver (2.50.0) 183 | childprocess (~> 0.5) 184 | multi_json (~> 1.0) 185 | rubyzip (~> 1.0) 186 | websocket (~> 1.0) 187 | sprockets (3.5.2) 188 | concurrent-ruby (~> 1.0) 189 | rack (> 1, < 3) 190 | sprockets-rails (3.0.1) 191 | actionpack (>= 4.0) 192 | activesupport (>= 4.0) 193 | sprockets (>= 3.0.0) 194 | sqlite3 (1.3.11) 195 | statsd-ruby (1.3.0) 196 | thor (0.19.1) 197 | thread_safe (0.3.5) 198 | tilt (2.0.2) 199 | tzinfo (1.2.2) 200 | thread_safe (~> 0.1) 201 | uglifier (2.7.2) 202 | execjs (>= 0.3.0) 203 | json (>= 1.8.0) 204 | unicode-display_width (0.3.1) 205 | virtus (1.0.5) 206 | axiom-types (~> 0.1) 207 | coercible (~> 1.0) 208 | descendants_tracker (~> 0.0, >= 0.0.3) 209 | equalizer (~> 0.0, >= 0.0.9) 210 | websocket (1.2.2) 211 | xpath (2.0.0) 212 | nokogiri (~> 1.3) 213 | zip-zip (0.3) 214 | rubyzip (>= 1.0.0) 215 | 216 | PLATFORMS 217 | ruby 218 | 219 | DEPENDENCIES 220 | capybara 221 | coffee-rails 222 | grape 223 | jquery-rails 224 | nokogiri 225 | rails 226 | rspec 227 | rspec-rails 228 | rubocop 229 | sass 230 | sass-rails 231 | selenium-webdriver 232 | sqlite3 233 | uglifier 234 | vitals! 235 | zip-zip 236 | 237 | BUNDLED WITH 238 | 1.11.2 239 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/README.md: -------------------------------------------------------------------------------- 1 | Grape on Rails 2 | ============== 3 | 4 | [![Build Status](https://travis-ci.org/ruby-grape/grape-on-rails.svg?branch=master)](https://travis-ci.org/ruby-grape/grape-on-rails) 5 | [![Dependency Status](https://gemnasium.com/ruby-grape/grape-on-rails.svg)](https://gemnasium.com/ruby-grape/grape-on-rails) 6 | [![Code Climate](https://codeclimate.com/github/ruby-grape/grape-on-rails.svg)](https://codeclimate.com/github/ruby-grape/grape-on-rails) 7 | 8 | A [Grape](http://github.com/ruby-grape/grape) API mounted on Rails. 9 | 10 | * [ping](app/api/acme/ping.rb): a hello world `GET` API 11 | * [post](app/api/acme/post.rb): post JSON data 12 | * [raise](app/api/acme/raise.rb): raise an error, Rails handling exceptions 13 | * [protected](app/api/acme/protected.rb): API protected with rudimentary Basic Authentication 14 | 15 | See 16 | --- 17 | 18 | An instance of this app is running on [grape-on-rails.herokuapp.com](http://grape-on-rails.herokuapp.com). 19 | 20 | Run 21 | --- 22 | 23 | ``` 24 | bundle install 25 | rails s 26 | ``` 27 | 28 | Try http://localhost:3000/api/ping or http://localhost:3000/api/protected/ping with _username_ and _password_. 29 | 30 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/Rakefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rake 2 | 3 | require File.expand_path('../config/application', __FILE__) 4 | 5 | GrapeOnRails::Application.load_tasks 6 | 7 | if Rails.env.test? || Rails.env.development? 8 | require 'rspec/core/rake_task' 9 | 10 | Rake::Task[:default].prerequisites.clear 11 | 12 | require 'rubocop/rake_task' 13 | RuboCop::RakeTask.new(:rubocop) 14 | 15 | task default: [:rubocop, :spec] 16 | end 17 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/app/api/acme/ping.rb: -------------------------------------------------------------------------------- 1 | module Acme 2 | class Ping < Grape::API 3 | desc 'Returns pong.' 4 | get :ping do 5 | { ping: params[:pong] || 'pong' } 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/app/api/acme/post.rb: -------------------------------------------------------------------------------- 1 | module Acme 2 | class Post < Grape::API 3 | desc 'Creates a spline that can be reticulated.' 4 | resource :spline do 5 | post do 6 | { reticulated: params[:reticulated] } 7 | end 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/app/api/acme/protected.rb: -------------------------------------------------------------------------------- 1 | module Acme 2 | class Protected < Grape::API 3 | namespace :protected do 4 | http_basic do |username, password| 5 | username == 'username' && password == 'password' 6 | end 7 | desc 'Returns pong if username=username and password=password.' 8 | get :ping do 9 | { ping: 'pong' } 10 | end 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/app/api/acme/raise.rb: -------------------------------------------------------------------------------- 1 | module Acme 2 | class Raise < Grape::API 3 | desc 'Raises an exception.' 4 | get :raise do 5 | raise 'Unexpected error.' 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/app/api/api.rb: -------------------------------------------------------------------------------- 1 | class API < Grape::API 2 | prefix 'api' 3 | format :json 4 | mount Acme::Ping 5 | mount Acme::Raise 6 | mount Acme::Protected 7 | mount Acme::Post 8 | end 9 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/app/assets/images/rails.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondot/vitals/6248acc31b9c892f2771a46ee46e3f8ec777d8b3/integration/multiverse/grape-on-rails/app/assets/images/rails.png -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/app/assets/javascripts/application.js: -------------------------------------------------------------------------------- 1 | // This is a manifest file that'll be compiled into application.js, which will include all the files 2 | // listed below. 3 | // 4 | // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, 5 | // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path. 6 | // 7 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the 8 | // the compiled file. 9 | // 10 | // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD 11 | // GO AFTER THE REQUIRES BELOW. 12 | // 13 | //= require jquery 14 | //= require jquery_ujs 15 | //= require_tree . 16 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/app/assets/javascripts/welcome.js.coffee: -------------------------------------------------------------------------------- 1 | # Place all the behaviors and hooks related to the matching controller here. 2 | # All this logic will automatically be available in application.js. 3 | # You can use CoffeeScript in this file: http://coffeescript.org/ 4 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/app/assets/stylesheets/application.css: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a manifest file that'll be compiled into application.css, which will include all the files 3 | * listed below. 4 | * 5 | * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, 6 | * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path. 7 | * 8 | * You're free to add application-wide styles to this file and they'll appear at the top of the 9 | * compiled file, but it's generally better to create a new file per style scope. 10 | * 11 | *= require_self 12 | *= require_tree . 13 | */ 14 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/app/assets/stylesheets/welcome.css.scss: -------------------------------------------------------------------------------- 1 | // Place all the styles related to the welcome controller here. 2 | // They will automatically be included in application.css. 3 | // You can use Sass (SCSS) here: http://sass-lang.com/ 4 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | protect_from_forgery 3 | end 4 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/app/controllers/welcome_controller.rb: -------------------------------------------------------------------------------- 1 | class WelcomeController < ApplicationController 2 | def index 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | end 3 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/app/helpers/welcome_helper.rb: -------------------------------------------------------------------------------- 1 | module WelcomeHelper 2 | end 3 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/app/mailers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondot/vitals/6248acc31b9c892f2771a46ee46e3f8ec777d8b3/integration/multiverse/grape-on-rails/app/mailers/.gitkeep -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/app/models/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondot/vitals/6248acc31b9c892f2771a46ee46e3f8ec777d8b3/integration/multiverse/grape-on-rails/app/models/.gitkeep -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | GrapeOnRails 5 | <%= stylesheet_link_tag "application", :media => "all" %> 6 | <%= javascript_include_tag "application" %> 7 | <%= csrf_meta_tags %> 8 | 9 | 10 | 11 | <%= yield %> 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/app/views/welcome/index.html.erb: -------------------------------------------------------------------------------- 1 |

Grape Mounted on Rails 4

2 | 6 | Fork me on Github 7 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/bin/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 3 | load Gem.bin_path('bundler', 'bundle') 4 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | APP_PATH = File.expand_path('../../config/application', __FILE__) 3 | require_relative '../config/boot' 4 | require 'rails/commands' 5 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require_relative '../config/boot' 3 | require 'rake' 4 | Rake.application.run 5 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require ::File.expand_path('../config/environment', __FILE__) 4 | run GrapeOnRails::Application 5 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/config/application.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../boot', __FILE__) 2 | 3 | # Pick the frameworks you want: 4 | require 'active_record/railtie' 5 | require 'action_controller/railtie' 6 | require 'action_mailer/railtie' 7 | require 'sprockets/railtie' 8 | # require "rails/test_unit/railtie" 9 | 10 | if defined?(Bundler) 11 | # If you precompile assets before deploying to production, use this line 12 | Bundler.require(*Rails.groups(assets: %w(development test))) 13 | # If you want your assets lazily compiled in production, use this line 14 | # Bundler.require(:default, :assets, Rails.env) 15 | end 16 | 17 | module GrapeOnRails 18 | class Application < Rails::Application 19 | # Settings in config/environments/* take precedence over those specified here. 20 | # Application configuration should go into files in config/initializers 21 | # -- all .rb files in that directory are automatically loaded. 22 | 23 | # Custom directories with classes and modules you want to be autoloadable. 24 | # config.autoload_paths += %W(#{config.root}/extras) 25 | 26 | # Auto-load API and its subdirectories 27 | config.paths.add 'app/api', glob: '**/*.rb' 28 | config.autoload_paths += Dir["#{Rails.root}/app/api/*"] 29 | 30 | # Only load the plugins named here, in the order given (default is alphabetical). 31 | # :all can be used as a placeholder for all plugins not explicitly named. 32 | # config.plugins = [ :exception_notification, :ssl_requirement, :all ] 33 | 34 | # Activate observers that should always be running. 35 | # config.active_record.observers = :cacher, :garbage_collector, :forum_observer 36 | 37 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. 38 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. 39 | # config.time_zone = 'Central Time (US & Canada)' 40 | 41 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. 42 | # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] 43 | # config.i18n.default_locale = :de 44 | 45 | # Configure the default encoding used in templates for Ruby 1.9. 46 | config.encoding = 'utf-8' 47 | 48 | # Configure sensitive parameters which will be filtered from the log file. 49 | config.filter_parameters += [:password] 50 | 51 | # Enable escaping HTML in JSON. 52 | config.active_support.escape_html_entities_in_json = true 53 | 54 | # Use SQL instead of Active Record's schema dumper when creating the database. 55 | # This is necessary if your schema can't be completely dumped by the schema dumper, 56 | # like if you have constraints or database-specific column types 57 | # config.active_record.schema_format = :sql 58 | 59 | # Enable the asset pipeline 60 | config.assets.enabled = true 61 | 62 | # Version of your assets, change this if you want to expire all your assets 63 | config.assets.version = '1.0' 64 | end 65 | end 66 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/config/boot.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | 3 | # Set up gems listed in the Gemfile. 4 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 5 | 6 | require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) 7 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/config/database.travis.yml: -------------------------------------------------------------------------------- 1 | test: 2 | adapter: postgresql 3 | database: grape_on_rails_test 4 | username: postgres 5 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/config/database.yml: -------------------------------------------------------------------------------- 1 | default: &default 2 | adapter: sqlite3 3 | pool: 5 4 | timeout: 5000 5 | 6 | development: 7 | <<: *default 8 | database: db/development.sqlite3 9 | 10 | # Warning: The database defined as "test" will be erased and 11 | # re-generated from your development database when you run "rake". 12 | # Do not set this db to the same as development or production. 13 | test: 14 | <<: *default 15 | database: db/test.sqlite3 16 | 17 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the rails application 2 | require File.expand_path('../application', __FILE__) 3 | 4 | # Initialize the rails application 5 | GrapeOnRails::Application.initialize! 6 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/config/environments/development.rb: -------------------------------------------------------------------------------- 1 | GrapeOnRails::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb 3 | 4 | config.eager_load = false 5 | 6 | # In the development environment your application's code is reloaded on 7 | # every request. This slows down response time but is perfect for development 8 | # since you don't have to restart the web server when you make code changes. 9 | config.cache_classes = false 10 | 11 | # Show full error reports and disable caching 12 | config.consider_all_requests_local = true 13 | config.action_controller.perform_caching = false 14 | 15 | # Don't care if the mailer can't send 16 | config.action_mailer.raise_delivery_errors = false 17 | 18 | # Print deprecation notices to the Rails logger 19 | config.active_support.deprecation = :log 20 | 21 | # Only use best-standards-support built into browsers 22 | config.action_dispatch.best_standards_support = :builtin 23 | 24 | # Do not compress assets 25 | config.assets.compress = false 26 | 27 | # Expands the lines which load the assets 28 | config.assets.debug = true 29 | end 30 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/config/environments/production.rb: -------------------------------------------------------------------------------- 1 | GrapeOnRails::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb 3 | 4 | config.eager_load = true 5 | 6 | # Code is not reloaded between requests 7 | config.cache_classes = true 8 | 9 | # Full error reports are disabled and caching is turned on 10 | config.consider_all_requests_local = false 11 | config.action_controller.perform_caching = true 12 | 13 | # Disable Rails's static asset server (Apache or nginx will already do this) 14 | config.serve_static_files = false 15 | 16 | # Compress JavaScripts and CSS 17 | config.assets.compress = true 18 | 19 | # Don't fallback to assets pipeline if a precompiled asset is missed 20 | config.assets.compile = false 21 | 22 | # Generate digests for assets URLs 23 | config.assets.digest = true 24 | 25 | # Defaults to nil and saved in location specified by config.assets.prefix 26 | # config.assets.manifest = YOUR_PATH 27 | 28 | # Specifies the header that your server uses for sending files 29 | # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache 30 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx 31 | 32 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 33 | # config.force_ssl = true 34 | 35 | # See everything in the log (default is :info) 36 | # config.log_level = :debug 37 | 38 | # Prepend all log lines with the following tags 39 | # config.log_tags = [ :subdomain, :uuid ] 40 | 41 | # Use a different logger for distributed setups 42 | # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) 43 | 44 | # Use a different cache store in production 45 | # config.cache_store = :mem_cache_store 46 | 47 | # Enable serving of images, stylesheets, and JavaScripts from an asset server 48 | # config.action_controller.asset_host = "http://assets.example.com" 49 | 50 | # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added) 51 | # config.assets.precompile += %w( search.js ) 52 | 53 | # Disable delivery errors, bad email addresses will be ignored 54 | # config.action_mailer.raise_delivery_errors = false 55 | 56 | # Enable threaded mode 57 | # config.threadsafe! 58 | 59 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 60 | # the I18n.default_locale when a translation can not be found) 61 | config.i18n.fallbacks = true 62 | 63 | # Send deprecation notices to registered listeners 64 | config.active_support.deprecation = :notify 65 | end 66 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/config/environments/test.rb: -------------------------------------------------------------------------------- 1 | GrapeOnRails::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb 3 | 4 | config.eager_load = false 5 | 6 | # The test environment is used exclusively to run your application's 7 | # test suite. You never need to work with it otherwise. Remember that 8 | # your test database is "scratch space" for the test suite and is wiped 9 | # and recreated between test runs. Don't rely on the data there! 10 | config.cache_classes = true 11 | 12 | # Configure static asset server for tests with Cache-Control for performance 13 | config.serve_static_files = true 14 | config.static_cache_control = 'public, max-age=3600' 15 | 16 | # Show full error reports and disable caching 17 | config.consider_all_requests_local = true 18 | config.action_controller.perform_caching = false 19 | 20 | # Raise exceptions instead of rendering exception templates 21 | config.action_dispatch.show_exceptions = true 22 | 23 | # Disable request forgery protection in test environment 24 | config.action_controller.allow_forgery_protection = false 25 | 26 | # Tell Action Mailer not to deliver emails to the real world. 27 | # The :test delivery method accumulates sent emails in the 28 | # ActionMailer::Base.deliveries array. 29 | config.action_mailer.delivery_method = :test 30 | 31 | # Print deprecation notices to the stderr 32 | config.active_support.deprecation = :stderr 33 | end 34 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 7 | # Rails.backtrace_cleaner.remove_silencers! 8 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format 4 | # (all these examples are active by default): 5 | # ActiveSupport::Inflector.inflections do |inflect| 6 | # inflect.plural /^(ox)$/i, '\1en' 7 | # inflect.singular /^(ox)en/i, '\1' 8 | # inflect.irregular 'person', 'people' 9 | # inflect.uncountable %w( fish sheep ) 10 | # end 11 | # 12 | # These inflection rules are supported but not enabled by default: 13 | # ActiveSupport::Inflector.inflections do |inflect| 14 | # inflect.acronym 'RESTful' 15 | # end 16 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new mime types for use in respond_to blocks: 4 | # Mime::Type.register "text/richtext", :rtf 5 | # Mime::Type.register_alias "text/html", :iphone 6 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/config/initializers/reload_api.rb: -------------------------------------------------------------------------------- 1 | api_dir = "#{Rails.root}/app/api" 2 | file_ext = 'rb' 3 | 4 | api_files = Dir["#{api_dir}/**/*.#{file_ext}"] 5 | 6 | api_reloader = ActiveSupport::FileUpdateChecker.new(api_files, api_dir => file_ext) do 7 | Rails.logger.info 'Reload routes for changed api files' 8 | Rails.application.reload_routes! 9 | end 10 | 11 | ActionDispatch::Reloader.to_prepare do 12 | api_reloader.execute_if_updated 13 | end 14 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/config/initializers/secret_token.rb: -------------------------------------------------------------------------------- 1 | GrapeOnRails::Application.config.secret_key_base = 'secret' 2 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | GrapeOnRails::Application.config.session_store :cookie_store, key: '_grape-on-rails_session' 4 | 5 | # Use the database for sessions instead of the cookie-based default, 6 | # which shouldn't be used to store highly confidential information 7 | # (create the session table with "rails generate session_migration") 8 | # GrapeOnRails::Application.config.session_store :active_record_store 9 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/config/initializers/vitals.rb: -------------------------------------------------------------------------------- 1 | require 'vitals' 2 | Vitals.configure! do |c| 3 | c.facility = 'grape_app' 4 | end 5 | 6 | require 'vitals/integrations/notifications/grape' 7 | Vitals::Integrations::Notifications::Grape.subscribe! 8 | 9 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | # 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] 9 | end 10 | 11 | # Disable root element in JSON by default. 12 | ActiveSupport.on_load(:active_record) do 13 | self.include_root_in_json = false 14 | end 15 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Sample localization file for English. Add more files in this directory for other locales. 2 | # See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points. 3 | 4 | en: 5 | hello: "Hello world" 6 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/config/routes.rb: -------------------------------------------------------------------------------- 1 | GrapeOnRails::Application.routes.draw do 2 | get 'welcome/index' 3 | mount API => '/' 4 | root 'welcome#index' 5 | end 6 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/db/schema.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # This file is auto-generated from the current state of the database. Instead 3 | # of editing this file, please use the migrations feature of Active Record to 4 | # incrementally modify your database, and then regenerate this schema definition. 5 | # 6 | # Note that this schema.rb definition is the authoritative source for your 7 | # database schema. If you need to create the application database on another 8 | # system, you should be using db:schema:load, not running all the migrations 9 | # from scratch. The latter is a flawed and unsustainable approach (the more migrations 10 | # you'll amass, the slower it'll run and the greater likelihood for issues). 11 | # 12 | # It's strongly recommended that you check this file into your version control system. 13 | 14 | ActiveRecord::Schema.define(version: 0) do 15 | 16 | end 17 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/db/seeds.rb: -------------------------------------------------------------------------------- 1 | # This file should contain all the record creation needed to seed the database with its default values. 2 | # The data can then be loaded with the rake db:seed (or created alongside the db with db:setup). 3 | # 4 | # Examples: 5 | # 6 | # cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }]) 7 | # Mayor.create(name: 'Emanuel', city: cities.first) 8 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/doc/README_FOR_APP: -------------------------------------------------------------------------------- 1 | Use this README file to introduce your application and point to useful places in the API for learning more. 2 | Run "rake doc:app" to generate API documentation for your models, controllers, helpers, and libraries. 3 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/lib/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondot/vitals/6248acc31b9c892f2771a46ee46e3f8ec777d8b3/integration/multiverse/grape-on-rails/lib/assets/.gitkeep -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/lib/tasks/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondot/vitals/6248acc31b9c892f2771a46ee46e3f8ec777d8b3/integration/multiverse/grape-on-rails/lib/tasks/.gitkeep -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/log/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondot/vitals/6248acc31b9c892f2771a46ee46e3f8ec777d8b3/integration/multiverse/grape-on-rails/log/.gitkeep -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The page you were looking for doesn't exist (404) 5 | 17 | 18 | 19 | 20 | 21 |
22 |

The page you were looking for doesn't exist.

23 |

You may have mistyped the address or the page may have moved.

24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/public/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The change you wanted was rejected (422) 5 | 17 | 18 | 19 | 20 | 21 |
22 |

The change you wanted was rejected.

23 |

Maybe you tried to change something you didn't have access to.

24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/public/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | We're sorry, but something went wrong (500) 5 | 17 | 18 | 19 | 20 | 21 |
22 |

We're sorry, but something went wrong.

23 |
24 | 25 | 26 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondot/vitals/6248acc31b9c892f2771a46ee46e3f8ec777d8b3/integration/multiverse/grape-on-rails/public/favicon.ico -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/public/robots.txt: -------------------------------------------------------------------------------- 1 | # See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file 2 | # 3 | # To ban all spiders from the entire site uncomment the next two lines: 4 | # User-Agent: * 5 | # Disallow: / 6 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/script/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. 3 | 4 | APP_PATH = File.expand_path('../../config/application', __FILE__) 5 | require File.expand_path('../../config/boot', __FILE__) 6 | require 'rails/commands' 7 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/spec/api/ping_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Acme::Ping do 4 | before do 5 | Vitals.reporter.flush 6 | end 7 | it 'ping' do 8 | get '/api/ping' 9 | metrics = %w{ 10 | grape.api.ping.get.200.all 11 | } 12 | assert_timings Vitals.reporter.reports, metrics, [0] 13 | expect(response.body).to eq({ ping: 'pong' }.to_json) 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /integration/multiverse/grape-on-rails/spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | 3 | ENV['RAILS_ENV'] = 'test' 4 | 5 | require File.expand_path('../../config/environment', __FILE__) 6 | 7 | require 'rspec/rails' 8 | RSpec.configure do |config| 9 | config.mock_with :rspec 10 | config.expect_with :rspec 11 | config.include RSpec::Rails::RequestExampleGroup, type: :request, file_path: /spec\/api/ 12 | end 13 | 14 | require 'capybara/rspec' 15 | require File.expand_path( '../../../multiverse_helper', File.dirname(__FILE__)) 16 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files for more about ignoring files. 2 | # 3 | # If you find yourself ignoring temporary files generated by your text editor 4 | # or operating system, you probably want to add a global ignore instead: 5 | # git config --global core.excludesfile '~/.gitignore_global' 6 | 7 | # Ignore bundler config. 8 | /.bundle 9 | 10 | # Ignore the default SQLite database. 11 | /db/*.sqlite3 12 | /db/*.sqlite3-journal 13 | 14 | # Ignore all logfiles and tempfiles. 15 | /log/* 16 | !/log/.keep 17 | /tmp 18 | vendor/ 19 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | 4 | # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' 5 | gem 'rails', '4.2.5' 6 | # Use sqlite3 as the database for Active Record 7 | gem 'sqlite3' 8 | # Use SCSS for stylesheets 9 | gem 'sass-rails', '~> 5.0' 10 | # Use Uglifier as compressor for JavaScript assets 11 | gem 'uglifier', '>= 1.3.0' 12 | # Use CoffeeScript for .coffee assets and views 13 | gem 'coffee-rails', '~> 4.1.0' 14 | # See https://github.com/rails/execjs#readme for more supported runtimes 15 | # gem 'therubyracer', platforms: :ruby 16 | 17 | # Use jquery as the JavaScript library 18 | gem 'jquery-rails' 19 | # Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks 20 | gem 'turbolinks' 21 | # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder 22 | gem 'jbuilder', '~> 2.0' 23 | # bundle exec rake doc:rails generates the API under doc/api. 24 | gem 'sdoc', '~> 0.4.0', group: :doc 25 | 26 | # Use ActiveModel has_secure_password 27 | # gem 'bcrypt', '~> 3.1.7' 28 | 29 | # Use Unicorn as the app server 30 | # gem 'unicorn' 31 | 32 | # Use Capistrano for deployment 33 | # gem 'capistrano-rails', group: :development 34 | 35 | group :development, :test do 36 | # Call 'byebug' anywhere in the code to stop execution and get a debugger console 37 | gem 'byebug' 38 | end 39 | 40 | group :development do 41 | # Access an IRB console on exception pages or by using <%= console %> in views 42 | gem 'web-console', '~> 2.0' 43 | 44 | # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring 45 | gem 'spring' 46 | end 47 | 48 | gem 'vitals', path: '../../../' 49 | 50 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: ../../../ 3 | specs: 4 | vitals (0.3.0) 5 | statsd-ruby (~> 1.3.0) 6 | 7 | GEM 8 | remote: https://rubygems.org/ 9 | specs: 10 | actionmailer (4.2.5) 11 | actionpack (= 4.2.5) 12 | actionview (= 4.2.5) 13 | activejob (= 4.2.5) 14 | mail (~> 2.5, >= 2.5.4) 15 | rails-dom-testing (~> 1.0, >= 1.0.5) 16 | actionpack (4.2.5) 17 | actionview (= 4.2.5) 18 | activesupport (= 4.2.5) 19 | rack (~> 1.6) 20 | rack-test (~> 0.6.2) 21 | rails-dom-testing (~> 1.0, >= 1.0.5) 22 | rails-html-sanitizer (~> 1.0, >= 1.0.2) 23 | actionview (4.2.5) 24 | activesupport (= 4.2.5) 25 | builder (~> 3.1) 26 | erubis (~> 2.7.0) 27 | rails-dom-testing (~> 1.0, >= 1.0.5) 28 | rails-html-sanitizer (~> 1.0, >= 1.0.2) 29 | activejob (4.2.5) 30 | activesupport (= 4.2.5) 31 | globalid (>= 0.3.0) 32 | activemodel (4.2.5) 33 | activesupport (= 4.2.5) 34 | builder (~> 3.1) 35 | activerecord (4.2.5) 36 | activemodel (= 4.2.5) 37 | activesupport (= 4.2.5) 38 | arel (~> 6.0) 39 | activesupport (4.2.5) 40 | i18n (~> 0.7) 41 | json (~> 1.7, >= 1.7.7) 42 | minitest (~> 5.1) 43 | thread_safe (~> 0.3, >= 0.3.4) 44 | tzinfo (~> 1.1) 45 | arel (6.0.3) 46 | binding_of_caller (0.7.2) 47 | debug_inspector (>= 0.0.1) 48 | builder (3.2.2) 49 | byebug (8.2.2) 50 | coffee-rails (4.1.1) 51 | coffee-script (>= 2.2.0) 52 | railties (>= 4.0.0, < 5.1.x) 53 | coffee-script (2.4.1) 54 | coffee-script-source 55 | execjs 56 | coffee-script-source (1.10.0) 57 | concurrent-ruby (1.0.1) 58 | debug_inspector (0.0.2) 59 | erubis (2.7.0) 60 | execjs (2.6.0) 61 | globalid (0.3.6) 62 | activesupport (>= 4.1.0) 63 | i18n (0.7.0) 64 | jbuilder (2.4.1) 65 | activesupport (>= 3.0.0, < 5.1) 66 | multi_json (~> 1.2) 67 | jquery-rails (4.1.1) 68 | rails-dom-testing (>= 1, < 3) 69 | railties (>= 4.2.0) 70 | thor (>= 0.14, < 2.0) 71 | json (1.8.3) 72 | loofah (2.0.3) 73 | nokogiri (>= 1.5.9) 74 | mail (2.6.3) 75 | mime-types (>= 1.16, < 3) 76 | mime-types (2.99.1) 77 | mini_portile2 (2.0.0) 78 | minitest (5.8.4) 79 | multi_json (1.11.2) 80 | nokogiri (1.6.7.2) 81 | mini_portile2 (~> 2.0.0.rc2) 82 | rack (1.6.4) 83 | rack-test (0.6.3) 84 | rack (>= 1.0) 85 | rails (4.2.5) 86 | actionmailer (= 4.2.5) 87 | actionpack (= 4.2.5) 88 | actionview (= 4.2.5) 89 | activejob (= 4.2.5) 90 | activemodel (= 4.2.5) 91 | activerecord (= 4.2.5) 92 | activesupport (= 4.2.5) 93 | bundler (>= 1.3.0, < 2.0) 94 | railties (= 4.2.5) 95 | sprockets-rails 96 | rails-deprecated_sanitizer (1.0.3) 97 | activesupport (>= 4.2.0.alpha) 98 | rails-dom-testing (1.0.7) 99 | activesupport (>= 4.2.0.beta, < 5.0) 100 | nokogiri (~> 1.6.0) 101 | rails-deprecated_sanitizer (>= 1.0.1) 102 | rails-html-sanitizer (1.0.3) 103 | loofah (~> 2.0) 104 | railties (4.2.5) 105 | actionpack (= 4.2.5) 106 | activesupport (= 4.2.5) 107 | rake (>= 0.8.7) 108 | thor (>= 0.18.1, < 2.0) 109 | rake (11.1.1) 110 | rdoc (4.2.2) 111 | json (~> 1.4) 112 | sass (3.4.21) 113 | sass-rails (5.0.4) 114 | railties (>= 4.0.0, < 5.0) 115 | sass (~> 3.1) 116 | sprockets (>= 2.8, < 4.0) 117 | sprockets-rails (>= 2.0, < 4.0) 118 | tilt (>= 1.1, < 3) 119 | sdoc (0.4.1) 120 | json (~> 1.7, >= 1.7.7) 121 | rdoc (~> 4.0) 122 | spring (1.6.4) 123 | sprockets (3.5.2) 124 | concurrent-ruby (~> 1.0) 125 | rack (> 1, < 3) 126 | sprockets-rails (3.0.4) 127 | actionpack (>= 4.0) 128 | activesupport (>= 4.0) 129 | sprockets (>= 3.0.0) 130 | sqlite3 (1.3.11) 131 | statsd-ruby (1.3.0) 132 | thor (0.19.1) 133 | thread_safe (0.3.5) 134 | tilt (2.0.2) 135 | turbolinks (2.5.3) 136 | coffee-rails 137 | tzinfo (1.2.2) 138 | thread_safe (~> 0.1) 139 | uglifier (2.7.2) 140 | execjs (>= 0.3.0) 141 | json (>= 1.8.0) 142 | web-console (2.3.0) 143 | activemodel (>= 4.0) 144 | binding_of_caller (>= 0.7.2) 145 | railties (>= 4.0) 146 | sprockets-rails (>= 2.0, < 4.0) 147 | 148 | PLATFORMS 149 | ruby 150 | 151 | DEPENDENCIES 152 | byebug 153 | coffee-rails (~> 4.1.0) 154 | jbuilder (~> 2.0) 155 | jquery-rails 156 | rails (= 4.2.5) 157 | sass-rails (~> 5.0) 158 | sdoc (~> 0.4.0) 159 | spring 160 | sqlite3 161 | turbolinks 162 | uglifier (>= 1.3.0) 163 | vitals! 164 | web-console (~> 2.0) 165 | 166 | BUNDLED WITH 167 | 1.11.2 168 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/README.rdoc: -------------------------------------------------------------------------------- 1 | == README 2 | 3 | This README would normally document whatever steps are necessary to get the 4 | application up and running. 5 | 6 | Things you may want to cover: 7 | 8 | * Ruby version 9 | 10 | * System dependencies 11 | 12 | * Configuration 13 | 14 | * Database creation 15 | 16 | * Database initialization 17 | 18 | * How to run the test suite 19 | 20 | * Services (job queues, cache servers, search engines, etc.) 21 | 22 | * Deployment instructions 23 | 24 | * ... 25 | 26 | 27 | Please feel free to use a different markup language if you do not plan to run 28 | rake doc:app. 29 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/Rakefile: -------------------------------------------------------------------------------- 1 | # Add your own tasks in files placed in lib/tasks ending in .rake, 2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 3 | 4 | require File.expand_path('../config/application', __FILE__) 5 | 6 | Rails.application.load_tasks 7 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/app/assets/images/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondot/vitals/6248acc31b9c892f2771a46ee46e3f8ec777d8b3/integration/multiverse/rails42_app/app/assets/images/.keep -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/app/assets/javascripts/application.js: -------------------------------------------------------------------------------- 1 | // This is a manifest file that'll be compiled into application.js, which will include all the files 2 | // listed below. 3 | // 4 | // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, 5 | // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path. 6 | // 7 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the 8 | // compiled file. 9 | // 10 | // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details 11 | // about supported directives. 12 | // 13 | //= require jquery 14 | //= require jquery_ujs 15 | //= require turbolinks 16 | //= require_tree . 17 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/app/assets/javascripts/posts.coffee: -------------------------------------------------------------------------------- 1 | # Place all the behaviors and hooks related to the matching controller here. 2 | # All this logic will automatically be available in application.js. 3 | # You can use CoffeeScript in this file: http://coffeescript.org/ 4 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/app/assets/stylesheets/application.css: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a manifest file that'll be compiled into application.css, which will include all the files 3 | * listed below. 4 | * 5 | * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, 6 | * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path. 7 | * 8 | * You're free to add application-wide styles to this file and they'll appear at the bottom of the 9 | * compiled file so the styles you add here take precedence over styles defined in any styles 10 | * defined in the other CSS/SCSS files in this directory. It is generally better to create a new 11 | * file per style scope. 12 | * 13 | *= require_tree . 14 | *= require_self 15 | */ 16 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/app/assets/stylesheets/posts.scss: -------------------------------------------------------------------------------- 1 | // Place all the styles related to the Posts controller here. 2 | // They will automatically be included in application.css. 3 | // You can use Sass (SCSS) here: http://sass-lang.com/ 4 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/app/assets/stylesheets/scaffolds.scss: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #fff; 3 | color: #333; 4 | font-family: verdana, arial, helvetica, sans-serif; 5 | font-size: 13px; 6 | line-height: 18px; 7 | } 8 | 9 | p, ol, ul, td { 10 | font-family: verdana, arial, helvetica, sans-serif; 11 | font-size: 13px; 12 | line-height: 18px; 13 | } 14 | 15 | pre { 16 | background-color: #eee; 17 | padding: 10px; 18 | font-size: 11px; 19 | } 20 | 21 | a { 22 | color: #000; 23 | 24 | &:visited { 25 | color: #666; 26 | } 27 | 28 | &:hover { 29 | color: #fff; 30 | background-color: #000; 31 | } 32 | } 33 | 34 | div { 35 | &.field, &.actions { 36 | margin-bottom: 10px; 37 | } 38 | } 39 | 40 | #notice { 41 | color: green; 42 | } 43 | 44 | .field_with_errors { 45 | padding: 2px; 46 | background-color: red; 47 | display: table; 48 | } 49 | 50 | #error_explanation { 51 | width: 450px; 52 | border: 2px solid red; 53 | padding: 7px; 54 | padding-bottom: 0; 55 | margin-bottom: 20px; 56 | background-color: #f0f0f0; 57 | 58 | h2 { 59 | text-align: left; 60 | font-weight: bold; 61 | padding: 5px 5px 5px 15px; 62 | font-size: 12px; 63 | margin: -7px; 64 | margin-bottom: 0px; 65 | background-color: #c00; 66 | color: #fff; 67 | } 68 | 69 | ul li { 70 | font-size: 12px; 71 | list-style: square; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | # Prevent CSRF attacks by raising an exception. 3 | # For APIs, you may want to use :null_session instead. 4 | protect_from_forgery with: :exception 5 | end 6 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/app/controllers/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondot/vitals/6248acc31b9c892f2771a46ee46e3f8ec777d8b3/integration/multiverse/rails42_app/app/controllers/concerns/.keep -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/app/controllers/posts_controller.rb: -------------------------------------------------------------------------------- 1 | class PostsController < ApplicationController 2 | before_action :set_post, only: [:show, :edit, :update, :destroy] 3 | 4 | # GET /posts 5 | # GET /posts.json 6 | def index 7 | @posts = Post.all 8 | end 9 | 10 | # GET /posts/1 11 | # GET /posts/1.json 12 | def show 13 | end 14 | 15 | # GET /posts/new 16 | def new 17 | FoobarCleanupJob.perform_later 18 | @post = Post.new 19 | end 20 | 21 | # GET /posts/1/edit 22 | def edit 23 | end 24 | 25 | # POST /posts 26 | # POST /posts.json 27 | def create 28 | @post = Post.new(post_params) 29 | 30 | respond_to do |format| 31 | if @post.save 32 | format.html { redirect_to @post, notice: 'Post was successfully created.' } 33 | format.json { render :show, status: :created, location: @post } 34 | else 35 | format.html { render :new } 36 | format.json { render json: @post.errors, status: :unprocessable_entity } 37 | end 38 | end 39 | end 40 | 41 | # PATCH/PUT /posts/1 42 | # PATCH/PUT /posts/1.json 43 | def update 44 | respond_to do |format| 45 | if @post.update(post_params) 46 | format.html { redirect_to @post, notice: 'Post was successfully updated.' } 47 | format.json { render :show, status: :ok, location: @post } 48 | else 49 | format.html { render :edit } 50 | format.json { render json: @post.errors, status: :unprocessable_entity } 51 | end 52 | end 53 | end 54 | 55 | # DELETE /posts/1 56 | # DELETE /posts/1.json 57 | def destroy 58 | @post.destroy 59 | respond_to do |format| 60 | format.html { redirect_to posts_url, notice: 'Post was successfully destroyed.' } 61 | format.json { head :no_content } 62 | end 63 | end 64 | 65 | private 66 | # Use callbacks to share common setup or constraints between actions. 67 | def set_post 68 | @post = Post.find(params[:id]) 69 | end 70 | 71 | # Never trust parameters from the scary internet, only allow the white list through. 72 | def post_params 73 | params.require(:post).permit(:title) 74 | end 75 | end 76 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | end 3 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/app/helpers/posts_helper.rb: -------------------------------------------------------------------------------- 1 | module PostsHelper 2 | end 3 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/app/jobs/foobar_cleanup_job.rb: -------------------------------------------------------------------------------- 1 | class FoobarCleanupJob < ActiveJob::Base 2 | queue_as :default 3 | 4 | def perform(*args) 5 | # Do something later 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/app/mailers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondot/vitals/6248acc31b9c892f2771a46ee46e3f8ec777d8b3/integration/multiverse/rails42_app/app/mailers/.keep -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/app/models/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondot/vitals/6248acc31b9c892f2771a46ee46e3f8ec777d8b3/integration/multiverse/rails42_app/app/models/.keep -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/app/models/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondot/vitals/6248acc31b9c892f2771a46ee46e3f8ec777d8b3/integration/multiverse/rails42_app/app/models/concerns/.keep -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/app/models/post.rb: -------------------------------------------------------------------------------- 1 | class Post < ActiveRecord::Base 2 | end 3 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Rails42App 5 | <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %> 6 | <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %> 7 | <%= csrf_meta_tags %> 8 | 9 | 10 | 11 | <%= yield %> 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/app/views/posts/_form.html.erb: -------------------------------------------------------------------------------- 1 | <%= form_for(@post) do |f| %> 2 | <% if @post.errors.any? %> 3 |
4 |

<%= pluralize(@post.errors.count, "error") %> prohibited this post from being saved:

5 | 6 | 11 |
12 | <% end %> 13 | 14 |
15 | <%= f.label :title %>
16 | <%= f.text_field :title %> 17 |
18 |
19 | <%= f.submit %> 20 |
21 | <% end %> 22 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/app/views/posts/edit.html.erb: -------------------------------------------------------------------------------- 1 |

Editing Post

2 | 3 | <%= render 'form' %> 4 | 5 | <%= link_to 'Show', @post %> | 6 | <%= link_to 'Back', posts_path %> 7 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/app/views/posts/index.html.erb: -------------------------------------------------------------------------------- 1 |

<%= notice %>

2 | 3 |

Listing Posts

4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | <% @posts.each do |post| %> 15 | 16 | 17 | 18 | 19 | 20 | 21 | <% end %> 22 | 23 |
Title
<%= post.title %><%= link_to 'Show', post %><%= link_to 'Edit', edit_post_path(post) %><%= link_to 'Destroy', post, method: :delete, data: { confirm: 'Are you sure?' } %>
24 | 25 |
26 | 27 | <%= link_to 'New Post', new_post_path %> 28 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/app/views/posts/index.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.array!(@posts) do |post| 2 | json.extract! post, :id, :title 3 | json.url post_url(post, format: :json) 4 | end 5 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/app/views/posts/new.html.erb: -------------------------------------------------------------------------------- 1 |

New Post

2 | 3 | <%= render 'form' %> 4 | 5 | <%= link_to 'Back', posts_path %> 6 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/app/views/posts/show.html.erb: -------------------------------------------------------------------------------- 1 |

<%= notice %>

2 | 3 |

4 | Title: 5 | <%= @post.title %> 6 |

7 | 8 | <%= link_to 'Edit', edit_post_path(@post) %> | 9 | <%= link_to 'Back', posts_path %> 10 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/app/views/posts/show.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.extract! @post, :id, :title, :created_at, :updated_at 2 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/bin/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 3 | load Gem.bin_path('bundler', 'bundle') 4 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | begin 3 | load File.expand_path('../spring', __FILE__) 4 | rescue LoadError => e 5 | raise unless e.message.include?('spring') 6 | end 7 | APP_PATH = File.expand_path('../../config/application', __FILE__) 8 | require_relative '../config/boot' 9 | require 'rails/commands' 10 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | begin 3 | load File.expand_path('../spring', __FILE__) 4 | rescue LoadError => e 5 | raise unless e.message.include?('spring') 6 | end 7 | require_relative '../config/boot' 8 | require 'rake' 9 | Rake.application.run 10 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'pathname' 3 | 4 | # path to your application root. 5 | APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) 6 | 7 | Dir.chdir APP_ROOT do 8 | # This script is a starting point to setup your application. 9 | # Add necessary setup steps to this file: 10 | 11 | puts "== Installing dependencies ==" 12 | system "gem install bundler --conservative" 13 | system "bundle check || bundle install" 14 | 15 | # puts "\n== Copying sample files ==" 16 | # unless File.exist?("config/database.yml") 17 | # system "cp config/database.yml.sample config/database.yml" 18 | # end 19 | 20 | puts "\n== Preparing database ==" 21 | system "bin/rake db:setup" 22 | 23 | puts "\n== Removing old logs and tempfiles ==" 24 | system "rm -f log/*" 25 | system "rm -rf tmp/cache" 26 | 27 | puts "\n== Restarting application server ==" 28 | system "touch tmp/restart.txt" 29 | end 30 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/bin/spring: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | # This file loads spring without using Bundler, in order to be fast. 4 | # It gets overwritten when you run the `spring binstub` command. 5 | 6 | unless defined?(Spring) 7 | require 'rubygems' 8 | require 'bundler' 9 | 10 | if (match = Bundler.default_lockfile.read.match(/^GEM$.*?^ (?: )*spring \((.*?)\)$.*?^$/m)) 11 | Gem.paths = { 'GEM_PATH' => [Bundler.bundle_path.to_s, *Gem.path].uniq.join(Gem.path_separator) } 12 | gem 'spring', match[1] 13 | require 'spring/binstub' 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require ::File.expand_path('../config/environment', __FILE__) 4 | run Rails.application 5 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/config/application.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../boot', __FILE__) 2 | 3 | require 'rails/all' 4 | 5 | # Require the gems listed in Gemfile, including any gems 6 | # you've limited to :test, :development, or :production. 7 | Bundler.require(*Rails.groups) 8 | 9 | module Rails42App 10 | class Application < Rails::Application 11 | # Settings in config/environments/* take precedence over those specified here. 12 | # Application configuration should go into files in config/initializers 13 | # -- all .rb files in that directory are automatically loaded. 14 | 15 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. 16 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. 17 | # config.time_zone = 'Central Time (US & Canada)' 18 | 19 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. 20 | # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] 21 | # config.i18n.default_locale = :de 22 | 23 | # Do not swallow errors in after_commit/after_rollback callbacks. 24 | config.active_record.raise_in_transactional_callbacks = true 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/config/boot.rb: -------------------------------------------------------------------------------- 1 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 2 | 3 | require 'bundler/setup' # Set up gems listed in the Gemfile. 4 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/config/database.yml: -------------------------------------------------------------------------------- 1 | # SQLite version 3.x 2 | # gem install sqlite3 3 | # 4 | # Ensure the SQLite 3 gem is defined in your Gemfile 5 | # gem 'sqlite3' 6 | # 7 | default: &default 8 | adapter: sqlite3 9 | pool: 5 10 | timeout: 5000 11 | 12 | development: 13 | <<: *default 14 | database: db/development.sqlite3 15 | 16 | # Warning: The database defined as "test" will be erased and 17 | # re-generated from your development database when you run "rake". 18 | # Do not set this db to the same as development or production. 19 | test: 20 | <<: *default 21 | database: db/test.sqlite3 22 | 23 | production: 24 | <<: *default 25 | database: db/production.sqlite3 26 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the Rails application. 2 | require File.expand_path('../application', __FILE__) 3 | 4 | # Initialize the Rails application. 5 | Rails.application.initialize! 6 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/config/environments/development.rb: -------------------------------------------------------------------------------- 1 | Rails.application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # In the development environment your application's code is reloaded on 5 | # every request. This slows down response time but is perfect for development 6 | # since you don't have to restart the web server when you make code changes. 7 | config.cache_classes = false 8 | 9 | # Do not eager load code on boot. 10 | config.eager_load = false 11 | 12 | # Show full error reports and disable caching. 13 | config.consider_all_requests_local = true 14 | config.action_controller.perform_caching = false 15 | 16 | # Don't care if the mailer can't send. 17 | config.action_mailer.raise_delivery_errors = false 18 | 19 | # Print deprecation notices to the Rails logger. 20 | config.active_support.deprecation = :log 21 | 22 | # Raise an error on page load if there are pending migrations. 23 | config.active_record.migration_error = :page_load 24 | 25 | # Debug mode disables concatenation and preprocessing of assets. 26 | # This option may cause significant delays in view rendering with a large 27 | # number of complex assets. 28 | config.assets.debug = true 29 | 30 | # Asset digests allow you to set far-future HTTP expiration dates on all assets, 31 | # yet still be able to expire them through the digest params. 32 | config.assets.digest = true 33 | 34 | # Adds additional error checking when serving assets at runtime. 35 | # Checks for improperly declared sprockets dependencies. 36 | # Raises helpful error messages. 37 | config.assets.raise_runtime_errors = true 38 | 39 | # Raises error for missing translations 40 | # config.action_view.raise_on_missing_translations = true 41 | end 42 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/config/environments/production.rb: -------------------------------------------------------------------------------- 1 | Rails.application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # Code is not reloaded between requests. 5 | config.cache_classes = true 6 | 7 | # Eager load code on boot. This eager loads most of Rails and 8 | # your application in memory, allowing both threaded web servers 9 | # and those relying on copy on write to perform better. 10 | # Rake tasks automatically ignore this option for performance. 11 | config.eager_load = true 12 | 13 | # Full error reports are disabled and caching is turned on. 14 | config.consider_all_requests_local = false 15 | config.action_controller.perform_caching = true 16 | 17 | # Enable Rack::Cache to put a simple HTTP cache in front of your application 18 | # Add `rack-cache` to your Gemfile before enabling this. 19 | # For large-scale production use, consider using a caching reverse proxy like 20 | # NGINX, varnish or squid. 21 | # config.action_dispatch.rack_cache = true 22 | 23 | # Disable serving static files from the `/public` folder by default since 24 | # Apache or NGINX already handles this. 25 | config.serve_static_files = ENV['RAILS_SERVE_STATIC_FILES'].present? 26 | 27 | # Compress JavaScripts and CSS. 28 | config.assets.js_compressor = :uglifier 29 | # config.assets.css_compressor = :sass 30 | 31 | # Do not fallback to assets pipeline if a precompiled asset is missed. 32 | config.assets.compile = false 33 | 34 | # Asset digests allow you to set far-future HTTP expiration dates on all assets, 35 | # yet still be able to expire them through the digest params. 36 | config.assets.digest = true 37 | 38 | # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb 39 | 40 | # Specifies the header that your server uses for sending files. 41 | # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache 42 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX 43 | 44 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 45 | # config.force_ssl = true 46 | 47 | # Use the lowest log level to ensure availability of diagnostic information 48 | # when problems arise. 49 | config.log_level = :debug 50 | 51 | # Prepend all log lines with the following tags. 52 | # config.log_tags = [ :subdomain, :uuid ] 53 | 54 | # Use a different logger for distributed setups. 55 | # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) 56 | 57 | # Use a different cache store in production. 58 | # config.cache_store = :mem_cache_store 59 | 60 | # Enable serving of images, stylesheets, and JavaScripts from an asset server. 61 | # config.action_controller.asset_host = 'http://assets.example.com' 62 | 63 | # Ignore bad email addresses and do not raise email delivery errors. 64 | # Set this to true and configure the email server for immediate delivery to raise delivery errors. 65 | # config.action_mailer.raise_delivery_errors = false 66 | 67 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 68 | # the I18n.default_locale when a translation cannot be found). 69 | config.i18n.fallbacks = true 70 | 71 | # Send deprecation notices to registered listeners. 72 | config.active_support.deprecation = :notify 73 | 74 | # Use default logging formatter so that PID and timestamp are not suppressed. 75 | config.log_formatter = ::Logger::Formatter.new 76 | 77 | # Do not dump schema after migrations. 78 | config.active_record.dump_schema_after_migration = false 79 | end 80 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/config/environments/test.rb: -------------------------------------------------------------------------------- 1 | Rails.application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # The test environment is used exclusively to run your application's 5 | # test suite. You never need to work with it otherwise. Remember that 6 | # your test database is "scratch space" for the test suite and is wiped 7 | # and recreated between test runs. Don't rely on the data there! 8 | config.cache_classes = true 9 | 10 | # Do not eager load code on boot. This avoids loading your whole application 11 | # just for the purpose of running a single test. If you are using a tool that 12 | # preloads Rails for running tests, you may have to set it to true. 13 | config.eager_load = false 14 | 15 | # Configure static file server for tests with Cache-Control for performance. 16 | config.serve_static_files = true 17 | config.static_cache_control = 'public, max-age=3600' 18 | 19 | # Show full error reports and disable caching. 20 | config.consider_all_requests_local = true 21 | config.action_controller.perform_caching = false 22 | 23 | # Raise exceptions instead of rendering exception templates. 24 | config.action_dispatch.show_exceptions = false 25 | 26 | # Disable request forgery protection in test environment. 27 | config.action_controller.allow_forgery_protection = false 28 | 29 | # Tell Action Mailer not to deliver emails to the real world. 30 | # The :test delivery method accumulates sent emails in the 31 | # ActionMailer::Base.deliveries array. 32 | config.action_mailer.delivery_method = :test 33 | 34 | # Randomize the order test cases are executed. 35 | config.active_support.test_order = :random 36 | 37 | # Print deprecation notices to the stderr. 38 | config.active_support.deprecation = :stderr 39 | 40 | # Raises error for missing translations 41 | # config.action_view.raise_on_missing_translations = true 42 | end 43 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/config/initializers/assets.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Version of your assets, change this if you want to expire all your assets. 4 | Rails.application.config.assets.version = '1.0' 5 | 6 | # Add additional assets to the asset load path 7 | # Rails.application.config.assets.paths << Emoji.images_path 8 | 9 | # Precompile additional assets. 10 | # application.js, application.css, and all non-JS/CSS in app/assets folder are already added. 11 | # Rails.application.config.assets.precompile += %w( search.js ) 12 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 7 | # Rails.backtrace_cleaner.remove_silencers! 8 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/config/initializers/cookies_serializer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | Rails.application.config.action_dispatch.cookies_serializer = :json 4 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Configure sensitive parameters which will be filtered from the log file. 4 | Rails.application.config.filter_parameters += [:password] 5 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format. Inflections 4 | # are locale specific, and you may define rules for as many different 5 | # locales as you wish. All of these examples are active by default: 6 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 7 | # inflect.plural /^(ox)$/i, '\1en' 8 | # inflect.singular /^(ox)en/i, '\1' 9 | # inflect.irregular 'person', 'people' 10 | # inflect.uncountable %w( fish sheep ) 11 | # end 12 | 13 | # These inflection rules are supported but not enabled by default: 14 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 15 | # inflect.acronym 'RESTful' 16 | # end 17 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new mime types for use in respond_to blocks: 4 | # Mime::Type.register "text/richtext", :rtf 5 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | Rails.application.config.session_store :cookie_store, key: '_rails42_app_session' 4 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/config/initializers/vitals.rb: -------------------------------------------------------------------------------- 1 | require 'vitals' 2 | 3 | Vitals.configure! do |c| 4 | c.facility = 'rails_42' 5 | end 6 | 7 | require 'vitals/integrations/notifications/action_controller' 8 | Vitals::Integrations::Notifications::ActionController.subscribe! 9 | 10 | require 'vitals/integrations/notifications/active_job' 11 | Vitals::Integrations::Notifications::ActiveJob.subscribe! 12 | 13 | require 'vitals/integrations/rack/requests' 14 | Rails.application.config.middleware.insert_before "Rails::Rack::Logger", Vitals::Integrations::Rack::Requests 15 | 16 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] if respond_to?(:wrap_parameters) 9 | end 10 | 11 | # To enable root element in JSON for ActiveRecord objects. 12 | # ActiveSupport.on_load(:active_record) do 13 | # self.include_root_in_json = true 14 | # end 15 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Files in the config/locales directory are used for internationalization 2 | # and are automatically loaded by Rails. If you want to use locales other 3 | # than English, add the necessary files in this directory. 4 | # 5 | # To use the locales, use `I18n.t`: 6 | # 7 | # I18n.t 'hello' 8 | # 9 | # In views, this is aliased to just `t`: 10 | # 11 | # <%= t('hello') %> 12 | # 13 | # To use a different locale, set it with `I18n.locale`: 14 | # 15 | # I18n.locale = :es 16 | # 17 | # This would use the information in config/locales/es.yml. 18 | # 19 | # To learn more, please read the Rails Internationalization guide 20 | # available at http://guides.rubyonrails.org/i18n.html. 21 | 22 | en: 23 | hello: "Hello world" 24 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/config/routes.rb: -------------------------------------------------------------------------------- 1 | Rails.application.routes.draw do 2 | resources :posts 3 | # The priority is based upon order of creation: first created -> highest priority. 4 | # See how all your routes lay out with "rake routes". 5 | 6 | # You can have the root of your site routed with "root" 7 | # root 'welcome#index' 8 | 9 | # Example of regular route: 10 | # get 'products/:id' => 'catalog#view' 11 | 12 | # Example of named route that can be invoked with purchase_url(id: product.id) 13 | # get 'products/:id/purchase' => 'catalog#purchase', as: :purchase 14 | 15 | # Example resource route (maps HTTP verbs to controller actions automatically): 16 | # resources :products 17 | 18 | # Example resource route with options: 19 | # resources :products do 20 | # member do 21 | # get 'short' 22 | # post 'toggle' 23 | # end 24 | # 25 | # collection do 26 | # get 'sold' 27 | # end 28 | # end 29 | 30 | # Example resource route with sub-resources: 31 | # resources :products do 32 | # resources :comments, :sales 33 | # resource :seller 34 | # end 35 | 36 | # Example resource route with more complex sub-resources: 37 | # resources :products do 38 | # resources :comments 39 | # resources :sales do 40 | # get 'recent', on: :collection 41 | # end 42 | # end 43 | 44 | # Example resource route with concerns: 45 | # concern :toggleable do 46 | # post 'toggle' 47 | # end 48 | # resources :posts, concerns: :toggleable 49 | # resources :photos, concerns: :toggleable 50 | 51 | # Example resource route within a namespace: 52 | # namespace :admin do 53 | # # Directs /admin/products/* to Admin::ProductsController 54 | # # (app/controllers/admin/products_controller.rb) 55 | # resources :products 56 | # end 57 | end 58 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/config/secrets.yml: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Your secret key is used for verifying the integrity of signed cookies. 4 | # If you change this key, all old signed cookies will become invalid! 5 | 6 | # Make sure the secret is at least 30 characters and all random, 7 | # no regular words or you'll be exposed to dictionary attacks. 8 | # You can use `rake secret` to generate a secure secret key. 9 | 10 | # Make sure the secrets in this file are kept private 11 | # if you're sharing your code publicly. 12 | 13 | development: 14 | secret_key_base: e36a8f4e224522a14b9104d7129cf19af517174af39f83dd9b72e52e8d3fb25e70f3d603be8d457bd7f0cf1d5fda66a4ff61755e234baeb08dd203197c7d0f3e 15 | 16 | test: 17 | secret_key_base: 50c9be4949a3d471b729779bd7e30b0e7dbb1a2aa3d6836dfa40c4fa00d328f7936bf2e228050a16c1771b86470fdcab77c7de98e810fe8aeab909a642791e81 18 | 19 | # Do not keep production secrets in the repository, 20 | # instead read values from the environment. 21 | production: 22 | secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> 23 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/db/migrate/20160321140358_create_posts.rb: -------------------------------------------------------------------------------- 1 | class CreatePosts < ActiveRecord::Migration 2 | def change 3 | create_table :posts do |t| 4 | t.string :title 5 | 6 | t.timestamps null: false 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/db/schema.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # This file is auto-generated from the current state of the database. Instead 3 | # of editing this file, please use the migrations feature of Active Record to 4 | # incrementally modify your database, and then regenerate this schema definition. 5 | # 6 | # Note that this schema.rb definition is the authoritative source for your 7 | # database schema. If you need to create the application database on another 8 | # system, you should be using db:schema:load, not running all the migrations 9 | # from scratch. The latter is a flawed and unsustainable approach (the more migrations 10 | # you'll amass, the slower it'll run and the greater likelihood for issues). 11 | # 12 | # It's strongly recommended that you check this file into your version control system. 13 | 14 | ActiveRecord::Schema.define(version: 20160321140358) do 15 | 16 | create_table "posts", force: :cascade do |t| 17 | t.string "title" 18 | t.datetime "created_at", null: false 19 | t.datetime "updated_at", null: false 20 | end 21 | 22 | end 23 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/db/seeds.rb: -------------------------------------------------------------------------------- 1 | # This file should contain all the record creation needed to seed the database with its default values. 2 | # The data can then be loaded with the rake db:seed (or created alongside the db with db:setup). 3 | # 4 | # Examples: 5 | # 6 | # cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }]) 7 | # Mayor.create(name: 'Emanuel', city: cities.first) 8 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/lib/assets/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondot/vitals/6248acc31b9c892f2771a46ee46e3f8ec777d8b3/integration/multiverse/rails42_app/lib/assets/.keep -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/lib/tasks/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondot/vitals/6248acc31b9c892f2771a46ee46e3f8ec777d8b3/integration/multiverse/rails42_app/lib/tasks/.keep -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/log/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondot/vitals/6248acc31b9c892f2771a46ee46e3f8ec777d8b3/integration/multiverse/rails42_app/log/.keep -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The page you were looking for doesn't exist (404) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

The page you were looking for doesn't exist.

62 |

You may have mistyped the address or the page may have moved.

63 |
64 |

If you are the application owner check the logs for more information.

65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/public/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The change you wanted was rejected (422) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

The change you wanted was rejected.

62 |

Maybe you tried to change something you didn't have access to.

63 |
64 |

If you are the application owner check the logs for more information.

65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/public/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | We're sorry, but something went wrong (500) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

We're sorry, but something went wrong.

62 |
63 |

If you are the application owner check the logs for more information.

64 |
65 | 66 | 67 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondot/vitals/6248acc31b9c892f2771a46ee46e3f8ec777d8b3/integration/multiverse/rails42_app/public/favicon.ico -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/public/robots.txt: -------------------------------------------------------------------------------- 1 | # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file 2 | # 3 | # To ban all spiders from the entire site uncomment the next two lines: 4 | # User-agent: * 5 | # Disallow: / 6 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/test/controllers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondot/vitals/6248acc31b9c892f2771a46ee46e3f8ec777d8b3/integration/multiverse/rails42_app/test/controllers/.keep -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/test/controllers/posts_controller_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class PostsControllerTest < ActionController::TestCase 4 | setup do 5 | @post = posts(:one) 6 | end 7 | 8 | test "should get index" do 9 | get :index 10 | assert_response :success 11 | assert_not_nil assigns(:posts) 12 | end 13 | 14 | test "should get new" do 15 | get :new 16 | assert_response :success 17 | end 18 | 19 | test "should create post" do 20 | assert_difference('Post.count') do 21 | post :create, post: { title: @post.title } 22 | end 23 | 24 | assert_redirected_to post_path(assigns(:post)) 25 | end 26 | 27 | test "should show post" do 28 | get :show, id: @post 29 | assert_response :success 30 | end 31 | 32 | test "should get edit" do 33 | get :edit, id: @post 34 | assert_response :success 35 | end 36 | 37 | test "should update post" do 38 | patch :update, id: @post, post: { title: @post.title } 39 | assert_redirected_to post_path(assigns(:post)) 40 | end 41 | 42 | test "should destroy post" do 43 | assert_difference('Post.count', -1) do 44 | delete :destroy, id: @post 45 | end 46 | 47 | assert_redirected_to posts_path 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/test/fixtures/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondot/vitals/6248acc31b9c892f2771a46ee46e3f8ec777d8b3/integration/multiverse/rails42_app/test/fixtures/.keep -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/test/fixtures/posts.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html 2 | 3 | one: 4 | title: MyString 5 | 6 | two: 7 | title: MyString 8 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/test/helpers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondot/vitals/6248acc31b9c892f2771a46ee46e3f8ec777d8b3/integration/multiverse/rails42_app/test/helpers/.keep -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/test/integration/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondot/vitals/6248acc31b9c892f2771a46ee46e3f8ec777d8b3/integration/multiverse/rails42_app/test/integration/.keep -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/test/integration/vitals_flow_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | require 'active_support/log_subscriber/test_helper' 3 | require 'action_controller/log_subscriber' 4 | 5 | class TestLogSubscriber < ActiveSupport::LogSubscriber 6 | cattr_accessor :event 7 | 8 | def process_action event 9 | self.class.event = event 10 | end 11 | 12 | def self.controller_times 13 | dbtime, viewtime = event.payload.slice(:db_runtime, :view_runtime).values 14 | viewtime ||= 0 15 | dbtime ||= 0 16 | # all time is simulated. we don't get the 'all' time here. 17 | [dbtime+viewtime, dbtime, viewtime] 18 | end 19 | 20 | def self.flush 21 | self.event = nil 22 | end 23 | end 24 | 25 | class VitalsFlowTest < ActionDispatch::IntegrationTest 26 | setup do 27 | Vitals.reporter.flush 28 | TestLogSubscriber.flush 29 | TestLogSubscriber.attach_to :action_controller 30 | end 31 | 32 | test "get posts with rack middleware" do 33 | get '/posts' 34 | metrics = %w{ 35 | controllers.posts_index.get.200.all 36 | controllers.posts_index.get.200.db 37 | controllers.posts_index.get.200.view 38 | requests.posts_index.get.200 39 | } 40 | 41 | assert_timings Vitals.reporter.reports, 42 | metrics, 43 | TestLogSubscriber.controller_times+[-1], 44 | 60 45 | end 46 | 47 | test "get new which also triggers a job" do 48 | get '/posts/new' 49 | 50 | metrics = %w{ 51 | jobs.default.foobarcleanup 52 | controllers.posts_new.get.200.all 53 | controllers.posts_new.get.200.db 54 | controllers.posts_new.get.200.view 55 | requests.posts_new.get.200 56 | } 57 | 58 | assert_timings Vitals.reporter.reports, 59 | metrics, 60 | [-1]+TestLogSubscriber.controller_times+[-1], 61 | 60 62 | 63 | end 64 | 65 | test "get posts" do 66 | get '/posts' 67 | 68 | metrics = %w{ 69 | controllers.posts_index.get.200.all 70 | controllers.posts_index.get.200.db 71 | controllers.posts_index.get.200.view 72 | requests.posts_index.get.200 73 | } 74 | 75 | assert_timings Vitals.reporter.reports, 76 | metrics, 77 | TestLogSubscriber.controller_times+[-1], 78 | 80 79 | end 80 | 81 | test "post posts" do 82 | post '/posts', post: { title: 'foobar'} 83 | 84 | metrics = %w{ 85 | controllers.posts_create.post.302.all 86 | controllers.posts_create.post.302.db 87 | requests.posts_create.post.302 88 | } 89 | 90 | assert_timings Vitals.reporter.reports, 91 | metrics, 92 | TestLogSubscriber.controller_times+[-1], 93 | 80 94 | end 95 | 96 | end 97 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/test/jobs/foobar_cleanup_job_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class FoobarCleanupJobTest < ActiveJob::TestCase 4 | # test "the truth" do 5 | # assert true 6 | # end 7 | end 8 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/test/mailers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondot/vitals/6248acc31b9c892f2771a46ee46e3f8ec777d8b3/integration/multiverse/rails42_app/test/mailers/.keep -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/test/models/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jondot/vitals/6248acc31b9c892f2771a46ee46e3f8ec777d8b3/integration/multiverse/rails42_app/test/models/.keep -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/test/models/post_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class PostTest < ActiveSupport::TestCase 4 | # test "the truth" do 5 | # assert true 6 | # end 7 | end 8 | -------------------------------------------------------------------------------- /integration/multiverse/rails42_app/test/test_helper.rb: -------------------------------------------------------------------------------- 1 | ENV['RAILS_ENV'] ||= 'test' 2 | require File.expand_path('../../config/environment', __FILE__) 3 | require 'rails/test_help' 4 | require File.expand_path( '../../../multiverse_helper', File.dirname(__FILE__)) 5 | 6 | class ActiveSupport::TestCase 7 | # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order. 8 | fixtures :all 9 | 10 | # Add more helper methods to be used by all tests here... 11 | end 12 | -------------------------------------------------------------------------------- /integration/multiverse_helper.rb: -------------------------------------------------------------------------------- 1 | 2 | def assert_timings(reports, metrics, times, delta=30) 3 | if Object.const_defined?('RSpec') 4 | expect(reports.count).to eq metrics.count 5 | metrics.zip(times).each_with_index do |(m,v), i| 6 | expect(reports[i][:timing]).to eq m 7 | expect(reports[i][:val]).to(be_within(delta).of(v)) if v >=0 8 | end 9 | else 10 | assert_equal reports.count, metrics.count 11 | metrics.zip(times).each_with_index do |(m,v), i| 12 | assert_equal reports[i][:timing], m 13 | assert_in_delta(reports[i][:val], v, delta) if v >=0 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /integration/multiverse_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'bundler' 3 | require 'fileutils' 4 | include FileUtils 5 | 6 | 7 | describe "multiverse" do 8 | let(:bundle){ 'bundle install --quiet --path=vendor/bundle' } 9 | def state 10 | puts `pwd` 11 | end 12 | it "rails 4.2" do 13 | Bundler.with_clean_env do 14 | Dir.chdir('integration/multiverse/rails42_app') do 15 | state 16 | system("#{bundle} && RAILS_ENV=test bundle exec rake db:migrate && bundle exec rake test").must_equal true 17 | end 18 | end 19 | end 20 | it "grape-rack" do 21 | Bundler.with_clean_env do 22 | Dir.chdir('integration/multiverse/grape-on-rack') do 23 | state 24 | system("#{bundle} && bundle exec rake spec").must_equal true 25 | end 26 | end 27 | end 28 | it "grape-rails" do 29 | Bundler.with_clean_env do 30 | Dir.chdir('integration/multiverse/grape-on-rails') do 31 | state 32 | system("#{ bundle } && bundle exec rake spec").must_equal true 33 | end 34 | end 35 | end 36 | it "padrino" do 37 | # TODO this should test the rack middleware, and padrino uses sinatra so that's good 38 | skip 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /lib/vitals.rb: -------------------------------------------------------------------------------- 1 | require "vitals/version" 2 | module Vitals 3 | module Formats;end 4 | module Reporters;end 5 | module Integrations 6 | module Notifications;end 7 | end 8 | end 9 | 10 | require 'vitals/configuration' 11 | require 'vitals/utils' 12 | 13 | require 'vitals/reporters/base_reporter' 14 | require 'vitals/reporters/inmem_reporter' 15 | require 'vitals/reporters/console_reporter' 16 | require 'vitals/reporters/multi_reporter' 17 | require 'vitals/reporters/statsd_reporter' 18 | require 'vitals/reporters/dns_resolving_statsd_reporter' 19 | 20 | require 'vitals/formats/production_format' 21 | require 'vitals/formats/host_last_format' 22 | require 'vitals/formats/no_host_format' 23 | 24 | 25 | module Vitals 26 | def self.configure! 27 | @config = Configuration.new 28 | yield(@config) if block_given? 29 | @reporter = @config.reporter 30 | @reporter.format = @config.build_format 31 | end 32 | 33 | def self.reporter=(r) 34 | @reporter = r 35 | end 36 | 37 | def self.reporter 38 | @reporter 39 | end 40 | 41 | def self.subscribe!(*modules) 42 | # give out a list of subscribers too 43 | modules.map do |mod| 44 | require "vitals/integrations/notifications/#{ mod }" 45 | klass = Object.const_get("Vitals::Integrations::Notifications::#{classify(mod)}") 46 | klass.subscribe! 47 | end 48 | end 49 | 50 | # 51 | # reporter delegators 52 | # 53 | # hardwired for performance 54 | # (forwardable delegators go through __send__ and generate gc waste) 55 | def self.inc(m) 56 | reporter.inc(m) 57 | end 58 | 59 | def self.timing(m, val) 60 | reporter.timing(m, val) 61 | end 62 | 63 | def self.time(m, &b) 64 | reporter.time(m, &b) 65 | end 66 | 67 | def self.count(m, val) 68 | reporter.count(m, val) 69 | end 70 | 71 | def self.gauge(m, val) 72 | reporter.gauge(m, val) 73 | end 74 | 75 | private 76 | def self.classify(sym) 77 | sym.to_s.split('_').collect!{ |w| w.capitalize }.join 78 | end 79 | end 80 | -------------------------------------------------------------------------------- /lib/vitals/configuration.rb: -------------------------------------------------------------------------------- 1 | module Vitals 2 | class Configuration 3 | attr_accessor :environment 4 | attr_accessor :facility 5 | attr_accessor :host 6 | attr_accessor :reporter 7 | attr_accessor :format 8 | 9 | def initialize 10 | @environment = fetch_development 11 | @facility = "default" 12 | @host = fetch_host 13 | @reporter = Vitals::Reporters::InmemReporter.new 14 | @format = Vitals::Formats::ProductionFormat 15 | self.path_sep = '.' 16 | end 17 | 18 | # delegate to utils, until this part of the utils 19 | # finds a new home with a new abstraction 20 | def path_sep=(val) 21 | Vitals::Utils.path_sep = val 22 | end 23 | 24 | def path_sep 25 | Vitals::Utils.path_sep = val 26 | end 27 | 28 | def build_format 29 | @format.new( 30 | environment: self.environment, 31 | facility: self.facility, 32 | host: self.host 33 | ) 34 | end 35 | 36 | private 37 | 38 | def fetch_development 39 | ENV["RACK_ENV"] || ENV["RAILS_ENV"] || ENV["NODE_ENV"] || "development" 40 | end 41 | 42 | def fetch_host 43 | Vitals::Utils.hostname 44 | end 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /lib/vitals/formats/host_last_format.rb: -------------------------------------------------------------------------------- 1 | module Vitals::Formats 2 | class HostLastFormat 3 | attr_accessor :environment 4 | attr_accessor :host 5 | attr_accessor :facility 6 | 7 | def initialize(environment:'development', facility:'default', host:'localhost') 8 | @environment = environment 9 | @facility = facility 10 | @host = host 11 | @host = Vitals::Utils.normalize_metric(host).freeze if @host 12 | @prefix = [environment, facility].compact.map{|m| Vitals::Utils.normalize_metric(m) } 13 | .join(Vitals::Utils::SEPARATOR).freeze 14 | @prefix_with_host = [environment, facility, @host].compact.map{|m| Vitals::Utils.normalize_metric(m) } 15 | .join(Vitals::Utils::SEPARATOR).freeze 16 | end 17 | 18 | def format(m) 19 | return @prefix_with_host if (m.nil? || m.empty?) 20 | # TODO optimize by building a renderer function (inlining this) in the initializer. 21 | # see https://github.com/evanphx/benchmark-ips/blob/master/lib/benchmark/ips/job/entry.rb#L63 22 | [@prefix, Vitals::Utils.normalize_metric(m), @host].reject{|s| s.nil? || s.empty? }.join(Vitals::Utils::SEPARATOR) 23 | end 24 | end 25 | end 26 | 27 | -------------------------------------------------------------------------------- /lib/vitals/formats/no_host_format.rb: -------------------------------------------------------------------------------- 1 | module Vitals::Formats 2 | class NoHostFormat 3 | attr_accessor :environment 4 | attr_accessor :facility 5 | 6 | def initialize(environment:'development', facility:'default', host: nil) 7 | @environment = environment 8 | @facility = facility 9 | @host = host 10 | @prefix = [environment, facility].compact 11 | .map { |m| Vitals::Utils.normalize_metric(m) } 12 | .join(Vitals::Utils::SEPARATOR) 13 | .freeze 14 | end 15 | 16 | def format(m) 17 | return @prefix if (m.nil? || m.empty?) 18 | # TODO optimize by building a renderer function (inlining this) in the initializer. 19 | # see https://github.com/evanphx/benchmark-ips/blob/master/lib/benchmark/ips/job/entry.rb#L63 20 | [@prefix, Vitals::Utils.normalize_metric(m)].reject{|s| s.nil? || s.empty? } 21 | .join(Vitals::Utils::SEPARATOR) 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /lib/vitals/formats/production_format.rb: -------------------------------------------------------------------------------- 1 | module Vitals::Formats 2 | class ProductionFormat 3 | attr_accessor :environment 4 | attr_accessor :host 5 | attr_accessor :facility 6 | 7 | def initialize(environment:'development', facility:'default', host:'localhost') 8 | @environment = environment 9 | @facility = facility 10 | @host = host 11 | @prefix = [environment, host, facility].compact.map{|m| Vitals::Utils.normalize_metric(m) } 12 | .join(".").freeze 13 | # TODO prematerialize working prefix with metric name sanitation 14 | end 15 | 16 | def format(m) 17 | return @prefix if (m.nil? || m.empty?) 18 | "#{@prefix}.#{Vitals::Utils.normalize_metric(m)}" 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /lib/vitals/integrations/notifications/action_controller.rb: -------------------------------------------------------------------------------- 1 | require 'vitals/integrations/notifications/base' 2 | 3 | module Vitals::Integrations::Notifications 4 | class ActionController < Base 5 | def self.event_name 6 | 'process_action.action_controller' 7 | end 8 | 9 | private 10 | 11 | def self.handle(name, started, finished, unique_id, payload) 12 | method = payload[:method].downcase 13 | status = payload[:status] 14 | action = payload[:action] 15 | ctrl = payload[:controller].sub(/Controller$/, '').downcase 16 | # format = payload[:format] 17 | 18 | m = "controllers.#{ctrl}_#{action}.#{method}.#{status}" 19 | Vitals.timing("#{m}.all", duration(started, finished)) 20 | Vitals.timing("#{m}.db", payload[:db_runtime]) if payload[:db_runtime] 21 | Vitals.timing("#{m}.view", payload[:view_runtime]) if payload[:view_runtime] 22 | end 23 | 24 | end 25 | end 26 | 27 | -------------------------------------------------------------------------------- /lib/vitals/integrations/notifications/active_job.rb: -------------------------------------------------------------------------------- 1 | require 'vitals/integrations/notifications/base' 2 | 3 | module Vitals::Integrations::Notifications 4 | # see https://github.com/rails/rails/blob/master/activejob/lib/active_job/logging.rb#L23 5 | class ActiveJob < Base 6 | def self.event_name 7 | 'perform.active_job' 8 | end 9 | 10 | private 11 | def self.handle(name, started, finished, unique_id, payload) 12 | job = payload[:job] 13 | name = job.class.name.sub(/Job$/, '').sub(/Worker$/,'').downcase 14 | 15 | Vitals.timing("jobs.#{job.queue_name}.#{name}", duration(started, finished)) 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /lib/vitals/integrations/notifications/base.rb: -------------------------------------------------------------------------------- 1 | require 'active_support' 2 | 3 | module Vitals::Integrations::Notifications 4 | class Base 5 | def self.subscribe! 6 | subscriber = ActiveSupport::Notifications.subscribe(event_name, &method(:handle)) 7 | 8 | subscriber 9 | end 10 | 11 | def self.handle 12 | raise "#handle not implemented" 13 | end 14 | 15 | def self.duration(started, finished) 16 | Vitals::Utils.sec_to_ms(finished - started) 17 | end 18 | end 19 | end 20 | 21 | -------------------------------------------------------------------------------- /lib/vitals/integrations/notifications/grape.rb: -------------------------------------------------------------------------------- 1 | require 'vitals/integrations/notifications/base' 2 | 3 | module Vitals::Integrations::Notifications 4 | class Grape < Base 5 | def self.event_name 6 | 'endpoint_run.grape' 7 | end 8 | 9 | private 10 | 11 | def self.handle(name, started, finished, unique_id, payload) 12 | endpoint = payload[:endpoint] 13 | route = endpoint.route 14 | method = route.route_method.downcase 15 | 16 | path = Vitals::Utils.grape_path(route) 17 | 18 | # TODO move 'grape' to configuration opts in subscribe!(opts) 19 | m = "grape.#{path}.#{method}.#{endpoint.status}.all" 20 | Vitals.timing(m, duration(started, finished)) 21 | end 22 | 23 | end 24 | end 25 | 26 | 27 | -------------------------------------------------------------------------------- /lib/vitals/integrations/rack/requests.rb: -------------------------------------------------------------------------------- 1 | module Vitals::Integrations::Rack 2 | class Requests 3 | REQUEST_METHOD = 'REQUEST_METHOD'.freeze 4 | 5 | RACK_PATH_INFO = 'PATH_INFO'.freeze 6 | RACK_ROUTER_INFO = 'rack.routing_args'.freeze 7 | SINATRA_PATH_INFO = 'sinatra.route'.freeze 8 | GRAPE_PATH_INFO = 'api.endpoint'.freeze 9 | RAILS_PATH_INFO = 'action_controller.instance'.freeze 10 | REQ_PREF = 'vitals.req_prefix' 11 | 12 | def initialize(app, options = {}) 13 | @app = app 14 | @prefix = options[:prefix] ? options[:prefix] + "." : nil 15 | end 16 | 17 | def call(env) 18 | start = Time.now 19 | status, header, body = @app.call(env) 20 | t = Time.now - start 21 | req_prefix = env[REQ_PREF] ? "#{env[REQ_PREF]}." : '' 22 | 23 | path = if env[SINATRA_PATH_INFO] 24 | Requests.sinatra_path(env) 25 | elsif env[GRAPE_PATH_INFO] 26 | Requests.grape_path(env) 27 | elsif env[RAILS_PATH_INFO] 28 | Requests.rails_path(env) 29 | else 30 | Requests.rack_path(env) 31 | end 32 | 33 | path = !path.empty? ? path + '.' : path 34 | m = "requests.#{@prefix}#{req_prefix}#{path}#{env[REQUEST_METHOD].downcase}.#{status}" 35 | 36 | # TODO add option to customize 'requests' through options 37 | Vitals.timing(m, Vitals::Utils.sec_to_ms(t)) 38 | 39 | [status, header, body] 40 | end 41 | 42 | private 43 | 44 | def self.sinatra_path(env) 45 | env[SINATRA_PATH_INFO].gsub(/^\w+\s+\//, '') 46 | end 47 | 48 | def self.grape_path(env) 49 | route = if env[RACK_ROUTER_INFO] 50 | # grape 0.11 route bug workaround with http_basic. 51 | # when unauthenticated, GRAPE_PATH_INFO route has a nil env. this one 52 | # here doesn't: 53 | env[RACK_ROUTER_INFO][:route_info] 54 | else 55 | # grape > 0.11 56 | env[GRAPE_PATH_INFO].route 57 | end 58 | Vitals::Utils.grape_path(route) 59 | end 60 | 61 | def self.rails_path(env) 62 | ctrl = env[RAILS_PATH_INFO] 63 | "#{ctrl.controller_name}_#{ctrl.action_name}" 64 | end 65 | 66 | def self.rack_path(env) 67 | '' 68 | end 69 | end 70 | end 71 | 72 | -------------------------------------------------------------------------------- /lib/vitals/reporters/base_reporter.rb: -------------------------------------------------------------------------------- 1 | module Vitals::Reporters 2 | class BaseReporter 3 | def time(m) 4 | start = Time.now 5 | yield 6 | timing(m, Vitals::Utils::sec_to_ms(Time.now - start)) 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /lib/vitals/reporters/console_reporter.rb: -------------------------------------------------------------------------------- 1 | module Vitals::Reporters 2 | class ConsoleReporter < BaseReporter 3 | attr_accessor :format 4 | 5 | def initialize(category:'main', output: $stdout, format:nil) 6 | @format = format 7 | @category = category 8 | @output = output 9 | end 10 | 11 | def inc(m) 12 | print "#{@category} INC #{self.format.format(m)}" 13 | end 14 | 15 | def gauge(m, v) 16 | print "#{@category} GAUGE #{self.format.format(m)} #{v}" 17 | end 18 | 19 | def count(m, v) 20 | print "#{@category} COUNT #{self.format.format(m)} #{v}" 21 | end 22 | 23 | def timing(m, v) 24 | print "#{@category} TIME #{self.format.format(m)} #{v}" 25 | end 26 | 27 | def print(str) 28 | @output.printf("#{ str }\n") 29 | end 30 | end 31 | end 32 | 33 | -------------------------------------------------------------------------------- /lib/vitals/reporters/dns_resolving_statsd_reporter.rb: -------------------------------------------------------------------------------- 1 | require 'statsd-ruby' 2 | require 'resolv' 3 | 4 | module Vitals::Reporters 5 | class DnsResolvingStatsdReporter < StatsdReporter 6 | def initialize(host: 'localhost', port: 8125, format: nil) 7 | @host = host 8 | @port = port 9 | @format = format 10 | setup_statsd 11 | end 12 | 13 | private 14 | def setup_statsd 15 | ip = @host 16 | unless (@host =~ Resolv::AddressRegex || @host == 'localhost'.freeze) 17 | ip, ttl = query_dns 18 | Thread.new do 19 | while true do 20 | sleep ttl 21 | previous_ip = ip 22 | ip, ttl = query_dns 23 | if ip != previous_ip 24 | @statsd = Statsd.new(ip, @port) 25 | end 26 | end 27 | end 28 | end 29 | @statsd = Statsd.new(ip, @port) 30 | end 31 | 32 | def query_dns 33 | ress = Resolv::DNS.open { |dns| dns.getresource(@host, Resolv::DNS::Resource::IN::A) } 34 | [ress.address.to_s, ress.ttl] 35 | end 36 | end 37 | end 38 | 39 | 40 | -------------------------------------------------------------------------------- /lib/vitals/reporters/inmem_reporter.rb: -------------------------------------------------------------------------------- 1 | module Vitals::Reporters 2 | class InmemReporter < BaseReporter 3 | attr_accessor :reports 4 | attr_accessor :format 5 | 6 | def initialize 7 | flush 8 | end 9 | 10 | def flush 11 | @reports = [] 12 | end 13 | 14 | def inc(m) 15 | @reports << { :inc => n( m ) } 16 | end 17 | 18 | def gauge(m, v) 19 | @reports << { :gauge => n( m ), :val => v } 20 | end 21 | 22 | def timing(m, v) 23 | @reports << { :timing => n( m ), :val => v } 24 | end 25 | 26 | private 27 | def n(m) 28 | Vitals::Utils.normalize_metric(m) 29 | end 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /lib/vitals/reporters/multi_reporter.rb: -------------------------------------------------------------------------------- 1 | module Vitals::Reporters 2 | class MultiReporter < BaseReporter 3 | attr_accessor :format 4 | 5 | def initialize(format:nil, reporters:[]) 6 | @format = format 7 | @reporters = reporters 8 | end 9 | 10 | def inc(m) 11 | @reporters.each{|r| r.inc(m) } 12 | end 13 | 14 | def gauge(m, v) 15 | @reporters.each{|r| r.gauge(m, v) } 16 | end 17 | 18 | def count(m, v) 19 | @reporters.each{|r| r.count(m, v) } 20 | end 21 | 22 | def timing(m, v) 23 | @reporters.each{|r| r.timing(m, v) } 24 | end 25 | end 26 | end 27 | 28 | 29 | -------------------------------------------------------------------------------- /lib/vitals/reporters/statsd_reporter.rb: -------------------------------------------------------------------------------- 1 | require 'statsd-ruby' 2 | 3 | module Vitals::Reporters 4 | class StatsdReporter < BaseReporter 5 | attr_accessor :format 6 | attr_reader :statsd 7 | 8 | def initialize(host:'localhost', port:8125, format:nil) 9 | @statsd = Statsd.new(host, port) 10 | @format = format 11 | end 12 | 13 | def inc(m) 14 | @statsd.increment(format.format(m)) 15 | end 16 | 17 | def gauge(m, v) 18 | @statsd.gauge(format.format(m), v) 19 | end 20 | 21 | def count(m, v) 22 | @statsd.count(format.format(m), v) 23 | end 24 | 25 | def timing(m, v) 26 | @statsd.timing(format.format(m), v) 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /lib/vitals/utils.rb: -------------------------------------------------------------------------------- 1 | module Vitals 2 | module Utils 3 | BAD_METRICS_CHARS = Regexp.compile('[\/\-:\s]').freeze 4 | SEPARATOR = '.'.freeze 5 | def self.normalize_metric(m) 6 | m.gsub(BAD_METRICS_CHARS, '_') 7 | end 8 | def self.hostname 9 | `hostname -s`.chomp 10 | end 11 | def self.sec_to_ms(sec) 12 | (1000.0 * sec).round 13 | end 14 | # XXX grape specific, move this away some day? 15 | def self.grape_path(route) 16 | if route.respond_to?(:version) && route.respond_to?(:path) 17 | version = route.version 18 | path = route.path 19 | else 20 | # deprecated methods 21 | version = route.route_version 22 | path = route.route_path 23 | end 24 | 25 | path = path.dup[1..-1] # /foo/bar/baz -> foo/bar/baz 26 | path.sub!(/\(\..*\)$/, '') # (.json) -> '' 27 | path.sub!(":version", version) if version # :version -> v1 28 | path.gsub!(/\//, self.path_sep) # foo/bar -> foo.bar 29 | path 30 | end 31 | 32 | def self.path_sep 33 | @path_sep 34 | end 35 | 36 | def self.path_sep=(val) 37 | @path_sep = val 38 | end 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /lib/vitals/version.rb: -------------------------------------------------------------------------------- 1 | module Vitals 2 | VERSION = "0.12.0" 3 | end 4 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__) 2 | require 'coveralls' 3 | Coveralls.wear! 4 | 5 | require 'vitals' 6 | 7 | require 'minitest/spec' 8 | require 'minitest/autorun' 9 | require 'rr' 10 | 11 | require 'rack/test' 12 | 13 | require 'benchmark/ipsa' 14 | require 'memory_profiler' 15 | 16 | # TODO remember to set vitals config to nil 17 | # globally for the test suite so that we don't 18 | # have test fallout (Vitals is static) 19 | 20 | # TODO extract this pattern to a gem 21 | def bench(label, cases) 22 | it "bench #{label}" do 23 | Benchmark.ipsa do |x| 24 | cases.each do |name, block| 25 | x.report(name, block) 26 | end 27 | end 28 | end 29 | end 30 | 31 | def format_configs 32 | [ 33 | { 34 | environment: 'env/foo-bar baz:qux', 35 | facility: 'service/foo-bar baz:qux', 36 | host: 'host/foo-bar baz:qux' 37 | }, 38 | { 39 | environment: 'env', 40 | facility: 'service', 41 | host: 'host' 42 | }, 43 | { 44 | environment: 'env', 45 | facility: nil, 46 | host: 'host' 47 | }, 48 | { 49 | environment: 'env', 50 | facility: 'service', 51 | host: nil 52 | }, 53 | { 54 | environment: nil, 55 | facility: 'service', 56 | host: 'host' 57 | }, 58 | { 59 | environment: 'env', 60 | facility: nil, 61 | host: nil 62 | }, 63 | { 64 | environment: nil, 65 | facility: nil, 66 | host: 'host' 67 | }, 68 | { 69 | environment: nil, 70 | facility: 'service', 71 | host: nil 72 | } 73 | ] 74 | end 75 | def format_cases 76 | ['1.2', 77 | '1', 78 | '', 79 | nil] 80 | end 81 | 82 | def it_formats(format_class, results) 83 | describe format_class do 84 | format_configs.each_with_index do |format_config, fi| 85 | format_cases.each_with_index do |args, index| 86 | result_index = fi * format_cases.size + index 87 | if result_index < results.size 88 | res = results[result_index] 89 | it "formats with #{fi}: #{format_config}(#{args}) -> [#{res}] (index: #{result_index})" do 90 | format_class.new(format_config).format(args).must_equal(res) 91 | end 92 | end 93 | end 94 | end 95 | end 96 | end 97 | 98 | class TestFormat 99 | def format(args) 100 | args 101 | end 102 | end 103 | 104 | 105 | require 'grape' 106 | 107 | -------------------------------------------------------------------------------- /spec/vitals/configuration_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Vitals::Configuration do 4 | before do 5 | @rack_env = ENV["RACK_ENV"] 6 | end 7 | 8 | after do 9 | ENV["RACK_ENV"] = @rack_env 10 | end 11 | 12 | it 'should autodiscover env' do 13 | c = Vitals::Configuration.new 14 | c.environment.must_equal(ENV["RACK_ENV"] || 'development') 15 | 16 | ENV["RACK_ENV"] = 'production' 17 | c = Vitals::Configuration.new 18 | c.environment.must_equal('production') 19 | end 20 | 21 | it 'must autodiscover host' do 22 | c = Vitals::Configuration.new 23 | c.host.must_equal(`hostname -s`.chomp) 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /spec/vitals/formats/host_last_format_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | it_formats( 4 | Vitals::Formats::HostLastFormat, 5 | %w{ 6 | env_foo_bar_baz_qux.service_foo_bar_baz_qux.1.2.host_foo_bar_baz_qux 7 | env_foo_bar_baz_qux.service_foo_bar_baz_qux.1.host_foo_bar_baz_qux 8 | env_foo_bar_baz_qux.service_foo_bar_baz_qux.host_foo_bar_baz_qux 9 | env_foo_bar_baz_qux.service_foo_bar_baz_qux.host_foo_bar_baz_qux 10 | 11 | env.service.1.2.host 12 | env.service.1.host 13 | env.service.host 14 | env.service.host 15 | 16 | env.1.2.host 17 | env.1.host 18 | env.host 19 | env.host 20 | 21 | env.service.1.2 22 | env.service.1 23 | env.service 24 | env.service 25 | 26 | service.1.2.host 27 | service.1.host 28 | service.host 29 | service.host 30 | 31 | env.1.2 32 | env.1 33 | env 34 | env 35 | 36 | 1.2.host 37 | 1.host 38 | host 39 | host 40 | 41 | service.1.2 42 | service.1 43 | service 44 | service 45 | } 46 | ) 47 | 48 | 49 | -------------------------------------------------------------------------------- /spec/vitals/formats/no_host_format_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | it_formats( 4 | Vitals::Formats::NoHostFormat, 5 | %W{ 6 | env_foo_bar_baz_qux.service_foo_bar_baz_qux.1.2 7 | env_foo_bar_baz_qux.service_foo_bar_baz_qux.1 8 | env_foo_bar_baz_qux.service_foo_bar_baz_qux 9 | env_foo_bar_baz_qux.service_foo_bar_baz_qux 10 | 11 | env.service.1.2 12 | env.service.1 13 | env.service 14 | env.service 15 | 16 | env.1.2 17 | env.1 18 | env 19 | env 20 | 21 | env.service.1.2 22 | env.service.1 23 | env.service 24 | env.service 25 | 26 | service.1.2 27 | service.1 28 | service 29 | service 30 | 31 | env.1.2 32 | env.1 33 | env 34 | env 35 | 36 | 1.2 37 | 1 38 | #{''} 39 | #{''} 40 | 41 | service.1.2 42 | service.1 43 | service 44 | service 45 | } 46 | ) 47 | -------------------------------------------------------------------------------- /spec/vitals/formats/production_format_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | it_formats( 4 | Vitals::Formats::ProductionFormat, 5 | %w{ 6 | env_foo_bar_baz_qux.host_foo_bar_baz_qux.service_foo_bar_baz_qux.1.2 7 | env_foo_bar_baz_qux.host_foo_bar_baz_qux.service_foo_bar_baz_qux.1 8 | env_foo_bar_baz_qux.host_foo_bar_baz_qux.service_foo_bar_baz_qux 9 | env_foo_bar_baz_qux.host_foo_bar_baz_qux.service_foo_bar_baz_qux 10 | 11 | env.host.service.1.2 12 | env.host.service.1 13 | env.host.service 14 | env.host.service 15 | 16 | env.host.1.2 17 | env.host.1 18 | env.host 19 | env.host 20 | 21 | env.service.1.2 22 | env.service.1 23 | env.service 24 | env.service 25 | 26 | host.service.1.2 27 | host.service.1 28 | host.service 29 | host.service 30 | 31 | env.1.2 32 | env.1 33 | env 34 | env 35 | 36 | host.1.2 37 | host.1 38 | host 39 | host 40 | 41 | service.1.2 42 | service.1 43 | service 44 | service 45 | } 46 | ) 47 | -------------------------------------------------------------------------------- /spec/vitals/integrations/notifications/action_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'vitals/integrations/notifications/action_controller' 3 | 4 | describe Vitals::Integrations::Notifications::ActionController do 5 | let(:reporter){Vitals::Reporters::InmemReporter.new} 6 | 7 | before do 8 | reporter.flush 9 | Vitals.configure! do |c| 10 | c.reporter = reporter 11 | end 12 | @sub = Vitals::Integrations::Notifications::ActionController.subscribe! 13 | end 14 | 15 | after do 16 | ActiveSupport::Notifications.unsubscribe(@sub) 17 | end 18 | 19 | it 'handle notifications' do 20 | ActiveSupport::Notifications.instrument('process_action.action_controller', 21 | { 22 | method: 'GET', 23 | status: 200, 24 | action: 'new', 25 | controller: 'RegistrationsController', 26 | db_runtime: 12, 27 | view_runtime: 30 28 | }) do 29 | sleep 0.1 30 | end 31 | 32 | reporter.reports.count.must_equal(3) 33 | report = reporter.reports[0] 34 | report[:timing].must_equal('controllers.registrations_new.get.200.all') 35 | report[:val].must_be_within_delta(100, 50) 36 | 37 | report = reporter.reports[1] 38 | report[:timing].must_equal('controllers.registrations_new.get.200.db') 39 | report[:val].must_equal(12) 40 | 41 | report = reporter.reports[2] 42 | report[:timing].must_equal('controllers.registrations_new.get.200.view') 43 | report[:val].must_equal(30) 44 | end 45 | end 46 | 47 | -------------------------------------------------------------------------------- /spec/vitals/integrations/notifications/active_job_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'vitals/integrations/notifications/active_job' 3 | 4 | describe Vitals::Integrations::Notifications::ActiveJob do 5 | let(:reporter){Vitals::Reporters::InmemReporter.new} 6 | before do 7 | reporter.flush 8 | Vitals.configure! do |c| 9 | c.reporter = reporter 10 | end 11 | @sub = Vitals::Integrations::Notifications::ActiveJob.subscribe! 12 | end 13 | after do 14 | ActiveSupport::Notifications.unsubscribe(@sub) 15 | end 16 | 17 | it 'handle notifications' do 18 | class FooBarWorker 19 | def queue_name 20 | 'foobarqueue_workers' 21 | end 22 | end 23 | 24 | class FooBarJob 25 | def queue_name 26 | 'foobarqueue_jobs' 27 | end 28 | end 29 | 30 | ActiveSupport::Notifications.instrument('perform.active_job', 31 | { 32 | job: FooBarWorker.new, 33 | }) do 34 | sleep 0.1 35 | end 36 | 37 | reporter.reports.count.must_equal(1) 38 | report = reporter.reports.first 39 | report[:timing].must_equal('jobs.foobarqueue_workers.foobar') 40 | report[:val].must_be_within_delta(100, 50) 41 | reporter.flush 42 | 43 | ActiveSupport::Notifications.instrument('perform.active_job', 44 | { 45 | job: FooBarJob.new, 46 | }) do 47 | sleep 0.1 48 | end 49 | 50 | reporter.reports.count.must_equal(1) 51 | report = reporter.reports.first 52 | report[:timing].must_equal('jobs.foobarqueue_jobs.foobar') 53 | report[:val].must_be_within_delta(100, 50) 54 | end 55 | end 56 | 57 | -------------------------------------------------------------------------------- /spec/vitals/integrations/notifications/grape_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'vitals/integrations/notifications/grape' 3 | require 'grape' 4 | 5 | # 6 | # Using real grape here because its notification abstraction 7 | # requires mocking an endpoint, and a path, and a route and 8 | # so on. Just use the real thing with rack-test. 9 | # 10 | 11 | describe Vitals::Integrations::Notifications::Grape do 12 | let(:reporter){Vitals::Reporters::InmemReporter.new} 13 | before do 14 | reporter.flush 15 | Vitals.configure! do |c| 16 | c.reporter = reporter 17 | end 18 | @sub = Vitals::Integrations::Notifications::Grape.subscribe! 19 | end 20 | 21 | after do 22 | ActiveSupport::Notifications.unsubscribe(@sub) 23 | end 24 | 25 | describe "grape notifications api" do 26 | include Rack::Test::Methods 27 | def app 28 | Class.new(Grape::API) do 29 | version 'v1', using: :path 30 | format :json 31 | prefix :api 32 | 33 | rescue_from StandardError do |e| 34 | error! "foobar" 35 | end 36 | 37 | get :raise_error do 38 | raise StandardError.new("Oh noes!") 39 | end 40 | 41 | get :make_error do 42 | error! "foobar" 43 | end 44 | 45 | resource :statuses do 46 | get :public_timeline do 47 | sleep 0.1 48 | "hello world" 49 | end 50 | end 51 | 52 | resource :auth do 53 | http_basic do |u,p| 54 | false 55 | end 56 | 57 | get :secret do 58 | "impossible to get here" 59 | end 60 | end 61 | end 62 | end 63 | 64 | it 'handles grape errors via raise, catch all' do 65 | get '/api/v1/raise_error' 66 | last_response.ok?.must_equal(false) 67 | last_response.status.must_equal 500 68 | #this fails: 69 | #reporter.reports[0][:timing].must_equal('grape.api.v1.raise_error.get.500.all') 70 | reporter.reports.count.must_equal 1 71 | end 72 | 73 | it 'handles grape errors via error!' do 74 | get '/api/v1/make_error' 75 | last_response.ok?.must_equal(false) 76 | last_response.status.must_equal 500 77 | reporter.reports[0][:timing].must_equal('grape.api.v1.make_error.get.500.all') 78 | reporter.reports.count.must_equal 1 79 | end 80 | 81 | it 'handles grape\'s http_basic middleware' do 82 | get '/api/v1/auth/secret' 83 | last_response.ok?.must_equal(false) 84 | last_response.status.must_equal 401 85 | # grape notification doesn't register if not auth'd :( 86 | reporter.reports.count.must_equal 0 87 | end 88 | 89 | it 'handles prefix, version and format' do 90 | get "/api/v1/statuses/public_timeline" 91 | last_response.ok?.must_equal(true) 92 | 93 | reporter.reports.count.must_equal(1) 94 | report = reporter.reports[0] 95 | report[:timing].must_equal('grape.api.v1.statuses.public_timeline.get.200.all') 96 | report[:val].must_be_within_delta(100, 40) 97 | end 98 | 99 | describe 'use a non-dot path separator' do 100 | before do 101 | Vitals.configure! do |c| 102 | c.reporter = reporter 103 | c.path_sep = '__' 104 | end 105 | end 106 | 107 | it 'handles prefix, version and format' do 108 | get "/api/v1/statuses/public_timeline" 109 | last_response.ok?.must_equal(true) 110 | 111 | reporter.reports.count.must_equal(1) 112 | report = reporter.reports[0] 113 | report[:timing].must_equal('grape.api__v1__statuses__public_timeline.get.200.all') 114 | report[:val].must_be_within_delta(100, 40) 115 | end 116 | end 117 | 118 | end 119 | 120 | describe "grape nonversioned notifications api" do 121 | include Rack::Test::Methods 122 | def app 123 | Class.new(Grape::API) do 124 | format :json 125 | resource :statuses do 126 | get :public_timeline do 127 | sleep 0.1 128 | "hello world" 129 | end 130 | end 131 | end 132 | end 133 | 134 | it 'handles default api' do 135 | get "/statuses/public_timeline" 136 | last_response.ok?.must_equal(true) 137 | reporter.reports.count.must_equal(1) 138 | report = reporter.reports[0] 139 | report[:timing].must_equal('grape.statuses.public_timeline.get.200.all') 140 | report[:val].must_be_within_delta(100, 40) 141 | end 142 | end 143 | end 144 | -------------------------------------------------------------------------------- /spec/vitals/integrations/rack/rails_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "rails" do 4 | it "rails on rack" do 5 | skip('see multiverse rails42 test for rack and middleware') 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /spec/vitals/integrations/rack/requests_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require 'vitals/integrations/rack/requests' 3 | require 'sinatra/base' 4 | 5 | # 6 | # Using real grape here because its notification abstraction 7 | # requires mocking an endpoint, and a path, and a route and 8 | # so on. Just use the real thing with rack-test. 9 | # 10 | 11 | describe Vitals::Integrations::Rack::Requests do 12 | let(:reporter){Vitals::Reporters::InmemReporter.new} 13 | before do 14 | reporter.flush 15 | Vitals.configure! do |c| 16 | c.reporter = reporter 17 | end 18 | end 19 | 20 | describe "grape rack non-versioned api" do 21 | include Rack::Test::Methods 22 | def app 23 | Class.new(Grape::API) do 24 | use Vitals::Integrations::Rack::Requests 25 | resource :statuses do 26 | get :public_timeline do 27 | sleep 0.1 28 | "hello world" 29 | end 30 | end 31 | resource :auth do 32 | http_basic do |u,p| 33 | false 34 | end 35 | 36 | get :secret do 37 | "impossible to get here" 38 | end 39 | end 40 | end 41 | end 42 | 43 | it 'handles grape\'s http_basic middleware' do 44 | get '/auth/secret' 45 | last_response.ok?.must_equal(false) 46 | last_response.status.must_equal 401 47 | # grape notification doesn't register if not auth'd :( 48 | reporter.reports.count.must_equal(1) 49 | report = reporter.reports[0] 50 | report[:timing].must_equal('requests.auth.secret.get.401') 51 | report[:val].must_be_within_delta(2, 20) 52 | end 53 | 54 | it 'handles get' do 55 | get "/statuses/public_timeline" 56 | last_response.ok?.must_equal(true) 57 | 58 | reporter.reports.count.must_equal(1) 59 | report = reporter.reports[0] 60 | report[:timing].must_equal('requests.statuses.public_timeline.get.200') 61 | report[:val].must_be_within_delta(100, 50) 62 | end 63 | 64 | describe 'use a non-dot path separator' do 65 | before do 66 | reporter.flush 67 | Vitals.configure! do |c| 68 | c.reporter = reporter 69 | end 70 | end 71 | 72 | it 'handles get' do 73 | get "/statuses/public_timeline" 74 | last_response.ok?.must_equal(true) 75 | 76 | reporter.reports.count.must_equal(1) 77 | report = reporter.reports[0] 78 | report[:timing].must_equal('requests.statuses.public_timeline.get.200') 79 | report[:val].must_be_within_delta(100, 50) 80 | end 81 | end 82 | end 83 | 84 | describe "grape rack versioned api" do 85 | include Rack::Test::Methods 86 | def app 87 | Class.new(Grape::API) do 88 | use Vitals::Integrations::Rack::Requests 89 | version 'v1', using: :path 90 | format :json 91 | prefix :api 92 | 93 | resource :statuses do 94 | get :public_timeline do 95 | sleep 0.1 96 | "hello world" 97 | end 98 | end 99 | end 100 | end 101 | 102 | it 'handles get' do 103 | get "/api/v1/statuses/public_timeline" 104 | last_response.ok?.must_equal(true) 105 | 106 | reporter.reports.count.must_equal(1) 107 | report = reporter.reports[0] 108 | report[:timing].must_equal('requests.api.v1.statuses.public_timeline.get.200') 109 | report[:val].must_be_within_delta(100, 20) 110 | end 111 | end 112 | 113 | describe "rack api request prefix" do 114 | include Rack::Test::Methods 115 | def app 116 | Class.new(Sinatra::Base) do 117 | use(Class.new do 118 | def initialize(app, options={}) 119 | @app = app 120 | end 121 | 122 | def call(env) 123 | env['vitals.req_prefix'] = 'foobar_req_prefix' 124 | @app.call(env) 125 | end 126 | end) 127 | use Vitals::Integrations::Rack::Requests 128 | 129 | get '/foo/bar/baz' do 130 | "hello get" 131 | end 132 | 133 | end 134 | end 135 | 136 | it 'handles get' do 137 | get '/foo/bar/baz' 138 | last_response.ok?.must_equal(true) 139 | 140 | reporter.reports.count.must_equal(1) 141 | report = reporter.reports[0] 142 | report[:timing].must_equal('requests.foobar_req_prefix.foo_bar_baz.get.200') 143 | end 144 | end 145 | 146 | describe "sinatra wacky rack api" do 147 | include Rack::Test::Methods 148 | def app 149 | Class.new(Sinatra::Base) do 150 | use Vitals::Integrations::Rack::Requests 151 | 152 | get '/' do 153 | "hello get" 154 | end 155 | end 156 | end 157 | 158 | it 'handles a blank get' do 159 | get '/' 160 | last_response.ok?.must_equal(true) 161 | 162 | reporter.reports.count.must_equal(1) 163 | report = reporter.reports[0] 164 | report[:timing].must_equal('requests.get.200') 165 | end 166 | end 167 | 168 | describe "sinatra rack api" do 169 | include Rack::Test::Methods 170 | def app 171 | Class.new(Sinatra::Base) do 172 | use Vitals::Integrations::Rack::Requests 173 | 174 | get '/foo/bar/baz' do 175 | sleep 0.1 176 | "hello get" 177 | end 178 | 179 | post '/foo/bar/:name' do 180 | sleep 0.1 181 | "hello post" 182 | end 183 | 184 | post '/posts/:id/comments' do 185 | sleep 0.1 186 | "posts" 187 | end 188 | end 189 | end 190 | 191 | it 'handles get' do 192 | get '/foo/bar/baz' 193 | last_response.ok?.must_equal(true) 194 | 195 | reporter.reports.count.must_equal(1) 196 | report = reporter.reports[0] 197 | report[:timing].must_equal('requests.foo_bar_baz.get.200') 198 | report[:val].must_be_within_delta(100, 20) 199 | end 200 | 201 | it 'handles post' do 202 | post '/foo/bar/baz' 203 | last_response.ok?.must_equal(true) 204 | 205 | reporter.reports.count.must_equal(1) 206 | report = reporter.reports[0] 207 | report[:timing].must_equal('requests.foo_bar__name.post.200') 208 | report[:val].must_be_within_delta(100, 20) 209 | end 210 | 211 | it 'gets a parameterized route' do 212 | post '/posts/242342/comments' 213 | last_response.ok?.must_equal(true) 214 | 215 | reporter.reports.count.must_equal(1) 216 | report = reporter.reports[0] 217 | report[:timing].must_equal('requests.posts__id_comments.post.200') 218 | report[:val].must_be_within_delta(100, 40) 219 | end 220 | end 221 | end 222 | 223 | -------------------------------------------------------------------------------- /spec/vitals/reporters/base_reporter_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Vitals::Reporters::BaseReporter do 4 | let(:reporter){ 5 | Vitals::Reporters::BaseReporter.new 6 | } 7 | 8 | it '#time' do 9 | mock(reporter).timing.with_any_args{|m, v| 10 | m.must_equal('1.2') 11 | v.must_be_within_delta(200, 20) 12 | } 13 | reporter.time('1.2'){ 14 | sleep 0.2 15 | } 16 | end 17 | end 18 | 19 | 20 | -------------------------------------------------------------------------------- /spec/vitals/reporters/console_reporter_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Vitals::Reporters::ConsoleReporter do 4 | let(:reporter){ Vitals::Reporters::ConsoleReporter.new(category: 'main', format: TestFormat.new) } 5 | 6 | it '#inc' do 7 | out, _ = capture_io{ reporter.inc('1.2') } 8 | out.must_equal("main INC 1.2\n") 9 | end 10 | 11 | it '#timing' do 12 | out, _ = capture_io{ reporter.timing('1.2', 42) } 13 | out.must_equal("main TIME 1.2 42\n") 14 | end 15 | 16 | it '#gauge' do 17 | out, _ = capture_io{ reporter.gauge('1.2', 32) } 18 | out.must_equal("main GAUGE 1.2 32\n") 19 | end 20 | 21 | it '#count' do 22 | out, _ = capture_io{ reporter.count('1.2', 32) } 23 | out.must_equal("main COUNT 1.2 32\n") 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /spec/vitals/reporters/dns_resolving_statsd_reporter_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Vitals::Reporters::DnsResolvingStatsdReporter do 4 | 5 | it 'successfully creates a statsd object when using localhost' do 6 | reporter = Vitals::Reporters::DnsResolvingStatsdReporter.new(host: 'localhost', port: 8125, format: TestFormat.new) 7 | 8 | assert_equal reporter.statsd.host, 'localhost' 9 | end 10 | 11 | it 'successfully creates a statsd object when using ip address' do 12 | reporter = Vitals::Reporters::DnsResolvingStatsdReporter.new(host: '127.0.0.1', port: 8125, format: TestFormat.new) 13 | 14 | assert_equal reporter.statsd.host, '127.0.0.1' 15 | end 16 | 17 | describe 'with domain name' do 18 | FIRST_QUERY_RESULT = '10.0.0.1' 19 | SUBSEQUENT_QUERY_RESULT = '10.0.0.2' 20 | 21 | class StatsdMockDns < Vitals::Reporters::DnsResolvingStatsdReporter 22 | def query_dns 23 | result = @called ? [SUBSEQUENT_QUERY_RESULT, 1] : [FIRST_QUERY_RESULT, 1] 24 | @called = true 25 | result 26 | end 27 | end 28 | 29 | let(:reporter) { StatsdMockDns.new(host: 'example.com', port: 8125, format: TestFormat.new) } 30 | 31 | it 'creates statsd with ip address' do 32 | assert_equal reporter.statsd.host, FIRST_QUERY_RESULT 33 | end 34 | 35 | it 'creates new statsd object when DNS query changes' do 36 | old_statsd_obj = reporter.statsd 37 | sleep 1.5 #enough to make the first tick of the sleep happen 38 | 39 | assert_equal reporter.statsd.host, SUBSEQUENT_QUERY_RESULT 40 | assert old_statsd_obj.object_id != reporter.statsd.object_id 41 | end 42 | 43 | it "doesn't create new statsd object with each TTL if no changes" do 44 | reporter.statsd 45 | sleep 1.5 #enough to make the first tick of the sleep happen 46 | old_statsd_obj = reporter.statsd 47 | sleep 1 48 | assert_equal reporter.statsd.object_id, old_statsd_obj.object_id 49 | end 50 | end 51 | end 52 | 53 | -------------------------------------------------------------------------------- /spec/vitals/reporters/multi_reporter_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Vitals::Reporters::ConsoleReporter do 4 | let(:reporter){ 5 | reporter_one = Vitals::Reporters::ConsoleReporter.new(category: 'one', format: TestFormat.new) 6 | reporter_two = Vitals::Reporters::ConsoleReporter.new(category: 'two', format: TestFormat.new) 7 | 8 | Vitals::Reporters::MultiReporter.new(reporters: [ 9 | reporter_one, 10 | reporter_two 11 | ]) 12 | } 13 | 14 | it '#inc' do 15 | out, _ = capture_io{ reporter.inc('1.2') } 16 | out.must_equal("one INC 1.2\ntwo INC 1.2\n") 17 | end 18 | 19 | it '#timing' do 20 | out, _ = capture_io{ reporter.timing('1.2', 42) } 21 | out.must_equal("one TIME 1.2 42\ntwo TIME 1.2 42\n") 22 | end 23 | 24 | it '#gauge' do 25 | out, _ = capture_io{ reporter.gauge('1.2', 32) } 26 | out.must_equal("one GAUGE 1.2 32\ntwo GAUGE 1.2 32\n") 27 | end 28 | 29 | it '#count' do 30 | out, _ = capture_io{ reporter.count('1.2', 32) } 31 | out.must_equal("one COUNT 1.2 32\ntwo COUNT 1.2 32\n") 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /spec/vitals/reporters/statsd_reporter_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Vitals::Reporters::StatsdReporter do 4 | let(:reporter){ Vitals::Reporters::StatsdReporter.new(host: 'localhost', port: 8125, format: TestFormat.new) } 5 | 6 | it 'should set up statsd' do 7 | skip("implement") 8 | end 9 | 10 | it '#inc' do 11 | mock(reporter.statsd).increment('1.2').times(1) 12 | reporter.inc('1.2') 13 | end 14 | 15 | it '#count' do 16 | mock(reporter.statsd).count('1.2', 32).times(1) 17 | reporter.count('1.2', 32) 18 | end 19 | 20 | it '#timing' do 21 | mock(reporter.statsd).timing('1.2', 42).times(1) 22 | reporter.timing('1.2', 42) 23 | end 24 | 25 | it '#gauge' do 26 | mock(reporter.statsd).gauge('1.2', 32).times(1) 27 | reporter.gauge('1.2', 32) 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /spec/vitals/utils_bench.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Vitals::Utils do 4 | bench "#normalize_metric", 5 | "bad metric" => ->{ 6 | Vitals::Utils.normalize_metric('service/foo-bar baz:qux') 7 | }, 8 | "good metric" => ->{ 9 | Vitals::Utils.normalize_metric('good_looking.metric__baz') 10 | } 11 | end 12 | 13 | -------------------------------------------------------------------------------- /spec/vitals/utils_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Vitals::Utils do 4 | it "#normalize_metric" do 5 | Vitals::Utils.normalize_metric('service/foo-bar baz:qux') 6 | .must_equal('service_foo_bar_baz_qux') 7 | Vitals::Utils.normalize_metric('legal_looking.metric_like__that') 8 | .must_equal('legal_looking.metric_like__that') 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /spec/vitals_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Vitals do 4 | describe 'test setup' do 5 | it 'should sync Gemfile for multiverse tests' do 6 | /vitals \(#{Vitals::VERSION}\)/.match(File.read(File.expand_path('../Gemfile.lock', File.dirname(__FILE__)))).wont_be_nil 7 | end 8 | end 9 | 10 | describe 'api' do 11 | it 'should delegate to its reporter' do 12 | mock(Vitals.reporter).inc("foo.bar").times(1) 13 | Vitals.inc("foo.bar") 14 | 15 | mock(Vitals.reporter).timing("foo.bar", 42).times(1) 16 | Vitals.timing("foo.bar", 42) 17 | 18 | mock(Vitals.reporter).time("foo.bar") 19 | Vitals.time("foo.bar"){ } 20 | 21 | mock(Vitals.reporter).gauge("foo.bar", 42).times(1) 22 | Vitals.gauge("foo.bar", 42) 23 | 24 | mock(Vitals.reporter).count("foo.bar", 42).times(1) 25 | Vitals.count("foo.bar", 42) 26 | end 27 | end 28 | 29 | describe ".configure" do 30 | let(:assert_defaults ){ lambda { 31 | host = Vitals::Utils.hostname 32 | Vitals.reporter.must_be_kind_of(Vitals::Reporters::InmemReporter) 33 | Vitals.reporter.format.environment.must_equal(ENV['RACK_ENV'] || 'development') 34 | Vitals.reporter.format.host.must_equal(host) 35 | Vitals.reporter.format.facility.must_equal('default') 36 | Vitals.reporter.format.must_be_kind_of(Vitals::Formats::ProductionFormat) 37 | } 38 | } 39 | 40 | it "has default configuration" do 41 | Vitals.configure! 42 | assert_defaults.call 43 | Vitals.configure! 44 | assert_defaults.call 45 | end 46 | 47 | it "configures context" do 48 | # .configure returns a reporter but doesn't set .reporter 49 | Vitals.configure! do |c| 50 | c.environment = 'env' 51 | c.facility = 'svc' 52 | c.host = 'foohost' 53 | c.reporter = Vitals::Reporters::ConsoleReporter.new 54 | c.format = Vitals::Formats::HostLastFormat 55 | end 56 | 57 | Vitals.reporter.must_be_kind_of(Vitals::Reporters::ConsoleReporter) 58 | Vitals.reporter.format.environment.must_equal('env') 59 | Vitals.reporter.format.host.must_equal('foohost') 60 | Vitals.reporter.format.facility.must_equal('svc') 61 | Vitals.reporter.format.must_be_kind_of(Vitals::Formats::HostLastFormat) 62 | end 63 | 64 | it 'configures modules' do 65 | begin 66 | subscribers = Vitals.subscribe!(:action_controller, :active_job, :grape) 67 | subscribers.each{|sub| sub.wont_be_nil } 68 | ensure 69 | subscribers.each{|sub| ActiveSupport::Notifications.unsubscribe(sub) } 70 | end 71 | end 72 | end 73 | end 74 | 75 | -------------------------------------------------------------------------------- /vitals.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'vitals/version' 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = "vitals" 8 | spec.version = Vitals::VERSION 9 | spec.authors = ["Dotan Nahum"] 10 | spec.email = ["jondotan@gmail.com"] 11 | 12 | spec.summary = %q{Flexible StatsD instrumentation for Rails, Rack, Grape and more} 13 | spec.description = %q{Flexible StatsD instrumentation for Rails, Rack, Grape and more} 14 | spec.homepage = "https://github.com/jondot/vitals" 15 | spec.license = "MIT" 16 | 17 | spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features|integration)/}) } 18 | spec.bindir = "exe" 19 | spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } 20 | spec.require_paths = ["lib"] 21 | 22 | spec.add_runtime_dependency "statsd-ruby", "~> 1.3.0" 23 | 24 | spec.add_development_dependency "guard-rubocop", "~> 1.2.0" 25 | spec.add_development_dependency "guard-minitest", "~> 2.4.4" 26 | spec.add_development_dependency "bundler", "~> 1.11" 27 | spec.add_development_dependency "rake", "~> 10.0" 28 | spec.add_development_dependency "minitest", "~> 5.0" 29 | spec.add_development_dependency "rack-test", "~> 0.6.3" 30 | spec.add_development_dependency "rr", "~> 1.1.2" 31 | spec.add_development_dependency "benchmark-ipsa", "~> 0.2.0" 32 | 33 | spec.add_development_dependency "coveralls", "~> 0.8.13" 34 | # integrations 35 | # TODO we should test these under isolated environment while removing 36 | # these from here and running without bundler, inside docker, or by 37 | # doing what newrelic does - which is hooking into bundler and Gemfile so that 38 | # we simulate different bundler environment, so, 39 | # we should test many versions of rails, grape, and so on with the same 40 | # set of integration tests 41 | # for now, we keep latest versions 42 | spec.add_development_dependency "grape", "~> 0.15.0" 43 | spec.add_development_dependency "activesupport", "~> 4.2.6" 44 | spec.add_development_dependency "sinatra", "~> 1.4.7" 45 | spec.add_development_dependency "byebug", "~> 8.2.2" 46 | 47 | end 48 | --------------------------------------------------------------------------------