Build time CDI dependency injection framework for Quarkus applications with conditional bean support and context management
—
CDI-based logger injection with support for custom logger names and automatic bean-specific logger creation. Quarkus Arc provides seamless integration with JBoss Logging through CDI qualifiers.
CDI qualifier annotation for injecting loggers with custom names.
/**
* CDI qualifier for injecting loggers with custom names.
*/
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
public @interface LoggerName {
/**
* The logger name must not be empty.
* @return the logger name
*/
@Nonbinding
String value();
/**
* Supports inline instantiation of this qualifier.
*/
public static final class Literal extends AnnotationLiteral<LoggerName> implements LoggerName {
private static final long serialVersionUID = 1L;
private final String value;
public Literal(String value);
public String value();
}
}Usage Examples:
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import io.quarkus.arc.log.LoggerName;
import org.jboss.logging.Logger;
@ApplicationScoped
public class UserService {
// Default logger - uses the class name as logger name
@Inject
Logger defaultLogger;
// Custom named logger
@Inject
@LoggerName("user.operations")
Logger operationsLogger;
// Another custom logger for security events
@Inject
@LoggerName("security.audit")
Logger securityLogger;
public void createUser(String username) {
defaultLogger.info("Creating user: " + username);
operationsLogger.debug("User creation operation started");
securityLogger.info("New user account created: " + username);
}
public void deleteUser(String username) {
defaultLogger.warn("Deleting user: " + username);
securityLogger.warn("User account deleted: " + username);
}
}Inject loggers as method parameters in producer methods or other CDI methods.
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.inject.Produces;
import io.quarkus.arc.log.LoggerName;
import org.jboss.logging.Logger;
@ApplicationScoped
public class ServiceFactory {
@Produces
@ApplicationScoped
public DatabaseService createDatabaseService(
@LoggerName("database.operations") Logger dbLogger) {
return new DatabaseService(dbLogger);
}
@Produces
@ApplicationScoped
public CacheService createCacheService(
@LoggerName("cache.operations") Logger cacheLogger) {
return new CacheService(cacheLogger);
}
}
class DatabaseService {
private final Logger logger;
public DatabaseService(Logger logger) {
this.logger = logger;
}
public void performQuery(String sql) {
logger.debug("Executing query: " + sql);
// Database operation
logger.info("Query executed successfully");
}
}
class CacheService {
private final Logger logger;
public CacheService(Logger logger) {
this.logger = logger;
}
public void put(String key, Object value) {
logger.trace("Caching value for key: " + key);
// Cache operation
}
}Use the LoggerName.Literal class for programmatic logger creation.
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.enterprise.inject.Instance;
import io.quarkus.arc.log.LoggerName;
import org.jboss.logging.Logger;
@ApplicationScoped
public class DynamicLoggingService {
@Inject
Instance<Logger> loggerInstance;
public void logWithDynamicName(String loggerName, String message) {
// Create logger with dynamic name
Logger logger = loggerInstance
.select(new LoggerName.Literal(loggerName))
.get();
logger.info(message);
}
public void processModules(String[] modules) {
for (String module : modules) {
Logger moduleLogger = loggerInstance
.select(new LoggerName.Literal("module." + module))
.get();
moduleLogger.info("Processing module: " + module);
}
}
}Organize loggers using hierarchical naming patterns.
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import io.quarkus.arc.log.LoggerName;
import org.jboss.logging.Logger;
@ApplicationScoped
public class OrderProcessingService {
// Main service logger
@Inject
@LoggerName("orders")
Logger ordersLogger;
// Validation subsystem
@Inject
@LoggerName("orders.validation")
Logger validationLogger;
// Payment subsystem
@Inject
@LoggerName("orders.payment")
Logger paymentLogger;
// Inventory subsystem
@Inject
@LoggerName("orders.inventory")
Logger inventoryLogger;
// Notification subsystem
@Inject
@LoggerName("orders.notifications")
Logger notificationLogger;
public void processOrder(Order order) {
ordersLogger.info("Processing order: " + order.getId());
try {
validateOrder(order);
processPayment(order);
updateInventory(order);
sendNotifications(order);
ordersLogger.info("Order processing completed: " + order.getId());
} catch (Exception e) {
ordersLogger.error("Order processing failed: " + order.getId(), e);
throw e;
}
}
private void validateOrder(Order order) {
validationLogger.debug("Validating order: " + order.getId());
// Validation logic
validationLogger.info("Order validation passed: " + order.getId());
}
private void processPayment(Order order) {
paymentLogger.debug("Processing payment for order: " + order.getId());
// Payment logic
paymentLogger.info("Payment processed: " + order.getId());
}
private void updateInventory(Order order) {
inventoryLogger.debug("Updating inventory for order: " + order.getId());
// Inventory logic
inventoryLogger.info("Inventory updated: " + order.getId());
}
private void sendNotifications(Order order) {
notificationLogger.debug("Sending notifications for order: " + order.getId());
// Notification logic
notificationLogger.info("Notifications sent: " + order.getId());
}
}
class Order {
private String id;
// Other order fields
public String getId() { return id; }
public void setId(String id) { this.id = id; }
}Create loggers in producer methods for dependency injection into non-CDI objects.
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.inject.Produces;
import jakarta.enterprise.inject.spi.InjectionPoint;
import io.quarkus.arc.log.LoggerName;
import org.jboss.logging.Logger;
@ApplicationScoped
public class LoggerProducer {
@Produces
public Logger createClassLogger(InjectionPoint injectionPoint) {
// Create logger based on the injection point's class
return Logger.getLogger(injectionPoint.getMember().getDeclaringClass());
}
@Produces
@LoggerName("custom")
public Logger createCustomLogger() {
return Logger.getLogger("custom.application.logger");
}
}
// Usage in services
@ApplicationScoped
public class ProductService {
@Inject
Logger logger; // Will be created using class name
@Inject
@LoggerName("custom")
Logger customLogger;
public void manageProduct(String productId) {
logger.info("Managing product: " + productId);
customLogger.debug("Custom logging for product: " + productId);
}
}Combine logger injection with configuration for dynamic logging behavior.
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import io.quarkus.arc.log.LoggerName;
import org.jboss.logging.Logger;
@ApplicationScoped
public class ConfigurableLoggingService {
@Inject
@LoggerName("app.performance")
Logger performanceLogger;
@Inject
@LoggerName("app.business")
Logger businessLogger;
@ConfigProperty(name = "logging.performance.enabled", defaultValue = "false")
boolean performanceLoggingEnabled;
@ConfigProperty(name = "logging.detailed", defaultValue = "false")
boolean detailedLogging;
public void performBusinessOperation(String operation) {
long startTime = System.currentTimeMillis();
if (detailedLogging) {
businessLogger.info("Starting business operation: " + operation);
}
try {
// Business logic here
Thread.sleep(100); // Simulate work
businessLogger.info("Completed business operation: " + operation);
} catch (Exception e) {
businessLogger.error("Business operation failed: " + operation, e);
throw new RuntimeException(e);
} finally {
if (performanceLoggingEnabled) {
long duration = System.currentTimeMillis() - startTime;
performanceLogger.info("Operation '" + operation + "' took " + duration + "ms");
}
}
}
}Configure logger levels and output through standard Quarkus logging configuration:
# Root logger configuration
quarkus.log.level=INFO
quarkus.log.console.enable=true
# Custom logger categories
quarkus.log.category."user.operations".level=DEBUG
quarkus.log.category."security.audit".level=INFO
quarkus.log.category."orders".level=INFO
quarkus.log.category."orders.validation".level=DEBUG
quarkus.log.category."orders.payment".level=WARN
# Performance logging
quarkus.log.category."app.performance".level=INFO
# File output for specific categories
quarkus.log.category."security.audit".handlers=SECURITY_FILE
quarkus.log.handler.file.SECURITY_FILE.enable=true
quarkus.log.handler.file.SECURITY_FILE.path=security-audit.log
quarkus.log.handler.file.SECURITY_FILE.format=%d{yyyy-MM-dd HH:mm:ss} %-5p [%c] %s%e%n# Enable/disable performance logging at runtime
logging.performance.enabled=true
logging.detailed=false// Use hierarchical naming for related loggers
@LoggerName("app.module.component") // Good
@LoggerName("RandomLoggerName") // Avoid
// Examples of good logger names
@LoggerName("security.authentication")
@LoggerName("performance.database")
@LoggerName("integration.external-api")
@LoggerName("business.order-processing")@ApplicationScoped
public class WellOrganizedService {
// Main service logger
@Inject
Logger serviceLogger;
// Specialized loggers for different concerns
@Inject
@LoggerName("performance.metrics")
Logger metricsLogger;
@Inject
@LoggerName("security.access")
Logger securityLogger;
@Inject
@LoggerName("integration.third-party")
Logger integrationLogger;
}@ApplicationScoped
public class ErrorHandlingExample {
@Inject
@LoggerName("errors.business")
Logger errorLogger;
public void handleBusinessOperation() {
try {
// Business logic
} catch (BusinessException e) {
errorLogger.warn("Business rule violation", e);
// Handle gracefully
} catch (Exception e) {
errorLogger.error("Unexpected error in business operation", e);
throw e;
}
}
}Install with Tessl CLI
npx tessl i tessl/maven-io-quarkus--quarkus-arc