The Apache Log4j implementation of java.util.logging providing JUL to Log4j bridge functionality
—
The level translation system provides bidirectional conversion between Java Util Logging (JUL) levels and Log4j levels, with support for custom levels and intelligent closest-match mapping for non-standard level values.
Level translation is essential for proper log filtering and routing when bridging JUL to Log4j. The system provides:
| JUL Level | Log4j Level | Notes |
|---|---|---|
| ALL | ALL | Both represent unlimited logging |
| FINEST | FINEST | Custom Log4j level (TRACE + 100) |
| FINER | TRACE | Fine-grained debugging |
| FINE | DEBUG | Standard debugging |
| CONFIG | CONFIG | Custom Log4j level (INFO + 50) |
| INFO | INFO | Informational messages |
| WARNING | WARN | Warning conditions |
| SEVERE | ERROR | Error conditions |
| OFF | OFF | No logging |
| Log4j Level | JUL Level | Notes |
|---|---|---|
| ALL | ALL | Both represent unlimited logging |
| FINEST | FINEST | Custom Log4j level maps back |
| TRACE | FINER | Fine-grained debugging |
| DEBUG | FINE | Standard debugging |
| CONFIG | CONFIG | Custom Log4j level maps back |
| INFO | INFO | Informational messages |
| WARN | WARNING | Warning conditions |
| ERROR | SEVERE | Error conditions |
| FATAL | SEVERE | Critical errors map to SEVERE |
| OFF | OFF | No logging |
import org.apache.logging.log4j.jul.LevelTranslator;
import org.apache.logging.log4j.Level;
// Convert JUL level to Log4j level
java.util.logging.Level julLevel = java.util.logging.Level.INFO;
Level log4jLevel = LevelTranslator.toLevel(julLevel);
// Convert Log4j level to JUL level
Level log4jError = Level.ERROR;
java.util.logging.Level julSevere = LevelTranslator.toJavaLevel(log4jError);
// Handle null values (JUL allows null levels)
Level result = LevelTranslator.toLevel(null); // returns nullThe translator automatically handles custom levels by finding the closest standard level:
// Custom JUL level between FINE and INFO
java.util.logging.Level customLevel = new java.util.logging.Level("CUSTOM", 750) {};
// Automatically maps to closest Log4j level (DEBUG in this case)
Level mapped = LevelTranslator.toLevel(customLevel);public final class LevelTranslator {
/**
* Custom Log4j level corresponding to JUL FINEST.
* Maps to TRACE + 100 for more specific than standard TRACE.
*/
public static final Level FINEST = Level.forName("FINEST", Level.TRACE.intLevel() + 100);
/**
* Custom Log4j level corresponding to JUL CONFIG.
* Maps to INFO + 50 for level between INFO and DEBUG.
*/
public static final Level CONFIG = Level.forName("CONFIG", Level.INFO.intLevel() + 50);
/**
* Converts a JUL logging Level to a Log4j logging Level.
* Uses pluggable LevelConverter for actual conversion.
*
* @param level JUL Level to convert, may be null per JUL specification
* @return converted Log4j Level or null if input was null
*/
public static Level toLevel(java.util.logging.Level level);
/**
* Converts a Log4j logging Level to a JUL logging Level.
* Uses pluggable LevelConverter for actual conversion.
*
* @param level Log4j Level to convert, must not be null
* @return converted JUL Level
*/
public static java.util.logging.Level toJavaLevel(Level level);
}public interface LevelConverter {
/**
* Converts a JUL logging Level to a Log4j logging Level.
* Implementation should handle null values and custom levels.
*
* @param javaLevel JUL Level to convert, may be null per JUL specification
* @return converted Log4j Level or null if conversion not possible
*/
Level toLevel(java.util.logging.Level javaLevel);
/**
* Converts a Log4j logging Level to a JUL logging Level.
* Implementation should handle all standard and custom Log4j levels.
*
* @param level Log4j Level to convert, should not be null
* @return converted JUL Level or null if conversion not possible
*/
java.util.logging.Level toJavaLevel(Level level);
}public class DefaultLevelConverter implements LevelConverter {
/**
* Creates converter with standard level mappings and custom level support.
* Initializes bidirectional mapping tables and sorted level list for nearest matching.
*/
public DefaultLevelConverter();
/**
* Converts JUL level to Log4j level with custom level support.
* For unknown levels, finds the nearest mapped level by numeric value.
*
* @param javaLevel JUL Level to convert
* @return corresponding Log4j Level or nearest match for custom levels
*/
public Level toLevel(java.util.logging.Level javaLevel);
/**
* Converts Log4j level to JUL level using direct mapping.
*
* @param level Log4j Level to convert
* @return corresponding JUL Level or null if not mapped
*/
public java.util.logging.Level toJavaLevel(Level level);
}You can provide a custom level converter implementation:
public class CustomLevelConverter implements LevelConverter {
@Override
public Level toLevel(java.util.logging.Level javaLevel) {
if (javaLevel == null) return null;
// Custom conversion logic
if (javaLevel.getName().equals("AUDIT")) {
return Level.forName("AUDIT", 450); // Between INFO and WARN
}
// Fall back to default behavior
return new DefaultLevelConverter().toLevel(javaLevel);
}
@Override
public java.util.logging.Level toJavaLevel(Level level) {
// Custom reverse conversion
if ("AUDIT".equals(level.name())) {
return java.util.logging.Level.parse("AUDIT");
}
return new DefaultLevelConverter().toJavaLevel(level);
}
}
// Configure custom converter
System.setProperty("log4j.jul.levelConverter", "com.example.CustomLevelConverter");For unknown JUL levels, the DefaultLevelConverter finds the nearest mapped level:
// Example: Custom level with value 650 (between FINE=500 and CONFIG=700)
java.util.logging.Level custom = new java.util.logging.Level("CUSTOM", 650) {};
// Nearest is CONFIG (700), so maps to LevelTranslator.CONFIG
Level result = LevelTranslator.toLevel(custom);The level converter is selected during static initialization:
log4j.jul.levelConverter property is set// Set custom converter class
System.setProperty("log4j.jul.levelConverter", "com.example.MyLevelConverter");Custom LevelConverter implementations must:
The level translation system handles various error conditions:
// Null handling (per JUL specification)
Level result = LevelTranslator.toLevel(null); // returns null
// Custom converter loading failures
try {
CustomConverter converter = LoaderUtil.newCheckedInstanceOf(className, LevelConverter.class);
} catch (Exception e) {
LOGGER.error("Could not create custom LevelConverter [{}].", className, e);
// Falls back to DefaultLevelConverter
}
// Graceful degradation for unknown levels
Level fallback = nearestLevel(unknownLevel); // finds closest matchAll level translation components are fully thread-safe:
Install with Tessl CLI
npx tessl i tessl/maven-org-apache-logging-log4j--log4j-jul