# 機能設計書 22-ログローテーション

## 概要

本ドキュメントは、Jenkinsのログローテーション（LogRotator）機能の設計仕様を定義する。この機能は、古いビルド履歴の自動削除を管理し、ディスク容量を効率的に管理するための仕組みを提供する。

### 本機能の処理概要

ログローテーションは、Jenkins上のジョブにおいて蓄積されるビルド履歴と成果物を自動的に整理・削除するための機能である。

**業務上の目的・背景**：継続的インテグレーション環境では、日々多数のビルドが実行され、大量のビルド履歴と成果物が蓄積される。これを放置するとディスク容量を圧迫し、システムパフォーマンスの低下を招く。ログローテーションは、保持ポリシーに基づいて古いビルド記録を自動的に削除し、ディスク使用量を適切に管理する機能を提供する。

**機能の利用シーン**：
- 開発チームが毎日多数のビルドを実行する環境での履歴管理
- ストレージコストを抑えたいクラウド環境での運用
- 重要なビルド（リリースビルド等）のみを長期保持したい場合
- 成果物は削除するがビルド記録は残したい場合

**主要な処理内容**：
1. 保持するビルド数に基づく古いビルドの削除（numToKeep）
2. 保持する日数に基づく古いビルドの削除（daysToKeep）
3. 成果物のみの削除（artifactNumToKeep、artifactDaysToKeep）
4. 最終成功ビルド・最終安定ビルドの保護
5. 手動でキープマークされたビルドの保護
6. ビルド中のビルドの保護

**関連システム・外部連携**：BuildDiscarderインターフェースの実装として機能。ジョブの設定として永続化され、新規ビルド完了時に自動実行される。

**権限による制御**：ジョブの設定権限を持つユーザーがログローテーションのパラメータを設定可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 12 | ジョブ設定 | 主画面 | ログローテーション設定の編集 |
| 18 | ビルド削除確認 | 補助機能 | ビルド履歴管理との連携 |

## 機能種別

データ管理 / 自動クリーンアップ

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| daysToKeep | int | No | ビルドを保持する日数（-1で無制限） | -1以上の整数 |
| numToKeep | int | No | 保持するビルド数（-1で無制限） | -1以上の整数 |
| artifactDaysToKeep | Integer | No | 成果物を保持する日数（-1で無制限） | -1以上の整数またはnull |
| artifactNumToKeep | Integer | No | 成果物を保持するビルド数（-1で無制限） | -1以上の整数またはnull |
| removeLastBuild | boolean | No | 最終成功・安定ビルドも削除するか | true/false |

### 入力データソース

ジョブ設定画面からの設定値。文字列形式で入力され、内部でintに変換される。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 削除されたビルド | Run[] | 削除対象となったビルドのリスト |
| 成果物削除されたビルド | Run[] | 成果物のみ削除されたビルドのリスト |

### 出力先

ファイルシステム上のビルドディレクトリとアーティファクトの削除。

## 処理フロー

### 処理シーケンス

```
1. ログローテーション開始（perform呼び出し）
   └─ ジョブの最終成功・安定ビルドを特定
2. numToKeepに基づく削除
   └─ 保持数を超える古いビルドを削除対象に
   └─ 保護対象（keepLog、最終成功、最終安定、ビルド中）を除外
   └─ 対象ビルドを削除
3. daysToKeepに基づく削除
   └─ 保持日数を超える古いビルドを削除対象に
   └─ 保護対象を除外
   └─ 対象ビルドを削除
4. artifactNumToKeepに基づく成果物削除
   └─ 保持数を超えるビルドの成果物を削除対象に
   └─ 保護対象を除外
   └─ 対象ビルドの成果物を削除
5. artifactDaysToKeepに基づく成果物削除
   └─ 保持日数を超えるビルドの成果物を削除対象に
   └─ 保護対象を除外
   └─ 対象ビルドの成果物を削除
6. エラー集約と報告
```

### フローチャート

