Class LogStreamManager
- All Implemented Interfaces:
org.bukkit.event.Listener
- Version:
- 2.0.0
- Author:
- UltiKits
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionprivate static final classParsed, validatedbatchConfigsection; each field is null when not present in the request.private static final classParsed, validatedlevelssection of a config-update request;LogStreamManager.LevelsSection.presentis false if absent. -
Field Summary
FieldsModifier and TypeFieldDescriptionprivate final com.google.gson.Gsonprivate static LogStreamManagerprivate UltiPanelLogTransmitterprivate SystemLogHandlerThe only level namesSystemLogHandlerever recognises -- exactly the vocabulary its own level mapping can produce ("info"/"warning"/"error"/"debug"), so a level a client asks to enable can always actually be reached by a published record's mapped level.private UltiPanelWebSocketClient -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionprivate voidapplyBatchConfig(LogStreamManager.BatchConfigSection batchConfig, List<String> changes) Applies an already-validatedbatchConfigsection (if present) and appends a description tochanges-- extracted fromhandleConfigUpdate(JsonObject, String)alongsideapplyLevels(LevelsSection, List)(Codacy Gate-2 NPath complexity finding).private voidapplyLevels(LogStreamManager.LevelsSection levels, List<String> changes) Applies an already-validatedlevelssection (if present) and appends a description tochanges-- extracted fromhandleConfigUpdate(JsonObject, String)alongsideapplyBatchConfig(BatchConfigSection, List)(Codacy Gate-2 NPath complexity finding).private voidDetaches every one of this framework'sSystemLogHandlerinstances from the JVM root logger.static LogStreamManagerDeprecated, for removal: This API element is subject to removal in a future version.There is no replacement: the framework's own UltiCloud session (protocol 2.0.0) streams the console itself.private StringGets the server ID.private voidhandleConfigUpdate(com.google.gson.JsonObject data, String clientId) Handles a configuration update.voidhandleLogStreamMessage(com.google.gson.JsonObject data) Deprecated, for removal: This API element is subject to removal in a future version.There is no replacement: the framework's own UltiCloud session (protocol 2.0.0) streams the console itself.voidinitialize(UltiPanelWebSocketClient client) Deprecated, for removal: This API element is subject to removal in a future version.There is no replacement: the framework never calls it, and its own UltiCloud session (protocol 2.0.0) streams the console itself.private booleanisDirectLevelEnabled(String level) Decides whether a log entry this class sends directly, rather than throughSystemLogHandler.publish(java.util.logging.LogRecord), may be sent atlevel(case 29b95cd4).private voidLoads the batch-send configuration from the config file.voidonPlayerJoin(org.bukkit.event.player.PlayerJoinEvent event) Deprecated, for removal: This API element is subject to removal in a future version.There is no replacement: the framework's own UltiCloud session (protocol 2.0.0) streams the console itself.voidonPlayerQuit(org.bukkit.event.player.PlayerQuitEvent event) Deprecated, for removal: This API element is subject to removal in a future version.There is no replacement: the framework's own UltiCloud session (protocol 2.0.0) streams the console itself.voidonServerLoad(org.bukkit.event.server.ServerLoadEvent event) Deprecated, for removal: This API element is subject to removal in a future version.There is no replacement: the framework's own UltiCloud session (protocol 2.0.0) streams the console itself.private booleanparseAndValidateBatchConfig(com.google.gson.JsonObject data, String clientId, LogStreamManager.BatchConfigSection out) Parses and validates thebatchConfigobject from a config-update request intoout, WITHOUT applying it (extracted fromhandleConfigUpdate(JsonObject, String), Codacy Gate-2 NPath complexity finding).private booleanparseAndValidateBatchEnabled(com.google.gson.JsonObject batchConfig, String clientId, LogStreamManager.BatchConfigSection out) Parses and validatesbatchConfig.enabledintoout-- extracted fromparseAndValidateBatchConfig(JsonObject, String, BatchConfigSection)alongside its two siblings (Codacy Gate-2 NPath complexity finding, round 7: the combined method peaked at 540 against a threshold of 200 once the round-6 strict-type checks were added inline).private booleanparseAndValidateBatchInterval(com.google.gson.JsonObject batchConfig, String clientId, LogStreamManager.BatchConfigSection out) Parses and validatesbatchConfig.intervalintoout-- seeparseAndValidateBatchEnabled(JsonObject, String, BatchConfigSection)'s javadoc for why this is a separate method.private booleanparseAndValidateBatchSize(com.google.gson.JsonObject batchConfig, String clientId, LogStreamManager.BatchConfigSection out) Parses and validatesbatchConfig.sizeintoout-- seeparseAndValidateBatchEnabled(JsonObject, String, BatchConfigSection)'s javadoc for why this is a separate method.private booleanparseAndValidateLevels(com.google.gson.JsonObject data, String clientId, LogStreamManager.LevelsSection out) Parses and validates thelevelsarray from a config-update request intoout, WITHOUT applying it (extracted fromhandleConfigUpdate(JsonObject, String), Codacy Gate-2 NPath complexity finding).private IntegerparseStrictInt(com.google.gson.JsonElement element, String fieldName, String clientId) Parseselementas a strict Javaint-- rejects a non-numeric value, a non-integral number (e.g.private voidsendControlActionRejection(String clientId, String action) Rejects astart/stop/pause/resumerequest (D-19/D-20, maintainer decisions 2026-09-14/2026-09-15).voidsendCustomLog(String level, String message, String source) Deprecated, for removal: This API element is subject to removal in a future version.There is no replacement: the framework's own UltiCloud session (protocol 2.0.0) streams the console itself.private voidsendErrorResponse(String clientId, String error) Sends an error response.private voidSends the initialization-complete logs.voidsendPlayerEventLog(String eventType, String playerName, String message) Deprecated, for removal: This API element is subject to removal in a future version.There is no replacement: the framework's own UltiCloud session (protocol 2.0.0) streams the console itself.voidsendPluginActionLog(String action, String details) Deprecated, for removal: This API element is subject to removal in a future version.There is no replacement: the framework's own UltiCloud session (protocol 2.0.0) streams the console itself.private voidsendStreamResponse(String clientId, String status, String message) Sends a stream response message (used by theconfigaction's acknowledgment).private voidsendStreamStatus(String clientId) Sends the stream status (D-20, maintainer decision 2026-09-15).voidshutdown()Shuts down the log stream manager.
-
Field Details
-
VALID_LOG_LEVELS
The only level namesSystemLogHandlerever recognises -- exactly the vocabulary its own level mapping can produce ("info"/"warning"/"error"/"debug"), so a level a client asks to enable can always actually be reached by a published record's mapped level. -
instance
-
webSocketClient
-
gson
private final com.google.gson.Gson gson -
logTransmitter
-
systemLogHandler
-
-
Constructor Details
-
LogStreamManager
private LogStreamManager()
-
-
Method Details
-
getInstance
-
initialize
Deprecated, for removal: This API element is subject to removal in a future version.There is no replacement: the framework never calls it, and its own UltiCloud session (protocol 2.0.0) streams the console itself. Removed in 6.4.0.Initializes the log stream manager.- Scheduled removal version:
- 6.4.0
-
loadBatchConfiguration
private void loadBatchConfiguration()Loads the batch-send configuration from the config file. -
sendInitializationLogs
private void sendInitializationLogs()Sends the initialization-complete logs. Both lines are direct entries at"info"and obey the panel's levels like every other direct entry (isDirectLevelEnabled(java.lang.String)). -
handleLogStreamMessage
@Deprecated(since="6.3.1", forRemoval=true) public void handleLogStreamMessage(com.google.gson.JsonObject data) Deprecated, for removal: This API element is subject to removal in a future version.There is no replacement: the framework's own UltiCloud session (protocol 2.0.0) streams the console itself. Removed in 6.4.0.Handles a log stream message.- Scheduled removal version:
- 6.4.0
-
handleConfigUpdate
Handles a configuration update.#433: a request naming an unrecognised level rejects the WHOLE request (previously-applied levels are left untouched) rather than partially applying the recognised entries -- a client that made a typo should not silently end up with a different filter than it asked for. An empty
levelsarray is applied literally: it is a request for zero levels, so zero levels are enabled and nothing is delivered until the client sets levels again -- this framework's own front end never actually sends this field today (measured against bothUltiPanelFrontendandultipanel-api-workerwhile planning this fix), so there is no real product behaviour to match, and applying the request literally is the one reading that never has to guess what the caller "really" meant.Gate-2 finding: BOTH the
levelssection and thebatchConfigsection are parsed and validated FIRST, before either is applied. Before this fix,levelswas applied immediately upon parsing; a request combining validlevelswith an invalidbatchConfigfield left the levels change already in effect by the time thebatchConfigvalidation failed and returned an error for the WHOLE request -- the same "declared rejection, partial effect" defect WR-02 already closed withinbatchConfigalone, reoccurring one level up, across the two top-level sections. -
applyLevels
Applies an already-validatedlevelssection (if present) and appends a description tochanges-- extracted fromhandleConfigUpdate(JsonObject, String)alongsideapplyBatchConfig(BatchConfigSection, List)(Codacy Gate-2 NPath complexity finding). -
applyBatchConfig
private void applyBatchConfig(LogStreamManager.BatchConfigSection batchConfig, List<String> changes) Applies an already-validatedbatchConfigsection (if present) and appends a description tochanges-- extracted fromhandleConfigUpdate(JsonObject, String)alongsideapplyLevels(LevelsSection, List)(Codacy Gate-2 NPath complexity finding). -
parseAndValidateLevels
private boolean parseAndValidateLevels(com.google.gson.JsonObject data, String clientId, LogStreamManager.LevelsSection out) Parses and validates thelevelsarray from a config-update request intoout, WITHOUT applying it (extracted fromhandleConfigUpdate(JsonObject, String), Codacy Gate-2 NPath complexity finding).out.presentstaysfalseiflevelsis absent from the request orsystemLogHandleris not yet wired -- that is not a rejection.Rejects (sends the error response itself, matching this class's own established "validator sends its own rejection" convention) the WHOLE request if
levelsis present but not a JSON array (Gate-2 round 3), or if any entry is not one ofVALID_LOG_LEVELS(#433) -- previously-applied levels survive either way.- Returns:
trueif absent or valid;falseif rejected -- the caller must return immediately without applying anything from either section
-
parseAndValidateBatchConfig
private boolean parseAndValidateBatchConfig(com.google.gson.JsonObject data, String clientId, LogStreamManager.BatchConfigSection out) Parses and validates thebatchConfigobject from a config-update request intoout, WITHOUT applying it (extracted fromhandleConfigUpdate(JsonObject, String), Codacy Gate-2 NPath complexity finding).out.presentstaysfalseifbatchConfigis absent from the request orlogTransmitteris not yet wired -- that is not a rejection.WR-01/WR-02: every present field is validated before any is applied -- a rejected
sizeorintervalmust not leave the OTHER fields in this samebatchConfigobject already applied.- Returns:
trueif absent or valid;falseif rejected -- the caller must return immediately without applying anything from either section
-
parseAndValidateBatchEnabled
private boolean parseAndValidateBatchEnabled(com.google.gson.JsonObject batchConfig, String clientId, LogStreamManager.BatchConfigSection out) Parses and validatesbatchConfig.enabledintoout-- extracted fromparseAndValidateBatchConfig(JsonObject, String, BatchConfigSection)alongside its two siblings (Codacy Gate-2 NPath complexity finding, round 7: the combined method peaked at 540 against a threshold of 200 once the round-6 strict-type checks were added inline). -
parseAndValidateBatchSize
private boolean parseAndValidateBatchSize(com.google.gson.JsonObject batchConfig, String clientId, LogStreamManager.BatchConfigSection out) Parses and validatesbatchConfig.sizeintoout-- seeparseAndValidateBatchEnabled(JsonObject, String, BatchConfigSection)'s javadoc for why this is a separate method. -
parseAndValidateBatchInterval
private boolean parseAndValidateBatchInterval(com.google.gson.JsonObject batchConfig, String clientId, LogStreamManager.BatchConfigSection out) Parses and validatesbatchConfig.intervalintoout-- seeparseAndValidateBatchEnabled(JsonObject, String, BatchConfigSection)'s javadoc for why this is a separate method. -
parseStrictInt
private Integer parseStrictInt(com.google.gson.JsonElement element, String fieldName, String clientId) Parseselementas a strict Javaint-- rejects a non-numeric value, a non-integral number (e.g.1.9), and a value outsideintrange (Gate-2 finding, round 6: Gson'sgetAsInt()silently truncates a fractional value and can wrap an out-of-range one, rather than validating that the payload is genuinely an integer). Sends the rejection response itself, matching this class's other validators.- Returns:
- the parsed value, or
nullif invalid (rejection response already sent)
-
sendControlActionRejection
Rejects astart/stop/pause/resumerequest (D-19/D-20, maintainer decisions 2026-09-14/2026-09-15).This framework has no per-viewer identity to gate any of these four actions with: the delivery messages (
log_stream/log_batch) carry no per-client address at all --UltiPanelLogTransmitter.sendLog(java.lang.String, java.lang.String, java.lang.String, java.lang.Throwable)broadcasts once over the single WebSocket connection this server holds to the panel relay, which fans a delivered record out to however many browser viewers are subscribed on that connection, invisibly to this framework. A server-side "real" implementation of any of the four would necessarily silence or resume delivery for every viewer of the server at once, not the one browser tab that asked.pause/resume(D-19): #434's original fix (a global "does any subscriber want delivery" check) could never actually suppress anything in production, becauseinitialize(com.ultikits.ultitools.websocket.UltiPanelWebSocketClient)used to permanently subscribe a synthetic"auto"client that was never paused -- see16-REVIEW-panel.mdCR-01.start/stop(D-20, issue #468): measured end to end -- the shipped frontend sendsstart/stoponly from its own toggle button and never gates rendering on the toggle state; the Worker's REST endpoint is a stateless relay minting a disposableclientIdper call with no per-browser stream state anywhere in its Durable Object; and this framework's own (now-removed)stopLogStreammutated only its own internal bookkeeping, which nothing on the delivery path ever consulted.stopnever actually stopped delivery for any real client, on any released version, before or after this change -- it changes only the response, not the underlying (already-inert) behaviour.The framework states plainly instead: it streams logs to the panel for as long as it is connected, with no per-viewer on/off state to toggle. Turning the live view on/off, or pausing/resuming it, is the panel view's own concern (stop/start rendering, optionally buffer client-side) -- not a request this server can selectively honour for one viewer. The removed
startLogStream(String, String)/startLogStream(String)/stopLogStream(String)/isStreaming()/getSubscriberCount()and (from D-19)pauseLogStream(String)/resumeLogStream(String)public methods are recorded inCOMPATIBILITY.mdunder the same-release exception. -
sendStreamResponse
Sends a stream response message (used by theconfigaction's acknowledgment). -
sendErrorResponse
Sends an error response. -
sendStreamStatus
Sends the stream status (D-20, maintainer decision 2026-09-15).Unlike
start/stop/pause/resume,statusasks nothing to be toggled -- it is a read-only introspection request, and every field it reports is backed by something genuinely tracked, not bookkeeping that no client's request ever actually drove. There is no longer asubscriberCountorstreamingfield: this framework has no concept of an individual subscribed viewer to count (seesendControlActionRejection(java.lang.String, java.lang.String)'s javadoc), and delivery is unconditional once the handler is attached, for as long as the panel connection is up -- which is exactly what the newconnectedfield reports honestly.logTransmitterEnabled/queueSizeare unchanged; both were already backed by realUltiPanelLogTransmitterstate. -
sendCustomLog
@Deprecated(since="6.3.1", forRemoval=true) public void sendCustomLog(String level, String message, String source) Deprecated, for removal: This API element is subject to removal in a future version.There is no replacement: the framework's own UltiCloud session (protocol 2.0.0) streams the console itself. Removed in 6.4.0.Sends a custom log message directly. Used for logging plugin-specific events.The panel's
levelsapply: the entry is sent only if its level is currently enabled in theSystemLogHandler's level state (a null or blank level counts as"info", matched case-insensitively; the level text sent is left as given). The panel'sexcluded-loggersdo not apply, because a direct entry has no logger name.- Scheduled removal version:
- 6.4.0
-
isDirectLevelEnabled
Decides whether a log entry this class sends directly, rather than throughSystemLogHandler.publish(java.util.logging.LogRecord), may be sent atlevel(case 29b95cd4).The handler stays the single level state: this reads its current enabled set on every call, so a panel
configrequest governs direct entries and handler records alike. A null or blank level counts as"info", asUltiPanelLogTransmitterrecords it; the comparison lower-cases withLocale.ROOTbecause the handler's set is lower case. With no handler wired yet there is no level state to apply and the entry is sent as before. -
sendPlayerEventLog
@Deprecated(since="6.3.1", forRemoval=true) public void sendPlayerEventLog(String eventType, String playerName, String message) Deprecated, for removal: This API element is subject to removal in a future version.There is no replacement: the framework's own UltiCloud session (protocol 2.0.0) streams the console itself. Removed in 6.4.0.Sends a player-event log at"info".The panel's
levelsapply, as forsendCustomLog(java.lang.String, java.lang.String, java.lang.String); the panel'sexcluded-loggersdo not, because a direct entry has no logger name.- Scheduled removal version:
- 6.4.0
-
sendPluginActionLog
@Deprecated(since="6.3.1", forRemoval=true) public void sendPluginActionLog(String action, String details) Deprecated, for removal: This API element is subject to removal in a future version.There is no replacement: the framework's own UltiCloud session (protocol 2.0.0) streams the console itself. Removed in 6.4.0.Sends a plugin-action log at"info".The panel's
levelsapply, as forsendCustomLog(java.lang.String, java.lang.String, java.lang.String); the panel'sexcluded-loggersdo not, because a direct entry has no logger name.- Scheduled removal version:
- 6.4.0
-
onPlayerJoin
@Deprecated(since="6.3.1", forRemoval=true) public void onPlayerJoin(org.bukkit.event.player.PlayerJoinEvent event) Deprecated, for removal: This API element is subject to removal in a future version.There is no replacement: the framework's own UltiCloud session (protocol 2.0.0) streams the console itself. Removed in 6.4.0.Sends a protocol v1 join line; does nothing without a v1 transmitter.- Scheduled removal version:
- 6.4.0
-
onPlayerQuit
@Deprecated(since="6.3.1", forRemoval=true) public void onPlayerQuit(org.bukkit.event.player.PlayerQuitEvent event) Deprecated, for removal: This API element is subject to removal in a future version.There is no replacement: the framework's own UltiCloud session (protocol 2.0.0) streams the console itself. Removed in 6.4.0.Sends a protocol v1 quit line; does nothing without a v1 transmitter.- Scheduled removal version:
- 6.4.0
-
onServerLoad
@Deprecated(since="6.3.1", forRemoval=true) public void onServerLoad(org.bukkit.event.server.ServerLoadEvent event) Deprecated, for removal: This API element is subject to removal in a future version.There is no replacement: the framework's own UltiCloud session (protocol 2.0.0) streams the console itself. Removed in 6.4.0.Sends a protocol v1 "server loaded" line; does nothing without a v1 transmitter.- Scheduled removal version:
- 6.4.0
-
getServerId
Gets the server ID. -
getLogTransmitter
Deprecated, for removal: This API element is subject to removal in a future version.There is no replacement: the framework's own UltiCloud session (protocol 2.0.0) streams the console itself. Removed in 6.4.0.The protocol v1 transmitterinitialize(UltiPanelWebSocketClient)built, ornullbefore that (always, as of 6.3.1, unless a caller hands in a v1 client).- Returns:
- the v1 transmitter, possibly
null - Scheduled removal version:
- 6.4.0
-
shutdown
public void shutdown()Shuts down the log stream manager. -
detachAllSystemLogHandlers
private void detachAllSystemLogHandlers()Detaches every one of this framework'sSystemLogHandlerinstances from the JVM root logger.Deliberately scans by type and removes every instance, rather than only removing
this.systemLogHandler: before this method existed, every successful reconnect attached one more to the root logger, the field could only ever hold onto the last one, and the previously-leaked ones had no reference pointing at them any more and so could never be detached. Only a type-based scan can clean up the whole historical backlog at once, and that is also the only formulation under which the acceptance criterion "handler count is always 1" can hold. See issue #181.
-