Wikantik Logging Configuration Guide
Understanding `jspwiki.use.external.logconfig`
The Logging Stack
Your Wikantik 3.0.2 uses this logging architecture:
```
Application Code → SLF4J API → log4j-slf4j-impl → Log4j2 Core
↑
log4j-1.2-api (legacy bridge)
```
The JARs in your `/opt/tomcat/webapps/ROOT/WEB-INF/lib/`:
- `slf4j-api-2.0.17.jar` - Facade API
- `log4j-slf4j-impl-2.25.2.jar` - Routes SLF4J to Log4j2
- `log4j-api-2.25.2.jar` - Log4j2 API
- `log4j-core-2.25.2.jar` - Log4j2 implementation
- `log4j-1.2-api-2.25.2.jar` - Bridges old Log4j 1.x calls
How `jspwiki.use.external.logconfig` Works
When Wikantik starts, `WikiBootstrapServletContextListener.initWikiLoggingFramework()` reads this property:
**When `false` (default):**
1. Wikantik reads all properties from `wikantik.properties` / `wikantik-custom.properties`
2. It filters properties starting with: `appender`, `logger`, `rootLogger`, `filter`, `status`, `dest`, `name`, `properties`, `property`, or `log4j2`
3. These are fed into Log4j2's `PropertiesConfigurationFactory`
4. Log4j2 is reconfigured programmatically
**When `true`:**
1. Wikantik does nothing with logging configuration
2. Log4j2 uses its standard automatic configuration mechanism
3. It searches the classpath for: `log4j2-test.xml`, `log4j2.xml`, `log4j2.properties`
4. Or you can specify `-Dlog4j2.configurationFile=/path/to/config.xml`
---
External XML Configuration Setup
Use a separate `log4j2.xml` file with full Log4j2 capabilities.
Step 1: Set in wikantik-custom.properties
```properties
jspwiki.use.external.logconfig = true
```
Also remove any existing broken logging lines (log4j.* properties are Log4j 1.x syntax and will be ignored).
Step 2: Create /opt/tomcat/lib/log4j2.xml
```xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" name="Wikantik-Production">
<Properties>
<Property name="logDir">/var/log/jspwiki</Property>
<Property name="pattern">%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n</Property>
</Properties>
<Appenders>
<!-- Console for catalina.out -->
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%highlight{[%-5level]} %d{HH:mm:ss.SSS} [%t] %c{1.} - %msg%n"/>
</Console>
<!-- Main application log with daily rotation -->
<RollingFile name="AppLog" fileName="${logDir}/jspwiki.log" filePattern="${logDir}/jspwiki-%d{yyyy-MM-dd}-%i.log.gz">
<PatternLayout pattern="${pattern}"/>
<Policies>
<TimeBasedTriggeringPolicy interval="1"/>
<SizeBasedTriggeringPolicy size="50MB"/>
</Policies>
<DefaultRolloverStrategy max="30"/>
</RollingFile>
<!-- Security audit log -->
<RollingFile name="SecurityLog" fileName="${logDir}/security.log" filePattern="${logDir}/security-%d{yyyy-MM-dd}.log.gz">
<PatternLayout pattern="%d{ISO8601} %level %msg%n"/>
<Policies>
<TimeBasedTriggeringPolicy interval="1"/>
</Policies>
<DefaultRolloverStrategy max="90"/>
</RollingFile>
<!-- Access log for page views -->
<RollingFile name="AccessLog" fileName="${logDir}/access.log" filePattern="${logDir}/access-%d{yyyy-MM-dd}.log.gz">
<PatternLayout pattern="%d{ISO8601} %msg%n"/>
<Policies>
<TimeBasedTriggeringPolicy interval="1"/>
</Policies>
</RollingFile>
</Appenders>
<Loggers>
<!-- Wikantik core -->
<Logger name="com.wikantik" level="INFO" additivity="false">
<AppenderRef ref="Console"/>
<AppenderRef ref="AppLog"/>
</Logger>
<!-- Security events (login, logout, access denied) -->
<Logger name="SecurityLog" level="INFO" additivity="false">
<AppenderRef ref="SecurityLog"/>
</Logger>
<!-- Page access tracking via WikiServlet -->
<Logger name="com.wikantik.WikiServlet" level="INFO" additivity="false">
<AppenderRef ref="Console"/>
<AppenderRef ref="AccessLog"/>
</Logger>
<!-- Database connection issues -->
<Logger name="org.apache.tomcat.dbcp" level="WARN"/>
<!-- Lucene search indexing -->
<Logger name="com.wikantik.search" level="INFO"/>
<!-- Root: catch-all -->
<Root level="WARN">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
```
Step 3: Create the log directory
```bash
sudo mkdir -p /var/log/jspwiki
sudo chown tomcat:tomcat /var/log/jspwiki
```
Step 4: Restart Tomcat
```bash
sudo systemctl restart tomcat
```
Step 5: Verify
```bash
Check catalina.out for startup messages
tail -f /opt/tomcat/logs/catalina.out
Check new log files are created
ls -la /var/log/jspwiki/
```
---
Customizing the Log Directory for Different Environments
The log directory is defined in the `<Properties>` section at the top of the XML file:
```xml
<Properties>
<Property name="logDir">/var/log/jspwiki</Property> <!-- Change this path -->
<Property name="pattern">%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n</Property>
</Properties>
```
The `logDir` property is referenced throughout the config as `${logDir}`, so changing it in one place updates all appenders:
```xml
fileName="${logDir}/jspwiki.log"
filePattern="${logDir}/jspwiki-%d{yyyy-MM-dd}-%i.log.gz"
```
Recommended Paths by Environment
| Environment | Path | Notes |
|-------------|------|-------|
| Production | `/var/log/jspwiki` | Standard Linux log location |
| Development | `/tmp/jspwiki-logs` | Easy access, cleared on reboot |
| Testing | `/opt/tomcat/logs/jspwiki` | Keeps logs with Tomcat |
| Portable | `${sys:catalina.base}/logs/jspwiki` | Relative to Tomcat install |
| Java temp | `${sys:java.io.tmpdir}/jspwiki` | Uses Java's temp directory |
Using System Property Lookups
The `${sys:...}` syntax references Java system properties, making configs portable across environments:
| Lookup | Description | Example Value |
|--------|-------------|---------------|
| `${sys:catalina.base}` | Tomcat base directory | `/opt/tomcat` |
| `${sys:catalina.home}` | Tomcat home directory | `/opt/tomcat` |
| `${sys:java.io.tmpdir}` | Java temp directory | `/tmp` |
| `${sys:user.home}` | User home directory | `/home/tomcat` |
**Example for development/testing:**
```xml
<Properties>
<Property name="logDir">${sys:catalina.base}/logs/jspwiki</Property>
<Property name="pattern">%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n</Property>
</Properties>
```
Environment Variables
You can also use environment variables with the `${env:...}` syntax:
```xml
<Property name="logDir">${env:JSPWIKI_LOG_DIR:-/var/log/jspwiki}</Property>
```
This uses `$JSPWIKI_LOG_DIR` if set, otherwise falls back to `/var/log/jspwiki`.
Important Reminders
1. **Permissions**: Ensure the `tomcat` user has write permission to the chosen directory
2. **Create directory**: The directory must exist before Tomcat starts (Log4j2 won't create parent directories)
3. **Disk space**: Choose a location with adequate space for log rotation
```bash
Example setup for testing environment
sudo mkdir -p /opt/tomcat/logs/jspwiki
sudo chown tomcat:tomcat /opt/tomcat/logs/jspwiki
```
---
Log4j2 Configuration Reference
Log Levels (in order of severity)
| Level | Description |
|-------|-------------|
| TRACE | Finest-grained debug information |
| DEBUG | Detailed debug information |
| INFO | General operational messages |
| WARN | Warning conditions |
| ERROR | Error conditions |
| FATAL | Critical errors causing shutdown |
Common Pattern Layout Tokens
| Token | Description |
|-------|-------------|
| `%d{pattern}` | Date/time with specified format |
| `%t` | Thread name |
| `%p` or `%level` | Log level |
| `%c{n}` | Logger name (n = precision) |
| `%C{n}` | Class name |
| `%M` | Method name |
| `%L` | Line number |
| `%m` or `%msg` | Log message |
| `%n` | Newline |
| `%x` | Thread context (NDC) |
| `%X{key}` | Thread context map (MDC) value |
| `%highlight{pattern}` | ANSI color highlighting |
Useful Wikantik Logger Names
| Logger | Purpose |
|--------|---------|
| `com.wikantik` | All Wikantik classes |
| `com.wikantik.WikiServlet` | Page request handling |
| `com.wikantik.auth` | Authentication/authorization |
| `com.wikantik.search` | Lucene search indexing |
| `com.wikantik.providers` | Page/attachment providers |
| `SecurityLog` | Security audit events |
| `SpamLog` | Spam filter events |
---
Advanced Features
Hot Reload Configuration
Add `monitorInterval` to automatically reload config changes:
```xml
<Configuration status="WARN" monitorInterval="30">
```
Async Logging (Performance)
Wrap appenders for non-blocking logging:
```xml
<Appenders>
<RollingFile name="AppLogFile" .../>
<Async name="AppLog">
<AppenderRef ref="AppLogFile"/>
</Async>
</Appenders>
```
Syslog Appender (Centralized Logging)
```xml
<Syslog name="Syslog"
host="logserver.example.com"
port="514"
protocol="UDP"
facility="LOCAL0"
appName="jspwiki"/>
```
Filter Sensitive Data
```xml
<RollingFile name="AppLog" ...>
<RegexFilter regex=".*password.*" onMatch="DENY" onMismatch="ACCEPT"/>
<PatternLayout .../>
</RollingFile>
```
---
Sources
- [Wikantik Releases - Log4j2 configuration notes](https://github.com/apache/jspwiki/releases)
- [Wikantik Dockerfile - External log config setup](https://github.com/apache/jspwiki/blob/master/Dockerfile)
- [Log4j2 Configuration Manual](https://logging.apache.org/log4j/2.x/manual/configuration.html)
- [External Log4j2 Configuration](https://gangmax.me/blog/2024/11/15/use-external-log4j2-configuration-file/)
- [Wikantik wikantik.properties defaults](https://github.com/apache/jspwiki/blob/master/wikantik-main/src/main/resources/ini/wikantik.properties)