こんにちは。
DX推進開発部というチームでアプリケーションエンジニアをしている鈴木です。
レガシーシステムのログひっ迫問題を、生成AIを利用して解決した話を書いてみようと思います。
目次
はじめに
私は社内向けの内製システムの開発・保守運用チームでアプリケーションエンジニアをしています。
担当するシステムは多岐にわたるのですが、中にはレガシーと呼ばれる古いシステムも存在します。
小規模なシステムなのですが、古い分潜在的な課題が残っていることがあります。
ある日、担当するシステムの一つ(Windowsバッチアプリケーション)で、サーバーの容量がひっ迫しているという問題が発生しました。
この問題に生成AIを利用して課題解決をしていったことを書いていきます。
ログ管理の問題
サーバーの容量ひっ迫について調査した結果、原因は膨大なログファイルデータによる容量不足であることが判明しました。
さらに調査を続けたところ、ログファイルに対して、いわゆるログローテーションと呼ばれる有効な設定(アーカイブや削除等)が入っておりませんでした。
生成AIに最適解を聞いてみる
ログローテーションに対して正しい知見を持っていなかったため、生成AIに相談してみます。
以下はプロンプトです。今回はGemini 1.5 Flashを利用しました。
命令書:
あなたは、優秀なシステムエンジニアです。
以下の相談事項をもとに適切なアドバイスをしてください。
相談事項:
Windows環境でバッチのログ管理を検討しています。
ログローテーションを導入するにあたって最適な方法を複数教えてください。
以下は回答です。
ログローテーションの最適解についてのアドバイス
Windowsバッチアプリケーションでのログローテーションは、アプリケーションの安定性、メンテナンス性、そして可用性を考慮することが重要です。以下にいくつかの方法とツールについて解説します。
1. ローカルでのログローテーション
ローカルスクリプトでのログローテーション
Windowsバッチファイルを使ってログローテーションを実現するシンプルな方法です。
(省略)
2. クラウドベースの解決策
ログデータをクラウドベースで管理することで、柔軟性やスケーラビリティが向上します。例えば、AWS、Azure、Google Cloud などのクラウドプロバイダーを利用できます。
(省略)
3. 専用ツールの利用
–  Splunk:Splunk はログデータの収集、分析、監視を行う強力なツールです。以下に簡単な設定手順を紹介します。
–  Logstash  と  ElasticSearch  を含む  ELK Stack :これにより、ログの収集、解析、および可視化が可能です。
–  Graylog :集中ログ管理を行うオープンソースツールで、ログデータの収集、インデックス作成、リアルタイム検索が可能です。
スクリプトを組むか、クラウドサービスを利用するか、サードパーティのツールを利用する手段を提示してくれました。
念のためGoogleで検索をしましたが概ね同じ内容が得られました。
しかしクラウドサービスやサードパーティツールは利用料がかかります。移行費用も含め、レガシーシステムにそこまでのコストを払うのは現実的ではありません。
そのためスクリプトを組むという方針で対応することにします。
コーディング
コーディングも例によってAIにお願いします。
今回はD:\APPLOGs\Logsというフォルダに「GMO01.YYYYMMDD.log」という名称で溜まっていくシンプルなログを想定してスクリプトを組んでもらいます。
あなたは、PowerShellに精通した優秀なエンジニアです。
以下の条件をもとに、PowerShellのスクリプトをコーディングしてください。
# 条件
・ログファイルのパス:D:\APPLOGs\Logs
・圧縮ファイルの格納パス:D:\APPLOGs\Logs\Archive
・ログファイルのファイル名:GMO01.YYYYMMDD.log(例:GMO01.20231231.log)
・1週間前までのログファイルを圧縮する
・2年前までの圧縮ファイルは削除する
スクリプトの生成は1回で期待する成果は返ってこないので、複数回のラリーとトライ&エラーをしています。
最終的に以下のようなコードとなりました。
# パス設定
$LogFilePath = "D:\APPLOGs\Logs"
$ArchivePath = "D:\APPLOGs\Logs\Archive"
$LogFileNamePrefix = "GMO01"
$CompressionFormat = "Zip"
$DaysToCompress = 7
$YearsToDelete = 2
$Now = Get-Date
$CompressDate = $Now.AddDays(-$DaysToCompress)
$DeleteDate = $Now.AddYears(-$YearsToDelete)
$logOutputPath = "D:\APPLOGs\script_output.log"
# ログ出力用関数
function WriteLog {
    param(
        [string]$message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logEntry = "$timestamp - $message"
    $logEntry | Out-File -FilePath $logOutputPath -Append -Encoding UTF8
    Write-Host $logEntry
}
WriteLog "Starting the script..."
# ログファイルを取得
Try {
    WriteLog "Starting to retrieve log files..."
    $LogFiles = Get-ChildItem -Path $LogFilePath -Filter "$LogFileNamePrefix*.log"
    WriteLog ("Retrieved log file list: {0} files" -f $LogFiles.Count)
    if ($LogFiles.Count -eq 0) {
        WriteLog "No target log files found."
    }
} Catch {
    WriteLog "Error occurred while retrieving log files: $_"
    Exit
}
# ログファイルを圧縮し、元のファイルを削除
foreach ($LogFile in $LogFiles) {
    Try {
        if ($LogFile.LastWriteTime -le $CompressDate) {
            $DestinationFile = Join-Path -Path $ArchivePath -ChildPath ($LogFile.BaseName + ".zip")
            Compress-Archive -Path $LogFile.FullName -DestinationPath $DestinationFile -CompressionLevel Optimal -Force
            WriteLog ("Compressed log file and moved to Archive folder: {0} -> {1}" -f $LogFile.FullName, $DestinationFile)
            
            # 元のログファイルを削除
            Remove-Item -Path $LogFile.FullName -Force
            WriteLog ("Deleted original log file: {0}" -f $LogFile.FullName)
        }
    } Catch {
        WriteLog "Error occurred during log file compression or deletion: $_"
    }
}
# 指定日付より古い圧縮ファイルを削除
Try {
    WriteLog "Starting to retrieve compressed files..."
    $CompressedFiles = Get-ChildItem -Path $ArchivePath -Filter "$LogFileNamePrefix*.zip"
    WriteLog ("Retrieved compressed file list: {0} files" -f $CompressedFiles.Count)
    if ($CompressedFiles.Count -eq 0) {
        WriteLog "No target compressed files found for deletion."
    } Else {
        foreach ($CompressedFile in $CompressedFiles) {
            Try {
                # ファイル名から日付を抽出(例:GMO01_yyyyMMdd.zip)
                $fileName = $CompressedFile.BaseName
                if ($fileName -match "$LogFileNamePrefix`.(\d{8})") {
                    $dateString = $matches[1] # yyyyMMdd 形式の文字列
                    $fileDate = [datetime]::ParseExact($dateString, "yyyyMMdd", $null)
                    WriteLog ("Date of compressed file: {0}, check date: {1}" -f $fileDate, $DeleteDate)
                    
                    if ($fileDate -le $DeleteDate) {
                        Remove-Item -Path $CompressedFile.FullName -Force
                        WriteLog ("Deleted compressed file: {0}" -f $CompressedFile.FullName)
                    } Else {
                        WriteLog ("Compressed file is not target for deletion: {0}" -f $CompressedFile.FullName)
                    }
                } Else {
                    WriteLog ("Compressed file name format is incorrect: {0}" -f $CompressedFile.FullName)
                }
            } Catch {
                WriteLog "Error occurred during compressed file deletion: $_"
            }
        }
    }
} Catch {
    WriteLog "Error occurred while retrieving compressed files: $_"
}
WriteLog "Script execution completed."
こちらのスクリプトをタスクスケジューラにタスク設定します。
週1の起動設定をすれば、毎週圧縮&削除を実施してくれるようになります。
スクリプトの解説
# ログ出力用関数
function WriteLog {
    param(
        [string]$message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logEntry = "$timestamp - $message"
    $logEntry | Out-File -FilePath $logOutputPath -Append -Encoding UTF8
    Write-Host $logEntry
}
このスクリプトを実施した際のログ出力用の関数
$logOutputPath = “D:\APPLOGs\script_output.log”に出力します。
# ログファイルを圧縮し、元のファイルを削除
foreach ($LogFile in $LogFiles) {
    Try {
        if ($LogFile.LastWriteTime -le $CompressDate) {
            $DestinationFile = Join-Path -Path $ArchivePath -ChildPath ($LogFile.BaseName + ".zip")
            Compress-Archive -Path $LogFile.FullName -DestinationPath $DestinationFile -CompressionLevel Optimal -Force
            WriteLog ("Compressed log file and moved to Archive folder: {0} -> {1}" -f $LogFile.FullName, $DestinationFile)
            
            # 元のログファイルを削除
            Remove-Item -Path $LogFile.FullName -Force
            WriteLog ("Deleted original log file: {0}" -f $LogFile.FullName)
        }
    } Catch {
        WriteLog "Error occurred during log file compression or deletion: $_"
    }
}
ログファイルの最終更新日時が$CompressDate以前かどうかを判定。
このサンプルでは$CompressDateは7日前です。
$CompressDate以前であれば、ログファイルを ZIP 形式で圧縮し、指定されたフォルダに移動します。
圧縮が成功したら、元のログファイルを削除します。
# 指定日付より古い圧縮ファイルを削除
Try {
    WriteLog "Starting to retrieve compressed files..."
    $CompressedFiles = Get-ChildItem -Path $ArchivePath -Filter "$LogFileNamePrefix*.zip"
    WriteLog ("Retrieved compressed file list: {0} files" -f $CompressedFiles.Count)
    if ($CompressedFiles.Count -eq 0) {
        WriteLog "No target compressed files found for deletion."
    } Else {
        foreach ($CompressedFile in $CompressedFiles) {
            Try {
                # ファイル名から日付を抽出(例:GMO01_yyyyMMdd.zip)
                $fileName = $CompressedFile.BaseName
                if ($fileName -match "$LogFileNamePrefix`.(\d{8})") {
                    $dateString = $matches[1] # yyyyMMdd 形式の文字列
                    $fileDate = [datetime]::ParseExact($dateString, "yyyyMMdd", $null)
                    WriteLog ("Date of compressed file: {0}, check date: {1}" -f $fileDate, $DeleteDate)
                    
                    if ($fileDate -le $DeleteDate) {
                        Remove-Item -Path $CompressedFile.FullName -Force
                        WriteLog ("Deleted compressed file: {0}" -f $CompressedFile.FullName)
                    } Else {
                        WriteLog ("Compressed file is not target for deletion: {0}" -f $CompressedFile.FullName)
                    }
                } Else {
                    WriteLog ("Compressed file name format is incorrect: {0}" -f $CompressedFile.FullName)
                }
            } Catch {
                WriteLog "Error occurred during compressed file deletion: $_"
            }
        }
    }
} Catch {
    WriteLog "Error occurred while retrieving compressed files: $_"
}
アーカイブファイルの削除を実施します。
削除条件はファイル名に含まれる日付が$DeleteDateよりも前かどうかで判定します。
このサンプルでは$DeleteDateは2年前です。
おわりに
今回、生成AIの力を借りて課題解決をした経験を書いてみました。
対応方針のヒントをもらい、開発コストを抑えることができました。
このように最近では生成AIを利用して効率的に課題解決を目指す機会が増えています。開発の時間を極力減らし、より生産的な作業に集中するということが重要になってきていると思います。
最後に、散々言われていることですが、生成AIも万能ではないです。出力内容が正確ではないこともあるため注意が必要です。
コーディングに関しての所感ですが、エラー処理、セキュリティ対策などはきちんと条件に含めないと正しく入れてくれないことが多いと感じています。
アイデア出しや基本的なコード作成は非常に強力ですが、最終的には自身でのチェックが必須になってきます。
ブログの著者欄
採用情報
関連記事
KEYWORD
CATEGORY
- 
                  技術情報(516)
 - 
                  イベント(193)
 - 
                  カルチャー(50)
 - 
                  デザイン(47)
 
TAG
- "eVTOL"
 - "Japan Drone"
 - "ロボティクス"
 - "空飛ぶクルマ"
 - 5G
 - Adam byGMO
 - AGI
 - AI
 - AI人財
 - APT攻撃
 - AWX
 - BIT VALLEY
 - Blade
 - blockchain
 - Canva
 - ChatGPT
 - ChatGPT Team
 - Claude Team
 - cloudflare
 - cloudnative
 - CloudStack
 - CM
 - CNDO
 - CNDT
 - CODEGYM Academy
 - ConoHa
 - ConoHa、Dify
 - CS
 - CSS
 - CTF
 - DC
 - design
 - Designship
 - Desiner
 - DeveloperExper
 - DeveloperExpert
 - DevRel
 - DevSecOpsThon
 - DiceCTF
 - Dify
 - DNS
 - Docker
 - DTF
 - Expert
 - Felo
 - GitLab
 - GMO AIR
 - GMO AIロボティクス大会議&表彰式
 - GMO DESIGN AWARD
 - GMO Developers Day
 - GMO Developers Night
 - GMO Developers ブログ
 - GMO Flatt Security
 - GMO GPUクラウド
 - GMO Hacking Night
 - GMO kitaQ
 - GMO SONIC
 - GMOアドパートナーズ
 - GMOアドマーケティング
 - GMOイエラエ
 - GMOインターネット
 - GMOインターネットグループ
 - GMOクラウド]
 - GMOグローバルサイン
 - GMOサイバーセキュリティbyイエラエ
 - GMOサイバーセキュリティ大会議
 - GMOサイバーセキュリティ大会議&表彰式
 - GMOソリューションパートナー
 - GMOデジキッズ
 - GMOブランドセキュリティ
 - GMOペイメントゲートウェイ
 - GMOペパボ
 - GMOメディア
 - GMOリサーチ
 - GMO大会議
 - Go
 - GPU
 - GPUクラウド
 - GTB
 - Hardning
 - Harvester
 - HCI
 - iOS
 - IoT
 - ISUCON
 - JapanDrone
 - Java
 - JJUG
 - K8s
 - Kaigi on Rails
 - Kids VALLEY
 - KidsVALLEY
 - LLM
 - MCP
 - MetaMask
 - MySQL
 - NFT
 - NVIDIA
 - NW構成図
 - NW設定
 - Ollama
 - OpenStack
 - Perl
 - perplexity
 - PHP
 - PHPcon
 - PHPerKaigi
 - PHPカンファレンス
 - QUIC
 - Rancher
 - RPA
 - Ruby
 - Selenium
 - Slack
 - Slack活用
 - Spectrum Tokyo Meetup
 - splunk
 - SRE
 - SSL
 - Terraform
 - TLS
 - TypeScript
 - UI/UX
 - vibe
 - VLAN
 - VS Code
 - Webアプリケーション
 - WEBディレクター
 - XSS
 - アドベントカレンダー
 - イベントレポート
 - インターンシップ
 - インハウス
 - オブジェクト指向
 - オンボーディング
 - お名前.com
 - カルチャー
 - クリエイター
 - クリエイティブ
 - コーディング
 - コンテナ
 - サイバーセキュリティ
 - システム研修
 - スクラム
 - スペシャリスト
 - セキュリティ
 - ソフトウェアテスト
 - チームビルディング
 - デザイン
 - ドローン
 - ネットのセキュリティもGMO
 - ネットワーク
 - ビジネス職
 - ヒューマノイド
 - ヒューマノイドロボット
 - プログラミング教育
 - ブロックチェーン
 - ベイズ統計学
 - マルチプレイ
 - ミドルウェア
 - モバイル
 - ゆめみらいワーク
 - リモートワーク
 - レンタルサーバー
 - ロボット
 - 京大ミートアップ
 - 人材派遣
 - 出展レポート
 - 動画
 - 協賛レポート
 - 基礎
 - 多拠点開発
 - 大学授業
 - 宮崎オフィス
 - 展示会
 - 応用
 - 技育プロジェクト
 - 技術広報
 - 採用
 - 採用サイトリニューアル
 - 採用活動
 - 新卒
 - 新卒研修
 - 日本科学未来館
 - 映像
 - 映像クリエイター
 - 暗号
 - 業務効率化
 - 業務時間削減
 - 機械学習
 - 決済
 - 物理暗号
 - 生成AI
 - 視覚暗号
 - 開発生産性
 - 開発生産性向上
 - 階層ベイズ
 - 高機能暗号
 
PICKUP
- 
                  
                    
                                        東京・福島・福岡の専門学校3校でConoHa AI Canvasを用いた講義を実施しました
技術情報
 - 
                  
                    
                                        【協賛レポート・前編】Designship 2025|参加者と“共につくる”デザインのかたち──私たちの挑戦を振り返る
デザイン
 - 
                  
                    
                                        NFSのパフォーマンストラブルに対応した話
技術情報
 - 
                  
                    
                                        Microsoft Entra アプリケーション プロキシ × Windows 統合認証環境での NTLM 廃止影響と対策
技術情報
 - 
                  
                    
                                        GMOインターネットグループ合同テクノロジーインターンシップ2025 体験記~ML/Webコース編①~
カルチャー
 - 
                  
                    
                                        ChatGPTとConoHa AI Canvasで検証:生成AIが変えるクリエイティブ制作
技術情報