[CentOS7.4] logrotateサービスを入れて日次でログを保存しよう

# はじめに
そういやログローテーションちゃんと設定できてるっけ？
確認してみよう！というのが始まり。

# インストール～設定まで

## インストール

基本的には``logrotate``サービスは標準で入っていることと思います。
入っていなかったら入れてください。

```bash:console
rpm -qa | grep logrotate
# logrotate-3.8.6-14.el7.x86_64

yum install -y logrotate
```

## ファイル構成

|名前・場所|やくめ|
|---|---|
|/etc/logrotate.conf|ログローテーション全体の管理ファイル|
|/etc/logrotate.d/*|ログファイル個々の設定ファイル|
|/var/lib/logrotate/logrotate/status|「最後にローテーションした日時」を管理するファイル|

## 管理ファイル編集

``logrotate``の管理ファイルはデフォルトだと``/etc/logrotate.conf``に保存されています。
ここを編集していきます。

|オプション|内容|
|---|---|
|compress / nocompress|ログファイル圧縮|
|create [（パーミッション）] [（ユーザー）] [（グループ）] / nocreate|ローテーション後、新しくファイルを作成できる<br>パーミッションなども付与することができる<br>設定しなかった場合、前のファイルの権限を継承する？|
|rotate|何世代前までログを保存するか|
|daily / weekly / monthly|<ul><li>daily -> 04:02</li><li>weekly -> 日曜日 04:22</li><li>monthly -> 毎月1日 04:42</li></ul>|
|dateext|日付型をファイル末尾に付与する|
|dateformat|末尾に付与する日付フォーマットの変更<br>デフォルト：``-%Y%m%d``|
|ifempty / notifempty|ログファイルがない場合にローテーションするかどうか|
|missingok / nomissingok|ログファイルが存在しない場合にエラー|
|olddir （ディレクトリ） / noolddir |古いログファイルをディレクトリに移行するかどうか|
|size （ファイルサイズ）|指定したサイズを上回った場合にローテーションする|
|postrotate / prerotate ~  endscript|pre -> 事前<br>post -> 事後<br>に処理するスクリプトを記述する|
|sharedscripts / nosharedscripts|（ログファイルをワイルドカードで指定した場合など）一つのサービスにつき複数個ログがある場合、スクリプトをそれぞれ実行する（``noshared``）か一回だけ実行する（``shared``）かを定義。|
|su （ユーザー） （グループ）|CentOS 7 以降[^1]<br>指定したユーザーとしてローテーションを実行する|

```ini:/etc/logrotate.conf
# see "man logrotate" for details
# ローテーションするサイクル monthly / weekly / daily
daily

# 設定された世代分のログを保管
rotate 14

# ログローテーション後に空のファイルを作成
create

# ファイルの末尾に日付を付与
dateext

# 日付フォーマットの変更
dateformat .%Y%m%d

# ログがなくても怒らない
missingok

# ログが空でもローテーション
ifempty

# ファイルを圧縮
#compress

# 個別設定ファイル保存先
include /etc/logrotate.d

# no packages own wtmp and btmp -- we'll rotate them here
/var/log/wtmp {
    monthly
    create 0664 root utmp
        minsize 1M
    rotate 1
}

/var/log/btmp {
    missingok
    monthly
    create 0600 root utmp
    rotate 1
}

# システムのログを以下に追記可能
```


## 設定ファイル編集

``/etc/logrotate.d/``配下にログごとの設定ファイルが保管してあります。
基本的にはこちらの中身をいじっていく。
任意でローテーションしたいログがある場合もこ↑こ↓に設定を記述するシステム。
それぞれのオプションについては上記の設定を参照のこと。

ここでは仮にApacheのログの中身を。
私の書き方が悪いだけだとは思うのですが、``*.log``のようにワイルドカードで指定した場合、なんかうまくローテーションしない事案が発生しました。


```ini:/etc/logrotate.d/httpd
/var/log/httpd/*log {
    daily
    ifempty
    missingok
    notifempty
    sharedscripts
    delaycompress
    postrotate
        /bin/systemctl reload httpd.service > /dev/null 2>/dev/null || true
    endscript
}
```

# 任意のログファイルをローテーションする

本題。
基本的には``/etc/logrotate.d/``配下に設定ファイルを追加するだけです。
試しに [**以前**](https://qiita.com/tosite0345/items/7e459fc06c67fa7a2c96#%E6%84%8F%E5%9B%B3%E7%9A%84%E3%81%AB%E3%82%B9%E3%83%AD%E3%83%BC%E3%82%AF%E3%82%A8%E3%83%AA%E3%82%92%E5%AE%9F%E8%A1%8C%E3%81%99%E3%82%8B) 設定したMySQLの``slow.log``をローテーションしてみます。

```ini:/etc/logrotate.d/slow
/var/log/slow.log {
    daily
    ifempty
    missingok
    notifempty
    sharedscripts
    delaycompress
    postrotate
        /bin/systemctl reload mysqld.service > /dev/null 2>/dev/null || true
    endscript
}
```

基本的にコピペしてちょこっと書き換えるだけの簡単仕様です。

## デバッグしてみる

以下のコマンドでデバッグを実行してみます。

```bash:console
logrotate -dv /etc/logrotate.conf

# reading config file /etc/logrotate.conf
# including /etc/logrotate.d
# reading config file slow
# Allocating hash table for state file, size 15360 B
#
# Handling 12 logs
# 
# rotating pattern: /var/log/slow.log
#  after 1 days (7 rotations)
# empty log files are rotated, old logs are removed
# considering log /var/log/slow.log
#   log does not need rotating (log has been rotated at 2017-12-21 17:19, that is not day ago yet)

# 実際にローテーションさせてみる
logrotate -f /etc/logrotate.conf
```

本当はもっと長いんですが。対象のファイルにエラーが発生していなければ問題ないかと。

## 日付を巻き戻してすぐに動作テストがしたい
と思っていた時期が私にもｒｙ

以下の手順で実施します。

+ ローテーション情報を書き換える
+ ローテーションを実行する

### ローテーション情報を書き換える

```ini:/var/lib/logrotate/logrotate.status
logrotate state -- version 2
"/var/log/yum.log" 2017-12-21-17:19:40
"/var/log/php-fpm/*log" 2017-12-21-1:0:0
"/var/log/boot.log" 2017-12-21-17:19:40
"/var/log/httpd/error_log" 2017-12-21-17:19:40
"/var/log/chrony/*.log" 2017-12-21-1:0:0
"/var/log/wtmp" 2017-12-21-17:19:40
"/var/log/spooler" 2017-12-21-17:19:40
"/var/log/mysql/slow.log" 2017-12-21-17:19:40
"/var/log/btmp" 2017-12-21-17:19:40
"/var/log/slow.log" 2017-12-19-17:6:27
"/var/log/maillog" 2017-12-21-17:19:40
"/var/log/wpa_supplicant.log" 2017-12-21-1:0:0
"/var/log/secure" 2017-12-21-17:19:40
"/var/log/messages" 2017-12-21-17:19:40
"/var/log/httpd/access_log" 2017-12-21-16:57:11
"/var/log/cron" 2017-12-21-17:19:40
```

これの日付を一日前に書き換えて保存。

### ローテーションを実行する

```bash:console
/etc/cron.daily/logrotate
```

ファイルサイズが空だったりするとうまくローテーションしない場合があるみたい？

# ローテーション時エラー

>error: skipping ~ because parent directory has insecure permissions (It's world writable or writable by group which is not "user") Set "su" directive in config file to tell logrotate which user/group should be used for rotation.
>
ガバガバ翻訳：
エラー：親ディレクトリに安全でないアクセス権があるのでファイル：～をスキップします。
"user"以外のグループによって書き込み可能か確認してください。
設定ファイルに "su"オプションを設定して、どのユーザー/グループでローテーションするべきかを指示してください。

とか怒られる場合があります。[^1]
ユーザーに権限がないだけなので、``su``オプションを付けて適切なユーザーに変更してあげてください。

```ini:/etc/logrotate.d/slow
/var/log/slow.log {
    daily
    ifempty
    missingok
    notifempty
    sharedscripts
    delaycompress
    postrotate
        /bin/systemctl reload mysqld.service > /dev/null 2>/dev/null || true
    endscript
    su root root
}
```


[^1]: CentOS7系から導入された。そもそもそれ以前では権限が甘いため、Permission Errorにすらならないとか。[**こちら**](http://boscono.hatenablog.com/entry/2016/01/08/222921) を参考にさせていただきました。