protected <T> void metricChanged(BaseMetricImpl<T> metric) { long lastTime = metric.changeTime; // NOTE: changeTime is only accurate for metrics that are enabled, and // to guarantee that it always corresponds to the value, updates to // enabled metrics are synchronized. metric.changeTime = timebase + System.nanoTime(); metric.valueChanged = true; metricsDataChanged = true; int level; if ((lastTime == 0) || (metric.changeTime <= lastTime)) { level = 0; } else { // Longer duration -> higher level. double r = random.nextDouble(); if (r == 0) { level = NLEVELS - 1; } else { level = Math.min( NLEVELS - 1, (int) (Math.log((metric.changeTime - lastTime) / r) / METRIC_LEVEL_DIVISOR)); } } MetricLevel<T> metricLevel = metric.levels.get(level); MetricLevelValues values = metricLevel.values.peekLast(); if ((values == null) || values.isFull()) { if (logger.isTraceEnabled()) { logger.trace( "New level {} entry at {} for {}", new Object[] {level, metric.changeTime, metric}); } values = new MetricLevelValues(metric.changeTime, metric.encodeValue()); metricLevel.values.addLast(values); } else { if (logger.isTraceEnabled()) { logger.trace( "Adding to level {} entry at {} for {}", new Object[] {level, metric.changeTime, metric}); } values.append(metric.encodeValue(metricLevel)); } metricLevel.lastValue = metric.getObject(); metricLevel.lastTime = metric.changeTime; }