Add tools/Collect-YALootBoxesLogs.ps1 log collector for debugging
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
f38ae14409
commit
4b59c8e34b
1 changed files with 162 additions and 0 deletions
162
tools/Collect-YALootBoxesLogs.ps1
Normal file
162
tools/Collect-YALootBoxesLogs.ps1
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
<#
|
||||
.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).'
|
||||
Loading…
Add table
Reference in a new issue