This is an automated email from the ASF dual-hosted git repository. chaow pushed a commit to branch feature/metric2021 in repository https://gitbox.apache.org/repos/asf/iotdb.git
commit e4c562aa53df6584dcb704edb4422de2de1873c9 Author: chaow <[email protected]> AuthorDate: Thu Feb 25 15:19:44 2021 +0800 add implements --- metrics/dropwizard-metrics/pom.xml | 27 ++ .../dropwizard/DropwizardMetricManager.java | 362 ++++++++++++++++++++ .../dropwizard/DropwizardMetricReporter.java | 93 ++++++ .../iotdb/metrics/dropwizard/MetricName.java | 116 +++++++ .../dropwizard/type/DropwizardCounter.java} | 15 +- .../metrics/dropwizard/type/DropwizardGauge.java | 62 ++++ .../dropwizard/type/DropwizardHistogram.java} | 30 +- .../type/DropwizardHistogramSnapshot.java | 73 ++++ .../metrics/dropwizard/type/DropwizardRate.java | 95 ++++++ .../metrics/dropwizard/type/DropwizardTimer.java} | 29 +- .../org.apache.iotdb.metrics.MetricManager | 18 + .../org.apache.iotdb.metrics.MetricReporter | 18 + .../org/apache/iotdb/metrics/MetricManager.java | 48 ++- .../org/apache/iotdb/metrics/MetricReporter.java | 2 +- .../org/apache/iotdb/metrics/MetricService.java | 55 +-- .../apache/iotdb/metrics/config/MetricConfig.java | 125 +++++++ .../metrics/config/MetricConfigDescriptor.java | 132 ++++++++ .../MetricConstant.java} | 10 +- .../iotdb/metrics/impl/DoNothingMetricManager.java | 29 +- .../iotdb/metrics/type/HistogramSnapshot.java | 2 - .../java/org/apache/iotdb/metrics/type/Timer.java | 7 +- .../ReporterType.java} | 37 ++- metrics/micrometer-metrics/pom.xml | 10 + .../iotdb/metrics/micrometer/MeterIdUtils.java} | 22 +- .../micrometer/MicrometerMetricFactory.java | 98 ------ .../micrometer/MicrometerMetricManager.java | 367 +++++++++++++++++++-- .../micrometer/MicrometerMetricReporter.java | 63 +++- .../metrics/micrometer/type/MicrometerCounter.java | 3 +- .../metrics/micrometer/type/MicrometerGauge.java} | 35 +- ...ometerCounter.java => MicrometerHistogram.java} | 28 +- .../type/MicrometerHistogramSnapshot.java | 91 +++++ .../metrics/micrometer/type/MicrometerRate.java | 81 +++++ ...MicrometerCounter.java => MicrometerTimer.java} | 32 +- ...otdb.metrics.micrometer.MicrometerMetricFactory | 1 - ...tdb.metrics.micrometer.MicrometerMetricReporter | 1 - .../org.apache.iotdb.metrics.MetricManager | 18 + .../org.apache.iotdb.metrics.MetricReporter | 18 + metrics/pom.xml | 2 +- server/pom.xml | 10 + .../resources/conf/iotdb-metric.properties | 30 ++ .../engine/storagegroup/StorageGroupProcessor.java | 36 ++ .../apache/iotdb/db/qp/executor/PlanExecutor.java | 25 ++ .../java/org/apache/iotdb/db/service/IoTDB.java | 5 +- .../org/apache/iotdb/db/service/TSServiceImpl.java | 41 ++- 44 files changed, 2092 insertions(+), 310 deletions(-) diff --git a/metrics/dropwizard-metrics/pom.xml b/metrics/dropwizard-metrics/pom.xml new file mode 100644 index 0000000..5779fae --- /dev/null +++ b/metrics/dropwizard-metrics/pom.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <artifactId>iotdb-metrics</artifactId> + <groupId>org.apache.iotdb</groupId> + <version>0.12.0-SNAPSHOT</version> + </parent> + <modelVersion>4.0.0</modelVersion> + <artifactId>dropwizard-metric</artifactId> + <dependencies> + <dependency> + <groupId>org.apache.iotdb</groupId> + <artifactId>metrics-interface</artifactId> + <version>0.12.0-SNAPSHOT</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>io.dropwizard.metrics</groupId> + <artifactId>metrics-core</artifactId> + <version>4.1.2</version> + </dependency> + <dependency> + <groupId>io.dropwizard.metrics</groupId> + <artifactId>metrics-jvm</artifactId> + </dependency> + </dependencies> +</project> diff --git a/metrics/dropwizard-metrics/src/main/java/org/apache/iotdb/metrics/dropwizard/DropwizardMetricManager.java b/metrics/dropwizard-metrics/src/main/java/org/apache/iotdb/metrics/dropwizard/DropwizardMetricManager.java new file mode 100644 index 0000000..1f34053 --- /dev/null +++ b/metrics/dropwizard-metrics/src/main/java/org/apache/iotdb/metrics/dropwizard/DropwizardMetricManager.java @@ -0,0 +1,362 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.iotdb.metrics.dropwizard; + +import org.apache.iotdb.metrics.KnownMetric; +import org.apache.iotdb.metrics.MetricManager; +import org.apache.iotdb.metrics.config.MetricConfig; +import org.apache.iotdb.metrics.config.MetricConfigDescriptor; +import org.apache.iotdb.metrics.dropwizard.type.DropwizardCounter; +import org.apache.iotdb.metrics.dropwizard.type.DropwizardGauge; +import org.apache.iotdb.metrics.dropwizard.type.DropwizardHistogram; +import org.apache.iotdb.metrics.dropwizard.type.DropwizardRate; +import org.apache.iotdb.metrics.dropwizard.type.DropwizardTimer; +import org.apache.iotdb.metrics.type.Counter; +import org.apache.iotdb.metrics.type.Gauge; +import org.apache.iotdb.metrics.type.Histogram; +import org.apache.iotdb.metrics.type.IMetric; +import org.apache.iotdb.metrics.type.Rate; +import org.apache.iotdb.metrics.type.Timer; + +import com.codahale.metrics.JvmAttributeGaugeSet; +import com.codahale.metrics.MetricRegistry; +import com.codahale.metrics.jvm.BufferPoolMetricSet; +import com.codahale.metrics.jvm.CachedThreadStatesGaugeSet; +import com.codahale.metrics.jvm.ClassLoadingGaugeSet; +import com.codahale.metrics.jvm.GarbageCollectorMetricSet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.management.ManagementFactory; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; + +public class DropwizardMetricManager implements MetricManager { + + private static final Logger logger = LoggerFactory.getLogger(DropwizardMetricManager.class); + + Map<MetricName, IMetric> currentMeters; + boolean isEnable; + + com.codahale.metrics.MetricRegistry metricRegistry; + MetricConfig metricConfig = MetricConfigDescriptor.getInstance().getMetricConfig(); + + public DropwizardMetricManager() { + metricRegistry = new MetricRegistry(); + isEnable = metricConfig.isEnabled(); + currentMeters = new ConcurrentHashMap<>(); + } + + @Override + public Counter counter(String metric, String... tags) { + if (!isEnable) { + return null; + } + MetricName name = new MetricName(metric, tags); + return (Counter) + currentMeters.computeIfAbsent( + name, key -> new DropwizardCounter(metricRegistry.counter(name.toFlatString()))); + } + + @Override + public Gauge gauge(String metric, String... tags) { + if (!isEnable) { + return null; + } + MetricName name = new MetricName(metric, tags); + return (Gauge) + currentMeters.computeIfAbsent( + name, + key -> { + DropwizardGauge dropwizardGauge = new DropwizardGauge(); + metricRegistry.register( + name.toFlatString(), dropwizardGauge.getDropwizardCachedGauge()); + return dropwizardGauge; + }); + } + + @Override + public Histogram histogram(String metric, String... tags) { + if (!isEnable) { + return null; + } + MetricName name = new MetricName(metric, tags); + return (Histogram) + currentMeters.computeIfAbsent( + name, key -> new DropwizardHistogram(metricRegistry.histogram(name.toFlatString()))); + } + + @Override + public Rate rate(String metric, String... tags) { + if (!isEnable) { + return null; + } + MetricName name = new MetricName(metric, tags); + return (Rate) + currentMeters.computeIfAbsent( + name, key -> new DropwizardRate(metricRegistry.meter(name.toFlatString()))); + } + + @Override + public Timer timer(String metric, String... tags) { + if (!isEnable) { + return null; + } + MetricName name = new MetricName(metric, tags); + return (Timer) + currentMeters.computeIfAbsent( + name, key -> new DropwizardTimer(metricRegistry.timer(name.toFlatString()))); + } + + @Override + public void count(int delta, String metric, String... tags) { + if (!isEnable) { + return; + } + MetricName name = new MetricName(metric, tags); + ((Counter) + currentMeters.computeIfAbsent( + name, key -> new DropwizardCounter(metricRegistry.counter(name.toFlatString())))) + .inc(delta); + } + + @Override + public void count(long delta, String metric, String... tags) { + if (!isEnable) { + return; + } + MetricName name = new MetricName(metric, tags); + ((Counter) + currentMeters.computeIfAbsent( + name, key -> new DropwizardCounter(metricRegistry.counter(name.toFlatString())))) + .inc(delta); + } + + @Override + public void histogram(int value, String metric, String... tags) { + if (!isEnable) { + return; + } + MetricName name = new MetricName(metric, tags); + ((Histogram) + currentMeters.computeIfAbsent( + name, + key -> new DropwizardHistogram(metricRegistry.histogram(name.toFlatString())))) + .update(value); + } + + @Override + public void histogram(long value, String metric, String... tags) { + if (!isEnable) { + return; + } + MetricName name = new MetricName(metric, tags); + ((Histogram) + currentMeters.computeIfAbsent( + name, + key -> new DropwizardHistogram(metricRegistry.histogram(name.toFlatString())))) + .update(value); + } + + @Override + public void gauge(int value, String metric, String... tags) { + if (!isEnable) { + return; + } + MetricName name = new MetricName(metric, tags); + ((Gauge) + currentMeters.computeIfAbsent( + name, + key -> { + DropwizardGauge dropwizardGauge = new DropwizardGauge(); + metricRegistry.register( + name.toFlatString(), dropwizardGauge.getDropwizardCachedGauge()); + return dropwizardGauge; + })) + .set(value); + } + + @Override + public void gauge(long value, String metric, String... tags) { + if (!isEnable) { + return; + } + MetricName name = new MetricName(metric, tags); + ((Gauge) + currentMeters.computeIfAbsent( + name, + key -> { + DropwizardGauge dropwizardGauge = new DropwizardGauge(); + metricRegistry.register( + name.toFlatString(), dropwizardGauge.getDropwizardCachedGauge()); + return dropwizardGauge; + })) + .set(value); + } + + @Override + public void rate(int value, String metric, String... tags) { + if (!isEnable) { + return; + } + MetricName name = new MetricName(metric, tags); + ((Rate) + currentMeters.computeIfAbsent( + name, key -> new DropwizardRate(metricRegistry.meter(name.toFlatString())))) + .mark(value); + } + + @Override + public void rate(long value, String metric, String... tags) { + if (!isEnable) { + return; + } + MetricName name = new MetricName(metric, tags); + ((Rate) + currentMeters.computeIfAbsent( + name, key -> new DropwizardRate(metricRegistry.meter(name.toFlatString())))) + .mark(value); + } + + @Override + public void timer(long delta, TimeUnit timeUnit, String metric, String... tags) { + if (!isEnable) { + return; + } + MetricName name = new MetricName(metric, tags); + ((Timer) + currentMeters.computeIfAbsent( + name, key -> new DropwizardTimer(metricRegistry.timer(name.toFlatString())))) + .update(delta, timeUnit); + } + + @Override + public List<String[]> getAllMetricKeys() { + if (!isEnable) { + return Collections.emptyList(); + } + List<String[]> keys = new ArrayList<>(currentMeters.size()); + currentMeters.keySet().forEach(k -> keys.add(k.toStringArray())); + return keys; + } + + @Override + public Map<String[], Counter> getAllCounters() { + Map<String[], Counter> counterMap = new HashMap<>(); + for (Map.Entry<MetricName, IMetric> entry : currentMeters.entrySet()) { + if (entry.getValue() instanceof Counter) { + counterMap.put(entry.getKey().toStringArray(), (Counter) entry.getValue()); + } + } + return counterMap; + } + + @Override + public Map<String[], Gauge> getAllGauges() { + Map<String[], Gauge> gaugeMap = new HashMap<>(); + for (Map.Entry<MetricName, IMetric> entry : currentMeters.entrySet()) { + if (entry.getValue() instanceof Gauge) { + gaugeMap.put(entry.getKey().toStringArray(), (Gauge) entry.getValue()); + } + } + return gaugeMap; + } + + @Override + public Map<String[], Rate> getAllRates() { + Map<String[], Rate> rateMap = new HashMap<>(); + for (Map.Entry<MetricName, IMetric> entry : currentMeters.entrySet()) { + if (entry.getValue() instanceof Rate) { + rateMap.put(entry.getKey().toStringArray(), (Rate) entry.getValue()); + } + } + return rateMap; + } + + @Override + public Map<String[], Histogram> getAllHistograms() { + Map<String[], Histogram> histogramMap = new HashMap<>(); + for (Map.Entry<MetricName, IMetric> entry : currentMeters.entrySet()) { + if (entry.getValue() instanceof Histogram) { + histogramMap.put(entry.getKey().toStringArray(), (Histogram) entry.getValue()); + } + } + return histogramMap; + } + + @Override + public Map<String[], Timer> getAllTimers() { + Map<String[], Timer> timerMap = new HashMap<>(); + for (Map.Entry<MetricName, IMetric> entry : currentMeters.entrySet()) { + if (entry.getValue() instanceof Timer) { + timerMap.put(entry.getKey().toStringArray(), (Timer) entry.getValue()); + } + } + return timerMap; + } + + @Override + public boolean isEnable() { + return isEnable; + } + + @Override + public void enableKnownMetric(KnownMetric metric) { + if (!isEnable) { + return; + } + switch (metric) { + case JVM: + enableJVMMetrics(); + break; + case SYSTEM: + break; + case THREAD: + break; + default: + // ignore; + } + } + + public MetricRegistry getMetricRegistry() { + return metricRegistry; + } + + private void enableJVMMetrics() { + if (!isEnable) { + return; + } + metricRegistry.registerAll(new JvmAttributeGaugeSet()); + metricRegistry.registerAll(new GarbageCollectorMetricSet()); + metricRegistry.registerAll(new ClassLoadingGaugeSet()); + metricRegistry.registerAll(new BufferPoolMetricSet(ManagementFactory.getPlatformMBeanServer())); + metricRegistry.registerAll(new CachedThreadStatesGaugeSet(5, TimeUnit.MILLISECONDS)); + } + + @Override + public boolean init() { + return true; + } +} diff --git a/metrics/dropwizard-metrics/src/main/java/org/apache/iotdb/metrics/dropwizard/DropwizardMetricReporter.java b/metrics/dropwizard-metrics/src/main/java/org/apache/iotdb/metrics/dropwizard/DropwizardMetricReporter.java new file mode 100644 index 0000000..235f9ad --- /dev/null +++ b/metrics/dropwizard-metrics/src/main/java/org/apache/iotdb/metrics/dropwizard/DropwizardMetricReporter.java @@ -0,0 +1,93 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.iotdb.metrics.dropwizard; + +import org.apache.iotdb.metrics.MetricManager; +import org.apache.iotdb.metrics.MetricReporter; +import org.apache.iotdb.metrics.config.MetricConfig; +import org.apache.iotdb.metrics.config.MetricConfigDescriptor; +import org.apache.iotdb.metrics.utils.ReporterType; + +import com.codahale.metrics.JmxReporter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; + +public class DropwizardMetricReporter implements MetricReporter { + private static Logger logger = LoggerFactory.getLogger(DropwizardMetricReporter.class); + private MetricManager dropwizardMetricManager; + private MetricConfig metricConfig = MetricConfigDescriptor.getInstance().getMetricConfig(); + + private JmxReporter jmxReporter; + + @Override + public boolean start() { + List<String> reporters = metricConfig.getReporterList(); + for (String reporter : reporters) { + switch (ReporterType.get(reporter)) { + case JMX: + { + jmxReporter = + JmxReporter.forRegistry( + ((DropwizardMetricManager) dropwizardMetricManager).getMetricRegistry()) + .build(); + startJmxReporter(jmxReporter); + } + break; + case IOTDB: + break; + case PROMETHEUS: + break; + default: + logger.warn("Dropwizard don't support reporter type {}", reporter); + } + } + return false; + } + + private void startJmxReporter(JmxReporter jmxReporter) { + jmxReporter.start(); + } + + @Override + public void setMetricManager(MetricManager metricManager) { + dropwizardMetricManager = metricManager; + } + + @Override + public boolean stop() { + List<String> reporters = metricConfig.getReporterList(); + for (String reporter : reporters) { + switch (ReporterType.get(reporter)) { + case JMX: + jmxReporter.stop(); + break; + case IOTDB: + break; + case PROMETHEUS: + break; + default: + logger.warn("Dropwizard don't support reporter type {}", reporter); + } + } + return true; + } +} diff --git a/metrics/dropwizard-metrics/src/main/java/org/apache/iotdb/metrics/dropwizard/MetricName.java b/metrics/dropwizard-metrics/src/main/java/org/apache/iotdb/metrics/dropwizard/MetricName.java new file mode 100644 index 0000000..d214463 --- /dev/null +++ b/metrics/dropwizard-metrics/src/main/java/org/apache/iotdb/metrics/dropwizard/MetricName.java @@ -0,0 +1,116 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.iotdb.metrics.dropwizard; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +public class MetricName { + public static final String SEPARATOR = "."; + public static final Map<String, String> EMPTY_TAGS = Collections.emptyMap(); + + public String name; + public Map<String, String> tags; + + public MetricName(String name, String... tags) { + this.name = name; + this.tags = new HashMap<>(); + for (int i = 0; i < tags.length; i++) { + this.tags.put(tags[i], tags[i + 1]); + i += 2; + } + } + + public MetricName(String name, Map<String, String> tags) { + this.name = name; + this.tags = tags; + } + + public String toFlatString() { + StringBuilder stringBuilder = new StringBuilder(name); + tags.forEach((k, v) -> stringBuilder.append(k).append(SEPARATOR).append(v)); + return stringBuilder.toString().replace(" ", "_"); + } + + public String[] toStringArray() { + List<String> allNames = new ArrayList<>(); + allNames.add(name); + tags.forEach( + (k, v) -> { + allNames.add(k); + allNames.add(v); + }); + return allNames.toArray(new String[0]); + } + + @Override + public String toString() { + return "MetricName{" + "name='" + name + '\'' + ", tags=" + tags + '}'; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Map<String, String> getTags() { + return tags; + } + + public void setTags(Map<String, String> tags) { + this.tags = tags; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof MetricName)) { + return false; + } + MetricName that = (MetricName) obj; + if (this.name != that.name) { + return false; + } + if (that.getTags().size() != this.tags.size()) { + return false; + } + Map<String, String> thatTags = that.getTags(); + for (Map.Entry<String, String> entry : this.tags.entrySet()) { + if (!thatTags.containsKey(entry.getKey())) { + return false; + } + if (!thatTags.get(entry.getKey()).equals(entry.getValue())) { + return false; + } + } + return true; + } + + @Override + public int hashCode() { + return Objects.hash(name, tags); + } +} diff --git a/metrics/micrometer-metrics/src/main/java/org/apache/iotdb/metrics/micrometer/type/MicrometerCounter.java b/metrics/dropwizard-metrics/src/main/java/org/apache/iotdb/metrics/dropwizard/type/DropwizardCounter.java similarity index 76% copy from metrics/micrometer-metrics/src/main/java/org/apache/iotdb/metrics/micrometer/type/MicrometerCounter.java copy to metrics/dropwizard-metrics/src/main/java/org/apache/iotdb/metrics/dropwizard/type/DropwizardCounter.java index 9fbfa6f..3261ed2 100644 --- a/metrics/micrometer-metrics/src/main/java/org/apache/iotdb/metrics/micrometer/type/MicrometerCounter.java +++ b/metrics/dropwizard-metrics/src/main/java/org/apache/iotdb/metrics/dropwizard/type/DropwizardCounter.java @@ -17,30 +17,29 @@ * under the License. */ -package org.apache.iotdb.metrics.micrometer.type; +package org.apache.iotdb.metrics.dropwizard.type; import org.apache.iotdb.metrics.type.Counter; -public class MicrometerCounter implements Counter { +public class DropwizardCounter implements Counter { + com.codahale.metrics.Counter counter; - public MicrometerCounter(io.micrometer.core.instrument.Counter counter) { + public DropwizardCounter(com.codahale.metrics.Counter counter) { this.counter = counter; } - io.micrometer.core.instrument.Counter counter; - @Override public void inc() { - counter.increment(); + counter.inc(); } @Override public void inc(long n) { - counter.increment(n); + counter.inc(n); } @Override public long count() { - return (long) counter.count(); + return counter.getCount(); } } diff --git a/metrics/dropwizard-metrics/src/main/java/org/apache/iotdb/metrics/dropwizard/type/DropwizardGauge.java b/metrics/dropwizard-metrics/src/main/java/org/apache/iotdb/metrics/dropwizard/type/DropwizardGauge.java new file mode 100644 index 0000000..c7175f5 --- /dev/null +++ b/metrics/dropwizard-metrics/src/main/java/org/apache/iotdb/metrics/dropwizard/type/DropwizardGauge.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.iotdb.metrics.dropwizard.type; + +import org.apache.iotdb.metrics.type.Gauge; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; + +public class DropwizardGauge implements Gauge { + + AtomicLong atomicLong; + DropwizardCachedGauge dropwizardCachedGauge; + + public DropwizardGauge() { + atomicLong = new AtomicLong(0); + dropwizardCachedGauge = new DropwizardCachedGauge(5, TimeUnit.MILLISECONDS); + } + + public class DropwizardCachedGauge extends com.codahale.metrics.CachedGauge<Long> { + + protected DropwizardCachedGauge(long timeout, TimeUnit timeoutUnit) { + super(timeout, timeoutUnit); + } + + @Override + protected Long loadValue() { + return atomicLong.get(); + } + } + + @Override + public long value() { + return dropwizardCachedGauge.getValue(); + } + + @Override + public void set(long value) { + atomicLong.set(value); + } + + public com.codahale.metrics.Gauge getDropwizardCachedGauge() { + return dropwizardCachedGauge; + } +} diff --git a/metrics/micrometer-metrics/src/main/java/org/apache/iotdb/metrics/micrometer/type/MicrometerCounter.java b/metrics/dropwizard-metrics/src/main/java/org/apache/iotdb/metrics/dropwizard/type/DropwizardHistogram.java similarity index 58% copy from metrics/micrometer-metrics/src/main/java/org/apache/iotdb/metrics/micrometer/type/MicrometerCounter.java copy to metrics/dropwizard-metrics/src/main/java/org/apache/iotdb/metrics/dropwizard/type/DropwizardHistogram.java index 9fbfa6f..edf5f2b 100644 --- a/metrics/micrometer-metrics/src/main/java/org/apache/iotdb/metrics/micrometer/type/MicrometerCounter.java +++ b/metrics/dropwizard-metrics/src/main/java/org/apache/iotdb/metrics/dropwizard/type/DropwizardHistogram.java @@ -17,30 +17,36 @@ * under the License. */ -package org.apache.iotdb.metrics.micrometer.type; +package org.apache.iotdb.metrics.dropwizard.type; -import org.apache.iotdb.metrics.type.Counter; +import org.apache.iotdb.metrics.type.Histogram; +import org.apache.iotdb.metrics.type.HistogramSnapshot; -public class MicrometerCounter implements Counter { +public class DropwizardHistogram implements Histogram { - public MicrometerCounter(io.micrometer.core.instrument.Counter counter) { - this.counter = counter; - } + com.codahale.metrics.Histogram histogram; - io.micrometer.core.instrument.Counter counter; + public DropwizardHistogram(com.codahale.metrics.Histogram histogram) { + this.histogram = histogram; + } @Override - public void inc() { - counter.increment(); + public void update(int value) { + histogram.update(value); } @Override - public void inc(long n) { - counter.increment(n); + public void update(long value) { + histogram.update(value); } @Override public long count() { - return (long) counter.count(); + return histogram.getCount(); + } + + @Override + public HistogramSnapshot takeSnapshot() { + return new DropwizardHistogramSnapshot(histogram.getSnapshot()); } } diff --git a/metrics/dropwizard-metrics/src/main/java/org/apache/iotdb/metrics/dropwizard/type/DropwizardHistogramSnapshot.java b/metrics/dropwizard-metrics/src/main/java/org/apache/iotdb/metrics/dropwizard/type/DropwizardHistogramSnapshot.java new file mode 100644 index 0000000..0fe3a9c --- /dev/null +++ b/metrics/dropwizard-metrics/src/main/java/org/apache/iotdb/metrics/dropwizard/type/DropwizardHistogramSnapshot.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.iotdb.metrics.dropwizard.type; + +import org.apache.iotdb.metrics.type.HistogramSnapshot; + +import java.io.OutputStream; + +public class DropwizardHistogramSnapshot implements HistogramSnapshot { + + com.codahale.metrics.Snapshot snapshot; + + public DropwizardHistogramSnapshot(com.codahale.metrics.Snapshot snapshot) { + this.snapshot = snapshot; + } + + @Override + public double getValue(double quantile) { + return snapshot.getValue(quantile); + } + + @Override + public long[] getValues() { + return snapshot.getValues(); + } + + @Override + public int size() { + return snapshot.size(); + } + + @Override + public double getMedian() { + return snapshot.getMedian(); + } + + @Override + public long getMax() { + return snapshot.getMax(); + } + + @Override + public double getMean() { + return snapshot.getMean(); + } + + @Override + public long getMin() { + return snapshot.getMin(); + } + + @Override + public void dump(OutputStream output) { + snapshot.dump(output); + } +} diff --git a/metrics/dropwizard-metrics/src/main/java/org/apache/iotdb/metrics/dropwizard/type/DropwizardRate.java b/metrics/dropwizard-metrics/src/main/java/org/apache/iotdb/metrics/dropwizard/type/DropwizardRate.java new file mode 100644 index 0000000..8be1309 --- /dev/null +++ b/metrics/dropwizard-metrics/src/main/java/org/apache/iotdb/metrics/dropwizard/type/DropwizardRate.java @@ -0,0 +1,95 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.iotdb.metrics.dropwizard.type; + +import org.apache.iotdb.metrics.type.Rate; + +import com.codahale.metrics.Meter; + +public class DropwizardRate implements Rate { + + Meter meter; + // read-only meter + com.codahale.metrics.Timer timer; + + public DropwizardRate(Meter meter) { + this.meter = meter; + this.timer = null; + } + + public DropwizardRate(com.codahale.metrics.Timer timer) { + this.timer = timer; + this.meter = null; + } + + @Override + public long getCount() { + if (meter != null) { + return meter.getCount(); + } + return timer.getCount(); + } + + @Override + public double getOneMinuteRate() { + if (meter != null) { + return meter.getOneMinuteRate(); + } + return timer.getOneMinuteRate(); + } + + @Override + public double getMeanRate() { + if (meter != null) { + return meter.getMeanRate(); + } + return timer.getMeanRate(); + } + + @Override + public double getFiveMinuteRate() { + if (meter != null) { + return meter.getFiveMinuteRate(); + } + return timer.getFiveMinuteRate(); + } + + @Override + public double getFifteenMinuteRate() { + if (meter != null) { + return meter.getFifteenMinuteRate(); + } + return timer.getFifteenMinuteRate(); + } + + @Override + public void mark() { + if (meter != null) { + meter.mark(); + } + } + + @Override + public void mark(long n) { + if (meter != null) { + meter.mark(n); + } + } +} diff --git a/metrics/micrometer-metrics/src/main/java/org/apache/iotdb/metrics/micrometer/type/MicrometerCounter.java b/metrics/dropwizard-metrics/src/main/java/org/apache/iotdb/metrics/dropwizard/type/DropwizardTimer.java similarity index 56% copy from metrics/micrometer-metrics/src/main/java/org/apache/iotdb/metrics/micrometer/type/MicrometerCounter.java copy to metrics/dropwizard-metrics/src/main/java/org/apache/iotdb/metrics/dropwizard/type/DropwizardTimer.java index 9fbfa6f..24a0849 100644 --- a/metrics/micrometer-metrics/src/main/java/org/apache/iotdb/metrics/micrometer/type/MicrometerCounter.java +++ b/metrics/dropwizard-metrics/src/main/java/org/apache/iotdb/metrics/dropwizard/type/DropwizardTimer.java @@ -17,30 +17,33 @@ * under the License. */ -package org.apache.iotdb.metrics.micrometer.type; +package org.apache.iotdb.metrics.dropwizard.type; -import org.apache.iotdb.metrics.type.Counter; +import org.apache.iotdb.metrics.type.HistogramSnapshot; +import org.apache.iotdb.metrics.type.Rate; +import org.apache.iotdb.metrics.type.Timer; -public class MicrometerCounter implements Counter { +import java.util.concurrent.TimeUnit; - public MicrometerCounter(io.micrometer.core.instrument.Counter counter) { - this.counter = counter; - } +public class DropwizardTimer implements Timer { + com.codahale.metrics.Timer timer; - io.micrometer.core.instrument.Counter counter; + public DropwizardTimer(com.codahale.metrics.Timer timer) { + this.timer = timer; + } @Override - public void inc() { - counter.increment(); + public void update(long duration, TimeUnit unit) { + timer.update(duration, unit); } @Override - public void inc(long n) { - counter.increment(n); + public HistogramSnapshot takeSnapshot() { + return new DropwizardHistogramSnapshot(timer.getSnapshot()); } @Override - public long count() { - return (long) counter.count(); + public Rate getImmutableRate() { + return new DropwizardRate(timer); } } diff --git a/metrics/dropwizard-metrics/src/main/resources/META-INF/services/org.apache.iotdb.metrics.MetricManager b/metrics/dropwizard-metrics/src/main/resources/META-INF/services/org.apache.iotdb.metrics.MetricManager new file mode 100644 index 0000000..b606911 --- /dev/null +++ b/metrics/dropwizard-metrics/src/main/resources/META-INF/services/org.apache.iotdb.metrics.MetricManager @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +org.apache.iotdb.metrics.dropwizard.DropwizardMetricManager \ No newline at end of file diff --git a/metrics/dropwizard-metrics/src/main/resources/META-INF/services/org.apache.iotdb.metrics.MetricReporter b/metrics/dropwizard-metrics/src/main/resources/META-INF/services/org.apache.iotdb.metrics.MetricReporter new file mode 100644 index 0000000..1ac1d1e --- /dev/null +++ b/metrics/dropwizard-metrics/src/main/resources/META-INF/services/org.apache.iotdb.metrics.MetricReporter @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +org.apache.iotdb.metrics.dropwizard.DropwizardMetricReporter \ No newline at end of file diff --git a/metrics/interface/src/main/java/org/apache/iotdb/metrics/MetricManager.java b/metrics/interface/src/main/java/org/apache/iotdb/metrics/MetricManager.java index d61bdb7..8add6ed 100644 --- a/metrics/interface/src/main/java/org/apache/iotdb/metrics/MetricManager.java +++ b/metrics/interface/src/main/java/org/apache/iotdb/metrics/MetricManager.java @@ -24,11 +24,17 @@ import org.apache.iotdb.metrics.type.Histogram; import org.apache.iotdb.metrics.type.Rate; import org.apache.iotdb.metrics.type.Timer; +import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; public interface MetricManager { - + /* + * The following functions will create or get a exist Metric + * @param metric: the metric name + * @param tags: string appear in pairs, like sg="ln",user="user1" will be "sg", "ln", "user", "user1" + * @return Metric Instance + */ Counter counter(String metric, String... tags); Gauge gauge(String metric, String... tags); @@ -39,7 +45,13 @@ public interface MetricManager { Timer timer(String metric, String... tags); - // metric.counter(5, "insertRecords","interface","insertRecords","sg","sg1"); + /* + * The following functions just update the current record value + * @param the delta value will be recorded + * @param metric the metric name + * @param tags string appear in pairs, like sg="ln",user="user1" will be "sg", "ln", "user", "user1" + */ + void count(int delta, String metric, String... tags); void count(long delta, String metric, String... tags); @@ -52,26 +64,40 @@ public interface MetricManager { void gauge(long value, String metric, String... tags); - void meter(int value, String metric, String... tags); + void rate(int value, String metric, String... tags); - void meter(long value, String metric, String... tags); + void rate(long value, String metric, String... tags); void timer(long delta, TimeUnit timeUnit, String metric, String... tags); - void timerStart(String metric, String... tags); - - void timerEnd(String metric, String... tags); + /** @return all MetricKeys, key is metric name, value is tags, which is a string array */ + List<String[]> getAllMetricKeys(); - Map<String, String[]> getAllMetricKeys(); - - // key is name + tags + // key is name + tags, value Map<String[], Counter> getAllCounters(); Map<String[], Gauge> getAllGauges(); - Map<String[], Rate> getAllMeters(); + Map<String[], Rate> getAllRates(); Map<String[], Histogram> getAllHistograms(); Map<String[], Timer> getAllTimers(); + + /** @return whether enable metricService */ + boolean isEnable(); + + /** + * enable pre-defined metric set + * + * @param metric which metric set we want to collect + */ + void enableKnownMetric(KnownMetric metric); + + /** + * init something + * + * @return + */ + boolean init(); } diff --git a/metrics/interface/src/main/java/org/apache/iotdb/metrics/MetricReporter.java b/metrics/interface/src/main/java/org/apache/iotdb/metrics/MetricReporter.java index a1af228..023f0fe 100644 --- a/metrics/interface/src/main/java/org/apache/iotdb/metrics/MetricReporter.java +++ b/metrics/interface/src/main/java/org/apache/iotdb/metrics/MetricReporter.java @@ -21,7 +21,7 @@ package org.apache.iotdb.metrics; public interface MetricReporter { boolean start(); - void setMetricFactory(MetricFactory metricFactory); + void setMetricManager(MetricManager metricManager); boolean stop(); } diff --git a/metrics/interface/src/main/java/org/apache/iotdb/metrics/MetricService.java b/metrics/interface/src/main/java/org/apache/iotdb/metrics/MetricService.java index 50b0d7d..8e1af33 100644 --- a/metrics/interface/src/main/java/org/apache/iotdb/metrics/MetricService.java +++ b/metrics/interface/src/main/java/org/apache/iotdb/metrics/MetricService.java @@ -18,55 +18,65 @@ */ package org.apache.iotdb.metrics; -import org.apache.iotdb.metrics.impl.DoNothingFactory; +import org.apache.iotdb.metrics.impl.DoNothingMetricManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.List; -import java.util.Map; import java.util.ServiceLoader; -/** MetricService is the entr */ +/** MetricService is the entry to manage all Metric system */ public class MetricService { private static final Logger logger = LoggerFactory.getLogger(MetricService.class); private static final List<MetricReporter> reporters = new ArrayList<>(); - private static MetricFactory factory; - static { init(); } - private static void init() { + private static final MetricService INSTANCE = new MetricService(); + + private static MetricManager metricManager; + + public static MetricService getINSTANCE() { + return INSTANCE; + } - ServiceLoader<MetricFactory> metricFactories = ServiceLoader.load(MetricFactory.class); + private MetricService() {} + + private static void init() { + logger.debug("init metric service"); + ServiceLoader<MetricManager> metricManagers = ServiceLoader.load(MetricManager.class); int size = 0; - MetricFactory nothingFactory = null; + MetricManager nothingManager = new DoNothingMetricManager(); - for (MetricFactory mf : metricFactories) { - if (mf instanceof DoNothingFactory) { - nothingFactory = mf; + for (MetricManager mf : metricManagers) { + if (mf instanceof DoNothingMetricManager) { + nothingManager = mf; continue; } size++; - factory = mf; + metricManager = mf; } - // if no more implementation, we use nothingFactory. + // if no more implementations, we use nothingFactory. if (size == 0) { - factory = nothingFactory; + metricManager = nothingManager; } else if (size > 1) { - logger.warn("detect more than one MetricFactory, will use {}", factory.getClass().getName()); + logger.warn( + "detect more than one MetricManager, will use {}", metricManager.getClass().getName()); } + // do some init work + metricManager.init(); ServiceLoader<MetricReporter> reporter = ServiceLoader.load(MetricReporter.class); for (MetricReporter r : reporter) { reporters.add(r); - r.setMetricFactory(factory); + r.setMetricManager(metricManager); r.start(); logger.info("detect MetricReporter {}", r.getClass().getName()); } @@ -74,23 +84,20 @@ public class MetricService { public static void stop() { for (MetricReporter r : reporters) { + logger.info("detect MetricReporter {}", r.getClass().getName()); r.stop(); } } - public static MetricManager getMetric(String namespace) { - return factory.getMetric(namespace); + public static MetricManager getMetricManager() { + return metricManager; } public static void enableKnownMetric(KnownMetric metric) { - factory.enableKnownMetric(metric); - } - - public static Map<String, MetricManager> getAllMetrics() { - return factory.getAllMetrics(); + metricManager.enableKnownMetric(metric); } public static boolean isEnable() { - return factory.isEnable(); + return metricManager.isEnable(); } } diff --git a/metrics/interface/src/main/java/org/apache/iotdb/metrics/config/MetricConfig.java b/metrics/interface/src/main/java/org/apache/iotdb/metrics/config/MetricConfig.java new file mode 100644 index 0000000..fd40973 --- /dev/null +++ b/metrics/interface/src/main/java/org/apache/iotdb/metrics/config/MetricConfig.java @@ -0,0 +1,125 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.iotdb.metrics.config; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Arrays; +import java.util.List; + +public class MetricConfig { + private static final Logger logger = LoggerFactory.getLogger(MetricConfig.class); + static final String CONFIG_NAME = "iotdb-metric.properties"; + + /** The period of data pushed by the reporter to the remote monitoring system */ + private int pushPeriodInSecond = 5; + + /** enable publishing data */ + private boolean isEnabled = true; + + /** provide or push metric data to remote system, could be jmx, prometheus, iotdb, etc. */ + private List<String> reporterList = + Arrays.asList("jmx", "prometheus"); // Collections.singletonList("jmx"); + + // the following is prometheus related config + /** the http server's port for prometheus exporter to get metric data */ + private String prometheusExporterPort = "8090"; + + // the following is iotdb related config + + private String iotdbSg = "monitor"; + private String iotdbUser = "root"; + private String iotdbPasswd = "root"; + private String iotdbIp = "127.0.0.1"; + private String iotdbPort = "6667"; + + public int getPushPeriodInSecond() { + return pushPeriodInSecond; + } + + public void setPushPeriodInSecond(int pushPeriodInSecond) { + this.pushPeriodInSecond = pushPeriodInSecond; + } + + public boolean isEnabled() { + return isEnabled; + } + + public void setEnabled(boolean enabled) { + isEnabled = enabled; + } + + public String getPrometheusExporterPort() { + return prometheusExporterPort; + } + + public void setPrometheusExporterPort(String prometheusExporterPort) { + this.prometheusExporterPort = prometheusExporterPort; + } + + public List<String> getReporterList() { + return reporterList; + } + + public void setReporterList(List<String> reporterList) { + this.reporterList = reporterList; + } + + public String getIotdbSg() { + return iotdbSg; + } + + public void setIotdbSg(String iotdbSg) { + this.iotdbSg = iotdbSg; + } + + public String getIotdbUser() { + return iotdbUser; + } + + public void setIotdbUser(String iotdbUser) { + this.iotdbUser = iotdbUser; + } + + public String getIotdbPasswd() { + return iotdbPasswd; + } + + public void setIotdbPasswd(String iotdbPasswd) { + this.iotdbPasswd = iotdbPasswd; + } + + public String getIotdbIp() { + return iotdbIp; + } + + public void setIotdbIp(String iotdbIp) { + this.iotdbIp = iotdbIp; + } + + public String getIotdbPort() { + return iotdbPort; + } + + public void setIotdbPort(String iotdbPort) { + this.iotdbPort = iotdbPort; + } +} diff --git a/metrics/interface/src/main/java/org/apache/iotdb/metrics/config/MetricConfigDescriptor.java b/metrics/interface/src/main/java/org/apache/iotdb/metrics/config/MetricConfigDescriptor.java new file mode 100644 index 0000000..7990a24 --- /dev/null +++ b/metrics/interface/src/main/java/org/apache/iotdb/metrics/config/MetricConfigDescriptor.java @@ -0,0 +1,132 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.iotdb.metrics.config; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Properties; + +public class MetricConfigDescriptor { + private static final Logger logger = LoggerFactory.getLogger(MetricConfigDescriptor.class); + private final MetricConfig metricConfig = new MetricConfig(); + + public MetricConfig getMetricConfig() { + return metricConfig; + } + + private MetricConfigDescriptor() { + loadProps(); + } + + public static MetricConfigDescriptor getInstance() { + return MetricConfigDescriptorHolder.INSTANCE; + } + + public String getPropsUrl() { + String url = System.getProperty(MetricConstant.METRIC_CONF, null); + if (url == null) { + url = System.getProperty(MetricConstant.IOTDB_HOME, null); + if (url != null) { + url = url + File.separatorChar + "conf" + File.separatorChar + MetricConfig.CONFIG_NAME; + } else { + logger.warn( + "Cannot find IOTDB_HOME or METRIC_CONF environment variable when loading " + + "config file {}, use default configuration", + MetricConfig.CONFIG_NAME); + // update all data seriesPath + return null; + } + } else { + url += (File.separatorChar + MetricConfig.CONFIG_NAME); + } + return url; + } + + /** load an property file and set TsfileDBConfig variables. */ + private void loadProps() { + + String url = getPropsUrl(); + Properties properties = System.getProperties(); + if (url != null) { + try (InputStream inputStream = new FileInputStream(new File(url))) { + logger.info("Start to read config file {}", url); + properties.load(inputStream); + } catch (IOException e) { + logger.warn("Fail to find config file {}", url, e); + } + } + + metricConfig.setEnabled( + Boolean.parseBoolean( + properties.getProperty("enable_metric", Boolean.toString(metricConfig.isEnabled())))); + + String reporterList = properties.getProperty("metric_reporter_list"); + if (reporterList != null) { + metricConfig.setReporterList(getReporterList(reporterList)); + } + + metricConfig.setPushPeriodInSecond( + Integer.parseInt( + properties.getProperty( + "push_period_in_second", Integer.toString(metricConfig.getPushPeriodInSecond())))); + + metricConfig.setPrometheusExporterPort( + properties.getProperty( + "prometheus_exporter_port", metricConfig.getPrometheusExporterPort())); + + metricConfig.setIotdbIp(properties.getProperty("iotdb_ip", metricConfig.getIotdbIp())); + + metricConfig.setIotdbPort(properties.getProperty("iotdb_port", metricConfig.getIotdbPort())); + + metricConfig.setIotdbSg(properties.getProperty("iotdb_sg", metricConfig.getIotdbSg())); + metricConfig.setIotdbUser(properties.getProperty("iotdb_user", metricConfig.getIotdbUser())); + metricConfig.setIotdbPasswd( + properties.getProperty("iotdb_passwd", metricConfig.getIotdbPasswd())); + } + + private List<String> getReporterList(String reporterList) { + if (reporterList == null) { + return Collections.emptyList(); + } + List<String> reporters = new ArrayList<>(); + String[] split = reporterList.split(","); + for (String reporter : split) { + reporter = reporter.trim(); + if ("".equals(reporter)) { + continue; + } + reporters.add(reporter); + } + return reporters; + } + + private static class MetricConfigDescriptorHolder { + + private static final MetricConfigDescriptor INSTANCE = new MetricConfigDescriptor(); + } +} diff --git a/metrics/interface/src/main/java/org/apache/iotdb/metrics/MetricReporter.java b/metrics/interface/src/main/java/org/apache/iotdb/metrics/config/MetricConstant.java similarity index 82% copy from metrics/interface/src/main/java/org/apache/iotdb/metrics/MetricReporter.java copy to metrics/interface/src/main/java/org/apache/iotdb/metrics/config/MetricConstant.java index a1af228..9bbfd37 100644 --- a/metrics/interface/src/main/java/org/apache/iotdb/metrics/MetricReporter.java +++ b/metrics/interface/src/main/java/org/apache/iotdb/metrics/config/MetricConstant.java @@ -16,12 +16,10 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.iotdb.metrics; -public interface MetricReporter { - boolean start(); +package org.apache.iotdb.metrics.config; - void setMetricFactory(MetricFactory metricFactory); - - boolean stop(); +public class MetricConstant { + static final String METRIC_CONF = "METRIC_CONF"; + public static final String IOTDB_HOME = "IOTDB_HOME"; } diff --git a/metrics/interface/src/main/java/org/apache/iotdb/metrics/impl/DoNothingMetricManager.java b/metrics/interface/src/main/java/org/apache/iotdb/metrics/impl/DoNothingMetricManager.java index 5f0480c..6b46b34 100644 --- a/metrics/interface/src/main/java/org/apache/iotdb/metrics/impl/DoNothingMetricManager.java +++ b/metrics/interface/src/main/java/org/apache/iotdb/metrics/impl/DoNothingMetricManager.java @@ -18,6 +18,7 @@ */ package org.apache.iotdb.metrics.impl; +import org.apache.iotdb.metrics.KnownMetric; import org.apache.iotdb.metrics.MetricManager; import org.apache.iotdb.metrics.type.Counter; import org.apache.iotdb.metrics.type.Gauge; @@ -25,6 +26,7 @@ import org.apache.iotdb.metrics.type.Histogram; import org.apache.iotdb.metrics.type.Rate; import org.apache.iotdb.metrics.type.Timer; +import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; @@ -74,22 +76,16 @@ public class DoNothingMetricManager implements MetricManager { public void gauge(long value, String metric, String... tags) {} @Override - public void meter(int value, String metric, String... tags) {} + public void rate(int value, String metric, String... tags) {} @Override - public void meter(long value, String metric, String... tags) {} + public void rate(long value, String metric, String... tags) {} @Override public void timer(long delta, TimeUnit timeUnit, String metric, String... tags) {} @Override - public void timerStart(String metric, String... tags) {} - - @Override - public void timerEnd(String metric, String... tags) {} - - @Override - public Map<String, String[]> getAllMetricKeys() { + public List<String[]> getAllMetricKeys() { return null; } @@ -104,7 +100,7 @@ public class DoNothingMetricManager implements MetricManager { } @Override - public Map<String[], Rate> getAllMeters() { + public Map<String[], Rate> getAllRates() { return null; } @@ -117,4 +113,17 @@ public class DoNothingMetricManager implements MetricManager { public Map<String[], Timer> getAllTimers() { return null; } + + @Override + public boolean isEnable() { + return false; + } + + @Override + public void enableKnownMetric(KnownMetric metric) {} + + @Override + public boolean init() { + return false; + } } diff --git a/metrics/interface/src/main/java/org/apache/iotdb/metrics/type/HistogramSnapshot.java b/metrics/interface/src/main/java/org/apache/iotdb/metrics/type/HistogramSnapshot.java index 54adeec..430adf8 100644 --- a/metrics/interface/src/main/java/org/apache/iotdb/metrics/type/HistogramSnapshot.java +++ b/metrics/interface/src/main/java/org/apache/iotdb/metrics/type/HistogramSnapshot.java @@ -37,8 +37,6 @@ public interface HistogramSnapshot { public abstract long getMin(); - public abstract double getStdDev(); - /** * Writes the values of the snapshot to the given stream. * diff --git a/metrics/interface/src/main/java/org/apache/iotdb/metrics/type/Timer.java b/metrics/interface/src/main/java/org/apache/iotdb/metrics/type/Timer.java index 2f05b2a..fb1952e 100644 --- a/metrics/interface/src/main/java/org/apache/iotdb/metrics/type/Timer.java +++ b/metrics/interface/src/main/java/org/apache/iotdb/metrics/type/Timer.java @@ -37,5 +37,10 @@ public interface Timer extends IMetric { HistogramSnapshot takeSnapshot(); - Rate getMeter(); + /** + * It's not safe to use the update interface + * + * @return the rate related with the timer + */ + Rate getImmutableRate(); } diff --git a/metrics/interface/src/main/java/org/apache/iotdb/metrics/MetricFactory.java b/metrics/interface/src/main/java/org/apache/iotdb/metrics/utils/ReporterType.java similarity index 59% copy from metrics/interface/src/main/java/org/apache/iotdb/metrics/MetricFactory.java copy to metrics/interface/src/main/java/org/apache/iotdb/metrics/utils/ReporterType.java index 4896aaa..b13884c 100644 --- a/metrics/interface/src/main/java/org/apache/iotdb/metrics/MetricFactory.java +++ b/metrics/interface/src/main/java/org/apache/iotdb/metrics/utils/ReporterType.java @@ -16,23 +16,36 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.iotdb.metrics; +package org.apache.iotdb.metrics.utils; + +import java.util.HashMap; import java.util.Map; -public interface MetricFactory { +public enum ReporterType { + JMX("jmx"), + PROMETHEUS("prometheus"), + IOTDB("iotdb"); + + private String name; + + ReporterType(String name) { + this.name = name; + } - /** - * repeated calling the method will return the same Object instance. - * - * @param namespace - * @return - */ - MetricManager getMetric(String namespace); + public String getName() { + return name; + } - void enableKnownMetric(KnownMetric metric); + private static final Map<String, ReporterType> lookup = new HashMap<>(); - Map<String, MetricManager> getAllMetrics(); + static { + for (ReporterType reporterType : ReporterType.values()) { + lookup.put(reporterType.getName(), reporterType); + } + } - boolean isEnable(); + public static ReporterType get(String name) { + return lookup.get(name); + } } diff --git a/metrics/micrometer-metrics/pom.xml b/metrics/micrometer-metrics/pom.xml index 1c51742..319fc04 100644 --- a/metrics/micrometer-metrics/pom.xml +++ b/metrics/micrometer-metrics/pom.xml @@ -39,5 +39,15 @@ <artifactId>micrometer-registry-prometheus</artifactId> <version>1.6.2</version> </dependency> + <dependency> + <groupId>io.micrometer</groupId> + <artifactId>micrometer-registry-jmx</artifactId> + <version>1.6.2</version> + </dependency> + <dependency> + <groupId>io.dropwizard.metrics</groupId> + <artifactId>metrics-core</artifactId> + <version>4.1.2</version> + </dependency> </dependencies> </project> diff --git a/metrics/interface/src/main/java/org/apache/iotdb/metrics/MetricFactory.java b/metrics/micrometer-metrics/src/main/java/org/apache/iotdb/metrics/micrometer/MeterIdUtils.java similarity index 68% rename from metrics/interface/src/main/java/org/apache/iotdb/metrics/MetricFactory.java rename to metrics/micrometer-metrics/src/main/java/org/apache/iotdb/metrics/micrometer/MeterIdUtils.java index 4896aaa..2112b22 100644 --- a/metrics/interface/src/main/java/org/apache/iotdb/metrics/MetricFactory.java +++ b/metrics/micrometer-metrics/src/main/java/org/apache/iotdb/metrics/micrometer/MeterIdUtils.java @@ -16,23 +16,17 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.iotdb.metrics; -import java.util.Map; +package org.apache.iotdb.metrics.micrometer; -public interface MetricFactory { +import io.micrometer.core.instrument.Meter; +import io.micrometer.core.instrument.Tags; - /** - * repeated calling the method will return the same Object instance. - * - * @param namespace - * @return - */ - MetricManager getMetric(String namespace); +public class MeterIdUtils { - void enableKnownMetric(KnownMetric metric); + private MeterIdUtils() {} - Map<String, MetricManager> getAllMetrics(); - - boolean isEnable(); + public static Meter.Id fromMetricName(String metricName, Meter.Type type, String... tags) { + return new Meter.Id(metricName, Tags.of(tags), null, null, type); + } } diff --git a/metrics/micrometer-metrics/src/main/java/org/apache/iotdb/metrics/micrometer/MicrometerMetricFactory.java b/metrics/micrometer-metrics/src/main/java/org/apache/iotdb/metrics/micrometer/MicrometerMetricFactory.java deleted file mode 100644 index 67aba66..0000000 --- a/metrics/micrometer-metrics/src/main/java/org/apache/iotdb/metrics/micrometer/MicrometerMetricFactory.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.iotdb.metrics.micrometer; - -import org.apache.iotdb.metrics.KnownMetric; -import org.apache.iotdb.metrics.MetricFactory; -import org.apache.iotdb.metrics.MetricManager; - -import io.micrometer.core.instrument.MeterRegistry; -import io.micrometer.core.instrument.binder.jvm.ClassLoaderMetrics; -import io.micrometer.core.instrument.binder.jvm.JvmCompilationMetrics; -import io.micrometer.core.instrument.binder.jvm.JvmGcMetrics; -import io.micrometer.core.instrument.binder.jvm.JvmHeapPressureMetrics; -import io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics; -import io.micrometer.core.instrument.binder.jvm.JvmThreadMetrics; - -import java.util.Collections; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -public class MicrometerMetricFactory implements MetricFactory { - boolean isEnable; - Map<String, MetricManager> currentMetricManagers = new ConcurrentHashMap<String, MetricManager>(); - - @Override - public MetricManager getMetric(String namespace) { - if (!isEnable) { - return null; - } - currentMetricManagers.putIfAbsent(namespace, new MicrometerMetricManager()); - return currentMetricManagers.get(namespace); - } - - @Override - public void enableKnownMetric(KnownMetric metric) { - if (!isEnable) { - return; - } - switch (metric) { - case JVM: - enableJVMMetrics(); - break; - case SYSTEM: - break; - case THREAD: - break; - default: - // ignore; - } - } - - private void enableJVMMetrics() { - MeterRegistry meterRegistry = (MeterRegistry) currentMetricManagers.get("iotdb"); - ClassLoaderMetrics classLoaderMetrics = new ClassLoaderMetrics(); - classLoaderMetrics.bindTo(meterRegistry); - JvmCompilationMetrics jvmCompilationMetrics = new JvmCompilationMetrics(); - jvmCompilationMetrics.bindTo(meterRegistry); - try (JvmGcMetrics jvmGcMetrics = new JvmGcMetrics(); - JvmHeapPressureMetrics jvmHeapPressureMetrics = new JvmHeapPressureMetrics()) { - jvmGcMetrics.bindTo(meterRegistry); - jvmHeapPressureMetrics.bindTo(meterRegistry); - } - JvmMemoryMetrics jvmMemoryMetrics = new JvmMemoryMetrics(); - jvmMemoryMetrics.bindTo(meterRegistry); - JvmThreadMetrics jvmThreadMetrics = new JvmThreadMetrics(); - jvmThreadMetrics.bindTo(meterRegistry); - } - - @Override - public Map<String, MetricManager> getAllMetrics() { - if (!isEnable) { - return Collections.emptyMap(); - } - return currentMetricManagers; - } - - @Override - public boolean isEnable() { - return isEnable; - } -} diff --git a/metrics/micrometer-metrics/src/main/java/org/apache/iotdb/metrics/micrometer/MicrometerMetricManager.java b/metrics/micrometer-metrics/src/main/java/org/apache/iotdb/metrics/micrometer/MicrometerMetricManager.java index 5eb65e4..249902c 100644 --- a/metrics/micrometer-metrics/src/main/java/org/apache/iotdb/metrics/micrometer/MicrometerMetricManager.java +++ b/metrics/micrometer-metrics/src/main/java/org/apache/iotdb/metrics/micrometer/MicrometerMetricManager.java @@ -19,42 +19,119 @@ package org.apache.iotdb.metrics.micrometer; +import org.apache.iotdb.metrics.KnownMetric; import org.apache.iotdb.metrics.MetricManager; +import org.apache.iotdb.metrics.config.MetricConfig; +import org.apache.iotdb.metrics.config.MetricConfigDescriptor; import org.apache.iotdb.metrics.micrometer.type.MicrometerCounter; +import org.apache.iotdb.metrics.micrometer.type.MicrometerGauge; +import org.apache.iotdb.metrics.micrometer.type.MicrometerHistogram; +import org.apache.iotdb.metrics.micrometer.type.MicrometerRate; +import org.apache.iotdb.metrics.micrometer.type.MicrometerTimer; import org.apache.iotdb.metrics.type.Counter; import org.apache.iotdb.metrics.type.Gauge; import org.apache.iotdb.metrics.type.Histogram; import org.apache.iotdb.metrics.type.IMetric; import org.apache.iotdb.metrics.type.Rate; import org.apache.iotdb.metrics.type.Timer; +import org.apache.iotdb.metrics.utils.ReporterType; +import io.micrometer.core.instrument.Clock; import io.micrometer.core.instrument.Meter; import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Metrics; +import io.micrometer.core.instrument.Tag; +import io.micrometer.core.instrument.Tags; +import io.micrometer.core.instrument.binder.jvm.ClassLoaderMetrics; +import io.micrometer.core.instrument.binder.jvm.JvmCompilationMetrics; +import io.micrometer.core.instrument.binder.jvm.JvmGcMetrics; +import io.micrometer.core.instrument.binder.jvm.JvmHeapPressureMetrics; +import io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics; +import io.micrometer.core.instrument.binder.jvm.JvmThreadMetrics; +import io.micrometer.jmx.JmxConfig; +import io.micrometer.jmx.JmxMeterRegistry; import io.micrometer.prometheus.PrometheusConfig; import io.micrometer.prometheus.PrometheusMeterRegistry; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; public class MicrometerMetricManager implements MetricManager { + private static final Logger logger = LoggerFactory.getLogger(MicrometerMetricManager.class); + Map<Meter.Id, IMetric> currentMeters; + boolean isEnable; - io.micrometer.prometheus.PrometheusMeterRegistry prometheusMeterRegistry; + io.micrometer.core.instrument.MeterRegistry meterRegistry; + MetricConfig metricConfig = MetricConfigDescriptor.getInstance().getMetricConfig(); public MicrometerMetricManager() { - prometheusMeterRegistry = new PrometheusMeterRegistry(PrometheusConfig.DEFAULT); + meterRegistry = Metrics.globalRegistry; currentMeters = new ConcurrentHashMap<>(); + isEnable = metricConfig.isEnabled(); + } + + @Override + public boolean init() { + logger.debug("micrometer init registry"); + List<String> reporters = metricConfig.getReporterList(); + for (String reporter : reporters) { + switch (ReporterType.get(reporter)) { + case JMX: + Metrics.addRegistry(new JmxMeterRegistry(JmxConfig.DEFAULT, Clock.SYSTEM)); + break; + case PROMETHEUS: + Metrics.addRegistry(new PrometheusMeterRegistry(PrometheusConfig.DEFAULT)); + break; + case IOTDB: + break; + default: + logger.warn("Unsupported report type {}, please check the config.", reporter); + return false; + } + } + return true; } public MeterRegistry getMeterRegistry() { - return prometheusMeterRegistry; + return meterRegistry; + } + + public PrometheusMeterRegistry getPrometheusMeterRegistry() { + Set<MeterRegistry> meterRegistrySet = Metrics.globalRegistry.getRegistries(); + for (MeterRegistry childMeterRegistry : meterRegistrySet) { + if (childMeterRegistry instanceof PrometheusMeterRegistry) { + return (PrometheusMeterRegistry) childMeterRegistry; + } + } + return null; + } + + public JmxMeterRegistry getJmxMeterRegistry() { + Set<MeterRegistry> meterRegistrySet = Metrics.globalRegistry.getRegistries(); + for (MeterRegistry childMeterRegistry : meterRegistrySet) { + if (childMeterRegistry instanceof JmxMeterRegistry) { + return (JmxMeterRegistry) childMeterRegistry; + } + } + return null; } @Override public Counter counter(String metric, String... tags) { - io.micrometer.core.instrument.Counter innerCounter = - prometheusMeterRegistry.counter(metric, tags); + if (!isEnable) { + return null; + } + io.micrometer.core.instrument.Counter innerCounter = meterRegistry.counter(metric, tags); return (Counter) currentMeters.computeIfAbsent( innerCounter.getId(), key -> new MicrometerCounter(innerCounter)); @@ -62,88 +139,312 @@ public class MicrometerMetricManager implements MetricManager { @Override public void count(int delta, String metric, String... tags) { - io.micrometer.core.instrument.Counter innerCounter = - prometheusMeterRegistry.counter(metric, tags); + io.micrometer.core.instrument.Counter innerCounter = meterRegistry.counter(metric, tags); innerCounter.increment(delta); } @Override - public void count(long delta, String metric, String... tags) {} + public void count(long delta, String metric, String... tags) { + io.micrometer.core.instrument.Counter innerCounter = meterRegistry.counter(metric, tags); + innerCounter.increment(delta); + } @Override public Gauge gauge(String metric, String... tags) { - return null; + if (!isEnable) { + return null; + } + Meter.Id id = MeterIdUtils.fromMetricName(metric, Meter.Type.GAUGE, tags); + return (Gauge) + currentMeters.computeIfAbsent(id, key -> new MicrometerGauge(meterRegistry, metric, tags)); } @Override public Histogram histogram(String metric, String... tags) { - return null; + if (!isEnable) { + return null; + } + Meter.Id id = MeterIdUtils.fromMetricName(metric, Meter.Type.DISTRIBUTION_SUMMARY, tags); + return (Histogram) + currentMeters.computeIfAbsent( + id, + key -> { + io.micrometer.core.instrument.DistributionSummary distributionSummary = + io.micrometer.core.instrument.DistributionSummary.builder(metric) + .tags(tags) + .register(meterRegistry); + return new MicrometerHistogram(distributionSummary); + }); } + /** + * We only create a gauge(AtomicLong) to record the raw value, because we assume that the backend + * metrics system has the ability to calculate rate + * + * @param metric + * @param tags + * @return + */ @Override + @Deprecated public Rate rate(String metric, String... tags) { - return null; + if (!isEnable) { + return null; + } + Meter.Id id = MeterIdUtils.fromMetricName(metric, Meter.Type.GAUGE, tags); + return (Rate) + currentMeters.computeIfAbsent( + id, + key -> + new MicrometerRate(meterRegistry.gauge(metric, Tags.of(tags), new AtomicLong(0)))); } @Override public Timer timer(String metric, String... tags) { - return null; + if (!isEnable) { + return null; + } + logger.info(metric + Arrays.toString(tags)); + Meter.Id id = MeterIdUtils.fromMetricName(metric, Meter.Type.TIMER, tags); + return (Timer) + currentMeters.computeIfAbsent( + id, + key -> { + io.micrometer.core.instrument.Timer timer = + io.micrometer.core.instrument.Timer.builder(metric) + .tags(tags) + .register(meterRegistry); + logger.info("create timer {}", metric); + return new MicrometerTimer(timer); + }); } @Override - public void histogram(int value, String metric, String... tags) {} - - @Override - public void histogram(long value, String metric, String... tags) {} - - @Override - public void gauge(int value, String metric, String... tags) {} + public void histogram(int value, String metric, String... tags) { + if (!isEnable) { + return; + } + Meter.Id id = MeterIdUtils.fromMetricName(metric, Meter.Type.DISTRIBUTION_SUMMARY, tags); + ((Histogram) + currentMeters.computeIfAbsent( + id, + key -> { + io.micrometer.core.instrument.DistributionSummary distributionSummary = + io.micrometer.core.instrument.DistributionSummary.builder(metric) + .tags(tags) + .publishPercentileHistogram() + .publishPercentiles(0) + .register(meterRegistry); + return new MicrometerHistogram(distributionSummary); + })) + .update(value); + } @Override - public void gauge(long value, String metric, String... tags) {} + public void histogram(long value, String metric, String... tags) { + if (!isEnable) { + return; + } + Meter.Id id = MeterIdUtils.fromMetricName(metric, Meter.Type.DISTRIBUTION_SUMMARY, tags); + ((Histogram) + currentMeters.computeIfAbsent( + id, + key -> { + io.micrometer.core.instrument.DistributionSummary distributionSummary = + io.micrometer.core.instrument.DistributionSummary.builder(metric) + .tags(tags) + .publishPercentileHistogram() + .publishPercentiles(0) + .register(meterRegistry); + return new MicrometerHistogram(distributionSummary); + })) + .update(value); + } @Override - public void meter(int value, String metric, String... tags) {} + public void gauge(int value, String metric, String... tags) { + if (!isEnable) { + return; + } + Meter.Id id = MeterIdUtils.fromMetricName(metric, Meter.Type.GAUGE, tags); + ((Gauge) + (currentMeters.computeIfAbsent( + id, key -> new MicrometerGauge(meterRegistry, metric, tags)))) + .set(value); + } @Override - public void meter(long value, String metric, String... tags) {} + public void gauge(long value, String metric, String... tags) { + if (!isEnable) { + return; + } + Meter.Id id = MeterIdUtils.fromMetricName(metric, Meter.Type.GAUGE, tags); + ((Gauge) + (currentMeters.computeIfAbsent( + id, key -> new MicrometerGauge(meterRegistry, metric, tags)))) + .set(value); + } @Override - public void timer(long delta, TimeUnit timeUnit, String metric, String... tags) {} + public void rate(int value, String metric, String... tags) { + if (!isEnable) { + return; + } + Meter.Id id = MeterIdUtils.fromMetricName(metric, Meter.Type.GAUGE, tags); + ((Rate) + currentMeters.computeIfAbsent( + id, + key -> + new MicrometerRate( + meterRegistry.gauge(metric, Tags.of(tags), new AtomicLong(0))))) + .mark(value); + } @Override - public void timerStart(String metric, String... tags) {} + public void rate(long value, String metric, String... tags) { + if (!isEnable) { + return; + } + Meter.Id id = MeterIdUtils.fromMetricName(metric, Meter.Type.GAUGE, tags); + ((Rate) + currentMeters.computeIfAbsent( + id, + key -> + new MicrometerRate( + meterRegistry.gauge(metric, Tags.of(tags), new AtomicLong(0))))) + .mark(value); + } @Override - public void timerEnd(String metric, String... tags) {} + public synchronized void timer(long delta, TimeUnit timeUnit, String metric, String... tags) { + if (!isEnable) { + return; + } + Meter.Id id = MeterIdUtils.fromMetricName(metric, Meter.Type.TIMER, tags); + ((Timer) + currentMeters.computeIfAbsent( + id, + key -> { + io.micrometer.core.instrument.Timer timer = + io.micrometer.core.instrument.Timer.builder(metric) + .tags(tags) + .register(meterRegistry); + return new MicrometerTimer(timer); + })) + .update(delta, timeUnit); + } @Override - public Map<String, String[]> getAllMetricKeys() { - return null; + public List<String[]> getAllMetricKeys() { + List<String[]> keys = new ArrayList<>(currentMeters.size()); + List<Meter> meterList = meterRegistry.getMeters(); + for (Meter meter : meterList) { + List<String> tags = new ArrayList<>(meter.getId().getTags().size() * 2 + 1); + tags.add(meter.getId().getName()); + for (Tag tag : meter.getId().getTags()) { + tags.add(tag.getKey()); + tags.add(tag.getValue()); + } + keys.add(tags.toArray(new String[0])); + } + return keys; } @Override public Map<String[], Counter> getAllCounters() { - return null; + Map<String[], IMetric> iMetricMap = getMetricByType(Meter.Type.COUNTER); + Map<String[], Counter> counterMap = new HashMap<>(); + iMetricMap.forEach((k, v) -> counterMap.put(k, (Counter) v)); + return counterMap; } @Override public Map<String[], Gauge> getAllGauges() { - return null; + Map<String[], IMetric> iMetricMap = getMetricByType(Meter.Type.GAUGE); + Map<String[], Gauge> gaugeMap = new HashMap<>(); + iMetricMap.forEach((k, v) -> gaugeMap.put(k, (Gauge) v)); + return gaugeMap; } @Override - public Map<String[], Rate> getAllMeters() { - return null; + public Map<String[], Rate> getAllRates() { + Map<String[], IMetric> iMetricMap = getMetricByType(Meter.Type.OTHER); + Map<String[], Rate> rateMap = new HashMap<>(); + iMetricMap.forEach((k, v) -> rateMap.put(k, (Rate) v)); + return rateMap; } @Override public Map<String[], Histogram> getAllHistograms() { - return null; + Map<String[], IMetric> iMetricMap = getMetricByType(Meter.Type.DISTRIBUTION_SUMMARY); + Map<String[], Histogram> histogramMap = new HashMap<>(); + iMetricMap.forEach((k, v) -> histogramMap.put(k, (Histogram) v)); + return histogramMap; } @Override public Map<String[], Timer> getAllTimers() { - return null; + Map<String[], IMetric> iMetricMap = getMetricByType(Meter.Type.TIMER); + Map<String[], Timer> timerMap = new HashMap<>(); + iMetricMap.forEach((k, v) -> timerMap.put(k, (Timer) v)); + return timerMap; + } + + private Map<String[], IMetric> getMetricByType(Meter.Type type) { + Map<String[], IMetric> iMetricMap = new HashMap<>(); + for (Map.Entry<Meter.Id, IMetric> entry : currentMeters.entrySet()) { + if (entry.getKey().getType() == type) { + List<String> tags = new ArrayList<>(entry.getKey().getTags().size() * 2); + tags.add(entry.getKey().getName()); + for (Tag tag : entry.getKey().getTags()) { + tags.add(tag.getKey()); + tags.add(tag.getValue()); + } + iMetricMap.put(tags.toArray(new String[0]), entry.getValue()); + } + } + return iMetricMap; + } + + @Override + public void enableKnownMetric(KnownMetric metric) { + if (!isEnable) { + return; + } + switch (metric) { + case JVM: + enableJVMMetrics(); + break; + case SYSTEM: + break; + case THREAD: + break; + default: + // ignore; + } + } + + private void enableJVMMetrics() { + if (!isEnable) { + return; + } + ClassLoaderMetrics classLoaderMetrics = new ClassLoaderMetrics(); + classLoaderMetrics.bindTo(meterRegistry); + JvmCompilationMetrics jvmCompilationMetrics = new JvmCompilationMetrics(); + jvmCompilationMetrics.bindTo(meterRegistry); + try (JvmGcMetrics jvmGcMetrics = new JvmGcMetrics(); + JvmHeapPressureMetrics jvmHeapPressureMetrics = new JvmHeapPressureMetrics()) { + jvmGcMetrics.bindTo(meterRegistry); + jvmHeapPressureMetrics.bindTo(meterRegistry); + } + JvmMemoryMetrics jvmMemoryMetrics = new JvmMemoryMetrics(); + jvmMemoryMetrics.bindTo(meterRegistry); + JvmThreadMetrics jvmThreadMetrics = new JvmThreadMetrics(); + jvmThreadMetrics.bindTo(meterRegistry); + } + + @Override + public boolean isEnable() { + return isEnable; } } diff --git a/metrics/micrometer-metrics/src/main/java/org/apache/iotdb/metrics/micrometer/MicrometerMetricReporter.java b/metrics/micrometer-metrics/src/main/java/org/apache/iotdb/metrics/micrometer/MicrometerMetricReporter.java index 518a4d0..3639dbe 100644 --- a/metrics/micrometer-metrics/src/main/java/org/apache/iotdb/metrics/micrometer/MicrometerMetricReporter.java +++ b/metrics/micrometer-metrics/src/main/java/org/apache/iotdb/metrics/micrometer/MicrometerMetricReporter.java @@ -19,32 +19,63 @@ package org.apache.iotdb.metrics.micrometer; -import org.apache.iotdb.metrics.MetricFactory; +import org.apache.iotdb.metrics.MetricManager; import org.apache.iotdb.metrics.MetricReporter; +import org.apache.iotdb.metrics.config.MetricConfig; +import org.apache.iotdb.metrics.config.MetricConfigDescriptor; +import org.apache.iotdb.metrics.utils.ReporterType; import com.sun.net.httpserver.HttpServer; +import io.micrometer.jmx.JmxMeterRegistry; import io.micrometer.prometheus.PrometheusMeterRegistry; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; import java.io.OutputStream; import java.net.InetSocketAddress; +import java.util.List; public class MicrometerMetricReporter implements MetricReporter { - MetricFactory micrometerMetricFactory; - Thread runThread; + private static final Logger logger = LoggerFactory.getLogger(MicrometerMetricReporter.class); + private MetricManager micrometerMetricManager; + private final MetricConfig metricConfig = MetricConfigDescriptor.getInstance().getMetricConfig(); + private Thread runThread; + + private JmxMeterRegistry jmxMeterRegistry; @Override public boolean start() { + List<String> reporters = metricConfig.getReporterList(); + for (String reporter : reporters) { + switch (ReporterType.get(reporter)) { + case JMX: + startJmxReporter( + ((MicrometerMetricManager) micrometerMetricManager).getJmxMeterRegistry()); + break; + case IOTDB: + break; + case PROMETHEUS: + startPrometheusReporter( + ((MicrometerMetricManager) micrometerMetricManager).getPrometheusMeterRegistry()); + break; + default: + logger.warn("Dropwizard don't support reporter type {}", reporter); + } + } + + return true; + } + + private void startPrometheusReporter(PrometheusMeterRegistry prometheusMeterRegistry) { try { - HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0); + HttpServer server = + HttpServer.create( + new InetSocketAddress(Integer.parseInt(metricConfig.getPrometheusExporterPort())), 0); server.createContext( "/prometheus", httpExchange -> { - String response = - ((PrometheusMeterRegistry) - ((MicrometerMetricManager) micrometerMetricFactory.getMetric("iotdb")) - .getMeterRegistry()) - .scrape(); + String response = prometheusMeterRegistry.scrape(); httpExchange.sendResponseHeaders(200, response.getBytes().length); try (OutputStream os = httpExchange.getResponseBody()) { os.write(response.getBytes()); @@ -56,12 +87,16 @@ public class MicrometerMetricReporter implements MetricReporter { } catch (IOException e) { throw new RuntimeException(e); } - return true; + } + + private void startJmxReporter(JmxMeterRegistry jmxMeterRegistry) { + logger.debug("start jmx reporter from micrometer"); + jmxMeterRegistry.start(); } @Override - public void setMetricFactory(MetricFactory metricFactory) { - micrometerMetricFactory = metricFactory; + public void setMetricManager(MetricManager metricManager) { + micrometerMetricManager = metricManager; } @Override @@ -69,8 +104,10 @@ public class MicrometerMetricReporter implements MetricReporter { try { runThread.join(); } catch (InterruptedException e) { - e.printStackTrace(); + logger.warn("Failed to stop prometheus reporter", e); } + + ((MicrometerMetricManager) micrometerMetricManager).getJmxMeterRegistry().stop(); return true; } } diff --git a/metrics/micrometer-metrics/src/main/java/org/apache/iotdb/metrics/micrometer/type/MicrometerCounter.java b/metrics/micrometer-metrics/src/main/java/org/apache/iotdb/metrics/micrometer/type/MicrometerCounter.java index 9fbfa6f..cdeb40a 100644 --- a/metrics/micrometer-metrics/src/main/java/org/apache/iotdb/metrics/micrometer/type/MicrometerCounter.java +++ b/metrics/micrometer-metrics/src/main/java/org/apache/iotdb/metrics/micrometer/type/MicrometerCounter.java @@ -22,13 +22,12 @@ package org.apache.iotdb.metrics.micrometer.type; import org.apache.iotdb.metrics.type.Counter; public class MicrometerCounter implements Counter { + io.micrometer.core.instrument.Counter counter; public MicrometerCounter(io.micrometer.core.instrument.Counter counter) { this.counter = counter; } - io.micrometer.core.instrument.Counter counter; - @Override public void inc() { counter.increment(); diff --git a/metrics/interface/src/main/java/org/apache/iotdb/metrics/impl/DoNothingFactory.java b/metrics/micrometer-metrics/src/main/java/org/apache/iotdb/metrics/micrometer/type/MicrometerGauge.java similarity index 56% rename from metrics/interface/src/main/java/org/apache/iotdb/metrics/impl/DoNothingFactory.java rename to metrics/micrometer-metrics/src/main/java/org/apache/iotdb/metrics/micrometer/type/MicrometerGauge.java index bce4ec8..e2c80b9 100644 --- a/metrics/interface/src/main/java/org/apache/iotdb/metrics/impl/DoNothingFactory.java +++ b/metrics/micrometer-metrics/src/main/java/org/apache/iotdb/metrics/micrometer/type/MicrometerGauge.java @@ -16,33 +16,32 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.iotdb.metrics.impl; -import org.apache.iotdb.metrics.KnownMetric; -import org.apache.iotdb.metrics.MetricFactory; -import org.apache.iotdb.metrics.MetricManager; +package org.apache.iotdb.metrics.micrometer.type; -import java.util.Collections; -import java.util.Map; +import org.apache.iotdb.metrics.type.Gauge; -public class DoNothingFactory implements MetricFactory { - private DoNothingMetricManager metric = new DoNothingMetricManager(); +import io.micrometer.core.instrument.Tags; - @Override - public MetricManager getMetric(String namespace) { - return metric; - } +import java.util.concurrent.atomic.AtomicLong; - @Override - public void enableKnownMetric(KnownMetric metric) {} +public class MicrometerGauge implements Gauge { + private final AtomicLong atomicLong; + + public MicrometerGauge( + io.micrometer.core.instrument.MeterRegistry meterRegistry, + String metricName, + String... tags) { + atomicLong = meterRegistry.gauge(metricName, Tags.of(tags), new AtomicLong(0)); + } @Override - public Map<String, MetricManager> getAllMetrics() { - return Collections.emptyMap(); + public long value() { + return atomicLong.get(); } @Override - public boolean isEnable() { - return true; + public void set(long value) { + atomicLong.set(value); } } diff --git a/metrics/micrometer-metrics/src/main/java/org/apache/iotdb/metrics/micrometer/type/MicrometerCounter.java b/metrics/micrometer-metrics/src/main/java/org/apache/iotdb/metrics/micrometer/type/MicrometerHistogram.java similarity index 57% copy from metrics/micrometer-metrics/src/main/java/org/apache/iotdb/metrics/micrometer/type/MicrometerCounter.java copy to metrics/micrometer-metrics/src/main/java/org/apache/iotdb/metrics/micrometer/type/MicrometerHistogram.java index 9fbfa6f..f843fa1 100644 --- a/metrics/micrometer-metrics/src/main/java/org/apache/iotdb/metrics/micrometer/type/MicrometerCounter.java +++ b/metrics/micrometer-metrics/src/main/java/org/apache/iotdb/metrics/micrometer/type/MicrometerHistogram.java @@ -19,28 +19,34 @@ package org.apache.iotdb.metrics.micrometer.type; -import org.apache.iotdb.metrics.type.Counter; +import org.apache.iotdb.metrics.type.Histogram; -public class MicrometerCounter implements Counter { +public class MicrometerHistogram implements Histogram { - public MicrometerCounter(io.micrometer.core.instrument.Counter counter) { - this.counter = counter; - } + io.micrometer.core.instrument.DistributionSummary distributionSummary; - io.micrometer.core.instrument.Counter counter; + public MicrometerHistogram( + io.micrometer.core.instrument.DistributionSummary distributionSummary) { + this.distributionSummary = distributionSummary; + } @Override - public void inc() { - counter.increment(); + public void update(int value) { + distributionSummary.record(value); } @Override - public void inc(long n) { - counter.increment(n); + public void update(long value) { + distributionSummary.record(value); } @Override public long count() { - return (long) counter.count(); + return distributionSummary.count(); + } + + @Override + public org.apache.iotdb.metrics.type.HistogramSnapshot takeSnapshot() { + return new MicrometerHistogramSnapshot(distributionSummary.takeSnapshot()); } } diff --git a/metrics/micrometer-metrics/src/main/java/org/apache/iotdb/metrics/micrometer/type/MicrometerHistogramSnapshot.java b/metrics/micrometer-metrics/src/main/java/org/apache/iotdb/metrics/micrometer/type/MicrometerHistogramSnapshot.java new file mode 100644 index 0000000..3c3aedb --- /dev/null +++ b/metrics/micrometer-metrics/src/main/java/org/apache/iotdb/metrics/micrometer/type/MicrometerHistogramSnapshot.java @@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.iotdb.metrics.micrometer.type; + +import org.apache.iotdb.metrics.type.HistogramSnapshot; + +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.Arrays; + +public class MicrometerHistogramSnapshot implements HistogramSnapshot { + + io.micrometer.core.instrument.distribution.HistogramSnapshot histogramSnapshot; + + public MicrometerHistogramSnapshot( + io.micrometer.core.instrument.distribution.HistogramSnapshot histogramSnapshot) { + this.histogramSnapshot = histogramSnapshot; + } + + @Override + public double getValue(double quantile) { + int prevIndex = 0; + int i = 0; + for (i = 0; i < this.histogramSnapshot.percentileValues().length; i++) { + if (this.histogramSnapshot.percentileValues()[i].percentile() == quantile) { + prevIndex = i; + break; + } else if (this.histogramSnapshot.percentileValues()[i].percentile() > quantile) { + break; + } + prevIndex = i; + } + + return this.histogramSnapshot.percentileValues()[prevIndex].value(); + } + + @Override + public long[] getValues() { + return Arrays.stream(this.histogramSnapshot.percentileValues()) + .mapToLong(k -> (long) k.value()) + .toArray(); + } + + @Override + public int size() { + return this.histogramSnapshot.percentileValues().length; + } + + @Override + public double getMedian() { + return getValue(0.5); + } + + @Override + public long getMax() { + return (long) this.histogramSnapshot.max(); + } + + @Override + public double getMean() { + return this.histogramSnapshot.mean(); + } + + @Override + public long getMin() { + // need distributionSummary to push 0 percentiles + return (long) getValue(0.0); + } + + @Override + public void dump(OutputStream output) { + this.histogramSnapshot.outputSummary((PrintStream) output, 100); + } +} diff --git a/metrics/micrometer-metrics/src/main/java/org/apache/iotdb/metrics/micrometer/type/MicrometerRate.java b/metrics/micrometer-metrics/src/main/java/org/apache/iotdb/metrics/micrometer/type/MicrometerRate.java new file mode 100644 index 0000000..0789f1c --- /dev/null +++ b/metrics/micrometer-metrics/src/main/java/org/apache/iotdb/metrics/micrometer/type/MicrometerRate.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.iotdb.metrics.micrometer.type; + +import org.apache.iotdb.metrics.type.Rate; + +import com.codahale.metrics.Meter; + +import java.util.concurrent.atomic.AtomicLong; + +/** + * could not publish to other metrics system exclude jmx and csv, because micrometer assumes that + * other metrics system have the ability to calculate rate. Details is at + * https://github.com/micrometer-metrics/micrometer/issues/1935. + * + * <p>Now, we only record a gauge for the rate record in micrometer, and we use dropwizard meter to + * calculate the meter. + */ +public class MicrometerRate implements Rate { + AtomicLong atomicLong; + Meter meter; + + public MicrometerRate(AtomicLong atomicLong) { + this.atomicLong = atomicLong; + meter = new Meter(); + } + + @Override + public long getCount() { + return meter.getCount(); + } + + @Override + public double getOneMinuteRate() { + return meter.getOneMinuteRate(); + } + + @Override + public double getMeanRate() { + return meter.getMeanRate(); + } + + @Override + public double getFiveMinuteRate() { + return meter.getFiveMinuteRate(); + } + + @Override + public double getFifteenMinuteRate() { + return meter.getFifteenMinuteRate(); + } + + @Override + public void mark() { + atomicLong.set(1); + meter.mark(); + } + + @Override + public void mark(long n) { + atomicLong.set(n); + meter.mark(n); + } +} diff --git a/metrics/micrometer-metrics/src/main/java/org/apache/iotdb/metrics/micrometer/type/MicrometerCounter.java b/metrics/micrometer-metrics/src/main/java/org/apache/iotdb/metrics/micrometer/type/MicrometerTimer.java similarity index 53% copy from metrics/micrometer-metrics/src/main/java/org/apache/iotdb/metrics/micrometer/type/MicrometerCounter.java copy to metrics/micrometer-metrics/src/main/java/org/apache/iotdb/metrics/micrometer/type/MicrometerTimer.java index 9fbfa6f..07c68e4 100644 --- a/metrics/micrometer-metrics/src/main/java/org/apache/iotdb/metrics/micrometer/type/MicrometerCounter.java +++ b/metrics/micrometer-metrics/src/main/java/org/apache/iotdb/metrics/micrometer/type/MicrometerTimer.java @@ -19,28 +19,36 @@ package org.apache.iotdb.metrics.micrometer.type; -import org.apache.iotdb.metrics.type.Counter; +import org.apache.iotdb.metrics.type.HistogramSnapshot; +import org.apache.iotdb.metrics.type.Rate; +import org.apache.iotdb.metrics.type.Timer; -public class MicrometerCounter implements Counter { +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; - public MicrometerCounter(io.micrometer.core.instrument.Counter counter) { - this.counter = counter; - } +public class MicrometerTimer implements Timer { + + io.micrometer.core.instrument.Timer timer; + MicrometerRate micrometerRate; - io.micrometer.core.instrument.Counter counter; + public MicrometerTimer(io.micrometer.core.instrument.Timer timer) { + this.timer = timer; + micrometerRate = new MicrometerRate(new AtomicLong(0)); + } @Override - public void inc() { - counter.increment(); + public void update(long duration, TimeUnit unit) { + timer.record(duration, unit); + micrometerRate.mark(duration); } @Override - public void inc(long n) { - counter.increment(n); + public HistogramSnapshot takeSnapshot() { + return new MicrometerHistogramSnapshot(timer.takeSnapshot()); } @Override - public long count() { - return (long) counter.count(); + public Rate getImmutableRate() { + return micrometerRate; } } diff --git a/metrics/micrometer-metrics/src/main/resources/META-INF.services/org.apache.iotdb.metrics.micrometer.MicrometerMetricFactory b/metrics/micrometer-metrics/src/main/resources/META-INF.services/org.apache.iotdb.metrics.micrometer.MicrometerMetricFactory deleted file mode 100644 index 6860085..0000000 --- a/metrics/micrometer-metrics/src/main/resources/META-INF.services/org.apache.iotdb.metrics.micrometer.MicrometerMetricFactory +++ /dev/null @@ -1 +0,0 @@ -# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by a [...] \ No newline at end of file diff --git a/metrics/micrometer-metrics/src/main/resources/META-INF.services/org.apache.iotdb.metrics.micrometer.MicrometerMetricReporter b/metrics/micrometer-metrics/src/main/resources/META-INF.services/org.apache.iotdb.metrics.micrometer.MicrometerMetricReporter deleted file mode 100644 index 3138baf..0000000 --- a/metrics/micrometer-metrics/src/main/resources/META-INF.services/org.apache.iotdb.metrics.micrometer.MicrometerMetricReporter +++ /dev/null @@ -1 +0,0 @@ -# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by a [...] \ No newline at end of file diff --git a/metrics/micrometer-metrics/src/main/resources/META-INF/services/org.apache.iotdb.metrics.MetricManager b/metrics/micrometer-metrics/src/main/resources/META-INF/services/org.apache.iotdb.metrics.MetricManager new file mode 100644 index 0000000..235ab43 --- /dev/null +++ b/metrics/micrometer-metrics/src/main/resources/META-INF/services/org.apache.iotdb.metrics.MetricManager @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +org.apache.iotdb.metrics.micrometer.MicrometerMetricManager \ No newline at end of file diff --git a/metrics/micrometer-metrics/src/main/resources/META-INF/services/org.apache.iotdb.metrics.MetricReporter b/metrics/micrometer-metrics/src/main/resources/META-INF/services/org.apache.iotdb.metrics.MetricReporter new file mode 100644 index 0000000..4a14a74 --- /dev/null +++ b/metrics/micrometer-metrics/src/main/resources/META-INF/services/org.apache.iotdb.metrics.MetricReporter @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +org.apache.iotdb.metrics.micrometer.MicrometerMetricReporter \ No newline at end of file diff --git a/metrics/pom.xml b/metrics/pom.xml index b7b9b10..6666aeb 100644 --- a/metrics/pom.xml +++ b/metrics/pom.xml @@ -35,6 +35,6 @@ <modules> <module>interface</module> <module>micrometer-metrics</module> + <module>dropwizard-metrics</module> </modules> - </project> diff --git a/server/pom.xml b/server/pom.xml index d1ce0ef..fb23f01 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -196,6 +196,16 @@ <artifactId>netty-buffer</artifactId> <version>4.1.27.Final</version> </dependency> + <dependency> + <groupId>org.apache.iotdb</groupId> + <artifactId>metrics-interface</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.apache.iotdb</groupId> + <artifactId>micrometer-metrics</artifactId> + <version>${project.version}</version> + </dependency> </dependencies> <build> <plugins> diff --git a/server/src/assembly/resources/conf/iotdb-metric.properties b/server/src/assembly/resources/conf/iotdb-metric.properties new file mode 100644 index 0000000..4fbc6bb --- /dev/null +++ b/server/src/assembly/resources/conf/iotdb-metric.properties @@ -0,0 +1,30 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +enable_metric=true +metric_reporter_list=jmx +push_period_in_second=5 +prometheus_exporter_port=8090 +iotdb_ip=127.0.0.1 +iotdb_port=6667 +iotdb_sg=iotdb +iotdb_user=root +iotdb_passwd=root + + diff --git a/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/StorageGroupProcessor.java b/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/StorageGroupProcessor.java index 8d97690..9625efa 100755 --- a/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/StorageGroupProcessor.java +++ b/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/StorageGroupProcessor.java @@ -66,6 +66,7 @@ import org.apache.iotdb.db.utils.MmapUtil; import org.apache.iotdb.db.utils.TestOnly; import org.apache.iotdb.db.utils.UpgradeUtils; import org.apache.iotdb.db.writelog.recover.TsFileRecoverPerformer; +import org.apache.iotdb.metrics.type.Timer; import org.apache.iotdb.rpc.RpcUtils; import org.apache.iotdb.rpc.TSStatusCode; import org.apache.iotdb.service.rpc.thrift.TSStatus; @@ -273,6 +274,10 @@ public class StorageGroupProcessor { // DEFAULT_POOL_TRIM_INTERVAL_MILLIS private long timeWhenPoolNotEmpty = Long.MAX_VALUE; + private Timer write_total_timer; + + private Timer read_total_timer; + /** get the direct byte buffer from pool, each fetch contains two ByteBuffer */ public ByteBuffer[] getWalDirectByteBuffer() { ByteBuffer[] res = new ByteBuffer[2]; @@ -384,6 +389,24 @@ public class StorageGroupProcessor { DEFAULT_POOL_TRIM_INTERVAL_MILLIS, TimeUnit.MILLISECONDS); recover(); + read_total_timer = + IoTDB.serverMetricManager.timer( + "read_latency", + "sg", + logicalStorageGroupName, + "user", + "total", + "host", + config.getRpcAddress()); + write_total_timer = + IoTDB.serverMetricManager.timer( + "write_latency", + "sg", + logicalStorageGroupName, + "user", + "total", + "host", + config.getRpcAddress()); } public String getLogicalStorageGroupName() { @@ -783,6 +806,7 @@ public class StorageGroupProcessor { if (!isAlive(insertRowPlan.getTime())) { throw new OutOfTTLException(insertRowPlan.getTime(), (System.currentTimeMillis() - dataTTL)); } + long startTime = System.currentTimeMillis(); if (enableMemControl) { StorageEngine.blockInsertionIfReject(); } @@ -813,6 +837,18 @@ public class StorageGroupProcessor { } finally { writeUnlock(); } + long end = System.currentTimeMillis(); + logger.info("timer insert cost {} millis", end - startTime); + IoTDB.serverMetricManager.timer( + end - startTime, + TimeUnit.MILLISECONDS, + "insert_row_latency", + "sg", + logicalStorageGroupName, + "user", + insertRowPlan.getLoginUserName(), + "host", + config.getRpcAddress()); } /** diff --git a/server/src/main/java/org/apache/iotdb/db/qp/executor/PlanExecutor.java b/server/src/main/java/org/apache/iotdb/db/qp/executor/PlanExecutor.java index c35ae48..f55532d 100644 --- a/server/src/main/java/org/apache/iotdb/db/qp/executor/PlanExecutor.java +++ b/server/src/main/java/org/apache/iotdb/db/qp/executor/PlanExecutor.java @@ -25,6 +25,7 @@ import org.apache.iotdb.db.auth.authorizer.IAuthorizer; import org.apache.iotdb.db.auth.entity.PathPrivilege; import org.apache.iotdb.db.auth.entity.Role; import org.apache.iotdb.db.auth.entity.User; +import org.apache.iotdb.db.conf.IoTDBConfig; import org.apache.iotdb.db.conf.IoTDBConstant; import org.apache.iotdb.db.conf.IoTDBDescriptor; import org.apache.iotdb.db.engine.StorageEngine; @@ -147,6 +148,7 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import java.util.concurrent.TimeUnit; import static org.apache.iotdb.db.conf.IoTDBConstant.COLUMN_CANCELLED; import static org.apache.iotdb.db.conf.IoTDBConstant.COLUMN_CHILD_PATHS; @@ -185,6 +187,7 @@ public class PlanExecutor implements IPlanExecutor { private IAuthorizer authorizer; private static final String INSERT_MEASUREMENTS_FAILED_MESSAGE = "failed to insert measurements "; + private IoTDBConfig config = IoTDBDescriptor.getInstance().getConfig(); public PlanExecutor() throws QueryProcessException { queryRouter = new QueryRouter(); @@ -1099,6 +1102,7 @@ public class PlanExecutor implements IPlanExecutor { @Override public void insert(InsertRowPlan insertRowPlan) throws QueryProcessException { + long startTime = System.currentTimeMillis(); try { insertRowPlan.setMeasurementMNodes( new MeasurementMNode[insertRowPlan.getMeasurements().length]); @@ -1109,6 +1113,16 @@ public class PlanExecutor implements IPlanExecutor { if (insertRowPlan.getFailedMeasurements() != null) { checkFailedMeasurments(insertRowPlan); } + IoTDB.serverMetricManager.timer( + System.currentTimeMillis() - startTime, + TimeUnit.MILLISECONDS, + "insert_latency", + "sg", + "root", // TODO infer from insertRowPlan.getDeviceId() + "user", + insertRowPlan.getLoginUserName(), + "host", + config.getRpcAddress()); } catch (StorageEngineException | MetadataException e) { if (IoTDBDescriptor.getInstance().getConfig().isEnableStatMonitor()) { StatMonitor.getInstance().updateFailedStatValue(); @@ -1135,6 +1149,7 @@ public class PlanExecutor implements IPlanExecutor { @Override public void insertTablet(InsertTabletPlan insertTabletPlan) throws QueryProcessException { + long startTime = System.currentTimeMillis(); try { insertTabletPlan.setMeasurementMNodes( new MeasurementMNode[insertTabletPlan.getMeasurements().length]); @@ -1143,6 +1158,16 @@ public class PlanExecutor implements IPlanExecutor { if (insertTabletPlan.getFailedMeasurements() != null) { checkFailedMeasurments(insertTabletPlan); } + IoTDB.serverMetricManager.timer( + System.currentTimeMillis() - startTime, + TimeUnit.MILLISECONDS, + "insert_tablet_latency", + "sg", + "root", // TODO infer from insertTabletPlan.getDeviceId() + "user", + insertTabletPlan.getLoginUserName(), + "host", + config.getRpcAddress()); } catch (StorageEngineException | MetadataException e) { if (IoTDBDescriptor.getInstance().getConfig().isEnableStatMonitor()) { StatMonitor.getInstance().updateFailedStatValue(); diff --git a/server/src/main/java/org/apache/iotdb/db/service/IoTDB.java b/server/src/main/java/org/apache/iotdb/db/service/IoTDB.java index b3442a3..7ad371a 100644 --- a/server/src/main/java/org/apache/iotdb/db/service/IoTDB.java +++ b/server/src/main/java/org/apache/iotdb/db/service/IoTDB.java @@ -53,14 +53,14 @@ public class IoTDB implements IoTDBMBean { private static final Logger logger = LoggerFactory.getLogger(IoTDB.class); private final String mbeanName = String.format("%s:%s=%s", IoTDBConstant.IOTDB_PACKAGE, IoTDBConstant.JMX_TYPE, "IoTDB"); - private RegisterManager registerManager = new RegisterManager(); + private final RegisterManager registerManager = new RegisterManager(); public static MManager metaManager = MManager.getInstance(); public static IoTDB getInstance() { return IoTDBHolder.INSTANCE; } - public static MetricManager serverMetricManager = MetricService.getMetric("iotdb"); + public static final MetricManager serverMetricManager = MetricService.getMetricManager(); public static void main(String[] args) { if (args.length > 0) { @@ -153,6 +153,7 @@ public class IoTDB implements IoTDBMBean { logger.info("Deactivating IoTDB..."); registerManager.deregisterAll(); JMXService.deregisterMBean(mbeanName); + MetricService.stop(); logger.info("IoTDB is deactivated."); } diff --git a/server/src/main/java/org/apache/iotdb/db/service/TSServiceImpl.java b/server/src/main/java/org/apache/iotdb/db/service/TSServiceImpl.java index e4fd01c..3a02261 100644 --- a/server/src/main/java/org/apache/iotdb/db/service/TSServiceImpl.java +++ b/server/src/main/java/org/apache/iotdb/db/service/TSServiceImpl.java @@ -84,7 +84,6 @@ import org.apache.iotdb.db.tools.watermark.WatermarkEncoder; import org.apache.iotdb.db.utils.FilePathUtils; import org.apache.iotdb.db.utils.QueryDataSetUtils; import org.apache.iotdb.db.utils.SchemaUtils; -import org.apache.iotdb.metrics.type.Counter; import org.apache.iotdb.rpc.RpcUtils; import org.apache.iotdb.rpc.TSStatusCode; import org.apache.iotdb.service.rpc.thrift.ServerProperties; @@ -212,8 +211,6 @@ public class TSServiceImpl implements TSIService.Iface, ServerContext { private QueryTimeManager queryTimeManager = QueryTimeManager.getInstance(); - Counter counter = IoTDB.serverMetricManager.counter("request_total", "user", "root"); - public TSServiceImpl() throws QueryProcessException { processor = new Planner(); executor = new PlanExecutor(); @@ -502,6 +499,8 @@ public class TSServiceImpl implements TSIService.Iface, ServerContext { processor.parseSQLToPhysicalPlan( statement, sessionIdZoneIdMap.get(req.getSessionId()), req.fetchSize); + physicalPlan.setLoginUserName(sessionIdUsernameMap.get(req.getSessionId())); + return physicalPlan.isQuery() ? internalExecuteQueryStatement( statement, @@ -528,6 +527,8 @@ public class TSServiceImpl implements TSIService.Iface, ServerContext { processor.parseSQLToPhysicalPlan( statement, sessionIdZoneIdMap.get(req.getSessionId()), req.fetchSize); + physicalPlan.setLoginUserName(sessionIdUsernameMap.get(req.getSessionId())); + return physicalPlan.isQuery() ? internalExecuteQueryStatement( statement, @@ -553,6 +554,7 @@ public class TSServiceImpl implements TSIService.Iface, ServerContext { PhysicalPlan physicalPlan = processor.rawDataQueryReqToPhysicalPlan(req, sessionIdZoneIdMap.get(req.getSessionId())); + physicalPlan.setLoginUserName(sessionIdUsernameMap.get(req.getSessionId())); return physicalPlan.isQuery() ? internalExecuteQueryStatement( "", @@ -697,6 +699,25 @@ public class TSServiceImpl implements TSIService.Iface, ServerContext { if (!(plan instanceof ShowQueryProcesslistPlan)) { queryTimeManager.unRegisterQuery(queryId); } + + LOGGER.info( + "{}, {}, {}", + plan.getOperatorType().name(), + plan.getLoginUserName(), + config.getRpcAddress()); + + IoTDB.serverMetricManager.timer( + System.currentTimeMillis() - startTime, + TimeUnit.MILLISECONDS, + "query_latency", + "sg", + "root", + "query_type", + plan.getOperatorType().name(), + "user", + plan.getLoginUserName(), + "host", + config.getRpcAddress()); return resp; } catch (Exception e) { releaseQueryResourceNoExceptions(queryId); @@ -1148,7 +1169,6 @@ public class TSServiceImpl implements TSIService.Iface, ServerContext { req.deviceIds.get(0), req.getTimestamps().get(0)); } - counter.inc(); List<TSStatus> statusList = new ArrayList<>(); @@ -1176,6 +1196,18 @@ public class TSServiceImpl implements TSIService.Iface, ServerContext { } } + long startTime = System.currentTimeMillis(); + IoTDB.serverMetricManager.timer( + System.currentTimeMillis() - startTime, + TimeUnit.MILLISECONDS, + "insert_records_latency", + "sg", + "root", + "user", + sessionIdUsernameMap.get(req.getSessionId()), + "host", + config.getRpcAddress()); + return isAllSuccessful ? RpcUtils.getStatus(TSStatusCode.SUCCESS_STATUS) : RpcUtils.getStatus(statusList); @@ -1657,6 +1689,7 @@ public class TSServiceImpl implements TSIService.Iface, ServerContext { private TSStatus checkAuthority(PhysicalPlan plan, long sessionId) { List<PartialPath> paths = plan.getPaths(); + plan.setLoginUserName(sessionIdUsernameMap.get(sessionId)); try { if (!checkAuthorization(paths, plan, sessionIdUsernameMap.get(sessionId))) { return RpcUtils.getStatus(
