package com.netflix.evcache.metrics; import java.lang.management.ManagementFactory; import javax.management.MBeanServer; import javax.management.ObjectName; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.netflix.evcache.EVCache.Call; import com.netflix.servo.monitor.StatsTimer; import com.netflix.servo.monitor.StepCounter; @edu.umd.cs.findbugs.annotations.SuppressFBWarnings("REC_CATCH_EXCEPTION") public class EVCacheMetrics implements EVCacheMetricsMBean, Stats { private static final Logger log = LoggerFactory.getLogger(EVCacheMetrics.class); private final String appName, cacheName; private StepCounter getCallsCounter, bulkCallsCounter, bulkHitsCounter, getHitsCounter, setCallsCounter, addCallsCounter, replaceCallCounter, delCallsCounter, incrCounter, decrCounter; private StepCounter bulkMissCounter, getMissCounter; private StatsTimer getDuration, bulkDuration, appendOrAddDuration, appendDuration; EVCacheMetrics(final String appName, String _cacheName) { this.appName = appName; this.cacheName = (_cacheName == null) ? "" : _cacheName; setupMonitoring(appName, cacheName); } public void operationCompleted(Call op, long duration) { if (op == Call.GET || op == Call.GET_AND_TOUCH) { getCallCounter().increment(); getGetCallDuration().record(duration); } else if (op == Call.SET) { getSetCallCounter().increment(); } else if (op == Call.REPLACE) { getReplaceCallCounter().increment(); } else if (op == Call.DELETE) { getDeleteCallCounter().increment(); } else if (op == Call.BULK) { getBulkCounter().increment(); getBulkCallDuration().record(duration); } else if (op == Call.APPEND_OR_ADD) { getAppendOrAddDuration().record(duration); } else if (op == Call.ADD) { getAddCallCounter().increment(); } else if (op == Call.APPEND) { getAppendDuration().record(duration); } else if (op == Call.INCR) { getIncrCounter().increment(); } else if (op == Call.DECR) { getDecrCounter().increment(); } } private void setupMonitoring(String _appName, String _cacheName) { try { String mBeanName = "com.netflix.evcache:Group=" + _appName + ",SubGroup=AtlasStats"; if (_cacheName != null) mBeanName = mBeanName + ",SubSubGroup=" + _cacheName; final ObjectName mBeanObj = ObjectName.getInstance(mBeanName); final MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer(); if (mbeanServer.isRegistered(mBeanObj)) { if (log.isDebugEnabled()) log.debug("MBEAN with name " + mBeanObj + " has been registered. Will unregister the previous instance and register a new one."); mbeanServer.unregisterMBean(mBeanObj); } mbeanServer.registerMBean(this, mBeanObj); if (log.isDebugEnabled()) log.debug("MBEAN with name " + mBeanObj + " has been registered."); } catch (Exception e) { if (log.isDebugEnabled()) log.debug(e.getMessage(), e); } } private StepCounter getCallCounter() { if (this.getCallsCounter != null) return this.getCallsCounter; this.getCallsCounter = EVCacheMetricsFactory.getStepCounter(appName, cacheName, "GetCall"); getHitCounter(); return getCallsCounter; } private StepCounter getHitCounter() { if (this.getHitsCounter != null) return this.getHitsCounter; this.getHitsCounter = EVCacheMetricsFactory.getStepCounter(appName, cacheName, "GetHit"); return getHitsCounter; } private StepCounter getMissCounter() { if (this.getMissCounter != null) return this.getMissCounter; this.getMissCounter = EVCacheMetricsFactory.getStepCounter(appName, cacheName, "GetMiss"); return getMissCounter; } private StepCounter getBulkCounter() { if (this.bulkCallsCounter != null) return this.bulkCallsCounter; this.bulkCallsCounter = EVCacheMetricsFactory.getStepCounter(appName, cacheName, "BulkCall"); return bulkCallsCounter; } private StepCounter getBulkHitCounter() { if(this.bulkHitsCounter != null) return this.bulkHitsCounter; this.bulkHitsCounter = EVCacheMetricsFactory.getStepCounter(appName, cacheName, "BulkHit"); return bulkHitsCounter; } private StepCounter getBulkMissCounter() { if(this.bulkMissCounter != null) return this.bulkMissCounter; this.bulkMissCounter = EVCacheMetricsFactory.getStepCounter(appName, cacheName, "BulkMiss"); return bulkMissCounter; } private StepCounter getAddCallCounter() { if (this.addCallsCounter != null) return this.addCallsCounter; this.addCallsCounter = EVCacheMetricsFactory.getStepCounter(appName, cacheName, "AddCall"); return addCallsCounter; } private StepCounter getSetCallCounter() { if (this.setCallsCounter != null) return this.setCallsCounter; this.setCallsCounter = EVCacheMetricsFactory.getStepCounter(appName, cacheName, "SetCall"); return setCallsCounter; } private StepCounter getReplaceCallCounter() { if (this.replaceCallCounter != null) return this.replaceCallCounter; this.replaceCallCounter = EVCacheMetricsFactory.getStepCounter(appName, cacheName, "ReplaceCall"); return replaceCallCounter; } private StepCounter getDeleteCallCounter() { if (this.delCallsCounter != null) return this.delCallsCounter; this.delCallsCounter = EVCacheMetricsFactory.getStepCounter(appName, cacheName, "DeleteCall"); return delCallsCounter; } private StatsTimer getAppendOrAddDuration() { if (appendOrAddDuration != null) return appendOrAddDuration; this.appendOrAddDuration = EVCacheMetricsFactory.getStatsTimer(appName, cacheName, "LatencyAppendOrAdd"); return appendOrAddDuration; } private StatsTimer getAppendDuration() { if (appendDuration != null) return appendDuration; this.appendDuration = EVCacheMetricsFactory.getStatsTimer(appName, cacheName, "LatencyAppend"); return appendDuration; } private StatsTimer getGetCallDuration() { if (getDuration != null) return getDuration; this.getDuration = EVCacheMetricsFactory.getStatsTimer(appName, cacheName, "LatencyGet"); return getDuration; } private StatsTimer getBulkCallDuration() { if (bulkDuration != null) return bulkDuration; this.bulkDuration = EVCacheMetricsFactory.getStatsTimer(appName, cacheName, "LatencyBulk"); return bulkDuration; } public long getGetCalls() { return getCallCounter().getValue().longValue(); } public long getCacheHits() { return getHitCounter().getValue().longValue(); } public long getCacheMiss() { return getMissCounter().getValue().longValue(); } public long getBulkCalls() { return getBulkCounter().getValue().longValue(); } public long getBulkHits() { return getBulkHitCounter().getValue().longValue(); } public long getBulkMiss() { return getBulkMissCounter().getValue().longValue(); } public long getSetCalls() { return getSetCallCounter().getValue().longValue(); } public void cacheHit(Call call) { if (call == Call.BULK) { this.getBulkHitCounter().increment(); } else { this.getHitCounter().increment(); } } public void cacheMiss(Call call) { if (call == Call.BULK) { this.getBulkMissCounter().increment(); } else { this.getMissCounter().increment(); } } private StepCounter getIncrCounter() { if (this.incrCounter != null) return this.incrCounter; this.incrCounter = EVCacheMetricsFactory.getStepCounter(appName, cacheName, "IncrCall"); return incrCounter; } private StepCounter getDecrCounter() { if (this.decrCounter != null) return this.decrCounter; this.decrCounter = EVCacheMetricsFactory.getStepCounter(appName, cacheName, "DecrCall"); return decrCounter; } public long getGetDuration() { return getGetCallDuration().getValue().longValue(); } public long getBulkDuration() { return getBulkCallDuration().getValue().longValue(); } public String toString() { return "EVCacheMetrics [ AppName=" + appName + ", CachePrefix=" + cacheName + ", getCalls=" + getCallCounter() + ", bulkCalls=" + getBulkCounter() + ", setCalls=" + getSetCallCounter() + ", cacheHits=" + getHitCounter() + ", cacheMiss=" + getMissCounter() + ", bulkHits=" + getBulkHitCounter() + ", bulkMiss=" + getBulkMissCounter() + ", deleteCalls=" + getDeleteCallCounter() + ", getDuration=" + getGetCallDuration() + ", bulkDuration=" + getBulkCallDuration() + ", replaceCalls=" + getReplaceCallCounter() + "]"; } public double getHitRate() { return (getCacheHits() / getGetCalls()) * 100; } public double getBulkHitRate() { return (getBulkHits() / getBulkCalls()) * 100; } }