Quarkus Topic

Configuration, Logging, and Profiles in Quarkus

1. Configuration Management

Configuration Sources Hierarchy

Quarkus follows this order (later sources override earlier ones):

  1. application.properties in src/main/resources

  2. application.yaml in src/main/resources

  3. System properties

  4. Environment variables

  5. .env file

  6. Kubernetes ConfigMaps and Secrets


2. Configuration Formats

application.properties (Traditional)

properties

# Application Configuration
quarkus.application.name=quarkus-config-demo
quarkus.application.version=1.0.0

# Server Configuration
quarkus.http.port=8080
quarkus.http.host=0.0.0.0
quarkus.http.cors=true
quarkus.http.cors.origins=http://localhost:3000,http://localhost:4200

# Database Configuration
quarkus.datasource.db-kind=postgresql
quarkus.datasource.username=quarkus_user
quarkus.datasource.password=quarkus_pass
quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/quarkusdb
quarkus.datasource.jdbc.max-size=16

# Hibernate ORM
quarkus.hibernate-orm.database.generation=update
quarkus.hibernate-orm.log.sql=true
quarkus.hibernate-orm.sql-load-script=import.sql

# Custom Application Configuration
app.name=Quarkus Config Demo
app.version=1.0.0
app.feature.flags.enabled=true
app.security.jwt.secret=my-secret-key
app.security.jwt.expiration=3600
app.rate-limit.requests-per-minute=100

# External Services
external.api.base-url=https://api.example.com
external.api.timeout=5000
external.api.retry.max-attempts=3
external.api.retry.delay=1000

# Email Configuration
app.email.smtp.host=smtp.gmail.com
app.email.smtp.port=587
app.email.smtp.username=your-email@gmail.com
app.email.smtp.password=your-app-password
app.email.from=noreply@example.com

# File Upload Configuration
app.upload.max-file-size=10485760
app.upload.allowed-extensions=jpg,jpeg,png,pdf,doc,docx
app.upload.storage-path=./uploads

application.yaml (Modern Approach)

yaml

# application.yaml
quarkus:
  application:
    name: "quarkus-config-demo"
    version: "1.0.0"
  
  http:
    port: 8080
    host: "0.0.0.0"
    cors: true
    cors:
      origins: "http://localhost:3000,http://localhost:4200"
  
  datasource:
    db-kind: "postgresql"
    username: "quarkus_user"
    password: "quarkus_pass"
    jdbc:
      url: "jdbc:postgresql://localhost:5432/quarkusdb"
      max-size: 16
  
  hibernate-orm:
    database:
      generation: "update"
    log:
      sql: true
    sql-load-script: "import.sql"

# Custom Application Configuration
app:
  name: "Quarkus Config Demo"
  version: "1.0.0"
  feature:
    flags:
      enabled: true
  
  security:
    jwt:
      secret: "my-secret-key"
      expiration: 3600
  
  rate-limit:
    requests-per-minute: 100
  
  upload:
    max-file-size: 10485760
    allowed-extensions: "jpg,jpeg,png,pdf,doc,docx"
    storage-path: "./uploads"
  
  email:
    smtp:
      host: "smtp.gmail.com"
      port: 587
      username: "your-email@gmail.com"
      password: "your-app-password"
    from: "noreply@example.com"

# External Services Configuration
external:
  api:
    base-url: "https://api.example.com"
    timeout: 5000
    retry:
      max-attempts: 3
      delay: 1000

# Feature Toggles
features:
  new-ui: true
  advanced-analytics: false
  experimental-api: true

3. Environment Profiles

Profile-specific Configuration

properties

# application.properties - Common configuration
quarkus.application.name=quarkus-config-demo
app.version=1.0.0

# Development Profile (%dev)
%dev.quarkus.log.level=DEBUG
%dev.quarkus.log.console.enable=true
%dev.quarkus.datasource.db-kind=h2
%dev.quarkus.datasource.jdbc.url=jdbc:h2:mem:devdb
%dev.quarkus.hibernate-orm.database.generation=drop-and-create
%dev.quarkus.hibernate-orm.log.sql=true
%dev.app.feature.flags.enabled=true
%dev.app.security.jwt.secret=dev-secret-key-only
%dev.external.api.base-url=https://dev-api.example.com

