/*
* Copyright (c) 2016, MGrossmann
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the jo-widgets.org nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL jo-widgets.org BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
package org.jowidgets.logging.api;
import java.text.MessageFormat;
import java.util.concurrent.TimeUnit;
import org.jowidgets.logging.tools.AbstractLogMessageDecorator;
import org.jowidgets.util.Assert;
import org.jowidgets.util.DefaultSystemTimeProvider;
import org.jowidgets.util.EmptyCheck;
import org.jowidgets.util.ISystemTimeProvider;
public final class SuppressingLogMessageDecorators {
public static final long DEFAULT_PERIOD = 1000;
public static final TimeUnit DEFAULT_TIME_UNIT = TimeUnit.MILLISECONDS;
public static final String DEFAULT_SUPPRESS_MESSAGE_TEXT = "More log messages will be suppressed the next {0} {1}.";
public static final String DEFAULT_SUPPRESSED_MESSAGE_TEXT = "{0} log messages was suppressed before.";
private SuppressingLogMessageDecorators() {}
/**
* Creates a new suppressing log message decorator with default period (1000 ms)
*
* @param maxPeriod The max period to use
*
* @return a new suppressing log message decorator
*/
public static ILogMessageDecorator create() {
return create(DEFAULT_PERIOD, DEFAULT_TIME_UNIT);
}
/**
* Creates a new suppressing log message decorator with a given maxPeriod in milliseconds
*
* @param maxPeriod The max period to use
*
* @return a new suppressing log message decorator
*/
public static ILogMessageDecorator create(final long maxPeriod) {
return create(maxPeriod, DEFAULT_TIME_UNIT);
}
/**
* Creates a new suppressing log message decorator
*
* @param maxPeriod The max period to use
* @param timeUnit The time unit for the period
*
* @return a new suppressing log message decorator
*/
public static ILogMessageDecorator create(final long maxPeriod, final TimeUnit timeUnit) {
return builder().setMaxPeriod(maxPeriod, timeUnit).build();
}
/**
* Creates a new builder
*
* @return a new builder
*/
public static ISuppressingLogMessageDecoratorBuilder builder() {
return new SuppressingLogMessageDecoratorBuilderImpl();
}
private static final class SuppressingLogMessageDecoratorBuilderImpl implements ISuppressingLogMessageDecoratorBuilder {
private ISystemTimeProvider systemTimeProvider;
private boolean appendMessage;
private String suppressMessageText;
private String suppressedMessageText;
private long period;
private TimeUnit timeUnit;
private SuppressingLogMessageDecoratorBuilderImpl() {
this.period = DEFAULT_PERIOD;
this.timeUnit = DEFAULT_TIME_UNIT;
this.appendMessage = true;
this.suppressMessageText = DEFAULT_SUPPRESS_MESSAGE_TEXT;
this.suppressedMessageText = DEFAULT_SUPPRESSED_MESSAGE_TEXT;
this.systemTimeProvider = DefaultSystemTimeProvider.getInstance();
}
@Override
public ISuppressingLogMessageDecoratorBuilder setMaxPeriod(final long period) {
return setMaxPeriod(period, TimeUnit.MILLISECONDS);
}
@Override
public ISuppressingLogMessageDecoratorBuilder setMaxPeriod(final long period, final TimeUnit timeUnit) {
Assert.paramNotNull(timeUnit, "timeUnit");
this.period = period;
this.timeUnit = timeUnit;
return this;
}
@Override
public ISuppressingLogMessageDecoratorBuilder appendMessage(final boolean appendMessage) {
this.appendMessage = appendMessage;
return this;
}
@Override
public ISuppressingLogMessageDecoratorBuilder setSuppressMessageText(final String text) {
this.suppressMessageText = text;
return this;
}
@Override
public ISuppressingLogMessageDecoratorBuilder setSuppressedMessageText(final String text) {
this.suppressedMessageText = text;
return this;
}
@Override
public ISuppressingLogMessageDecoratorBuilder setSystemTimeProvider(final ISystemTimeProvider systemTimeProvider) {
Assert.paramNotNull(systemTimeProvider, "systemTimeProvider");
this.systemTimeProvider = systemTimeProvider;
return this;
}
long getPeriod() {
return period;
}
TimeUnit getTimeUnit() {
return timeUnit;
}
boolean isAppendMessage() {
return appendMessage;
}
String getSuppressMessageText() {
return suppressMessageText;
}
String getSuppressedMessageText() {
return suppressedMessageText;
}
ISystemTimeProvider getSystemTimeProvider() {
return systemTimeProvider;
}
@Override
public ILogMessageDecorator build() {
return new SuppressingLogMessageDecoratorImpl(this);
}
}
private static final class SuppressingLogMessageDecoratorImpl extends AbstractLogMessageDecorator implements
ILogMessageDecorator {
private final boolean appendMessage;
private final long period;
private final TimeUnit timeUnit;
private final ISystemTimeProvider systemTimeProvider;
private final String suppressMessageText;
private final String suppressedMessageText;
private long supressedLogMessageCount;
private long lastLogEventTimestamp;
SuppressingLogMessageDecoratorImpl(final SuppressingLogMessageDecoratorBuilderImpl builder) {
this.appendMessage = isAppendMessage(builder);
this.suppressMessageText = formatSuppressMessageText(builder);
this.suppressedMessageText = builder.getSuppressedMessageText();
this.period = builder.getPeriod();
this.timeUnit = builder.getTimeUnit();
this.systemTimeProvider = builder.getSystemTimeProvider();
this.supressedLogMessageCount = 0;
this.lastLogEventTimestamp = -1;
}
private boolean isAppendMessage(final SuppressingLogMessageDecoratorBuilderImpl builder) {
return !(!builder.isAppendMessage() || (EmptyCheck.isEmpty(builder.getSuppressMessageText()) && EmptyCheck.isEmpty(builder.getSuppressMessageText())));
}
private String formatSuppressMessageText(final SuppressingLogMessageDecoratorBuilderImpl builder) {
final String result = builder.getSuppressMessageText();
if (EmptyCheck.isEmpty(result)) {
return null;
}
else {
return MessageFormat.format(result, builder.getPeriod(), builder.timeUnit);
}
}
@Override
public void error(final String message, final Throwable throwable, final ILogger original) {
if (original.isErrorEnabled() && !(handleMessageAndDetermineIfSupress())) {
original.error(getDecoratedMessage(message), throwable);
supressedLogMessageCount = 0;
}
}
@Override
public void warn(final String message, final Throwable throwable, final ILogger original) {
if (original.isWarnEnabled() && !(handleMessageAndDetermineIfSupress())) {
original.warn(getDecoratedMessage(message), throwable);
supressedLogMessageCount = 0;
}
}
@Override
public void info(final String message, final Throwable throwable, final ILogger original) {
if (original.isWarnEnabled() && !(handleMessageAndDetermineIfSupress())) {
original.info(getDecoratedMessage(message), throwable);
supressedLogMessageCount = 0;
}
}
@Override
public void debug(final String message, final Throwable throwable, final ILogger original) {
if (original.isDebugEnabled() && !(handleMessageAndDetermineIfSupress())) {
original.debug(getDecoratedMessage(message), throwable);
supressedLogMessageCount = 0;
}
}
@Override
public void trace(final String message, final Throwable throwable, final ILogger original) {
if (original.isTraceEnabled() && !(handleMessageAndDetermineIfSupress())) {
original.trace(getDecoratedMessage(message), throwable);
supressedLogMessageCount = 0;
}
}
private boolean handleMessageAndDetermineIfSupress() {
final long currentTime = systemTimeProvider.currentTimeMillis();
final boolean supress;
if (lastLogEventTimestamp == -1) {
supress = false;
}
else {
supress = isDurationBelowPeriod(currentTime - lastLogEventTimestamp);
}
if (supress) {
supressedLogMessageCount++;
}
else {
lastLogEventTimestamp = currentTime;
}
return supress;
}
private boolean isDurationBelowPeriod(final long durationMillis) {
return durationMillis < TimeUnit.MILLISECONDS.convert(period, timeUnit);
}
private String getDecoratedMessage(final String message) {
if (!appendMessage) {
return message;
}
else if (EmptyCheck.isEmpty(message)) {
return getMessageSuffix();
}
else {
return message + " " + getMessageSuffix();
}
}
private String getMessageSuffix() {
if (supressedLogMessageCount > 0) {
return createMessageTextForAlreadySuppressed();
}
else {
return suppressMessageText;
}
}
private String createMessageTextForAlreadySuppressed() {
final StringBuilder builder = new StringBuilder(" ");
builder.append(formatSuppressedMessageText());
builder.append(" ");
builder.append(suppressMessageText);
return builder.toString();
}
private String formatSuppressedMessageText() {
if (EmptyCheck.isEmpty(suppressedMessageText)) {
return null;
}
else {
return MessageFormat.format(suppressedMessageText, supressedLogMessageCount);
}
}
}
}