blob: e2974413dc5b0b4a038adba7db78db36e10741db [file] [log] [blame]
/*
* 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;
import java.util.Collections;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.logging.log4j.message.Message;
import org.apache.logging.log4j.message.MessageFactory;
import org.apache.logging.log4j.spi.AbstractResourceLogger;
import org.apache.logging.log4j.spi.ExtendedLogger;
import org.apache.logging.log4j.util.StackLocatorUtil;
import org.apache.logging.log4j.util.Strings;
/**
* Logger for resources. The Supplier provides resource attributes that should be included in all log events generated
* from the current resource. Note that since the Supplier is called for every LogEvent being generated
* the values returned may change as necessary. Care should be taken to make the Supplier as efficient as
* possible to avoid performance issues.
*
* Unlike regular Loggers ResourceLoggers CANNOT be declared to be static. A ResourceLogger
* must be declared as a class member that will be garbage collected along with the instance of the resource.
*/
public final class ScopedResourceLogger extends AbstractResourceLogger {
private static final long serialVersionUID = -5837924138744974513L;
private final ScopedContext.Instance scopedInstance;
public static ScopedResourceLoggerBuilder newBuilder() {
return new ScopedResourceLoggerBuilder();
}
/*
* Pass our MessageFactory with its Supplier to AbstractLogger. This will be used to create
* the Messages prior to them being passed to the "real" Logger.
*/
private ScopedResourceLogger(
final ExtendedLogger logger, final Supplier<Map<String, ?>> supplier, MessageFactory messageFactory) {
super(logger, supplier, messageFactory);
scopedInstance = null;
}
/*
* Pass our MessageFactory with its Map to AbstractLogger. This will be used to create
* the Messages prior to them being passed to the "real" Logger.
*/
private ScopedResourceLogger(final ExtendedLogger logger, final Map<String, ?> map, MessageFactory messageFactory) {
super(logger, map, messageFactory);
scopedInstance = ScopedContext.where(map);
}
@Override
public void logMessage(String fqcn, Level level, Marker marker, Message message, Throwable t) {
if (supplier != null) {
ScopedContext.runWhere(supplier.get(), () -> logger.logMessage(fqcn, level, marker, message, t));
} else if (scopedInstance != null) {
scopedInstance.run(() -> logger.logMessage(fqcn, level, marker, message, t));
} else {
logger.logMessage(fqcn, level, marker, message, t);
}
}
/**
* Constructs a ResourceLogger.
*/
public static final class ScopedResourceLoggerBuilder extends ResourceLoggerBuilder<ScopedResourceLoggerBuilder> {
/**
* Create the builder.
*/
private ScopedResourceLoggerBuilder() {
super();
}
/**
* Construct the ResourceLogger.
* @return the ResourceLogger.
*/
public Logger build() {
if (this.logger == null) {
if (Strings.isEmpty(name)) {
Class<?> clazz = StackLocatorUtil.getCallerClass(2);
name = clazz.getCanonicalName() != null ? clazz.getCanonicalName() : clazz.getName();
}
this.logger = (ExtendedLogger) LogManager.getLogger(name);
}
if (supplyOnce) {
Map<String, ?> map = this.supplier != null ? supplier.get() : Collections.emptyMap();
return new ScopedResourceLogger(logger, map, messageFactory);
} else {
Supplier<Map<String, ?>> mapSupplier = this.supplier != null ? this.supplier : Collections::emptyMap;
return new ScopedResourceLogger(logger, mapSupplier, messageFactory);
}
}
}
}