forked from hugegraph/hugegraph-sync
feat(api): support metric API Prometheus format & add statistic metric api (#2286)
This commit is contained in:
parent
4bb48814bb
commit
176637c47a
|
|
@ -27,6 +27,7 @@ import org.apache.hugegraph.HugeException;
|
|||
import org.apache.hugegraph.HugeGraph;
|
||||
import org.apache.hugegraph.core.GraphManager;
|
||||
import org.apache.hugegraph.define.Checkable;
|
||||
import org.apache.hugegraph.exception.NotFoundException;
|
||||
import org.apache.hugegraph.metrics.MetricsUtil;
|
||||
import org.apache.hugegraph.util.E;
|
||||
import org.apache.hugegraph.util.InsertionOrderUtil;
|
||||
|
|
@ -38,7 +39,6 @@ import com.codahale.metrics.Meter;
|
|||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import jakarta.ws.rs.ForbiddenException;
|
||||
import jakarta.ws.rs.NotFoundException;
|
||||
import jakarta.ws.rs.NotSupportedException;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
|
||||
|
|
@ -49,6 +49,7 @@ public class API {
|
|||
public static final String APPLICATION_JSON = MediaType.APPLICATION_JSON;
|
||||
public static final String APPLICATION_JSON_WITH_CHARSET =
|
||||
APPLICATION_JSON + ";charset=" + CHARSET;
|
||||
public static final String APPLICATION_TEXT_WITH_CHARSET = MediaType.TEXT_PLAIN + ";charset=" + CHARSET;
|
||||
public static final String JSON = MediaType.APPLICATION_JSON_TYPE
|
||||
.getSubtype();
|
||||
public static final String ACTION_APPEND = "append";
|
||||
|
|
|
|||
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* 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.hugegraph.api.filter;
|
||||
|
||||
import static org.apache.hugegraph.api.filter.PathFilter.REQUEST_TIME;
|
||||
import static org.apache.hugegraph.metrics.MetricsUtil.METRICS_PATH_FAILED_COUNTER;
|
||||
import static org.apache.hugegraph.metrics.MetricsUtil.METRICS_PATH_RESPONSE_TIME_HISTOGRAM;
|
||||
import static org.apache.hugegraph.metrics.MetricsUtil.METRICS_PATH_SUCCESS_COUNTER;
|
||||
import static org.apache.hugegraph.metrics.MetricsUtil.METRICS_PATH_TOTAL_COUNTER;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.hugegraph.metrics.MetricsUtil;
|
||||
|
||||
import jakarta.inject.Singleton;
|
||||
import jakarta.ws.rs.container.ContainerRequestContext;
|
||||
import jakarta.ws.rs.container.ContainerResponseContext;
|
||||
import jakarta.ws.rs.container.ContainerResponseFilter;
|
||||
import jakarta.ws.rs.ext.Provider;
|
||||
|
||||
|
||||
@Provider
|
||||
@Singleton
|
||||
public class AccessLogFilter implements ContainerResponseFilter {
|
||||
|
||||
private static final String DELIMETER = "/";
|
||||
|
||||
/**
|
||||
* Use filter to log request info
|
||||
*
|
||||
* @param requestContext requestContext
|
||||
* @param responseContext responseContext
|
||||
*/
|
||||
@Override
|
||||
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
|
||||
// Grab corresponding request / response info from context;
|
||||
String method = requestContext.getRequest().getMethod();
|
||||
String path = requestContext.getUriInfo().getPath();
|
||||
String metricsName = join(path, method);
|
||||
|
||||
MetricsUtil.registerCounter(join(metricsName, METRICS_PATH_TOTAL_COUNTER)).inc();
|
||||
if (statusOk(responseContext.getStatus())) {
|
||||
MetricsUtil.registerCounter(join(metricsName, METRICS_PATH_SUCCESS_COUNTER)).inc();
|
||||
} else {
|
||||
MetricsUtil.registerCounter(join(metricsName, METRICS_PATH_FAILED_COUNTER)).inc();
|
||||
}
|
||||
|
||||
// get responseTime
|
||||
Object requestTime = requestContext.getProperty(REQUEST_TIME);
|
||||
if(requestTime!=null){
|
||||
long now = System.currentTimeMillis();
|
||||
long responseTime = (now - (long)requestTime);
|
||||
|
||||
MetricsUtil.registerHistogram(
|
||||
join(metricsName, METRICS_PATH_RESPONSE_TIME_HISTOGRAM))
|
||||
.update(responseTime);
|
||||
}
|
||||
}
|
||||
|
||||
private String join(String path1, String path2) {
|
||||
return String.join(DELIMETER, path1, path2);
|
||||
}
|
||||
|
||||
private boolean statusOk(int status){
|
||||
return status == 200 || status == 201 || status == 202;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* 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.hugegraph.api.filter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import jakarta.inject.Singleton;
|
||||
import jakarta.ws.rs.container.ContainerRequestContext;
|
||||
import jakarta.ws.rs.container.ContainerRequestFilter;
|
||||
import jakarta.ws.rs.container.PreMatching;
|
||||
import jakarta.ws.rs.ext.Provider;
|
||||
|
||||
@Provider
|
||||
@Singleton
|
||||
@PreMatching
|
||||
public class PathFilter implements ContainerRequestFilter {
|
||||
|
||||
public static final String REQUEST_TIME = "request_time";
|
||||
|
||||
@Override
|
||||
public void filter(ContainerRequestContext context)
|
||||
throws IOException {
|
||||
context.setProperty(REQUEST_TIME, System.currentTimeMillis());
|
||||
}
|
||||
}
|
||||
|
|
@ -19,33 +19,66 @@ package org.apache.hugegraph.api.metrics;
|
|||
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
import static org.apache.hugegraph.metrics.MetricsUtil.COUNT_ATTR;
|
||||
import static org.apache.hugegraph.metrics.MetricsUtil.END_LSTR;
|
||||
import static org.apache.hugegraph.metrics.MetricsUtil.FIFT_MIN_RATE_ATRR;
|
||||
import static org.apache.hugegraph.metrics.MetricsUtil.FIVE_MIN_RATE_ATRR;
|
||||
import static org.apache.hugegraph.metrics.MetricsUtil.GAUGE_TYPE;
|
||||
import static org.apache.hugegraph.metrics.MetricsUtil.HISTOGRAM_TYPE;
|
||||
import static org.apache.hugegraph.metrics.MetricsUtil.LEFT_NAME_STR;
|
||||
import static org.apache.hugegraph.metrics.MetricsUtil.MEAN_RATE_ATRR;
|
||||
import static org.apache.hugegraph.metrics.MetricsUtil.METRICS_PATH_FAILED_COUNTER;
|
||||
import static org.apache.hugegraph.metrics.MetricsUtil.METRICS_PATH_RESPONSE_TIME_HISTOGRAM;
|
||||
import static org.apache.hugegraph.metrics.MetricsUtil.METRICS_PATH_SUCCESS_COUNTER;
|
||||
import static org.apache.hugegraph.metrics.MetricsUtil.METRICS_PATH_TOTAL_COUNTER;
|
||||
import static org.apache.hugegraph.metrics.MetricsUtil.ONE_MIN_RATE_ATRR;
|
||||
import static org.apache.hugegraph.metrics.MetricsUtil.PROM_HELP_NAME;
|
||||
import static org.apache.hugegraph.metrics.MetricsUtil.RIGHT_NAME_STR;
|
||||
import static org.apache.hugegraph.metrics.MetricsUtil.SPACE_STR;
|
||||
import static org.apache.hugegraph.metrics.MetricsUtil.STR_HELP;
|
||||
import static org.apache.hugegraph.metrics.MetricsUtil.STR_TYPE;
|
||||
import static org.apache.hugegraph.metrics.MetricsUtil.UNTYPED;
|
||||
import static org.apache.hugegraph.metrics.MetricsUtil.VERSION_STR;
|
||||
import static org.apache.hugegraph.metrics.MetricsUtil.exportSnapshot;
|
||||
import static org.apache.hugegraph.metrics.MetricsUtil.replaceDotDashInKey;
|
||||
import static org.apache.hugegraph.metrics.MetricsUtil.replaceSlashInKey;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.hugegraph.HugeGraph;
|
||||
import org.apache.hugegraph.api.API;
|
||||
import org.apache.hugegraph.backend.store.BackendMetrics;
|
||||
import org.apache.hugegraph.core.GraphManager;
|
||||
import org.apache.hugegraph.metrics.MetricsKeys;
|
||||
import org.apache.hugegraph.metrics.MetricsModule;
|
||||
import org.apache.hugegraph.metrics.MetricsUtil;
|
||||
import org.apache.hugegraph.metrics.ServerReporter;
|
||||
import org.apache.hugegraph.metrics.SystemMetrics;
|
||||
import org.apache.hugegraph.util.InsertionOrderUtil;
|
||||
import org.apache.hugegraph.util.JsonUtil;
|
||||
import org.apache.hugegraph.util.Log;
|
||||
import org.apache.hugegraph.version.ApiVersion;
|
||||
import org.apache.tinkerpop.gremlin.server.util.MetricManager;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import com.codahale.metrics.Counter;
|
||||
import com.codahale.metrics.Gauge;
|
||||
import com.codahale.metrics.Histogram;
|
||||
import com.codahale.metrics.Meter;
|
||||
import com.codahale.metrics.Metric;
|
||||
import com.codahale.metrics.annotation.Timed;
|
||||
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.security.RolesAllowed;
|
||||
import jakarta.inject.Singleton;
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.Produces;
|
||||
import jakarta.ws.rs.QueryParam;
|
||||
import jakarta.ws.rs.core.Context;
|
||||
|
||||
import org.apache.hugegraph.core.GraphManager;
|
||||
import org.apache.hugegraph.metrics.MetricsModule;
|
||||
import org.apache.hugegraph.metrics.ServerReporter;
|
||||
import org.apache.hugegraph.metrics.SystemMetrics;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import org.apache.hugegraph.HugeGraph;
|
||||
import org.apache.hugegraph.api.API;
|
||||
import org.apache.hugegraph.backend.store.BackendMetrics;
|
||||
import org.apache.hugegraph.util.InsertionOrderUtil;
|
||||
import org.apache.hugegraph.util.JsonUtil;
|
||||
import org.apache.hugegraph.util.Log;
|
||||
import com.codahale.metrics.Metric;
|
||||
import com.codahale.metrics.annotation.Timed;
|
||||
|
||||
@Singleton
|
||||
@Path("metrics")
|
||||
@Tag(name = "MetricsAPI")
|
||||
|
|
@ -53,12 +86,14 @@ public class MetricsAPI extends API {
|
|||
|
||||
private static final Logger LOG = Log.logger(MetricsAPI.class);
|
||||
|
||||
private SystemMetrics systemMetrics;
|
||||
private static final String JSON_STR = "json";
|
||||
|
||||
static {
|
||||
JsonUtil.registerModule(new MetricsModule(SECONDS, MILLISECONDS, false));
|
||||
}
|
||||
|
||||
private final SystemMetrics systemMetrics;
|
||||
|
||||
public MetricsAPI() {
|
||||
this.systemMetrics = new SystemMetrics();
|
||||
}
|
||||
|
|
@ -94,21 +129,6 @@ public class MetricsAPI extends API {
|
|||
return JsonUtil.toJson(results);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Timed
|
||||
@Produces(APPLICATION_JSON_WITH_CHARSET)
|
||||
@RolesAllowed({"admin", "$owner= $action=metrics_read"})
|
||||
public String all() {
|
||||
ServerReporter reporter = ServerReporter.instance();
|
||||
Map<String, Map<String, ? extends Metric>> result = new LinkedHashMap<>();
|
||||
result.put("gauges", reporter.gauges());
|
||||
result.put("counters", reporter.counters());
|
||||
result.put("histograms", reporter.histograms());
|
||||
result.put("meters", reporter.meters());
|
||||
result.put("timers", reporter.timers());
|
||||
return JsonUtil.toJson(result);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Timed
|
||||
@Path("gauges")
|
||||
|
|
@ -158,4 +178,242 @@ public class MetricsAPI extends API {
|
|||
ServerReporter reporter = ServerReporter.instance();
|
||||
return JsonUtil.toJson(reporter.timers());
|
||||
}
|
||||
|
||||
@GET
|
||||
@Timed
|
||||
@Produces(APPLICATION_TEXT_WITH_CHARSET)
|
||||
@RolesAllowed({"admin", "$owner= $action=metrics_read"})
|
||||
public String all(@Context GraphManager manager,
|
||||
@QueryParam("type") String type) {
|
||||
if (type != null && type.equals(JSON_STR)) {
|
||||
return baseMetricAll();
|
||||
} else {
|
||||
return baseMetricPrometheusAll();
|
||||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("statistics")
|
||||
@Timed
|
||||
@Produces(APPLICATION_TEXT_WITH_CHARSET)
|
||||
@RolesAllowed({"admin", "$owner= $action=metrics_read"})
|
||||
public String statistics(@QueryParam("type") String type) {
|
||||
Map<String, Map<String, Object>> metricMap = statistics();
|
||||
|
||||
if (type != null && type.equals(JSON_STR)) {
|
||||
return JsonUtil.toJson(metricMap);
|
||||
}
|
||||
return statisticsProm(metricMap);
|
||||
}
|
||||
|
||||
public String baseMetricAll() {
|
||||
ServerReporter reporter = ServerReporter.instance();
|
||||
Map<String, Map<String, ? extends Metric>> result = new LinkedHashMap<>();
|
||||
result.put("gauges", reporter.gauges());
|
||||
result.put("counters", reporter.counters());
|
||||
result.put("histograms", reporter.histograms());
|
||||
result.put("meters", reporter.meters());
|
||||
result.put("timers", reporter.timers());
|
||||
return JsonUtil.toJson(result);
|
||||
}
|
||||
|
||||
private String baseMetricPrometheusAll() {
|
||||
StringBuilder promMetric = new StringBuilder();
|
||||
ServerReporter reporter = ServerReporter.instance();
|
||||
String helpName = PROM_HELP_NAME;
|
||||
// build version info
|
||||
promMetric.append(STR_HELP)
|
||||
.append(helpName).append(END_LSTR);
|
||||
promMetric.append(STR_TYPE)
|
||||
.append(helpName)
|
||||
.append(SPACE_STR + UNTYPED + END_LSTR);
|
||||
promMetric.append(helpName)
|
||||
.append(VERSION_STR)
|
||||
.append(ApiVersion.VERSION.toString()).append("\",}")
|
||||
.append(SPACE_STR + "1.0" + END_LSTR);
|
||||
|
||||
// build gauges metric info
|
||||
for (String key : reporter.gauges().keySet()) {
|
||||
final Gauge<?> gauge
|
||||
= reporter.gauges().get(key);
|
||||
if (gauge != null) {
|
||||
helpName = replaceDotDashInKey(key);
|
||||
promMetric.append(STR_HELP)
|
||||
.append(helpName).append(END_LSTR);
|
||||
promMetric.append(STR_TYPE)
|
||||
.append(helpName).append(SPACE_STR + GAUGE_TYPE + END_LSTR);
|
||||
promMetric.append(helpName)
|
||||
.append(SPACE_STR + gauge.getValue() + END_LSTR);
|
||||
}
|
||||
}
|
||||
|
||||
// build histograms metric info
|
||||
for (String histogramkey : reporter.histograms().keySet()) {
|
||||
final Histogram histogram = reporter.histograms().get(histogramkey);
|
||||
if (histogram != null) {
|
||||
helpName = replaceDotDashInKey(histogramkey);
|
||||
promMetric.append(STR_HELP)
|
||||
.append(helpName).append(END_LSTR);
|
||||
promMetric.append(STR_TYPE)
|
||||
.append(helpName)
|
||||
.append(SPACE_STR + HISTOGRAM_TYPE + END_LSTR);
|
||||
|
||||
promMetric.append(helpName)
|
||||
.append(COUNT_ATTR)
|
||||
.append(histogram.getCount() + END_LSTR);
|
||||
promMetric.append(
|
||||
exportSnapshot(helpName, histogram.getSnapshot()));
|
||||
}
|
||||
}
|
||||
|
||||
// build meters metric info
|
||||
for (String meterkey : reporter.meters().keySet()) {
|
||||
final Meter metric = reporter.meters().get(meterkey);
|
||||
if (metric != null) {
|
||||
helpName = replaceDotDashInKey(meterkey);
|
||||
promMetric.append(STR_HELP)
|
||||
.append(helpName).append(END_LSTR);
|
||||
promMetric.append(STR_TYPE)
|
||||
.append(helpName)
|
||||
.append(SPACE_STR + HISTOGRAM_TYPE + END_LSTR);
|
||||
|
||||
promMetric.append(helpName)
|
||||
.append(COUNT_ATTR)
|
||||
.append(metric.getCount() + END_LSTR);
|
||||
promMetric.append(helpName)
|
||||
.append(MEAN_RATE_ATRR)
|
||||
.append(metric.getMeanRate() + END_LSTR);
|
||||
promMetric.append(helpName)
|
||||
.append(ONE_MIN_RATE_ATRR)
|
||||
.append(metric.getOneMinuteRate() + END_LSTR);
|
||||
promMetric.append(helpName)
|
||||
.append(FIVE_MIN_RATE_ATRR)
|
||||
.append(metric.getFiveMinuteRate() + END_LSTR);
|
||||
promMetric.append(helpName)
|
||||
.append(FIFT_MIN_RATE_ATRR)
|
||||
.append(metric.getFifteenMinuteRate() + END_LSTR);
|
||||
}
|
||||
}
|
||||
|
||||
// build timer metric info
|
||||
for (String timerkey : reporter.timers().keySet()) {
|
||||
final com.codahale.metrics.Timer timer = reporter.timers()
|
||||
.get(timerkey);
|
||||
if (timer != null) {
|
||||
helpName = replaceDotDashInKey(timerkey);
|
||||
promMetric.append(STR_HELP)
|
||||
.append(helpName).append(END_LSTR);
|
||||
promMetric.append(STR_TYPE)
|
||||
.append(helpName)
|
||||
.append(SPACE_STR + HISTOGRAM_TYPE + END_LSTR);
|
||||
|
||||
promMetric.append(helpName)
|
||||
.append(COUNT_ATTR)
|
||||
.append(timer.getCount() + END_LSTR);
|
||||
promMetric.append(helpName)
|
||||
.append(ONE_MIN_RATE_ATRR)
|
||||
.append(timer.getOneMinuteRate() + END_LSTR);
|
||||
promMetric.append(helpName)
|
||||
.append(FIVE_MIN_RATE_ATRR)
|
||||
.append(timer.getFiveMinuteRate() + END_LSTR);
|
||||
promMetric.append(helpName)
|
||||
.append(FIFT_MIN_RATE_ATRR)
|
||||
.append(timer.getFifteenMinuteRate() + END_LSTR);
|
||||
promMetric.append(
|
||||
exportSnapshot(helpName, timer.getSnapshot()));
|
||||
}
|
||||
}
|
||||
|
||||
MetricsUtil.writePrometheusFormat(promMetric, MetricManager.INSTANCE.getRegistry());
|
||||
|
||||
return promMetric.toString();
|
||||
}
|
||||
|
||||
private Map<String, Map<String, Object>> statistics() {
|
||||
Map<String, Map<String, Object>> metricsMap = new HashMap<>();
|
||||
ServerReporter reporter = ServerReporter.instance();
|
||||
for (Map.Entry<String, Histogram> entry : reporter.histograms().entrySet()) {
|
||||
// entryKey = path/method/responseTimeHistogram
|
||||
String entryKey = entry.getKey();
|
||||
String[] split = entryKey.split("/");
|
||||
String lastWord = split[split.length - 1];
|
||||
if (!lastWord.equals(METRICS_PATH_RESPONSE_TIME_HISTOGRAM)) {
|
||||
// original metrics dont report
|
||||
continue;
|
||||
}
|
||||
// metricsName = path/method
|
||||
String metricsName =
|
||||
entryKey.substring(0, entryKey.length() - lastWord.length() - 1);
|
||||
|
||||
Counter totalCounter = reporter.counters().get(
|
||||
joinWithSlash(metricsName, METRICS_PATH_TOTAL_COUNTER));
|
||||
Counter failedCounter = reporter.counters().get(
|
||||
joinWithSlash(metricsName, METRICS_PATH_FAILED_COUNTER));
|
||||
Counter successCounter = reporter.counters().get(
|
||||
joinWithSlash(metricsName, METRICS_PATH_SUCCESS_COUNTER));
|
||||
|
||||
|
||||
Histogram histogram = entry.getValue();
|
||||
Map<String, Object> entryMetricsMap = new HashMap<>();
|
||||
entryMetricsMap.put(MetricsKeys.MAX_RESPONSE_TIME.name(),
|
||||
histogram.getSnapshot().getMax());
|
||||
entryMetricsMap.put(MetricsKeys.MEAN_RESPONSE_TIME.name(),
|
||||
histogram.getSnapshot().getMean());
|
||||
|
||||
entryMetricsMap.put(MetricsKeys.TOTAL_REQUEST.name(),
|
||||
totalCounter.getCount());
|
||||
|
||||
if (failedCounter == null) {
|
||||
entryMetricsMap.put(MetricsKeys.FAILED_REQUEST.name(), 0);
|
||||
} else {
|
||||
entryMetricsMap.put(MetricsKeys.FAILED_REQUEST.name(),
|
||||
failedCounter.getCount());
|
||||
}
|
||||
|
||||
if (successCounter == null) {
|
||||
entryMetricsMap.put(MetricsKeys.SUCCESS_REQUEST.name(), 0);
|
||||
} else {
|
||||
entryMetricsMap.put(MetricsKeys.SUCCESS_REQUEST.name(),
|
||||
successCounter.getCount());
|
||||
}
|
||||
|
||||
metricsMap.put(metricsName, entryMetricsMap);
|
||||
|
||||
}
|
||||
return metricsMap;
|
||||
}
|
||||
|
||||
private String statisticsProm(Map<String, Map<String, Object>> metricMap) {
|
||||
StringBuilder promMetric = new StringBuilder();
|
||||
|
||||
// build version info
|
||||
promMetric.append(STR_HELP)
|
||||
.append(PROM_HELP_NAME).append(END_LSTR);
|
||||
promMetric.append(STR_TYPE)
|
||||
.append(PROM_HELP_NAME)
|
||||
.append(SPACE_STR + UNTYPED + END_LSTR);
|
||||
promMetric.append(PROM_HELP_NAME)
|
||||
.append(VERSION_STR)
|
||||
.append(ApiVersion.VERSION.toString()).append("\",}")
|
||||
.append(SPACE_STR + "1.0" + END_LSTR);
|
||||
|
||||
for (String methodKey : metricMap.keySet()) {
|
||||
String metricName = replaceSlashInKey(methodKey);
|
||||
promMetric.append(STR_HELP)
|
||||
.append(metricName).append(END_LSTR);
|
||||
promMetric.append(STR_TYPE)
|
||||
.append(metricName).append(SPACE_STR + GAUGE_TYPE + END_LSTR);
|
||||
Map<String, Object> itemMetricMap = metricMap.get(methodKey);
|
||||
for (String labelName : itemMetricMap.keySet()) {
|
||||
promMetric.append(metricName).append(LEFT_NAME_STR).append(labelName)
|
||||
.append(RIGHT_NAME_STR).append(itemMetricMap.get(labelName))
|
||||
.append(END_LSTR);
|
||||
}
|
||||
}
|
||||
return promMetric.toString();
|
||||
}
|
||||
|
||||
private String joinWithSlash(String path1, String path2) {
|
||||
return String.join("/", path1, path2);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* 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.hugegraph.metrics;
|
||||
|
||||
public enum MetricsKeys {
|
||||
|
||||
MAX_RESPONSE_TIME(1, "max_response_time"),
|
||||
|
||||
MEAN_RESPONSE_TIME(2, "mean_response_time"),
|
||||
|
||||
TOTAL_REQUEST(3, "total_request"),
|
||||
|
||||
FAILED_REQUEST(4, "failed_request"),
|
||||
|
||||
SUCCESS_REQUEST(5, "success_request");
|
||||
|
||||
private final byte code;
|
||||
private final String name;
|
||||
|
||||
MetricsKeys(int code, String name) {
|
||||
assert code < 256;
|
||||
this.code = (byte) code;
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
|
@ -24,12 +24,45 @@ import com.codahale.metrics.Gauge;
|
|||
import com.codahale.metrics.Histogram;
|
||||
import com.codahale.metrics.Meter;
|
||||
import com.codahale.metrics.MetricRegistry;
|
||||
import com.codahale.metrics.Snapshot;
|
||||
import com.codahale.metrics.Timer;
|
||||
|
||||
public class MetricsUtil {
|
||||
|
||||
private static final MetricRegistry REGISTRY =
|
||||
MetricManager.INSTANCE.getRegistry();
|
||||
public static final String METRICS_PATH_TOTAL_COUNTER = "TOTAL_COUNTER";
|
||||
public static final String METRICS_PATH_FAILED_COUNTER = "FAILED_COUNTER";
|
||||
public static final String METRICS_PATH_SUCCESS_COUNTER = "SUCCESS_COUNTER";
|
||||
public static final String METRICS_PATH_RESPONSE_TIME_HISTOGRAM =
|
||||
"RESPONSE_TIME_HISTOGRAM";
|
||||
public static final String P75_ATTR = "{name=\"p75\",} ";
|
||||
public static final String P95_ATTR = "{name=\"p95\",} ";
|
||||
public static final String P98_ATTR = "{name=\"p98\",} ";
|
||||
public static final String P99_ATTR = "{name=\"p99\",} ";
|
||||
public static final String P999_ATTR = "{name=\"p999\",} ";
|
||||
public static final String MEAN_RATE_ATRR = "{name=\"mean_rate\",} ";
|
||||
public static final String ONE_MIN_RATE_ATRR = "{name=\"m1_rate\",} ";
|
||||
public static final String FIVE_MIN_RATE_ATRR = "{name=\"m5_rate\",} ";
|
||||
public static final String FIFT_MIN_RATE_ATRR = "{name=\"m15_rate\",} ";
|
||||
public static final MetricRegistry REGISTRY = MetricManager.INSTANCE.getRegistry();
|
||||
public static final String STR_HELP = "# HELP ";
|
||||
public static final String STR_TYPE = "# TYPE ";
|
||||
public static final String HISTOGRAM_TYPE = "histogram";
|
||||
public static final String UNTYPED = "untyped";
|
||||
public static final String GAUGE_TYPE = "gauge";
|
||||
public static final String END_LSTR = "\n";
|
||||
public static final String SPACE_STR = " ";
|
||||
public static final String VERSION_STR = "{version=\"";
|
||||
public static final String COUNT_ATTR = "{name=\"count\",} ";
|
||||
public static final String MIN_ATTR = "{name=\"min\",} ";
|
||||
public static final String MAX_ATTR = "{name=\"max\",} ";
|
||||
public static final String MEAN_ATTR = "{name=\"mean\",} ";
|
||||
public static final String STDDEV_ATTR = "{name=\"stddev\",} ";
|
||||
public static final String P50_ATTR = "{name=\"p50\",} ";
|
||||
|
||||
public static final String LEFT_NAME_STR = "{name=";
|
||||
public static final String RIGHT_NAME_STR = ",} ";
|
||||
public static final String PROM_HELP_NAME = "hugegraph_info";
|
||||
|
||||
|
||||
public static <T> Gauge<T> registerGauge(Class<?> clazz, String name,
|
||||
Gauge<T> gauge) {
|
||||
|
|
@ -40,10 +73,18 @@ public class MetricsUtil {
|
|||
return REGISTRY.counter(MetricRegistry.name(clazz, name));
|
||||
}
|
||||
|
||||
public static Counter registerCounter(String name) {
|
||||
return REGISTRY.counter(MetricRegistry.name(name));
|
||||
}
|
||||
|
||||
public static Histogram registerHistogram(Class<?> clazz, String name) {
|
||||
return REGISTRY.histogram(MetricRegistry.name(clazz, name));
|
||||
}
|
||||
|
||||
public static Histogram registerHistogram(String name) {
|
||||
return REGISTRY.histogram(name);
|
||||
}
|
||||
|
||||
public static Meter registerMeter(Class<?> clazz, String name) {
|
||||
return REGISTRY.meter(MetricRegistry.name(clazz, name));
|
||||
}
|
||||
|
|
@ -51,4 +92,124 @@ public class MetricsUtil {
|
|||
public static Timer registerTimer(Class<?> clazz, String name) {
|
||||
return REGISTRY.timer(MetricRegistry.name(clazz, name));
|
||||
}
|
||||
|
||||
public static String replaceDotDashInKey(String orgKey) {
|
||||
return orgKey.replace(".", "_").replace("-", "_");
|
||||
}
|
||||
|
||||
public static String replaceSlashInKey(String orgKey) {
|
||||
return orgKey.replace("/", "_");
|
||||
}
|
||||
|
||||
public static void writePrometheusFormat(StringBuilder promeMetrics, MetricRegistry registry) {
|
||||
// gauges
|
||||
registry.getGauges().forEach((key, gauge) -> {
|
||||
if (gauge != null) {
|
||||
String helpName = replaceDotDashInKey(key);
|
||||
promeMetrics.append(STR_HELP)
|
||||
.append(helpName).append(END_LSTR);
|
||||
promeMetrics.append(STR_TYPE)
|
||||
.append(helpName).append(SPACE_STR + GAUGE_TYPE + END_LSTR);
|
||||
promeMetrics.append(helpName).append(SPACE_STR).append(gauge.getValue())
|
||||
.append(END_LSTR);
|
||||
}
|
||||
});
|
||||
|
||||
// histograms
|
||||
registry.getHistograms().forEach((key, histogram) -> {
|
||||
if (histogram != null) {
|
||||
String helpName = replaceDotDashInKey(key);
|
||||
promeMetrics.append(STR_HELP)
|
||||
.append(helpName).append(END_LSTR);
|
||||
promeMetrics.append(STR_TYPE)
|
||||
.append(helpName)
|
||||
.append(SPACE_STR + HISTOGRAM_TYPE + END_LSTR);
|
||||
|
||||
promeMetrics.append(helpName)
|
||||
.append(COUNT_ATTR).append(histogram.getCount()).append(END_LSTR);
|
||||
promeMetrics.append(
|
||||
exportSnapshot(helpName, histogram.getSnapshot()));
|
||||
}
|
||||
});
|
||||
|
||||
// meters
|
||||
registry.getMeters().forEach((key, metric) -> {
|
||||
if (metric != null) {
|
||||
String helpName = replaceDotDashInKey(key);
|
||||
promeMetrics.append(STR_HELP)
|
||||
.append(helpName).append(END_LSTR);
|
||||
promeMetrics.append(STR_TYPE)
|
||||
.append(helpName)
|
||||
.append(SPACE_STR + HISTOGRAM_TYPE + END_LSTR);
|
||||
|
||||
promeMetrics.append(helpName)
|
||||
.append(COUNT_ATTR).append(metric.getCount()).append(END_LSTR);
|
||||
promeMetrics.append(helpName)
|
||||
.append(MEAN_RATE_ATRR).append(metric.getMeanRate()).append(END_LSTR);
|
||||
promeMetrics.append(helpName)
|
||||
.append(ONE_MIN_RATE_ATRR).append(metric.getOneMinuteRate())
|
||||
.append(END_LSTR);
|
||||
promeMetrics.append(helpName)
|
||||
.append(FIVE_MIN_RATE_ATRR).append(metric.getFiveMinuteRate())
|
||||
.append(END_LSTR);
|
||||
promeMetrics.append(helpName)
|
||||
.append(FIFT_MIN_RATE_ATRR).append(metric.getFifteenMinuteRate())
|
||||
.append(END_LSTR);
|
||||
}
|
||||
});
|
||||
|
||||
// timer
|
||||
registry.getTimers().forEach((key, timer) -> {
|
||||
if (timer != null) {
|
||||
String helpName = replaceDotDashInKey(key);
|
||||
promeMetrics.append(STR_HELP)
|
||||
.append(helpName).append(END_LSTR);
|
||||
promeMetrics.append(STR_TYPE)
|
||||
.append(helpName)
|
||||
.append(SPACE_STR + HISTOGRAM_TYPE + END_LSTR);
|
||||
|
||||
promeMetrics.append(helpName)
|
||||
.append(COUNT_ATTR).append(timer.getCount()).append(END_LSTR);
|
||||
promeMetrics.append(helpName)
|
||||
.append(ONE_MIN_RATE_ATRR).append(timer.getOneMinuteRate())
|
||||
.append(END_LSTR);
|
||||
promeMetrics.append(helpName)
|
||||
.append(FIVE_MIN_RATE_ATRR).append(timer.getFiveMinuteRate())
|
||||
.append(END_LSTR);
|
||||
promeMetrics.append(helpName)
|
||||
.append(FIFT_MIN_RATE_ATRR).append(timer.getFifteenMinuteRate())
|
||||
.append(END_LSTR);
|
||||
promeMetrics.append(
|
||||
exportSnapshot(helpName, timer.getSnapshot()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static String exportSnapshot(final String helpName, final Snapshot snapshot) {
|
||||
if (snapshot == null) {
|
||||
return "";
|
||||
}
|
||||
StringBuilder snapMetrics = new StringBuilder();
|
||||
snapMetrics.append(helpName)
|
||||
.append(MIN_ATTR).append(snapshot.getMin()).append(END_LSTR);
|
||||
snapMetrics.append(helpName)
|
||||
.append(MAX_ATTR).append(snapshot.getMax()).append(END_LSTR);
|
||||
snapMetrics.append(helpName)
|
||||
.append(MEAN_ATTR).append(snapshot.getMean()).append(END_LSTR);
|
||||
snapMetrics.append(helpName)
|
||||
.append(STDDEV_ATTR).append(snapshot.getStdDev()).append(END_LSTR);
|
||||
snapMetrics.append(helpName)
|
||||
.append(P50_ATTR).append(snapshot.getMedian()).append(END_LSTR);
|
||||
snapMetrics.append(helpName)
|
||||
.append(P75_ATTR).append(snapshot.get75thPercentile()).append(END_LSTR);
|
||||
snapMetrics.append(helpName)
|
||||
.append(P95_ATTR).append(snapshot.get95thPercentile()).append(END_LSTR);
|
||||
snapMetrics.append(helpName)
|
||||
.append(P98_ATTR).append(snapshot.get98thPercentile()).append(END_LSTR);
|
||||
snapMetrics.append(helpName)
|
||||
.append(P99_ATTR).append(snapshot.get99thPercentile()).append(END_LSTR);
|
||||
snapMetrics.append(helpName)
|
||||
.append(P999_ATTR).append(snapshot.get999thPercentile()).append(END_LSTR);
|
||||
return snapMetrics.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,20 +17,24 @@
|
|||
|
||||
package org.apache.hugegraph.api;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import org.apache.hugegraph.testutil.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.hugegraph.testutil.Assert;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
|
||||
public class MetricsApiTest extends BaseApiTest {
|
||||
|
||||
private static String path = "/metrics";
|
||||
private static final String path = "/metrics";
|
||||
private static final String statisticsPath = path + "/statistics";
|
||||
|
||||
@Test
|
||||
public void testMetricsAll() {
|
||||
Response r = client().get(path);
|
||||
public void testBaseMetricsAll() {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("type", "json");
|
||||
Response r = client().get(path, params);
|
||||
String result = assertResponseStatus(200, r);
|
||||
assertJsonContains(result, "gauges");
|
||||
assertJsonContains(result, "counters");
|
||||
|
|
@ -39,6 +43,26 @@ public class MetricsApiTest extends BaseApiTest {
|
|||
assertJsonContains(result, "timers");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBaseMetricsPromAll() {
|
||||
Response r = client().get(path);
|
||||
assertResponseStatus(200, r);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStatisticsMetricsAll() {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("type", "json");
|
||||
Response r = client().get(path);
|
||||
assertResponseStatus(200, r);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStatisticsMetricsPromAll() {
|
||||
Response r = client().get(statisticsPath);
|
||||
assertResponseStatus(200, r);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMetricsSystem() {
|
||||
Response r = client().get(path, "system");
|
||||
|
|
|
|||
Loading…
Reference in New Issue