001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache license, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the license for the specific language governing permissions and
015 * limitations under the license.
016 */
017
018package org.apache.logging.log4j.core.config;
019
020import java.util.Objects;
021import java.util.concurrent.locks.ReadWriteLock;
022import java.util.concurrent.locks.ReentrantReadWriteLock;
023
024import org.apache.logging.log4j.Level;
025import org.apache.logging.log4j.Marker;
026import org.apache.logging.log4j.core.LogEvent;
027import org.apache.logging.log4j.core.impl.LocationAware;
028import org.apache.logging.log4j.message.Message;
029import org.apache.logging.log4j.util.Supplier;
030
031/**
032 * ReliabilityStrategy that uses read/write locks to prevent the LoggerConfig from stopping while it is in use.
033 */
034public class LockingReliabilityStrategy implements ReliabilityStrategy, LocationAwareReliabilityStrategy {
035    private final LoggerConfig loggerConfig;
036    private final ReadWriteLock reconfigureLock = new ReentrantReadWriteLock();
037    private volatile boolean isStopping = false;
038
039    public LockingReliabilityStrategy(final LoggerConfig loggerConfig) {
040        this.loggerConfig = Objects.requireNonNull(loggerConfig, "loggerConfig was null");
041    }
042
043    /*
044     * (non-Javadoc)
045     *
046     * @see org.apache.logging.log4j.core.config.ReliabilityStrategy#log(org.apache.logging.log4j.util.Supplier,
047     * java.lang.String, java.lang.String, org.apache.logging.log4j.Marker, org.apache.logging.log4j.Level,
048     * org.apache.logging.log4j.message.Message, java.lang.Throwable)
049     */
050    @Override
051    public void log(final Supplier<LoggerConfig> reconfigured, final String loggerName, final String fqcn,
052            final Marker marker, final Level level, final Message data, final Throwable t) {
053
054        final LoggerConfig config = getActiveLoggerConfig(reconfigured);
055        try {
056            config.log(loggerName, fqcn, marker, level, data, t);
057        } finally {
058            config.getReliabilityStrategy().afterLogEvent();
059        }
060    }
061
062    /*
063     * (non-Javadoc)
064     *
065     * @see org.apache.logging.log4j.core.config.ReliabilityStrategy#log(org.apache.logging.log4j.util.Supplier,
066     * java.lang.String, java.lang.String, java.lang.StackTraceElement, org.apache.logging.log4j.Marker,
067     * org.apache.logging.log4j.Level, org.apache.logging.log4j.message.Message, java.lang.Throwable)
068     */
069    @Override
070    public void log(final Supplier<LoggerConfig> reconfigured, final String loggerName, final String fqcn,
071        final StackTraceElement location, final Marker marker, final Level level, final Message data,
072        final Throwable t) {
073        final LoggerConfig config = getActiveLoggerConfig(reconfigured);
074        try {
075            config.log(loggerName, fqcn, location, marker, level, data, t);
076        } finally {
077            config.getReliabilityStrategy().afterLogEvent();
078        }
079    }
080
081    /*
082     * (non-Javadoc)
083     *
084     * @see org.apache.logging.log4j.core.config.ReliabilityStrategy#log(org.apache.logging.log4j.util.Supplier,
085     * org.apache.logging.log4j.core.LogEvent)
086     */
087    @Override
088    public void log(final Supplier<LoggerConfig> reconfigured, final LogEvent event) {
089        final LoggerConfig config = getActiveLoggerConfig(reconfigured);
090        try {
091            config.log(event);
092        } finally {
093            config.getReliabilityStrategy().afterLogEvent();
094        }
095    }
096
097    /*
098     * (non-Javadoc)
099     *
100     * @see
101     * org.apache.logging.log4j.core.config.ReliabilityStrategy#beforeLogEvent(org.apache.logging.log4j.core.config.
102     * LoggerConfig, org.apache.logging.log4j.util.Supplier)
103     */
104    @Override
105    public LoggerConfig getActiveLoggerConfig(final Supplier<LoggerConfig> next) {
106        LoggerConfig result = this.loggerConfig;
107        if (!beforeLogEvent()) {
108            result = next.get();
109            return result == this.loggerConfig ? result : result.getReliabilityStrategy().getActiveLoggerConfig(next);
110        }
111        return result;
112    }
113
114    private boolean beforeLogEvent() {
115        reconfigureLock.readLock().lock();
116        if (isStopping) {
117            reconfigureLock.readLock().unlock();
118            return false;
119        }
120        return true;
121    }
122
123    @Override
124    public void afterLogEvent() {
125        reconfigureLock.readLock().unlock();
126    }
127
128    /*
129     * (non-Javadoc)
130     *
131     * @see org.apache.logging.log4j.core.config.ReliabilityStrategy#beforeStopAppenders()
132     */
133    @Override
134    public void beforeStopAppenders() {
135        reconfigureLock.writeLock().lock();
136        try {
137            isStopping = true;
138        } finally {
139            reconfigureLock.writeLock().unlock();
140        }
141    }
142
143    /*
144     * (non-Javadoc)
145     *
146     * @see
147     * org.apache.logging.log4j.core.config.ReliabilityStrategy#beforeStopConfiguration(org.apache.logging.log4j.core
148     * .config.Configuration)
149     */
150    @Override
151    public void beforeStopConfiguration(final Configuration configuration) {
152        // no action
153    }
154
155}