CDAP Common provides core common utilities and abstractions for the CDAP (Cask Data Application Platform) ecosystem including exception handling, service management, configuration, HTTP utilities, metadata management, security abstractions, discovery services, and various utility classes that are shared across CDAP components.
—
Comprehensive logging framework with context-aware logging, audit trail capabilities, and structured logging utilities for CDAP components.
Context-aware logging system for structured log organization and filtering.
/**
* Interface for logging context
*/
public interface LoggingContext {
/**
* Get the log partition for this context
* @return Log partition identifier
*/
String getLogPartition();
/**
* Get the log path fragment for this context
* @return Path fragment for log organization
*/
String getLogPathFragment();
/**
* Get system tags for this logging context
* @return Map of system tags
*/
Map<String, String> getSystemTags();
}
/**
* Abstract base class for logging contexts
*/
public abstract class AbstractLoggingContext implements LoggingContext {
protected AbstractLoggingContext();
@Override
public abstract String getLogPartition();
@Override
public abstract String getLogPathFragment();
@Override
public Map<String, String> getSystemTags();
/**
* Add a system tag
*/
protected void addSystemTag(String key, String value);
}Specific logging context implementations for different CDAP components.
/**
* Logging context for CDAP components
*/
public class ComponentLoggingContext extends AbstractLoggingContext {
public ComponentLoggingContext(String componentName);
public ComponentLoggingContext(String componentName, String instanceId);
@Override
public String getLogPartition();
@Override
public String getLogPathFragment();
/**
* Get the component name
*/
public String getComponentName();
/**
* Get the instance ID
*/
public String getInstanceId();
}
/**
* Logging context for namespace-specific operations
*/
public class NamespaceLoggingContext extends AbstractLoggingContext {
public NamespaceLoggingContext(String namespaceId);
@Override
public String getLogPartition();
@Override
public String getLogPathFragment();
/**
* Get the namespace ID
*/
public String getNamespaceId();
}
/**
* Logging context for service-specific operations
*/
public class ServiceLoggingContext extends AbstractLoggingContext {
public ServiceLoggingContext(String serviceName, String serviceId);
public ServiceLoggingContext(String serviceName, String serviceId, String runId);
@Override
public String getLogPartition();
@Override
public String getLogPathFragment();
/**
* Get the service name
*/
public String getServiceName();
/**
* Get the service ID
*/
public String getServiceId();
/**
* Get the run ID
*/
public String getRunId();
}Utilities for logger creation and management.
/**
* Logger utilities
*/
public class Loggers {
/**
* Get logger for a class
*/
public static <T> Logger getLogger(Class<T> clazz);
/**
* Get logger with specified name
*/
public static Logger getLogger(String name);
/**
* Get logger for a class with logging context
*/
public static <T> Logger getLogger(Class<T> clazz, LoggingContext loggingContext);
/**
* Set logging context for current thread
*/
public static void setLoggingContext(LoggingContext loggingContext);
/**
* Get logging context for current thread
*/
public static LoggingContext getLoggingContext();
/**
* Clear logging context for current thread
*/
public static void clearLoggingContext();
}Log sampling interfaces and implementations for controlling log volume.
/**
* Interface for log sampling decisions
*/
public interface LogSampler {
/**
* Decide whether to accept a log entry
* @param logLevel The log level
* @param loggerName The logger name
* @param message The log message
* @return true if log should be accepted
*/
boolean accept(String logLevel, String loggerName, String message);
}
/**
* Log sampler implementations
*/
public class LogSamplers {
/**
* Accept all log entries (no sampling)
*/
public static LogSampler acceptAll();
/**
* Accept no log entries (drop all)
*/
public static LogSampler acceptNone();
/**
* Sample based on rate (e.g., accept 1 in every N)
*/
public static LogSampler rateBased(int rate);
/**
* Sample based on time window (e.g., max N logs per minute)
*/
public static LogSampler timeBased(int maxLogsPerWindow, long windowSizeMs);
/**
* Sample based on log level
*/
public static LogSampler levelBased(String minLevel);
/**
* Combine multiple samplers with AND logic
*/
public static LogSampler and(LogSampler... samplers);
/**
* Combine multiple samplers with OR logic
*/
public static LogSampler or(LogSampler... samplers);
}Audit log entry representation and utilities.
/**
* Audit log entry representation
*/
public class AuditLogEntry {
public AuditLogEntry(String user, String operation, String entityType,
String entityId, long timestamp);
/**
* Get the user who performed the operation
*/
public String getUser();
/**
* Get the operation performed
*/
public String getOperation();
/**
* Get the type of entity operated on
*/
public String getEntityType();
/**
* Get the ID of the entity operated on
*/
public String getEntityId();
/**
* Get the timestamp of the operation
*/
public long getTimestamp();
/**
* Get additional metadata
*/
public Map<String, String> getMetadata();
/**
* Add metadata entry
*/
public AuditLogEntry addMetadata(String key, String value);
/**
* Convert to JSON representation
*/
public String toJson();
}Usage Examples:
import io.cdap.cdap.common.logging.*;
import org.slf4j.Logger;
// Using logging contexts
public class ApplicationService {
private static final Logger LOG = Loggers.getLogger(ApplicationService.class);
public void deployApplication(String namespaceId, String appId, ApplicationSpec spec) {
// Set namespace logging context
NamespaceLoggingContext loggingContext = new NamespaceLoggingContext(namespaceId);
Loggers.setLoggingContext(loggingContext);
try {
LOG.info("Deploying application: {}", appId);
// Component-specific logging context
ComponentLoggingContext componentContext =
new ComponentLoggingContext("app-fabric", "instance-1");
Loggers.setLoggingContext(componentContext);
performDeployment(spec);
LOG.info("Application deployed successfully: {}", appId);
} catch (Exception e) {
LOG.error("Failed to deploy application: {}", appId, e);
throw e;
} finally {
Loggers.clearLoggingContext();
}
}
private void performDeployment(ApplicationSpec spec) {
Logger componentLogger = Loggers.getLogger(ApplicationService.class,
Loggers.getLoggingContext());
componentLogger.debug("Processing application spec: {}", spec.getName());
// Deployment logic...
}
}
// Service with logging context
public class DatasetService {
private final ServiceLoggingContext loggingContext;
private final Logger LOG;
public DatasetService(String serviceId, String runId) {
this.loggingContext = new ServiceLoggingContext("dataset-service", serviceId, runId);
this.LOG = Loggers.getLogger(DatasetService.class, loggingContext);
}
public void createDataset(String datasetId, DatasetSpec spec) {
LOG.info("Creating dataset: {} with type: {}", datasetId, spec.getType());
try {
// Dataset creation logic
datasetManager.create(datasetId, spec);
LOG.info("Dataset created successfully: {}", datasetId);
} catch (Exception e) {
LOG.error("Failed to create dataset: {}", datasetId, e);
throw e;
}
}
}
// Log sampling configuration
public class LoggingConfig {
public void configureSampling() {
// Rate-based sampling: accept 1 in every 100 logs
LogSampler rateSampler = LogSamplers.rateBased(100);
// Time-based sampling: max 10 logs per minute
LogSampler timeSampler = LogSamplers.timeBased(10, 60000);
// Level-based sampling: only WARN and above
LogSampler levelSampler = LogSamplers.levelBased("WARN");
// Combined sampling: rate AND level
LogSampler combinedSampler = LogSamplers.and(rateSampler, levelSampler);
// Apply sampler (implementation specific)
applySampler(combinedSampler);
}
private void applySampler(LogSampler sampler) {
// Configure logging framework with sampler
System.out.println("Configured log sampler: " + sampler.getClass().getSimpleName());
}
}
// Audit logging
public class AuditService {
private final Logger auditLogger = Loggers.getLogger("AUDIT");
public void auditApplicationDeployment(String user, String namespaceId,
String appId, boolean success) {
AuditLogEntry entry = new AuditLogEntry(
user,
success ? "APPLICATION_DEPLOY" : "APPLICATION_DEPLOY_FAILED",
"APPLICATION",
appId,
System.currentTimeMillis()
)
.addMetadata("namespace", namespaceId)
.addMetadata("success", String.valueOf(success));
auditLogger.info(entry.toJson());
}
public void auditDatasetAccess(String user, String datasetId, String operation) {
AuditLogEntry entry = new AuditLogEntry(
user,
"DATASET_" + operation.toUpperCase(),
"DATASET",
datasetId,
System.currentTimeMillis()
)
.addMetadata("operation", operation)
.addMetadata("source", "dataset-service");
auditLogger.info(entry.toJson());
}
}
// Advanced logging with thread-local context
public class ThreadContextLogging {
private static final Logger LOG = Loggers.getLogger(ThreadContextLogging.class);
public void processRequest(String namespaceId, String requestId) {
// Set context for entire request processing
NamespaceLoggingContext context = new NamespaceLoggingContext(namespaceId);
context.addSystemTag("requestId", requestId);
context.addSystemTag("threadId", Thread.currentThread().getName());
Loggers.setLoggingContext(context);
try {
LOG.info("Processing request: {}", requestId);
// Spawn sub-tasks that inherit logging context
CompletableFuture.supplyAsync(() -> {
Logger taskLogger = Loggers.getLogger(ThreadContextLogging.class,
Loggers.getLoggingContext());
taskLogger.debug("Executing sub-task for request: {}", requestId);
return performSubTask();
}).get();
LOG.info("Request processing completed: {}", requestId);
} catch (Exception e) {
LOG.error("Request processing failed: {}", requestId, e);
} finally {
Loggers.clearLoggingContext();
}
}
private String performSubTask() {
// Sub-task logic with inherited logging context
return "result";
}
}Install with Tessl CLI
npx tessl i tessl/maven-io-cdap-cdap--cdap-common