• DoRubyとは
  • お問い合わせ
  • Ruby/Rails
  • Web開発
  • Webマーケティング
  • アピリッツ
  • ライフハック
  • ゲーム制作/開発
  • Railsの小技
  • Rubyの小技
  • Gemの紹介
  • ActiveRecord
  • 初心者向け
  • Java/Scalaテク
  • Unixのあれこれ
  • データベース
  • スマホ開発
  • HTML/CSS/JavaScript
  • デザイン製作
  • インフラ
  • クラウド
  • セキュリティ
  • エディタ
  • バージョン管理
  • その他
  • python
  • アクセス解析
  • Googleアナリティクス
  • Googleデータスタジオ
  • Web広告
  • SEO
  • UI/UX
  • ソーシャルメディア
  • EC開発
  • Webシステム開発
  • コンサルティング
  • Webデザイン
  • ブロックチェーン
  • ゲーム紹介
  • アプリ紹介
  • ASP
  • 風景
  • パソコン
  • ツール
  • ガジェット
  • 仕事術
  • 健康
  • 生活
  • 書評
  • Excel(エクセル)
  • PowerPoint(パワーポイント)
  • ゲームプランニング
  • SpriteStudio
  • マスターデータ入力/作成
  • Unity
  • キャラクターデザイン
  • ゲームシナリオ
  • レベルデザイン
  • ゲーム分析
  • 3DCG
  • イラスト制作
  • CG/アニメーション
  1. ホーム
  2. Ruby/Rails
  3. Rubyの小技
  4. systemd でデーモン化しつつ logrotate に対応したスクリプトを書く
  • 2017-05-30
    • カテゴリ:
    • Rubyの小技
    • タグ:
    • systemd
    • logrotate
    • ruby

systemd でデーモン化しつつ logrotate に対応したスクリプトを書く

この記事は公開から1年以上が経過しています。情報が古い可能性がありますのでご注意ください。

ときどき、「rubyでちょっとしたデーモンを動かしたい」かつ、「出力されるログファイルもローテーションさせたい」ということたびたび発生します。 そんなとき、どのようにスクリプトを組むのが良いかという点についてまとめてみました。

TL;DR

ポイントは以下です。

  • ふつうにRubyのスクリプト書いて systemd でデーモン化する
  • logrotate の postscript の中で実行中のスクリプトに対してUSR1を送出する
  • スクリプト側ではUSR1シグナルを受け取ったらログファイルをreopenする

スクリプト本体

デーモンとなるスクリプト本体です。

log_file = File.expand_path("hoge.log", File.dirname(__FILE__))
pid_file = File.expand_path("hoge.pid", File.dirname(__FILE__))

# pid 作成
File.write(pid_file, Process.pid)

# logger 初期化
logger = Logger.new(log_file)
logger.level = Logger::INFO

$reopen_log = false

# USR1シグナルでログのreopenフラグを立てる
trap("USR1") do
  $reopen_log = true
end

# 終了時に pid ファイルを削除
END {
  File.delete(pid_file)
}

loop do
  # フラグ立ってたらログを reopen する
  if $reopen_log
    logger.reopen(log_file)
    $reopen_log = false
  end

  logger.info "hogehoge---"
  sleep 10
end

スクリプトのポイント

いくつかポイントとなる箇所があるので解説。

プロセスIDをファイルに出力する

理由は、logrotate の postrotate のスクリプトで kill -USR1 でプロセスに対してシグナルを送出するためです。

# pid 作成
File.write(pid_file, Process.pid)
# 終了時に pid ファイルを削除
END {
  File.delete(pid_file)
}

シグナルを受け取ってログを再オープンする

普通にログローテートすると、対象ファイルがローテーションした際、既存のファイルがリネームされて新しいファイルが作られるが、reopenしないとずっと古いファイル(リネームされた方)に出力されてしまう。
そこで、USR1(たいていUSR1が使われるらしい)のシグナルを捕捉して、シグナルを受け取ったらreopenする処理を組み込む。

# USR1シグナルでログのreopenフラグを立てる
trap("USR1") do
  $reopen_log = true
end
  # フラグ立ってたらログを reopen する
  if $reopen_log
    logger.reopen(log_file)
    $reopen_log = false
  end

ちなみに、trap()のブロック内(シグナルハンドラと呼ぶらしい)でreopenしてみましたが、Threadがなんちゃらというエラーが出て落ちてしまいました。
一般的にシグナルハンドラの中では入出力を伴う処理等を行うのはよくないらしく、フラグを立てるくらいしたほうが良いらしいです。