# Test Profile (%test)
%test.quarkus.log.level=INFO
%test.quarkus.datasource.db-kind=h2
%test.quarkus.datasource.jdbc.url=jdbc:h2:mem:testdb
%test.quarkus.hibernate-orm.database.generation=drop-and-create
%test.app.security.jwt.secret=test-secret-key-only
%test.external.api.base-url=https://test-api.example.com

# Production Profile (%prod)
%prod.quarkus.log.level=WARN
%prod.quarkus.datasource.db-kind=postgresql
%prod.quarkus.datasource.jdbc.url=jdbc:postgresql://prod-db:5432/quarkusdb
%prod.quarkus.hibernate-orm.database.generation=validate
%prod.quarkus.hibernate-orm.log.sql=false
%prod.app.feature.flags.enabled=false
%prod.app.security.jwt.secret=${JWT_SECRET:default-prod-secret}
%prod.external.api.base-url=https://api.example.com

# Staging Profile (%staging)
%staging.quarkus.log.level=INFO
%staging.quarkus.datasource.db-kind=postgresql
%staging.quarkus.datasource.jdbc.url=jdbc:postgresql://staging-db:5432/quarkusdb
%staging.quarkus.hibernate-orm.database.generation=update
%staging.app.security.jwt.secret=${JWT_SECRET:staging-secret}
%staging.external.api.base-url=https://staging-api.example.com

YAML with Profiles

yaml

# application.yaml
quarkus:
  application:
    name: "quarkus-config-demo"
    version: "1.0.0"

app:
  name: "Quarkus Config Demo"
  security:
    jwt:
      expiration: 3600

# Development Profile
"%dev":
  quarkus:
    log:
      level: "DEBUG"
      console:
        enable: true
    datasource:
      db-kind: "h2"
      jdbc:
        url: "jdbc:h2:mem:devdb"
    hibernate-orm:
      database:
        generation: "drop-and-create"
      log:
        sql: true
  app:
    feature:
      flags:
        enabled: true
    security:
      jwt:
        secret: "dev-secret-key-only"
  external:
    api:
      base-url: "https://dev-api.example.com"

# Test Profile
"%test":
  quarkus:
    log:
      level: "INFO"
    datasource:
      db-kind: "h2"
      jdbc:
        url: "jdbc:h2:mem:testdb"
    hibernate-orm:
      database:
        generation: "drop-and-create"
  app:
    security:
      jwt:
        secret: "test-secret-key-only"
  external:
    api:
      base-url: "https://test-api.example.com"

# Production Profile
"%prod":
  quarkus:
    log:
      level: "WARN"
    datasource:
      db-kind: "postgresql"
      jdbc:
        url: "jdbc:postgresql://prod-db:5432/quarkusdb"
    hibernate-orm:
      database:
        generation: "validate"
      log:
        sql: false
  app:
    feature:
      flags:
        enabled: false
    security:
      jwt:
        secret: "${JWT_SECRET:default-prod-secret}"
  external:
    api:
      base-url: "https://api.example.com"

4. Type-Safe Configuration with @ConfigMapping

Configuration Classes

java

package com.example.config;

import io.smallrye.config.ConfigMapping;
import io.smallrye.config.WithDefault;
import io.smallrye.config.WithName;

import java.util.List;
import java.util.Optional;

@ConfigMapping(prefix = "app")
public interface AppConfig {
    
    String name();
    String version();
    
    SecurityConfig security();
    DatabaseConfig database();
    ExternalApiConfig external();
    FeatureFlags features();
    UploadConfig upload();
    EmailConfig email();
    
    interface SecurityConfig {
        JwtConfig jwt();
        OAuthConfig oauth();
        CorsConfig cors();
        
        interface JwtConfig {
            String secret();
            @WithDefault("3600")
            long expiration();
            @WithDefault("HS256")
            String algorithm();
        }
        
        interface OAuthConfig {
            String clientId();
            String clientSecret();
            String redirectUri();
        }
        
        interface CorsConfig {
            @WithDefault("http://localhost:3000")
            List<String> allowedOrigins();
            @WithDefault("GET,POST,PUT,DELETE,OPTIONS")
            List<String> allowedMethods();
        }
    }
    
    interface DatabaseConfig {
        @WithName("max-connections")
        @WithDefault("10")
        int maxConnections();
        
