0
# Logging Framework
1
2
Comprehensive logging framework with context-aware logging, audit trail capabilities, and structured logging utilities for CDAP components.
3
4
## Capabilities
5
6
### Logging Context Management
7
8
Context-aware logging system for structured log organization and filtering.
9
10
```java { .api }
11
/**
12
* Interface for logging context
13
*/
14
public interface LoggingContext {
15
/**
16
* Get the log partition for this context
17
* @return Log partition identifier
18
*/
19
String getLogPartition();
20
21
/**
22
* Get the log path fragment for this context
23
* @return Path fragment for log organization
24
*/
25
String getLogPathFragment();
26
27
/**
28
* Get system tags for this logging context
29
* @return Map of system tags
30
*/
31
Map<String, String> getSystemTags();
32
}
33
34
/**
35
* Abstract base class for logging contexts
36
*/
37
public abstract class AbstractLoggingContext implements LoggingContext {
38
protected AbstractLoggingContext();
39
40
@Override
41
public abstract String getLogPartition();
42
43
@Override
44
public abstract String getLogPathFragment();
45
46
@Override
47
public Map<String, String> getSystemTags();
48
49
/**
50
* Add a system tag
51
*/
52
protected void addSystemTag(String key, String value);
53
}
54
```
55
56
### Logging Context Implementations
57
58
Specific logging context implementations for different CDAP components.
59
60
```java { .api }
61
/**
62
* Logging context for CDAP components
63
*/
64
public class ComponentLoggingContext extends AbstractLoggingContext {
65
public ComponentLoggingContext(String componentName);
66
public ComponentLoggingContext(String componentName, String instanceId);
67
68
@Override
69
public String getLogPartition();
70
71
@Override
72
public String getLogPathFragment();
73
74
/**
75
* Get the component name
76
*/
77
public String getComponentName();
78
79
/**
80
* Get the instance ID
81
*/
82
public String getInstanceId();
83
}
84
85
/**
86
* Logging context for namespace-specific operations
87
*/
88
public class NamespaceLoggingContext extends AbstractLoggingContext {
89
public NamespaceLoggingContext(String namespaceId);
90
91
@Override
92
public String getLogPartition();
93
94
@Override
95
public String getLogPathFragment();
96
97
/**
98
* Get the namespace ID
99
*/
100
public String getNamespaceId();
101
}
102
103
/**
104
* Logging context for service-specific operations
105
*/
106
public class ServiceLoggingContext extends AbstractLoggingContext {
107
public ServiceLoggingContext(String serviceName, String serviceId);
108
public ServiceLoggingContext(String serviceName, String serviceId, String runId);
109
110
@Override
111
public String getLogPartition();
112
113
@Override
114
public String getLogPathFragment();
115
116
/**
117
* Get the service name
118
*/
119
public String getServiceName();
120
121
/**
122
* Get the service ID
123
*/
124
public String getServiceId();
125
126
/**
127
* Get the run ID
128
*/
129
public String getRunId();
130
}
131
```
132
133
### Logger Utilities
134
135
Utilities for logger creation and management.
136
137
```java { .api }
138
/**
139
* Logger utilities
140
*/
141
public class Loggers {
142
/**
143
* Get logger for a class
144
*/
145
public static <T> Logger getLogger(Class<T> clazz);
146
147
/**
148
* Get logger with specified name
149
*/
150
public static Logger getLogger(String name);
151
152
/**
153
* Get logger for a class with logging context
154
*/
155
public static <T> Logger getLogger(Class<T> clazz, LoggingContext loggingContext);
156
157
/**
158
* Set logging context for current thread
159
*/
160
public static void setLoggingContext(LoggingContext loggingContext);
161
162
/**
163
* Get logging context for current thread
164
*/
165
public static LoggingContext getLoggingContext();
166
167
/**
168
* Clear logging context for current thread
169
*/
170
public static void clearLoggingContext();
171
}
172
```
173
174
### Log Sampling
175
176
Log sampling interfaces and implementations for controlling log volume.
177
178
```java { .api }
179
/**
180
* Interface for log sampling decisions
181
*/
182
public interface LogSampler {
183
/**
184
* Decide whether to accept a log entry
185
* @param logLevel The log level
186
* @param loggerName The logger name
187
* @param message The log message
188
* @return true if log should be accepted
189
*/
190
boolean accept(String logLevel, String loggerName, String message);
191
}
192
193
/**
194
* Log sampler implementations
195
*/
196
public class LogSamplers {
197
/**
198
* Accept all log entries (no sampling)
199
*/
200
public static LogSampler acceptAll();
201
202
/**
203
* Accept no log entries (drop all)
204
*/
205
public static LogSampler acceptNone();
206
207
/**
208
* Sample based on rate (e.g., accept 1 in every N)
209
*/
210
public static LogSampler rateBased(int rate);
211
212
/**
213
* Sample based on time window (e.g., max N logs per minute)
214
*/
215
public static LogSampler timeBased(int maxLogsPerWindow, long windowSizeMs);
216
217
/**
218
* Sample based on log level
219
*/
220
public static LogSampler levelBased(String minLevel);
221
222
/**
223
* Combine multiple samplers with AND logic
224
*/
225
public static LogSampler and(LogSampler... samplers);
226
227
/**
228
* Combine multiple samplers with OR logic
229
*/
230
public static LogSampler or(LogSampler... samplers);
231
}
232
```
233
234
### Audit Logging
235
236
Audit log entry representation and utilities.
237
238
```java { .api }
239
/**
240
* Audit log entry representation
241
*/
242
public class AuditLogEntry {
243
public AuditLogEntry(String user, String operation, String entityType,
244
String entityId, long timestamp);
245
246
/**
247
* Get the user who performed the operation
248
*/
249
public String getUser();
250
251
/**
252
* Get the operation performed
253
*/
254
public String getOperation();
255
256
/**
257
* Get the type of entity operated on
258
*/
259
public String getEntityType();
260
261
/**
262
* Get the ID of the entity operated on
263
*/
264
public String getEntityId();
265
266
/**
267
* Get the timestamp of the operation
268
*/
269
public long getTimestamp();
270
271
/**
272
* Get additional metadata
273
*/
274
public Map<String, String> getMetadata();
275
276
/**
277
* Add metadata entry
278
*/
279
public AuditLogEntry addMetadata(String key, String value);
280
281
/**
282
* Convert to JSON representation
283
*/
284
public String toJson();
285
}
286
```
287
288
**Usage Examples:**
289
290
```java
291
import io.cdap.cdap.common.logging.*;
292
import org.slf4j.Logger;
293
294
// Using logging contexts
295
public class ApplicationService {
296
private static final Logger LOG = Loggers.getLogger(ApplicationService.class);
297
298
public void deployApplication(String namespaceId, String appId, ApplicationSpec spec) {
299
// Set namespace logging context
300
NamespaceLoggingContext loggingContext = new NamespaceLoggingContext(namespaceId);
301
Loggers.setLoggingContext(loggingContext);
302
303
try {
304
LOG.info("Deploying application: {}", appId);
305
306
// Component-specific logging context
307
ComponentLoggingContext componentContext =
308
new ComponentLoggingContext("app-fabric", "instance-1");
309
Loggers.setLoggingContext(componentContext);
310
311
performDeployment(spec);
312
LOG.info("Application deployed successfully: {}", appId);
313
314
} catch (Exception e) {
315
LOG.error("Failed to deploy application: {}", appId, e);
316
throw e;
317
} finally {
318
Loggers.clearLoggingContext();
319
}
320
}
321
322
private void performDeployment(ApplicationSpec spec) {
323
Logger componentLogger = Loggers.getLogger(ApplicationService.class,
324
Loggers.getLoggingContext());
325
componentLogger.debug("Processing application spec: {}", spec.getName());
326
// Deployment logic...
327
}
328
}
329
330
// Service with logging context
331
public class DatasetService {
332
private final ServiceLoggingContext loggingContext;
333
private final Logger LOG;
334
335
public DatasetService(String serviceId, String runId) {
336
this.loggingContext = new ServiceLoggingContext("dataset-service", serviceId, runId);
337
this.LOG = Loggers.getLogger(DatasetService.class, loggingContext);
338
}
339
340
public void createDataset(String datasetId, DatasetSpec spec) {
341
LOG.info("Creating dataset: {} with type: {}", datasetId, spec.getType());
342
343
try {
344
// Dataset creation logic
345
datasetManager.create(datasetId, spec);
346
LOG.info("Dataset created successfully: {}", datasetId);
347
} catch (Exception e) {
348
LOG.error("Failed to create dataset: {}", datasetId, e);
349
throw e;
350
}
351
}
352
}
353
354
// Log sampling configuration
355
public class LoggingConfig {
356
public void configureSampling() {
357
// Rate-based sampling: accept 1 in every 100 logs
358
LogSampler rateSampler = LogSamplers.rateBased(100);
359
360
// Time-based sampling: max 10 logs per minute
361
LogSampler timeSampler = LogSamplers.timeBased(10, 60000);
362
363
// Level-based sampling: only WARN and above
364
LogSampler levelSampler = LogSamplers.levelBased("WARN");
365
366
// Combined sampling: rate AND level
367
LogSampler combinedSampler = LogSamplers.and(rateSampler, levelSampler);
368
369
// Apply sampler (implementation specific)
370
applySampler(combinedSampler);
371
}
372
373
private void applySampler(LogSampler sampler) {
374
// Configure logging framework with sampler
375
System.out.println("Configured log sampler: " + sampler.getClass().getSimpleName());
376
}
377
}
378
379
// Audit logging
380
public class AuditService {
381
private final Logger auditLogger = Loggers.getLogger("AUDIT");
382
383
public void auditApplicationDeployment(String user, String namespaceId,
384
String appId, boolean success) {
385
AuditLogEntry entry = new AuditLogEntry(
386
user,
387
success ? "APPLICATION_DEPLOY" : "APPLICATION_DEPLOY_FAILED",
388
"APPLICATION",
389
appId,
390
System.currentTimeMillis()
391
)
392
.addMetadata("namespace", namespaceId)
393
.addMetadata("success", String.valueOf(success));
394
395
auditLogger.info(entry.toJson());
396
}
397
398
public void auditDatasetAccess(String user, String datasetId, String operation) {
399
AuditLogEntry entry = new AuditLogEntry(
400
user,
401
"DATASET_" + operation.toUpperCase(),
402
"DATASET",
403
datasetId,
404
System.currentTimeMillis()
405
)
406
.addMetadata("operation", operation)
407
.addMetadata("source", "dataset-service");
408
409
auditLogger.info(entry.toJson());
410
}
411
}
412
413
// Advanced logging with thread-local context
414
public class ThreadContextLogging {
415
private static final Logger LOG = Loggers.getLogger(ThreadContextLogging.class);
416
417
public void processRequest(String namespaceId, String requestId) {
418
// Set context for entire request processing
419
NamespaceLoggingContext context = new NamespaceLoggingContext(namespaceId);
420
context.addSystemTag("requestId", requestId);
421
context.addSystemTag("threadId", Thread.currentThread().getName());
422
423
Loggers.setLoggingContext(context);
424
425
try {
426
LOG.info("Processing request: {}", requestId);
427
428
// Spawn sub-tasks that inherit logging context
429
CompletableFuture.supplyAsync(() -> {
430
Logger taskLogger = Loggers.getLogger(ThreadContextLogging.class,
431
Loggers.getLoggingContext());
432
taskLogger.debug("Executing sub-task for request: {}", requestId);
433
return performSubTask();
434
}).get();
435
436
LOG.info("Request processing completed: {}", requestId);
437
438
} catch (Exception e) {
439
LOG.error("Request processing failed: {}", requestId, e);
440
} finally {
441
Loggers.clearLoggingContext();
442
}
443
}
444
445
private String performSubTask() {
446
// Sub-task logic with inherited logging context
447
return "result";
448
}
449
}
450
```