public void run() { for (Map.Entry<String, Sensor> sensorEntry : sensors.entrySet()) { // removeSensor also locks the sensor object. This is fine because synchronized is reentrant // There is however a minor race condition here. Assume we have a parent sensor P and child sensor C. // Calling record on C would cause a record on P as well. // So expiration time for P == expiration time for C. If the record on P happens via C just after P is removed, // that will cause C to also get removed. // Since the expiration time is typically high it is not expected to be a significant concern // and thus not necessary to optimize synchronized (sensorEntry.getValue()) { if (sensorEntry.getValue().hasExpired()) { log.debug("Removing expired sensor {}", sensorEntry.getKey()); removeSensor(sensorEntry.getKey()); } } } } }
/** * Register a metric with this sensor * * @param metricName The name of the metric * @param stat The statistic to keep * @param config A special configuration for this metric. If null use the sensor default configuration. * @return true if metric is added to sensor, false if sensor is expired */ public synchronized boolean add(final MetricName metricName, final MeasurableStat stat, final MetricConfig config) { if (hasExpired()) { return false; } else if (metrics.containsKey(metricName)) { return true; } else { final KafkaMetric metric = new KafkaMetric( metricLock(), Utils.notNull(metricName), Utils.notNull(stat), config == null ? this.config : config, time ); registry.registerMetric(metric); metrics.put(metric.metricName(), metric); stats.add(stat); return true; } }
/** * Register a compound statistic with this sensor which yields multiple measurable quantities (like a histogram) * @param stat The stat to register * @param config The configuration for this stat. If null then the stat will use the default configuration for this * sensor. * @return true if stat is added to sensor, false if sensor is expired */ public synchronized boolean add(CompoundStat stat, MetricConfig config) { if (hasExpired()) return false; this.stats.add(Utils.notNull(stat)); Object lock = metricLock(); for (NamedMeasurable m : stat.stats()) { final KafkaMetric metric = new KafkaMetric(lock, m.name(), m.stat(), config == null ? this.config : config, time); if (!metrics.containsKey(metric.metricName())) { registry.registerMetric(metric); metrics.put(metric.metricName(), metric); } } return true; }