        @WithDefault("30000")
        long connectionTimeout();
        
        PoolConfig pool();
        
        interface PoolConfig {
            @WithDefault("5")
            int minSize();
            @WithDefault("20")
            int maxSize();
        }
    }
    
    interface ExternalApiConfig {
        String baseUrl();
        @WithDefault("5000")
        int timeout();
        RetryConfig retry();
        
        interface RetryConfig {
            @WithName("max-attempts")
            @WithDefault("3")
            int maxAttempts();
            @WithDefault("1000")
            long delay();
            @WithDefault("2.0")
            double multiplier();
        }
    }
    
    interface FeatureFlags {
        @WithDefault("false")
        boolean newDashboard();
        @WithDefault("true")
        boolean advancedSearch();
        @WithDefault("false")
        boolean experimentalFeatures();
        Optional<Boolean> darkMode(); // Optional feature
    }
    
    interface UploadConfig {
        @WithName("max-file-size")
        @WithDefault("10485760") // 10MB
        long maxFileSize();
        
        @WithName("allowed-extensions")
        List<String> allowedExtensions();
        
        @WithName("storage-path")
        @WithDefault("./uploads")
        String storagePath();
    }
    
    interface EmailConfig {
        SmtpConfig smtp();
        String from();
        TemplatesConfig templates();
        
        interface SmtpConfig {
            String host();
            int port();
            String username();
            String password();
            @WithDefault("true")
            boolean auth();
            @WithDefault("true")
            boolean starttls();
        }
        
        interface TemplatesConfig {
            String welcome();
            String passwordReset();
            String notification();
        }
    }
}

Using Configuration in Services

java

package com.example.service;

import com.example.config.AppConfig;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import org.eclipse.microprofile.config.inject.ConfigProperty;

import java.util.List;

@ApplicationScoped
public class ConfigurationService {
    
    @Inject
    AppConfig appConfig;
    
    // Alternative: Direct property injection
    @ConfigProperty(name = "app.name")
    String appName;
    
    @ConfigProperty(name = "app.security.jwt.secret")
    String jwtSecret;
    
    @ConfigProperty(name = "app.feature.flags.new-dashboard", defaultValue = "false")
    boolean newDashboardEnabled;
    
    public void printConfiguration() {
        System.out.println("=== Application Configuration ===");
        System.out.println("App Name: " + appConfig.name());
        System.out.println("Version: " + appConfig.version());
        
        // Security config
        System.out.println("JWT Secret: " + appConfig.security().jwt().secret());
        System.out.println("JWT Expiration: " + appConfig.security().jwt().expiration());
        
        // Database config
        System.out.println("Max Connections: " + appConfig.database().maxConnections());
        
        // External API config
        System.out.println("API Base URL: " + appConfig.external().baseUrl());
        System.out.println("API Timeout: " + appConfig.external().timeout());
        System.out.println("Retry Max Attempts: " + appConfig.external().retry().maxAttempts());
        
        // Feature flags
        System.out.println("New Dashboard: " + appConfig.features().newDashboard());
        System.out.println("Advanced Search: " + appConfig.features().advancedSearch());
        
        // Upload config
        System.out.println("Max File Size: " + appConfig.upload().maxFileSize());
        System.out.println("Allowed Extensions: " + appConfig.upload().allowedExtensions());
    }
    
    public boolean isFeatureEnabled(String featureName) {
        switch (featureName) {
            case "new-dashboard":
                return appConfig.features().newDashboard();
            case "advanced-search":
                return appConfig.features().advancedSearch();
            case "experimental-features":
                return appConfig.features().experimentalFeatures();
            default:
                return false;
        }
    }
    
    public List<String> getAllowedFileExtensions() {
        return appConfig.upload().allowedExtensions();
    }
    
    public long getMaxFileSizeBytes() {
        return appConfig.upload().maxFileSize();
    }
}

// Service using external API configuration
package com.example.service;

import com.example.config.AppConfig;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;

import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;

@ApplicationScoped
public class ExternalApiService {
    
    @Inject
    AppConfig appConfig;
    
    private final HttpClient httpClient;
    
    public ExternalApiService() {
        this.httpClient = HttpClient.newBuilder()
                .connectTimeout(Duration.ofMillis(appConfig.external().timeout()))
                .build();
    }
    
