Logging and Debugging

OmegaT uses a flexible logging system based on the Java Logging API (JUL) with an SLF4J bridge. This allows developers and users to control the level of detail recorded in log files. OmegaT also use a slf4j-format-jdk14 library to format log messages with placefolder syntax “{0}” as same as JUL standard.

Logging in Code

The Log Class

The primary entry point for logging is the org.omegat.util.Log class. It provides static methods for different logging levels.

  • Log.log(String message): Logs an informational message.

  • Log.log(Throwable throwable): Logs an exception with its stack trace.

  • Log.logDebug(String message, Object... params): Logs a debug message.

  • Log.isDebugEnabled(): Checks if debug logging is enabled.

Localized Logging (Resource Bundles)

OmegaT supports localized logging using resource bundles. This is useful for user-facing logs that might need translation, although developers generally prefer the technical keys for troubleshooting.

  • Log.logRB(String key, Object... params): Info level.

  • Log.logWarningRB(String key, Object... params): Warning level.

  • Log.logErrorRB(String key, Object... params): Error level.

  • Log.logErrorRB(Throwable throwable, String key, Object...): Error level with exception.

Example:

Log.logErrorRB("TF_ERROR_WHILE_READING_CONFIG_FILE", fileName);

Testing with a specific locale for log message assertions

OmegaT has a fixture that allows you to set the locale for testing.

The LocaleRule is a JUnit test rule located in test/fixtures/org/omegat/util/LocaleRule.java that allows tests to temporarily change the default locale for the duration of a test. This is particularly useful when testing localized log messages to ensure they appear in the expected language.

The ILogger Interface

For more fine-grained control or when working in specific modules, you can get a logger instance:

private static final ILogger LOGGER = Log.getLogger(MyClass.class);

The ILogger interface provides a fluent API:

LOGGER.atDebug().setMessage("Starting process").log();

Log Files Location

By default, OmegaT stores its log files in the logs subdirectory of the user configuration directory.

  • Windows: %APPDATA%\OmegaT\logs

  • macOS: ~/Library/Preferences/OmegaT/logs

  • Linux: ~/.omegat/logs

The current log file is named using the pattern OmegaT_YYYY-MM-DD_HH-mm_######.log, where:

  • YYYY-MM-DD_HH-mm is the session start time.

  • ###### is a random 5-digit session ID.

Older logs are rotated when they exceed a certain size, and a retention policy limits the number or age of kept logs.

Logging Utility Classes

OmegaT uses custom implementations for log file handling and formatting to meet specific requirements like session-based naming and localized formatting.

OmegaTFileHandler

org.omegat.util.logging.OmegaTFileHandler is a custom java.util.logging.StreamHandler that manages OmegaT’s log files.

  • Log File Naming: It generates unique log file names for each session to avoid conflicts when multiple instances of OmegaT are running. The format is: ${AppName}_${yyyy-MM-dd_HH-mm}_${SessionID}.log

  • Locking: It uses .lck files to ensure that only one instance writes to a specific log file.

  • Rotation and Retention: It supports rotating logs based on size and removing old logs based on count or age.

    • org.omegat.util.logging.OmegaTFileHandler.size: Maximum size of a log file before rotation (default: 1MB).

    • org.omegat.util.logging.OmegaTFileHandler.count: Maximum number of log files to keep (default: 30).

    • org.omegat.util.logging.OmegaTFileHandler.retention: Time in seconds to keep log files (default: 20 days).

OmegaTLogFormatter

org.omegat.util.logging.OmegaTLogFormatter is a custom java.util.logging.Formatter that provides flexible log entry formatting using a mask.

  • Mask Configuration: The format of each log line can be customized using the org.omegat.util.logging.OmegaTLogFormatter.mask property.

  • Available Placeholders:

    • $mark: The session ID.

    • $time: The timestamp of the log record.

    • $level: The localized log level (e.g., INFO, WARNING).

    • $text: The log message itself.

    • $key: The resource bundle key (if applicable), enclosed in parentheses.

    • $threadName: The name of the thread that generated the log.

    • $loggerName: The name of the logger.

  • Time Format: The $time format can be customized using org.omegat.util.logging.OmegaTLogFormatter.timeFormat (default: HH:mm:ss).

Example mask from logger.properties:

org.omegat.util.logging.OmegaTLogFormatter.mask=$time: $level: $text $key

Configuration

Default Configuration

The default logging configuration is stored in src/org/omegat/logger.properties. It defines handlers (Console and File), log levels, and rotation policies.

Custom Configuration

You can override the default logging configuration in several ways:

  1. System Property: Use -Djava.util.logging.config.file=/path/to/your/logger.properties when starting OmegaT.

  2. User Configuration File: Place a file named logger.properties in your OmegaT configuration directory.

  3. Command Line (Gradle):

    ./gradlew run --args="-Djava.util.logging.config.file=/path/to/logger.properties"
    

Log configuration for CI/CD

OmegaT uses a custom log configuration for CI/CD. A file named logger.properties is placed in the config/test directory.

Useful Log Levels

To enable debug logging for specific packages, add lines like these to your logger.properties:

org.omegat.core.data.level = ALL
org.omegat.gui.editor.level = FINE

Debugging

Using a Debugger (IDE)

Most developers use an IDE (IntelliJ IDEA, Eclipse, or NetBeans) to debug OmegaT.

IntelliJ IDEA

  1. Create a “Gradle” run configuration.

  2. Task: run

  3. Click the “Debug” icon.

Remote Debugging

To start OmegaT and wait for a debugger to attach on port 5005:

./gradlew run --debug-jvm

Or use the specialized task (if applicable):

./gradlew runDebugger

Logging as a Debugging Tool

When a debugger is not practical (e.g., race conditions or remote issues), increasing the log level to ALL or FINEST for relevant packages is often the best approach.