or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

bridge-handler.mdindex.mdlevel-translation.mdlogger-adapters.mdlogmanager-integration.md

level-translation.mddocs/

0

# Level Translation

1

2

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.

3

4

## Overview

5

6

Level translation is essential for proper log filtering and routing when bridging JUL to Log4j. The system provides:

7

8

- **Standard Mappings**: Predefined conversions between common JUL and Log4j levels

9

- **Custom Levels**: Special Log4j levels for JUL-specific levels (FINEST, CONFIG)

10

- **Dynamic Mapping**: Closest-match algorithm for custom or non-standard levels

11

- **Pluggable Converters**: Interface for custom level conversion strategies

12

13

## Standard Level Mappings

14

15

### JUL to Log4j

16

17

| JUL Level | Log4j Level | Notes |

18

|-----------|-------------|--------|

19

| ALL | ALL | Both represent unlimited logging |

20

| FINEST | FINEST | Custom Log4j level (TRACE + 100) |

21

| FINER | TRACE | Fine-grained debugging |

22

| FINE | DEBUG | Standard debugging |

23

| CONFIG | CONFIG | Custom Log4j level (INFO + 50) |

24

| INFO | INFO | Informational messages |

25

| WARNING | WARN | Warning conditions |

26

| SEVERE | ERROR | Error conditions |

27

| OFF | OFF | No logging |

28

29

### Log4j to JUL

30

31

| Log4j Level | JUL Level | Notes |

32

|-------------|-----------|--------|

33

| ALL | ALL | Both represent unlimited logging |

34

| FINEST | FINEST | Custom Log4j level maps back |

35

| TRACE | FINER | Fine-grained debugging |

36

| DEBUG | FINE | Standard debugging |

37

| CONFIG | CONFIG | Custom Log4j level maps back |

38

| INFO | INFO | Informational messages |

39

| WARN | WARNING | Warning conditions |

40

| ERROR | SEVERE | Error conditions |

41

| FATAL | SEVERE | Critical errors map to SEVERE |

42

| OFF | OFF | No logging |

43

44

## Usage

45

46

### Basic Level Conversion

47

48

```java

49

import org.apache.logging.log4j.jul.LevelTranslator;

50

import org.apache.logging.log4j.Level;

51

52

// Convert JUL level to Log4j level

53

java.util.logging.Level julLevel = java.util.logging.Level.INFO;

54

Level log4jLevel = LevelTranslator.toLevel(julLevel);

55

56

// Convert Log4j level to JUL level

57

Level log4jError = Level.ERROR;

58

java.util.logging.Level julSevere = LevelTranslator.toJavaLevel(log4jError);

59

60

// Handle null values (JUL allows null levels)

61

Level result = LevelTranslator.toLevel(null); // returns null

62

```

63

64

### Custom Level Handling

65

66

The translator automatically handles custom levels by finding the closest standard level:

67

68

```java

69

// Custom JUL level between FINE and INFO

70

java.util.logging.Level customLevel = new java.util.logging.Level("CUSTOM", 750) {};

71

72

// Automatically maps to closest Log4j level (DEBUG in this case)

73

Level mapped = LevelTranslator.toLevel(customLevel);

74

```

75

76

## API Reference

77

78

### LevelTranslator Class

79

80

```java { .api }

81

public final class LevelTranslator {

82

/**

83

* Custom Log4j level corresponding to JUL FINEST.

84

* Maps to TRACE + 100 for more specific than standard TRACE.

85

*/

86

public static final Level FINEST = Level.forName("FINEST", Level.TRACE.intLevel() + 100);

87

88

/**

89

* Custom Log4j level corresponding to JUL CONFIG.

90

* Maps to INFO + 50 for level between INFO and DEBUG.

91

*/

92

public static final Level CONFIG = Level.forName("CONFIG", Level.INFO.intLevel() + 50);

93

94

/**

95

* Converts a JUL logging Level to a Log4j logging Level.

96

* Uses pluggable LevelConverter for actual conversion.

97

*

98

* @param level JUL Level to convert, may be null per JUL specification

99

* @return converted Log4j Level or null if input was null

100

*/

101

public static Level toLevel(java.util.logging.Level level);

102

103

/**

104

* Converts a Log4j logging Level to a JUL logging Level.

105

* Uses pluggable LevelConverter for actual conversion.

106

*

107

* @param level Log4j Level to convert, must not be null

108

* @return converted JUL Level

109

*/

110

public static java.util.logging.Level toJavaLevel(Level level);

111

}

112

```

113

114

### LevelConverter Interface

115

116

```java { .api }

117

public interface LevelConverter {

118

/**

119

* Converts a JUL logging Level to a Log4j logging Level.

120

* Implementation should handle null values and custom levels.

121

*

122

* @param javaLevel JUL Level to convert, may be null per JUL specification

123

* @return converted Log4j Level or null if conversion not possible

124

*/

125

Level toLevel(java.util.logging.Level javaLevel);

126

127

/**

128

* Converts a Log4j logging Level to a JUL logging Level.

129

* Implementation should handle all standard and custom Log4j levels.

130

*

131

* @param level Log4j Level to convert, should not be null

132

* @return converted JUL Level or null if conversion not possible

133

*/

134

java.util.logging.Level toJavaLevel(Level level);

135

}

136

```