```mermaid
flowchart TD
    A[ログローテーション開始] --> B[最終成功/安定ビルド特定]
    B --> C{numToKeep設定?}
    C -->|Yes| D[保持数超過ビルドを削除]
    C -->|No| E{daysToKeep設定?}
    D --> E
    E -->|Yes| F[保持日数超過ビルドを削除]
    E -->|No| G{artifactNumToKeep設定?}
    F --> G
    G -->|Yes| H[保持数超過の成果物を削除]
    G -->|No| I{artifactDaysToKeep設定?}
    H --> I
    I -->|Yes| J[保持日数超過の成果物を削除]
    I -->|No| K[エラー集約]
    J --> K
    K --> L{エラーあり?}
    L -->|Yes| M[CompositeIOException送出]
    L -->|No| N[正常終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | キープマーク保護 | isKeepLog()がtrueのビルドは削除しない | 全削除判定時 |
| BR-002 | 最終成功ビルド保護 | 最終成功ビルドは削除しない（removeLastBuildがfalseの場合） | 全削除判定時 |
| BR-003 | 最終安定ビルド保護 | 最終安定ビルドは削除しない（removeLastBuildがfalseの場合） | 全削除判定時 |
| BR-004 | ビルド中保護 | isLogUpdated()がtrueのビルド（実行中）は削除しない | 全削除判定時 |
| BR-005 | 日付判定 | ビルドのタイムスタンプが保持日数以内であれば削除しない | daysToKeep/artifactDaysToKeep適用時 |

### 計算ロジック

```java
// 保持日数の計算
Calendar cal = new GregorianCalendar();
cal.add(Calendar.DAY_OF_YEAR, -daysToKeep);
// ビルドのタイムスタンプがcalより前であれば削除対象
```

## データベース操作仕様

### 操作別データベース影響一覧

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| ビルド削除 | builds/ | DELETE | ビルドディレクトリ全体の削除 |
| 成果物削除 | archive/ | DELETE | アーティファクトディレクトリの削除 |

### テーブル別操作詳細

#### ビルドディレクトリ（$JENKINS_HOME/jobs/[job]/builds/[build]）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| DELETE | ディレクトリ全体 | 削除条件を満たすビルド | Run.delete()による再帰削除 |

#### アーティファクトディレクトリ

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| DELETE | archive/ | 成果物削除条件を満たすビルド | Run.deleteArtifacts()による削除 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | IOException | ビルド削除中のI/Oエラー | exceptionMapに記録して続行、最後にCompositeIOExceptionとして送出 |
| - | CompositeIOException | 複数の削除エラーが発生 | 全エラーを集約して報告 |

### リトライ仕様

削除失敗時のリトライは行わない。エラーは集約されて報告される。

## トランザクション仕様

トランザクション管理はない。各ビルドの削除は独立して実行され、一部の削除に失敗しても他の削除処理は続行される。

## パフォーマンス要件

- 大量のビルド履歴がある場合でもメモリ効率的に処理
- Stream APIを使用した遅延評価による効率化

## セキュリティ考慮事項

- ログローテーション設定はジョブの設定権限を持つユーザーのみが変更可能
- 削除操作自体はシステムが自動実行するため、追加の認証は不要

## 備考

- 歴史的経緯からLogRotatorという名前だが、実際にはログをローテートしない（ビルド記録を削除する）
- Jenkins 1.350以降、成果物のみの削除オプションが追加
- Jenkins 2.474以降、removeLastBuildオプションが追加

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

LogRotatorのフィールド構造と設定パラメータを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | LogRotator.java | `core/src/main/java/hudson/tasks/LogRotator.java` | クラスフィールド（daysToKeep, numToKeep等） |
| 1-2 | BuildDiscarder.java | `core/src/main/java/jenkins/model/BuildDiscarder.java` | 親クラスの抽象定義 |

**読解のコツ**: LogRotatorはBuildDiscarderの実装クラス。4つの保持パラメータ（daysToKeep、numToKeep、artifactDaysToKeep、artifactNumToKeep）とremoveLastBuildフラグを持つ。

#### Step 2: エントリーポイントを理解する

performメソッドがログローテーションの主要なエントリーポイント。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | LogRotator.java | `core/src/main/java/hudson/tasks/LogRotator.java` | performメソッドの全体構造 |

**主要処理フロー**:
1. **156-160行目**: performメソッド開始、例外マップの初期化
2. **163-164行目**: 最終成功ビルド・最終安定ビルドの取得
3. **166-173行目**: numToKeepに基づくビルド削除
4. **175-190行目**: daysToKeepに基づくビルド削除
5. **192-199行目**: artifactNumToKeepに基づく成果物削除
6. **201-216行目**: artifactDaysToKeepに基づく成果物削除
7. **218-225行目**: 例外集約と送出

#### Step 3: 保護判定ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | LogRotator.java | `core/src/main/java/hudson/tasks/LogRotator.java` | shouldKeepRunメソッド |

**主要処理フロー**:
- **228-246行目**: `shouldKeepRun` - ビルドを保持すべきかの判定
  - **229-231行目**: isKeepLog()チェック
  - **233-235行目**: 最終成功ビルドチェック
  - **237-239行目**: 最終安定ビルドチェック
  - **241-243行目**: ビルド中チェック

#### Step 4: 日付判定ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | LogRotator.java | `core/src/main/java/hudson/tasks/LogRotator.java` | tooNewメソッド |

**主要処理フロー**:
- **248-255行目**: `tooNew` - ビルドが保持期間内かの判定

### プログラム呼び出し階層図

```
Job.logRotate()
    │
    └─ BuildDiscarder.perform(Job)
           │
           └─ LogRotator.perform(Job)
                  │
                  ├─ shouldKeepRun(Run, lsb, lstb)
                  │      └─ isKeepLog(), isLogUpdated()判定
                  │
                  ├─ tooNew(Run, Calendar)
                  │      └─ 日付判定
                  │
                  ├─ Run.delete()
                  │      └─ ビルド記録の完全削除
                  │
                  └─ Run.deleteArtifacts()
                         └─ 成果物のみ削除
```

### データフロー図

```
[入力]                    [処理]                         [出力]

ジョブ設定
├─ numToKeep        LogRotator.perform()
├─ daysToKeep       ├─ ビルドリスト取得
├─ artifactNumToKeep├─ 保護判定 ───────────────▶ 削除対象リスト
├─ artifactDaysToKeep   └─ shouldKeepRun()
└─ removeLastBuild  ├─ 日付判定
                    │   └─ tooNew()
                    ├─ Run.delete() ───────────▶ ビルド削除
                    └─ Run.deleteArtifacts() ──▶ 成果物削除
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| LogRotator.java | `core/src/main/java/hudson/tasks/LogRotator.java` | ソース | ログローテーションの実装クラス |
| BuildDiscarder.java | `core/src/main/java/jenkins/model/BuildDiscarder.java` | ソース | ビルド破棄の抽象基底クラス |
| BuildDiscarderDescriptor.java | `core/src/main/java/jenkins/model/BuildDiscarderDescriptor.java` | ソース | Descriptor基底クラス |
| Run.java | `core/src/main/java/hudson/model/Run.java` | ソース | ビルド実行の基底クラス（delete/deleteArtifacts） |
| Job.java | `core/src/main/java/hudson/model/Job.java` | ソース | ジョブの基底クラス（logRotate呼び出し元） |
| CompositeIOException.java | `core/src/main/java/jenkins/util/io/CompositeIOException.java` | ソース | 複合例外クラス |
