Repository navigation
Audit Log
"Who paid what, to whom, and when?" - a shop, a trade plugin or a quest plugin answers it with an AuditLog
(package br.com.finalcraft.evernifecore.logic.audit): a persisted record of what that plugin moved, in its own
storage, with retention and a query a command can page.
AuditLog log = AuditLog.of(getPluginData(), storage); // 30 days kept
AuditLog forever = AuditLog.of(getPluginData(), storage, AuditRetention.forever());
log.query(new AuditQuery().between(alex, bia).since(Instant.now().minus(Duration.ofDays(7))))
.thenAccept(entries -> entries.forEach(entry -> sender.sendMessage(AuditCommandNode.line(entry))));The in-memory AuditTrail of one run is a different thing (see Logic); the log is
what survives.
While open, the log listens on ECEventBus.global() and records only what its owner moved - the events whose
Caller is that plugin:
| Kind | From |
|---|---|
GATE_PAID, GATE_DENIED
|
the plugin's gates |
REFUND_FAILED |
a cost refund that failed |
BALANCE_CHANGE |
a BalanceChangeEvent (the legs of a transfer are covered by the transfer) |
TRANSFER |
a TransferEvent: the payer as getPlayer(), the receiver as getCounterparty()
|
DELIVERY_ENQUEUED, DELIVERY_CLAIMED, DELIVERY_EXPIRED, DELIVERY_PURGED, DELIVERY_DISCARDED
|
the plugin's deliveries |
BOOSTER_GRANTED |
its BoosterManager.grant (Boosters) |
REWARD_PAID |
each member a Rewards.pay of the plugin paid, applied or delivered - the subject is the reward's owner (Groups) |
DEPOSIT |
a deposit to one of its contributions (Dynamic Values) |
record(entry) adds anything else; record(trail) files a run's AuditTrail (costs taken and refunded, refunds that
failed, effects applied or failed - an effect that audited its own EFFECT_FAILED is not also EFFECT_APPLIED).
Writing never waits: the entry is stored off the calling thread; awaitWrites() (for tests and shutdown) completes when
every write started so far landed, a failed one too (it was logged).
getId(), getKind(), getCaller() (plugin and origin), getOwner(), getInstant(), getText(), getAmount(),
getPlayer(), getCounterparty() (the other party of a transfer, a trade or a give; null when none), getSubject()
(the currency, item or variable id). Build one with AuditEntry.builder(kind, caller) -
.player(uuid).counterparty(uuid).subject("money").amount(price).text("...").build().
Each call narrows; none is required. Newest first, 50 at most unless limit says otherwise. Short-lived, not
thread-safe: build it where it is used.
| Call | Keeps |
|---|---|
player(uuid) / counterparty(uuid)
|
entries of that player / with that other party |
between(a, b) |
entries where a and b are player and counterparty, in either order |
since(instant) |
entries from that instant on |
kind(AuditKind) |
one kind |
limit(n) |
at most n
|
Collection ec_audit, indexed by at, player, kind and counterparty. AuditRetention.days(n) (30 by default)
or AuditRetention.forever(); the old entries are swept once an hour (ECDebugModule.AUDIT logs how many). One log
per plugin: AuditLog.ofIfPresent(owner), closed at the owner's shutdown (AuditLog.closeOwnedBy).
A plugin mounts the view on its own command:
@FinalCMD.Node(subcmd = "log", permission = "awshop.command.awshop.log")
private final AuditCommandNode log = new AuditCommandNode(auditLog, "awshop.command.awshop.log");/awshop log [--player Steve] [--since 2h] [--kind transfer] [--page 2], or positionally /awshop log view [player] [since] [kind] [page], pages the entries, newest first, 20 a page:
at | kind | player | counterparty | subject amount | caller origin. Every view needs <permissionBase>.view
(awshop.command.awshop.log.view), checked before any argument is read.
For debugging, /ecore logic audit <plugin> [player] [since] [--page] (permission
evernifecore.command.logic.audit) shows the same page for any plugin that has a log.
LogicWorld.auditLog() is the fake plugin's log over an in-memory storage; LogicWorld.awaitAudit() waits on its
awaitWrites() before a query, instead of polling. A node is driven through the
Commands harness like any command (see Testing Toolkit).
EverNifeCore · Home · made by Petrus Pradella
Getting Started
Commands & Text
Player Data & Storage
- PlayerData & PDSections
- Accounts
- Storage Backends
- Inline Backends for Plugins
- Block Data (SVWorldDataManager)
- Legacy Data Migration
- Cooldowns
Config & Minecraft Systems
- Configuration
- Logging & Debug Modules
- Events
- Regions
- Groups
- Notifications
- NPCs
- Logic
- Quests
- Provenance
- Scheduler & Threading
- Items & NBT
- Screens
- Dialogues
- Menus
- Integrations
- Economy
- Boosters
- Deliveries
- Audit Log
- Dynamic Values
- Player Ignore
- Version Compatibility
Architecture & Reference