package com.netflix.evcache.metrics; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantReadWriteLock; import com.netflix.config.DynamicIntProperty; import com.netflix.evcache.EVCache.Call; import com.netflix.evcache.pool.ServerGroup; import com.netflix.evcache.util.EVCacheConfig; import com.netflix.servo.DefaultMonitorRegistry; import com.netflix.servo.annotations.DataSourceType; import com.netflix.servo.monitor.BasicCounter; import com.netflix.servo.monitor.Counter; import com.netflix.servo.monitor.LongGauge; import com.netflix.servo.monitor.Monitor; import com.netflix.servo.monitor.MonitorConfig; import com.netflix.servo.monitor.Monitors; import com.netflix.servo.monitor.MonitorConfig.Builder; import com.netflix.servo.monitor.StatsTimer; import com.netflix.servo.monitor.StepCounter; import com.netflix.servo.monitor.Timer; import com.netflix.servo.stats.StatsConfig; import com.netflix.servo.tag.BasicTagList; import com.netflix.servo.tag.Tag; import com.netflix.servo.tag.TagList; import com.netflix.spectator.api.DistributionSummary; import com.netflix.spectator.api.Id; import com.netflix.spectator.api.Registry; import com.netflix.spectator.api.Spectator; import com.netflix.servo.tag.BasicTag; @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = { "NF_LOCAL_FAST_PROPERTY", "PMB_POSSIBLE_MEMORY_BLOAT" }, justification = "Creates only when needed") public final class EVCacheMetricsFactory { private static final Map<String, Stats> statsMap = new ConcurrentHashMap<String, Stats>(); private static final Map<String, Monitor<?>> monitorMap = new ConcurrentHashMap<String, Monitor<?>>(); private static final Map<String, DistributionSummary> distributionSummaryMap = new ConcurrentHashMap<String, DistributionSummary>(); private static final Lock writeLock = (new ReentrantReadWriteLock()).writeLock(); private static final Map<String, Timer> timerMap = new HashMap<String, Timer>(); private static final DynamicIntProperty sampleSize = EVCacheConfig.getInstance().getDynamicIntProperty("EVCache.metrics.sample.size", 100); public static Operation getOperation(String name) { return getOperation(name, null, null, Operation.TYPE.MILLI); } public static Operation getOperation(String name, Call op, Stats stats) { return getOperation(name, op, stats, Operation.TYPE.MILLI); } public static Operation getOperation(String name, Call op, Stats stats, Operation.TYPE type) { final Operation operation = new EVCacheOperation(name, op, stats, type); operation.start(); return operation; } public static Stats getStats(String appName, String cacheName) { final String key = (cacheName == null) ? appName + ":NA" : appName + ":" + cacheName; Stats metrics = statsMap.get(key); if (metrics != null) return metrics; writeLock.lock(); try { if (statsMap.containsKey(key)) { metrics = statsMap.get(key); } else { statsMap.put(key, metrics = new EVCacheMetrics(appName, cacheName)); } } finally { writeLock.unlock(); } return metrics; } public static Map<String, Stats> getAllMetrics() { return statsMap; } public static Map<String, Monitor<?>> getAllMonitor() { return monitorMap; } public static Map<String, DistributionSummary> getAllDistributionSummaryMap() { return distributionSummaryMap; } public static LongGauge getLongGauge(String name) { LongGauge gauge = (LongGauge) monitorMap.get(name); if (gauge == null) { writeLock.lock(); try { if (monitorMap.containsKey(name)) { gauge = (LongGauge) monitorMap.get(name); } else { gauge = new LongGauge(MonitorConfig.builder(name).build()); monitorMap.put(name, gauge); DefaultMonitorRegistry.getInstance().register(gauge); } } finally { writeLock.unlock(); } } return gauge; } public static LongGauge getLongGauge(String cName, TagList tag) { final String name = cName + tag.toString(); LongGauge gauge = (LongGauge) monitorMap.get(name); if (gauge == null) { writeLock.lock(); try { if (monitorMap.containsKey(name)) { gauge = (LongGauge) monitorMap.get(name); } else { gauge = new LongGauge(MonitorConfig.builder(cName).withTags(tag).build()); monitorMap.put(name, gauge); DefaultMonitorRegistry.getInstance().register(gauge); } } finally { writeLock.unlock(); } } return gauge; } public static Counter getCounter(String cName, Tag tag) { if (tag == null) return getCounter(cName); final String name = cName + tag.tagString(); Counter counter = (Counter) monitorMap.get(name); if (counter == null) { writeLock.lock(); try { if (monitorMap.containsKey(name)) { counter = (Counter) monitorMap.get(name); } else { counter = new BasicCounter(MonitorConfig.builder(cName).withTag(tag).build()); monitorMap.put(name, counter); DefaultMonitorRegistry.getInstance().register(counter); } } finally { writeLock.unlock(); } } return counter; } public static Counter getCounter(String cName, TagList tag) { final String name = cName + tag.toString(); Counter counter = (Counter) monitorMap.get(name); if (counter == null) { writeLock.lock(); try { if (monitorMap.containsKey(name)) { counter = (Counter) monitorMap.get(name); } else { counter = new BasicCounter(MonitorConfig.builder(cName).withTags(tag).build()); monitorMap.put(name, counter); DefaultMonitorRegistry.getInstance().register(counter); } } finally { writeLock.unlock(); } } return counter; } public static Counter getCounter(String name) { return getCounter(name, DataSourceType.COUNTER); } public static void increment(String name) { final Counter counter = getCounter(name); counter.increment(); } public static void increment(String appName, String cacheName, String metricName) { final Counter counter = getCounter(appName, cacheName, null, metricName, DataSourceType.COUNTER); counter.increment(); } public static void increment(String appName, String cacheName, String serverGroupName, String metricName) { final Counter counter = getCounter(appName, cacheName, serverGroupName, metricName, DataSourceType.COUNTER); counter.increment(); } public static Counter getCounter(String appName, String cacheName, String metricName, Tag tag) { return getCounter(appName, cacheName, null, metricName, DataSourceType.COUNTER); } public static Counter getCounter(String appName, String cacheName, String serverGroupName, String metricName, Tag tag) { final String name = appName + (cacheName != null ? cacheName : "") + (serverGroupName != null ? serverGroupName : "") + metricName + tag.tagString(); Counter counter = (Counter) monitorMap.get(name); if (counter == null) { TagList tags = BasicTagList.of("APP", appName, tag.getKey(), tag.getValue()); if (cacheName != null && cacheName.length() > 0) { tags = BasicTagList.concat(tags, new BasicTag("CACHE", cacheName)); } if(serverGroupName != null && serverGroupName.length() > 0) { tags = BasicTagList.concat(tags, new BasicTag("ServerGroup", serverGroupName)); } if(!tags.containsKey(DataSourceType.COUNTER.getKey())) { tags = BasicTagList.concat(tags, DataSourceType.COUNTER); } writeLock.lock(); try { if (monitorMap.containsKey(name)) { counter = (Counter) monitorMap.get(name); } else { counter = new BasicCounter(MonitorConfig.builder(metricName).build().withAdditionalTags(tags)); monitorMap.put(name, counter); DefaultMonitorRegistry.getInstance().register(counter); } } finally { writeLock.unlock(); } } return counter; } public static StepCounter getStepCounter(String appName, String cacheName, String metric) { final String metricName = getMetricName(appName, null, metric); final String name = metricName + (cacheName == null ? "" : "-" + cacheName + "-") + "type=StepCounter"; final StepCounter counter = (StepCounter) monitorMap.get(name); if (counter != null) return counter; writeLock.lock(); try { if (monitorMap.containsKey(name)) return (StepCounter) monitorMap.get(name); else { final StepCounter _counter = new StepCounter(getMonitorConfig(metricName, appName, cacheName, metric)); monitorMap.put(name, _counter); DefaultMonitorRegistry.getInstance().register(_counter); return _counter; } } finally { writeLock.unlock(); } } public static StatsTimer getStatsTimer(String appName, String cacheName, String metric) { final String metricName = getMetricName(appName, null, metric); final String name = metricName + (cacheName == null ? "" : "-" + cacheName + "-") + "type=StatsTimer"; final StatsTimer duration = (StatsTimer) monitorMap.get(name); if (duration != null) return duration; writeLock.lock(); try { if (monitorMap.containsKey(name)) return (StatsTimer) monitorMap.get(name); else { final StatsConfig statsConfig = new StatsConfig.Builder().withPercentiles(new double[] { 95, 99 }) .withPublishMax(true).withPublishMin(true) .withPublishMean(true).withPublishCount(true).withSampleSize(sampleSize.get()).build(); final StatsTimer _duration = new StatsTimer(getMonitorConfig(metricName, appName, cacheName, metric), statsConfig, TimeUnit.MILLISECONDS); monitorMap.put(name, _duration); DefaultMonitorRegistry.getInstance().register(_duration); return _duration; } } finally { writeLock.unlock(); } } public static StatsTimer getStatsTimer(String appName, ServerGroup serverGroup, String metric) { final String serverGroupName = (serverGroup != null ? serverGroup.getName() : ""); final String metricName = getMetricName(appName, null, metric); final String name = metricName + serverGroupName + "type=StatsTimer"; final StatsTimer duration = (StatsTimer) monitorMap.get(name); if (duration != null) return duration; writeLock.lock(); try { if (monitorMap.containsKey(name)) return (StatsTimer) monitorMap.get(name); else { final StatsConfig statsConfig = new StatsConfig.Builder().withPercentiles(new double[] { 95, 99 }) .withPublishMax(true).withPublishMin(true) .withPublishMean(true).withPublishCount(true).withSampleSize(sampleSize.get()).build(); final StatsTimer _duration = new StatsTimer(getMonitorConfig(metricName, appName, null, serverGroupName, metric), statsConfig, TimeUnit.MILLISECONDS); monitorMap.put(name, _duration); DefaultMonitorRegistry.getInstance().register(_duration); return _duration; } } finally { writeLock.unlock(); } } public static String getMetricName(String appName, String cacheName, String metric) { return appName + (cacheName == null ? "-" : "-" + cacheName + "-") + metric; } public static MonitorConfig getMonitorConfig(String appName, String cacheName, String metric) { return getMonitorConfig(getMetricName(appName, cacheName, metric), appName, cacheName, metric); } public static MonitorConfig getMonitorConfig(String name, String appName, String cacheName, String metric) { Builder builder = MonitorConfig.builder(name).withTag("APP", appName).withTag("METRIC", metric); if (cacheName != null && cacheName.length() > 0) { builder = builder.withTag("CACHE", cacheName); } return builder.build(); } public static MonitorConfig getMonitorConfig(String name, String appName, String cacheName, String serverGroup, String metric) { Builder builder = MonitorConfig.builder(name).withTag("APP", appName).withTag("METRIC", metric); if (cacheName != null && cacheName.length() > 0) { builder = builder.withTag("CACHE", cacheName); } if (serverGroup != null && serverGroup.length() > 0) { builder = builder.withTag("ServerGroup", serverGroup); } return builder.build(); } public static Timer getStatsTimer(String name) { Timer timer = timerMap.get(name); if (timer != null) return timer; writeLock.lock(); try { if (timerMap.containsKey(name)) { return timerMap.get(name); } else { final StatsConfig statsConfig = new StatsConfig.Builder().withPercentiles(new double[] { 95, 99 }) .withPublishMax(true).withPublishMin(true).withPublishMean(true) .withPublishCount(true).withSampleSize(sampleSize.get()).build(); final MonitorConfig monitorConfig = MonitorConfig.builder(name).build(); timer = new StatsTimer(monitorConfig, statsConfig, TimeUnit.MILLISECONDS); DefaultMonitorRegistry.getInstance().register(timer); timerMap.put(name, timer); return timer; } } finally { writeLock.unlock(); } } public static DistributionSummary getDistributionSummary(String name, String appName, String serverGroup) { final String metricName = getMetricName(appName, serverGroup, name); final DistributionSummary _ds = distributionSummaryMap.get(metricName); if(_ds != null) return _ds; final Registry registry = Spectator.globalRegistry(); //_poolManager.getRegistry(); if (registry != null) { Id id = registry.createId(name); id = id.withTag("APP", appName); if(serverGroup != null) id = id.withTag("ServerGroup", serverGroup); final DistributionSummary ds = registry.distributionSummary(id); if (!Monitors.isObjectRegistered(ds)) Monitors.registerObject(ds); distributionSummaryMap.put(metricName, ds); return ds; } return null; } }