/* Copyright (c) 2011 Danish Maritime Authority
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
package dk.dma.ais.abnormal.application.statistics;
import com.google.inject.Singleton;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
/**
* Class for holding information on the file processing process
*/
@Singleton
public class AppStatisticsServiceImpl implements AppStatisticsService {
private static final Logger LOG = LoggerFactory.getLogger(AppStatisticsServiceImpl.class);
private static final int DEFAULT_DUMP_INTERVAL_SECONDS = 3600;
private final int dumpInterval;
private final LocalDateTime timeStart = LocalDateTime.now();
private final AtomicLong lastDump = new AtomicLong(System.currentTimeMillis());
private final AtomicLong lastMessageCount = new AtomicLong(0);
private final AtomicLong unfilteredPacketCount = new AtomicLong(0);
private final AtomicLong filteredPacketCount = new AtomicLong(0);
private final AtomicLong messageCount = new AtomicLong(0);
private final AtomicLong messagesOutOfSequence = new AtomicLong(0);
private final AtomicLong posMsgCount = new AtomicLong(0);
private final AtomicLong statMsgCount = new AtomicLong(0);
private final AtomicInteger trackCount = new AtomicInteger(0);
private final ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
public AppStatisticsServiceImpl() {
this.dumpInterval = DEFAULT_DUMP_INTERVAL_SECONDS;
}
public AppStatisticsServiceImpl(int dumpInterval) {
this.dumpInterval = dumpInterval;
}
@Override
public void start() {
LOG.debug("Starting statistics service.");
scheduledExecutorService.scheduleAtFixedRate(() -> dumpStatistics(), 0 /* dumpInterval */, dumpInterval, TimeUnit.SECONDS);
LOG.info("Statistics service started.");
}
@Override
public void stop() {
LOG.debug("Stopping statistics service.");
scheduledExecutorService.shutdown();
try {
scheduledExecutorService.awaitTermination(2* dumpInterval, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
LOG.error(e.getMessage(), e);
}
LOG.info("Statistics service stopped.");
}
@Override
public final long getFilteredPacketCount() {
return filteredPacketCount.get();
}
@Override
public final long getMessageCount() {
return messageCount.get();
}
@Override
public final long getPosMsgCount() {
return posMsgCount.get();
}
@Override
public final long getStatMsgCount() {
return statMsgCount.get();
}
@Override
public final void incFilteredPacketCount() {
filteredPacketCount.incrementAndGet();
}
@Override
public final void incUnfilteredPacketCount() {
this.unfilteredPacketCount.incrementAndGet();
}
@Override
public final void incMessageCount() {
messageCount.incrementAndGet();
}
@Override
public final void incPosMsgCount() {
posMsgCount.incrementAndGet();
}
@Override
public final void incStatMsgCount() {
statMsgCount.incrementAndGet();
}
@Override
public final void incOutOfSequenceMessages() {
messagesOutOfSequence.incrementAndGet();
}
@Override
public void setTrackCount(int trackCount) {
this.trackCount.set(trackCount);
}
protected double getMessageRate() {
double secs = (double)(System.currentTimeMillis() - lastDump.get()) / 1000.0;
long msgs = messageCount.get() - lastMessageCount.get();
lastDump.set(System.currentTimeMillis());
lastMessageCount.set(messageCount.get());
return (double) msgs / secs;
}
@Override
public void dumpStatistics() {
final LocalDateTime now = LocalDateTime.now();
final String runTimeAsString = Duration.between(timeStart, now).toString();
LOG.info("==== AIS Abnormal Behavior application statistics ====");
LOG.info("==== Application statistics ====");
LOG.info(String.format("%-30s %31s", "Time start", timeStart.toString()));
LOG.info(String.format("%-30s %31s", "Time now", now));
LOG.info(String.format("%-30s %" + (8+runTimeAsString.length()) + "s", "Runtime duration", runTimeAsString));
LOG.info(String.format("%-30s %9d", "Unfiltered packet count", unfilteredPacketCount.get()));
LOG.info(String.format("%-30s %9d", "Filtered packet count", filteredPacketCount.get()));
LOG.info(String.format("%-30s %9d", "Message count", messageCount.get()));
LOG.info(String.format("%-30s %9d", "Messages out of sequence", messagesOutOfSequence.get()));
LOG.info(String.format("%-30s %9d", "Pos message count", posMsgCount.get()));
LOG.info(String.format("%-30s %9d", "Stat message count", statMsgCount.get()));
LOG.info(String.format("%-30s %9d", "Track count", trackCount.get()));
LOG.info(String.format("%-30s %9.0f msg/sec", "Message rate", getMessageRate()));
LOG.info("==== Application statistics ====");
}
}