Skip to Content
Hytale logoCommunity-built docsOpen source and updated by the community.
Plugin DevelopmentLogging Best Practices

Logging Best Practices

Proper logging is essential for debugging and monitoring your Hytale plugins. This guide covers the logging APIs and best practices.

Basic Logging

Using Plugin Logger

The recommended way to log from your plugin is using JavaPlugin#getLogger():

public class MyPlugin extends JavaPlugin { @Override protected void setup() { getLogger().atInfo().log("Plugin is setting up..."); } @Override protected void start() { getLogger().atInfo().log("Plugin started successfully!"); } public void someMethod() { getLogger().atFine().log("Processing something..."); getLogger().atWarning().log("This might be a problem"); getLogger().atSevere().log("Something went wrong!"); } }

Log Levels

LevelMethodUse Case
SEVEREatSevere()Errors, exceptions, critical failures
WARNINGatWarning()Potential problems, deprecated usage
INFOatInfo()General information, startup/shutdown
FINEatFine()Debug information
FINERatFiner()More detailed debug
FINESTatFinest()Most verbose debug

Logging with Parameters

// Simple string getLogger().atInfo().log("Player joined: " + playerName); // With exception try { // risky operation } catch (Exception e) { getLogger().atSevere().log("Failed to process", e); } // Formatted message (if supported) getLogger().atInfo().log("Player %s joined world %s", playerName, worldName);

Log File Locations

Client/Launcher Logs

# Windows %APPDATA%\Hytale\UserData\Logs\ # Linux (Flatpak) $HOME/.var/app/com.hypixel.HytaleLauncher/data/Hytale/UserData/Logs/ # macOS ~/Library/Application Support/Hytale/UserData/Logs/

Server Logs

# Relative to server directory ./logs/latest.log ./logs/YYYY-MM-DD-N.log.gz # Archived logs

Finding Your Plugin Logs

Plugin logs appear in the server logs prefixed with your plugin name:

[2026/01/15 14:30:00 INFO] [MyPlugin] Plugin started successfully! [2026/01/15 14:30:01 WARN] [MyPlugin] Configuration file not found, using defaults

Static Logger Access

For utility classes or non-plugin classes, use HytaleLogger:

import com.hypixel.hytale.logger.HytaleLogger; public class MyUtility { private static final HytaleLogger LOGGER = HytaleLogger.getLogger(MyUtility.class); public static void doSomething() { LOGGER.atInfo().log("Doing something..."); } }

Logging Patterns

Startup/Shutdown Logging

@Override protected void setup() { getLogger().atInfo().log("=== MyPlugin Setup ==="); getLogger().atInfo().log("Version: " + getManifest().getVersion()); getLogger().atInfo().log("Registering commands..."); // register commands getLogger().atInfo().log("Registering events..."); // register events getLogger().atInfo().log("=== Setup Complete ==="); } @Override protected void shutdown() { getLogger().atInfo().log("Shutting down MyPlugin..."); // cleanup getLogger().atInfo().log("Goodbye!"); }

Error Handling with Context

public void processPlayer(Player player) { try { // risky operation database.savePlayer(player); } catch (DatabaseException e) { getLogger().atSevere().log( "Failed to save player data for: " + player.getName() + " (UUID: " + player.getUUID() + ")", e ); } }

Debug Logging

public void complexOperation(String input) { getLogger().atFine().log("Starting complex operation with input: " + input); // Step 1 getLogger().atFiner().log("Step 1: Validating input..."); if (!isValid(input)) { getLogger().atWarning().log("Invalid input received: " + input); return; } // Step 2 getLogger().atFiner().log("Step 2: Processing..."); String result = process(input); getLogger().atFine().log("Operation complete. Result: " + result); }

Conditional Logging

For expensive log operations, check if level is enabled:

// Good for expensive toString() calls if (getLogger().isLoggable(Level.FINE)) { getLogger().atFine().log("Complex object state: " + complexObject.toDetailedString()); }

Server Log Configuration

Configure log levels in config.json:

{ "logLevels": { "MyPlugin": "FINE", "com.hypixel.hytale.server": "INFO", "com.hypixel.hytale.network": "WARNING" } }

Log Level Per Package

{ "logLevels": { "com.example.myplugin": "FINE", "com.example.myplugin.commands": "INFO", "com.example.myplugin.debug": "FINEST" } }

Common Mistakes

Mistake 1: Using System.out

// WRONG - Goes to stdout, not log files System.out.println("Debug: " + value); // CORRECT - Uses proper logging getLogger().atInfo().log("Debug: " + value);

Mistake 2: Expensive String Concatenation

// WRONG - String concatenation happens even if log level disabled getLogger().atFine().log("Data: " + expensiveObject.toString()); // CORRECT - Check log level first if (getLogger().isLoggable(Level.FINE)) { getLogger().atFine().log("Data: " + expensiveObject.toString()); }

Mistake 3: Logging Sensitive Data

// WRONG - Don't log passwords, tokens, etc. getLogger().atInfo().log("User login: " + username + " password: " + password); // CORRECT - Mask or omit sensitive data getLogger().atInfo().log("User login: " + username);

Mistake 4: Over-Logging in Hot Paths

// WRONG - Logging every tick causes performance issues @Override public void onTick() { getLogger().atInfo().log("Tick!"); // 30 times per second! } // CORRECT - Log occasionally or at debug level private int tickCount = 0; @Override public void onTick() { tickCount++; if (tickCount % 600 == 0) { // Every 20 seconds getLogger().atFine().log("Processed 600 ticks"); } }

Sentry Integration

The server includes Sentry for error reporting. Severe errors are automatically sent to Sentry if configured.

// Severe errors with exceptions are captured by Sentry try { criticalOperation(); } catch (Exception e) { // This will be sent to Sentry if configured getLogger().atSevere().log("Critical failure in operation", e); }

Reading Logs

Linux/macOS

# Follow latest log tail -f logs/latest.log # Search for plugin messages grep "MyPlugin" logs/latest.log # Search for errors grep -E "(SEVERE|ERROR)" logs/latest.log # Last 100 lines tail -100 logs/latest.log

Windows PowerShell

# Follow latest log Get-Content logs\latest.log -Wait # Search for plugin messages Select-String "MyPlugin" logs\latest.log

Summary

TaskApproach
Plugin logginggetLogger().atLevel().log()
Utility class loggingHytaleLogger.getLogger(Class)
Error logginggetLogger().atSevere().log(msg, exception)
Debug logginggetLogger().atFine().log() with level check
Log configurationlogLevels in config.json

Next Steps

Last updated on