All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jboss.as.arquillian.setup.ConfigureLoggingSetupTask Maven / Gradle / Ivy

There is a newer version: 5.1.0.Beta6
Show newest version
/*
 * Copyright The WildFly Authors
 * SPDX-License-Identifier: Apache-2.0
 */

package org.jboss.as.arquillian.setup;

import java.io.IOException;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.jboss.as.arquillian.api.ServerSetupTask;
import org.jboss.as.arquillian.container.ManagementClient;
import org.jboss.as.controller.client.ModelControllerClient;
import org.jboss.as.controller.client.Operation;
import org.jboss.as.controller.client.helpers.Operations;
import org.jboss.as.controller.client.helpers.Operations.CompositeOperationBuilder;
import org.jboss.dmr.ModelNode;

/**
 * A setup task for configuring loggers for tests.
 * 

* You can define the log levels and logger names in two ways. The first is to pass a map of known logger levels with * associated logger names to the {@linkplain ConfigureLoggingSetupTask#ConfigureLoggingSetupTask(Map) constructor}. * The other is via a system property. *

*

* To set the levels and logger names via a system property, use a key of {@code wildfly.logging.level.${level}} where * {@code level} is one of the following: *

    *
  1. all
  2. *
  3. trace
  4. *
  5. debug
  6. *
  7. info
  8. *
  9. warn
  10. *
  11. error
  12. *
  13. off
  14. *
* * The value for each property is a comma delimited set of logger names. *

* Example: * *

 *       {@code -Dwildfly.logging.level.debug=org.wildfly.security,org.jboss.resteasy}
 *   
*

*

* When using the constructor, the map should consist of a known log level as the key and loggers to be associated with * that level as the value of the map. Example: * *

 *     {@code
 *          public class WildFlyLoggingSetupTask extends ConfigurationLoggingSetupTask {
 *              public WildFlyLoggingSetupTask() {
 *                  super(Map.of("DEBUG", Set.of("org.wildfly.core", "org.wildfly"}));
 *              }
 *          }
 *     )
 * 
* * Note that when using the map constructor, you can still use the system property and the maps will be merged. *

* * @author James R. Perkins */ public class ConfigureLoggingSetupTask implements ServerSetupTask { private final String handlerType; private final String handlerName; private final Map> logLevels; private final BlockingDeque tearDownOps; /** * Creates a new setup task which configures the {@code console-handler=CONSOLE} handler to allow all log levels. * Then configures, either by modifying or adding, the loggers represented by the values from the system properties. */ public ConfigureLoggingSetupTask() { this(Map.of()); } /** * Creates a new setup task which configures the handler to allow all log levels. Then configures, either by * modifying or adding, the loggers represented by system properties. * * @param handlerType the handler type which should be modified to ensure it allows all log levels, if {@code null} * {@code console-handler} will be used * @param handlerName the name of the handler which should be modified to ensure it allows all log levels, if {@code null} * {@code console-handler} will be used */ public ConfigureLoggingSetupTask(final String handlerType, final String handlerName) { this(handlerType, handlerName, Map.of()); } /** * Creates a new setup task which configures the {@code console-handler=CONSOLE} handler to allow all log levels. * Then configures, either by modifying or adding, the loggers represented by the values of the map passed in. The * key of the map is the level desired for each logger. *

* The map consists of levels as the key and a set of logger names as the value for each level. *

* * @param logLevels the map of levels and loggers */ public ConfigureLoggingSetupTask(final Map> logLevels) { this(null, null, logLevels); } /** * Creates a new setup task which configures the handler to allow all log levels. Then configures, either by * modifying or adding, the loggers represented by the values of the map passed in. The key of the map is the level * desired for each logger. *

* If the {@code handlerType} is {@code null} the value will be {@code console-handler}. If the {@code handlerName} * is {@code null} the value used will be {@code CONSOLE}. *

*

* The map consists of levels as the key and a set of logger names as the value for each level. *

* * @param handlerType the handler type which should be modified to ensure it allows all log levels, if {@code null} * {@code console-handler} will be used * @param handlerName the name of the handler which should be modified to ensure it allows all log levels, if {@code null} * {@code console-handler} will be used * @param logLevels the map of levels and loggers */ public ConfigureLoggingSetupTask(final String handlerType, final String handlerName, final Map> logLevels) { this.handlerType = handlerType == null ? "console-handler" : handlerType; this.handlerName = handlerName == null ? "CONSOLE" : handlerName; this.logLevels = createMap(logLevels); this.tearDownOps = new LinkedBlockingDeque<>(); } @Override public void setup(final ManagementClient client, final String containerId) throws Exception { final CompositeOperationBuilder builder = CompositeOperationBuilder.create(); ModelNode address = Operations.createAddress("subsystem", "logging", handlerType, handlerName); // We need the current level to reset it when done ModelNode currentValue = executeOp(client.getControllerClient(), Operations.createReadAttributeOperation(address, "level")); if (currentValue.isDefined()) { tearDownOps.add(Operations.createWriteAttributeOperation(address, "level", currentValue.asString())); } builder.addStep(Operations.createUndefineAttributeOperation(address, "level")); for (Map.Entry> entry : logLevels.entrySet()) { for (String logger : entry.getValue()) { if (logger.isBlank()) { address = Operations.createAddress("subsystem", "logging", "root-logger", "ROOT"); } else { address = Operations.createAddress("subsystem", "logging", "logger", logger); } builder.addStep(createLoggerOp(client.getControllerClient(), address, entry.getKey())); } } executeOp(client.getControllerClient(), builder.build()); } @Override public void tearDown(final ManagementClient managementClient, final String containerId) throws Exception { // Create a composite operation with all the tear-down operations final CompositeOperationBuilder builder = CompositeOperationBuilder.create(); ModelNode removeOp; while ((removeOp = tearDownOps.pollFirst()) != null) { builder.addStep(removeOp); } executeOp(managementClient.getControllerClient(), builder.build()); } private ModelNode createLoggerOp(final ModelControllerClient client, final ModelNode address, final String level) throws IOException { // First check if the logger exists final ModelNode op = Operations.createReadResourceOperation(address); final ModelNode result = client.execute(op); if (Operations.isSuccessfulOutcome(result)) { // Get the current level from te result final ModelNode loggerConfig = Operations.readResult(result); if (loggerConfig.hasDefined("level")) { tearDownOps.add(Operations.createWriteAttributeOperation(address, "level", loggerConfig.get("level") .asString())); } return Operations.createWriteAttributeOperation(address, "level", level); } tearDownOps.add(Operations.createRemoveOperation(address)); final ModelNode addOp = Operations.createAddOperation(address); addOp.get("level").set(level); return addOp; } private ModelNode executeOp(final ModelControllerClient client, final ModelNode op) throws IOException { return executeOp(client, Operation.Factory.create(op)); } private ModelNode executeOp(final ModelControllerClient client, final Operation op) throws IOException { final ModelNode result = client.execute(op); if (!Operations.isSuccessfulOutcome(result)) { throw new RuntimeException(Operations.getFailureDescription(result).asString()); } return Operations.readResult(result); } private static Map> createMap(final Map> toMerge) { // We only allow a known set of levels final Map> logLevels = new HashMap<>(); addLoggingConfig(logLevels, "all"); addLoggingConfig(logLevels, "trace"); addLoggingConfig(logLevels, "debug"); addLoggingConfig(logLevels, "info"); addLoggingConfig(logLevels, "warn"); addLoggingConfig(logLevels, "error"); addLoggingConfig(logLevels, "off"); return Map.copyOf(merge(logLevels, toMerge)); } private static void addLoggingConfig(final Map> map, final String level) { final String value = System.getProperty("wildfly.logging.level." + level); if (value != null) { final Set names = Set.of(value.split(",")); if (!names.isEmpty()) { map.put(level.toUpperCase(Locale.ROOT), names); } } } private static Map> merge(final Map> map1, final Map> map2) { final Map> result = new HashMap<>(); for (var entry : map1.entrySet()) { result.put(entry.getKey().toUpperCase(Locale.ROOT), entry.getValue()); } for (final var entry : map2.entrySet()) { if (entry.getValue().isEmpty()) { continue; } final String key = entry.getKey().toUpperCase(Locale.ROOT); if (result.containsKey(key)) { result.put(key, Stream.concat(result.get(key).stream(), entry.getValue().stream()) .collect(Collectors.toSet())); } else { result.put(key, Set.copyOf(entry.getValue())); } } return Map.copyOf(result); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy