Madogiwa Blog

主に技術系の学習メモに使っていきます。

Ruby on Rails: OK Computerを使ってヘルスチェックを行うときの導入方法とかMEMO

OK ComputerというGemを教えてもらい、個人サービスに入れてみたところ、適当に設定すると色々見れて便利だったので導入方法とかをメモしておきます📝

github.com

導入方法

OK Computerのインストール

Gemfileに以下を追加して、bundle installします。

gem 'okcomputer'

OK Computerのmount

OK Computerでの監視結果を見るためにroutesを定義します。

以下のような形でmountします。※atには任意のパスを設定してください。

Rails.application.routes.draw do
  mount OkComputer::Engine
end

これで/helth_checkにアクセスすると以下のようにOK Computerの監視結果を見ることができます。

f:id:madogiwa0124:20210509154727p:plain

監視項目の追加

OK Computerには以下の通りbuildinで色々な監視が用意されていて自分で追加することができます。

okcomputer/lib/ok_computer/built_in_checks at master · sportngin/okcomputer · GitHub

追加方法はconfig/initilalizer内にokcomputer.rbのようなファイルを用意して、その中で追加を行います。

# okcomputer.rb
OkComputer::Registry.register 'ruby version', OkComputer::RubyVersionCheck.new

私は以下のような形で設定してみました。

# okcomputer.rb
OkComputer::Registry.register 'redis', OkComputer::RedisCheck.new({})
OkComputer::Registry.register 'ruby version', OkComputer::RubyVersionCheck.new
OkComputer::Registry.register 'cache', OkComputer::GenericCacheCheck.new
OkComputer::Registry.register 'sidekiq latency', OkComputer::SidekiqLatencyCheck.new('default')
'SOURCE_VERSION'
OkComputer::Registry.register 'version', OkComputer::AppVersionCheck.new(env: env_name)

Basic認証の追加

OK ComputerではBasic認証を設定することもできます。 監視項目によっては外部から参照されるとリスクになる可能性がある場合には以下のような形で設定しておくと良さそうです。

# Basic認証
OkComputer.require_authentication(ENV['BASIC_AUTH_USER'], ENV['BASIC_AUTH_PASSWORD'])

おまけ:OK ComputerのViewをカスタマイズする

デフォルトだとちょっと見た目が寂しいので既存のOK ComputerのControllerにモンキーパッチを当てて多少見やすくする方法をおまけで載せておきます。

まずOK ComputerはRails Engineという仕組みでアプリケーションに組み込み、監視結果を表示しているので通常のRailsと同じでContollerでrenderするテンプレートを切り替えれば任意のViewを表示できます。

Rails Engineについてはこちら

guides.rubyonrails.org

OK Computerの監視項目の表示を行ってるコントローラーは以下で、その中でもrespondrenderを行っていることがわかるので以下のような感じのコントローラーを用意して、htmlの場合は作成するviewを表示するようにオーバーライドします。

# /lib/okcomputer/app/controllers
OkComputer::OkComputerController.class_eval do
  self.view_paths = 'lib/okcomputer/app/views'

  def respond(data, status)
    respond_to do |format|
      format.text { render plain: data, status: status, content_type: 'text/plain' }
      format.html { render "/#{action_name}", locals: { data: data, status: status }, content_type: 'text/html' }
      format.json { render json: data, status: status }
    end
  end
end

そしてアクションに合わせて以下のようなviewを作成し適当にスタイルを当ててあげます。※html5.2からはbody内の任意の箇所でstyleが記載できるようになったようです。

<!-- lib/okcomputer/app/views/index.html.erb -->
<h1>OkComputer ALL</h1>

<% status_class_name = data.collection.values.any?(&:failure_occurred) ? 'faild' : 'passed' %>
<% checks = data.collection.values %>

<h2 class="status">STATUS: <span class="<%= class_name %>"><%= status %></span></h2>
<table>
  <thead>
    <tr>
      <th>NAME</th>
      <th>PASS/FAIL</th>
      <th>MESSAGE</th>
      <th>TIME</th>
    </tr>
  </thead>
  <tbody>
    <% checks.each do |check| %>
      <% passfail = check.success? ? "passed" : "failed" %>
      <tr class="<%= passfail %>">
        <td class="registrant_name"><%= check.registrant_name %></td>
        <td class="passfail"><%= passfail.upcase %></td>
        <td class="message"><%= check.message %></td>
        <td class="time"><%= check.time ? sprintf('%.3f', check.time) : '?' %></td>
      </tr>
    <% end %>
  </tbody>
</table>
<!-- lib/okcomputer/app/views/show.html.erb -->
<h1><%= "OkComputer #{data.registrant_name}" %></h1>

<% status_class_name = data.failure_occurred ? 'faild' : 'passed' %>
<% checks = [data] %>

<h2 class="status">STATUS: <span class="<%= class_name %>"><%= status %></span></h2>
<table>
  <thead>
    <tr>
      <th>NAME</th>
      <th>PASS/FAIL</th>
      <th>MESSAGE</th>
      <th>TIME</th>
    </tr>
  </thead>
  <tbody>
    <% checks.each do |check| %>
      <% passfail = check.success? ? "passed" : "failed" %>
      <tr class="<%= passfail %>">
        <td class="registrant_name"><%= check.registrant_name %></td>
        <td class="passfail"><%= passfail.upcase %></td>
        <td class="message"><%= check.message %></td>
        <td class="time"><%= check.time ? sprintf('%.3f', check.time) : '?' %></td>
      </tr>
    <% end %>
  </tbody>
</table>

モンキーパッチはファイルパスとnamespaceを合わせるのが難しく、auto loadの対象になるとエラーになるので対象にならないように無効化しときます。

# NOTE: zeitwerkの期待するファイルパスとnamespaceを含めたclass名を一致させることが厳しいので、
# okcomputerへのmonkey patchを入れているapp配下はautoloadの対象外にする
Rails.autoloaders.main.ignore("#{Rails.root}/lib/okcomputer/app")

最後にapplication.rbで以下のように作成したControllerをloadするようにしてあげると、

    # Rails engineで導入されているokcomputerのcontrollerのオーバーライド
    # https://edgeguides.rubyonrails.org/engines.html#overriding-models-and-controllers
    config.to_prepare do
      load "#{Rails.root}/lib/okcomputer/app/controllers/ok_computer_controller.rb"
    end

ちょっと見やすくできました✨

f:id:madogiwa0124:20210509160913p:plain

参考

qiita.com

html5.2ではstyle要素をbody内に書けるようになりました - webのあれこれ

t.co