137

138

### DefaultLevelConverter Class

139

140

```java { .api }

141

public class DefaultLevelConverter implements LevelConverter {

142

/**

143

* Creates converter with standard level mappings and custom level support.

144

* Initializes bidirectional mapping tables and sorted level list for nearest matching.

145

*/

146

public DefaultLevelConverter();

147

148

/**

149

* Converts JUL level to Log4j level with custom level support.

150

* For unknown levels, finds the nearest mapped level by numeric value.

151

*

152

* @param javaLevel JUL Level to convert

153

* @return corresponding Log4j Level or nearest match for custom levels

154

*/

155

public Level toLevel(java.util.logging.Level javaLevel);

156

157

/**

158

* Converts Log4j level to JUL level using direct mapping.

159

*

160

* @param level Log4j Level to convert

161

* @return corresponding JUL Level or null if not mapped

162

*/

163

public java.util.logging.Level toJavaLevel(Level level);

164

}

165

```

166

167

## Custom Level Converter

168

169

You can provide a custom level converter implementation:

170

171

```java

172

public class CustomLevelConverter implements LevelConverter {

173

@Override

174

public Level toLevel(java.util.logging.Level javaLevel) {

175

if (javaLevel == null) return null;

176

177

// Custom conversion logic

178

if (javaLevel.getName().equals("AUDIT")) {

179

return Level.forName("AUDIT", 450); // Between INFO and WARN

180

}

181

182

// Fall back to default behavior

183

return new DefaultLevelConverter().toLevel(javaLevel);

184

}

185

186

@Override

187

public java.util.logging.Level toJavaLevel(Level level) {

188

// Custom reverse conversion

189

if ("AUDIT".equals(level.name())) {

190

return java.util.logging.Level.parse("AUDIT");

191

}

192

193

return new DefaultLevelConverter().toJavaLevel(level);

194

}

195

}

196

197

// Configure custom converter

198

System.setProperty("log4j.jul.levelConverter", "com.example.CustomLevelConverter");

199

```

200

201

## Custom Level Support

202

203

### Nearest Level Algorithm

204

205

For unknown JUL levels, the DefaultLevelConverter finds the nearest mapped level:

206

207

1. **Calculate Distance**: Compute numeric distance between custom level and all known levels

208

2. **Find Minimum**: Select the known level with smallest distance

209

3. **Cache Result**: Store mapping for future lookups

210

4. **Return Mapping**: Return the Log4j level corresponding to nearest JUL level

211

212

```java

213

// Example: Custom level with value 650 (between FINE=500 and CONFIG=700)

214

java.util.logging.Level custom = new java.util.logging.Level("CUSTOM", 650) {};

215

216

// Nearest is CONFIG (700), so maps to LevelTranslator.CONFIG

217

Level result = LevelTranslator.toLevel(custom);

218

```

219

220

### Performance Optimization

221

222

- **Caching**: Custom level mappings are cached after first lookup

223

- **Sorted Search**: Binary search through sorted level list

224

- **Static Initialization**: Standard mappings pre-populated at class loading

225

226

## Configuration

227

228

### Level Converter Selection

229

230

The level converter is selected during static initialization:

231

232

1. **Custom Converter**: If `log4j.jul.levelConverter` property is set

233

2. **Default Converter**: Falls back to DefaultLevelConverter

234

235

```java

236

// Set custom converter class

237

System.setProperty("log4j.jul.levelConverter", "com.example.MyLevelConverter");

238

```

239

240

### Requirements for Custom Converters

241

242

Custom LevelConverter implementations must:

243

- Have a public no-argument constructor

244

- Handle null input values gracefully

245

- Be thread-safe for concurrent access

246

- Provide reasonable mappings for standard levels

247

248

## Integration with Bridge Components

249

250

### LogManager Integration

251

- **Automatic Translation**: All JUL logging calls automatically use level translation

252

- **Bi-directional**: Supports both JUL→Log4j and Log4j→JUL conversions

253

- **Transparent**: No code changes required in application

254

255

### Bridge Handler Integration

256

- **Event Processing**: Translates levels for each published LogRecord

257

- **Level Propagation**: Uses reverse translation for propagating Log4j levels to JUL

258

- **Performance**: Efficient translation with minimal overhead

259

260

## Error Handling

261

262

The level translation system handles various error conditions:

263

264

```java

265

// Null handling (per JUL specification)

266

Level result = LevelTranslator.toLevel(null); // returns null

267

268

// Custom converter loading failures

269

try {

270

CustomConverter converter = LoaderUtil.newCheckedInstanceOf(className, LevelConverter.class);

271

} catch (Exception e) {

272

LOGGER.error("Could not create custom LevelConverter [{}].", className, e);

273

// Falls back to DefaultLevelConverter

274

}

275

276

// Graceful degradation for unknown levels

277

Level fallback = nearestLevel(unknownLevel); // finds closest match

278

```

279

280

## Thread Safety

281

282

All level translation components are fully thread-safe:

283

- **Static Fields**: FINEST and CONFIG levels are immutable

284

- **Concurrent Maps**: DefaultLevelConverter uses ConcurrentHashMap for caching

285

- **Immutable Mappings**: Standard level mappings are immutable after initialization

286

- **Atomic Operations**: Level lookup and caching operations are atomic