Skip to content

Commit

Permalink
Display indicator data in KEY, VALUE format (#12273)
Browse files Browse the repository at this point in the history
* metrics default.

* check style

* test fail

* metrics default update

* qos

* test

* default metrics reporter

* native image

* If no specific metrics type is configured and there is no Prometheus dependency in the dependencies.

* prometheus set

* MeterRegistry dependency check

* errorcode check fail

* CHECKSTYLE

* 1.null check
2.method replace

* default metricsreport register

* format response

---------

Co-authored-by: Albumen Kevin <jhq0812@gmail.com>
Co-authored-by: songxiaosheng <songxiaosheng@elastic.link>
  • Loading branch information
3 people authored May 26, 2023
1 parent 50798b9 commit 1697a33
Show file tree
Hide file tree
Showing 12 changed files with 303 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
public interface MetricsConstants {

String PROTOCOL_PROMETHEUS = "prometheus";
String PROTOCOL_DEFAULT = "default";

String TAG_IP = "ip";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
import org.apache.dubbo.metrics.config.event.ConfigCenterEvent;
import org.apache.dubbo.metrics.event.MetricsEventBus;
import org.apache.dubbo.metrics.registry.event.RegistryEvent;
import org.apache.dubbo.metrics.report.DefaultMetricsReporterFactory;
import org.apache.dubbo.metrics.report.MetricsReporter;
import org.apache.dubbo.metrics.report.MetricsReporterFactory;
import org.apache.dubbo.metrics.service.MetricsServiceExporter;
Expand Down Expand Up @@ -92,11 +93,13 @@
import static org.apache.dubbo.common.config.ConfigurationUtils.parseProperties;
import static org.apache.dubbo.common.constants.CommonConstants.REGISTRY_SPLIT_PATTERN;
import static org.apache.dubbo.common.constants.CommonConstants.REMOTE_METADATA_STORAGE_TYPE;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_METRICS_COLLECTOR_EXCEPTION;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_FAILED_EXECUTE_DESTROY;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_FAILED_INIT_CONFIG_CENTER;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_FAILED_START_MODEL;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_REFRESH_INSTANCE_ERROR;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_REGISTER_INSTANCE_ERROR;
import static org.apache.dubbo.common.constants.MetricsConstants.PROTOCOL_DEFAULT;
import static org.apache.dubbo.common.constants.MetricsConstants.PROTOCOL_PROMETHEUS;
import static org.apache.dubbo.common.utils.StringUtils.isEmpty;
import static org.apache.dubbo.common.utils.StringUtils.isNotEmpty;
Expand Down Expand Up @@ -369,25 +372,45 @@ private void initMetricsService() {
}

private void initMetricsReporter() {
if (!isSupportMetrics()) {
return;
}
DefaultMetricsCollector collector =
applicationModel.getBeanFactory().getBean(DefaultMetricsCollector.class);
Optional<MetricsConfig> configOptional = configManager.getMetrics();

// TODO compatible with old usage of metrics, remove protocol check after new metrics is ready for use.
if (!isSupportPrometheus()) {
return;
}
//If no specific metrics type is configured and there is no Prometheus dependency in the dependencies.
MetricsConfig metricsConfig = configOptional.orElse(new MetricsConfig(applicationModel));
if (StringUtils.isBlank(metricsConfig.getProtocol())) {
metricsConfig.setProtocol(PROTOCOL_PROMETHEUS);
metricsConfig.setProtocol(isSupportPrometheus() ? PROTOCOL_PROMETHEUS : PROTOCOL_DEFAULT);
}
collector.setCollectEnabled(true);
collector.collectApplication();
collector.setThreadpoolCollectEnabled(Optional.ofNullable(metricsConfig.getEnableThreadpool()).orElse(true));
MetricsReporterFactory metricsReporterFactory = getExtensionLoader(MetricsReporterFactory.class).getAdaptiveExtension();
MetricsReporter metricsReporter = metricsReporterFactory.createMetricsReporter(metricsConfig.toUrl());
MetricsReporter metricsReporter = null;
try {
metricsReporter = metricsReporterFactory.createMetricsReporter(metricsConfig.toUrl());
} catch (IllegalStateException e) {
if (e.getMessage().startsWith("No such extension org.apache.dubbo.metrics.report.MetricsReporterFactory")) {
logger.warn(COMMON_METRICS_COLLECTOR_EXCEPTION, "", "", e.getMessage());
return;
} else {
throw e;
}
}
metricsReporter.init();
applicationModel.getBeanFactory().registerBean(metricsReporter);
//If the protocol is not the default protocol, the default protocol is also initialized.
if (!PROTOCOL_DEFAULT.equals(metricsConfig.getProtocol())) {
DefaultMetricsReporterFactory defaultMetricsReporterFactory = new DefaultMetricsReporterFactory(applicationModel);
MetricsReporter defaultMetricsReporter = defaultMetricsReporterFactory.createMetricsReporter(metricsConfig.toUrl());
defaultMetricsReporter.init();
applicationModel.getBeanFactory().registerBean(defaultMetricsReporter);
}
}

public boolean isSupportMetrics() {
return isClassPresent("io.micrometer.core.instrument.MeterRegistry");
}

public static boolean isSupportPrometheus() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,8 @@ public interface MetricsReporter {
void refreshData();

String getResponse();

default String getResponseWithName(String metricsName) {
return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*
* 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.dubbo.metrics.report;

import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.Gauge;
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.Timer;
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;

import org.apache.dubbo.common.URL;
import org.apache.dubbo.rpc.model.ApplicationModel;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import java.util.concurrent.TimeUnit;

public class DefaultMetricsReporter extends AbstractMetricsReporter {

SimpleMeterRegistry meterRegistry = new SimpleMeterRegistry();

protected DefaultMetricsReporter(URL url, ApplicationModel applicationModel) {
super(url, applicationModel);
}

@Override
public String getResponse() {
return null;
}

@Override
public String getResponseWithName(String metricsName) {
Map<String, List<Tag>> metricsTags = new HashMap<>();
Map<String, Object> metricsValue = new HashMap<>();
StringBuilder sb = new StringBuilder();
meterRegistry.getMeters().stream().filter(meter -> {
if (meter == null || meter.getId() == null || meter.getId().getName() == null) {
return false;
}
if (metricsName != null) {
return meter.getId().getName().contains(metricsName);
}
return true;
}).forEach(meter -> {
Object value = null;
if (meter instanceof Counter) {
Counter counter = (Counter) meter;
value = counter.count();
}
if (meter instanceof Gauge) {
Gauge gauge = (Gauge) meter;
value = gauge.value();
}
if (meter instanceof Timer) {
Timer timer = (Timer) meter;
value = timer.totalTime(TimeUnit.MILLISECONDS);
}
metricsTags.put(meter.getId().getName(), meter.getId().getTags());
metricsValue.put(meter.getId().getName(), value);
});
metricsValue.forEach((key, value) -> {
sb.append(key).append("{");
List<Tag> tags = metricsTags.get(key);
if (tags != null && tags.size() > 0) {
tags.forEach(tag -> {
sb.append(tag.getKey()).append("=").append(tag.getValue()).append(",");
});
}
sb.append("} ").append(value).append(System.lineSeparator());
});
return sb.toString();
}

@Override
protected void doInit() {
addMeterRegistry(meterRegistry);
}

@Override
protected void doDestroy() {

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* 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.dubbo.metrics.report;

import org.apache.dubbo.common.URL;
import org.apache.dubbo.rpc.model.ApplicationModel;

public class DefaultMetricsReporterFactory extends AbstractMetricsReporterFactory {
private final ApplicationModel applicationModel;

public DefaultMetricsReporterFactory(ApplicationModel applicationModel) {
super(applicationModel);
this.applicationModel = applicationModel;
}

@Override
public MetricsReporter createMetricsReporter(URL url) {
return new DefaultMetricsReporter(url, applicationModel);
}
}
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
default-collector=org.apache.dubbo.metrics.collector.DefaultMetricsCollector
aggregateMetricsCollector=org.apache.dubbo.metrics.collector.AggregateMetricsCollector
histogramMetricsCollector=org.apache.dubbo.metrics.collector.HistogramMetricsCollector
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
default=org.apache.dubbo.metrics.report.DefaultMetricsReporterFactory
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ public boolean logResult() {
private String getResponseByApplication(ApplicationModel applicationModel) {

String response = "MetricsReporter not init";
MetricsReporter metricsReporter = applicationModel.getBeanFactory().getBean(MetricsReporter.class);
MetricsReporter metricsReporter = applicationModel.getBeanFactory().getBean(PrometheusMetricsReporter.class);
if (metricsReporter != null) {
long begin = System.currentTimeMillis();
if (logger.isDebugEnabled()) {
Expand Down
5 changes: 5 additions & 0 deletions dubbo-plugin/dubbo-qos/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -75,5 +75,10 @@
<artifactId>dubbo-qos-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-metrics-default</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/*
* 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.dubbo.qos.command.impl;

import org.apache.dubbo.common.utils.JsonUtils;
import org.apache.dubbo.metrics.report.DefaultMetricsReporter;
import org.apache.dubbo.metrics.report.MetricsReporter;
import org.apache.dubbo.qos.api.BaseCommand;
import org.apache.dubbo.qos.api.Cmd;
import org.apache.dubbo.qos.api.CommandContext;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.apache.dubbo.rpc.model.FrameworkModel;

import java.io.CharArrayReader;
import java.io.IOException;
import java.io.LineNumberReader;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

@Cmd(name = "metrics_default", summary = "display metrics information")
public class DefaultMetricsReporterCmd implements BaseCommand {

public FrameworkModel frameworkModel;

public DefaultMetricsReporterCmd(FrameworkModel frameworkModel) {
this.frameworkModel = frameworkModel;
}

@Override
public String execute(CommandContext commandContext, String[] args) {
List<ApplicationModel> models = frameworkModel.getApplicationModels();
String result = "There is no application with data";
if (notSpecifyApplication(args)) {
result = useFirst(models, result, null);
} else if (args.length == 1) {
result = specifyApplication(args[0], models, null);
} else if (args.length == 2) {
result = specifyApplication(args[0], models, args[1]);
}
return result;
}

private boolean notSpecifyApplication(String[] args) {
return args == null || args.length == 0;
}

private String useFirst(List<ApplicationModel> models, String result, String metricsName) {
for (ApplicationModel model : models) {
String current = getResponseByApplication(model, metricsName);
if (current != null && getLineNumber(current) > 0) {
result = current;
break;
}
}
return result;
}

private String specifyApplication(String appName, List<ApplicationModel> models, String metricsName) {
if ("application_all".equals(appName)) {
return allApplication(models);
} else {
return specifySingleApplication(appName, models, metricsName);
}
}

private String specifySingleApplication(String appName, List<ApplicationModel> models, String metricsName) {
Optional<ApplicationModel> modelOptional = models.stream()
.filter(applicationModel -> appName.equals(applicationModel.getApplicationName())).findFirst();
if (modelOptional.isPresent()) {
return getResponseByApplication(modelOptional.get(), metricsName);
} else {
return "Not exist application: " + appName;
}
}

private String allApplication(List<ApplicationModel> models) {
Map<String, String> appResultMap = new HashMap<>();
for (ApplicationModel model : models) {
appResultMap.put(model.getApplicationName(), getResponseByApplication(model, null));
}
return JsonUtils.toJson(appResultMap);
}

private String getResponseByApplication(ApplicationModel applicationModel, String metricsName) {
String response = "DefaultMetricsReporter not init";
MetricsReporter metricsReporter = applicationModel.getBeanFactory().getBean(DefaultMetricsReporter.class);
if (metricsReporter != null) {
metricsReporter.refreshData();
response = metricsReporter.getResponseWithName(metricsName);
}
return response;
}


private static long getLineNumber(String content) {
LineNumberReader lnr = new LineNumberReader(new CharArrayReader(content.toCharArray()));
try {
lnr.skip(Long.MAX_VALUE);
lnr.close();
} catch (IOException ignore) {
}
return lnr.getLineNumber();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,4 @@ serializeWarnedClasses=org.apache.dubbo.qos.command.impl.SerializeWarnedClasses
getConfig=org.apache.dubbo.qos.command.impl.GetConfig
getAddress=org.apache.dubbo.qos.command.impl.GetAddress
gracefulShutdown=org.apache.dubbo.qos.command.impl.GracefulShutdown
metrics_default=org.apache.dubbo.qos.command.impl.DefaultMetricsReporterCmd
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.apache.dubbo.qos.command.GreetingCommand;
import org.apache.dubbo.qos.command.impl.ChangeTelnet;
import org.apache.dubbo.qos.command.impl.CountTelnet;
import org.apache.dubbo.qos.command.impl.DefaultMetricsReporterCmd;
import org.apache.dubbo.qos.command.impl.DisableDetailProfiler;
import org.apache.dubbo.qos.command.impl.DisableRouterSnapshot;
import org.apache.dubbo.qos.command.impl.DisableSimpleProfiler;
Expand Down Expand Up @@ -125,6 +126,7 @@ void testGetAllCommandClass() {
expectedClasses.add(GetConfig.class);
expectedClasses.add(GetAddress.class);
expectedClasses.add(GracefulShutdown.class);
expectedClasses.add(DefaultMetricsReporterCmd.class);
assertThat(classes, containsInAnyOrder(expectedClasses.toArray(new Class<?>[0])));
}

Expand Down

0 comments on commit 1697a33

Please sign in to comment.