    public String callExternalApi(String endpoint) {
        try {
            String url = appConfig.external().baseUrl() + endpoint;
            
            HttpRequest request = HttpRequest.newBuilder()
                    .uri(java.net.URI.create(url))
                    .timeout(Duration.ofMillis(appConfig.external().timeout()))
                    .GET()
                    .build();
            
            HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
            
            if (response.statusCode() == 200) {
                return response.body();
            } else {
                throw new RuntimeException("API call failed with status: " + response.statusCode());
            }
            
        } catch (Exception e) {
            // Implement retry logic based on configuration
            return handleApiErrorWithRetry(endpoint, e);
        }
    }
    
    private String handleApiErrorWithRetry(String endpoint, Exception originalError) {
        int maxAttempts = appConfig.external().retry().maxAttempts();
        long delay = appConfig.external().retry().delay();
        double multiplier = appConfig.external().retry().multiplier();
        
        for (int attempt = 1; attempt <= maxAttempts; attempt++) {
            try {
                Thread.sleep((long) (delay * Math.pow(multiplier, attempt - 1)));
                return callExternalApi(endpoint); // Recursive retry
            } catch (InterruptedException ie) {
                Thread.currentThread().interrupt();
                throw new RuntimeException("Retry interrupted", ie);
            } catch (Exception e) {
                if (attempt == maxAttempts) {
                    throw new RuntimeException("All retry attempts failed", e);
                }
                // Continue to next retry attempt
            }
        }
        throw new RuntimeException("All retry attempts failed", originalError);
    }
}

5. Logging Configuration

Basic Logging Configuration

properties

# Logging Levels
quarkus.log.level=INFO
quarkus.log.category."com.example".level=DEBUG
quarkus.log.category."org.hibernate".level=WARN
quarkus.log.category."io.quarkus".level=INFO

# Console Logging
quarkus.log.console.enable=true
quarkus.log.console.level=INFO
quarkus.log.console.format=%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%c{3.}] (%t) %s%e%n
quarkus.log.console.color=true

# File Logging
quarkus.log.file.enable=true
quarkus.log.file.path=logs/application.log
quarkus.log.file.level=DEBUG
quarkus.log.file.format=%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%c{3.}] (%t) %s%e%n
quarkus.log.file.rotation.max-file-size=10M
quarkus.log.file.rotation.max-backup-index=10

# Syslog Configuration
quarkus.log.syslog.enable=false
quarkus.log.syslog.endpoint=localhost:514
quarkus.log.syslog.protocol=TCP
quarkus.log.syslog.app-name=quarkus-app

JSON Logging (Structured Logging)

properties

# JSON Logging Configuration
quarkus.log.console.json=true
quarkus.log.console.json.excluded-keys=hostName,processName
quarkus.log.console.json.pretty-print=false

# Custom JSON Fields
quarkus.log.console.json.keys.timestamp=@timestamp
quarkus.log.console.json.keys.logger=logger_name
quarkus.log.console.json.keys.level=severity
quarkus.log.console.json.keys.message=message

# Additional MDC Fields
quarkus.log.console.json.include-mdc=true
quarkus.log.console.json.mdc-key-prefix=mdc.

# Custom JSON Format
quarkus.log.console.json.date-format=yyyy-MM-dd'T'HH:mm:ss.SSSZ
quarkus.log.console.json.exception-output-type=detailed_and_formatted
quarkus.log.console.json.print-details=true

GELF Logging (Graylog Extended Log Format)

properties

# GELF Logging Configuration
quarkus.log.handler.gelf.enabled=true
quarkus.log.handler.gelf.host=udp:localhost
quarkus.log.handler.gelf.port=12201
quarkus.log.handler.gelf.version=1.1

# GELF Additional Fields
quarkus.log.handler.gelf.include-full-mdc=true
quarkus.log.handler.gelf.include-log-message=true
quarkus.log.handler.gelf.include-message-parameters=true
quarkus.log.handler.gelf.include-stack-trace=true

# GELF Custom Fields
quarkus.log.handler.gelf.additional-field.app-name.value=quarkus-app
quarkus.log.handler.gelf.additional-field.environment.value=development
quarkus.log.handler.gelf.additional-field.version.value=1.0.0

