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 */ 017package org.apache.logging.log4j.core.appender; 018 019import java.util.concurrent.TimeUnit; 020 021import org.apache.logging.log4j.Logger; 022import org.apache.logging.log4j.core.Appender; 023import org.apache.logging.log4j.core.ErrorHandler; 024import org.apache.logging.log4j.core.LogEvent; 025import org.apache.logging.log4j.status.StatusLogger; 026 027import static java.util.Objects.requireNonNull; 028 029/** 030 * The default {@link ErrorHandler} implementation falling back to {@link StatusLogger}. 031 * <p> 032 * It avoids flooding the {@link StatusLogger} by allowing either the first 3 errors or errors once every 5 minutes. 033 * </p> 034 */ 035public class DefaultErrorHandler implements ErrorHandler { 036 037 private static final Logger LOGGER = StatusLogger.getLogger(); 038 039 private static final int MAX_EXCEPTION_COUNT = 3; 040 041 private static final long EXCEPTION_INTERVAL_NANOS = TimeUnit.MINUTES.toNanos(5); 042 043 private int exceptionCount = 0; 044 045 private long lastExceptionInstantNanos = System.nanoTime() - EXCEPTION_INTERVAL_NANOS - 1; 046 047 private final Appender appender; 048 049 public DefaultErrorHandler(final Appender appender) { 050 this.appender = requireNonNull(appender, "appender"); 051 } 052 053 /** 054 * Handle an error with a message. 055 * @param msg a message 056 */ 057 @Override 058 public void error(final String msg) { 059 final boolean allowed = acquirePermit(); 060 if (allowed) { 061 LOGGER.error(msg); 062 } 063 } 064 065 /** 066 * Handle an error with a message and an exception. 067 * 068 * @param msg a message 069 * @param error a {@link Throwable} 070 */ 071 @Override 072 public void error(final String msg, final Throwable error) { 073 final boolean allowed = acquirePermit(); 074 if (allowed) { 075 LOGGER.error(msg, error); 076 } 077 if (!appender.ignoreExceptions() && error != null && !(error instanceof AppenderLoggingException)) { 078 throw new AppenderLoggingException(msg, error); 079 } 080 } 081 082 /** 083 * Handle an error with a message, an exception, and a logging event. 084 * 085 * @param msg a message 086 * @param event a {@link LogEvent} 087 * @param error a {@link Throwable} 088 */ 089 @Override 090 public void error(final String msg, final LogEvent event, final Throwable error) { 091 final boolean allowed = acquirePermit(); 092 if (allowed) { 093 LOGGER.error(msg, error); 094 } 095 if (!appender.ignoreExceptions() && error != null && !(error instanceof AppenderLoggingException)) { 096 throw new AppenderLoggingException(msg, error); 097 } 098 } 099 100 private boolean acquirePermit() { 101 final long currentInstantNanos = System.nanoTime(); 102 synchronized (this) { 103 if (currentInstantNanos - lastExceptionInstantNanos > EXCEPTION_INTERVAL_NANOS) { 104 lastExceptionInstantNanos = currentInstantNanos; 105 return true; 106 } else if (exceptionCount < MAX_EXCEPTION_COUNT) { 107 exceptionCount++; 108 lastExceptionInstantNanos = currentInstantNanos; 109 return true; 110 } else { 111 return false; 112 } 113 } 114 } 115 116 public Appender getAppender() { 117 return appender; 118 } 119 120}