【bat】バッチファイルでログローテーションを実装する方法|日付管理・自動削除・世代管理の完全ガイド

【bat】バッチファイルでログローテーションを実装する方法|日付管理・自動削除・世代管理の完全ガイド bat

バッチファイルを毎日定期実行していると、ある日突然「ディスクがいっぱいです」というエラーが出て処理が止まる——そんな経験はありませんか?

1日1ファイルでも1年で365件。5年運用すれば1,800件を超えます。手動での削除は手間がかかり、いつかは必ず忘れます。

解決策はログローテーションの自動化です。「N日分だけ保持して古いファイルは自動削除」「一定サイズを超えたら新ファイルへ切替」という仕組みをバッチ内に組み込むことで、ログ管理を完全に自動化できます。

この記事では FORFILES による日付方式の自動削除・世代管理・サイズ制限・ZIP圧縮アーカイブ・INFO/WARN/ERRORのログレベル実装まで、コピーしてすぐ使える実装例を体系的に解説します。

スポンサーリンク

ログローテーションとは

ログローテーション(Log Rotation)とは、古いログファイルを自動的に削除・圧縮・リネームして、保持するログ量を一定に保つ仕組みです。

ローテーション方式 概要 向いている用途
日付方式 1日1ファイル、古いファイルをN日後削除 定期バッチ・毎日実行
世代方式 最新N件だけ保持、超えたら古い順に削除 実行回数ベースの管理
サイズ方式 ファイルサイズがN MBを超えたらローテーション 長時間連続稼働

基本:日付付きログファイルを作る

日付ローテーションの出発点は、%DATE% を整形してファイル名に使うことです。ロケールに依存しない安全な取り出し方と、%TIME% を組み合わせた実装を押さえましょう。

log-basic.bat
@echo off
setlocal

:: ── 日付・時刻の取得(ロケール非依存) ──────────────
for /f "tokens=1-3 delims=/" %%a in ('wmic os get LocalDateTime /value | find "="') do (
    for /f "tokens=2 delims==" %%d in ("%%a") do set DT=%%d
)
set YYYY=%DT:~0,4%
set MM=%DT:~4,2%
set DD=%DT:~6,2%
set HH=%DT:~8,2%
set MI=%DT:~10,2%
set SS=%DT:~12,2%

:: ── ログファイルパス ─────────────────────────────
set LOGDIR=%~dp0logs
if not exist "%LOGDIR%" mkdir "%LOGDIR%"
set LOGFILE=%LOGDIR%%YYYY%-%MM%-%DD%.log

:: ── ログ出力 ─────────────────────────────────────
set TIMESTAMP=%YYYY%-%MM%-%DD% %HH%:%MI%:%SS%
echo [%TIMESTAMP%] [INFO] バッチ処理を開始 ^>> "%LOGFILE%"

:: ── メイン処理 ───────────────────────────────────
xcopy C:data D:ackup /D /Y ^>> "%LOGFILE%"
echo [%TIMESTAMP%] [INFO] バックアップ完了 ^>> "%LOGFILE%"

endlocal
ポイント
%DATE% はロケール設定(地域)によって形式が異なります(2026/03/132026-03-13 など)。wmic os get LocalDateTime を使うと YYYYMMDDHHmmss 固定形式で取得でき、どの環境でも動作します。

FORFILES で古いログを自動削除する

FORFILES コマンドは「N日以上前のファイルを対象にコマンドを実行する」という処理に最適です。ログローテーションの核心です。

bat
:: 30日以上前の .log ファイルを削除
FORFILES /p "%LOGDIR%" /m *.log /d -30 /c "cmd /c del @path"

:: エラー抑制(対象ファイルなしでも止まらない)
FORFILES /p "%LOGDIR%" /m *.log /d -30 /c "cmd /c del @path" 2^>nul
オプション 説明
/p パス 対象フォルダ
/m パターン ファイル名パターン(例: *.log)
/d -N N日以上前のファイルを対象(-30 = 30日前以前)
/d +N N日以内(未来含む)のファイルを対象
/c “コマンド” 各ファイルに対して実行するコマンド。@path = フルパス、@fname = ファイル名

日付方式ローテーションの完全実装

ログ出力 + 古いファイルの自動削除をひとつのバッチにまとめた実装例です。

log-rotate-date.bat
@echo off
setlocal

:: ── 設定 ──────────────────────────────────────────
set LOGDIR=%~dp0logs
set KEEP_DAYS=30         &:: 保持日数

:: ── 日時取得(ロケール非依存) ────────────────────
for /f "skip=1 tokens=1" %%t in ('wmic os get LocalDateTime') do (
    if not "%%t"=="" set DT=%%t
)
set YYYY=%DT:~0,4%  & set MM=%DT:~4,2%  & set DD=%DT:~6,2%
set HH=%DT:~8,2%   & set MI=%DT:~10,2% & set SS=%DT:~12,2%
set TS=%YYYY%-%MM%-%DD% %HH%:%MI%:%SS%
set LOGFILE=%LOGDIR%%YYYY%-%MM%-%DD%.log

