package org.altbeacon.beacon.service; import org.altbeacon.beacon.Beacon; import org.altbeacon.beacon.logging.LogManager; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; /** * Stats module used for internal performance testing of the library * Created by dyoung on 10/16/14. */ public class Stats { private static final Stats INSTANCE = new Stats(); private static final String TAG = "Stats"; /** * Synchronize all usage as this is not a thread safe class. */ private static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("HH:mm:ss.SSS"); private ArrayList<Sample> mSamples; private long mSampleIntervalMillis; private boolean mEnableLogging; private boolean mEnableHistoricalLogging; private boolean mEnabled; private Sample mSample; public static Stats getInstance() { return INSTANCE; } private Stats() { mSampleIntervalMillis = 0l; clearSamples(); } public ArrayList<Sample> getSamples() { rollSampleIfNeeded(); return mSamples; } public void setEnabled(boolean enabled) { mEnabled = enabled; } public boolean isEnabled() { return mEnabled; } public void setLoggingEnabled(boolean enabled) { mEnableLogging = enabled; } public void setHistoricalLoggingEnabled(boolean enabled) { mEnableHistoricalLogging = enabled; } public void setSampleIntervalMillis(long interval) { mSampleIntervalMillis = interval; } public void log(Beacon beacon) { rollSampleIfNeeded(); mSample.detectionCount++; if (mSample.firstDetectionTime == null) { mSample.firstDetectionTime = new Date(); } if (mSample.lastDetectionTime != null) { long timeSinceLastDetection = new Date().getTime() - mSample.lastDetectionTime.getTime(); if (timeSinceLastDetection > mSample.maxMillisBetweenDetections) { mSample.maxMillisBetweenDetections = timeSinceLastDetection; } } mSample.lastDetectionTime = new Date(); } public void clearSample() { mSample = null; } public void newSampleInterval() { Date boundaryTime = new Date(); if (mSample != null) { boundaryTime = new Date(mSample.sampleStartTime.getTime()+mSampleIntervalMillis); mSample.sampleStopTime = boundaryTime; if (!mEnableHistoricalLogging && mEnableLogging) { logSample(mSample, true); } } mSample = new Sample(); mSample.sampleStartTime = boundaryTime; mSamples.add(mSample); if (mEnableHistoricalLogging) { logSamples(); } } public void clearSamples() { mSamples = new ArrayList<Sample>(); newSampleInterval(); } private void logSample(Sample sample, boolean showHeader) { if (showHeader) { LogManager.d(TAG, "sample start time, sample stop time, first detection" + " time, last detection time, max millis between detections, detection count"); } LogManager.d(TAG, "%s, %s, %s, %s, %s, %s", formattedDate(sample.sampleStartTime), formattedDate(sample.sampleStopTime), formattedDate(sample.firstDetectionTime), formattedDate(sample.lastDetectionTime), sample.maxMillisBetweenDetections, sample.detectionCount); } private String formattedDate(Date d) { String formattedDate = ""; if (d != null) { synchronized (SIMPLE_DATE_FORMAT) { formattedDate = SIMPLE_DATE_FORMAT.format(d); } } return formattedDate; } private void logSamples() { LogManager.d(TAG, "--- Stats for %s samples", mSamples.size()); boolean firstPass = true; for (Sample sample : mSamples) { logSample(sample, firstPass); firstPass = false; } } private void rollSampleIfNeeded() { if (mSample == null || (mSampleIntervalMillis > 0 && (new Date().getTime() - mSample.sampleStartTime.getTime()) >= mSampleIntervalMillis)) { newSampleInterval(); } } public static class Sample { public long detectionCount = 0l; public long maxMillisBetweenDetections; public Date firstDetectionTime; public Date lastDetectionTime; public Date sampleStartTime; public Date sampleStopTime; } }