0
# Logging
1
2
Configurable logging system with multiple severity levels and custom logger support. This module enables debugging, monitoring, and troubleshooting of libfreenect2 operations.
3
4
## Capabilities
5
6
### Logger Base Class
7
8
Base logging interface that can be extended for custom logging implementations.
9
10
```java { .api }
11
/**
12
* Provide interfaces to receive log messages.
13
* You can inherit this class and implement your custom logger.
14
*/
15
abstract class Logger {
16
// Logging level constants
17
/** No logging output */
18
static final int None = 0;
19
/** Error messages only */
20
static final int Error = 1;
21
/** Error and warning messages */
22
static final int Warning = 2;
23
/** Error, warning, and info messages */
24
static final int Info = 3;
25
/** All messages including debug output */
26
static final int Debug = 4;
27
28
/**
29
* Default logging level (Info), or overridden by environment variable.
30
* LIBFREENECT2_LOGGER_LEVEL can contain a case-insensitive name of level.
31
*/
32
@Cast("libfreenect2::Logger::Level") static int getDefaultLevel();
33
34
/**
35
* Convert logging level to a human-readable name
36
*/
37
@StdString static BytePointer level2str(@Cast("libfreenect2::Logger::Level") int level);
38
39
/**
40
* Get the level of the logger; the level is immutable
41
*/
42
@Cast("libfreenect2::Logger::Level") abstract int level();
43
44
/**
45
* libfreenect2 calls this function to output all log messages
46
* @param level Message severity level
47
* @param message Log message content
48
*/
49
void log(@Cast("libfreenect2::Logger::Level") int level, @StdString BytePointer message);
50
void log(@Cast("libfreenect2::Logger::Level") int level, @StdString String message);
51
}
52
```
53
54
**Usage Examples:**
55
56
```java
57
// Check default logging level
58
int defaultLevel = Logger.getDefaultLevel();
59
System.out.println("Default log level: " + Logger.level2str(defaultLevel).getString());
60
61
// The library automatically creates a console logger, but you can customize it
62
```
63
64
### Custom Logger Implementation
65
66
Implement custom loggers for different output destinations and formats.
67
68
**Usage Examples:**
69
70
```java
71
// Custom file logger implementation
72
class FileLogger extends Logger {
73
private final int logLevel;
74
private final PrintWriter writer;
75
76
public FileLogger(int level, String filename) throws IOException {
77
this.logLevel = level;
78
this.writer = new PrintWriter(new FileWriter(filename, true));
79
}
80
81
@Override
82
public int level() {
83
return logLevel;
84
}
85
86
@Override
87
public void log(int level, String message) {
88
if (level <= this.logLevel) {
89
String timestamp = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
90
String levelName = Logger.level2str(level).getString();
91
writer.println("[" + timestamp + "] " + levelName + ": " + message);
92
writer.flush();
93
}
94
}
95
96
@Override
97
public void log(int level, BytePointer message) {
98
log(level, message.getString());
99
}
100
101
public void close() {
102
writer.close();
103
}
104
}
105
106
// Custom console logger with formatting
107
class FormattedConsoleLogger extends Logger {
108
private final int logLevel;
109
110
public FormattedConsoleLogger(int level) {
111
this.logLevel = level;
112
}
113
114
@Override
115
public int level() {
116
return logLevel;
117
}
118
119
@Override
120
public void log(int level, String message) {
121
if (level <= this.logLevel) {
122
String levelName = Logger.level2str(level).getString();
123
String prefix = "";
124
125
switch (level) {
126
case Logger.Error:
127
prefix = "ERROR ";
128
break;
129
case Logger.Warning:
130
prefix = "WARN ";
131
break;
132
case Logger.Info:
133
prefix = "INFO ";
134
break;
135
case Logger.Debug:
136
prefix = "DEBUG ";
137
break;
138
}
139
140
System.out.println("[libfreenect2] " + prefix + message);
141
}
142
}
143
144
@Override
145
public void log(int level, BytePointer message) {
146
log(level, message.getString());
147
}
148
}
149
```
150
151
### Logging Level Configuration
152
153
Configure logging levels through environment variables or programmatically.
154
155
**Usage Examples:**
156
157
```java
158
// Check environment variable configuration
159
// Set environment variable: LIBFREENECT2_LOGGER_LEVEL=debug
160
int envLevel = Logger.getDefaultLevel();
161
switch (envLevel) {
162
case Logger.None:
163
System.out.println("Logging disabled");
164
break;
165
case Logger.Error:
166
System.out.println("Error logging only");
167
break;
168
case Logger.Warning:
169
System.out.println("Warning and error logging");
170
break;
171
case Logger.Info:
172
System.out.println("Info, warning, and error logging");
173
break;
174
case Logger.Debug:
175
System.out.println("All logging enabled");
176
break;
177
}
178
179
// Create loggers with different levels
180
Logger errorLogger = new FormattedConsoleLogger(Logger.Error);
181
Logger debugLogger = new FormattedConsoleLogger(Logger.Debug);
182
183
// Level names for display
184
for (int level = Logger.None; level <= Logger.Debug; level++) {
185
System.out.println("Level " + level + ": " + Logger.level2str(level).getString());
186
}
187
```
188
189
### Multi-Output Logging
190
191
Implement loggers that output to multiple destinations simultaneously.
192
193
**Usage Examples:**
194
195
```java
196
// Multi-output logger that logs to both console and file
197
class MultiLogger extends Logger {
198
private final List<Logger> loggers;
199
private final int logLevel;
200
201
public MultiLogger(int level, Logger... loggers) {
202
this.logLevel = level;
203
this.loggers = Arrays.asList(loggers);
204
}
205
206
@Override
207
public int level() {
208
return logLevel;
209
}
210
211
@Override
212
public void log(int level, String message) {
213
if (level <= this.logLevel) {
214
for (Logger logger : loggers) {
215
if (level <= logger.level()) {
216
logger.log(level, message);
217
}
218
}
219
}
220
}
221
222
@Override
223
public void log(int level, BytePointer message) {
224
log(level, message.getString());
225
}
226
}
227
228
// Usage
229
try {
230
FileLogger fileLogger = new FileLogger(Logger.Debug, "libfreenect2.log");
231
FormattedConsoleLogger consoleLogger = new FormattedConsoleLogger(Logger.Info);
232
233
MultiLogger multiLogger = new MultiLogger(Logger.Debug, fileLogger, consoleLogger);
234
235
// This would be set as the global logger if the library supported it
236
// In practice, libfreenect2 manages its own logging internally
237
238
} catch (IOException e) {
239
System.err.println("Failed to create file logger: " + e.getMessage());
240
}
241
```
242
243
### Filtering and Conditional Logging
244
245
Implement advanced logging features like filtering and conditional output.
246
247
**Usage Examples:**
248
249
```java
250
// Filtered logger that only logs messages containing specific keywords
251
class FilteredLogger extends Logger {
252
private final Logger delegate;
253
private final Set<String> keywords;
254
private final boolean includeMode; // true = include, false = exclude
255
256
public FilteredLogger(Logger delegate, boolean includeMode, String... keywords) {
257
this.delegate = delegate;
258
this.includeMode = includeMode;
259
this.keywords = new HashSet<>(Arrays.asList(keywords));
260
}
261
262
@Override
263
public int level() {
264
return delegate.level();
265
}
266
267
@Override
268
public void log(int level, String message) {
269
boolean hasKeyword = keywords.stream().anyMatch(message::contains);
270
271
if ((includeMode && hasKeyword) || (!includeMode && !hasKeyword)) {
272
delegate.log(level, message);
273
}
274
}
275
276
@Override
277
public void log(int level, BytePointer message) {
278
log(level, message.getString());
279
}
280
}
281
282
// Rate-limited logger to prevent spam
283
class RateLimitedLogger extends Logger {
284
private final Logger delegate;
285
private final Map<String, Long> lastLogTime = new HashMap<>();
286
private final long minIntervalMs;
287
288
public RateLimitedLogger(Logger delegate, long minIntervalMs) {
289
this.delegate = delegate;
290
this.minIntervalMs = minIntervalMs;
291
}
292
293
@Override
294
public int level() {
295
return delegate.level();
296
}
297
298
@Override
299
public void log(int level, String message) {
300
long now = System.currentTimeMillis();
301
Long lastTime = lastLogTime.get(message);
302
303
if (lastTime == null || (now - lastTime) >= minIntervalMs) {
304
delegate.log(level, message);
305
lastLogTime.put(message, now);
306
}
307
}
308
309
@Override
310
public void log(int level, BytePointer message) {
311
log(level, message.getString());
312
}
313
}
314
315
// Usage examples
316
FormattedConsoleLogger baseLogger = new FormattedConsoleLogger(Logger.Debug);
317
318
// Only log messages containing "device" or "frame"
319
FilteredLogger deviceLogger = new FilteredLogger(baseLogger, true, "device", "frame");
320
321
// Prevent duplicate messages within 5 seconds
322
RateLimitedLogger rateLimitedLogger = new RateLimitedLogger(baseLogger, 5000);
323
```
324
325
## Global Logging Functions
326
327
The library provides global functions for logger management, though these are typically handled internally:
328
329
```java
330
// Note: These are conceptual - actual global logger management
331
// is handled internally by the native library
332
333
/**
334
* Allocate a Logger instance that outputs log to standard input/output
335
*/
336
// Logger createConsoleLogger(int level);
337
338
/**
339
* Create console logger with default level from environment
340
*/
341
// Logger createConsoleLoggerWithDefaultLevel();
342
343
/**
344
* Get the pointer to the current logger (informational only)
345
*/
346
// Logger getGlobalLogger();
347
348
/**
349
* Set the logger for all log output in this library
350
* @param logger Pointer to your logger, or null to disable logging
351
*/
352
// void setGlobalLogger(Logger logger);
353
```
354
355
## Best Practices
356
357
### Logging in Production Applications
358
359
```java
360
public class LibFreenect2Logger {
361
private static Logger applicationLogger;
362
363
public static void initializeLogging(String logFile, int level) {
364
try {
365
if (logFile != null) {
366
FileLogger fileLogger = new FileLogger(level, logFile);
367
FormattedConsoleLogger consoleLogger = new FormattedConsoleLogger(Logger.Warning);
368
applicationLogger = new MultiLogger(level, fileLogger, consoleLogger);
369
} else {
370
applicationLogger = new FormattedConsoleLogger(level);
371
}
372
373
System.out.println("Logging initialized at level: " +
374
Logger.level2str(level).getString());
375
376
} catch (IOException e) {
377
System.err.println("Failed to initialize file logging: " + e.getMessage());
378
applicationLogger = new FormattedConsoleLogger(level);
379
}
380
}
381
382
public static void logDeviceInfo(Freenect2Device device) {
383
if (applicationLogger != null && applicationLogger.level() >= Logger.Info) {
384
String info = "Device Info - Serial: " + device.getSerialNumber().getString() +
385
", Firmware: " + device.getFirmwareVersion().getString();
386
applicationLogger.log(Logger.Info, info);
387
}
388
}
389
390
public static void logError(String message, Exception e) {
391
if (applicationLogger != null) {
392
applicationLogger.log(Logger.Error, message + ": " + e.getMessage());
393
}
394
}
395
}