Log Rotationは、アーカイブ、圧縮、古いレコードの削除によってディスクオーバーフローを防ぐ自動ログファイル管理メカニズムです。モバイルアプリケーションでは、ログはユーザーのデバイスに蓄積され、ローテーションがないと使用開始から数週間でギガバイトのメモリを占有する可能性があります。Redisドキュメントによると、log rotationの適切な設定により、制御不能なログ増加と比較して、ディスク満杯によるシステム障害のリスクを99%削減できます。主なローテーション戦略は、ファイルサイズ基準、時間基準、ファイル数基準の3つで、それぞれ使用シナリオに応じて選択されます。Linuxのlogrotate、iOSのCocoaLumberjack、AndroidのTimberはすべて3つのアプローチをサポートしています。
重要ポイント
Log Rotationは、アクティブログファイルを定期的に新しいファイルに切り替え、古いファイルをアーカイブ、圧縮、または削除するプロセスです。ローテーションがないと、単一のログファイルが無制限に成長し、ディスクパーティション全体を埋め尽くし、アプリケーションの障害とデータ損失を引き起こします。
典型的なシナリオ:アプリケーションはapp.logファイルにログを書き込みます。app.logが100 MBに達すると、システムはそれをapp.log.1に名前変更し、app.log.1.gzに圧縮して、新しい空のapp.logを作成します。次の満杯時に、app.log.1はapp.log.2に、app.log.1.gzはapp.log.2.gzになり、古いapp.log.2.gzは削除されます。このメカニズムはキープカウント付きローテーションと呼ばれ、アーカイブコピーの数は固定されています。
Splunk(2023年)によると、誤ったローテーション設定はアプリケーションサーバーでのディスク容量枯渇に関連するインシデントの40%の原因です。モバイルデバイスでは、ユーザーが手動でログを管理できないため、ローテーションはさらに重要です。
Log Rotationは、組み合わせ可能な3つの基本戦略をサポートしています。戦略の選択はアプリケーションの種類によって異なります。サーバーシステムは時間ベースのローテーションを、モバイルはサイズベースを、組み込みシステムはファイル数ベースをよく使用します。
| 戦略 | トリガー | 使用するケース |
|---|---|---|
| サイズ基準 | ファイルがNバイトに到達 | 予測不能なログ量の高負荷システム |
| 時間基準 | N時間/日が経過 | 日次ダンプ、コンプライアンス要件 |
| ファイル数基準 | Nファイル作成 | ディスク容量が限られたモバイルデバイス |
サイズベースのローテーションは、どのログファイルも設定された制限を超えないことを保証します。制限は、利用可能なディスク容量とロギング頻度に基づいて選択されます。サーバーの場合、一般的な制限はファイルあたり100~500 MB、モバイルデバイスの場合は1~10 MBです。アプリケーションが積極的にログを記録する場合は、制限を下げる必要があります。そうしないと、ローテーションが数分ごとに発生します。
時間ベースのローテーションはログ量に依存せず、ファイルはスケジュールに従って厳密に切り替えられます。ログを固定日数保存する必要があるシステムに便利です。キープカウント=30の日次ローテーションは30日間の保存を意味します。欠点は、高負荷時に1つのファイルが1日でギガバイトまで成長する可能性があることです。
logrotateは、自動ログローテーションのための標準Linuxユーティリティです。cronを介して実行され、/etc/logrotate.d/の設定ファイルを処理します。各サービス(nginx、postgresql、アプリケーション)は、ログパス、ローテーション戦略、ローテーション後のアクションを指定して独自の設定を作成します。
# /etc/logrotate.d/myapp — アプリケーションのログローテーション
/var/log/myapp/*.log {
daily
rotate 7
compress
delaycompress
missingok
notifempty
create 0640 www-data www-data
postrotate
kill -HUP $(cat /var/run/myapp.pid)
endscript
}
この設定は、ログを日次でローテーションし、7つのアーカイブコピーを保持し、古いファイルをgzipで圧縮し(最後のファイルを除く — delaycompress)、ログがない場合エラーにせず(missingok)、空のファイルをローテーションせず(notifempty)、0640権限でファイルを再作成します。ローテーション後、postrotateスクリプトを介してアプリケーションプロセスにHUPシグナルを送信します。
size — サイズ到達時のローテーション(size 100M)。rotate — アーカイブコピーの数(rotate 7)。compress — gzip圧縮。dateext — シーケンス番号の代わりにファイル名に日付を追加。sharedscripts — 各ファイル個別ではなく全ファイルに対してpostrotateを1回実行。maxage — N日より古いアーカイブを削除。
モバイルデバイスでは、ユーザーがファイルシステムを管理せず、アプリケーションがログでギガバイトを占有することを想定していないため、Log Rotationは重要です。iOSとAndroidには組み込みのメカニズムがあります。iOSのos_logは固定サイズのリングバッファ(上書きによるローテーション)を使用し、Android Logcatはカーネルに制限付きバッファを持っています。
iOSのカスタムファイルログには、サイズベースと時間ベースのローテーションをサポートするDDFileLoggerクラスを使用したCocoaLumberjackが使用されます。Androidでは、LogbackまたはRollingFileAppenderを介したカスタム実装が使用されます。どちらのツールも、最大ファイルサイズとアーカイブ数を設定できます。
// CocoaLumberjack — iOSのファイルローテーション
import CocoaLumberjack
let fileLogger = DDFileLogger()
fileLogger.maximumFileSize = 1024 * 1024 // 1 MB
fileLogger.logFileManager.maximumNumberOfLogFiles = 5
DDLog.add(fileLogger)
iOS:os_logはローテーションを必要としません — メッセージはリングバッファで上書きされます。ただし、アプリケーションがカスタムファイルログ(デバッグやサーバー送信用)を書き込む場合は、ローテーションを手動で設定する必要があります。CocoaLumberjackはiOSチームの標準的な選択肢であり、アーカイブを自動的に.gzに圧縮し、制限を超えた古いファイルを削除します。
Androidは、アプリケーションが自身のディレクトリにログを書き込むことを制限しません。開発者がローテーションなしでファイルにデバッグログを書き込むと、アクティブな使用から1か月で500 MBから1 GBを占有する可能性があります。ユーザーはシステムがストレージ不足の警告を表示したときに問題を発見し、アプリケーションを削除します。RollingFileAppenderを使用したLogbackはこの問題を解決します。3つのアーカイブで5 MBの制限を設定すれば、ログが20 MBを超えることは決してありません。
以下に、両プラットフォームでのログローテーション設定の例を示します。iOSではCocoaLumberjack、AndroidではXML設定を使用したLogbackが使用されます。
// AndroidのLogback — logback.xmlでのローテーション設定
// ファイルサイズ5MB、3つのアーカイブコピー
@file:Suppress("unused")
// logback.xml内:
// <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
// <file>${DATA_DIR}/logs/app.log</file>
// <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
// <fileNamePattern>app.%i.log.gz</fileNamePattern>
// <minIndex>1</minIndex>
// <maxIndex>3</maxIndex>
// </rollingPolicy>
// <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
// <maxFileSize>5MB</maxFileSize>
// </triggeringPolicy>
// </appender>
iOSのCocoaLumberjackは、サイズベースのローテーションだけでなく、logFileManager.maximumLogFilesを使用した日付による古いログの削除もサポートしています。maximumLogFiles = 0を設定すると制限が解除され、ログが無制限に蓄積されるため、本番環境では危険です。
// 総容量チェック付きカスタムローテーション
class SizeAwareLogger {
let maxTotalSize: Int64 = 20 * 1024 * 1024
func enforceQuota(at logDirectory: URL) {
let files = (try? FileManager.default
.contentsOfDirectory(
at: logDirectory,
includingPropertiesForKeys: [.fileSize]
)) ?? []
let total = files.reduce(0) {
$0 + (try? $1.resourceValues(forKeys: [.fileSize])
.fileSize).map(Int64.init) ?? 0
}
if total > maxTotalSize {
// 最も古いファイルを削除
files.sorted { $0.path < $1.path }.first.map {
try? FileManager.default.removeItem(at: $0)
}
}
}
}
Log Rotationは自動アーカイブだけでなく、システムヘルスの指標でもあります。ログのローテーションが頻繁すぎる(数分ごと)場合は、過剰なロギングまたはエラーログループを示しています。ローテーション頻度にアラートを設定してください。1時間に10回を超えるローテーションは調査の対象です。
監視システム(Prometheus、Grafana、Datadog)は、ファイルシステムエクスポーターを介してローテーションメトリクスを追跡できます。Prometheus node_exporterはファイルサイズと変更時間のメトリクスを提供します。モバイルデバイスでは、ローテーション監視は通常SDKに組み込まれています。CocoaLumberjackはDDLogを介してローテーションイベントを記録し、Logbackはアペンダーを介してステータスを送信します。
アラート:アーカイブが予想よりも多い場合(ローテーションカウントが制限を超えた)またはログの総容量がクォータを超えた場合、システムは管理者に通知する必要があります。サーバーの標準しきい値はパーティションサイズの80%、モバイルデバイスの場合はアプリケーションあたり50 MB超過時にアラートを発します。
よくある質問
サーバーの場合は100~500 MB、モバイルアプリケーションの場合は1~10 MBです。小さすぎる制限(1 MB未満)は頻繁なローテーションと不要なI/O操作を引き起こします。大きすぎる制限(500 MB超)はファイルのオープンと検索の時間を増加させます。
本番環境では最低7日間(日次ローテーション)または3~5アーカイブ(サイズベースのローテーション)です。コンプライアンス要件の場合は30~90日ですが、同じパーティションでのローテーションではなく、圧縮と保持ポリシーを持つ別のストレージを使用してください。
logrotateはLinuxユーティリティであり、iOSやAndroidでは使用できません。モバイルデバイスでは、ローテーションはライブラリによって実装されます。iOS用のCocoaLumberjackとAndroid用のLogbackです。これらはrootアクセスを必要とせず、アプリケーションのサンドボックス環境内で動作します。
循環ロギングがないか確認してください — エラー処理自体が新しいエラーを生成するケースです。保護を追加します。しきい値付きの同一タイプの繰り返しロギングカウンター(1分間に100件を超える同一メッセージを禁止)と、超過後の一時ロックを設定します。
必須ではありませんが、推奨されます。gzipはテキストログをデータ損失なく10~20倍に圧縮します。モバイルデバイスでは、圧縮によりストレージ使用量が50 MBから3~5 MBに削減されます。唯一の欠点は、解凍なしではアーカイブを読めないことですが、分析には通常現在のファイルのみが必要です。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。