0
# Logging System
1
2
Standardized logging interface for Maven plugins with support for debug, info, warn, and error levels. Integrates with Maven's output system and supports both message-only and message-with-throwable logging.
3
4
## Capabilities
5
6
### Log Interface
7
8
Main logging interface providing the standard Maven logging mechanism. Accepts CharSequence (not just String) for convenience and provides hierarchical log levels with enable/disable checking.
9
10
```java { .api }
11
/**
12
* Logging interface for Maven plugins using standard Maven channels
13
*/
14
public interface Log {
15
16
/**
17
* Check if debug level is enabled
18
* @return true if debug messages will be output
19
*/
20
boolean isDebugEnabled();
21
22
/**
23
* Send debug message to user
24
* @param content message content (accepts CharSequence for convenience)
25
*/
26
void debug(CharSequence content);
27
28
/**
29
* Send debug message with exception to user
30
* @param content message content
31
* @param error exception whose stacktrace will be output
32
*/
33
void debug(CharSequence content, Throwable error);
34
35
/**
36
* Send exception to user at debug level
37
* @param error exception whose stacktrace will be output
38
*/
39
void debug(Throwable error);
40
41
/**
42
* Check if info level is enabled
43
* @return true if info messages will be output
44
*/
45
boolean isInfoEnabled();
46
47
/**
48
* Send info message to user
49
* @param content message content
50
*/
51
void info(CharSequence content);
52
53
/**
54
* Send info message with exception to user
55
* @param content message content
56
* @param error exception whose stacktrace will be output
57
*/
58
void info(CharSequence content, Throwable error);
59
60
/**
61
* Send exception to user at info level
62
* @param error exception whose stacktrace will be output
63
*/
64
void info(Throwable error);
65
66
/**
67
* Check if warn level is enabled
68
* @return true if warn messages will be output
69
*/
70
boolean isWarnEnabled();
71
72
/**
73
* Send warning message to user
74
* @param content message content
75
*/
76
void warn(CharSequence content);
77
78
/**
79
* Send warning message with exception to user
80
* @param content message content
81
* @param error exception whose stacktrace will be output
82
*/
83
void warn(CharSequence content, Throwable error);
84
85
/**
86
* Send exception to user at warn level
87
* @param error exception whose stacktrace will be output
88
*/
89
void warn(Throwable error);
90
91
/**
92
* Check if error level is enabled
93
* @return true if error messages will be output
94
*/
95
boolean isErrorEnabled();
96
97
/**
98
* Send error message to user
99
* @param content message content
100
*/
101
void error(CharSequence content);
102
103
/**
104
* Send error message with exception to user
105
* @param content message content
106
* @param error exception whose stacktrace will be output
107
*/
108
void error(CharSequence content, Throwable error);
109
110
/**
111
* Send exception to user at error level
112
* @param error exception whose stacktrace will be output
113
*/
114
void error(Throwable error);
115
}
116
```
117
118
**Usage Examples:**
119
120
```java
121
public class ExampleMojo extends AbstractMojo {
122
123
@Override
124
public void execute() throws MojoExecutionException {
125
Log log = getLog();
126
127
// Basic logging
128
log.info("Starting plugin execution");
129
log.debug("Debug mode enabled");
130
131
// Conditional logging to avoid expensive operations
132
if (log.isDebugEnabled()) {
133
log.debug("Processing files: " + files.stream()
134
.map(File::getName)
135
.collect(Collectors.joining(", ")));
136
}
137
138
// Logging with exceptions
139
try {
140
processFiles();
141
} catch (IOException e) {
142
log.error("Failed to process files", e);
143
throw new MojoExecutionException("Processing failed", e);
144
}
145
146
// Warning about deprecated usage
147
if (useDeprecatedOption) {
148
log.warn("The 'oldOption' parameter is deprecated. Use 'newOption' instead.");
149
}
150
151
// CharSequence support - can pass StringBuilder directly
152
StringBuilder report = new StringBuilder();
153
report.append("Processed ").append(fileCount).append(" files");
154
log.info(report);
155
}
156
}
157
```
158
159
### SystemStreamLog Class
160
161
Default Log implementation that outputs to System.out and System.err. Used as fallback when no logger has been injected into the Mojo.
162
163
```java { .api }
164
/**
165
* Default Log implementation using System.out and System.err streams
166
*/
167
public class SystemStreamLog implements Log {
168
// Debug level is disabled by default
169
// Info, warn, error levels are enabled by default
170
// Error messages go to System.err, others to System.out
171
}
172
```
173
174
**Characteristics:**
175
- Debug logging is **disabled by default**
176
- Info, warn, and error logging are **enabled by default**
177
- Error-level messages are written to `System.err`
178
- Debug, info, and warn messages are written to `System.out`
179
- Used automatically by `AbstractMojo.getLog()` when no logger is injected
180
181
### DefaultLog Class
182
183
Log implementation that bridges Maven Plugin API logging to Plexus logging system. Wraps a Plexus Logger and safely converts CharSequence to String. Located in package `org.apache.maven.monitor.logging`.
184
185
```java { .api }
186
/**
187
* Log implementation bridging to Plexus logging (org.apache.maven.monitor.logging.DefaultLog)
188
*/
189
public class DefaultLog implements Log {
190
/**
191
* Create DefaultLog wrapping Plexus logger
192
* @param logger Plexus logger instance from org.codehaus.plexus.logging.Logger
193
*/
194
public DefaultLog(Logger logger);
195
}
196
```
197
198
**Features:**
199
- Wraps a Plexus Logger instance
200
- Safely converts CharSequence to String
201
- Delegates all logging operations to underlying Plexus logger
202
- Used internally by Maven to provide proper logging integration
203
204
## Logging Best Practices
205
206
### Log Level Guidelines
207
208
**Debug Level**: Detailed diagnostic information for plugin developers
209
```java
210
log.debug("Analyzing file: " + file.getAbsolutePath());
211
log.debug("Configuration loaded: " + config.toString());
212
log.debug("Cache hit for key: " + cacheKey);
213
```
214
215
**Info Level**: General information about plugin execution progress
216
```java
217
log.info("Processing " + fileCount + " source files");
218
log.info("Generated " + outputFiles.size() + " output files");
219
log.info("Plugin execution completed successfully");
220
```
221
222
**Warn Level**: Important issues that don't prevent execution
223
```java
224
log.warn("No source files found in " + sourceDirectory);
225
log.warn("Parameter 'oldParam' is deprecated, use 'newParam' instead");
226
log.warn("Output file already exists and will be overwritten: " + outputFile);
227
```
228
229
**Error Level**: Serious problems that may cause execution to fail
230
```java
231
log.error("Failed to read configuration file: " + configFile);
232
log.error("Required dependency not found on classpath");
233
log.error("Unable to create output directory: " + outputDir);
234
```
235
236
### Performance Considerations
237
238
Always check if logging level is enabled before expensive operations:
239
240
```java
241
// Good - avoids expensive string operations when debug is disabled
242
if (log.isDebugEnabled()) {
243
log.debug("Processing items: " + items.stream()
244
.map(Item::toString)
245
.collect(Collectors.joining(", ")));
246
}
247
248
// Bad - performs expensive operations even when debug is disabled
249
log.debug("Processing items: " + items.stream()
250
.map(Item::toString)
251
.collect(Collectors.joining(", ")));
252
```
253
254
### Exception Logging
255
256
Include both message context and exception details:
257
258
```java
259
try {
260
Files.copy(source, target);
261
} catch (IOException e) {
262
// Log the error with context
263
log.error("Failed to copy " + source + " to " + target, e);
264
265
// Then throw appropriate Mojo exception
266
throw new MojoExecutionException("File copy operation failed", e);
267
}
268
```
269
270
### Structured Logging
271
272
Use consistent formatting for better readability:
273
274
```java
275
// Good - consistent, structured format
276
log.info("=== Starting Code Generation ===");
277
log.info("Source directory: " + sourceDir);
278
log.info("Output directory: " + outputDir);
279
log.info("Template files: " + templateFiles.size());
280
281
// Process files...
282
283
log.info("=== Code Generation Complete ===");
284
log.info("Generated " + generatedCount + " files in " + duration + "ms");
285
```
286
287
### CharSequence Support
288
289
Take advantage of CharSequence support to avoid unnecessary string conversions:
290
291
```java
292
// Can pass StringBuilder directly
293
StringBuilder message = new StringBuilder();
294
message.append("Processed ").append(count).append(" items");
295
log.info(message); // No need to call toString()
296
297
// StringBuffer also works
298
StringBuffer buffer = new StringBuffer();
299
buffer.append("Configuration: ").append(config.getName());
300
log.debug(buffer);
301
```
302
303
### Never Use System.out or System.err
304
305
Always use the injected Log interface instead of direct console output:
306
307
```java
308
// Good - uses Maven logging system
309
getLog().info("Processing complete");
310
311
// Bad - bypasses Maven logging
312
System.out.println("Processing complete");
313
```