mirror of
https://gitee.com/dromara/hmily.git
synced 2024-12-02 03:08:12 +08:00
refactor hmily metrics (#312)
This commit is contained in:
parent
5cf086cdc4
commit
76fa0136ec
@ -89,7 +89,8 @@
|
||||
<motan.version>1.0.0</motan.version>
|
||||
<disruptor.version>3.4.0</disruptor.version>
|
||||
<hikaricp.version>3.2.0</hikaricp.version>
|
||||
<prometheus-java-client.version>0.6.0</prometheus-java-client.version>
|
||||
<prometheus-java-client.version>0.10.0</prometheus-java-client.version>
|
||||
<prometheus-jmx.version>0.15.0</prometheus-jmx.version>
|
||||
<zookeeper.version>3.6.0</zookeeper.version>
|
||||
<zkClient.version>0.4</zkClient.version>
|
||||
<aspectj.version>1.8.9</aspectj.version>
|
||||
@ -185,6 +186,13 @@
|
||||
<version>${prometheus-java-client.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/io.prometheus.jmx/collector -->
|
||||
<dependency>
|
||||
<groupId>io.prometheus.jmx</groupId>
|
||||
<artifactId>collector</artifactId>
|
||||
<version>${prometheus-jmx.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
|
@ -17,16 +17,13 @@
|
||||
|
||||
package org.dromara.hmily.config.api.entity;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.management.ObjectName;
|
||||
import lombok.Data;
|
||||
import org.dromara.hmily.config.api.AbstractConfig;
|
||||
import org.dromara.hmily.config.api.constant.PrefixConstants;
|
||||
import org.dromara.hmily.spi.HmilySPI;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Metrics config.
|
||||
*
|
||||
@ -42,10 +39,6 @@ public final class HmilyMetricsConfig extends AbstractConfig {
|
||||
|
||||
private Integer port = 9091;
|
||||
|
||||
private boolean async = true;
|
||||
|
||||
private Integer threadCount = Runtime.getRuntime().availableProcessors() << 1;
|
||||
|
||||
private String jmxConfig;
|
||||
|
||||
private Properties props;
|
||||
@ -54,134 +47,5 @@ public final class HmilyMetricsConfig extends AbstractConfig {
|
||||
public String prefix() {
|
||||
return PrefixConstants.METRICS_PREFIX;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class HmilyJmxConfig {
|
||||
|
||||
/**
|
||||
* The Start delay seconds.
|
||||
*/
|
||||
private Integer startDelaySeconds = 0;
|
||||
|
||||
/**
|
||||
* The Jmx url.
|
||||
*/
|
||||
private String jmxUrl = "";
|
||||
|
||||
/**
|
||||
* The Username.
|
||||
*/
|
||||
private String username = "";
|
||||
|
||||
/**
|
||||
* The Password.
|
||||
*/
|
||||
private String password = "";
|
||||
|
||||
/**
|
||||
* The Ssl.
|
||||
*/
|
||||
private boolean ssl;
|
||||
|
||||
/**
|
||||
* The Lowercase output name.
|
||||
*/
|
||||
private boolean lowercaseOutputName;
|
||||
|
||||
/**
|
||||
* The Lowercase output label names.
|
||||
*/
|
||||
private boolean lowercaseOutputLabelNames;
|
||||
|
||||
/**
|
||||
* The Whitelist object names.
|
||||
*/
|
||||
private List<ObjectName> whitelistObjectNames = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* The Blacklist object names.
|
||||
*/
|
||||
private List<ObjectName> blacklistObjectNames = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* The Rules.
|
||||
*/
|
||||
private List<Rule> rules = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* The type Rule.
|
||||
*/
|
||||
@Data
|
||||
public static class Rule {
|
||||
|
||||
private Pattern pattern;
|
||||
|
||||
/**
|
||||
* The Name.
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* The Value.
|
||||
*/
|
||||
private String value;
|
||||
|
||||
/**
|
||||
* The Value factor.
|
||||
*/
|
||||
private Double valueFactor = 1.0;
|
||||
|
||||
/**
|
||||
* The Help.
|
||||
*/
|
||||
private String help;
|
||||
|
||||
/**
|
||||
* The Attr name snake case.
|
||||
*/
|
||||
private boolean attrNameSnakeCase;
|
||||
|
||||
/**
|
||||
* The Type.
|
||||
*/
|
||||
private Type type = Type.UNTYPED;
|
||||
|
||||
/**
|
||||
* The Label names.
|
||||
*/
|
||||
private List<String> labelNames = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* The Label values.
|
||||
*/
|
||||
private List<String> labelValues = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* The enum Type.
|
||||
*/
|
||||
public enum Type {
|
||||
/**
|
||||
* Counter type.
|
||||
*/
|
||||
COUNTER,
|
||||
/**
|
||||
* Gauge type.
|
||||
*/
|
||||
GAUGE,
|
||||
/**
|
||||
* Summary type.
|
||||
*/
|
||||
SUMMARY,
|
||||
/**
|
||||
* Histogram type.
|
||||
*/
|
||||
HISTOGRAM,
|
||||
/**
|
||||
* Untyped type.
|
||||
*/
|
||||
UNTYPED,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,6 @@
|
||||
|
||||
package org.dromara.hmily.core.bootstrap;
|
||||
|
||||
import java.util.Objects;
|
||||
import org.dromara.hmily.common.exception.HmilyRuntimeException;
|
||||
import org.dromara.hmily.common.hook.HmilyShutdownHook;
|
||||
import org.dromara.hmily.common.utils.StringUtils;
|
||||
@ -33,13 +32,15 @@ import org.dromara.hmily.core.provide.ObjectProvide;
|
||||
import org.dromara.hmily.core.provide.ReflectObject;
|
||||
import org.dromara.hmily.core.repository.HmilyRepositoryFacade;
|
||||
import org.dromara.hmily.core.schedule.HmilyTransactionSelfRecoveryScheduled;
|
||||
import org.dromara.hmily.metrics.spi.MetricsInit;
|
||||
import org.dromara.hmily.metrics.facade.MetricsTrackerFacade;
|
||||
import org.dromara.hmily.repository.spi.HmilyRepository;
|
||||
import org.dromara.hmily.serializer.spi.HmilySerializer;
|
||||
import org.dromara.hmily.spi.ExtensionLoaderFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* The type Hmily bootstrap.
|
||||
*
|
||||
@ -92,9 +93,9 @@ public final class HmilyBootstrap {
|
||||
private void initMetrics() {
|
||||
HmilyMetricsConfig metricsConfig = ConfigEnv.getInstance().getConfig(HmilyMetricsConfig.class);
|
||||
if (Objects.nonNull(metricsConfig) && StringUtils.isNoneBlank(metricsConfig.getMetricsName())) {
|
||||
MetricsInit metricsInit = ExtensionLoaderFactory.load(MetricsInit.class);
|
||||
metricsInit.init(metricsConfig);
|
||||
registerAutoCloseable(metricsInit);
|
||||
MetricsTrackerFacade facade = new MetricsTrackerFacade();
|
||||
facade.start(metricsConfig);
|
||||
registerAutoCloseable(facade);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,78 +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.dromara.hmily.metrics.facade;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import java.util.Optional;
|
||||
import org.dromara.hmily.config.api.entity.HmilyMetricsConfig;
|
||||
import org.dromara.hmily.metrics.facade.handler.MetricsTrackerHandler;
|
||||
import org.dromara.hmily.metrics.spi.MetricsInit;
|
||||
import org.dromara.hmily.metrics.spi.MetricsTrackerManager;
|
||||
import org.dromara.hmily.spi.ExtensionLoaderFactory;
|
||||
import org.dromara.hmily.spi.HmilySPI;
|
||||
|
||||
/**
|
||||
* The type Metrics init facade.
|
||||
*
|
||||
* @author xiaoyu
|
||||
*/
|
||||
@HmilySPI(value = "metricsInit")
|
||||
public class MetricsInitFacade implements MetricsInit {
|
||||
|
||||
private static volatile boolean enabled;
|
||||
|
||||
private static MetricsTrackerManager metricsTrackerManager;
|
||||
|
||||
/**
|
||||
* Gets enabled.
|
||||
*
|
||||
* @return the enabled
|
||||
*/
|
||||
public static boolean getEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(final HmilyMetricsConfig metricsConfig) {
|
||||
if (!enabled) {
|
||||
doInit(metricsConfig);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (!enabled) {
|
||||
return;
|
||||
}
|
||||
if (null != metricsTrackerManager) {
|
||||
metricsTrackerManager.stop();
|
||||
}
|
||||
MetricsTrackerHandler.getInstance().close();
|
||||
enabled = false;
|
||||
}
|
||||
|
||||
private static void doInit(final HmilyMetricsConfig metricsConfig) {
|
||||
Preconditions.checkNotNull(metricsConfig, "metrics configuration can not be null.");
|
||||
metricsTrackerManager = ExtensionLoaderFactory.load(MetricsTrackerManager.class, metricsConfig.getMetricsName());
|
||||
Preconditions.checkNotNull(metricsTrackerManager, "Can not find metrics tracker manager with metrics name in metrics configuration.");
|
||||
metricsTrackerManager.start(metricsConfig);
|
||||
Integer threadCount = Optional.ofNullable(metricsConfig.getThreadCount()).orElse(Runtime.getRuntime().availableProcessors());
|
||||
MetricsTrackerHandler.getInstance().init(metricsConfig.isAsync(), threadCount, metricsTrackerManager);
|
||||
enabled = true;
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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.dromara.hmily.metrics.facade;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.hmily.config.api.entity.HmilyMetricsConfig;
|
||||
import org.dromara.hmily.metrics.spi.MetricsBootService;
|
||||
import org.dromara.hmily.metrics.spi.MetricsRegister;
|
||||
import org.dromara.hmily.spi.ExtensionLoaderFactory;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
* Metrics tracker facade.
|
||||
*/
|
||||
@Slf4j
|
||||
public final class MetricsTrackerFacade implements AutoCloseable {
|
||||
|
||||
private MetricsBootService metricsBootService;
|
||||
|
||||
private final AtomicBoolean isStarted = new AtomicBoolean(false);
|
||||
|
||||
/**
|
||||
* Init for metrics tracker manager.
|
||||
*
|
||||
* @param metricsConfig metrics config
|
||||
*/
|
||||
public void start(final HmilyMetricsConfig metricsConfig) {
|
||||
if (this.isStarted.compareAndSet(false, true)) {
|
||||
metricsBootService = ExtensionLoaderFactory.load(MetricsBootService.class, metricsConfig.getMetricsName());
|
||||
Preconditions.checkNotNull(metricsBootService,
|
||||
"Can not find metrics tracker manager with metrics name : %s in metrics configuration.", metricsConfig.getMetricsName());
|
||||
metricsBootService.start(metricsConfig, ExtensionLoaderFactory.load(MetricsRegister.class, metricsConfig.getMetricsName()));
|
||||
} else {
|
||||
log.info("metrics tracker has started !");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
this.isStarted.compareAndSet(true, false);
|
||||
if (null != metricsBootService) {
|
||||
metricsBootService.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,95 +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.dromara.hmily.metrics.facade;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.hmily.metrics.api.HistogramMetricsTrackerDelegate;
|
||||
import org.dromara.hmily.metrics.api.SummaryMetricsTrackerDelegate;
|
||||
import org.dromara.hmily.metrics.facade.handler.MetricsTrackerHandler;
|
||||
import org.dromara.hmily.metrics.spi.MetricsHandlerFacade;
|
||||
import org.dromara.hmily.spi.HmilySPI;
|
||||
|
||||
/**
|
||||
* Metrics tracker facade.
|
||||
*
|
||||
* @author xiaoyu
|
||||
*/
|
||||
@Slf4j
|
||||
@HmilySPI(value = "metricsTrackerHandlerFacade")
|
||||
public final class MetricsTrackerHandlerFacade implements MetricsHandlerFacade {
|
||||
|
||||
@Override
|
||||
public void counterIncrement(final String metricsLabel, final String... labelValues) {
|
||||
if (MetricsInitFacade.getEnabled()) {
|
||||
MetricsTrackerHandler.getInstance().counterInc(metricsLabel, labelValues);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void gaugeIncrement(final String metricsLabel, final String... labelValues) {
|
||||
if (MetricsInitFacade.getEnabled()) {
|
||||
MetricsTrackerHandler.getInstance().gaugeInc(metricsLabel, labelValues);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void gaugeDecrement(final String metricsLabel, final String... labelValues) {
|
||||
if (MetricsInitFacade.getEnabled()) {
|
||||
MetricsTrackerHandler.getInstance().gaugeDec(metricsLabel, labelValues);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Supplier<Boolean> histogramStartTimer(final String metricsLabel, final String... labelValues) {
|
||||
if (!MetricsInitFacade.getEnabled()) {
|
||||
return () -> false;
|
||||
}
|
||||
Optional<HistogramMetricsTrackerDelegate> histogramMetricsTrackerDelegate = MetricsTrackerHandler.getInstance().histogramStartTimer(metricsLabel, labelValues);
|
||||
return () -> {
|
||||
histogramMetricsTrackerDelegate.ifPresent(this::histogramObserveDuration);
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
private void histogramObserveDuration(final HistogramMetricsTrackerDelegate delegate) {
|
||||
if (MetricsInitFacade.getEnabled()) {
|
||||
MetricsTrackerHandler.getInstance().histogramObserveDuration(delegate);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Supplier<Boolean> summaryStartTimer(final String metricsLabel, final String... labelValues) {
|
||||
if (!MetricsInitFacade.getEnabled()) {
|
||||
return () -> false;
|
||||
}
|
||||
Optional<SummaryMetricsTrackerDelegate> optionalSummaryMetricsTrackerDelegate = MetricsTrackerHandler.getInstance().summaryStartTimer(metricsLabel, labelValues);
|
||||
return () -> {
|
||||
optionalSummaryMetricsTrackerDelegate.ifPresent(this::summaryObserveDuration);
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
private void summaryObserveDuration(final SummaryMetricsTrackerDelegate delegate) {
|
||||
if (MetricsInitFacade.getEnabled()) {
|
||||
MetricsTrackerHandler.getInstance().summaryObserveDuration(delegate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,70 +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.dromara.hmily.metrics.facade.executor;
|
||||
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.RejectedExecutionHandler;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.hmily.common.concurrent.HmilyThreadFactory;
|
||||
|
||||
/**
|
||||
* Metrics thread pool executor.
|
||||
*/
|
||||
@Slf4j
|
||||
public final class MetricsThreadPoolExecutor extends ThreadPoolExecutor {
|
||||
|
||||
@Getter
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* Instantiates a new Metrics thread pool executor.
|
||||
*
|
||||
* @param threadCount core and max thread count
|
||||
* @param queueSize queue size
|
||||
*/
|
||||
public MetricsThreadPoolExecutor(final int threadCount, final int queueSize) {
|
||||
super(threadCount, threadCount, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(queueSize),
|
||||
HmilyThreadFactory.create("metrics", true), buildRejectedExecutionHandler(queueSize));
|
||||
this.name = "metrics";
|
||||
}
|
||||
|
||||
private static RejectedExecutionHandler buildRejectedExecutionHandler(final int size) {
|
||||
return (r, executor) -> {
|
||||
BlockingQueue<Runnable> queue = executor.getQueue();
|
||||
while (queue.size() >= size) {
|
||||
if (executor.isShutdown()) {
|
||||
throw new RejectedExecutionException("metrics thread pool executor closed");
|
||||
}
|
||||
((MetricsThreadPoolExecutor) executor).onRejected();
|
||||
}
|
||||
if (!executor.isShutdown()) {
|
||||
executor.execute(r);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void onRejected() {
|
||||
log.info("...thread:{}, Saturation occurs, actuator:{}", Thread.currentThread().getName(), name);
|
||||
}
|
||||
}
|
||||
|
@ -1,238 +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.dromara.hmily.metrics.facade.handler;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.hmily.metrics.api.CounterMetricsTracker;
|
||||
import org.dromara.hmily.metrics.api.GaugeMetricsTracker;
|
||||
import org.dromara.hmily.metrics.api.HistogramMetricsTracker;
|
||||
import org.dromara.hmily.metrics.api.HistogramMetricsTrackerDelegate;
|
||||
import org.dromara.hmily.metrics.api.MetricsTracker;
|
||||
import org.dromara.hmily.metrics.api.NoneHistogramMetricsTrackerDelegate;
|
||||
import org.dromara.hmily.metrics.api.NoneSummaryMetricsTrackerDelegate;
|
||||
import org.dromara.hmily.metrics.api.SummaryMetricsTracker;
|
||||
import org.dromara.hmily.metrics.api.SummaryMetricsTrackerDelegate;
|
||||
import org.dromara.hmily.metrics.enums.MetricsTypeEnum;
|
||||
import org.dromara.hmily.metrics.facade.executor.MetricsThreadPoolExecutor;
|
||||
import org.dromara.hmily.metrics.spi.MetricsTrackerManager;
|
||||
|
||||
/**
|
||||
* Metrics tracker handler.
|
||||
*/
|
||||
@Slf4j
|
||||
public final class MetricsTrackerHandler {
|
||||
|
||||
private static final int FUTURE_GET_TIME_OUT_MILLISECONDS = 500;
|
||||
|
||||
private static final int QUEUE_SIZE = 5000;
|
||||
|
||||
@Getter
|
||||
private MetricsTrackerManager metricsTrackerManager;
|
||||
|
||||
@Getter
|
||||
private ExecutorService executorService;
|
||||
|
||||
private volatile boolean async;
|
||||
|
||||
/**
|
||||
* Get metrics tracker handler of lazy load singleton.
|
||||
*
|
||||
* @return Metrics tracker handler
|
||||
*/
|
||||
public static MetricsTrackerHandler getInstance() {
|
||||
return MetricsTrackerHandlerHolder.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Init for metrics tracker handler.
|
||||
*
|
||||
* @param async async
|
||||
* @param threadCount thread count
|
||||
* @param metricsTrackerManager metrics tracker manager
|
||||
*/
|
||||
public void init(final boolean async, final int threadCount, final MetricsTrackerManager metricsTrackerManager) {
|
||||
this.async = async;
|
||||
this.metricsTrackerManager = metricsTrackerManager;
|
||||
if (async) {
|
||||
executorService = new MetricsThreadPoolExecutor(threadCount, QUEUE_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment of counter metrics tracker.
|
||||
*
|
||||
* @param metricsLabel metrics label
|
||||
* @param labelValues label values
|
||||
*/
|
||||
public void counterInc(final String metricsLabel, final String... labelValues) {
|
||||
if (async) {
|
||||
executorService.execute(() -> handlerCounter(metricsLabel, labelValues));
|
||||
} else {
|
||||
handlerCounter(metricsLabel, labelValues);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment of gauge metrics tracker.
|
||||
*
|
||||
* @param metricsLabel metrics label
|
||||
* @param labelValues label values
|
||||
*/
|
||||
public void gaugeInc(final String metricsLabel, final String... labelValues) {
|
||||
if (async) {
|
||||
executorService.execute(() -> handlerGaugeInc(metricsLabel, labelValues));
|
||||
} else {
|
||||
handlerGaugeInc(metricsLabel, labelValues);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrement of gauge metrics tracker.
|
||||
*
|
||||
* @param metricsLabel metrics label
|
||||
* @param labelValues label values
|
||||
*/
|
||||
public void gaugeDec(final String metricsLabel, final String... labelValues) {
|
||||
if (async) {
|
||||
executorService.execute(() -> handlerGaugeDec(metricsLabel, labelValues));
|
||||
} else {
|
||||
handlerGaugeDec(metricsLabel, labelValues);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start timer of histogram metrics tracker.
|
||||
*
|
||||
* @param metricsLabel metrics label
|
||||
* @param labelValues label values
|
||||
* @return histogram metrics tracker delegate
|
||||
*/
|
||||
public Optional<HistogramMetricsTrackerDelegate> histogramStartTimer(final String metricsLabel, final String... labelValues) {
|
||||
if (async) {
|
||||
try {
|
||||
return executorService.submit(() -> handlerHistogramStartTimer(metricsLabel, labelValues)).get(FUTURE_GET_TIME_OUT_MILLISECONDS, TimeUnit.MILLISECONDS);
|
||||
} catch (InterruptedException | ExecutionException | TimeoutException e) {
|
||||
throw new IllegalStateException(String.format("Error while fetching histogram metric with metricsLabel= %s and labelValues=%s", metricsLabel, Arrays.toString(labelValues)), e);
|
||||
}
|
||||
} else {
|
||||
return handlerHistogramStartTimer(metricsLabel, labelValues);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Observe amount of time since start time with histogram metrics tracker.
|
||||
*
|
||||
* @param delegate histogram metrics tracker delegate
|
||||
*/
|
||||
public void histogramObserveDuration(final HistogramMetricsTrackerDelegate delegate) {
|
||||
if (async) {
|
||||
executorService.execute(delegate::observeDuration);
|
||||
} else {
|
||||
delegate.observeDuration();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start timer of summary metrics tracker.
|
||||
*
|
||||
* @param metricsLabel metrics label
|
||||
* @param labelValues label values
|
||||
* @return summary metrics tracker delegate
|
||||
*/
|
||||
public Optional<SummaryMetricsTrackerDelegate> summaryStartTimer(final String metricsLabel, final String... labelValues) {
|
||||
if (async) {
|
||||
try {
|
||||
return executorService.submit(() -> handlerSummaryStartTimer(metricsLabel, labelValues)).get(FUTURE_GET_TIME_OUT_MILLISECONDS, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException | ExecutionException | TimeoutException e) {
|
||||
throw new IllegalStateException(String.format("Error while fetching summary metric with metricsLabel= %s and labelValues=%s", metricsLabel, Arrays.toString(labelValues)), e);
|
||||
}
|
||||
} else {
|
||||
return handlerSummaryStartTimer(metricsLabel, labelValues);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Observe amount of time since start time with summary metrics tracker.
|
||||
*
|
||||
* @param delegate summary metrics tracker delegate
|
||||
*/
|
||||
public void summaryObserveDuration(final SummaryMetricsTrackerDelegate delegate) {
|
||||
if (async) {
|
||||
executorService.execute(delegate::observeDuration);
|
||||
} else {
|
||||
delegate.observeDuration();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executor service close.
|
||||
*/
|
||||
public void close() {
|
||||
async = false;
|
||||
if (null != executorService && !executorService.isShutdown()) {
|
||||
executorService.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
private void handlerCounter(final String metricsLabel, final String... labelValues) {
|
||||
metricsTrackerManager.getMetricsTrackerFactory().create(MetricsTypeEnum.COUNTER.name(), metricsLabel)
|
||||
.ifPresent(metricsTracker -> ((CounterMetricsTracker) metricsTracker).inc(1.0, labelValues));
|
||||
}
|
||||
|
||||
private void handlerGaugeInc(final String metricsLabel, final String... labelValues) {
|
||||
metricsTrackerManager.getMetricsTrackerFactory().create(MetricsTypeEnum.GAUGE.name(), metricsLabel)
|
||||
.ifPresent(metricsTracker -> ((GaugeMetricsTracker) metricsTracker).inc(1.0, labelValues));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler gauge dec.
|
||||
*
|
||||
* @param metricsLabel the metrics label
|
||||
* @param labelValues the label values
|
||||
*/
|
||||
public void handlerGaugeDec(final String metricsLabel, final String... labelValues) {
|
||||
metricsTrackerManager.getMetricsTrackerFactory().create(MetricsTypeEnum.GAUGE.name(), metricsLabel)
|
||||
.ifPresent(metricsTracker -> ((GaugeMetricsTracker) metricsTracker).dec(1.0, labelValues));
|
||||
}
|
||||
|
||||
private Optional<HistogramMetricsTrackerDelegate> handlerHistogramStartTimer(final String metricsLabel, final String... labelValues) {
|
||||
Optional<MetricsTracker> metricsTracker = metricsTrackerManager.getMetricsTrackerFactory().create(MetricsTypeEnum.HISTOGRAM.name(), metricsLabel);
|
||||
return metricsTracker.map(tracker -> Optional.of(((HistogramMetricsTracker) tracker).startTimer(labelValues))).orElseGet(() -> Optional.of(new NoneHistogramMetricsTrackerDelegate()));
|
||||
}
|
||||
|
||||
private Optional<SummaryMetricsTrackerDelegate> handlerSummaryStartTimer(final String metricsLabel, final String... labelValues) {
|
||||
Optional<MetricsTracker> metricsTracker = metricsTrackerManager.getMetricsTrackerFactory().create(MetricsTypeEnum.SUMMARY.name(), metricsLabel);
|
||||
return metricsTracker.map(tracker -> Optional.of(((SummaryMetricsTracker) tracker).startTimer(labelValues))).orElseGet(() -> Optional.of(new NoneSummaryMetricsTrackerDelegate()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Metrics tracker handler holder.
|
||||
*/
|
||||
private static class MetricsTrackerHandlerHolder {
|
||||
|
||||
private static final MetricsTrackerHandler INSTANCE = new MetricsTrackerHandler();
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +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.
|
||||
#
|
||||
|
||||
org.dromara.hmily.metrics.facade.MetricsTrackerHandlerFacade
|
@ -1,18 +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.
|
||||
#
|
||||
|
||||
org.dromara.hmily.metrics.facade.MetricsInitFacade
|
@ -56,5 +56,9 @@
|
||||
<groupId>io.prometheus</groupId>
|
||||
<artifactId>simpleclient_hotspot</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.prometheus.jmx</groupId>
|
||||
<artifactId>collector</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
@ -1,51 +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.dromara.hmily.metrics.prometheus;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
import org.dromara.hmily.metrics.api.MetricsTracker;
|
||||
import org.dromara.hmily.metrics.api.MetricsTrackerFactory;
|
||||
import org.dromara.hmily.metrics.prometheus.impl.counter.TransactionStatusCounterMetricsTracker;
|
||||
import org.dromara.hmily.metrics.prometheus.impl.counter.TransactionTotalCounterMetricsTracker;
|
||||
import org.dromara.hmily.metrics.prometheus.impl.histogram.TransactionLatencyHistogramMetricsTracker;
|
||||
import org.dromara.hmily.metrics.prometheus.impl.summary.TransactionLatencySummaryMetricsTracker;
|
||||
|
||||
/**
|
||||
* Prometheus metrics tracker factory.
|
||||
*
|
||||
* @author xiaoyu
|
||||
*/
|
||||
public final class PrometheusMetricsTrackerFactory implements MetricsTrackerFactory {
|
||||
|
||||
private static final Collection<MetricsTracker> REGISTER = new ArrayList<>();
|
||||
|
||||
static {
|
||||
REGISTER.add(new TransactionTotalCounterMetricsTracker());
|
||||
REGISTER.add(new TransactionStatusCounterMetricsTracker());
|
||||
REGISTER.add(new TransactionLatencyHistogramMetricsTracker());
|
||||
REGISTER.add(new TransactionLatencySummaryMetricsTracker());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<MetricsTracker> create(final String metricsType, final String metricsLabel) {
|
||||
return REGISTER.stream().filter(each -> each.metricsLabel().equals(metricsLabel) && each.metricsType().equals(metricsType)).findFirst();
|
||||
}
|
||||
}
|
||||
|
@ -15,19 +15,17 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.dromara.hmily.metrics.prometheus.impl.collector;
|
||||
package org.dromara.hmily.metrics.prometheus.collector;
|
||||
|
||||
import io.prometheus.client.Collector;
|
||||
import io.prometheus.client.GaugeMetricFamily;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* The type Build info collector.
|
||||
*
|
||||
* @author xiaoyu
|
||||
*/
|
||||
public class BuildInfoCollector extends Collector {
|
||||
|
@ -1,408 +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.dromara.hmily.metrics.prometheus.impl.collector;
|
||||
|
||||
import io.prometheus.client.Collector;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentSkipListMap;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.management.MalformedObjectNameException;
|
||||
import javax.management.ObjectName;
|
||||
import org.dromara.hmily.common.utils.GsonUtils;
|
||||
import org.dromara.hmily.config.api.entity.HmilyMetricsConfig;
|
||||
|
||||
/**
|
||||
* The type Jmx collector.
|
||||
*
|
||||
* @author xiaoyu
|
||||
*/
|
||||
public class JmxCollector extends Collector implements Collector.Describable {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(JmxCollector.class.getName());
|
||||
|
||||
private HmilyMetricsConfig.HmilyJmxConfig config;
|
||||
|
||||
private long createTimeNanoSecs = System.nanoTime();
|
||||
|
||||
private final JmxMBeanPropertyCache jmxMBeanPropertyCache = new JmxMBeanPropertyCache();
|
||||
|
||||
/**
|
||||
* Instantiates a new Jmx collector.
|
||||
*
|
||||
* @param json the json
|
||||
* @throws MalformedObjectNameException the malformed object name exception
|
||||
*/
|
||||
public JmxCollector(final String json) throws MalformedObjectNameException {
|
||||
config = loadConfig(GsonUtils.getInstance().toObjectMap(json));
|
||||
}
|
||||
|
||||
private HmilyMetricsConfig.HmilyJmxConfig loadConfig(final Map<String, Object> paramMap) throws MalformedObjectNameException {
|
||||
HmilyMetricsConfig.HmilyJmxConfig cfg = new HmilyMetricsConfig.HmilyJmxConfig();
|
||||
if (paramMap == null || paramMap.size() == 0) {
|
||||
return cfg;
|
||||
}
|
||||
if (paramMap.containsKey("startDelaySeconds")) {
|
||||
try {
|
||||
cfg.setStartDelaySeconds((Integer) paramMap.get("startDelaySeconds"));
|
||||
} catch (NumberFormatException e) {
|
||||
throw new IllegalArgumentException("Invalid number provided for startDelaySeconds", e);
|
||||
}
|
||||
}
|
||||
if (paramMap.containsKey("hostPort")) {
|
||||
if (paramMap.containsKey("jmxUrl")) {
|
||||
throw new IllegalArgumentException("At most one of hostPort and jmxUrl must be provided");
|
||||
}
|
||||
cfg.setJmxUrl("service:jmx:rmi:///jndi/rmi://" + paramMap.get("hostPort") + "/jmxrmi");
|
||||
} else if (paramMap.containsKey("jmxUrl")) {
|
||||
cfg.setJmxUrl((String) paramMap.get("jmxUrl"));
|
||||
}
|
||||
|
||||
if (paramMap.containsKey("username")) {
|
||||
cfg.setUsername((String) paramMap.get("username"));
|
||||
}
|
||||
|
||||
if (paramMap.containsKey("password")) {
|
||||
cfg.setPassword((String) paramMap.get("password"));
|
||||
}
|
||||
|
||||
if (paramMap.containsKey("ssl")) {
|
||||
cfg.setSsl((Boolean) paramMap.get("ssl"));
|
||||
}
|
||||
|
||||
if (paramMap.containsKey("lowercaseOutputName")) {
|
||||
cfg.setLowercaseOutputName((Boolean) paramMap.get("lowercaseOutputName"));
|
||||
}
|
||||
|
||||
if (paramMap.containsKey("lowercaseOutputLabelNames")) {
|
||||
cfg.setLowercaseOutputLabelNames((Boolean) paramMap.get("lowercaseOutputLabelNames"));
|
||||
}
|
||||
|
||||
if (paramMap.containsKey("whitelistObjectNames")) {
|
||||
List<String> names = GsonUtils.getInstance().fromList(paramMap.get("whitelistObjectNames").toString(), String.class);
|
||||
for (String name : names) {
|
||||
cfg.getWhitelistObjectNames().add(new ObjectName(name));
|
||||
}
|
||||
}
|
||||
|
||||
if (paramMap.containsKey("blacklistObjectNames")) {
|
||||
List<String> names = GsonUtils.getInstance().fromList(paramMap.get("blacklistObjectNames").toString(), String.class);
|
||||
for (String name : names) {
|
||||
cfg.getBlacklistObjectNames().add(new ObjectName(name));
|
||||
}
|
||||
}
|
||||
|
||||
if (paramMap.containsKey("rules")) {
|
||||
List<Map<String, Object>> configRules = GsonUtils.getInstance().toListMap(paramMap.get("rules").toString());
|
||||
for (Map<String, Object> ruleObject : configRules) {
|
||||
HmilyMetricsConfig.HmilyJmxConfig.Rule rule = new HmilyMetricsConfig.HmilyJmxConfig.Rule();
|
||||
cfg.getRules().add(rule);
|
||||
if (ruleObject.containsKey("pattern")) {
|
||||
rule.setPattern(Pattern.compile("^.*(?:" + ruleObject.get("pattern") + ").*$"));
|
||||
}
|
||||
if (ruleObject.containsKey("name")) {
|
||||
rule.setName((String) ruleObject.get("name"));
|
||||
}
|
||||
if (ruleObject.containsKey("value")) {
|
||||
rule.setValue(String.valueOf(ruleObject.get("value")));
|
||||
}
|
||||
if (ruleObject.containsKey("valueFactor")) {
|
||||
String valueFactor = String.valueOf(ruleObject.get("valueFactor"));
|
||||
try {
|
||||
rule.setValueFactor(Double.valueOf(valueFactor));
|
||||
} catch (NumberFormatException e) {
|
||||
// use default value
|
||||
}
|
||||
}
|
||||
if (ruleObject.containsKey("attrNameSnakeCase")) {
|
||||
rule.setAttrNameSnakeCase((Boolean) ruleObject.get("attrNameSnakeCase"));
|
||||
}
|
||||
if (ruleObject.containsKey("type")) {
|
||||
rule.setType(HmilyMetricsConfig.HmilyJmxConfig.Type.valueOf(String.valueOf(ruleObject.containsKey("type"))));
|
||||
}
|
||||
if (ruleObject.containsKey("help")) {
|
||||
rule.setHelp(String.valueOf(ruleObject.get("help")));
|
||||
}
|
||||
if (ruleObject.containsKey("labels")) {
|
||||
ConcurrentSkipListMap<String, Object> labels = GsonUtils.getInstance().toTreeMap(ruleObject.get("labels").toString());
|
||||
for (Map.Entry<String, Object> entry : labels.entrySet()) {
|
||||
rule.getLabelNames().add(entry.getKey());
|
||||
rule.getLabelValues().add((String) entry.getValue());
|
||||
}
|
||||
}
|
||||
// Validation.
|
||||
if ((rule.getLabelValues() != null || rule.getHelp() != null) && rule.getName() == null) {
|
||||
throw new IllegalArgumentException("Must provide name, if help or labels are given: " + ruleObject);
|
||||
}
|
||||
if (rule.getName() != null && rule.getPattern() == null) {
|
||||
throw new IllegalArgumentException("Must provide pattern, if name is given: " + ruleObject);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Default to a single default rule.
|
||||
cfg.getRules().add(new HmilyMetricsConfig.HmilyJmxConfig.Rule());
|
||||
}
|
||||
return cfg;
|
||||
}
|
||||
|
||||
private static String toSnakeAndLowerCase(final String attrName) {
|
||||
if (attrName == null || attrName.isEmpty()) {
|
||||
return attrName;
|
||||
}
|
||||
char firstChar = attrName.subSequence(0, 1).charAt(0);
|
||||
boolean prevCharIsUpperCaseOrUnderscore = Character.isUpperCase(firstChar) || firstChar == '_';
|
||||
StringBuilder resultBuilder = new StringBuilder(attrName.length()).append(Character.toLowerCase(firstChar));
|
||||
for (char attrChar : attrName.substring(1).toCharArray()) {
|
||||
boolean charIsUpperCase = Character.isUpperCase(attrChar);
|
||||
if (!prevCharIsUpperCaseOrUnderscore && charIsUpperCase) {
|
||||
resultBuilder.append("_");
|
||||
}
|
||||
resultBuilder.append(Character.toLowerCase(attrChar));
|
||||
prevCharIsUpperCaseOrUnderscore = charIsUpperCase || attrChar == '_';
|
||||
}
|
||||
return resultBuilder.toString();
|
||||
}
|
||||
|
||||
private static String safeName(final String name) {
|
||||
if (name == null) {
|
||||
return null;
|
||||
}
|
||||
boolean prevCharIsUnderscore = false;
|
||||
StringBuilder safeNameBuilder = new StringBuilder(name.length());
|
||||
if (!name.isEmpty() && Character.isDigit(name.charAt(0))) {
|
||||
// prevent a numeric prefix.
|
||||
safeNameBuilder.append("_");
|
||||
}
|
||||
for (char nameChar : name.toCharArray()) {
|
||||
boolean isUnsafeChar = !JmxCollector.isLegalCharacter(nameChar);
|
||||
if (isUnsafeChar || nameChar == '_') {
|
||||
if (!prevCharIsUnderscore) {
|
||||
safeNameBuilder.append("_");
|
||||
prevCharIsUnderscore = true;
|
||||
}
|
||||
} else {
|
||||
safeNameBuilder.append(nameChar);
|
||||
prevCharIsUnderscore = false;
|
||||
}
|
||||
}
|
||||
return safeNameBuilder.toString();
|
||||
}
|
||||
|
||||
private static boolean isLegalCharacter(final char input) {
|
||||
return (input == ':') || (input == '_') || (input >= 'a' && input <= 'z') || (input >= 'A' && input <= 'Z') || (input >= '0' && input <= '9');
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MetricFamilySamples> collect() {
|
||||
Receiver receiver = new Receiver();
|
||||
JmxScraper scraper = new JmxScraper(config.getJmxUrl(), config.getUsername(), config.getPassword(), config.isSsl(),
|
||||
config.getWhitelistObjectNames(), config.getBlacklistObjectNames(), receiver, jmxMBeanPropertyCache);
|
||||
long start = System.nanoTime();
|
||||
double error = 0;
|
||||
if ((config.getStartDelaySeconds() > 0) && ((start - createTimeNanoSecs) / 1000000000L < config.getStartDelaySeconds())) {
|
||||
throw new IllegalStateException("JMXCollector waiting for startDelaySeconds");
|
||||
}
|
||||
try {
|
||||
scraper.doScrape();
|
||||
} catch (IOException e) {
|
||||
error = 1;
|
||||
StringWriter sw = new StringWriter();
|
||||
e.printStackTrace(new PrintWriter(sw));
|
||||
LOGGER.severe("JMX scrape failed: " + sw.toString());
|
||||
}
|
||||
List<MetricFamilySamples> mfsList = new ArrayList<>(receiver.metricFamilySamplesMap.values());
|
||||
List<MetricFamilySamples.Sample> samples = new ArrayList<>();
|
||||
samples.add(new MetricFamilySamples.Sample(
|
||||
"jmx_scrape_duration_seconds", new ArrayList<>(), new ArrayList<>(), (System.nanoTime() - start) / 1.0E9));
|
||||
mfsList.add(new MetricFamilySamples("jmx_scrape_duration_seconds", Type.GAUGE, "Time this JMX scrape took, in seconds.", samples));
|
||||
samples = new ArrayList<>();
|
||||
samples.add(new MetricFamilySamples.Sample(
|
||||
"jmx_scrape_error", new ArrayList<>(), new ArrayList<>(), error));
|
||||
mfsList.add(new MetricFamilySamples("jmx_scrape_error", Type.GAUGE, "Non-zero if this scrape failed.", samples));
|
||||
return mfsList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MetricFamilySamples> describe() {
|
||||
List<MetricFamilySamples> sampleFamilies = new ArrayList<>();
|
||||
sampleFamilies.add(new MetricFamilySamples("jmx_scrape_duration_seconds", Type.GAUGE, "Time this JMX scrape took, in seconds.", new ArrayList<>()));
|
||||
sampleFamilies.add(new MetricFamilySamples("jmx_scrape_error", Type.GAUGE, "Non-zero if this scrape failed.", new ArrayList<>()));
|
||||
return sampleFamilies;
|
||||
}
|
||||
|
||||
/**
|
||||
* The type Receiver.
|
||||
*/
|
||||
class Receiver implements MBeanReceiver {
|
||||
|
||||
private static final char SEP = '_';
|
||||
|
||||
private Map<String, MetricFamilySamples> metricFamilySamplesMap = new HashMap<>();
|
||||
|
||||
// [] and () are special in regexes, so swtich to <>.
|
||||
private String angleBrackets(final String s) {
|
||||
return "<" + s.substring(1, s.length() - 1) + ">";
|
||||
}
|
||||
|
||||
/**
|
||||
* Add sample.
|
||||
*
|
||||
* @param sample the sample
|
||||
* @param type the type
|
||||
* @param help the help
|
||||
*/
|
||||
void addSample(final MetricFamilySamples.Sample sample, final Type type, final String help) {
|
||||
MetricFamilySamples mfs = metricFamilySamplesMap.get(sample.name);
|
||||
if (mfs == null) {
|
||||
// JmxScraper.MBeanReceiver is only called from one thread,
|
||||
// so there's no race here.
|
||||
mfs = new MetricFamilySamples(sample.name, type, help, new ArrayList<>());
|
||||
metricFamilySamplesMap.put(sample.name, mfs);
|
||||
}
|
||||
mfs.samples.add(sample);
|
||||
}
|
||||
|
||||
private void defaultExport(final String domain, final Map<String, String> beanProperties,
|
||||
final LinkedList<String> attrKeys, final String attrName, final String help, final Object value, final Type type) {
|
||||
StringBuilder name = new StringBuilder();
|
||||
name.append(domain);
|
||||
if (beanProperties.size() > 0) {
|
||||
name.append(SEP);
|
||||
name.append(beanProperties.values().iterator().next());
|
||||
}
|
||||
for (String k : attrKeys) {
|
||||
name.append(SEP);
|
||||
name.append(k);
|
||||
}
|
||||
name.append(SEP);
|
||||
name.append(attrName);
|
||||
String fullname = safeName(name.toString());
|
||||
|
||||
if (config.isLowercaseOutputName()) {
|
||||
fullname = fullname.toLowerCase();
|
||||
}
|
||||
|
||||
List<String> labelNames = new ArrayList<>();
|
||||
List<String> labelValues = new ArrayList<>();
|
||||
if (beanProperties.size() > 1) {
|
||||
Iterator<Map.Entry<String, String>> iter = beanProperties.entrySet().iterator();
|
||||
// Skip the first one, it's been used in the name.
|
||||
iter.next();
|
||||
while (iter.hasNext()) {
|
||||
Map.Entry<String, String> entry = iter.next();
|
||||
String labelName = safeName(entry.getKey());
|
||||
if (config.isLowercaseOutputName()) {
|
||||
labelName = labelName.toLowerCase();
|
||||
}
|
||||
labelNames.add(labelName);
|
||||
labelValues.add(entry.getValue());
|
||||
}
|
||||
}
|
||||
addSample(new MetricFamilySamples.Sample(fullname, labelNames, labelValues, ((Number) value).doubleValue()), type, help);
|
||||
}
|
||||
|
||||
public void recordBean(final String domain, final Map<String, String> beanProperties, final LinkedList<String> attrKeys,
|
||||
final String attrName, final String attrType, final String attrDescription, final Object beanObject) {
|
||||
String beanName = domain + angleBrackets(beanProperties.toString()) + angleBrackets(attrKeys.toString());
|
||||
// attrDescription tends not to be useful, so give the fully qualified name too.
|
||||
String help = attrDescription + " (" + beanName + attrName + ")";
|
||||
String attrNameSnakeCase = toSnakeAndLowerCase(attrName);
|
||||
for (HmilyMetricsConfig.HmilyJmxConfig.Rule rule : config.getRules()) {
|
||||
Matcher matcher = null;
|
||||
String matchName = beanName + (rule.isAttrNameSnakeCase() ? attrNameSnakeCase : attrName);
|
||||
if (rule.getPattern() != null) {
|
||||
matcher = rule.getPattern().matcher(matchName + ": " + beanObject);
|
||||
if (!matcher.matches()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
Number value;
|
||||
Object beanValue = beanObject;
|
||||
if (rule.getValue() != null && !rule.getValue().isEmpty()) {
|
||||
assert matcher != null;
|
||||
String val = matcher.replaceAll(rule.getValue());
|
||||
|
||||
try {
|
||||
beanValue = Double.valueOf(val);
|
||||
} catch (NumberFormatException e) {
|
||||
LOGGER.fine("Unable to parse configured value '" + val + "' to number for bean: " + beanName + attrName + ": " + beanValue);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (beanValue instanceof Number) {
|
||||
value = ((Number) beanValue).doubleValue() * rule.getValueFactor();
|
||||
} else if (beanValue instanceof Boolean) {
|
||||
value = (Boolean) beanValue ? 1 : 0;
|
||||
} else {
|
||||
LOGGER.fine("Ignoring unsupported bean: " + beanName + attrName + ": " + beanValue);
|
||||
return;
|
||||
}
|
||||
// If there's no name provided, use default export format.
|
||||
if (rule.getName() == null) {
|
||||
defaultExport(domain, beanProperties, attrKeys, rule.isAttrNameSnakeCase() ? attrNameSnakeCase : attrName, help, value, Type.valueOf(rule.getType().name()));
|
||||
return;
|
||||
}
|
||||
|
||||
// Matcher is set below here due to validation in the constructor.
|
||||
assert matcher != null;
|
||||
String name = safeName(matcher.replaceAll(rule.getName()));
|
||||
if (name.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (config.isLowercaseOutputName()) {
|
||||
name = name.toLowerCase();
|
||||
}
|
||||
// Set the help.
|
||||
if (rule.getHelp() != null) {
|
||||
help = matcher.replaceAll(rule.getHelp());
|
||||
}
|
||||
// Set the labels.
|
||||
ArrayList<String> labelNames = new ArrayList<>();
|
||||
ArrayList<String> labelValues = new ArrayList<>();
|
||||
if (rule.getLabelNames() != null) {
|
||||
for (int i = 0; i < rule.getLabelNames().size(); i++) {
|
||||
final String unsafeLabelName = rule.getLabelNames().get(i);
|
||||
final String labelValReplacement = rule.getLabelValues().get(i);
|
||||
String labelName = safeName(matcher.replaceAll(unsafeLabelName));
|
||||
String labelValue = matcher.replaceAll(labelValReplacement);
|
||||
if (config.isLowercaseOutputName()) {
|
||||
labelName = labelName.toLowerCase();
|
||||
}
|
||||
if (!labelName.isEmpty() && !labelValue.isEmpty()) {
|
||||
labelNames.add(labelName);
|
||||
labelValues.add(labelValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Add to samples.
|
||||
LOGGER.fine("add metric sample: " + name + " " + labelNames + " " + labelValues + " " + value.doubleValue());
|
||||
addSample(new MetricFamilySamples.Sample(name, labelNames, labelValues, value.doubleValue()), Type.valueOf(rule.getType().name()), help);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,99 +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.dromara.hmily.metrics.prometheus.impl.collector;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.management.ObjectName;
|
||||
|
||||
/**
|
||||
* This object stores a mapping of mBean objectNames to mBean key property lists. The main purpose of it is to reduce
|
||||
* the frequency with which we invoke PROPERTY_PATTERN when discovering mBeans.
|
||||
*
|
||||
* @author xiaoyu
|
||||
*/
|
||||
public class JmxMBeanPropertyCache {
|
||||
|
||||
private static final Pattern PROPERTY_PATTERN = Pattern.compile(
|
||||
"([^,=:*?]+)"
|
||||
+ "="
|
||||
+ "("
|
||||
+ "\""
|
||||
+ "(?:"
|
||||
+ "[^\\\\\"]*"
|
||||
+ "(?:\\\\.)?"
|
||||
+ ")*"
|
||||
+ "\""
|
||||
+ "|"
|
||||
+ "[^,=:\"]*"
|
||||
+ ")");
|
||||
|
||||
// Implement a version of ObjectName.getKeyPropertyList that returns the
|
||||
// properties in the ordered they were added (the ObjectName stores them
|
||||
// in the order they were added).
|
||||
private final Map<ObjectName, Map<String, String>> keyPropertiesPerBean;
|
||||
|
||||
/**
|
||||
* Instantiates a new Jmx m bean property cache.
|
||||
*/
|
||||
public JmxMBeanPropertyCache() {
|
||||
this.keyPropertiesPerBean = new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets key property list.
|
||||
*
|
||||
* @param mbeanName the mbean name
|
||||
* @return the key property list
|
||||
*/
|
||||
public Map<String, String> getKeyPropertyList(final ObjectName mbeanName) {
|
||||
Map<String, String> keyProperties = keyPropertiesPerBean.get(mbeanName);
|
||||
if (keyProperties == null) {
|
||||
keyProperties = new LinkedHashMap<>();
|
||||
String properties = mbeanName.getKeyPropertyListString();
|
||||
Matcher match = PROPERTY_PATTERN.matcher(properties);
|
||||
while (match.lookingAt()) {
|
||||
keyProperties.put(match.group(1), match.group(2));
|
||||
properties = properties.substring(match.end());
|
||||
if (properties.startsWith(",")) {
|
||||
properties = properties.substring(1);
|
||||
}
|
||||
match.reset(properties);
|
||||
}
|
||||
keyPropertiesPerBean.put(mbeanName, keyProperties);
|
||||
}
|
||||
return keyProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only keep m beans.
|
||||
*
|
||||
* @param latestBeans the latest beans
|
||||
*/
|
||||
public void onlyKeepMBeans(final Set<ObjectName> latestBeans) {
|
||||
for (ObjectName prevName : keyPropertiesPerBean.keySet()) {
|
||||
if (!latestBeans.contains(prevName)) {
|
||||
keyPropertiesPerBean.remove(prevName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,296 +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.dromara.hmily.metrics.prometheus.impl.collector;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.management.Attribute;
|
||||
import javax.management.AttributeList;
|
||||
import javax.management.InstanceNotFoundException;
|
||||
import javax.management.JMException;
|
||||
import javax.management.MBeanAttributeInfo;
|
||||
import javax.management.MBeanInfo;
|
||||
import javax.management.MBeanServerConnection;
|
||||
import javax.management.ObjectInstance;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.ReflectionException;
|
||||
import javax.management.openmbean.CompositeData;
|
||||
import javax.management.openmbean.CompositeType;
|
||||
import javax.management.openmbean.TabularData;
|
||||
import javax.management.openmbean.TabularType;
|
||||
import javax.management.remote.JMXConnector;
|
||||
import javax.management.remote.JMXConnectorFactory;
|
||||
import javax.management.remote.JMXServiceURL;
|
||||
import javax.management.remote.rmi.RMIConnectorServer;
|
||||
import javax.naming.Context;
|
||||
import javax.rmi.ssl.SslRMIClientSocketFactory;
|
||||
|
||||
/**
|
||||
* The type Jmx scraper.
|
||||
*
|
||||
* @author xiaoyu
|
||||
*/
|
||||
public class JmxScraper {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(JmxScraper.class.getName());
|
||||
|
||||
private final MBeanReceiver receiver;
|
||||
|
||||
private final String jmxUrl;
|
||||
|
||||
private final String username;
|
||||
|
||||
private final String password;
|
||||
|
||||
private final boolean ssl;
|
||||
|
||||
private final List<ObjectName> whitelistObjectNames;
|
||||
|
||||
private final List<ObjectName> blacklistObjectNames;
|
||||
|
||||
private final JmxMBeanPropertyCache jmxMBeanPropertyCache;
|
||||
|
||||
/**
|
||||
* Instantiates a new Jmx scraper.
|
||||
*
|
||||
* @param jmxUrl the jmx url
|
||||
* @param username the username
|
||||
* @param password the password
|
||||
* @param ssl the ssl
|
||||
* @param whitelistObjectNames the whitelist object names
|
||||
* @param blacklistObjectNames the blacklist object names
|
||||
* @param receiver the receiver
|
||||
* @param jmxMBeanPropertyCache the jmx m bean property cache
|
||||
*/
|
||||
public JmxScraper(final String jmxUrl, final String username, final String password, final boolean ssl,
|
||||
final List<ObjectName> whitelistObjectNames, final List<ObjectName> blacklistObjectNames,
|
||||
final MBeanReceiver receiver, final JmxMBeanPropertyCache jmxMBeanPropertyCache) {
|
||||
this.jmxUrl = jmxUrl;
|
||||
this.receiver = receiver;
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
this.ssl = ssl;
|
||||
this.whitelistObjectNames = whitelistObjectNames;
|
||||
this.blacklistObjectNames = blacklistObjectNames;
|
||||
this.jmxMBeanPropertyCache = jmxMBeanPropertyCache;
|
||||
}
|
||||
|
||||
private static void logScrape(final ObjectName mbeanName, final Set<String> names, final String msg) {
|
||||
logScrape(mbeanName + "_" + names, msg);
|
||||
}
|
||||
|
||||
private static void logScrape(final ObjectName mbeanName, final MBeanAttributeInfo attr, final String msg) {
|
||||
logScrape(mbeanName + "'_'" + attr.getName(), msg);
|
||||
}
|
||||
|
||||
private static void logScrape(final String name, final String msg) {
|
||||
LOGGER.log(Level.FINE, "scrape: '" + name + "': " + msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of mbeans on host_port and scrape their values.
|
||||
* Values are passed to the receiver in a single thread.
|
||||
*
|
||||
* @throws IOException the exception
|
||||
*/
|
||||
public void doScrape() throws IOException {
|
||||
MBeanServerConnection beanConn;
|
||||
JMXConnector jmxc = null;
|
||||
if (jmxUrl.isEmpty()) {
|
||||
beanConn = ManagementFactory.getPlatformMBeanServer();
|
||||
} else {
|
||||
Map<String, Object> environment = new HashMap<>();
|
||||
if (username != null && username.length() != 0 && password != null && password.length() != 0) {
|
||||
String[] credent = new String[]{username, password};
|
||||
environment.put(JMXConnector.CREDENTIALS, credent);
|
||||
}
|
||||
if (ssl) {
|
||||
environment.put(Context.SECURITY_PROTOCOL, "ssl");
|
||||
SslRMIClientSocketFactory clientSocketFactory = new SslRMIClientSocketFactory();
|
||||
environment.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE, clientSocketFactory);
|
||||
environment.put("com.sun.jndi.rmi.factory.socket", clientSocketFactory);
|
||||
}
|
||||
|
||||
jmxc = JMXConnectorFactory.connect(new JMXServiceURL(jmxUrl), environment);
|
||||
beanConn = jmxc.getMBeanServerConnection();
|
||||
}
|
||||
try {
|
||||
// Query MBean names, see #89 for reasons queryMBeans() is used instead of queryNames()
|
||||
Set<ObjectName> mBeanNames = new HashSet<>();
|
||||
for (ObjectName name : whitelistObjectNames) {
|
||||
for (ObjectInstance instance : beanConn.queryMBeans(name, null)) {
|
||||
mBeanNames.add(instance.getObjectName());
|
||||
}
|
||||
}
|
||||
|
||||
for (ObjectName name : blacklistObjectNames) {
|
||||
for (ObjectInstance instance : beanConn.queryMBeans(name, null)) {
|
||||
mBeanNames.remove(instance.getObjectName());
|
||||
}
|
||||
}
|
||||
|
||||
// Now that we have *only* the whitelisted mBeans, remove any old ones from the cache:
|
||||
jmxMBeanPropertyCache.onlyKeepMBeans(mBeanNames);
|
||||
|
||||
for (ObjectName objectName : mBeanNames) {
|
||||
long start = System.nanoTime();
|
||||
scrapeBean(beanConn, objectName);
|
||||
LOGGER.fine("TIME: " + (System.nanoTime() - start) + " ns for " + objectName.toString());
|
||||
}
|
||||
} finally {
|
||||
if (jmxc != null) {
|
||||
jmxc.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void scrapeBean(final MBeanServerConnection beanConn, final ObjectName mbeanName) {
|
||||
MBeanInfo info;
|
||||
try {
|
||||
info = beanConn.getMBeanInfo(mbeanName);
|
||||
} catch (IOException | JMException e) {
|
||||
logScrape(mbeanName.toString(), "getMBeanInfo Fail: " + e);
|
||||
return;
|
||||
}
|
||||
MBeanAttributeInfo[] attrInfos = info.getAttributes();
|
||||
|
||||
Map<String, MBeanAttributeInfo> name2AttrInfo = new LinkedHashMap<>();
|
||||
for (MBeanAttributeInfo attr : attrInfos) {
|
||||
if (!attr.isReadable()) {
|
||||
logScrape(mbeanName, attr, "not readable");
|
||||
continue;
|
||||
}
|
||||
name2AttrInfo.put(attr.getName(), attr);
|
||||
}
|
||||
final AttributeList attributes;
|
||||
try {
|
||||
attributes = beanConn.getAttributes(mbeanName, name2AttrInfo.keySet().toArray(new String[0]));
|
||||
if (attributes == null) {
|
||||
logScrape(mbeanName.toString(), "getAttributes Fail: attributes are null");
|
||||
return;
|
||||
}
|
||||
} catch (InstanceNotFoundException | ReflectionException | IOException e) {
|
||||
logScrape(mbeanName, name2AttrInfo.keySet(), "Fail: " + e);
|
||||
return;
|
||||
}
|
||||
for (Attribute attribute : attributes.asList()) {
|
||||
MBeanAttributeInfo attr = name2AttrInfo.get(attribute.getName());
|
||||
logScrape(mbeanName, attr, "process");
|
||||
processBeanValue(mbeanName.getDomain(), jmxMBeanPropertyCache.getKeyPropertyList(mbeanName),
|
||||
new LinkedList<>(), attr.getName(), attr.getType(), attr.getDescription(), attribute.getValue());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursive function for exporting the values of an mBean.
|
||||
* JMX is a very open technology, without any prescribed way of declaring mBeans
|
||||
* so this function tries to do a best-effort pass of getting the values/names
|
||||
* out in a way it can be processed elsewhere easily.
|
||||
*/
|
||||
private void processBeanValue(final String domain, final Map<String, String> beanProperties,
|
||||
final LinkedList<String> attrKeysParam, final String attrName, final String attrTypeParam,
|
||||
final String attrDescription, final Object valueParam) {
|
||||
LinkedList<String> attrKeys = attrKeysParam;
|
||||
String attrType = attrTypeParam;
|
||||
Object value = valueParam;
|
||||
if (value == null) {
|
||||
logScrape(domain + beanProperties + attrName, "null");
|
||||
} else if (value instanceof Number || value instanceof String || value instanceof Boolean || value instanceof java.util.Date) {
|
||||
if (value instanceof java.util.Date) {
|
||||
attrType = "java.lang.Double";
|
||||
value = ((java.util.Date) value).getTime() / 1000.0;
|
||||
}
|
||||
logScrape(domain + beanProperties + attrName, value.toString());
|
||||
this.receiver.recordBean(domain, beanProperties, attrKeys, attrName, attrType, attrDescription, value);
|
||||
} else if (value instanceof CompositeData) {
|
||||
logScrape(domain + beanProperties + attrName, "compositedata");
|
||||
CompositeData composite = (CompositeData) value;
|
||||
CompositeType type = composite.getCompositeType();
|
||||
attrKeys = new LinkedList<>(attrKeys);
|
||||
attrKeys.add(attrName);
|
||||
for (String key : type.keySet()) {
|
||||
String typ = type.getType(key).getTypeName();
|
||||
Object valu = composite.get(key);
|
||||
processBeanValue(domain, beanProperties, attrKeys, key, typ, type.getDescription(), valu);
|
||||
}
|
||||
} else if (value instanceof TabularData) {
|
||||
// I don't pretend to have a good understanding of TabularData.
|
||||
// The real world usage doesn't appear to match how they were
|
||||
// meant to be used according to the docs. I've only seen them
|
||||
// used as 'key' 'value' pairs even when 'value' is itself a
|
||||
// CompositeData of multiple values.
|
||||
logScrape(domain + beanProperties + attrName, "tabulardata");
|
||||
TabularData tds = (TabularData) value;
|
||||
TabularType tt = tds.getTabularType();
|
||||
List<String> rowKeys = tt.getIndexNames();
|
||||
CompositeType type = tt.getRowType();
|
||||
Set<String> valueKeys = new TreeSet<>(type.keySet());
|
||||
valueKeys.removeAll(rowKeys);
|
||||
LinkedList<String> extendedAttrKeys = new LinkedList<>(attrKeys);
|
||||
extendedAttrKeys.add(attrName);
|
||||
for (Object valu : tds.values()) {
|
||||
if (valu instanceof CompositeData) {
|
||||
CompositeData composite = (CompositeData) valu;
|
||||
Map<String, String> rowKeyMap = new LinkedHashMap<>(beanProperties);
|
||||
String resultKey;
|
||||
for (String rowKey : rowKeys) {
|
||||
resultKey = rowKey;
|
||||
Object obj = composite.get(resultKey);
|
||||
if (obj != null) {
|
||||
// Nested tabulardata will repeat the 'key' label, so
|
||||
// append a suffix to distinguish each.
|
||||
while (rowKeyMap.containsKey(resultKey)) {
|
||||
resultKey = resultKey + "_";
|
||||
}
|
||||
rowKeyMap.put(resultKey, obj.toString());
|
||||
}
|
||||
}
|
||||
for (String valueIdx : valueKeys) {
|
||||
LinkedList<String> attrNames = extendedAttrKeys;
|
||||
String typ = type.getType(valueIdx).getTypeName();
|
||||
String name = valueIdx;
|
||||
if ("value".equalsIgnoreCase(valueIdx.toLowerCase())) {
|
||||
// Skip appending 'value' to the name
|
||||
attrNames = attrKeys;
|
||||
name = attrName;
|
||||
}
|
||||
processBeanValue(domain, rowKeyMap, attrNames, name, typ, type.getDescription(), composite.get(valueIdx));
|
||||
}
|
||||
} else {
|
||||
logScrape(domain, "not a correct tabulardata format");
|
||||
}
|
||||
}
|
||||
} else if (value.getClass().isArray()) {
|
||||
logScrape(domain, "arrays are unsupported");
|
||||
} else {
|
||||
logScrape(domain + beanProperties, attrType + " is not exported");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,44 +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.dromara.hmily.metrics.prometheus.impl.collector;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* The interface M bean receiver.
|
||||
*
|
||||
* @author xiaoyu
|
||||
*/
|
||||
public interface MBeanReceiver {
|
||||
|
||||
/**
|
||||
* Record bean.
|
||||
*
|
||||
* @param domain the domain
|
||||
* @param beanProperties the bean properties
|
||||
* @param attrKeys the attr keys
|
||||
* @param attrName the attr name
|
||||
* @param attrType the attr type
|
||||
* @param attrDescription the attr description
|
||||
* @param value the value
|
||||
*/
|
||||
void recordBean(String domain, Map<String, String> beanProperties,
|
||||
LinkedList<String> attrKeys, String attrName, String attrType,
|
||||
String attrDescription, Object value);
|
||||
}
|
@ -1,44 +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.dromara.hmily.metrics.prometheus.impl.counter;
|
||||
|
||||
import io.prometheus.client.Counter;
|
||||
import org.dromara.hmily.metrics.api.CounterMetricsTracker;
|
||||
import org.dromara.hmily.metrics.enums.MetricsLabelEnum;
|
||||
|
||||
/**
|
||||
* Transaction counter metrics tracker.
|
||||
*/
|
||||
public final class TransactionStatusCounterMetricsTracker implements CounterMetricsTracker {
|
||||
|
||||
private static final Counter TRANSACTION_STATUS = Counter.build()
|
||||
.name("transaction")
|
||||
.labelNames("type", "role", "status")
|
||||
.help("collect transaction status count")
|
||||
.register();
|
||||
|
||||
@Override
|
||||
public void inc(final double amount, final String... labelValues) {
|
||||
TRANSACTION_STATUS.labels(labelValues).inc(amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String metricsLabel() {
|
||||
return MetricsLabelEnum.TRANSACTION_STATUS.getName();
|
||||
}
|
||||
}
|
@ -1,45 +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.dromara.hmily.metrics.prometheus.impl.counter;
|
||||
|
||||
import io.prometheus.client.Counter;
|
||||
import org.dromara.hmily.metrics.api.CounterMetricsTracker;
|
||||
import org.dromara.hmily.metrics.enums.MetricsLabelEnum;
|
||||
|
||||
/**
|
||||
* Request total counter metrics tracker.
|
||||
*/
|
||||
public final class TransactionTotalCounterMetricsTracker implements CounterMetricsTracker {
|
||||
|
||||
private static final Counter TRANSACTION_TOTAL = Counter.build()
|
||||
.name("transaction_total")
|
||||
.labelNames("type")
|
||||
.help("hmily request total count")
|
||||
.register();
|
||||
|
||||
@Override
|
||||
public void inc(final double amount, final String... labelValues) {
|
||||
TRANSACTION_TOTAL.labels(labelValues).inc(amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String metricsLabel() {
|
||||
return MetricsLabelEnum.TRANSACTION_TOTAL.getName();
|
||||
}
|
||||
}
|
||||
|
@ -1,39 +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.dromara.hmily.metrics.prometheus.impl.histogram;
|
||||
|
||||
import io.prometheus.client.Histogram;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.hmily.metrics.api.HistogramMetricsTrackerDelegate;
|
||||
|
||||
/**
|
||||
* Prometheus histogram metrics tracker delegate.
|
||||
*
|
||||
* @author xiaoyu
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public final class PrometheusHistogramMetricsTrackerDelegate implements HistogramMetricsTrackerDelegate {
|
||||
|
||||
private final Histogram.Timer timer;
|
||||
|
||||
@Override
|
||||
public void observeDuration() {
|
||||
timer.observeDuration();
|
||||
}
|
||||
}
|
||||
|
@ -1,48 +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.dromara.hmily.metrics.prometheus.impl.histogram;
|
||||
|
||||
import io.prometheus.client.Histogram;
|
||||
import org.dromara.hmily.metrics.api.HistogramMetricsTracker;
|
||||
import org.dromara.hmily.metrics.api.HistogramMetricsTrackerDelegate;
|
||||
import org.dromara.hmily.metrics.enums.MetricsLabelEnum;
|
||||
|
||||
/**
|
||||
* Transaction latency histogram metrics tracker.
|
||||
*
|
||||
* @author xiaoyu
|
||||
*/
|
||||
public final class TransactionLatencyHistogramMetricsTracker implements HistogramMetricsTracker {
|
||||
|
||||
private static final Histogram TRANSACTION_LATENCY = Histogram.build()
|
||||
.labelNames("type")
|
||||
.name("transaction_latency_histogram_millis").help("Transaction Latency Histogram Millis (ms)")
|
||||
.register();
|
||||
|
||||
@Override
|
||||
public HistogramMetricsTrackerDelegate startTimer(final String... labelValues) {
|
||||
Histogram.Timer timer = TRANSACTION_LATENCY.labels(labelValues).startTimer();
|
||||
return new PrometheusHistogramMetricsTrackerDelegate(timer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String metricsLabel() {
|
||||
return MetricsLabelEnum.TRANSACTION_LATENCY.getName();
|
||||
}
|
||||
}
|
||||
|
@ -1,39 +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.dromara.hmily.metrics.prometheus.impl.summary;
|
||||
|
||||
import io.prometheus.client.Summary;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.hmily.metrics.api.SummaryMetricsTrackerDelegate;
|
||||
|
||||
/**
|
||||
* Prometheus summary metrics tracker delegate.
|
||||
*
|
||||
* @author xiaoyu
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public final class PrometheusSummaryMetricsTrackerDelegate implements SummaryMetricsTrackerDelegate {
|
||||
|
||||
private final Summary.Timer timer;
|
||||
|
||||
@Override
|
||||
public void observeDuration() {
|
||||
timer.observeDuration();
|
||||
}
|
||||
}
|
||||
|
@ -1,54 +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.dromara.hmily.metrics.prometheus.impl.summary;
|
||||
|
||||
import io.prometheus.client.Summary;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.dromara.hmily.metrics.api.SummaryMetricsTracker;
|
||||
import org.dromara.hmily.metrics.api.SummaryMetricsTrackerDelegate;
|
||||
import org.dromara.hmily.metrics.enums.MetricsLabelEnum;
|
||||
|
||||
/**
|
||||
* Transaction latency summary metrics tracker.
|
||||
*
|
||||
* @author xiaoyu
|
||||
*/
|
||||
public final class TransactionLatencySummaryMetricsTracker implements SummaryMetricsTracker {
|
||||
|
||||
private static final Summary TRANSACTION_LATENCY = Summary.build()
|
||||
.name("transaction_latency_summary_millis").labelNames("type")
|
||||
.help("Requests Latency Summary Millis (ms)")
|
||||
.quantile(0.5, 0.05)
|
||||
.quantile(0.95, 0.01)
|
||||
.quantile(0.99, 0.001)
|
||||
.maxAgeSeconds(TimeUnit.MINUTES.toSeconds(5))
|
||||
.ageBuckets(5)
|
||||
.register();
|
||||
|
||||
@Override
|
||||
public SummaryMetricsTrackerDelegate startTimer(final String... labelValues) {
|
||||
Summary.Timer timer = TRANSACTION_LATENCY.labels(labelValues).startTimer();
|
||||
return new PrometheusSummaryMetricsTrackerDelegate(timer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String metricsLabel() {
|
||||
return MetricsLabelEnum.TRANSACTION_LATENCY.getName();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,129 @@
|
||||
/*
|
||||
* 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.dromara.hmily.metrics.prometheus.register;
|
||||
|
||||
import io.prometheus.client.Counter;
|
||||
import io.prometheus.client.Gauge;
|
||||
import io.prometheus.client.Histogram;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.hmily.metrics.spi.MetricsRegister;
|
||||
import org.dromara.hmily.spi.HmilySPI;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Prometheus metrics register.
|
||||
*/
|
||||
@Slf4j
|
||||
@HmilySPI("prometheus")
|
||||
public final class PrometheusMetricsRegister implements MetricsRegister {
|
||||
|
||||
private static final Map<String, Counter> COUNTER_MAP = new ConcurrentHashMap<>();
|
||||
|
||||
private static final Map<String, Gauge> GAUGE_MAP = new ConcurrentHashMap<>();
|
||||
|
||||
private static final Map<String, Histogram> HISTOGRAM_MAP = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* Get instance prometheus metrics register.
|
||||
*
|
||||
* @return the prometheus metrics register
|
||||
*/
|
||||
public static PrometheusMetricsRegister getInstance() {
|
||||
return PrometheusMetricsRegisterHolder.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerCounter(final String name, final String[] labelNames, final String document) {
|
||||
if (!COUNTER_MAP.containsKey(name)) {
|
||||
Counter.Builder builder = Counter.build().name(name).help(document);
|
||||
if (null != labelNames) {
|
||||
builder.labelNames(labelNames);
|
||||
}
|
||||
COUNTER_MAP.put(name, builder.register());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerGauge(final String name, final String[] labelNames, final String document) {
|
||||
if (!GAUGE_MAP.containsKey(name)) {
|
||||
Gauge.Builder builder = Gauge.build().name(name).help(document);
|
||||
if (null != labelNames) {
|
||||
builder.labelNames(labelNames);
|
||||
}
|
||||
GAUGE_MAP.put(name, builder.register());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerHistogram(final String name, final String[] labelNames, final String document) {
|
||||
if (!HISTOGRAM_MAP.containsKey(name)) {
|
||||
Histogram.Builder builder = Histogram.build().name(name).help(document);
|
||||
if (null != labelNames) {
|
||||
builder.labelNames(labelNames);
|
||||
}
|
||||
HISTOGRAM_MAP.put(name, builder.register());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void counterIncrement(final String name, final String[] labelValues, final long count) {
|
||||
Counter counter = COUNTER_MAP.get(name);
|
||||
if (null != labelValues) {
|
||||
counter.labels(labelValues).inc(count);
|
||||
} else {
|
||||
counter.inc(count);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void gaugeIncrement(final String name, final String[] labelValues) {
|
||||
Gauge gauge = GAUGE_MAP.get(name);
|
||||
if (null != labelValues) {
|
||||
gauge.labels(labelValues).inc();
|
||||
} else {
|
||||
gauge.inc();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void gaugeDecrement(final String name, final String[] labelValues) {
|
||||
Gauge gauge = GAUGE_MAP.get(name);
|
||||
if (null != labelValues) {
|
||||
gauge.labels(labelValues).dec();
|
||||
} else {
|
||||
gauge.dec();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recordTime(final String name, final String[] labelValues, final long duration) {
|
||||
Histogram histogram = HISTOGRAM_MAP.get(name);
|
||||
if (null != labelValues) {
|
||||
histogram.labels(labelValues).observe(duration);
|
||||
} else {
|
||||
histogram.observe(duration);
|
||||
}
|
||||
}
|
||||
|
||||
private static class PrometheusMetricsRegisterHolder {
|
||||
|
||||
private static final PrometheusMetricsRegister INSTANCE = new PrometheusMetricsRegister();
|
||||
}
|
||||
}
|
@ -15,24 +15,26 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.dromara.hmily.metrics.prometheus;
|
||||
package org.dromara.hmily.metrics.prometheus.service;
|
||||
|
||||
import io.prometheus.client.CollectorRegistry;
|
||||
import io.prometheus.client.exporter.HTTPServer;
|
||||
import io.prometheus.client.hotspot.DefaultExports;
|
||||
import io.prometheus.jmx.JmxCollector;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.dromara.hmily.config.api.entity.HmilyMetricsConfig;
|
||||
import org.dromara.hmily.metrics.prometheus.collector.BuildInfoCollector;
|
||||
import org.dromara.hmily.metrics.reporter.MetricsReporter;
|
||||
import org.dromara.hmily.metrics.spi.MetricsBootService;
|
||||
import org.dromara.hmily.metrics.spi.MetricsRegister;
|
||||
import org.dromara.hmily.spi.HmilySPI;
|
||||
|
||||
import javax.management.MalformedObjectNameException;
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import javax.management.MalformedObjectNameException;
|
||||
import lombok.Getter;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.hmily.config.api.entity.HmilyMetricsConfig;
|
||||
import org.dromara.hmily.metrics.api.MetricsTrackerFactory;
|
||||
import org.dromara.hmily.metrics.prometheus.impl.collector.BuildInfoCollector;
|
||||
import org.dromara.hmily.metrics.prometheus.impl.collector.JmxCollector;
|
||||
import org.dromara.hmily.metrics.spi.MetricsTrackerManager;
|
||||
import org.dromara.hmily.spi.HmilySPI;
|
||||
|
||||
/**
|
||||
* Prometheus metrics tracker manager.
|
||||
@ -40,31 +42,43 @@ import org.dromara.hmily.spi.HmilySPI;
|
||||
@Getter
|
||||
@Slf4j
|
||||
@HmilySPI("prometheus")
|
||||
public final class PrometheusMetricsTrackerManager implements MetricsTrackerManager {
|
||||
|
||||
private final MetricsTrackerFactory metricsTrackerFactory = new PrometheusMetricsTrackerFactory();
|
||||
public final class PrometheusBootService implements MetricsBootService {
|
||||
|
||||
private HTTPServer server;
|
||||
|
||||
private volatile AtomicBoolean registered = new AtomicBoolean(false);
|
||||
|
||||
@SneakyThrows(IOException.class)
|
||||
@Override
|
||||
public void start(final HmilyMetricsConfig metricsConfig) {
|
||||
register(metricsConfig.getJmxConfig());
|
||||
InetSocketAddress inetSocketAddress;
|
||||
if ("".equals(metricsConfig.getHost()) || null == metricsConfig.getHost()) {
|
||||
inetSocketAddress = new InetSocketAddress(metricsConfig.getPort());
|
||||
} else {
|
||||
inetSocketAddress = new InetSocketAddress(metricsConfig.getHost(), metricsConfig.getPort());
|
||||
}
|
||||
server = new HTTPServer(inetSocketAddress, CollectorRegistry.defaultRegistry, true);
|
||||
log.info("you start prometheus metrics http server host is :{}, port is :{} ", inetSocketAddress.getHostString(), inetSocketAddress.getPort());
|
||||
public void start(final HmilyMetricsConfig metricsConfig, final MetricsRegister register) {
|
||||
startServer(metricsConfig);
|
||||
MetricsReporter.register(register);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
server.stop();
|
||||
if (server != null) {
|
||||
server.stop();
|
||||
registered.set(false);
|
||||
CollectorRegistry.defaultRegistry.clear();
|
||||
}
|
||||
}
|
||||
|
||||
private void startServer(final HmilyMetricsConfig metricsConfig) {
|
||||
register(metricsConfig.getJmxConfig());
|
||||
int port = metricsConfig.getPort();
|
||||
String host = metricsConfig.getHost();
|
||||
InetSocketAddress inetSocketAddress;
|
||||
if (null == host || "".equalsIgnoreCase(host)) {
|
||||
inetSocketAddress = new InetSocketAddress(port);
|
||||
} else {
|
||||
inetSocketAddress = new InetSocketAddress(host, port);
|
||||
}
|
||||
try {
|
||||
server = new HTTPServer(inetSocketAddress, CollectorRegistry.defaultRegistry, true);
|
||||
log.info(String.format("Prometheus metrics HTTP server `%s:%s` start success.", inetSocketAddress.getHostString(), inetSocketAddress.getPort()));
|
||||
} catch (final IOException ex) {
|
||||
log.error("Prometheus metrics HTTP server start fail", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void register(final String jmxConfig) {
|
||||
@ -72,11 +86,13 @@ public final class PrometheusMetricsTrackerManager implements MetricsTrackerMana
|
||||
return;
|
||||
}
|
||||
new BuildInfoCollector().register();
|
||||
DefaultExports.initialize();
|
||||
try {
|
||||
new JmxCollector(jmxConfig).register();
|
||||
DefaultExports.initialize();
|
||||
if (StringUtils.isNotEmpty(jmxConfig)) {
|
||||
new JmxCollector(jmxConfig).register();
|
||||
}
|
||||
} catch (MalformedObjectNameException e) {
|
||||
log.error("init jxm collector error", e);
|
||||
log.error("init jmx collector error", e);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
org.dromara.hmily.metrics.prometheus.service.PrometheusBootService
|
@ -0,0 +1 @@
|
||||
org.dromara.hmily.metrics.prometheus.register.PrometheusMetricsRegister
|
@ -1 +0,0 @@
|
||||
org.dromara.hmily.metrics.prometheus.PrometheusMetricsTrackerManager
|
@ -1,46 +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.dromara.hmily.metrics.api;
|
||||
|
||||
import org.dromara.hmily.metrics.enums.MetricsTypeEnum;
|
||||
|
||||
/**
|
||||
* Counter metrics tracker interface.
|
||||
*
|
||||
* @author xiaoyu
|
||||
*/
|
||||
public interface CounterMetricsTracker extends MetricsTracker {
|
||||
|
||||
/**
|
||||
* Increment the counter with label values by the given amount.
|
||||
*
|
||||
* @param amount amount
|
||||
* @param labelValues label values
|
||||
*/
|
||||
void inc(double amount, String... labelValues);
|
||||
|
||||
/**
|
||||
* Metrics type.
|
||||
*
|
||||
* @return metrics type
|
||||
*/
|
||||
default String metricsType() {
|
||||
return MetricsTypeEnum.COUNTER.name();
|
||||
}
|
||||
}
|
||||
|
@ -1,54 +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.dromara.hmily.metrics.api;
|
||||
|
||||
import org.dromara.hmily.metrics.enums.MetricsTypeEnum;
|
||||
|
||||
/**
|
||||
* Gauge metrics tracker interface.
|
||||
*
|
||||
* @author xiaoyu
|
||||
*/
|
||||
public interface GaugeMetricsTracker extends MetricsTracker {
|
||||
|
||||
/**
|
||||
* Increment the Gauge with label values by the given amount.
|
||||
*
|
||||
* @param amount amount
|
||||
* @param labelValues label values
|
||||
*/
|
||||
void inc(double amount, String... labelValues);
|
||||
|
||||
/**
|
||||
* Decrement the Gauge with label values by the given amount.
|
||||
*
|
||||
* @param amount amount
|
||||
* @param labelValues label values
|
||||
*/
|
||||
void dec(double amount, String... labelValues);
|
||||
|
||||
/**
|
||||
* Metrics type.
|
||||
*
|
||||
* @return metrics type
|
||||
*/
|
||||
default String metricsType() {
|
||||
return MetricsTypeEnum.GAUGE.name();
|
||||
}
|
||||
}
|
||||
|
@ -1,56 +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.dromara.hmily.metrics.api;
|
||||
|
||||
import org.dromara.hmily.metrics.enums.MetricsTypeEnum;
|
||||
|
||||
/**
|
||||
* Histogram metrics tracker.
|
||||
*
|
||||
* @author xiaoyu
|
||||
*/
|
||||
public interface HistogramMetricsTracker extends MetricsTracker {
|
||||
|
||||
/**
|
||||
* Start timer with histogram.
|
||||
*
|
||||
* @param labelValues label values
|
||||
* @return histogram metrics tracker delegate
|
||||
*/
|
||||
default HistogramMetricsTrackerDelegate startTimer(String... labelValues) {
|
||||
return new NoneHistogramMetricsTrackerDelegate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Observe the given amount.
|
||||
*
|
||||
* @param amount amount
|
||||
*/
|
||||
default void observer(long amount) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Metrics type.
|
||||
*
|
||||
* @return metrics type
|
||||
*/
|
||||
default String metricsType() {
|
||||
return MetricsTypeEnum.HISTOGRAM.name();
|
||||
}
|
||||
}
|
||||
|
@ -1,33 +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.dromara.hmily.metrics.api;
|
||||
|
||||
/**
|
||||
* Histogram metrics tracker delegate.
|
||||
*
|
||||
* @author xiaoyu
|
||||
*/
|
||||
public interface HistogramMetricsTrackerDelegate {
|
||||
|
||||
/**
|
||||
* Observe amount of time since start time.
|
||||
*/
|
||||
default void observeDuration() {
|
||||
}
|
||||
}
|
||||
|
@ -1,38 +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.dromara.hmily.metrics.api;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Metrics tracker factory.
|
||||
*
|
||||
* @author xiaoyu
|
||||
*/
|
||||
public interface MetricsTrackerFactory {
|
||||
|
||||
/**
|
||||
* Create of metrics tracker.
|
||||
*
|
||||
* @param metricsType metrics type
|
||||
* @param metricsLabel metrics label
|
||||
* @return metrics tracker
|
||||
*/
|
||||
Optional<MetricsTracker> create(String metricsType, String metricsLabel);
|
||||
}
|
||||
|
@ -1,27 +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.dromara.hmily.metrics.api;
|
||||
|
||||
/**
|
||||
* The type None histogram metrics tracker delegate.
|
||||
*
|
||||
* @author xiaoyu
|
||||
*/
|
||||
public final class NoneHistogramMetricsTrackerDelegate implements HistogramMetricsTrackerDelegate {
|
||||
}
|
||||
|
@ -1,27 +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.dromara.hmily.metrics.api;
|
||||
|
||||
/**
|
||||
* None summary metrics tracker delegate.
|
||||
*
|
||||
* @author xiaoyu
|
||||
*/
|
||||
public final class NoneSummaryMetricsTrackerDelegate implements SummaryMetricsTrackerDelegate {
|
||||
}
|
||||
|
@ -1,55 +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.dromara.hmily.metrics.api;
|
||||
|
||||
import org.dromara.hmily.metrics.enums.MetricsTypeEnum;
|
||||
|
||||
/**
|
||||
* Summary metrics tracker.
|
||||
*
|
||||
* @author xiaoyu
|
||||
*/
|
||||
public interface SummaryMetricsTracker extends MetricsTracker {
|
||||
|
||||
/**
|
||||
* Start timer with summary.
|
||||
*
|
||||
* @param labelValues label values
|
||||
* @return Summary metrics tracker delegate
|
||||
*/
|
||||
default SummaryMetricsTrackerDelegate startTimer(String... labelValues) {
|
||||
return new NoneSummaryMetricsTrackerDelegate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Observe the given amount.
|
||||
*
|
||||
* @param amount amount
|
||||
*/
|
||||
default void observer(long amount) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Metrics type.
|
||||
*
|
||||
* @return metrics type
|
||||
*/
|
||||
default String metricsType() {
|
||||
return MetricsTypeEnum.SUMMARY.name();
|
||||
}
|
||||
}
|
@ -1,33 +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.dromara.hmily.metrics.api;
|
||||
|
||||
/**
|
||||
* Summary metrics tracker delegate.
|
||||
*
|
||||
* @author xiaoyu
|
||||
*/
|
||||
public interface SummaryMetricsTrackerDelegate {
|
||||
|
||||
/**
|
||||
* Observe amount of time in seconds since start time.
|
||||
*/
|
||||
default void observeDuration() {
|
||||
}
|
||||
}
|
||||
|
@ -15,27 +15,25 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.dromara.hmily.metrics.api;
|
||||
package org.dromara.hmily.metrics.constant;
|
||||
|
||||
/**
|
||||
* Metrics tracker.
|
||||
*
|
||||
* @author xiaoyu
|
||||
* The Label names.
|
||||
*/
|
||||
public interface MetricsTracker {
|
||||
public final class LabelNames {
|
||||
|
||||
/**
|
||||
* Metrics label.
|
||||
*
|
||||
* @return metrics label
|
||||
* The constant TRANSACTION_STATUS.
|
||||
*/
|
||||
String metricsLabel();
|
||||
public static final String TRANSACTION_STATUS = "hmily_transaction_status";
|
||||
|
||||
/**
|
||||
* Metrics type.
|
||||
*
|
||||
* @return metrics type
|
||||
* The constant TRANSACTION_TOTAL.
|
||||
*/
|
||||
String metricsType();
|
||||
public static final String TRANSACTION_TOTAL = "hmily_transaction_total";
|
||||
|
||||
/**
|
||||
* The constant TRANSACTION_LATENCY.
|
||||
*/
|
||||
public static final String TRANSACTION_LATENCY = "hmily_transaction_latency_histogram_millis";
|
||||
}
|
||||
|
@ -15,34 +15,26 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.dromara.hmily.metrics.enums;
|
||||
package org.dromara.hmily.metrics.entity;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.dromara.hmily.metrics.enums.MetricType;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Metrics label enum.
|
||||
*
|
||||
* @author xiaoyu
|
||||
* Metric.
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public enum MetricsLabelEnum {
|
||||
@RequiredArgsConstructor
|
||||
public final class Metric {
|
||||
|
||||
/**
|
||||
* transaction total metrics label.
|
||||
*/
|
||||
TRANSACTION_TOTAL("transaction_total"),
|
||||
|
||||
/**
|
||||
* transaction latency metrics label.
|
||||
*/
|
||||
TRANSACTION_LATENCY("transaction_latency"),
|
||||
|
||||
/**
|
||||
* Transaction status metrics label enum.
|
||||
*/
|
||||
TRANSACTION_STATUS("transaction_status");
|
||||
private final MetricType type;
|
||||
|
||||
private final String name;
|
||||
|
||||
private final String document;
|
||||
|
||||
private final List<String> labels;
|
||||
}
|
@ -17,31 +17,28 @@
|
||||
|
||||
package org.dromara.hmily.metrics.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* Metrics type enum.
|
||||
*
|
||||
* @author xiaoyu
|
||||
* Metric type.
|
||||
*/
|
||||
public enum MetricsTypeEnum {
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public enum MetricType {
|
||||
|
||||
/**
|
||||
* Counter metrics type.
|
||||
* Counter metric type.
|
||||
*/
|
||||
COUNTER,
|
||||
|
||||
/**
|
||||
* Gauge metrics type.
|
||||
* Gauge metric type.
|
||||
*/
|
||||
GAUGE,
|
||||
|
||||
/**
|
||||
* Histogram metrics type.
|
||||
* Histogram metric type.
|
||||
*/
|
||||
HISTOGRAM,
|
||||
|
||||
/**
|
||||
* Summary metrics type.
|
||||
*/
|
||||
SUMMARY
|
||||
HISTOGRAM
|
||||
}
|
||||
|
@ -0,0 +1,221 @@
|
||||
/*
|
||||
* 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.dromara.hmily.metrics.reporter;
|
||||
|
||||
import org.dromara.hmily.metrics.spi.MetricsRegister;
|
||||
import org.dromara.hmily.metrics.entity.Metric;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Metrics reporter.
|
||||
*/
|
||||
public final class MetricsReporter {
|
||||
|
||||
private static MetricsRegister metricsRegister;
|
||||
|
||||
/**
|
||||
* Register.
|
||||
*
|
||||
* @param metricsRegister metrics register
|
||||
*/
|
||||
public static void register(final MetricsRegister metricsRegister) {
|
||||
MetricsReporter.metricsRegister = metricsRegister;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register metrics.
|
||||
*
|
||||
* @param metrics metric collection
|
||||
*/
|
||||
public static void registerMetrics(final Collection<Metric> metrics) {
|
||||
for (Metric metric : metrics) {
|
||||
switch (metric.getType()) {
|
||||
case COUNTER:
|
||||
registerCounter(metric.getName(), getLabelNames(metric.getLabels()), metric.getDocument());
|
||||
break;
|
||||
case GAUGE:
|
||||
registerGauge(metric.getName(), getLabelNames(metric.getLabels()), metric.getDocument());
|
||||
break;
|
||||
case HISTOGRAM:
|
||||
registerHistogram(metric.getName(), getLabelNames(metric.getLabels()), metric.getDocument());
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("we not support metric registration for type: " + metric.getType());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register counter.
|
||||
*
|
||||
* @param name name
|
||||
* @param labelNames label names
|
||||
* @param document document for counter
|
||||
*/
|
||||
public static void registerCounter(final String name, final String[] labelNames, final String document) {
|
||||
Optional.ofNullable(metricsRegister).ifPresent(register -> register.registerCounter(name, labelNames, document));
|
||||
}
|
||||
|
||||
/**
|
||||
* Register counter.
|
||||
*
|
||||
* @param name name
|
||||
* @param document document for counter
|
||||
*/
|
||||
public static void registerCounter(final String name, final String document) {
|
||||
registerCounter(name, null, document);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register gauge.
|
||||
*
|
||||
* @param name name
|
||||
* @param labelNames label names
|
||||
* @param document document for gauge
|
||||
*/
|
||||
public static void registerGauge(final String name, final String[] labelNames, final String document) {
|
||||
Optional.ofNullable(metricsRegister).ifPresent(register -> register.registerGauge(name, labelNames, document));
|
||||
}
|
||||
|
||||
/**
|
||||
* Register gauge.
|
||||
*
|
||||
* @param name name
|
||||
* @param document document for gauge
|
||||
*/
|
||||
public static void registerGauge(final String name, final String document) {
|
||||
registerGauge(name, null, document);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register histogram by label names.
|
||||
*
|
||||
* @param name name
|
||||
* @param labelNames label names
|
||||
* @param document document for histogram
|
||||
*/
|
||||
public static void registerHistogram(final String name, final String[] labelNames, final String document) {
|
||||
Optional.ofNullable(metricsRegister).ifPresent(register -> register.registerHistogram(name, labelNames, document));
|
||||
}
|
||||
|
||||
/**
|
||||
* Register histogram.
|
||||
*
|
||||
* @param name name
|
||||
* @param document document for histogram
|
||||
*/
|
||||
public static void registerHistogram(final String name, final String document) {
|
||||
registerHistogram(name, null, document);
|
||||
}
|
||||
|
||||
/**
|
||||
* Counter increment.
|
||||
*
|
||||
* @param name name
|
||||
* @param labelValues label values
|
||||
*/
|
||||
public static void counterIncrement(final String name, final String[] labelValues) {
|
||||
counterIncrement(name, labelValues, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Counter increment.
|
||||
*
|
||||
* @param name name
|
||||
*/
|
||||
public static void counterIncrement(final String name) {
|
||||
counterIncrement(name, null, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Counter increment by count.
|
||||
*
|
||||
* @param name name
|
||||
* @param labelValues label values
|
||||
* @param count count
|
||||
*/
|
||||
public static void counterIncrement(final String name, final String[] labelValues, final long count) {
|
||||
Optional.ofNullable(metricsRegister).ifPresent(register -> register.counterIncrement(name, labelValues, count));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gauge increment.
|
||||
*
|
||||
* @param name name
|
||||
* @param labelValues label values
|
||||
*/
|
||||
public static void gaugeIncrement(final String name, final String[] labelValues) {
|
||||
Optional.ofNullable(metricsRegister).ifPresent(register -> register.gaugeIncrement(name, labelValues));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gauge increment.
|
||||
*
|
||||
* @param name name
|
||||
*/
|
||||
public static void gaugeIncrement(final String name) {
|
||||
gaugeIncrement(name, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gauge decrement.
|
||||
*
|
||||
* @param name name
|
||||
* @param labelValues label values
|
||||
*/
|
||||
public static void gaugeDecrement(final String name, final String[] labelValues) {
|
||||
Optional.ofNullable(metricsRegister).ifPresent(register -> register.gaugeDecrement(name, labelValues));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gauge decrement.
|
||||
*
|
||||
* @param name name
|
||||
*/
|
||||
public static void gaugeDecrement(final String name) {
|
||||
gaugeDecrement(name, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Record time by duration.
|
||||
*
|
||||
* @param name name
|
||||
* @param labelValues label values
|
||||
* @param duration duration
|
||||
*/
|
||||
public static void recordTime(final String name, final String[] labelValues, final long duration) {
|
||||
Optional.ofNullable(metricsRegister).ifPresent(register -> register.recordTime(name, labelValues, duration));
|
||||
}
|
||||
|
||||
/**
|
||||
* Record time by duration.
|
||||
*
|
||||
* @param name name
|
||||
* @param duration duration
|
||||
*/
|
||||
public static void recordTime(final String name, final long duration) {
|
||||
recordTime(name, null, duration);
|
||||
}
|
||||
|
||||
private static String[] getLabelNames(final List<String> labels) {
|
||||
return labels.toArray(new String[0]);
|
||||
}
|
||||
}
|
@ -18,28 +18,19 @@
|
||||
package org.dromara.hmily.metrics.spi;
|
||||
|
||||
import org.dromara.hmily.config.api.entity.HmilyMetricsConfig;
|
||||
import org.dromara.hmily.metrics.api.MetricsTrackerFactory;
|
||||
|
||||
/**
|
||||
* Metrics tracker manager.
|
||||
*
|
||||
* @author xiaoyu
|
||||
*/
|
||||
public interface MetricsTrackerManager {
|
||||
public interface MetricsBootService {
|
||||
|
||||
/**
|
||||
* Start metrics tracker.
|
||||
*
|
||||
* @param metricsConfig metrics config
|
||||
* @param register the register
|
||||
*/
|
||||
void start(HmilyMetricsConfig metricsConfig);
|
||||
|
||||
/**
|
||||
* Gets metrics tracker factory.
|
||||
*
|
||||
* @return metrics tracker factory
|
||||
*/
|
||||
MetricsTrackerFactory getMetricsTrackerFactory();
|
||||
void start(HmilyMetricsConfig metricsConfig, MetricsRegister register);
|
||||
|
||||
/**
|
||||
* Stop metrics tracker.
|
@ -1,71 +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.dromara.hmily.metrics.spi;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Metrics Handler facade.
|
||||
*
|
||||
* @author xiaoyu
|
||||
*/
|
||||
public interface MetricsHandlerFacade {
|
||||
|
||||
/**
|
||||
* Increment of counter metrics tracker.
|
||||
*
|
||||
* @param metricsLabel metrics label
|
||||
* @param labelValues label values
|
||||
*/
|
||||
void counterIncrement(String metricsLabel, String... labelValues);
|
||||
|
||||
/**
|
||||
* Increment of gauge metrics tracker.
|
||||
*
|
||||
* @param metricsLabel metrics label
|
||||
* @param labelValues label values
|
||||
*/
|
||||
void gaugeIncrement(String metricsLabel, String... labelValues);
|
||||
|
||||
/**
|
||||
* Decrement of gauge metrics tracker.
|
||||
*
|
||||
* @param metricsLabel metrics label
|
||||
* @param labelValues label values
|
||||
*/
|
||||
void gaugeDecrement(String metricsLabel, String... labelValues);
|
||||
|
||||
/**
|
||||
* Start timer of histogram metrics tracker.
|
||||
*
|
||||
* @param metricsLabel metrics label
|
||||
* @param labelValues label values
|
||||
* @return histogram metrics tracker delegate
|
||||
*/
|
||||
Supplier<Boolean> histogramStartTimer(String metricsLabel, String... labelValues);
|
||||
|
||||
/**
|
||||
* Start timer of summary metrics tracker.
|
||||
*
|
||||
* @param metricsLabel metrics label
|
||||
* @param labelValues label values
|
||||
* @return summary metrics tracker delegate
|
||||
*/
|
||||
Supplier<Boolean> summaryStartTimer(String metricsLabel, String... labelValues);
|
||||
}
|
||||
|
@ -1,38 +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.dromara.hmily.metrics.spi;
|
||||
|
||||
import java.util.Optional;
|
||||
import org.dromara.hmily.spi.ExtensionLoaderFactory;
|
||||
|
||||
/**
|
||||
* The type Metrics handler facade engine.
|
||||
*
|
||||
* @author xiaoyu
|
||||
*/
|
||||
public final class MetricsHandlerFacadeEngine {
|
||||
|
||||
/**
|
||||
* Load MetricsHandlerFacade optional.
|
||||
*
|
||||
* @return the optional
|
||||
*/
|
||||
public static Optional<MetricsHandlerFacade> load() {
|
||||
return Optional.ofNullable(ExtensionLoaderFactory.load(MetricsHandlerFacade.class));
|
||||
}
|
||||
}
|
@ -1,35 +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.dromara.hmily.metrics.spi;
|
||||
|
||||
import org.dromara.hmily.config.api.entity.HmilyMetricsConfig;
|
||||
|
||||
/**
|
||||
* The interface Metrics init.
|
||||
*
|
||||
* @author xiaoyu
|
||||
*/
|
||||
public interface MetricsInit extends AutoCloseable {
|
||||
|
||||
/**
|
||||
* Init.
|
||||
*
|
||||
* @param metricsConfig the metrics config
|
||||
*/
|
||||
void init(HmilyMetricsConfig metricsConfig);
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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.dromara.hmily.metrics.spi;
|
||||
|
||||
/**
|
||||
* Metrics register.
|
||||
*/
|
||||
public interface MetricsRegister {
|
||||
|
||||
/**
|
||||
* Register gauge.
|
||||
*
|
||||
* @param name name
|
||||
* @param labelNames label names
|
||||
* @param document document for gauge
|
||||
*/
|
||||
void registerGauge(String name, String[] labelNames, String document);
|
||||
|
||||
/**
|
||||
* Register counter.
|
||||
*
|
||||
* @param name name
|
||||
* @param labelNames label names
|
||||
* @param document document for counter
|
||||
*/
|
||||
void registerCounter(String name, String[] labelNames, String document);
|
||||
|
||||
/**
|
||||
* Register histogram.
|
||||
*
|
||||
* @param name name
|
||||
* @param labelNames label names
|
||||
* @param document document for histogram
|
||||
*/
|
||||
void registerHistogram(String name, String[] labelNames, String document);
|
||||
|
||||
/**
|
||||
* Counter increment by count.
|
||||
*
|
||||
* @param name name
|
||||
* @param labelValues label values
|
||||
* @param count count
|
||||
*/
|
||||
void counterIncrement(String name, String[] labelValues, long count);
|
||||
|
||||
/**
|
||||
* Gauge increment.
|
||||
*
|
||||
* @param name name
|
||||
* @param labelValues label values
|
||||
*/
|
||||
void gaugeIncrement(String name, String[] labelValues);
|
||||
|
||||
/**
|
||||
* Gauge decrement.
|
||||
*
|
||||
* @param name name
|
||||
* @param labelValues label values
|
||||
*/
|
||||
void gaugeDecrement(String name, String[] labelValues);
|
||||
|
||||
/**
|
||||
* Record time by duration.
|
||||
*
|
||||
* @param name name
|
||||
* @param labelValues label values
|
||||
* @param duration duration
|
||||
*/
|
||||
void recordTime(String name, String[] labelValues, long duration);
|
||||
}
|
@ -20,8 +20,8 @@
|
||||
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>hmily</artifactId>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>hmily</artifactId>
|
||||
<version>2.1.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
@ -28,8 +28,8 @@ import org.dromara.hmily.core.context.HmilyContextHolder;
|
||||
import org.dromara.hmily.core.context.HmilyTransactionContext;
|
||||
import org.dromara.hmily.core.repository.HmilyRepositoryStorage;
|
||||
import org.dromara.hmily.core.service.HmilyTransactionHandler;
|
||||
import org.dromara.hmily.metrics.enums.MetricsLabelEnum;
|
||||
import org.dromara.hmily.metrics.spi.MetricsHandlerFacadeEngine;
|
||||
import org.dromara.hmily.metrics.constant.LabelNames;
|
||||
import org.dromara.hmily.metrics.reporter.MetricsReporter;
|
||||
import org.dromara.hmily.repository.spi.entity.HmilyParticipant;
|
||||
import org.dromara.hmily.tac.core.transaction.HmilyTacParticipantCoordinator;
|
||||
|
||||
@ -46,6 +46,10 @@ public class ParticipantHmilyTacTransactionHandler implements HmilyTransactionHa
|
||||
|
||||
private final HmilyTacParticipantCoordinator coordinator = HmilyTacParticipantCoordinator.getInstance();
|
||||
|
||||
static {
|
||||
MetricsReporter.registerCounter(LabelNames.TRANSACTION_STATUS, new String[]{"type", "role", "status"}, "collect hmily transaction count");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object handleTransaction(final ProceedingJoinPoint point, final HmilyTransactionContext context) throws Throwable {
|
||||
HmilyParticipant hmilyParticipant = null;
|
||||
@ -69,14 +73,12 @@ public class ParticipantHmilyTacTransactionHandler implements HmilyTransactionHa
|
||||
HmilyContextHolder.remove();
|
||||
}
|
||||
case CONFIRMING:
|
||||
MetricsHandlerFacadeEngine.load().ifPresent(metricsHandlerFacade -> metricsHandlerFacade.counterIncrement(MetricsLabelEnum.TRANSACTION_STATUS.getName(),
|
||||
TransTypeEnum.TAC.name(), HmilyRoleEnum.PARTICIPANT.name(), HmilyActionEnum.CONFIRMING.name()));
|
||||
MetricsReporter.counterIncrement(LabelNames.TRANSACTION_STATUS, new String[]{TransTypeEnum.TAC.name(), HmilyRoleEnum.PARTICIPANT.name(), HmilyActionEnum.CONFIRMING.name()});
|
||||
List<HmilyParticipant> confirmList = HmilyParticipantCacheManager.getInstance().get(context.getParticipantId());
|
||||
coordinator.commitParticipant(confirmList, context.getParticipantId());
|
||||
break;
|
||||
case CANCELING:
|
||||
MetricsHandlerFacadeEngine.load().ifPresent(metricsHandlerFacade -> metricsHandlerFacade.counterIncrement(MetricsLabelEnum.TRANSACTION_STATUS.getName(),
|
||||
TransTypeEnum.TAC.name(), HmilyRoleEnum.PARTICIPANT.name(), HmilyActionEnum.CANCELING.name()));
|
||||
MetricsReporter.counterIncrement(LabelNames.TRANSACTION_STATUS, new String[]{TransTypeEnum.TAC.name(), HmilyRoleEnum.PARTICIPANT.name(), HmilyActionEnum.CANCELING.name()});
|
||||
List<HmilyParticipant> cancelList = HmilyParticipantCacheManager.getInstance().get(context.getParticipantId());
|
||||
coordinator.rollbackParticipant(cancelList, context.getParticipantId());
|
||||
break;
|
||||
|
@ -27,14 +27,13 @@ import org.dromara.hmily.core.disruptor.HmilyDisruptor;
|
||||
import org.dromara.hmily.core.disruptor.handler.HmilyTransactionEventConsumer;
|
||||
import org.dromara.hmily.core.service.HmilyTransactionHandler;
|
||||
import org.dromara.hmily.core.service.HmilyTransactionTask;
|
||||
import org.dromara.hmily.metrics.enums.MetricsLabelEnum;
|
||||
import org.dromara.hmily.metrics.spi.MetricsHandlerFacade;
|
||||
import org.dromara.hmily.metrics.spi.MetricsHandlerFacadeEngine;
|
||||
import org.dromara.hmily.metrics.constant.LabelNames;
|
||||
import org.dromara.hmily.metrics.reporter.MetricsReporter;
|
||||
import org.dromara.hmily.repository.spi.entity.HmilyTransaction;
|
||||
import org.dromara.hmily.tac.core.transaction.HmilyTacTransactionManager;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
|
||||
|
||||
/**
|
||||
@ -48,6 +47,12 @@ public class StarterHmilyTacTransactionHandler implements HmilyTransactionHandle
|
||||
|
||||
private final HmilyDisruptor<HmilyTransactionTask> disruptor;
|
||||
|
||||
static {
|
||||
MetricsReporter.registerCounter(LabelNames.TRANSACTION_TOTAL, new String[]{"type"}, "hmily transaction total count");
|
||||
MetricsReporter.registerHistogram(LabelNames.TRANSACTION_LATENCY, "hmily transaction Latency Histogram Millis (ms)");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Instantiates a new Starter hmily tac transaction handler.
|
||||
*/
|
||||
@ -61,13 +66,9 @@ public class StarterHmilyTacTransactionHandler implements HmilyTransactionHandle
|
||||
public Object handleTransaction(final ProceedingJoinPoint point, final HmilyTransactionContext context)
|
||||
throws Throwable {
|
||||
Object returnValue;
|
||||
Supplier<Boolean> histogramSupplier = null;
|
||||
Optional<MetricsHandlerFacade> metricsFacade = MetricsHandlerFacadeEngine.load();
|
||||
MetricsReporter.counterIncrement(LabelNames.TRANSACTION_TOTAL, new String[]{TransTypeEnum.TAC.name()});
|
||||
LocalDateTime starterTime = LocalDateTime.now();
|
||||
try {
|
||||
if (metricsFacade.isPresent()) {
|
||||
metricsFacade.get().counterIncrement(MetricsLabelEnum.TRANSACTION_TOTAL.getName(), TransTypeEnum.TAC.name());
|
||||
histogramSupplier = metricsFacade.get().histogramStartTimer(MetricsLabelEnum.TRANSACTION_LATENCY.getName(), TransTypeEnum.TAC.name());
|
||||
}
|
||||
tm.begin();
|
||||
try {
|
||||
//execute try
|
||||
@ -76,8 +77,7 @@ public class StarterHmilyTacTransactionHandler implements HmilyTransactionHandle
|
||||
//if exception ,execute cancel
|
||||
final HmilyTransaction currentTransaction = tm.getHmilyTransaction();
|
||||
disruptor.getProvider().onData(() -> {
|
||||
metricsFacade.ifPresent(metricsHandlerFacade -> metricsHandlerFacade.counterIncrement(MetricsLabelEnum.TRANSACTION_STATUS.getName(),
|
||||
TransTypeEnum.TAC.name(), HmilyRoleEnum.START.name(), HmilyActionEnum.CANCELING.name()));
|
||||
MetricsReporter.counterIncrement(LabelNames.TRANSACTION_STATUS, new String[]{TransTypeEnum.TAC.name(), HmilyRoleEnum.START.name(), HmilyActionEnum.CANCELING.name()});
|
||||
tm.rollback(currentTransaction);
|
||||
});
|
||||
throw throwable;
|
||||
@ -85,16 +85,13 @@ public class StarterHmilyTacTransactionHandler implements HmilyTransactionHandle
|
||||
// execute confirm
|
||||
final HmilyTransaction currentTransaction = tm.getHmilyTransaction();
|
||||
disruptor.getProvider().onData(() -> {
|
||||
metricsFacade.ifPresent(metricsHandlerFacade -> metricsHandlerFacade.counterIncrement(MetricsLabelEnum.TRANSACTION_STATUS.getName(),
|
||||
TransTypeEnum.TAC.name(), HmilyRoleEnum.START.name(), HmilyActionEnum.CONFIRMING.name()));
|
||||
MetricsReporter.counterIncrement(LabelNames.TRANSACTION_STATUS, new String[]{TransTypeEnum.TAC.name(), HmilyRoleEnum.START.name(), HmilyActionEnum.CONFIRMING.name()});
|
||||
tm.commit(currentTransaction);
|
||||
});
|
||||
} finally {
|
||||
HmilyContextHolder.remove();
|
||||
tm.remove();
|
||||
if (null != histogramSupplier) {
|
||||
histogramSupplier.get();
|
||||
}
|
||||
MetricsReporter.recordTime(LabelNames.TRANSACTION_LATENCY, starterTime.until(LocalDateTime.now(), ChronoUnit.MILLIS));
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
@ -28,8 +28,8 @@ import org.dromara.hmily.core.context.HmilyContextHolder;
|
||||
import org.dromara.hmily.core.context.HmilyTransactionContext;
|
||||
import org.dromara.hmily.core.repository.HmilyRepositoryStorage;
|
||||
import org.dromara.hmily.core.service.HmilyTransactionHandler;
|
||||
import org.dromara.hmily.metrics.enums.MetricsLabelEnum;
|
||||
import org.dromara.hmily.metrics.spi.MetricsHandlerFacadeEngine;
|
||||
import org.dromara.hmily.metrics.constant.LabelNames;
|
||||
import org.dromara.hmily.metrics.reporter.MetricsReporter;
|
||||
import org.dromara.hmily.repository.spi.entity.HmilyParticipant;
|
||||
import org.dromara.hmily.tcc.executor.HmilyTccTransactionExecutor;
|
||||
|
||||
@ -46,6 +46,10 @@ public class ParticipantHmilyTccTransactionHandler implements HmilyTransactionHa
|
||||
|
||||
private final HmilyTccTransactionExecutor executor = HmilyTccTransactionExecutor.getInstance();
|
||||
|
||||
static {
|
||||
MetricsReporter.registerCounter(LabelNames.TRANSACTION_STATUS, new String[]{"type", "role", "status"}, "collect hmily transaction count");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object handleTransaction(final ProceedingJoinPoint point, final HmilyTransactionContext context) throws Throwable {
|
||||
HmilyParticipant hmilyParticipant = null;
|
||||
@ -69,13 +73,11 @@ public class ParticipantHmilyTccTransactionHandler implements HmilyTransactionHa
|
||||
HmilyContextHolder.remove();
|
||||
}
|
||||
case CONFIRMING:
|
||||
MetricsHandlerFacadeEngine.load().ifPresent(metricsHandlerFacade -> metricsHandlerFacade.counterIncrement(MetricsLabelEnum.TRANSACTION_STATUS.getName(),
|
||||
TransTypeEnum.TCC.name(), HmilyRoleEnum.PARTICIPANT.name(), HmilyActionEnum.CONFIRMING.name()));
|
||||
MetricsReporter.counterIncrement(LabelNames.TRANSACTION_STATUS, new String[]{TransTypeEnum.TCC.name(), HmilyRoleEnum.PARTICIPANT.name(), HmilyActionEnum.CONFIRMING.name()});
|
||||
List<HmilyParticipant> confirmList = HmilyParticipantCacheManager.getInstance().get(context.getParticipantId());
|
||||
return executor.participantConfirm(confirmList, context.getParticipantId());
|
||||
case CANCELING:
|
||||
MetricsHandlerFacadeEngine.load().ifPresent(metricsHandlerFacade -> metricsHandlerFacade.counterIncrement(MetricsLabelEnum.TRANSACTION_STATUS.getName(),
|
||||
TransTypeEnum.TCC.name(), HmilyRoleEnum.PARTICIPANT.name(), HmilyActionEnum.CANCELING.name()));
|
||||
MetricsReporter.counterIncrement(LabelNames.TRANSACTION_STATUS, new String[]{TransTypeEnum.TCC.name(), HmilyRoleEnum.PARTICIPANT.name(), HmilyActionEnum.CANCELING.name()});
|
||||
List<HmilyParticipant> cancelList = HmilyParticipantCacheManager.getInstance().get(context.getParticipantId());
|
||||
return executor.participantCancel(cancelList, context.getParticipantId());
|
||||
default:
|
||||
|
@ -28,14 +28,13 @@ import org.dromara.hmily.core.disruptor.handler.HmilyTransactionEventConsumer;
|
||||
import org.dromara.hmily.core.holder.HmilyTransactionHolder;
|
||||
import org.dromara.hmily.core.service.HmilyTransactionHandler;
|
||||
import org.dromara.hmily.core.service.HmilyTransactionTask;
|
||||
import org.dromara.hmily.metrics.enums.MetricsLabelEnum;
|
||||
import org.dromara.hmily.metrics.spi.MetricsHandlerFacade;
|
||||
import org.dromara.hmily.metrics.spi.MetricsHandlerFacadeEngine;
|
||||
import org.dromara.hmily.metrics.constant.LabelNames;
|
||||
import org.dromara.hmily.metrics.reporter.MetricsReporter;
|
||||
import org.dromara.hmily.repository.spi.entity.HmilyTransaction;
|
||||
import org.dromara.hmily.tcc.executor.HmilyTccTransactionExecutor;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
|
||||
|
||||
/**
|
||||
@ -49,6 +48,11 @@ public class StarterHmilyTccTransactionHandler implements HmilyTransactionHandle
|
||||
|
||||
private HmilyDisruptor<HmilyTransactionTask> disruptor;
|
||||
|
||||
static {
|
||||
MetricsReporter.registerCounter(LabelNames.TRANSACTION_TOTAL, new String[]{"type"}, "hmily transaction total count");
|
||||
MetricsReporter.registerHistogram(LabelNames.TRANSACTION_LATENCY, "hmily transaction Latency Histogram Millis (ms)");
|
||||
}
|
||||
|
||||
public StarterHmilyTccTransactionHandler() {
|
||||
disruptor = new HmilyDisruptor<>(new HmilyTransactionEventConsumer(),
|
||||
Runtime.getRuntime().availableProcessors() << 1, HmilyDisruptor.DEFAULT_SIZE);
|
||||
@ -59,13 +63,9 @@ public class StarterHmilyTccTransactionHandler implements HmilyTransactionHandle
|
||||
public Object handleTransaction(final ProceedingJoinPoint point, final HmilyTransactionContext context)
|
||||
throws Throwable {
|
||||
Object returnValue;
|
||||
Supplier<Boolean> histogramSupplier = null;
|
||||
Optional<MetricsHandlerFacade> handlerFacade = MetricsHandlerFacadeEngine.load();
|
||||
MetricsReporter.counterIncrement(LabelNames.TRANSACTION_TOTAL, new String[]{TransTypeEnum.TCC.name()});
|
||||
LocalDateTime starterTime = LocalDateTime.now();
|
||||
try {
|
||||
if (handlerFacade.isPresent()) {
|
||||
handlerFacade.get().counterIncrement(MetricsLabelEnum.TRANSACTION_TOTAL.getName(), TransTypeEnum.TCC.name());
|
||||
histogramSupplier = handlerFacade.get().histogramStartTimer(MetricsLabelEnum.TRANSACTION_LATENCY.getName(), TransTypeEnum.TCC.name());
|
||||
}
|
||||
HmilyTransaction hmilyTransaction = executor.preTry(point);
|
||||
try {
|
||||
//execute try
|
||||
@ -76,8 +76,7 @@ public class StarterHmilyTccTransactionHandler implements HmilyTransactionHandle
|
||||
//if exception ,execute cancel
|
||||
final HmilyTransaction currentTransaction = HmilyTransactionHolder.getInstance().getCurrentTransaction();
|
||||
disruptor.getProvider().onData(() -> {
|
||||
handlerFacade.ifPresent(metricsHandlerFacade -> metricsHandlerFacade.counterIncrement(MetricsLabelEnum.TRANSACTION_STATUS.getName(),
|
||||
TransTypeEnum.TCC.name(), HmilyRoleEnum.START.name(), HmilyActionEnum.CANCELING.name()));
|
||||
MetricsReporter.counterIncrement(LabelNames.TRANSACTION_STATUS, new String[]{TransTypeEnum.TCC.name(), HmilyRoleEnum.START.name(), HmilyActionEnum.CANCELING.name()});
|
||||
executor.globalCancel(currentTransaction);
|
||||
});
|
||||
throw throwable;
|
||||
@ -85,16 +84,13 @@ public class StarterHmilyTccTransactionHandler implements HmilyTransactionHandle
|
||||
//execute confirm
|
||||
final HmilyTransaction currentTransaction = HmilyTransactionHolder.getInstance().getCurrentTransaction();
|
||||
disruptor.getProvider().onData(() -> {
|
||||
handlerFacade.ifPresent(metricsHandlerFacade -> metricsHandlerFacade.counterIncrement(MetricsLabelEnum.TRANSACTION_STATUS.getName(),
|
||||
TransTypeEnum.TCC.name(), HmilyRoleEnum.START.name(), HmilyActionEnum.CONFIRMING.name()));
|
||||
MetricsReporter.counterIncrement(LabelNames.TRANSACTION_STATUS, new String[]{TransTypeEnum.TCC.name(), HmilyRoleEnum.START.name(), HmilyActionEnum.CONFIRMING.name()});
|
||||
executor.globalConfirm(currentTransaction);
|
||||
});
|
||||
} finally {
|
||||
HmilyContextHolder.remove();
|
||||
executor.remove();
|
||||
if (null != histogramSupplier) {
|
||||
histogramSupplier.get();
|
||||
}
|
||||
MetricsReporter.recordTime(LabelNames.TRANSACTION_LATENCY, starterTime.until(LocalDateTime.now(), ChronoUnit.MILLIS));
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user