Hytale Logging Skill
Use this skill when adding logging to Hytale plugins. Hytale provides HytaleLogger, a Flogger-based logger (com.google.common.flogger.AbstractLogger) that writes to the server's log file at {Hytale install}/UserData/Saves/{World}/logs.
Quick Reference
| Concept | Description |
|---|---|
| HytaleLogger | Main logging API, extends AbstractLogger from Google Flogger |
| Package | com.hypixel.hytale.logger.HytaleLogger |
| Log Levels | atInfo(), atWarning(), atSevere() (default visible levels) |
| Arguments | printf-style format specifiers (%s, %d, %f, %b, %c) |
| Exceptions | .withCause(exception) to attach stack traces |
| Backend | HytaleLoggerBackend — manages log levels and sinks |
Creating a Logger
Use HytaleLogger.forEnclosingClass() to create a logger scoped to the current class. Declare it as a public static final field so it can be reused across the plugin.
import com.hypixel.hytale.logger.HytaleLogger;
public class ExamplePlugin extends JavaPlugin {
public static final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass();
@Override
protected void setup() {
LOGGER.atInfo().log("ExamplePlugin loaded");
}
}
Named Logger
You can also create a logger with a custom name. The name appears before the log message in the log file for easier identification.
HytaleLogger LOGGER = HytaleLogger.get("MyPluginName");
Using the Logger from Other Classes
Reference the static logger from your main plugin class:
ExamplePlugin.LOGGER.atInfo().log("hello world");
Log Levels
Only Info, Warning, and Severe messages are printed with default configuration.
| Method | Purpose | When to Use |
|---|---|---|
atInfo() | Informational messages | Normal behavior, startup, state changes |
atWarning() | Potential problems | Situations that could lead to errors |
atSevere() | Serious errors | Failures that prevent correct operation |
LOGGER.atInfo().log("Provide high-level information about normal behavior.");
LOGGER.atWarning().log("Signal a potential problem or a situation that could lead to an error.");
LOGGER.atSevere().log("A serious error that will prevent things from working as expected.");
Template Arguments (printf-style)
HytaleLogger uses printf-style format specifiers. Pass arguments after the format string — do NOT use string concatenation.
Common Specifiers
| Specifier | Type | Example |
|---|---|---|
%s | String | "Hello %s", name → Hello World |
%d | Integer | "Count: %d", 42 → Count: 42 |
%f | Float/Double | "Value: %f", 3.14 → Value: 3.140000 |
%b | Boolean | "Active: %b", true → Active: true |
%c | Char | "Letter: %c", 'A' → Letter: A |
Example
final String name = "World";
LOGGER.atInfo().log("Hello %s", name);
// prints: Hello World
int count = 5;
LOGGER.atInfo().log("Found %d items for player %s", count, playerName);
Why printf-style over concatenation?
- •Performance: Arguments are only evaluated if the log level is active
- •Consistency: Matches Flogger conventions
- •Safety: Avoids null pointer issues with string concatenation
Exceptions and Causes
Attach exceptions to log messages using .withCause(exception) to include the full stack trace.
try {
// risky operation
} catch (IOException e) {
LOGGER.atSevere().withCause(e).log("Failed to load configuration file");
}
Chaining with Arguments
try {
loadResource(path);
} catch (Exception e) {
LOGGER.atSevere().withCause(e).log("Failed to load resource: %s", path);
}
Best Practices
- •Use
forEnclosingClass()— Automatically scopes the logger to the class; no manual name changes needed when refactoring. - •Prefer
atInfo()for normal flow — ReserveatWarning()andatSevere()for actual problems. - •Use printf-style arguments — Never concatenate strings in log calls; arguments are lazily evaluated.
- •Always attach exceptions — Use
.withCause(e)instead of logginge.getMessage()to preserve stack traces. - •Declare logger as
public static final— Allows reuse across the plugin and from other classes. - •Don't over-log — Excessive
atInfo()in tick loops will flood the log file and hurt performance.
Complete Example
import com.hypixel.hytale.logger.HytaleLogger;
import com.hypixel.hytale.server.pluginframework.JavaPlugin;
public class MyPlugin extends JavaPlugin {
public static final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass();
@Override
protected void setup() {
LOGGER.atInfo().log("MyPlugin setup starting");
try {
initializeSystems();
LOGGER.atInfo().log("MyPlugin setup complete — %d systems initialized", systemCount);
} catch (Exception e) {
LOGGER.atSevere().withCause(e).log("MyPlugin setup failed");
}
}
@Override
protected void start() {
LOGGER.atInfo().log("MyPlugin started");
}
private void onPlayerAction(String playerName, String action) {
LOGGER.atInfo().log("Player %s performed action: %s", playerName, action);
}
}
Internal Details (Reference Only)
| Class | Package | Role |
|---|---|---|
HytaleLogger | com.hypixel.hytale.logger | Main logging API |
HytaleLoggerBackend | com.hypixel.hytale.logger.backend | Backend, log levels, sinks |
HytaleFileHandler | com.hypixel.hytale.logger | File-based log output |
HytaleLogManager | com.hypixel.hytale.logger | Log manager integration |
- •
HytaleLogger.init()— Initializes the logging backend (called during server boot). - •
HytaleLogger.replaceStd()— RedirectsSystem.out/System.errinto logger streams. - •Log files are written to
{Hytale install}/UserData/Saves/{World}/logs.