# GELF Network Configuration
quarkus.log.handler.gelf.tcp-keep-alive=true
quarkus.log.handler.gelf.connect-timeout=1000
quarkus.log.handler.gelf.reconnect-delay=500
quarkus.log.handler.gelf.retry-count=3

Profile-specific Logging

properties

# Development Logging
%dev.quarkus.log.level=DEBUG
%dev.quarkus.log.console.level=DEBUG
%dev.quarkus.log.console.format=%d{HH:mm:ss} %-5p [%c{2.}] (%t) %s%e%n
%dev.quarkus.log.console.color=true
%dev.quarkus.log.file.enable=false
%dev.quarkus.log.handler.gelf.enabled=false

# Test Logging
%test.quarkus.log.level=INFO
%test.quarkus.log.console.level=INFO
%test.quarkus.log.file.enable=true
%test.quarkus.log.file.path=build/logs/test.log
%test.quarkus.log.handler.gelf.enabled=false

# Production Logging
%prod.quarkus.log.level=WARN
%prod.quarkus.log.console.level=WARN
%prod.quarkus.log.console.json=true
%prod.quarkus.log.file.enable=true
%prod.quarkus.log.file.path=/var/log/quarkus/app.log
%prod.quarkus.log.file.rotation.max-file-size=100M
%prod.quarkus.log.file.rotation.max-backup-index=50
%prod.quarkus.log.handler.gelf.enabled=true

Custom Logger Implementation

java

package com.example.logging;

import org.jboss.logging.Logger;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;

import java.util.HashMap;
import java.util.Map;

@ApplicationScoped
public class ApplicationLogger {
    
    private final Logger logger;
    
    @Inject
    public ApplicationLogger() {
        this.logger = Logger.getLogger(ApplicationLogger.class);
    }
    
    public void debug(String message) {
        logger.debug(message);
    }
    
    public void info(String message) {
        logger.info(message);
    }
    
    public void warn(String message) {
        logger.warn(message);
    }
    
    public void error(String message) {
        logger.error(message);
    }
    
    public void error(String message, Throwable throwable) {
        logger.error(message, throwable);
    }
    
    // Structured logging methods
    public void infoWithContext(String message, Map<String, Object> context) {
        try (org.jboss.logging.MDCCloseable mdc = org.jboss.logging.MDC.putCloseable("context", context.toString())) {
            logger.info(message);
        }
    }
    
    public void auditLog(String action, String resource, String userId, Map<String, Object> details) {
        Map<String, Object> auditContext = new HashMap<>();
        auditContext.put("action", action);
        auditContext.put("resource", resource);
        auditContext.put("userId", userId);
        auditContext.put("timestamp", java.time.Instant.now().toString());
        auditContext.putAll(details);
        
        try (org.jboss.logging.MDCCloseable mdc = org.jboss.logging.MDC.putCloseable("audit", auditContext.toString())) {
            logger.infof("AUDIT: %s on %s by %s", action, resource, userId);
        }
    }
    
    // Performance logging
    public void logPerformance(String operation, long durationMs, Map<String, Object> metadata) {
        Map<String, Object> perfContext = new HashMap<>();
        perfContext.put("operation", operation);
        perfContext.put("duration_ms", durationMs);
        perfContext.put("threshold_warn", 1000); // 1 second
        perfContext.put("threshold_error", 5000); // 5 seconds
        perfContext.putAll(metadata);
        
        try (org.jboss.logging.MDCCloseable mdc = org.jboss.logging.MDC.putCloseable("performance", perfContext.toString())) {
            if (durationMs > 5000) {
                logger.errorf("PERFORMANCE ERROR: %s took %d ms", operation, durationMs);
            } else if (durationMs > 1000) {
                logger.warnf("PERFORMANCE WARN: %s took %d ms", operation, durationMs);
            } else {
                logger.infof("PERFORMANCE: %s took %d ms", operation, durationMs);
            }
        }
    }
}

// Usage in services
package com.example.service;

import com.example.logging.ApplicationLogger;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;

import java.util.HashMap;
import java.util.Map;

@ApplicationScoped
public class UserService {
    
    @Inject
    ApplicationLogger logger;
    
