promotional bannermobile promotional banner

Threat Logger

An addon to extract threat data for raid and dungeon encounters for use in external tools.
Back to Files

ThreatLogger-v0.2.0-classic

File nameClassicThreatLogger-ThreatLogger-v0.2.0-classic.zip
Uploader
PmptastyPmptasty
Uploaded
Oct 6, 2026
Downloads
5
Size
23.7 KB
Flavors
Classic
File ID
9075334
Type
R
Release
Supported game versions
  • 1.15.8

What's new

Changelog

[v0.2.0] - 2026-10-05

Fixed

  • Upgrading from v0.1.x would error on load. v0.1.x saved ClassicThreatLoggerDB as { version, encounters }, and the new code read a log it did not have. Superseded by the move to per-character recordings below: the account-wide table is no longer read at all.
  • /ctl instance off did not survive a reload. InitDB loaded each saved setting as Settings.x or Config.x, so a saved false fell through to the true default and instance auto-start switched itself back on at every login. Settings now load when they are not nil.
  • The log grew without limit, was loaded by every character, and slowed every login. maxEntries only printed a warning, twice a second for the rest of the session. The whole log was one account-wide SavedVariables table, which the client reads into memory for every character at every login and /reload; one real save file had reached 101,470 lines and 21 MB. The log is now meant to live for a day or two, for a raid's record keeper to copy out (see Changed). Whether this was a measurable part of the slow startup is not verified.
  • Rows of zeros for units with no threat. When UnitDetailedThreatSituation returned nothing (the unit is not on the mob's threat table) the poll still wrote a row of zeros and false: 58,628 of the 101,470 lines in that save file. Nothing is written for them now.
  • /ctl list cut timestamps at a fixed 26 characters. The timestamp's length depends on the timezone offset (-6 vs +10), so the list showed a stray character or lost one. It now takes everything before the two-space separator.
  • A threat value past 2^31 would raise. The threat column was written with %d, which raises "integer overflow" past 231, and nothing bounds the value the threat API returns. It is now written with %.0f, which prints the same digits. Whether a real fight reaches 231 is not verified.
  • "Active Mob Targets" in /ctl status was always 0. It counted a table nothing ever filled. Status now shows "Mobs in last poll", the number of distinct mobs the latest poll saw.
  • A large recording would have saved a file that does not load, losing everything (peer review of this release). Each line was its own string, and a SavedVariables file is one Lua chunk, which Lua 5.1 refuses past 2^18 - 1 distinct strings ("constant table overflow"; reported for WoW saved files on forum.buffed.de, and reproduced by a spec). That is about 262,000 lines, near 50 MB, under the 170 MB default. A file that fails to load arrives as nil, InitDB replaced it with an empty table, and the next logout saved that over every recording. Lines are now stored in 16 KB blocks (see Changed), which puts the largest limit, 1000 MB, at 64,000 strings. That the WoW client keeps stock Lua's limit is confirmed by player reports, not by a test in the client.
  • The UTC offset was an hour off during daylight saving time. FormatTimestamp passed date("!*t") to time() with isdst = false, so the UTC fields were read as standard time: -6 in a US Central summer where the client's combat log writes -5. The local daylight flag is now carried over, and a spec pins -5.
  • Timestamps could run backwards within a second. The whole second came from time() and the milliseconds from GetTime(), two clocks with no shared second boundary. Every stamp is now GetTime() plus one offset (CTL:Now), which only ever moves forward, except that a drop of more than 2 seconds (the PC's clock set back) is followed rather than leaving every later stamp ahead.
  • Combat auto-start stopped recordings it had not started. Leaving combat stopped any recording, so with both auto-starts on a raid's recording ended at the first pull and every later pull became its own session; a manual /ctl start ended with the first fight. Each recording now remembers what started it: combat ends only a fight's recording, leaving an instance ends a fight's or the instance's, and a manual one runs until /ctl stop.
  • /ctl interval had no upper bound, so /ctl interval 1e999 handed the ticker infinity. It now takes 0.1 to 10 seconds.
  • /ctl list split every stored line to print the last few, a freeze on a large raid save. It now skips whole recordings by their line count. The Live log also reads the block being written from memory instead of re-splitting 16 KB twice a second.
  • The Live log dropped a selection twice a second. It is no longer refreshed while it has focus, so Ctrl+A, Ctrl+C can copy; it catches up once you click away.

Changed

  • Breaking: recordings are per character, one per session, and delete themselves.
    • ClassicThreatLoggerDB (account-wide log) is replaced by ClassicThreatLoggerCharDB (## SavedVariablesPerCharacter): { version = 3, sessions = { { started, ended, bytes, lines, blocks } } }. lines is the line count and blocks the lines themselves, about 16 KB of lines joined by \n per string (see Fixed). A version 2 recording, one string per line, is repacked into blocks at load. An alt no longer loads the raider's recordings. The old account table is deleted at load and, being no longer listed in the TOC, is not saved again.
    • Kept by age: a recording older than retentionHours (default 48, 1 to 720, /ctl keep) is deleted at login and at PLAYER_LOGOUT, the last event before the file is written.
    • Kept by size: maxMB (default 170, 10 to 1000, /ctl max) is measured from the recordings' actual saved size (CTL:LineBytes: the line, its escaped quotes and backslashes, and the \n the client writes between lines; a spec checks the running total against the file's exact text), and the oldest finished recordings are deleted past it. The default is calculated for a whole 40-player raid night: 40 x 2 readings a second x 3 hours x 200 bytes, rounded up to 10 MB. 200 bytes covers a measured 191-byte raid line; a spec fails if a real line outgrows it.
    • The recording in progress is never deleted, however large, so a raid is always captured whole.
    • The line-count cap (maxEntries, TrimLog) from earlier in this release is gone.
  • /ctl flush (and /ctl clear) ask before deleting, through LibAceGUIWidgets' dialog.
  • Breaking: the log follows the client's combat log layout (log format version 2). Each line is a date-time stamp, two spaces, an event, then a comma-separated payload, as in Logs\WoWCombatLog-*.txt.
    • The stamp is the combat log's own: month and day are no longer zero-padded (8/7/2026, not 08/07/2026), matching 8/17/2026 10:10:26.692-5 in a combat log on this box.
    • Every session opens with CTL_LOG_VERSION,2,ADDON_VERSION,…,BUILD_VERSION,…,PROJECT_ID,…, modelled on COMBAT_LOG_VERSION, and closes with CTL_SESSION_END.
    • Zone and subzone moved out of every row into ZONE_CHANGE,instanceID,"zone",difficultyID (the combat log's own fields) and SUBZONE_CHANGE,"subzone", written only when they change.
    • THREAT_SNAPSHOT is now unitGUID,"unitName",mobGUID,"mobName",isTanking,status,scaledPct,rawPct,threat: unit then mob, as combat log events order their units, then the values in the threat API's return order. isTanking is 1/0 instead of true/false.
  • Removed the <unit>focus lookups. Every poll also read playerfocus, party1focus, raid3focus and so on. Those are not unit tokens: the wiki's UnitToken page lists focus only as the player's own base token, so the lookups never matched. Not checked in-game.
  • Removed dead code: the unused UnitThreatSituation local, the never-read combatStartTime, the never-filled activeEncounters, and CountEntriesInLog, a duplicate of GetLogEntryCount.
  • The addon title in the AddOns list is now in the brand orange.

Added

  • A settings window (/ctl options, ClassicThreatLoggerUI.lua), built on AceGUI-3.0 and LibAceGUIWidgets (ClearFrame, LAGW-Stepper, ShowDialog): the two recording switches, the keep time, the size limit, Delete all recordings, a status line of what is stored, and a Live log (AceGUI MultiLineEditBox) of the newest 30 lines exactly as saved, refreshed after every poll and at start and stop, for checking the format in game. Every control calls the same setter as its slash command (SetRetentionHours, SetMaxMB, SetAutoStart, ...).
  • /ctl keep [hours] and /ctl max [MB]; /ctl status shows both and the stored size.
  • VersionCheck-1.0: registered at load with VC:Enable("ClassicThreatLogger"), the library's documented wiring, so guildmates are told when a newer version is out.
  • Dependencies: ## Dependencies: Ace3, VersionCheck-1.0, LibAceGUIWidgets, and the same three as required-dependencies in .pkgmeta so CurseForge installs them; a spec pins the two together.
  • An offline test suite on the WoWAPITesting harness (Tests/wowapi submodule, Tests/threatlogger_spec.lua): 90 specs, 100% line coverage of both Lua files, loading the installed AceGUI-3.0, LibAceGUIWidgets and VersionCheck-1.0. Run it with lua Tests/wowapi/run.lua from the addon root. Harness pinned at cc6a10c.
  • .luacheckrc, with the WoW globals the addon reads.
  • An MIT LICENSE, the same text as the other Pimptasty addons. The README's "personal use only" line now points to it.

Packaging

  • .pkgmeta: comments removed, Tests ignored, and the entries that could not work dropped. .git/, .github/, .vscode/ and docs/ had trailing slashes, which the packager turns into patterns that match nothing; dot-folders are pruned by the packager anyway. **/*.ps1 missed root-level files. docs, *.txt, *.ps1 and *.bat matched no file in the repo.