u16suzuの blog

日々学んだことのメモブログです。

Rubyで別ファイルにログを出力する

Railsで開発をしていると、たくさんSQLを実行しているサーバだと development.log の出力が多すぎて追うのが大変になります。

こういう時、別ファイルに出力させたいのですが、以下のように行えばOKです。

また、log/ 以下は gitignore されていることがほとんどだと思うので、log以下にファイルを置くと良いです。

Logger.new('log/out.log').info( "ログ出力したい文言" )

出力例は以下のようになります。 

I, [2019-01-15T18:59:25.132692 #6825]  INFO -- : ログ出力したい文言

Rails外の場合だと、require が必要です。

require "logger"

Logger.new('out.log').info( "ログ出力したい文言" )

size,count,empty? のパフォーマンスを確認する

size,count,empty? のパフォーマンスを確認をしてみる。

require "benchmark"

count = 1000_000

ar = [1, 2, 3, 4, 5]

Benchmark.bm(10) do |x| # 10はラベルの為に確保する長さ
  x.report("size") do
    count.times do
      ar.empty?
    end
  end

  x.report("count") do
    count.times do
      ar.count == 0
    end
  end

  x.report("length") do
    count.times do
      ar.length == 0
    end
  end
end
  • 実行結果
                 user     system      total        real
size         0.040000   0.000000   0.040000 (  0.048787)
count        0.060000   0.000000   0.060000 (  0.058087)
length       0.040000   0.000000   0.040000 (  0.045684)
  • 1回あたりの実行時間を nano sec に直してみる。
size 48.787[nano sec]
count 58.087[nano sec]
length 45.684[nano sec]

参考資料のNumbers Everyone Should Know - High Scalability -によると、Send 2K bytes over 1 Gbps network 20,000 ns

すなわち、2K bytes のデータを 1Gbpsのネットワークで送信した場合 20[micro sec] かかるということなので、

普通の web application を作っているのならば、これらのメソッドの速度の違いはあまり気にする必要はなさそうだ。

また、Railsのアプリケーションログを見てみると、ざっくりこんな感じで1リクエスト毎にms単位の時間がかかっている。

I, [2019-01-10T12:30:21.152318 #21603]  INFO -- : [2236aa74-e13c-475e-a42c-5a87dc7fba51] Completed 200 OK in 143ms (Views: 0.4ms | ActiveRecord: 12.7ms)

これと比較したらメソッド毎の nano sec 単位の実行速度の違いなど誤差の範囲である。

参考資料

gem のコードを git clone して RubyMine で開くスクリプト

以下を /usr/local/bin に置いて、 chmod a+x clone_and_open.rb しておく。

clone_and_open.rb https://github.com/u16suzu/foo すると ~/src にダウンロードされる。

clone_and_open.rb

#!/usr/bin/env ruby

class CodeReader
  # clone and open
  #
  # git repository を ~/src に clone して RubyMine で開くコマンド
  def clone_and_open(uri=ARGV[0])
    dir_name = uri.split("/")[-2]
    repo_name= uri.split("/")[-1]

    system "mkdir -p ~/src/#{dir_name}"

    # password入力を避けるために ssh 形式で clone する
    system "git clone git@github.com:#{dir_name}/#{repo_name}.git ~/src/#{dir_name}/#{repo_name}"

    system "mine ~/src/#{dir_name}/#{repo_name}"
  end
end

CodeReader.new.clone_and_open

2018年12月にリリースされたRubyGems, BundlerのRubyの対応バージョンのメモ

2018年12月にリリースされた RubyGems v3系, Bundler v2系にてRubyの対応バージョンが2.3以上必須となった。

早速この影響でTravisCIが落ちるなどしたのでシュッと対応しておいた。

RubyGems v3系 (3.0.0)

Bundler v2系 (2.0.0)

gemのソースを pry-byebug を使ってブレークポイントで止めて読む準備

いつも仕事でもプライベートでも使っている bundler だけど、中身のコードを把握していないのでどうも雰囲気で使っている感が否めない。

そこで、ソースを読み腹落ち感を得るためにコードを読む準備を進めてみた。

pry-byebug を使ってブレークポイントで止められるようにする

(1). システムに pry-byebugを入れる

毎回 Gemfile 書くのは面倒なのでシステムに入れちゃう

gem install pry-byebug
gem install pry-stack_explorer # 超便利なのでこれも

(2). require "pry" して、止めたいところで binding.pryすれば止まる

require "pry"

ar = [1,2,3]

ar.each do |i|
  binding.pry # ここで止まる
  p i
end

便利。

bundlerのコードで試してみる

(1). ソースを git cloneする

$ git clone git@github.com:bundler/bundler.git ~/src

/vendor/bundle に入ったコードだと git blame できなくて普通に読みづらいので、git clone したり gem-src を使うなりして git repository を取得した方が良い。

(2). CUI ツールのエントリポイントであるbundler/exe/bundle でまずは require "pry"する

#!/usr/bin/env ruby
# frozen_string_literal: true

require 'pry'
(略

(3). 実行して止まるか確認

./bundler で実行すればシステムに入っている方ではなく git clone した方の bundler が実行できる。

$ cd /Users/suzuki_y/src/bundler/exe/
suzuki_y@MBP:~/s/b/exe$ ./bundle install                             

From: /Users/suzuki_y/src/bundler/exe/bundle @ line 30 :

    25:   require "bundler/cli"
    26:
    27:   binding.pry
    28:
    29:   # Allow any command to use --help flag to show help for that command
 => 30:   help_flags = %w[--help -h]
    31:   help_flag_used = ARGV.any? {|a| help_flags.include? a }
    32:   args = help_flag_used ? Bundler::CLI.reformatted_help_args(ARGV) : ARGV
    33:
    34:   Bundler::CLI.start(args, :debug => true)
    35: end

[1] pry(main)>

無事止まりました。

show-stackでコールスタックもみれます。

[1] pry(main)> show-stack

Showing all accessible frames in stack (9 in total):
--
=> #0  <main>
   #1 [block]   block in run <Byebug::PryProcessor#run(&_block)>
   #2 [method]  run <Byebug::PryProcessor#run(&_block)>
   #3 [method]  resume_pry <Byebug::PryProcessor#resume_pry()>
   #4 [method]  at_line <Byebug::PryProcessor#at_line()>
   #5 [method]  at_line <Byebug::Context#at_line()>
   #6 [block]   block in <main>
   #7 [method]  with_friendly_errors <Bundler.with_friendly_errors()>
   #8 [main]    <main>

あとは、コードを好きにいじりながら自由にコード読み放題です。

メソッド系のgemの場合

また、 bundlerのようなコマンド系の gem ではなく、tapp gem のようにコード内で使用するメソッド系の gem は、

gemのルートディレクトリに main.rb みたいな適当なファイルを作って、そこから対象のgemを require して呼び出しを行ってとっかかりを作ります。

# src/tapp/main.rb
require "./lib/tapp"
require "pry"

binding.pry

"123".tapp
"123".taputs
From: /Users/suzuki_y/src/tapp/main.rb @ line 6 :

    1: require "./lib/tapp"
    2: require "pry"
    3:
    4: binding.pry
    5:
 => 6: "123".tapp
    7: "123".taputs

[1] pry(main)> step

From: /Users/suzuki_y/src/tapp/lib/tapp.rb @ line 13 Tapp.config:

    12: def config
 => 13:   @config ||= Tapp::Configuration.new
    14: end

[1] pry(Tapp):1>

いい感じですね。

RubyMineを使ったやり方もあとで追記したいと思います。

rails console から任意のメソッドのソースコードをRubyMineで開く

設定

.pryrcに以下を追記する。RubyMineのCUIコマンドがない場合は Tools > Create Command-line Launcher... で作っておく。

Pry.config.editor = proc { |file, line| "/usr/local/bin/mine --line #{line} #{file}" }

Pry.commands.alias_command 'mine', 'edit'
Pry.commands.alias_command 'mi', 'edit'

実行例

以下のコマンドを実行すると、RubyMine で User.first.label を定義している部分のコードが開かれる。

pry(main)> mine User.first.label

こちらももちろん呼び出し可能。

pry(main) mine User.first.label=

Rails などの gem のコードも同様に開ける。

pry(main)> mine Rails.cache.read

開かれたコード。dalli_store.rb の 115行目あたり。

      def read(name, options=nil)
        options ||= {}
        name = expanded_key name

        instrument(:read, name, options) do |payload|
          entry = read_entry(name, options)
          payload[:hit] = !!entry if payload
          entry
        end
      end

自分の小さな「箱」から脱出する方法を読んだ

自分の中で一方的に師と仰いでいる元KLab CTO 仙石さんの投稿をきっかけにして、 以前購入し積読してあった本を読んだ。 とても良い本だった。

自分の小さな「箱」から脱出する方法

自分の小さな「箱」から脱出する方法

  • 作者: アービンジャーインスティチュート,金森重樹,冨永星
  • 出版社/メーカー: 大和書房
  • 発売日: 2006/10/19
  • メディア: 単行本(ソフトカバー)
  • 購入: 156人 クリック: 3,495回
  • この商品を含むブログ (418件) を見る

本書の概要

自分が本来相手のためにすべきだと思ったことをしないことを、心理学の世界では「自己欺瞞」という。 これを本書ではシンプルに「箱に入る」とか自分への裏切りと呼ぶ。

一度この自己欺瞞が始まると、そこから...

1. 他人の欠点を大げさにあげつらう
2. 自分の長所を過大に評価する
3. 自己欺瞞を正当化する。ものの価値を過大に評価する
4. 相手に非があると考える

というような流れで悪化していき、物事を見る目が曇ってしまい、しまいには他人との信頼関係が壊れてしまう。 本書では、これを防ぐには自分が箱の中に入っているかどうかを意識して、 なんとか箱の中から脱出することで、解決を目指しましょうということを述べている。 もちろん、つねに箱から出ているのが理想ではあるけれども、 そうもいかないので、たまには箱に入ることもある。 でも、箱に入っている状態を意識するというのは大事だと思う。

正直、過去現在に自分が周りで観測した人間関係のこじれはこの流れに沿っている。 もちろん自分が当事者になった時もあるし、そうじゃない時もある。 本書では、そのような過去の事柄についても、ことあるごとにその時どうすればベストだったか? を振り返って考えることを勧めている。

最後に

最後に本の最終ページに書いてあったリストを引用しておく。

知っておくべきこと

  • 自分への裏切りは、自己欺瞞へ、さらには箱へとつながっていく。
  • 箱の中にいると、業績向上に気持ちを集中することができなくなる。
  • 自分が人にどのような影響を及ぼすか、成功できるかどうかは、全てはこの外に出ているか否かにかかっている。
  • 他の人々に抵抗するのをやめた時、箱の外に出ることができる。

知ったことに即して生きること

  • 完璧であろうと思うな。より良くなろうと思え。
  • すでにそのことを知っている人以外には、箱などの言葉を使うな。自分自身の生活に、この原則を活かせ。
  • 他の人々の箱を見つけようとするのではなく、自分の箱を探せ。
  • 箱の中に入っているといって他人を責めるな。自分自身が箱の外に留まるようにしろ。
  • 自分が箱の中にいることがわかっても、あきらめるな。努力を続けろ。
  • 自分が箱の中にいた場合、箱の中にいたということを否定するな。謝った上で、さらに前へ進め。これから先、もっと他の人の役に立つよう努力しろ。
  • 他の人が間違ったことをしているという点に注目するのではなく、どのような正しいことをすればその人に手を貸せるかを、よく考えろ。
  • 他の人が手を貸してくれるかどうかを気にやむのはやめろ。自分が他の人に手を貸せているかどうかに気をつけろ。