systemd に登録するやつ

特に解説はしません。
Systemdを使ってさくっと自作コマンドをサービス化してみる - Qiita などを参考に。

[Unit]
Description = xxxx daemon

[Service]
ExecStart = /home/xxxx/.rbenv/shims/ruby /path/to/hoge.rb
Restart = always
Type = simple
User = hoge
Group = hoge

[Install]
WantedBy = multi-user.target

このファイル名 hoge.service がサービス名(hogeと省略可能)となります。

logrotate

日毎のローテーションで、履歴を10件保持する設定です。
この設定のポイントは、postrotateのブロックに記述されたスクリプトで、kill -USR1 $(cat $pid) の部分です。
これによってローテーション完了後、スクリプトにUSR1シグナルが送出され、それによってスクリプト側ではログファイルがreopenされ、結果としてローテーション後の新しいログファイルにログが出力されるようになるという仕組みになっています。

/path/to/hoge.log {
    daily
    rotate 10
    missingok
    su hoge hoge
    create 0600 hoge hoge
    postrotate
        pid=/path/to/hoge.pid
        test -e $pid && kill -USR1 $(cat $pid) || true
    endscript
}

デーモンの起動/停止

以下のコマンドでデーモンが起動します。

$ sudo systemctl start hoge

停止は以下

$ sudo systemctl stop hoge

さいごに

こんな感じで、意外なほど簡単にRubyで気軽にデーモンが作れるのでbotとかいろいろ作ってみたらどうでしょうか。


  • 241 views
    • Tweet
    • このエントリーをはてなブックマークに追加

この記事を書いた人
nakamatsu
仕事ではRubyでサーバサイド/Node.jsでServerlessアプリケーション/AWSインフラ・DevOpsなど。 趣味で Alexa スキル作ったりしてます。 「俺のメモ」シリーズは DoRuby をメモ帳代わりに使う実験。 記事の内容についてのご連絡は 【e-mail: nakamatsu "at" appirits.com】 まで、お願いします。

「いいね!」するとDoRubyの最新記事を受け取ることができます。

Facebook

Twitterから最新記事を受け取るならこちら

Follow @doruby

Feedlyから最新記事を受け取るならこちら

follow us in feedly

おすすめの記事
  • 693 views
  • 2015-10-01
RailsのViewを自在にカスタマイズするための「Cosme」gem
  • 878 views
  • 2016-07-31
carrierwaveとfogでRiak CSへの画像アップロードを実装する

カテゴリ

Ruby/RailsRailsの小技Rubyの小技Gemの紹介ActiveRecord初心者向けWeb開発Java/ScalaテクUnixのあれこれデータベーススマホ開発HTML/CSS/JavaScriptデザイン製作インフラクラウドセキュリティエディタバージョン管理その他pythonWebマーケティングアクセス解析GoogleアナリティクスGoogleデータスタジオWeb広告SEOUI/UXソーシャルメディアアピリッツEC開発Webシステム開発コンサルティングWebデザインブロックチェーンゲーム紹介アプリ紹介ASP風景ライフハックパソコンツールガジェット仕事術健康生活書評Excel(エクセル)PowerPoint(パワーポイント)ゲーム制作/開発ゲームプランニングSpriteStudioマスターデータ入力/作成Unityキャラクターデザインゲームシナリオレベルデザインゲーム分析3DCGイラスト制作CG/アニメーション

    人気の記事
    最近の記事
    • 3,599 views
    • 2020-04-02
    Kali Linux 2020.2 導入と日本語化
    • 828 views
    • 2020-03-06
    rack-lineprofを改造して管理画面からファイル指定&ログ追跡出来るように
    • 802 views
    • 2020-03-05
    FactoryBot と Gimei を使って架空のユーザを作る
    • 584 views
    • 2020-02-04
    ActionCable実装しようwith webpack
    • 517 views
    • 2020-01-27
    この頃のプルリクに対するレビュー
    Facebook

      サイト情報
      • DoRubyとは
      • 株式会社アピリッツ

      ソーシャルアカウント
      • Facebook
      • Twitter

      企業情報
      • 会社概要
      • 採用情報
      • お問い合わせ
      サービス製品
      • レコメンドASP
      • サイト内検索ASP「Advantage Search」
      • オープンソースECサイト構築パッケージ「エレコマ」
      • 受注・在庫・商品情報一元管理「モールコネクター」
      • セキュリティ診断サービス
      • Googleアナリティクスセミナー

      Copyright © Appirits All Rights Reserved.