Add ProjectZomboidServerLog (DebugLog-server.txt)

Concrete Log subclass for the engine debug log. Captures time, level,
and subsystem prefix per entry; stack-trace continuation lines attach
to the triggering ERROR entry via PatternParser's append-on-no-match
behaviour. Detectors: filename match on DebugLog-server.txt plus two
content signatures (the version=X.Y.Z+hash banner and the level/
subsystem/f/t/st header shape). Pattern constants live in
src/Pattern/ProjectZomboid/DebugServerPattern.php with named groups
ready for analyser use in phase B. Synthetic fixture under
test/src/Games/ProjectZomboid/fixtures/ uses zeroed identifiers and
placeholder paths.
This commit is contained in:
2026-04-30 20:34:03 +00:00
parent c032fd34b8
commit d863fae9e6
5 changed files with 170 additions and 0 deletions

View File

@@ -0,0 +1,22 @@
[16-04-26 00:00:42.314] LOG : General f:0, t:1776297642254, st:48,648,157,434> SLF4J(W): No SLF4J providers were found..
[16-04-26 00:00:42.315] LOG : General f:0, t:1776297642314, st:48,648,157,492> SLF4J(W): Defaulting to no-operation (NOP) logger implementation.
[16-04-26 00:00:42.407] LOG : General f:0, t:1776297642406, st:48,648,157,584> version=42.16.3 0000000000000000000000000000000000000000 2026-04-08 11:54:01 (ZB) demo=false.
[16-04-26 00:00:42.407] LOG : General f:0, t:1776297642407, st:48,648,157,585> revision=0000000000000000000000000000000000000000 date=2026-04-08 time=11:54:01 (ZB).
[16-04-26 00:01:19.080] ERROR: General f:0, t:1776297679080, st:48,648,194,258> DebugFileWatcher.registerDir> Exception thrown
java.nio.file.NoSuchFileException: /placeholder/config/mods at UnixException.translateToIOException(null:-1).
Stack trace:
java.base/sun.nio.fs.UnixException.translateToIOException(Unknown Source)
java.base/sun.nio.fs.UnixException.asIOException(Unknown Source)
java.base/sun.nio.fs.LinuxWatchService$Poller.implRegister(Unknown Source)
java.base/sun.nio.fs.AbstractPoller.processRequests(Unknown Source)
java.base/sun.nio.fs.LinuxWatchService$Poller.run(Unknown Source)
[16-04-26 00:01:19.131] LOG : Mod f:0, t:1776297679131, st:48,648,194,309> loading example_mod_alpha.
[16-04-26 00:01:19.142] LOG : Mod f:0, t:1776297679142, st:48,648,194,320> loading example_mod_beta.
[16-04-26 00:01:19.155] LOG : Mod f:0, t:1776297679155, st:48,648,194,333> loading example_mod_gamma.
[16-04-26 00:01:19.200] WARN : Mod f:0, t:1776297679200, st:48,648,194,378> ZomboidFileSystem.loadModAndRequired> required mod "absent_mod" not found.
[16-04-26 00:01:45.937] ERROR: WorldGen f:0, t:1776297705937, st:48,648,221,115> IsoPropertyType.lookupOrDefaultStr> Exception thrown
zombie.core.properties.IsoPropertyType$IsoPropertyTypeNotFoundException: Property Name not found: ladderW at IsoPropertyType.lookup(IsoPropertyType.java:269). Message: Property Name not found: ladderW
at zombie.core.properties.IsoPropertyType.lookup(IsoPropertyType.java:269)
at zombie.iso.IsoChunkData.PostProcessChunk(IsoChunkData.java:512)
[16-04-26 00:02:00.000] LOG : General f:0, t:1776297720000, st:48,648,235,178> server initialised.
[16-04-26 00:05:00.000] LOG : General f:0, t:1776297900000, st:48,648,415,178> shutdown requested.

View File

@@ -0,0 +1,67 @@
<?php
namespace IndifferentKetchup\Codex\Test\Tests\Games\ProjectZomboid\Log;
use IndifferentKetchup\Codex\Detective\Detective;
use IndifferentKetchup\Codex\Log\File\PathLogFile;
use IndifferentKetchup\Codex\Log\Level;
use IndifferentKetchup\Codex\Log\ProjectZomboid\ProjectZomboidServerLog;
use PHPUnit\Framework\TestCase;
class ProjectZomboidServerLogTest extends TestCase
{
private function fixturePath(): string
{
return __DIR__ . '/../../../../src/Games/ProjectZomboid/fixtures/debug-server-minimal.txt';
}
public function testParsesEntriesWithLevelAndPrefix(): void
{
$log = (new ProjectZomboidServerLog())->setLogFile(new PathLogFile($this->fixturePath()));
$log->parse();
$entries = $log->getEntries();
$this->assertNotEmpty($entries);
$first = $entries[0];
$this->assertSame('General', $first->getPrefix());
$this->assertSame(Level::INFO, $first->getLevel());
$this->assertNotNull($first->getTime());
}
public function testStackTraceLinesAttachToTriggeringErrorEntry(): void
{
$log = (new ProjectZomboidServerLog())->setLogFile(new PathLogFile($this->fixturePath()));
$log->parse();
$errorEntry = null;
foreach ($log->getEntries() as $entry) {
if ($entry->getLevel() === Level::ERROR && $entry->getPrefix() === 'General') {
$errorEntry = $entry;
break;
}
}
$this->assertNotNull($errorEntry);
$this->assertGreaterThan(1, count($errorEntry->getLines()));
}
public function testWarnLevelMapsCorrectly(): void
{
$log = (new ProjectZomboidServerLog())->setLogFile(new PathLogFile($this->fixturePath()));
$log->parse();
$warnEntries = array_filter($log->getEntries(), fn($e) => $e->getLevel() === Level::WARNING);
$this->assertNotEmpty($warnEntries);
}
public function testDetectiveDispatchesByContent(): void
{
$detective = (new Detective())
->setLogFile(new PathLogFile($this->fixturePath()))
->addPossibleLogClass(ProjectZomboidServerLog::class);
$log = $detective->detect();
$this->assertInstanceOf(ProjectZomboidServerLog::class, $log);
}
}