YALootBoxes/tools/Collect-YALootBoxesLogs.ps1
smthspec 4b59c8e34b Add tools/Collect-YALootBoxesLogs.ps1 log collector for debugging
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 23:07:57 +03:00

162 lines
6.6 KiB
PowerShell

<#
.SYNOPSIS
Collects DayZ server + client logs (and the mod's live config) for
debugging the YALootBoxes mod, then bundles them into one timestamped
.zip that is easy to hand off.
.DESCRIPTION
Copies recent .RPT / .ADM / .log / .mdmp / crash logs from the server
profile folder and the client log folder, plus the auto-generated
profiles\YALootBoxes\*.json config. Produces:
- server\ , client\ : the raw collected files
- server\YALootBoxes_config\*.json: the mod's live config
- YALootBoxes_filtered.txt : every "[YALootBoxes]" line, by file
- summary.txt : machine info + ERROR/WARN counts + file list
...all inside YALootBoxes_logs_<timestamp>.zip on your Desktop.
Handles files locked by a running server (shared-read copy).
.EXAMPLE
powershell -ExecutionPolicy Bypass -File .\Collect-YALootBoxesLogs.ps1
.EXAMPLE
# widen the window to the last 48 hours
powershell -ExecutionPolicy Bypass -File .\Collect-YALootBoxesLogs.ps1 -SinceHours 48
#>
[CmdletBinding()]
param(
[string]$ServerProfile = 'C:\Program Files (x86)\Steam\steamapps\common\DayZServer\profiles',
[string]$ClientLogs = 'C:\Users\drasi\AppData\Local\DayZ',
[string]$OutDir = "$env:USERPROFILE\Desktop",
[int] $SinceHours = 12,
[string]$Tag = '[YALootBoxes]'
)
$ErrorActionPreference = 'Stop'
$stamp = Get-Date -Format 'yyyyMMdd_HHmmss'
$stageRoot = Join-Path $env:TEMP "YALB_logs_$stamp"
$stageServer = Join-Path $stageRoot 'server'
$stageClient = Join-Path $stageRoot 'client'
New-Item -ItemType Directory -Force -Path $stageServer, $stageClient | Out-Null
$patterns = '*.RPT', '*.log', '*.ADM', '*.mdmp', 'crash_*.log', 'error.log', 'script*.log'
$cutoff = (Get-Date).AddHours(-$SinceHours)
# Copy a file even if a running server holds it open (shared read).
function Copy-Locked {
param([string]$Src, [string]$Dst)
try {
$in = [System.IO.File]::Open($Src, 'Open', 'Read', 'ReadWrite')
try {
$out = [System.IO.File]::Create($Dst)
try { $in.CopyTo($out) } finally { $out.Dispose() }
} finally { $in.Dispose() }
return $true
} catch {
Write-Warning "Could not copy '$Src': $($_.Exception.Message)"
return $false
}
}
function Collect {
param([string]$Source, [string]$Stage, [string]$Label)
if (-not (Test-Path $Source)) {
Write-Warning "$Label path not found: $Source"
return @()
}
$files = Get-ChildItem -Path $Source -Recurse -File -Include $patterns -ErrorAction SilentlyContinue |
Where-Object { $_.LastWriteTime -ge $cutoff }
# Always include the newest .RPT even if it predates the cutoff window.
if (-not ($files | Where-Object { $_.Extension -eq '.RPT' })) {
$newestRpt = Get-ChildItem -Path $Source -Recurse -File -Filter '*.RPT' -ErrorAction SilentlyContinue |
Sort-Object LastWriteTime -Descending | Select-Object -First 1
if ($newestRpt) { $files = @($files) + $newestRpt }
}
$collected = @()
foreach ($f in ($files | Sort-Object FullName -Unique)) {
$dst = Join-Path $Stage $f.Name
if (Test-Path $dst) {
$dst = Join-Path $Stage ('{0}_{1}{2}' -f $f.BaseName, $f.LastWriteTime.ToString('HHmmss'), $f.Extension)
}
if (Copy-Locked $f.FullName $dst) {
$collected += [pscustomobject]@{
Source = $Label; Name = $f.Name; Size = $f.Length; Modified = $f.LastWriteTime
}
}
}
return $collected
}
# --- collect server + client logs ---
$serverFiles = @(Collect -Source $ServerProfile -Stage $stageServer -Label 'server')
$clientFiles = @(Collect -Source $ClientLogs -Stage $stageClient -Label 'client')
# --- grab the mod's live generated config ($profile:YALootBoxes\*.json) ---
$modCfg = Join-Path $ServerProfile 'YALootBoxes'
if (Test-Path $modCfg) {
$cfgStage = Join-Path $stageServer 'YALootBoxes_config'
New-Item -ItemType Directory -Force -Path $cfgStage | Out-Null
Get-ChildItem $modCfg -Filter '*.json' -File -ErrorAction SilentlyContinue | ForEach-Object {
Copy-Locked $_.FullName (Join-Path $cfgStage $_.Name) | Out-Null
}
} else {
Write-Warning "Mod config folder not found (mod may not have run yet): $modCfg"
}
$all = $serverFiles + $clientFiles
# --- extract only the mod-tagged lines into one file ---
$filterPath = Join-Path $stageRoot 'YALootBoxes_filtered.txt'
$sb = New-Object System.Text.StringBuilder
$textFiles = Get-ChildItem -Path $stageServer, $stageClient -Recurse -File |
Where-Object { $_.Extension -in '.RPT', '.log', '.ADM' }
foreach ($tf in $textFiles) {
$hits = Select-String -Path $tf.FullName -SimpleMatch -Pattern $Tag -ErrorAction SilentlyContinue
if ($hits) {
[void]$sb.AppendLine("===== $($tf.Name) ($($hits.Count) line(s)) =====")
foreach ($h in $hits) { [void]$sb.AppendLine(('{0,6}: {1}' -f $h.LineNumber, $h.Line.Trim())) }
[void]$sb.AppendLine('')
}
}
if ($sb.Length -eq 0) { [void]$sb.AppendLine("No '$Tag' lines found in the collected logs.") }
Set-Content -Path $filterPath -Value $sb.ToString() -Encoding UTF8
# --- summary ---
$errCount = (Select-String -Path $filterPath -SimpleMatch -Pattern '[ERROR]' -ErrorAction SilentlyContinue).Count
$warnCount = (Select-String -Path $filterPath -SimpleMatch -Pattern '[WARN]' -ErrorAction SilentlyContinue).Count
$lines = @(
'YALootBoxes log bundle'
"Generated: $(Get-Date -Format 'u')"
"Machine: $env:COMPUTERNAME User: $env:USERNAME"
"Window: last $SinceHours hour(s) Tag: $Tag"
"Server src: $ServerProfile"
"Client src: $ClientLogs"
''
"Mod-tagged ERROR lines: $errCount"
"Mod-tagged WARN lines: $warnCount"
''
'Files collected:'
)
if ($all) {
foreach ($f in $all) {
$lines += (' [{0}] {1} ({2:N0} bytes, {3:yyyy-MM-dd HH:mm})' -f $f.Source, $f.Name, $f.Size, $f.Modified)
}
} else {
$lines += ' (none - check the paths or widen -SinceHours)'
}
Set-Content -Path (Join-Path $stageRoot 'summary.txt') -Value $lines -Encoding UTF8
# --- zip + cleanup ---
$zip = Join-Path $OutDir "YALootBoxes_logs_$stamp.zip"
if (Test-Path $zip) { Remove-Item $zip -Force }
Compress-Archive -Path (Join-Path $stageRoot '*') -DestinationPath $zip
Remove-Item $stageRoot -Recurse -Force
Write-Host ''
Write-Host "Collected $($all.Count) log file(s)." -ForegroundColor Green
Write-Host "Mod-tagged lines -> ERROR: $errCount WARN: $warnCount"
Write-Host "Bundle: $zip" -ForegroundColor Cyan
Write-Host 'Send me that .zip (summary.txt + YALootBoxes_filtered.txt inside are the key files).'