    public void createUser(String username, String email) {
        long startTime = System.currentTimeMillis();
        
        try {
            logger.info("Starting user creation");
            
            Map<String, Object> context = new HashMap<>();
            context.put("username", username);
            context.put("email", email);
            context.put("operation", "createUser");
            
            logger.infoWithContext("Creating user", context);
            
            // Business logic here
            // ...
            
            // Audit log
            Map<String, Object> auditDetails = new HashMap<>();
            auditDetails.put("email", email);
            auditDetails.put("source", "web");
            
            logger.auditLog("CREATE", "USER", "system", auditDetails);
            
        } catch (Exception e) {
            logger.error("Failed to create user: " + username, e);
            throw e;
        } finally {
            long duration = System.currentTimeMillis() - startTime;
            Map<String, Object> perfMetadata = new HashMap<>();
            perfMetadata.put("username", username);
            
            logger.logPerformance("createUser", duration, perfMetadata);
        }
    }
}

6. Secrets and Externalized Configuration

Environment Variables

properties

# Using environment variables in configuration
quarkus.datasource.username=${DB_USERNAME:quarkus_user}
quarkus.datasource.password=${DB_PASSWORD:quarkus_pass}
quarkus.datasource.jdbc.url=${DB_URL:jdbc:postgresql://localhost:5432/quarkusdb}

# JWT Secret from environment
app.security.jwt.secret=${JWT_SECRET:default-dev-secret}

# External API configuration
external.api.base-url=${API_BASE_URL:https://dev-api.example.com}
external.api.key=${API_KEY:dev-key}

# Feature flags from environment
app.feature.flags.new-dashboard=${FEATURE_NEW_DASHBOARD:false}
app.feature.flags.experimental-features=${FEATURE_EXPERIMENTAL:false}

.env File Support

bash

# .env file in project root
DB_USERNAME=production_user
DB_PASSWORD=super_secure_password
DB_URL=jdbc:postgresql://prod-db:5432/production_db

JWT_SECRET=very-long-and-secure-jwt-secret-key-here

API_BASE_URL=https://api.production.com
API_KEY=prod-api-key-12345

FEATURE_NEW_DASHBOARD=true
FEATURE_EXPERIMENTAL=false

LOG_LEVEL=WARN
GRAYLOG_HOST=graylog.production.com

Kubernetes Secrets and ConfigMaps

properties

# Kubernetes configuration
quarkus.kubernetes-config.enabled=true
quarkus.kubernetes-config.config-maps=app-config
quarkus.kubernetes-config.secrets=app-secrets
quarkus.kubernetes-config.namespace=default

# Fallback to environment variables if not in Kubernetes
quarkus.datasource.username=${DB_USERNAME:${postgres.username:quarkus_user}}
quarkus.datasource.password=${DB_PASSWORD:${postgres.password:quarkus_pass}}

Vault Integration

properties

# HashiCorp Vault Configuration
quarkus.vault.url=https://vault.example.com:8200
quarkus.vault.authentication.client-token=${VAULT_TOKEN}
quarkus.vault.kv-secret-engine-mount-path=secret
quarkus.vault.kv-secret-engine-version=2

# Read secrets from Vault
quarkus.datasource.password=${vault:secret/data/database#data.password}
app.security.jwt.secret=${vault:secret/data/app#data.jwt_secret}
external.api.key=${vault:secret/data/external-api#data.api_key}

7. Runtime Configuration Updates

Dynamic Configuration

java

package com.example.config;

import io.smallrye.config.ConfigMapping;
import io.smallrye.config.WithDefault;

import java.util.List;
import java.util.concurrent.atomic.AtomicReference;

@ConfigMapping(prefix = "app")
public interface DynamicConfig {
    
    FeatureFlags features();
    
    interface FeatureFlags {
        AtomicReference<Boolean> newDashboard();
        AtomicReference<Boolean> advancedSearch();
        AtomicReference<List<String>> enabledModules();
    }
}

// Configuration Update Service
package com.example.service;

import com.example.config.DynamicConfig;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import org.eclipse.microprofile.config.Config;
import org.eclipse.microprofile.config.ConfigProvider;

import java.util.HashMap;
import java.util.Map;

@ApplicationScoped
public class DynamicConfigService {
    
    @Inject
    DynamicConfig dynamicConfig;
    
    private final Config config = ConfigProvider.getConfig();
    
    public void enableFeature(String featureName) {
        switch (featureName) {
            case "new-dashboard":
                dynamicConfig.features().newDashboard().set(true);
                break;
            case "advanced-search":
                dynamicConfig.features().advancedSearch().set(true);
                break;
            default:
                throw new IllegalArgumentException("Unknown feature: " + featureName);
        }
    }
    
    public void disableFeature(String featureName) {
        switch (featureName) {
            case "new-dashboard":
                dynamicConfig.features().newDashboard().set(false);
                break;
            case "advanced-search":
                dynamicConfig.features().advancedSearch().set(false);
                break;
            default:
                throw new IllegalArgumentException("Unknown feature: " + featureName);
        }
    }
    
    public Map<String, Object> getCurrentConfig() {
        Map<String, Object> configMap = new HashMap<>();
        
        configMap.put("new-dashboard", dynamicConfig.features().newDashboard().get());
        configMap.put("advanced-search", dynamicConfig.features().advancedSearch().get());
        configMap.put("enabled-modules", dynamicConfig.features().enabledModules().get());
        
        // Add some static config values
        configMap.put("app-name", config.getValue("app.name", String.class));
        configMap.put("app-version", config.getValue("app.version", String.class));
        
        return configMap;
    }
}

8. Complete Configuration Example

Final application.properties

properties

# ===== APPLICATION CONFIGURATION =====
quarkus.application.name=quarkus-config-demo
quarkus.application.version=1.0.0

# ===== SERVER CONFIGURATION =====
quarkus.http.port=8080
quarkus.http.host=0.0.0.0
quarkus.http.ssl-port=8443
quarkus.http.cors=true

# ===== DATABASE CONFIGURATION =====
quarkus.datasource.db-kind=postgresql
quarkus.datasource.username=${DB_USERNAME:quarkus_user}
quarkus.datasource.password=${DB_PASSWORD:quarkus_pass}
quarkus.datasource.jdbc.url=${DB_URL:jdbc:postgresql://localhost:5432/quarkusdb}
quarkus.datasource.jdbc.max-size=20
quarkus.datasource.jdbc.min-size=5

quarkus.hibernate-orm.database.generation=update
quarkus.hibernate-orm.log.sql=true

# ===== LOGGING CONFIGURATION =====
quarkus.log.level=INFO
quarkus.log.console.enable=true
quarkus.log.console.format=%d{yyyy-MM-dd HH:mm:ss} %-5p [%c{3.}] (%t) %s%e%n
quarkus.log.file.enable=true
quarkus.log.file.path=logs/app.log

# ===== CUSTOM APPLICATION CONFIG =====
app.name=Quarkus Configuration Demo
app.version=1.0.0

app.security.jwt.secret=${JWT_SECRET:dev-secret-key}
app.security.jwt.expiration=3600

app.upload.max-file-size=10485760
app.upload.allowed-extensions=jpg,jpeg,png,pdf

app.external.api.base-url=${API_BASE_URL:https://dev-api.example.com}
app.external.api.timeout=5000

# ===== PROFILE CONFIGURATIONS =====

# Development Profile
%dev.quarkus.log.level=DEBUG
%dev.quarkus.datasource.db-kind=h2
%dev.quarkus.datasource.jdbc.url=jdbc:h2:mem:devdb
%dev.quarkus.hibernate-orm.database.generation=drop-and-create
%dev.app.security.jwt.secret=dev-only-secret-key

# Test Profile
%test.quarkus.log.level=INFO
%test.quarkus.datasource.db-kind=h2
%test.quarkus.datasource.jdbc.url=jdbc:h2:mem:testdb
%test.quarkus.hibernate-orm.database.generation=drop-and-create

# Production Profile
%prod.quarkus.log.level=WARN
%prod.quarkus.log.console.json=true
%prod.quarkus.log.handler.gelf.enabled=true
%prod.quarkus.log.handler.gelf.host=graylog.prod.com
%prod.app.security.jwt.secret=${JWT_SECRET}

# Staging Profile
%staging.quarkus.log.level=INFO
%staging.quarkus.log.console.json=true
%staging.app.security.jwt.secret=${JWT_SECRET:staging-secret}

This extensive guide covers all aspects of configuration, logging, and profiles in Quarkus, providing you with the tools to manage your application's configuration effectively across different environments while maintaining security and best practices.

 

Comments (0)

No comments yet. Be the first to comment!

LecturreAI Assistant

Hello! I'm LecturreAI

What would you like to learn today?