/* | |
* Licensed to the Apache Software Foundation (ASF) under one or more | |
* contributor license agreements. See the NOTICE file distributed with | |
* this work for additional information regarding copyright ownership. | |
* The ASF licenses this file to You under the Apache License, Version 2.0 | |
* (the "License"); you may not use this file except in compliance with | |
* the License. You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
package org.apache.logging.log4j.core.config.status; | |
import java.util.Collection; | |
import java.util.Collections; | |
import java.util.LinkedList; | |
import org.apache.logging.log4j.Level; | |
import org.apache.logging.log4j.status.StatusListener; | |
import org.apache.logging.log4j.status.StatusLogger; | |
/** | |
* Configuration for setting up {@link StatusConsoleListener} instances. | |
*/ | |
public class StatusConfiguration { | |
private static final Level DEFAULT_STATUS = Level.ERROR; | |
private static final Verbosity DEFAULT_VERBOSITY = Verbosity.QUIET; | |
private final Collection<String> errorMessages = Collections.synchronizedCollection(new LinkedList<String>()); | |
private final StatusLogger logger = StatusLogger.getLogger(); | |
private volatile boolean initialized = false; | |
private Class<? extends StatusConsoleListener> destination = StatusStdOutListener.class; | |
private Level status = DEFAULT_STATUS; | |
private Verbosity verbosity = DEFAULT_VERBOSITY; | |
private String[] verboseClasses; | |
/** | |
* Specifies how verbose the StatusLogger should be. | |
*/ | |
public static enum Verbosity { | |
QUIET, VERBOSE; | |
/** | |
* Parses the verbosity property into an enum. | |
* | |
* @param value property value to parse. | |
* @return enum corresponding to value, or QUIET by default. | |
*/ | |
public static Verbosity toVerbosity(final String value) { | |
return Boolean.parseBoolean(value) ? VERBOSE : QUIET; | |
} | |
} | |
/** | |
* Logs an error message to the StatusLogger. If the StatusLogger hasn't been set up yet, queues the message to be | |
* logged after initialization. | |
* | |
* @param message error message to log. | |
*/ | |
public void error(final String message) { | |
if (!this.initialized) { | |
this.errorMessages.add(message); | |
} else { | |
this.logger.error(message); | |
} | |
} | |
/** | |
* Specifies the destination for StatusLogger events. This can be {@code out} (default) for using | |
* {@link System#out standard out}, {@code err} for using {@link System#err standard error}, or a file URI to | |
* which log events will be written. If the provided URI is invalid, then the default destination of standard | |
* out will be used. | |
* | |
* @param destination where status log messages should be output. | |
* @return {@code this} | |
*/ | |
public StatusConfiguration withDestination(final String destination) { | |
if ("out".equalsIgnoreCase(destination)) { | |
this.destination = StatusStdOutListener.class; | |
} else if ("err".equalsIgnoreCase(destination)) { | |
this.destination = StatusStdErrListener.class; | |
} else { | |
this.error("Invalid destination [" + destination + "]. Only 'out' or 'err' are supported. Defaulting to 'out'."); | |
this.destination = StatusStdOutListener.class; | |
} | |
return this; | |
} | |
/** | |
* Specifies the logging level by name to use for filtering StatusLogger messages. | |
* | |
* @param status name of logger level to filter below. | |
* @return {@code this} | |
* @see Level | |
*/ | |
public StatusConfiguration withStatus(final String status) { | |
this.status = Level.toLevel(status, null); | |
if (this.status == null) { | |
this.error("Invalid status level specified: " + status + ". Defaulting to ERROR."); | |
this.status = Level.ERROR; | |
} | |
return this; | |
} | |
/** | |
* Specifies the logging level to use for filtering StatusLogger messages. | |
* | |
* @param status logger level to filter below. | |
* @return {@code this} | |
*/ | |
public StatusConfiguration withStatus(final Level status) { | |
this.status = status; | |
return this; | |
} | |
/** | |
* Specifies the verbosity level to log at. This only applies to classes configured by | |
* {@link #withVerboseClasses(String...) verboseClasses}. | |
* | |
* @param verbosity basic filter for status logger messages. | |
* @return {@code this} | |
*/ | |
public StatusConfiguration withVerbosity(final String verbosity) { | |
this.verbosity = Verbosity.toVerbosity(verbosity); | |
return this; | |
} | |
/** | |
* Specifies which class names to filter if the configured verbosity level is QUIET. | |
* | |
* @param verboseClasses names of classes to filter if not using VERBOSE. | |
* @return {@code this} | |
*/ | |
public StatusConfiguration withVerboseClasses(final String... verboseClasses) { | |
this.verboseClasses = verboseClasses; | |
return this; | |
} | |
/** | |
* Configures and initializes the StatusLogger using the configured options in this instance. | |
*/ | |
public void initialize() { | |
if (!this.initialized) { | |
if (this.status == Level.OFF) { | |
this.initialized = true; | |
} else { | |
final boolean configured = configureExistingStatusConsoleListener(); | |
if (!configured) { | |
registerNewStatusConsoleListener(); | |
} | |
migrateSavedLogMessages(); | |
} | |
} | |
} | |
private boolean configureExistingStatusConsoleListener() { | |
boolean configured = false; | |
for (final StatusListener statusListener : this.logger.getListeners()) { | |
if (this.destination.isInstance(statusListener)) { | |
final StatusConsoleListener listener = (StatusConsoleListener) statusListener; | |
listener.setStatusLevel(this.status); | |
if (this.verbosity == Verbosity.QUIET) { | |
listener.setFilters(this.verboseClasses); | |
} | |
configured = true; | |
} | |
} | |
return configured; | |
} | |
private void registerNewStatusConsoleListener() { | |
StatusConsoleListener listener; | |
try { | |
listener = this.destination.newInstance(); | |
listener.setStatusLevel(this.status); | |
if (this.verbosity == Verbosity.QUIET) { | |
listener.setFilters(this.verboseClasses); | |
} | |
this.logger.registerListener(listener); | |
} catch (ReflectiveOperationException e) { | |
logger.error("Cannot create listener of type " + destination.getClass()); | |
} | |
} | |
private void migrateSavedLogMessages() { | |
for (final String message : this.errorMessages) { | |
this.logger.error(message); | |
} | |
this.initialized = true; | |
this.errorMessages.clear(); | |
} | |
} |