:: ── ログフォルダ作成 ───────────────────────────────
if not exist "%LOGDIR%" mkdir "%LOGDIR%"

:: ── ログ書き込み関数(CALL :LOG レベル メッセージ) ──
call :LOG INFO "処理開始"

:: ── メイン処理 ───────────────────────────────────
xcopy "C:data" "D:ackup" /D /Y ^>> "%LOGFILE%" 2^>&1
if %ERRORLEVEL% neq 0 (
    call :LOG ERROR "xcopy 失敗 ERRORLEVEL=%ERRORLEVEL%"
) else (
    call :LOG INFO  "バックアップ完了"
)

:: ── ローテーション: KEEP_DAYS日より古いログを削除 ─────
FORFILES /p "%LOGDIR%" /m *.log /d -%KEEP_DAYS% /c "cmd /c del @path" 2^>nul
call :LOG INFO  "ローテーション完了(%KEEP_DAYS%日超ログ削除)"

endlocal
exit /b 0

:: ── :LOG サブルーチン ────────────────────────────
:LOG
:: 使い方: call :LOG [INFO|WARN|ERROR] "メッセージ"
echo [%TS%] [%~1] %~2 ^>> "%LOGFILE%"
exit /b 0

世代管理方式(最新N件だけ残す)

日付ではなく「何個まで保持するか」でローテーションしたい場合の実装です。ファイル数が一定以上になったら古い順に削除します。

log-rotate-gen.bat
@echo off
setlocal enabledelayedexpansion

set LOGDIR=%~dp0logs
set MAX_FILES=10        &:: 保持するファイル数

:: ── ファイル数を数える ───────────────────────────
set COUNT=0
for %%f in ("%LOGDIR%*.log") do set /a COUNT+=1

:: ── MAX_FILES を超えたら古い順に削除 ───────────────
if %COUNT% gtr %MAX_FILES% (
    set DEL_COUNT=0
    set /a DEL_TARGET=%COUNT% - %MAX_FILES%
    :: 更新日時の昇順(古い順)でループ
    for /f "delims=" %%f in ('dir /b /o:d "%LOGDIR%*.log"') do (
        if !DEL_COUNT! lss !DEL_TARGET! (
            del "%LOGDIR%\%%f"
            echo 削除: %%f
            set /a DEL_COUNT+=1
        )
    )
)

echo 世代管理完了(現在: %COUNT%件 → 上限: %MAX_FILES%件)

サイズ制限方式(ファイルサイズでローテーション)

長時間連続稼働するバッチでは、1つのログファイルが肥大化します。一定サイズを超えたら新しいファイルに切り替える実装です。

log-rotate-size.bat
@echo off
setlocal enabledelayedexpansion

set LOGDIR=%~dp0logs
set LOGBASE=app
set MAX_SIZE=10485760    &:: 10MB(バイト単位)
set LOGFILE=%LOGDIR%%LOGBASE%.log

if not exist "%LOGDIR%" mkdir "%LOGDIR%"

:: ── 既存ログファイルのサイズ確認 ───────────────────
if exist "%LOGFILE%" (
    for %%s in ("%LOGFILE%") do set FILESIZE=%%~zs
    if !FILESIZE! gtr %MAX_SIZE% (
        :: タイムスタンプ付きでリネーム
        for /f "skip=1 tokens=1" %%t in ('wmic os get LocalDateTime') do (
            if not "%%t"=="" set DT2=%%t
        )
        ren "%LOGFILE%" "%LOGBASE%_!DT2:~0,14!.log"
        echo ローテーション: !FILESIZE! bytes ^> 新ファイルへ切替
    )
)

:: ── ログ書き込み ─────────────────────────────────
echo [処理実行] ^>> "%LOGFILE%"

古いログをZIP圧縮してアーカイブする

削除せずに圧縮保管したいケースでは、PowerShell の Compress-Archive と組み合わせます。

log-archive.bat
@echo off
setlocal enabledelayedexpansion

set LOGDIR=%~dp0logs
set ARCHIVEDIR=%~dp0logsarchive
set ARCHIVE_DAYS=7    &:: 7日以上前を圧縮対象

if not exist "%ARCHIVEDIR%" mkdir "%ARCHIVEDIR%"

:: 7日以上前のログを1ファイルずつZIP圧縮して元ファイルを削除
FORFILES /p "%LOGDIR%" /m *.log /d -%ARCHIVE_DAYS% /c ^
    "cmd /c powershell -NoProfile -Command "Compress-Archive -Path @path -DestinationPath '%ARCHIVEDIR%\@fname.zip' -Force" && del @path" 2^>nul

echo アーカイブ完了: %ARCHIVEDIR%

ログレベル対応の汎用ロガーを作る

INFO/WARN/ERROR の3段階ログレベルを持つサブルーチンを実装すれば、どのバッチでも call :LOG レベル "メッセージ" の一行で書けます。

logger.bat(共通ロガー)
@echo off
setlocal enabledelayedexpansion

:: ── 設定 ──────────────────────────────────────────
set LOGDIR=%~dp0logs
set KEEP_DAYS=30
set LOG_LEVEL_MIN=INFO    &:: INFO / WARN / ERROR(これ未満は出力しない)

:: ── 日時取得 ───────────────────────────────────────
for /f "skip=1 tokens=1" %%t in ('wmic os get LocalDateTime') do (
    if not "%%t"=="" set DT=%%t
)
set YYYY=%DT:~0,4%  & set MM=%DT:~4,2%  & set DD=%DT:~6,2%
set HH=%DT:~8,2%   & set MI=%DT:~10,2% & set SS=%DT:~12,2%
set TS=%YYYY%-%MM%-%DD% %HH%:%MI%:%SS%
set LOGFILE=%LOGDIR%%YYYY%-%MM%-%DD%.log

if not exist "%LOGDIR%" mkdir "%LOGDIR%"

:: ── メイン処理 ───────────────────────────────────
call :LOG INFO  "===== バッチ開始 ====="
call :LOG INFO  "バックアップ実行中"
xcopy "C:data" "D:ackup" /D /Y 1^>>"%LOGFILE%" 2^>&1
if %ERRORLEVEL% neq 0 (
    call :LOG ERROR "バックアップ失敗 code=%ERRORLEVEL%"
    exit /b 1
)
call :LOG INFO  "バックアップ完了"
call :LOG INFO  "===== バッチ終了 ====="

:: ローテーション
FORFILES /p "%LOGDIR%" /m *.log /d -%KEEP_DAYS% /c "cmd /c del @path" 2^>nul

endlocal
exit /b 0

:: ═══════════════════════════════════════════════════
:: :LOG サブルーチン
:: 引数1: レベル (INFO / WARN / ERROR)
:: 引数2: メッセージ
:: ═══════════════════════════════════════════════════
:LOG
set _LV=%~1
set _MSG=%~2
:: ファイルに記録
echo [%TS%] [%_LV%] %_MSG% ^>> "%LOGFILE%"
:: ERRORだけコンソールにも表示
if /i "%_LV%"=="ERROR" echo [ERROR] %_MSG%
exit /b 0

出力されるログの例:

2026-03-13.log(出力例)
[2026-03-13 02:30:01] [INFO] ===== バッチ開始 =====
[2026-03-13 02:30:01] [INFO] バックアップ実行中
[2026-03-13 02:30:05] [INFO] バックアップ完了
[2026-03-13 02:30:05] [INFO] ===== バッチ終了 =====

タスクスケジューラで毎日自動実行する

ローテーション付きバッチをタスクスケジューラに登録すれば、完全自動化できます。schtasks コマンドで登録できます。

bat
:: 毎日 02:30 に logger.bat を実行するタスクを登録
schtasks /create ^
    /tn "DailyBackupLogger" ^
    /tr "C:scriptslogger.bat" ^
    /sc daily ^
    /st 02:30 ^
    /ru SYSTEM ^
    /f

:: 登録内容を確認
schtasks /query /tn "DailyBackupLogger"

よくある問題と対処法

❓ FORFILES でエラー「指定したファイルが見つかりません」 クリックで開閉

対象ファイルが1件も存在しないとエラーになります。2^>nul でエラー出力を抑制してください。

FORFILES /p "%LOGDIR%" /m *.log /d -30 /c "cmd /c del @path" 2^>nul
❓ 日付取得が文字化けする・ロケール依存でずれる クリックで開閉

%DATE% の代わりに wmic os get LocalDateTime を使うと、どのロケール設定でも YYYYMMDDHHmmss 固定形式で取得でき安全です。

for /f "skip=1 tokens=1" %%t in ('wmic os get LocalDateTime') do (
    if not "%%t"=="" set DT=%%t
)
:: DT = 20260313023001.000000+540 (先頭14桁だけ使う)
❓ タスクスケジューラから実行するとログが別の場所に作られる クリックで開閉

タスクスケジューラ実行時のカレントディレクトリは C:WindowsSystem32 です。%~dp0 でバッチファイル自身のディレクトリを基準にすると、どこから実行しても同じ場所にログが作られます。

:: NG: 相対パス(カレントディレクトリ依存)
set LOGDIR=logs

:: OK: %~dp0 でバッチと同じ場所に固定
set LOGDIR=%~dp0logs

まとめ

やりたいこと 使うもの
日付付きファイル名を作る wmic os get LocalDateTime + 文字列切り出し
N日以上前のファイルを削除 FORFILES /d -N /c “cmd /c del @path”
最新N件だけ残す dir /b /o:d + for /f でカウントしながら削除
ファイルサイズでローテーション for %%s in (…) do set SIZE=%%~zs で比較
古いログをZIP圧縮 FORFILES + PowerShell Compress-Archive
INFO/WARN/ERRORのログレベル call :LOG サブルーチン
毎日自動実行 schtasks /create /sc daily

ログローテーションは一度組み込めば完全自動で機能します。KEEP_DAYS などの定数を先頭にまとめておくと、後から保持日数だけ変更するメンテナンスも簡単です。この記事のコードをそのままコピーして、自社バッチのロガーとして使ってみてください。

関連記事
ログの基本的な書き出し方法から知りたい方は 【bat】バッチファイルでログを自動で日付付きファイルに保存する方法 も参照してください。