/** * Copyright (c) 2013 Eclectic Logic LLC * * Licensed 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 com.eclecticlogic.whisper.core; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import com.eclecticlogic.whisper.spi.Message; /** * Handles the core logic of figuring out if messages should be suppressed. * * @author Karthik Abram * */ public class Muffler<E> { private final String messageKey; private boolean inSuppression; private AtomicInteger messagesSinceSuppressionStart = new AtomicInteger(); private AtomicInteger messagesSinceLastDigest = new AtomicInteger(); private AtomicReference<Message<E>> lastMessage = new AtomicReference<Message<E>>(); private SuppressionQueue queue = new SuppressionQueue(); private WhisperManager<E> manager; public Muffler(WhisperManager<E> manager, String messageKey) { super(); this.manager = manager; this.messageKey = messageKey; queue.setSuppressAfter(manager.getSuppressAfter()); } /** * @param message Message to log (and possible suppress). */ public void log(Message<E> message) { if (inSuppression) { Message<E> msg = lastMessage.get(); if (msg != null && msg.getMessageAge() > manager.getSuppressionExpirationTime()) { // Suppression ends inSuppression = false; manager.remove(this.messageKey); // Re-attempt to log this. manager.log(message); } else { messagesSinceSuppressionStart.incrementAndGet(); messagesSinceLastDigest.incrementAndGet(); lastMessage.set(message); } } else { queue.offer(message.getMessageTime()); if (queue.size() > manager.getSuppressionOnMessagesCount()) { // Start suppression queue.clear(); inSuppression = true; // Circle back in to invoke suppression behavior. log(message); } else { // log manager.logThrough(message); } } } /** * Record message suppression digest. * @param digest */ public void digest(Digest digest) { // Write digest only if we've suppressed something. Without the null check, an error message that is written // just once will cause a NPE (see https://github.com/eclecticlogic/whisper/issues/1) Message<E> m = lastMessage.get(); if (m != null) { // Added check to see if any messages have been supressed since last digest otherwise // code sends suppression message indicating nothing happened. // Refer to https://github.com/eclecticlogic/whisper/issues/3 if (this.messagesSinceLastDigest.get() == 0) { if (m.getMessageAge() > this.manager.getSuppressionExpirationTime()) { // Suppression ends inSuppression = false; manager.remove(this.messageKey); lastMessage.set(null); } else { // We haven't received any new messages but we are not outside the suppression time either. // Do nothing. } } else { DigestMessage dm = new DigestMessage(); dm.setMessage(m.getMessage()); dm.setFullMessage(m.getFullMessage()); dm.setMessagesSinceLastDigest(messagesSinceLastDigest.get()); dm.setMessagesSinceSuppressionStart(messagesSinceSuppressionStart.get()); messagesSinceLastDigest.set(0); digest.add(dm); } } } }