├── .gitignore ├── rails_app ├── log │ └── .keep ├── storage │ └── .keep ├── tmp │ ├── .keep │ ├── pids │ │ └── .keep │ └── storage │ │ └── .keep ├── vendor │ └── .keep ├── lib │ ├── assets │ │ └── .keep │ └── tasks │ │ └── .keep ├── public │ ├── favicon.ico │ ├── apple-touch-icon.png │ ├── apple-touch-icon-precomposed.png │ ├── robots.txt │ ├── 500.html │ ├── 422.html │ └── 404.html ├── app │ ├── assets │ │ ├── images │ │ │ └── .keep │ │ ├── config │ │ │ └── manifest.js │ │ └── stylesheets │ │ │ └── application.css │ ├── models │ │ ├── concerns │ │ │ └── .keep │ │ └── application_record.rb │ ├── controllers │ │ ├── concerns │ │ │ └── .keep │ │ ├── application_controller.rb │ │ └── home_controller.rb │ ├── views │ │ ├── layouts │ │ │ ├── mailer.text.erb │ │ │ ├── mailer.html.erb │ │ │ └── application.html.erb │ │ └── home │ │ │ └── index.html.erb │ ├── helpers │ │ └── application_helper.rb │ ├── jobs │ │ ├── waiting_job.rb │ │ ├── danger_job.rb │ │ ├── empty_job.rb │ │ └── application_job.rb │ ├── channels │ │ └── application_cable │ │ │ ├── channel.rb │ │ │ └── connection.rb │ └── mailers │ │ └── application_mailer.rb ├── db │ ├── development.sqlite3 │ └── seeds.rb ├── .ruby-version ├── config │ ├── master.key │ ├── initializers │ │ ├── yabeda_rails.rb │ │ ├── sidekiq.rb │ │ ├── filter_parameter_logging.rb │ │ ├── permissions_policy.rb │ │ ├── assets.rb │ │ ├── inflections.rb │ │ └── content_security_policy.rb │ ├── sidekiq.yml │ ├── environment.rb │ ├── routes.rb │ ├── cable.yml │ ├── boot.rb │ ├── credentials.yml.enc │ ├── database.yml │ ├── locales │ │ └── en.yml │ ├── storage.yml │ ├── application.rb │ ├── puma.rb │ └── environments │ │ ├── test.rb │ │ ├── development.rb │ │ └── production.rb ├── bin │ ├── rake │ ├── rails │ ├── setup │ └── bundle ├── .gitattributes ├── config.ru ├── Rakefile ├── Dockerfile ├── README.md ├── .gitignore ├── Gemfile └── Gemfile.lock ├── grafana_db └── grafana.db ├── rails_stressor └── Dockerfile ├── prometheus.yml ├── docker-compose.yml └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /rails_app/log/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /rails_app/storage/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /rails_app/tmp/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /rails_app/vendor/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /rails_app/lib/assets/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /rails_app/lib/tasks/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /rails_app/public/favicon.ico: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /rails_app/tmp/pids/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /rails_app/tmp/storage/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /rails_app/app/assets/images/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /rails_app/db/development.sqlite3: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /rails_app/.ruby-version: -------------------------------------------------------------------------------- 1 | ruby-3.2.0 2 | -------------------------------------------------------------------------------- /rails_app/app/models/concerns/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /rails_app/public/apple-touch-icon.png: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /rails_app/app/controllers/concerns/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /rails_app/public/apple-touch-icon-precomposed.png: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /rails_app/app/views/layouts/mailer.text.erb: -------------------------------------------------------------------------------- 1 | <%= yield %> 2 | -------------------------------------------------------------------------------- /rails_app/config/master.key: -------------------------------------------------------------------------------- 1 | 2bb418e2b02cebeec4682fe0961cffcf -------------------------------------------------------------------------------- /grafana_db/grafana.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yabeda-rb/example-prometheus/HEAD/grafana_db/grafana.db -------------------------------------------------------------------------------- /rails_app/app/assets/config/manifest.js: -------------------------------------------------------------------------------- 1 | //= link_tree ../images 2 | //= link_directory ../stylesheets .css 3 | -------------------------------------------------------------------------------- /rails_app/config/initializers/yabeda_rails.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | Yabeda::Rails.install! 4 | -------------------------------------------------------------------------------- /rails_app/app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module ApplicationHelper 4 | end 5 | -------------------------------------------------------------------------------- /rails_stressor/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang 2 | 3 | RUN go install github.com/rakyll/hey@latest 4 | 5 | ENTRYPOINT ["hey"] 6 | -------------------------------------------------------------------------------- /rails_app/public/robots.txt: -------------------------------------------------------------------------------- 1 | # See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file 2 | -------------------------------------------------------------------------------- /rails_app/config/sidekiq.yml: -------------------------------------------------------------------------------- 1 | :concurrency: 5 2 | :queues: 3 | - [urgent, 20] 4 | - [mailers, 10] 5 | - [default, 10] 6 | - [utils, 1] 7 | -------------------------------------------------------------------------------- /rails_app/app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ApplicationController < ActionController::Base 4 | end 5 | -------------------------------------------------------------------------------- /rails_app/bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | require_relative '../config/boot' 5 | require 'rake' 6 | Rake.application.run 7 | -------------------------------------------------------------------------------- /rails_app/app/models/application_record.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ApplicationRecord < ActiveRecord::Base 4 | primary_abstract_class 5 | end 6 | -------------------------------------------------------------------------------- /rails_app/app/jobs/waiting_job.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class WaitingJob < ApplicationJob 4 | def perform 5 | sleep rand(10) 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /rails_app/config/initializers/sidekiq.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | Sidekiq.configure_server do 4 | Yabeda::Prometheus::Exporter.start_metrics_server! 5 | end 6 | -------------------------------------------------------------------------------- /rails_app/app/channels/application_cable/channel.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module ApplicationCable 4 | class Channel < ActionCable::Channel::Base 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /rails_app/app/channels/application_cable/connection.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module ApplicationCable 4 | class Connection < ActionCable::Connection::Base 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /rails_app/app/jobs/danger_job.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class DangerJob < ApplicationJob 4 | def perform 5 | raise "You're not lucky today" if rand < 0.5 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /rails_app/app/mailers/application_mailer.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ApplicationMailer < ActionMailer::Base 4 | default from: 'from@example.com' 5 | layout 'mailer' 6 | end 7 | -------------------------------------------------------------------------------- /rails_app/bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | APP_PATH = File.expand_path('../config/application', __dir__) 5 | require_relative '../config/boot' 6 | require 'rails/commands' 7 | -------------------------------------------------------------------------------- /rails_app/config/environment.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Load the Rails application. 4 | require_relative 'application' 5 | 6 | # Initialize the Rails application. 7 | Rails.application.initialize! 8 | -------------------------------------------------------------------------------- /rails_app/app/views/home/index.html.erb: -------------------------------------------------------------------------------- 1 | <%= form_tag("/", method: "post") do %> 2 | <%= submit_tag("Let the jobs flow through Sidekiq queues!", disable_with: "Please stand by…", class: 'e-form__button') %> 3 | <% end %> 4 | -------------------------------------------------------------------------------- /rails_app/app/jobs/empty_job.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class EmptyJob < ApplicationJob 4 | queue_as :utils 5 | 6 | def perform 7 | Rails.logger.info "I'm empty job, I'm doing nothing" 8 | sleep rand 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /rails_app/config/routes.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "sidekiq/web" 4 | 5 | Rails.application.routes.draw do 6 | mount Sidekiq::Web => "/sidekiq" 7 | 8 | post '/', to: "home#enqueue" 9 | root to: "home#index" 10 | end 11 | -------------------------------------------------------------------------------- /rails_app/config/cable.yml: -------------------------------------------------------------------------------- 1 | development: 2 | adapter: async 3 | 4 | test: 5 | adapter: test 6 | 7 | production: 8 | adapter: redis 9 | url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> 10 | channel_prefix: rails_app_production 11 | -------------------------------------------------------------------------------- /rails_app/config/boot.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) 4 | 5 | require 'bundler/setup' # Set up gems listed in the Gemfile. 6 | require 'bootsnap/setup' # Speed up boot time by caching expensive operations. 7 | -------------------------------------------------------------------------------- /rails_app/.gitattributes: -------------------------------------------------------------------------------- 1 | # See https://git-scm.com/docs/gitattributes for more about git attribute files. 2 | 3 | # Mark the database schema as having been generated. 4 | db/schema.rb linguist-generated 5 | 6 | # Mark any vendored files as having been vendored. 7 | vendor/* linguist-vendored 8 | -------------------------------------------------------------------------------- /rails_app/config.ru: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # This file is used by Rack-based servers to start the application. 4 | 5 | require_relative 'config/environment' 6 | 7 | use Yabeda::Prometheus::Exporter 8 | 9 | run Rails.application 10 | Rails.application.load_server 11 | -------------------------------------------------------------------------------- /rails_app/Rakefile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Add your own tasks in files placed in lib/tasks ending in .rake, 4 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 5 | 6 | require_relative 'config/application' 7 | 8 | Rails.application.load_tasks 9 | -------------------------------------------------------------------------------- /rails_app/app/views/layouts/mailer.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | <%= yield %> 12 | 13 | 14 | -------------------------------------------------------------------------------- /rails_app/app/jobs/application_job.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ApplicationJob < ActiveJob::Base 4 | # Automatically retry jobs that encountered a deadlock 5 | # retry_on ActiveRecord::Deadlocked 6 | 7 | # Most jobs are safe to ignore if the underlying records are no longer available 8 | # discard_on ActiveJob::DeserializationError 9 | end 10 | -------------------------------------------------------------------------------- /rails_app/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ruby:3.2.0 2 | 3 | RUN dpkg --configure -a 4 | 5 | RUN apt-get update && apt-get install -qq -y --no-install-recommends \ 6 | build-essential \ 7 | sqlite3 8 | 9 | RUN mkdir -p /app 10 | WORKDIR /app 11 | 12 | COPY Gemfile Gemfile.lock ./ 13 | RUN gem install bundler && bundle install --jobs 4 --retry 5 14 | 15 | COPY . . 16 | 17 | EXPOSE 5000 18 | -------------------------------------------------------------------------------- /rails_app/app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | RailsApp 5 | 6 | <%= csrf_meta_tags %> 7 | <%= csp_meta_tag %> 8 | 9 | <%= stylesheet_link_tag "application" %> 10 | 11 | 12 | 13 | <%= yield %> 14 | 15 | 16 | -------------------------------------------------------------------------------- /prometheus.yml: -------------------------------------------------------------------------------- 1 | global: 2 | scrape_interval: 15s 3 | evaluation_interval: 15s 4 | 5 | scrape_configs: 6 | - job_name: 'rails' 7 | scheme: http 8 | metrics_path: '/metrics' 9 | static_configs: 10 | - targets: 11 | - 'rails:5000' 12 | - job_name: 'sidekiq' 13 | scheme: http 14 | metrics_path: '/metrics' 15 | static_configs: 16 | - targets: 17 | - 'sidekiq:5100' 18 | -------------------------------------------------------------------------------- /rails_app/db/seeds.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # This file should contain all the record creation needed to seed the database with its default values. 3 | # The data can then be loaded with the bin/rails db:seed command (or created alongside the database with db:setup). 4 | # 5 | # Examples: 6 | # 7 | # movies = Movie.create([{ name: "Star Wars" }, { name: "Lord of the Rings" }]) 8 | # Character.create(name: "Luke", movie: movies.first) 9 | -------------------------------------------------------------------------------- /rails_app/app/controllers/home_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class HomeController < ApplicationController 4 | def index; end 5 | 6 | def enqueue 7 | rand(1000).times do 8 | EmptyJob.perform_later 9 | end 10 | rand(1000).times do 11 | WaitingJob.perform_later 12 | end 13 | rand(100).times do 14 | DangerJob.perform_later 15 | end 16 | redirect_to root_path 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /rails_app/config/credentials.yml.enc: -------------------------------------------------------------------------------- 1 | LLGLWwqxt3BhqfsscIMFUpUE+wgXKjjtWekgusHljYCOH142Y7LU4yFRg7HxBC8vtrUAIy0FhO4J28XnIcNxk6W09S8NB8ohnwQXRtM3JOPIv1MWFDifgj8Cze1ZTuMpfsJG6fIYREd//9uUkTl4Q6A9EcX1C6o/AQ7eIyKpopLs1aAEyHrR+3DnsXit35zER+0B2Uu0rtHmhVZKKfuOeSbS4dO9oUt5NA0OAM33JJ2OHMVbOkTWz0qjZ9rzgp1DWztxAD5fQAh91fZgBGFBxCy7RvcUbZvDjEQnw0ULMYFSe9ZVNNJc9d5YVg5uHjD+aUdvqkTuprxncbd58/wrP2JKpbwCOW9MFXI0w3iGqWR6CRCuxXa3m+SRV4RQ7XeOZjk2vjqxgfdCoCfx2PmmE7IsmDjJvPmteJGS--gOSc/EnWhngfNB5Q--Pt8voHBvdFQP805t4plu+A== -------------------------------------------------------------------------------- /rails_app/README.md: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /rails_app/config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Be sure to restart your server when you modify this file. 4 | 5 | # Configure parameters to be filtered from the log file. Use this to limit dissemination of 6 | # sensitive information. See the ActiveSupport::ParameterFilter documentation for supported 7 | # notations and behaviors. 8 | Rails.application.config.filter_parameters += %i[ 9 | passw secret token _key crypt salt certificate otp ssn 10 | ] 11 | -------------------------------------------------------------------------------- /rails_app/config/initializers/permissions_policy.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # Define an application-wide HTTP permissions policy. For further 3 | # information see https://developers.google.com/web/updates/2018/06/feature-policy 4 | # 5 | # Rails.application.config.permissions_policy do |f| 6 | # f.camera :none 7 | # f.gyroscope :none 8 | # f.microphone :none 9 | # f.usb :none 10 | # f.fullscreen :self 11 | # f.payment :self, "https://secure.example.com" 12 | # end 13 | -------------------------------------------------------------------------------- /rails_app/config/initializers/assets.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Be sure to restart your server when you modify this file. 4 | 5 | # Version of your assets, change this if you want to expire all your assets. 6 | Rails.application.config.assets.version = '1.0' 7 | 8 | # Add additional assets to the asset load path. 9 | # Rails.application.config.assets.paths << Emoji.images_path 10 | 11 | # Precompile additional assets. 12 | # application.js, application.css, and all non-JS/CSS in the app/assets 13 | # folder are already added. 14 | # Rails.application.config.assets.precompile += %w( admin.js admin.css ) 15 | -------------------------------------------------------------------------------- /rails_app/config/database.yml: -------------------------------------------------------------------------------- 1 | # SQLite. Versions 3.8.0 and up are supported. 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: <%= ENV.fetch("RAILS_MAX_THREADS") { 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 | -------------------------------------------------------------------------------- /rails_app/config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # Be sure to restart your server when you modify this file. 3 | 4 | # Add new inflection rules using the following format. Inflections 5 | # are locale specific, and you may define rules for as many different 6 | # locales as you wish. All of these examples are active by default: 7 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 8 | # inflect.plural /^(ox)$/i, "\\1en" 9 | # inflect.singular /^(ox)en/i, "\\1" 10 | # inflect.irregular "person", "people" 11 | # inflect.uncountable %w( fish sheep ) 12 | # end 13 | 14 | # These inflection rules are supported but not enabled by default: 15 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 16 | # inflect.acronym "RESTful" 17 | # end 18 | -------------------------------------------------------------------------------- /rails_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, if configured) file within this directory, lib/assets/stylesheets, or any plugin's 6 | * 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 other CSS 10 | * files in this directory. Styles in this file should be added after the last require_* statement. 11 | * It is generally better to create a new file per style scope. 12 | * 13 | *= require_tree . 14 | *= require_self 15 | */ 16 | -------------------------------------------------------------------------------- /rails_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-* 13 | 14 | # Ignore all logfiles and tempfiles. 15 | /log/* 16 | /tmp/* 17 | !/log/.keep 18 | !/tmp/.keep 19 | 20 | # Ignore pidfiles, but keep the directory. 21 | /tmp/pids/* 22 | !/tmp/pids/ 23 | !/tmp/pids/.keep 24 | 25 | # Ignore uploaded files in development. 26 | /storage/* 27 | !/storage/.keep 28 | /tmp/storage/* 29 | !/tmp/storage/ 30 | !/tmp/storage/.keep 31 | 32 | /public/assets 33 | 34 | # Ignore master key for decrypting credentials and more. 35 | /config/master.key 36 | -------------------------------------------------------------------------------- /rails_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 | # The following keys must be escaped otherwise they will not be retrieved by 20 | # the default I18n backend: 21 | # 22 | # true, false, on, off, yes, no 23 | # 24 | # Instead, surround them with single quotes. 25 | # 26 | # en: 27 | # "true": "foo" 28 | # 29 | # To learn more, please read the Rails Internationalization guide 30 | # available at https://guides.rubyonrails.org/i18n.html. 31 | 32 | en: 33 | hello: "Hello world" 34 | -------------------------------------------------------------------------------- /rails_app/bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | require 'fileutils' 5 | 6 | # path to your application root. 7 | APP_ROOT = File.expand_path('..', __dir__) 8 | 9 | def system!(*args) 10 | system(*args) || abort("\n== Command #{args} failed ==") 11 | end 12 | 13 | FileUtils.chdir APP_ROOT do 14 | # This script is a way to set up or update your development environment automatically. 15 | # This script is idempotent, so that you can run it at any time and get an expectable outcome. 16 | # Add necessary setup steps to this file. 17 | 18 | puts '== Installing dependencies ==' 19 | system! 'gem install bundler --conservative' 20 | system('bundle check') || system!('bundle install') 21 | 22 | # puts "\n== Copying sample files ==" 23 | # unless File.exist?("config/database.yml") 24 | # FileUtils.cp "config/database.yml.sample", "config/database.yml" 25 | # end 26 | 27 | puts "\n== Preparing database ==" 28 | system! 'bin/rails db:prepare' 29 | 30 | puts "\n== Removing old logs and tempfiles ==" 31 | system! 'bin/rails log:clear tmp:clear' 32 | 33 | puts "\n== Restarting application server ==" 34 | system! 'bin/rails restart' 35 | end 36 | -------------------------------------------------------------------------------- /rails_app/config/initializers/content_security_policy.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | # Be sure to restart your server when you modify this file. 3 | 4 | # Define an application-wide content security policy. 5 | # See the Securing Rails Applications Guide for more information: 6 | # https://guides.rubyonrails.org/security.html#content-security-policy-header 7 | 8 | # Rails.application.configure do 9 | # config.content_security_policy do |policy| 10 | # policy.default_src :self, :https 11 | # policy.font_src :self, :https, :data 12 | # policy.img_src :self, :https, :data 13 | # policy.object_src :none 14 | # policy.script_src :self, :https 15 | # policy.style_src :self, :https 16 | # # Specify URI for violation reports 17 | # # policy.report_uri "/csp-violation-report-endpoint" 18 | # end 19 | # 20 | # # Generate session nonces for permitted importmap and inline scripts 21 | # config.content_security_policy_nonce_generator = ->(request) { request.session.id.to_s } 22 | # config.content_security_policy_nonce_directives = %w(script-src) 23 | # 24 | # # Report violations without enforcing the policy. 25 | # # config.content_security_policy_report_only = true 26 | # end 27 | -------------------------------------------------------------------------------- /rails_app/config/storage.yml: -------------------------------------------------------------------------------- 1 | test: 2 | service: Disk 3 | root: <%= Rails.root.join("tmp/storage") %> 4 | 5 | local: 6 | service: Disk 7 | root: <%= Rails.root.join("storage") %> 8 | 9 | # Use bin/rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) 10 | # amazon: 11 | # service: S3 12 | # access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> 13 | # secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> 14 | # region: us-east-1 15 | # bucket: your_own_bucket-<%= Rails.env %> 16 | 17 | # Remember not to checkin your GCS keyfile to a repository 18 | # google: 19 | # service: GCS 20 | # project: your_project 21 | # credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> 22 | # bucket: your_own_bucket-<%= Rails.env %> 23 | 24 | # Use bin/rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) 25 | # microsoft: 26 | # service: AzureStorage 27 | # storage_account_name: your_account_name 28 | # storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> 29 | # container: your_container_name-<%= Rails.env %> 30 | 31 | # mirror: 32 | # service: Mirror 33 | # primary: local 34 | # mirrors: [ amazon, google, microsoft ] 35 | -------------------------------------------------------------------------------- /rails_app/config/application.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'boot' 4 | 5 | require 'rails' 6 | # Pick the frameworks you want: 7 | require 'active_model/railtie' 8 | require 'active_job/railtie' 9 | require 'active_record/railtie' 10 | require 'active_storage/engine' 11 | require 'action_controller/railtie' 12 | require 'action_mailer/railtie' 13 | require 'action_mailbox/engine' 14 | require 'action_text/engine' 15 | require 'action_view/railtie' 16 | require 'action_cable/engine' 17 | # require "rails/test_unit/railtie" 18 | 19 | # Require the gems listed in Gemfile, including any gems 20 | # you've limited to :test, :development, or :production. 21 | Bundler.require(*Rails.groups) 22 | 23 | module RailsApp 24 | class Application < Rails::Application 25 | # Initialize configuration defaults for originally generated Rails version. 26 | config.load_defaults 7.0 27 | 28 | # Configuration for the application, engines, and railties goes here. 29 | # 30 | # These settings can be overridden in specific environments using the files 31 | # in config/environments, which are processed later. 32 | # 33 | # config.time_zone = "Central Time (US & Canada)" 34 | # config.eager_load_paths << Rails.root.join("extras") 35 | 36 | # Don't generate system test files. 37 | config.generators.system_tests = nil 38 | 39 | config.active_job.queue_adapter = :sidekiq 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.4' 2 | 3 | x-app-service-template: &app 4 | build: rails_app 5 | image: yabeda-rails-app:1.0 6 | volumes: 7 | - ./rails_app:/app 8 | 9 | services: 10 | rails: 11 | <<: *app 12 | ports: 13 | - 5000:5000 14 | environment: 15 | REDIS_URL: redis://redis:6379/0 16 | stdin_open: true 17 | tty: true 18 | depends_on: 19 | - redis 20 | 21 | command: bundle exec puma -C config/puma.rb 22 | 23 | sidekiq: 24 | <<: *app 25 | ports: 26 | - 5100:5100 27 | environment: 28 | PORT: 5100 29 | REDIS_URL: redis://redis:6379/0 30 | depends_on: 31 | - redis 32 | 33 | command: sidekiq -C config/sidekiq.yml 34 | 35 | redis: 36 | image: redis 37 | command: redis-server 38 | 39 | grafana: 40 | image: grafana/grafana:10.2.2 41 | depends_on: 42 | - prometheus 43 | ports: 44 | - 3000:3000/tcp 45 | volumes: 46 | - ./grafana_db:/var/lib/grafana 47 | user: "0" 48 | 49 | prometheus: 50 | image: prom/prometheus:v2.48.1 51 | volumes: 52 | - ./prometheus.yml:/etc/prometheus/prometheus.yml 53 | ports: 54 | - 9090:9090/tcp 55 | depends_on: 56 | - rails 57 | command: 58 | - --config.file=/etc/prometheus/prometheus.yml 59 | 60 | rails_stressor: 61 | build: rails_stressor 62 | image: rails_stressor 63 | depends_on: 64 | - rails 65 | command: -z 2m -c 15 -m GET http://rails:5000 66 | -------------------------------------------------------------------------------- /rails_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 | -------------------------------------------------------------------------------- /rails_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 | -------------------------------------------------------------------------------- /rails_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 | -------------------------------------------------------------------------------- /rails_app/config/puma.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Puma can serve each request in a thread from an internal thread pool. 4 | # The `threads` method setting takes two numbers: a minimum and maximum. 5 | # Any libraries that use thread pools should be configured to match 6 | # the maximum value specified for Puma. Default is set to 5 threads for minimum 7 | # and maximum; this matches the default thread size of Active Record. 8 | # 9 | max_threads_count = ENV.fetch('RAILS_MAX_THREADS', 5) 10 | min_threads_count = ENV.fetch('RAILS_MIN_THREADS') { max_threads_count } 11 | threads min_threads_count, max_threads_count 12 | 13 | # Specifies the `worker_timeout` threshold that Puma will use to wait before 14 | # terminating a worker in development environments. 15 | # 16 | worker_timeout 3600 if ENV.fetch('RAILS_ENV', 'development') == 'development' 17 | 18 | # Specifies the `port` that Puma will listen on to receive requests; default is 3000. 19 | # 20 | port ENV.fetch('PORT', 5000) 21 | 22 | # Specifies the `environment` that Puma will run in. 23 | # 24 | environment ENV.fetch('RAILS_ENV', 'development') 25 | 26 | # Specifies the `pidfile` that Puma will use. 27 | pidfile ENV.fetch('PIDFILE', 'tmp/pids/server.pid') 28 | 29 | # Specifies the number of `workers` to boot in clustered mode. 30 | # Workers are forked web server processes. If using threads and workers together 31 | # the concurrency of the application would be max `threads` * `workers`. 32 | # Workers do not work on JRuby or Windows (both of which do not support 33 | # processes). 34 | # 35 | # workers ENV.fetch("WEB_CONCURRENCY") { 2 } 36 | 37 | activate_control_app 38 | plugin :yabeda 39 | 40 | # Use the `preload_app!` method when specifying a `workers` number. 41 | # This directive tells Puma to first boot the application and load code 42 | # before forking the application. This takes advantage of Copy On Write 43 | # process behavior so workers use less memory. 44 | # 45 | # preload_app! 46 | 47 | # Allow puma to be restarted by `bin/rails restart` command. 48 | plugin :tmp_restart 49 | -------------------------------------------------------------------------------- /rails_app/Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source 'https://rubygems.org' 4 | git_source(:github) { |repo| "https://github.com/#{repo}.git" } 5 | 6 | ruby '3.2.0' 7 | 8 | # Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main" 9 | gem 'rails', '~> 7.0.7' 10 | 11 | # The original asset pipeline for Rails [https://github.com/rails/sprockets-rails] 12 | gem 'sprockets-rails' 13 | 14 | # Use sqlite3 as the database for Active Record 15 | gem 'sqlite3', '~> 1.4' 16 | 17 | # Use the Puma web server [https://github.com/puma/puma] 18 | gem 'puma', '~> 5.0' 19 | 20 | # Build JSON APIs with ease [https://github.com/rails/jbuilder] 21 | gem 'jbuilder' 22 | 23 | # Use Redis adapter to run Action Cable in production 24 | # gem "redis", "~> 4.0" 25 | 26 | # Use Kredis to get higher-level data types in Redis [https://github.com/rails/kredis] 27 | # gem "kredis" 28 | 29 | # Use Active Model has_secure_password [https://guides.rubyonrails.org/active_model_basics.html#securepassword] 30 | # gem "bcrypt", "~> 3.1.7" 31 | 32 | # Windows does not include zoneinfo files, so bundle the tzinfo-data gem 33 | gem 'tzinfo-data', platforms: %i[mingw mswin x64_mingw jruby] 34 | 35 | # Reduces boot times through caching; required in config/boot.rb 36 | gem 'bootsnap', require: false 37 | 38 | # Use Sass to process CSS 39 | # gem "sassc-rails" 40 | 41 | # Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images] 42 | # gem "image_processing", "~> 1.2" 43 | 44 | gem "sidekiq" 45 | 46 | gem "yabeda-rails" 47 | gem "yabeda-sidekiq" 48 | gem "webrick" # for yabeda-sidekiq 49 | gem "yabeda-prometheus" 50 | gem "yabeda-puma-plugin" 51 | 52 | # Since v0.1.4 yabeda-prometheus can work either with official client 53 | # or with GitLab's fork which can handle multi-process application servers 54 | # We'll stick with official one. 55 | gem "prometheus-client" 56 | 57 | group :development, :test do 58 | # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem 59 | gem 'debug', platforms: %i[mri mingw x64_mingw] 60 | end 61 | 62 | group :development do 63 | # Use console on exceptions pages [https://github.com/rails/web-console] 64 | gem 'web-console' 65 | 66 | # Add speed badges [https://github.com/MiniProfiler/rack-mini-profiler] 67 | # gem "rack-mini-profiler" 68 | 69 | # Speed up commands on slow machines / big apps [https://github.com/rails/spring] 70 | # gem "spring" 71 | end 72 | -------------------------------------------------------------------------------- /rails_app/config/environments/test.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'active_support/core_ext/integer/time' 4 | 5 | # The test environment is used exclusively to run your application's 6 | # test suite. You never need to work with it otherwise. Remember that 7 | # your test database is "scratch space" for the test suite and is wiped 8 | # and recreated between test runs. Don't rely on the data there! 9 | 10 | Rails.application.configure do 11 | # Settings specified here will take precedence over those in config/application.rb. 12 | 13 | # Turn false under Spring and add config.action_view.cache_template_loading = true. 14 | config.cache_classes = true 15 | 16 | # Eager loading loads your whole application. When running a single test locally, 17 | # this probably isn't necessary. It's a good idea to do in a continuous integration 18 | # system, or in some way before deploying your code. 19 | config.eager_load = ENV['CI'].present? 20 | 21 | # Configure public file server for tests with Cache-Control for performance. 22 | config.public_file_server.enabled = true 23 | config.public_file_server.headers = { 24 | 'Cache-Control' => "public, max-age=#{1.hour.to_i}" 25 | } 26 | 27 | # Show full error reports and disable caching. 28 | config.consider_all_requests_local = true 29 | config.action_controller.perform_caching = false 30 | config.cache_store = :null_store 31 | 32 | # Raise exceptions instead of rendering exception templates. 33 | config.action_dispatch.show_exceptions = false 34 | 35 | # Disable request forgery protection in test environment. 36 | config.action_controller.allow_forgery_protection = false 37 | 38 | # Store uploaded files on the local file system in a temporary directory. 39 | config.active_storage.service = :test 40 | 41 | config.action_mailer.perform_caching = false 42 | 43 | # Tell Action Mailer not to deliver emails to the real world. 44 | # The :test delivery method accumulates sent emails in the 45 | # ActionMailer::Base.deliveries array. 46 | config.action_mailer.delivery_method = :test 47 | 48 | # Print deprecation notices to the stderr. 49 | config.active_support.deprecation = :stderr 50 | 51 | # Raise exceptions for disallowed deprecations. 52 | config.active_support.disallowed_deprecation = :raise 53 | 54 | # Tell Active Support which deprecation messages to disallow. 55 | config.active_support.disallowed_deprecation_warnings = [] 56 | 57 | # Raises error for missing translations. 58 | # config.i18n.raise_on_missing_translations = true 59 | 60 | # Annotate rendered view with file names. 61 | # config.action_view.annotate_rendered_view_with_filenames = true 62 | end 63 | -------------------------------------------------------------------------------- /rails_app/config/environments/development.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'active_support/core_ext/integer/time' 4 | 5 | Rails.application.configure do 6 | # Settings specified here will take precedence over those in config/application.rb. 7 | 8 | # In the development environment your application's code is reloaded any time 9 | # it changes. This slows down response time but is perfect for development 10 | # since you don't have to restart the web server when you make code changes. 11 | config.cache_classes = false 12 | 13 | # Do not eager load code on boot. 14 | config.eager_load = false 15 | 16 | # Show full error reports. 17 | config.consider_all_requests_local = true 18 | 19 | # Enable server timing 20 | config.server_timing = true 21 | 22 | # Enable/disable caching. By default caching is disabled. 23 | # Run rails dev:cache to toggle caching. 24 | if Rails.root.join('tmp/caching-dev.txt').exist? 25 | config.action_controller.perform_caching = true 26 | config.action_controller.enable_fragment_cache_logging = true 27 | 28 | config.cache_store = :memory_store 29 | config.public_file_server.headers = { 30 | 'Cache-Control' => "public, max-age=#{2.days.to_i}" 31 | } 32 | else 33 | config.action_controller.perform_caching = false 34 | 35 | config.cache_store = :null_store 36 | end 37 | 38 | # Store uploaded files on the local file system (see config/storage.yml for options). 39 | config.active_storage.service = :local 40 | 41 | # Don't care if the mailer can't send. 42 | config.action_mailer.raise_delivery_errors = false 43 | 44 | config.action_mailer.perform_caching = false 45 | 46 | # Print deprecation notices to the Rails logger. 47 | config.active_support.deprecation = :log 48 | 49 | # Raise exceptions for disallowed deprecations. 50 | config.active_support.disallowed_deprecation = :raise 51 | 52 | # Tell Active Support which deprecation messages to disallow. 53 | config.active_support.disallowed_deprecation_warnings = [] 54 | 55 | # Raise an error on page load if there are pending migrations. 56 | config.active_record.migration_error = :page_load 57 | 58 | # Highlight code that triggered database queries in logs. 59 | config.active_record.verbose_query_logs = true 60 | 61 | # Suppress logger output for asset requests. 62 | config.assets.quiet = true 63 | 64 | # Raises error for missing translations. 65 | # config.i18n.raise_on_missing_translations = true 66 | 67 | # Annotate rendered view with file names. 68 | # config.action_view.annotate_rendered_view_with_filenames = true 69 | 70 | # Uncomment if you wish to allow Action Cable access from any origin. 71 | # config.action_cable.disable_request_forgery_protection = true 72 | end 73 | -------------------------------------------------------------------------------- /rails_app/bin/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'bundle' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require 'rubygems' 12 | 13 | m = Module.new do 14 | module_function 15 | 16 | def invoked_as_script? 17 | File.expand_path($PROGRAM_NAME) == File.expand_path(__FILE__) 18 | end 19 | 20 | def env_var_version 21 | ENV['BUNDLER_VERSION'] 22 | end 23 | 24 | def cli_arg_version 25 | return unless invoked_as_script? # don't want to hijack other binstubs 26 | return unless 'update'.start_with?(ARGV.first || ' ') # must be running `bundle update` 27 | 28 | bundler_version = nil 29 | update_index = nil 30 | ARGV.each_with_index do |a, i| 31 | bundler_version = a if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN 32 | next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/ 33 | 34 | bundler_version = Regexp.last_match(1) 35 | update_index = i 36 | end 37 | bundler_version 38 | end 39 | 40 | def gemfile 41 | gemfile = ENV['BUNDLE_GEMFILE'] 42 | return gemfile if gemfile && !gemfile.empty? 43 | 44 | File.expand_path('../Gemfile', __dir__) 45 | end 46 | 47 | def lockfile 48 | lockfile = 49 | case File.basename(gemfile) 50 | when 'gems.rb' then gemfile.sub(/\.rb$/, gemfile) 51 | else "#{gemfile}.lock" 52 | end 53 | File.expand_path(lockfile) 54 | end 55 | 56 | def lockfile_version 57 | return unless File.file?(lockfile) 58 | 59 | lockfile_contents = File.read(lockfile) 60 | return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/ 61 | 62 | Regexp.last_match(1) 63 | end 64 | 65 | def bundler_requirement 66 | @bundler_requirement ||= 67 | env_var_version || 68 | cli_arg_version || 69 | bundler_requirement_for(lockfile_version) 70 | end 71 | 72 | def bundler_requirement_for(version) 73 | return "#{Gem::Requirement.default}.a" unless version 74 | 75 | bundler_gem_version = Gem::Version.new(version) 76 | 77 | bundler_gem_version.approximate_recommendation 78 | end 79 | 80 | def load_bundler! 81 | ENV['BUNDLE_GEMFILE'] ||= gemfile 82 | 83 | activate_bundler 84 | end 85 | 86 | def activate_bundler 87 | gem_error = activation_error_handling do 88 | gem 'bundler', bundler_requirement 89 | end 90 | return if gem_error.nil? 91 | 92 | require_error = activation_error_handling do 93 | require 'bundler/version' 94 | end 95 | if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION)) 96 | return 97 | end 98 | 99 | warn "Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`" 100 | exit 42 101 | end 102 | 103 | def activation_error_handling 104 | yield 105 | nil 106 | rescue StandardError, LoadError => e 107 | e 108 | end 109 | end 110 | 111 | m.load_bundler! 112 | 113 | load Gem.bin_path('bundler', 'bundle') if m.invoked_as_script? 114 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Example of Rails, Sidekiq and Puma metrics exported to Prometheus + Grafana 2 | 3 | This example illustrates how to use [yabeda] gem suite with rails application to draw graphs for app metrics. 4 | 5 | ## Prerequisites 6 | 7 | Recent versions of Docker and Docker Compose installed. 8 | 9 | ## Usage 10 | 11 | - Execute `docker-compose up` to start. 12 | - Go to rails application at http://localhost:5000 13 | - Hit the button and refresh page few times 14 | - Go to Grafana Web UI at [localhost](http://localhost:3000/d/000000001/yabeda-metrics-for-rails-sidekiq-and-puma?refresh=5s) (user: `admin`/`admin`) 15 | - Look for graphs 16 | - After starting up docker-compose will run `rails-stressor` service to simulate huge load for the rails app. By default will do the request for 2 minutes. 17 | Settings could be changed in `docker-compose.yml` config (command parameter of the `rails_stressor` service). 18 | 19 | You also could run rails stressor again by executing `docker-compose up rails_stressor` command. 20 | 21 | ## Notes 22 | 23 | - Sample [Rails] application is equipped with [yabeda-rails], [yabeda-sidekiq], [yabeda-puma-plugin], and [yabeda-prometheus] gems and properly configured. 24 | - Raw rails metrics are exposed at http://localhost:5000/metrics 25 | - Raw sidekiq metrics are exposed at http://localhost:5100/metrics 26 | - Raw puma metrics are exposed at http://localhost:5100/metrics 27 | - The [Prometheus] Web UI runs at http://localhost:9090 28 | - The [Grafana] Web UI runs at http://localhost:3000 , user: `admin`/`admin`. 29 | - The [Sidekiq] Web UI is available at http://localhost:5000/sidekiq 30 | 31 | ## Possible errors and their solutions 32 | 33 | ### Permission denied error / My grafana container is not running (Stopping after boot) 34 | 35 | If your grafana's container is not running correctly after you run `docker-compose up` you're probably getting this error, if you check at `docker ps -a` you'll see your grana container with the status `Exited`, picks the id of this container and run `docker logs YOUR_GRAFANA_CONTAINER_ID` and check if the errors is equal to the following: 36 | 37 | ``` 38 | GF_PATHS_DATA='/var/lib/grafana' is not writable. 39 | You may have issues with file permissions, more information here: http://docs.grafana.org/installation/docker/#migration-from-a-previou 40 | s-version-of-the-docker-container-to-5-1-or-later 41 | mkdir: cannot create directory '/var/lib/grafana/plugins': Permission denied 42 | ``` 43 | 44 | #### Solution 45 | 46 | Replace at your `docker-compose.yml` line 38 by your user's `id` that you will get on the following command: 47 | 48 | ```sh 49 | id -u 50 | ``` 51 | 52 | ## Acknowledgement 53 | 54 | The configurations are based off the following articles and repositories: 55 | - https://finestructure.co/blog/2016/5/16/monitoring-with-prometheus-grafana-docker-part-1 56 | - https://github.com/NikolajLeischner/local-prometheus-grafana 57 | - https://www.digitalocean.com/community/tutorials/how-to-add-a-prometheus-dashboard-to-grafana 58 | 59 | ## License 60 | 61 | This example is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). 62 | 63 | [yabeda]: https://github.com/yabeda-rb/yabeda 64 | [yabeda-rails]: https://github.com/yabeda-rb/yabeda-rails 65 | [yabeda-sidekiq]: https://github.com/yabeda-rb/yabeda-sidekiq 66 | [yabeda-puma-plugin]: https://github.com/yabeda-rb/yabeda-puma-plugin 67 | [yabeda-prometheus]: https://github.com/yabeda-rb/yabeda-prometheus 68 | [Rails]: https://rubyonrails.org "Ruby on Rails MVC web-application framework optimized for programmer happiness" 69 | [Sidekiq]: https://github.com/mperham/sidekiq/ "Simple, efficient background processing for Ruby" 70 | [Prometheus]: https://prometheus.io/ "Open-source monitoring solution" 71 | [Grafana]: https://grafana.com/ 72 | -------------------------------------------------------------------------------- /rails_app/config/environments/production.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'active_support/core_ext/integer/time' 4 | 5 | Rails.application.configure do 6 | # Settings specified here will take precedence over those in config/application.rb. 7 | 8 | # Code is not reloaded between requests. 9 | config.cache_classes = true 10 | 11 | # Eager load code on boot. This eager loads most of Rails and 12 | # your application in memory, allowing both threaded web servers 13 | # and those relying on copy on write to perform better. 14 | # Rake tasks automatically ignore this option for performance. 15 | config.eager_load = true 16 | 17 | # Full error reports are disabled and caching is turned on. 18 | config.consider_all_requests_local = false 19 | config.action_controller.perform_caching = true 20 | 21 | # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] 22 | # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). 23 | # config.require_master_key = true 24 | 25 | # Disable serving static files from the `/public` folder by default since 26 | # Apache or NGINX already handles this. 27 | config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present? 28 | 29 | # Compress CSS using a preprocessor. 30 | # config.assets.css_compressor = :sass 31 | 32 | # Do not fallback to assets pipeline if a precompiled asset is missed. 33 | config.assets.compile = false 34 | 35 | # Enable serving of images, stylesheets, and JavaScripts from an asset server. 36 | # config.asset_host = "http://assets.example.com" 37 | 38 | # Specifies the header that your server uses for sending files. 39 | # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache 40 | # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX 41 | 42 | # Store uploaded files on the local file system (see config/storage.yml for options). 43 | config.active_storage.service = :local 44 | 45 | # Mount Action Cable outside main process or domain. 46 | # config.action_cable.mount_path = nil 47 | # config.action_cable.url = "wss://example.com/cable" 48 | # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] 49 | 50 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 51 | # config.force_ssl = true 52 | 53 | # Include generic and useful information about system operation, but avoid logging too much 54 | # information to avoid inadvertent exposure of personally identifiable information (PII). 55 | config.log_level = :info 56 | 57 | # Prepend all log lines with the following tags. 58 | config.log_tags = [:request_id] 59 | 60 | # Use a different cache store in production. 61 | # config.cache_store = :mem_cache_store 62 | 63 | # Use a real queuing backend for Active Job (and separate queues per environment). 64 | # config.active_job.queue_adapter = :resque 65 | # config.active_job.queue_name_prefix = "rails_app_production" 66 | 67 | config.action_mailer.perform_caching = false 68 | 69 | # Ignore bad email addresses and do not raise email delivery errors. 70 | # Set this to true and configure the email server for immediate delivery to raise delivery errors. 71 | # config.action_mailer.raise_delivery_errors = false 72 | 73 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 74 | # the I18n.default_locale when a translation cannot be found). 75 | config.i18n.fallbacks = true 76 | 77 | # Don't log any deprecations. 78 | config.active_support.report_deprecations = false 79 | 80 | # Use default logging formatter so that PID and timestamp are not suppressed. 81 | config.log_formatter = ::Logger::Formatter.new 82 | 83 | # Use a different logger for distributed setups. 84 | # require "syslog/logger" 85 | # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") 86 | 87 | if ENV['RAILS_LOG_TO_STDOUT'].present? 88 | logger = ActiveSupport::Logger.new($stdout) 89 | logger.formatter = config.log_formatter 90 | config.logger = ActiveSupport::TaggedLogging.new(logger) 91 | end 92 | 93 | # Do not dump schema after migrations. 94 | config.active_record.dump_schema_after_migration = false 95 | end 96 | -------------------------------------------------------------------------------- /rails_app/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | actioncable (7.0.7) 5 | actionpack (= 7.0.7) 6 | activesupport (= 7.0.7) 7 | nio4r (~> 2.0) 8 | websocket-driver (>= 0.6.1) 9 | actionmailbox (7.0.7) 10 | actionpack (= 7.0.7) 11 | activejob (= 7.0.7) 12 | activerecord (= 7.0.7) 13 | activestorage (= 7.0.7) 14 | activesupport (= 7.0.7) 15 | mail (>= 2.7.1) 16 | net-imap 17 | net-pop 18 | net-smtp 19 | actionmailer (7.0.7) 20 | actionpack (= 7.0.7) 21 | actionview (= 7.0.7) 22 | activejob (= 7.0.7) 23 | activesupport (= 7.0.7) 24 | mail (~> 2.5, >= 2.5.4) 25 | net-imap 26 | net-pop 27 | net-smtp 28 | rails-dom-testing (~> 2.0) 29 | actionpack (7.0.7) 30 | actionview (= 7.0.7) 31 | activesupport (= 7.0.7) 32 | rack (~> 2.0, >= 2.2.4) 33 | rack-test (>= 0.6.3) 34 | rails-dom-testing (~> 2.0) 35 | rails-html-sanitizer (~> 1.0, >= 1.2.0) 36 | actiontext (7.0.7) 37 | actionpack (= 7.0.7) 38 | activerecord (= 7.0.7) 39 | activestorage (= 7.0.7) 40 | activesupport (= 7.0.7) 41 | globalid (>= 0.6.0) 42 | nokogiri (>= 1.8.5) 43 | actionview (7.0.7) 44 | activesupport (= 7.0.7) 45 | builder (~> 3.1) 46 | erubi (~> 1.4) 47 | rails-dom-testing (~> 2.0) 48 | rails-html-sanitizer (~> 1.1, >= 1.2.0) 49 | activejob (7.0.7) 50 | activesupport (= 7.0.7) 51 | globalid (>= 0.3.6) 52 | activemodel (7.0.7) 53 | activesupport (= 7.0.7) 54 | activerecord (7.0.7) 55 | activemodel (= 7.0.7) 56 | activesupport (= 7.0.7) 57 | activestorage (7.0.7) 58 | actionpack (= 7.0.7) 59 | activejob (= 7.0.7) 60 | activerecord (= 7.0.7) 61 | activesupport (= 7.0.7) 62 | marcel (~> 1.0) 63 | mini_mime (>= 1.1.0) 64 | activesupport (7.0.7) 65 | concurrent-ruby (~> 1.0, >= 1.0.2) 66 | i18n (>= 1.6, < 2) 67 | minitest (>= 5.1) 68 | tzinfo (~> 2.0) 69 | anyway_config (2.5.1) 70 | ruby-next-core (>= 0.14.0) 71 | bindex (0.8.1) 72 | bootsnap (1.16.0) 73 | msgpack (~> 1.2) 74 | builder (3.2.4) 75 | concurrent-ruby (1.2.2) 76 | connection_pool (2.4.1) 77 | crass (1.0.6) 78 | date (3.3.3) 79 | debug (1.8.0) 80 | irb (>= 1.5.0) 81 | reline (>= 0.3.1) 82 | dry-initializer (3.1.1) 83 | erubi (1.12.0) 84 | globalid (1.1.0) 85 | activesupport (>= 5.0) 86 | i18n (1.14.1) 87 | concurrent-ruby (~> 1.0) 88 | io-console (0.6.0) 89 | irb (1.7.4) 90 | reline (>= 0.3.6) 91 | jbuilder (2.11.5) 92 | actionview (>= 5.0.0) 93 | activesupport (>= 5.0.0) 94 | json (2.6.3) 95 | loofah (2.21.3) 96 | crass (~> 1.0.2) 97 | nokogiri (>= 1.12.0) 98 | mail (2.8.1) 99 | mini_mime (>= 0.1.1) 100 | net-imap 101 | net-pop 102 | net-smtp 103 | marcel (1.0.2) 104 | method_source (1.0.0) 105 | mini_mime (1.1.5) 106 | minitest (5.19.0) 107 | msgpack (1.7.2) 108 | net-imap (0.3.7) 109 | date 110 | net-protocol 111 | net-pop (0.1.2) 112 | net-protocol 113 | net-protocol (0.2.1) 114 | timeout 115 | net-smtp (0.3.3) 116 | net-protocol 117 | nio4r (2.5.9) 118 | nokogiri (1.15.4-aarch64-linux) 119 | racc (~> 1.4) 120 | nokogiri (1.15.4-arm64-darwin) 121 | racc (~> 1.4) 122 | nokogiri (1.15.4-x86_64-linux) 123 | racc (~> 1.4) 124 | prometheus-client (4.2.1) 125 | puma (5.6.7) 126 | nio4r (~> 2.0) 127 | racc (1.7.1) 128 | rack (2.2.8) 129 | rack-test (2.1.0) 130 | rack (>= 1.3) 131 | rails (7.0.7) 132 | actioncable (= 7.0.7) 133 | actionmailbox (= 7.0.7) 134 | actionmailer (= 7.0.7) 135 | actionpack (= 7.0.7) 136 | actiontext (= 7.0.7) 137 | actionview (= 7.0.7) 138 | activejob (= 7.0.7) 139 | activemodel (= 7.0.7) 140 | activerecord (= 7.0.7) 141 | activestorage (= 7.0.7) 142 | activesupport (= 7.0.7) 143 | bundler (>= 1.15.0) 144 | railties (= 7.0.7) 145 | rails-dom-testing (2.2.0) 146 | activesupport (>= 5.0.0) 147 | minitest 148 | nokogiri (>= 1.6) 149 | rails-html-sanitizer (1.6.0) 150 | loofah (~> 2.21) 151 | nokogiri (~> 1.14) 152 | railties (7.0.7) 153 | actionpack (= 7.0.7) 154 | activesupport (= 7.0.7) 155 | method_source 156 | rake (>= 12.2) 157 | thor (~> 1.0) 158 | zeitwerk (~> 2.5) 159 | rake (13.0.6) 160 | redis-client (0.16.0) 161 | connection_pool 162 | reline (0.3.8) 163 | io-console (~> 0.5) 164 | ruby-next-core (0.15.3) 165 | sidekiq (7.1.2) 166 | concurrent-ruby (< 2) 167 | connection_pool (>= 2.3.0) 168 | rack (>= 2.2.4) 169 | redis-client (>= 0.14.0) 170 | sprockets (4.2.0) 171 | concurrent-ruby (~> 1.0) 172 | rack (>= 2.2.4, < 4) 173 | sprockets-rails (3.4.2) 174 | actionpack (>= 5.2) 175 | activesupport (>= 5.2) 176 | sprockets (>= 3.0.0) 177 | sqlite3 (1.6.3-aarch64-linux) 178 | sqlite3 (1.6.3-arm64-darwin) 179 | sqlite3 (1.6.3-x86_64-linux) 180 | thor (1.2.2) 181 | timeout (0.4.0) 182 | tzinfo (2.0.6) 183 | concurrent-ruby (~> 1.0) 184 | web-console (4.2.0) 185 | actionview (>= 6.0.0) 186 | activemodel (>= 6.0.0) 187 | bindex (>= 0.4.0) 188 | railties (>= 6.0.0) 189 | webrick (1.8.1) 190 | websocket-driver (0.7.6) 191 | websocket-extensions (>= 0.1.0) 192 | websocket-extensions (0.1.5) 193 | yabeda (0.12.0) 194 | anyway_config (>= 1.0, < 3) 195 | concurrent-ruby 196 | dry-initializer 197 | yabeda-prometheus (0.9.0) 198 | prometheus-client (>= 3.0, < 5.0) 199 | rack 200 | yabeda (~> 0.10) 201 | yabeda-puma-plugin (0.7.1) 202 | json 203 | puma 204 | yabeda (~> 0.5) 205 | yabeda-rails (0.9.0) 206 | activesupport 207 | anyway_config (>= 1.3, < 3) 208 | railties 209 | yabeda (~> 0.8) 210 | yabeda-sidekiq (0.10.0) 211 | anyway_config (>= 1.3, < 3) 212 | sidekiq 213 | yabeda (~> 0.6) 214 | zeitwerk (2.6.11) 215 | 216 | PLATFORMS 217 | aarch64-linux 218 | arm64-darwin-22 219 | x86_64-linux 220 | 221 | DEPENDENCIES 222 | bootsnap 223 | debug 224 | jbuilder 225 | prometheus-client 226 | puma (~> 5.0) 227 | rails (~> 7.0.7) 228 | sidekiq 229 | sprockets-rails 230 | sqlite3 (~> 1.4) 231 | tzinfo-data 232 | web-console 233 | webrick 234 | yabeda-prometheus 235 | yabeda-puma-plugin 236 | yabeda-rails 237 | yabeda-sidekiq 238 | 239 | RUBY VERSION 240 | ruby 3.2.0p0 241 | 242 | BUNDLED WITH 243 | 2.4.1 244 | --------------------------------------------------------------------------------