0
# Web-Specific Features
1
2
Web-aware logging components including servlet context lookups for configuration variables, servlet appenders for direct logging to container logs, and thread context utilities for capturing request information. These features enable Log4j to integrate deeply with web application environments.
3
4
## Capabilities
5
6
### WebLookup
7
8
Log4j lookup plugin that provides access to servlet context information within log configurations. Enables dynamic configuration values based on web application context.
9
10
```java { .api }
11
/**
12
* Log4j lookup for accessing servlet context information in configurations.
13
* Supports servlet context attributes, init parameters, and container metadata.
14
*/
15
@Plugin(name = "web", category = "Lookup")
16
public class WebLookup extends AbstractLookup {
17
18
/**
19
* Resolves web-related lookup keys to their corresponding values.
20
* Accesses current ServletContext via WebLoggerContextUtils.
21
*
22
* @param event LogEvent triggering the lookup (unused)
23
* @param key Lookup key specifying what information to retrieve
24
* @return String value corresponding to the key, or null if not found
25
*/
26
public String lookup(LogEvent event, String key);
27
}
28
```
29
30
**Supported Lookup Keys:**
31
32
```java { .api }
33
public class WebLookup extends AbstractLookup {
34
/** Prefix for servlet context attributes */
35
private static final String ATTR_PREFIX = "attr.";
36
37
/** Prefix for servlet init parameters */
38
private static final String INIT_PARAM_PREFIX = "initParam.";
39
}
40
```
41
42
**Available Lookup Values:**
43
44
- **`attr.{name}`** - ServletContext attribute value by name
45
- **`initParam.{name}`** - ServletContext init parameter by name
46
- **`rootDir`** - Web application root directory path
47
- **`contextPath`** - ServletContext path (e.g., "/myapp")
48
- **`contextPathName`** - Context path name without slashes
49
- **`servletContextName`** - ServletContext display name
50
- **`serverInfo`** - Server container information
51
- **`effectiveMajorVersion`** - Effective servlet API major version
52
- **`effectiveMinorVersion`** - Effective servlet API minor version
53
- **`majorVersion`** - Servlet API major version
54
- **`minorVersion`** - Servlet API minor version
55
- **Direct attribute/parameter names** - Falls back to direct ServletContext lookup
56
57
**Usage in Log4j Configuration:**
58
59
```xml
60
<Configuration>
61
<Properties>
62
<Property name="logDir">${web:rootDir}/logs</Property>
63
<Property name="appName">${web:servletContextName}</Property>
64
<Property name="version">${web:attr.appVersion}</Property>
65
</Properties>
66
67
<Appenders>
68
<File name="AppLog" fileName="${logDir}/${appName}.log">
69
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%level] %logger{36} - %msg%n"/>
70
</File>
71
</Appenders>
72
73
<Loggers>
74
<Root level="info">
75
<AppenderRef ref="AppLog"/>
76
</Root>
77
</Loggers>
78
</Configuration>
79
```
80
81
**Error Handling:**
82
83
The WebLookup can throw exceptions in certain scenarios:
84
85
```java
86
// If rootDir cannot be resolved (e.g., in unexploded WAR)
87
throw new IllegalStateException(
88
"Failed to resolve web:rootDir -- servlet container unable to translate virtual path " +
89
" to real path (probably not deployed as exploded"
90
);
91
```
92
93
**Common Exceptions:**
94
- **`IllegalStateException`**: Thrown when web:rootDir cannot be resolved (usually in non-exploded WAR deployments)
95
- Returns `null` for unknown lookup keys or when ServletContext is not available
96
97
### ServletAppender
98
99
Log4j appender that writes log events directly to the servlet container's logging system using `ServletContext.log()`. Integrates Log4j output with container-managed logs.
100
101
```java { .api }
102
/**
103
* Log4j appender that logs using ServletContext's log method.
104
* Integrates with servlet container logging infrastructure.
105
*/
106
@Plugin(name = "Servlet", category = "Core", elementType = "appender", printObject = true)
107
public final class ServletAppender extends AbstractAppender {
108
109
/**
110
* Appends a log event to the servlet context log.
111
* Uses ServletContext.log() with optional throwable support.
112
*
113
* @param event LogEvent to append to servlet context log
114
*/
115
public void append(LogEvent event);
116
117
/**
118
* Creates a new ServletAppender builder for configuration.
119
*
120
* @return Builder instance for ServletAppender configuration
121
*/
122
public static <B extends Builder<B>> B newBuilder();
123
124
/**
125
* Creates ServletAppender instance (deprecated - use newBuilder()).
126
*
127
* @param layout Layout for formatting log events (must extend StringLayout)
128
* @param filter Filter for event filtering (optional)
129
* @param name Appender name (required)
130
* @param ignoreExceptions Whether to ignore exceptions during appending
131
* @return ServletAppender instance or null if invalid configuration
132
* @deprecated Use newBuilder() instead
133
*/
134
@Deprecated
135
public static ServletAppender createAppender(
136
Layout<? extends Serializable> layout,
137
Filter filter,
138
String name,
139
boolean ignoreExceptions);
140
}
141
```
142
143
**ServletAppender Builder:**
144
145
```java { .api }
146
/**
147
* Builder for ServletAppender configuration.
148
* Extends AbstractAppender.Builder with servlet-specific options.
149
*/
150
public static class Builder<B extends Builder<B>> extends AbstractAppender.Builder<B>
151
implements org.apache.logging.log4j.core.util.Builder<ServletAppender> {
152
153
/**
154
* Builds the ServletAppender with current configuration.
155
* Validates ServletContext availability and layout requirements.
156
*
157
* @return ServletAppender instance or null if validation fails
158
*/
159
public ServletAppender build();
160
161
/**
162
* Gets whether throwables are logged with servlet context.
163
*
164
* @return true if throwables logged via ServletContext.log(String, Throwable)
165
*/
166
public boolean isLogThrowables();
167
168
/**
169
* Sets whether to log throwables with servlet context.
170
* Controls whether to use ServletContext.log(String) or log(String, Throwable).
171
*
172
* @param logThrowables true to log throwables with servlet context
173
*/
174
public void setLogThrowables(boolean logThrowables);
175
}
176
```
177
178
**Configuration in Log4j XML:**
179
180
```xml
181
<Configuration>
182
<Appenders>
183
<Servlet name="ServletLog" logThrowables="true">
184
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%level] %logger{36} - %msg%n"/>
185
</Servlet>
186
</Appenders>
187
188
<Loggers>
189
<Logger name="com.example.web" level="debug">
190
<AppenderRef ref="ServletLog"/>
191
</Logger>
192
<Root level="info">
193
<AppenderRef ref="ServletLog"/>
194
</Root>
195
</Loggers>
196
</Configuration>
197
```
198
199
**Usage Notes:**
200
- Requires StringLayout (PatternLayout, SimpleLayout, etc.)
201
- Only available when ServletContext is accessible
202
- Integrates with container's native logging (Tomcat catalina.out, etc.)
203
- `logThrowables` parameter controls exception logging behavior
204
205
### ServletRequestThreadContext
206
207
Utility class for capturing servlet request information in Log4j's ThreadContext. Enables automatic inclusion of request details in log messages.
208
209
```java { .api }
210
/**
211
* Utility for adding servlet request information to ThreadContext.
212
* Captures request metadata for inclusion in log messages.
213
*/
214
public class ServletRequestThreadContext {
215
216
/**
217
* Adds servlet request information to ThreadContext.
218
* Captures remote address, host, and port with specified key prefix.
219
*
220
* @param key Prefix for ThreadContext keys
221
* @param servletRequest ServletRequest to capture information from
222
*/
223
public static void put(String key, ServletRequest servletRequest);
224
225
/**
226
* Adds HTTP servlet request information to ThreadContext.
227
* Delegates to ServletRequest version - HTTP-specific data handled elsewhere.
228
*
229
* @param key Prefix for ThreadContext keys
230
* @param servletRequest HttpServletRequest to capture information from
231
*/
232
public static void put(String key, HttpServletRequest servletRequest);
233
234
/**
235
* Adds field-value pair to ThreadContext with key prefix.
236
* Helper method for structured request data capture.
237
*
238
* @param key Base key for ThreadContext
239
* @param field Field name to append to key
240
* @param value Field value to store
241
*/
242
public static void put(String key, String field, Object value);
243
244
/**
245
* Adds key-value pair directly to ThreadContext.
246
* Direct wrapper around ThreadContext.put().
247
*
248
* @param key ThreadContext key
249
* @param value ThreadContext value
250
*/
251
public static void put(String key, String value);
252
}
253
```
254
255
**Captured Request Information:**
256
257
When calling `put(String key, ServletRequest servletRequest)`, the following ThreadContext entries are created:
258
- **`{key}.RemoteAddr`** - `request.getRemoteAddr()`
259
- **`{key}.RemoteHost`** - `request.getRemoteHost()`
260
- **`{key}.RemotePort`** - `request.getRemotePort()`
261
262
**Usage in Servlet Filter:**
263
264
```java
265
public class RequestLoggingFilter implements Filter {
266
267
@Override
268
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
269
throws IOException, ServletException {
270
271
// Capture request information in ThreadContext
272
ServletRequestThreadContext.put("request", request);
273
274
if (request instanceof HttpServletRequest) {
275
HttpServletRequest httpRequest = (HttpServletRequest) request;
276
ServletRequestThreadContext.put("request", "Method", httpRequest.getMethod());
277
ServletRequestThreadContext.put("request", "URI", httpRequest.getRequestURI());
278
ServletRequestThreadContext.put("request", "QueryString", httpRequest.getQueryString());
279
}
280
281
try {
282
chain.doFilter(request, response);
283
} finally {
284
// ThreadContext automatically cleared by Log4jServletFilter
285
}
286
}
287
}
288
```
289
290
**Log4j Configuration with Request Data:**
291
292
```xml
293
<Configuration>
294
<Appenders>
295
<Console name="Console">
296
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%level] %logger{36} - %msg [%X{request.RemoteAddr}] [%X{request.Method} %X{request.URI}]%n"/>
297
</Console>
298
</Appenders>
299
300
<Loggers>
301
<Root level="info">
302
<AppenderRef ref="Console"/>
303
</Root>
304
</Loggers>
305
</Configuration>
306
```
307
308
## Integration Examples
309
310
### Combined Web Features Usage
311
312
```java
313
@WebFilter("/*")
314
public class LoggingFilter implements Filter {
315
316
@Override
317
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
318
throws IOException, ServletException {
319
320
// Capture request context
321
ServletRequestThreadContext.put("req", request);
322
323
if (request instanceof HttpServletRequest) {
324
HttpServletRequest httpReq = (HttpServletRequest) request;
325
ServletRequestThreadContext.put("req", "method", httpReq.getMethod());
326
ServletRequestThreadContext.put("req", "uri", httpReq.getRequestURI());
327
ServletRequestThreadContext.put("req", "userAgent", httpReq.getHeader("User-Agent"));
328
}
329
330
Logger logger = LogManager.getLogger();
331
logger.info("Processing request");
332
333
try {
334
chain.doFilter(request, response);
335
logger.info("Request completed successfully");
336
} catch (Exception e) {
337
logger.error("Request failed", e);
338
throw e;
339
}
340
}
341
}
342
```
343
344
### Dynamic Configuration with Web Lookups
345
346
```xml
347
<Configuration>
348
<Properties>
349
<Property name="app.name">${web:servletContextName}</Property>
350
<Property name="app.version">${web:attr.version}</Property>
351
<Property name="log.path">${web:rootDir}/WEB-INF/logs</Property>
352
<Property name="container.info">${web:serverInfo}</Property>
353
</Properties>
354
355
<Appenders>
356
<File name="AppFile" fileName="${log.path}/${app.name}-${app.version}.log">
357
<PatternLayout pattern="%d [%level] %logger - %msg [%X{req.RemoteAddr}] [%X{req.method} %X{req.uri}]%n"/>
358
</File>
359
360
<Servlet name="ContainerLog" logThrowables="true">
361
<PatternLayout pattern="[${app.name}] %d [%level] %logger - %msg%n"/>
362
</Servlet>
363
</Appenders>
364
365
<Loggers>
366
<Logger name="com.example" level="debug">
367
<AppenderRef ref="AppFile"/>
368
<AppenderRef ref="ContainerLog"/>
369
</Logger>
370
<Root level="info">
371
<AppenderRef ref="ContainerLog"/>
372
</Root>
373
</Loggers>
374
</Configuration>
375
```
376
377
This configuration demonstrates:
378
- Dynamic file paths using web application root directory
379
- Application name and version from servlet context
380
- Request information in log patterns
381
- Dual output to both file and container logs