未验证 提交 b6661b51 编写于 作者: G Gao Hongtao 提交者: GitHub

Add health checker module (#5046)

上级 c8fc457e
# Health Check
Health check intends to provide a unique approach to check the healthy status of OAP server. It includes the health status
of modules, GraphQL and gRPC services readiness.
## Health Checker Module.
Health Checker module could solute how to observe the health status of modules. We can active it by below:
```yaml
health-checker:
selector: ${SW_HEALTH_CHECKER:default}
default:
checkIntervalSeconds: ${SW_HEALTH_CHECKER_INTERVAL_SECONDS:5}
```
Notice, we should enable `telemetry` module at the same time. That means the provider should not be `-` and `none`.
After that, we can query OAP server health status by querying GraphQL:
```
query{
checkHealth{
score
details
}
}
```
If the OAP server is healthy, the response should be
```json
{
"data": {
"checkHealth": {
"score": 0,
"details": ""
}
}
}
```
Once some modules are unhealthy, for instance, storage H2 is down. The result might be like below:
```json
{
"data": {
"checkHealth": {
"score": 1,
"details": "storage_h2,"
}
}
}
```
You could refer to [checkHealth query](https://github.com/apache/skywalking-query-protocol/blob/master/common.graphql)
for more details.
## The readiness of GraphQL and gRPC
We could opt to above query to check the readiness of GraphQL.
OAP has implemented [gRPC Health Checking Protocol](https://github.com/grpc/grpc/blob/master/doc/health-checking.md).
We could use [grpc-health-probe](https://github.com/grpc-ecosystem/grpc-health-probe) or any other tools to check the
health of OAP gRPC services.
...@@ -46,6 +46,7 @@ ...@@ -46,6 +46,7 @@
<module>server-bootstrap</module> <module>server-bootstrap</module>
<module>server-tools</module> <module>server-tools</module>
<module>server-fetcher-plugin</module> <module>server-fetcher-plugin</module>
<module>server-health-checker</module>
</modules> </modules>
<properties> <properties>
......
...@@ -270,3 +270,8 @@ exporter: ...@@ -270,3 +270,8 @@ exporter:
grpc: grpc:
targetHost: ${SW_EXPORTER_GRPC_HOST:127.0.0.1} targetHost: ${SW_EXPORTER_GRPC_HOST:127.0.0.1}
targetPort: ${SW_EXPORTER_GRPC_PORT:9870} targetPort: ${SW_EXPORTER_GRPC_PORT:9870}
health-checker:
selector: ${SW_HEALTH_CHECKER:-}
default:
checkIntervalSeconds: ${SW_HEALTH_CHECKER_INTERVAL_SECONDS:5}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.oap.server.core.query.type;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class HealthStatus {
// score == 0 means healthy, otherwise it's unhealthy.
private int score;
private String details;
}
...@@ -90,6 +90,11 @@ public class RemoteClientManagerTestCase { ...@@ -90,6 +90,11 @@ public class RemoteClientManagerTestCase {
public void setValue(double value) { public void setValue(double value) {
} }
@Override
public double getValue() {
return 0;
}
}); });
ModuleDefineTesting telemetryModuleDefine = new ModuleDefineTesting(); ModuleDefineTesting telemetryModuleDefine = new ModuleDefineTesting();
moduleManager.put(TelemetryModule.NAME, telemetryModuleDefine); moduleManager.put(TelemetryModule.NAME, telemetryModuleDefine);
......
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ 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.
~
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>oap-server</artifactId>
<groupId>org.apache.skywalking</groupId>
<version>8.1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>server-health-checker</artifactId>
<dependencies>
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>server-core</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>
\ No newline at end of file
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.oap.server.health.checker.module;
import org.apache.skywalking.oap.server.health.checker.provider.HealthQueryService;
import org.apache.skywalking.oap.server.library.module.ModuleDefine;
/**
* HealthCheckerModule intends to provide a channel to expose the healthy status of modules to external.
*/
public class HealthCheckerModule extends ModuleDefine {
public static final String NAME = "health-checker";
public HealthCheckerModule() {
super(NAME);
}
@Override
public Class[] services() {
return new Class[]{HealthQueryService.class};
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.oap.server.health.checker.provider;
import lombok.Getter;
import org.apache.skywalking.oap.server.library.module.ModuleConfig;
/**
* The Configuration of health checker module.
*/
@Getter
public class HealthCheckerConfig extends ModuleConfig {
private long checkIntervalSeconds = 5;
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.oap.server.health.checker.provider;
import com.google.common.util.concurrent.AtomicDouble;
import io.vavr.collection.Stream;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.apache.skywalking.oap.server.health.checker.module.HealthCheckerModule;
import org.apache.skywalking.oap.server.library.module.ModuleConfig;
import org.apache.skywalking.oap.server.library.module.ModuleDefine;
import org.apache.skywalking.oap.server.library.module.ModuleProvider;
import org.apache.skywalking.oap.server.library.module.ModuleServiceHolder;
import org.apache.skywalking.oap.server.library.module.ModuleStartException;
import org.apache.skywalking.oap.server.library.module.ServiceNotProvidedException;
import org.apache.skywalking.oap.server.telemetry.TelemetryModule;
import org.apache.skywalking.oap.server.telemetry.api.MetricsCollector;
import org.apache.skywalking.oap.server.telemetry.api.MetricsCreator;
/**
* HealthCheckerProvider fetches health check metrics from telemetry module, then calculates health score and generates
* details explains the score. External service or users can query health status by HealthCheckerService.
*/
@Slf4j
public class HealthCheckerProvider extends ModuleProvider {
private final AtomicDouble score = new AtomicDouble();
private final AtomicReference<String> details = new AtomicReference<>();
private final HealthCheckerConfig config = new HealthCheckerConfig();
private MetricsCollector collector;
private MetricsCreator metricsCreator;
private ScheduledExecutorService ses;
@Override public String name() {
return "default";
}
@Override public Class<? extends ModuleDefine> module() {
return HealthCheckerModule.class;
}
@Override public ModuleConfig createConfigBeanIfAbsent() {
return config;
}
@Override public void prepare() throws ServiceNotProvidedException, ModuleStartException {
score.set(-1);
ses = Executors.newSingleThreadScheduledExecutor();
this.registerServiceImplementation(HealthQueryService.class, new HealthQueryService(score, details));
}
@Override public void start() throws ServiceNotProvidedException, ModuleStartException {
ModuleServiceHolder telemetry = getManager().find(TelemetryModule.NAME).provider();
metricsCreator = telemetry.getService(MetricsCreator.class);
collector = telemetry.getService(MetricsCollector.class);
}
@Override public void notifyAfterCompleted() throws ServiceNotProvidedException, ModuleStartException {
ses.scheduleAtFixedRate(() -> {
StringBuilder unhealthyModules = new StringBuilder();
score.set(Stream.ofAll(collector.collect())
.flatMap(metricFamily -> metricFamily.samples)
.filter(sample -> metricsCreator.isHealthCheckerMetrics(sample.name))
.peek(sample -> {
if (sample.value > 0.0) {
unhealthyModules.append(metricsCreator.extractModuleName(sample.name)).append(",");
}
})
.map(sample -> sample.value)
.collect(Collectors.summingDouble(Double::doubleValue)));
details.set(unhealthyModules.toString());
},
2, config.getCheckIntervalSeconds(), TimeUnit.SECONDS);
}
@Override public String[] requiredModules() {
return new String[]{TelemetryModule.NAME};
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.oap.server.health.checker.provider;
import com.google.common.util.concurrent.AtomicDouble;
import java.util.concurrent.atomic.AtomicReference;
import lombok.RequiredArgsConstructor;
import org.apache.skywalking.oap.server.core.query.type.HealthStatus;
import org.apache.skywalking.oap.server.library.module.Service;
@RequiredArgsConstructor
public class HealthQueryService implements Service {
private final AtomicDouble score;
private final AtomicReference<String> details;
public HealthStatus checkHealth() {
HealthStatus s = new HealthStatus();
s.setScore(score.intValue());
s.setDetails(details.get());
return s;
}
}
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#
org.apache.skywalking.oap.server.health.checker.module.HealthCheckerModule
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#
org.apache.skywalking.oap.server.health.checker.provider.HealthCheckerProvider
...@@ -26,6 +26,10 @@ import java.sql.ResultSet; ...@@ -26,6 +26,10 @@ import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import java.util.Properties; import java.util.Properties;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import org.apache.skywalking.oap.server.library.client.Client; import org.apache.skywalking.oap.server.library.client.Client;
import org.apache.skywalking.oap.server.library.client.jdbc.JDBCClientException; import org.apache.skywalking.oap.server.library.client.jdbc.JDBCClientException;
import org.slf4j.Logger; import org.slf4j.Logger;
...@@ -44,6 +48,17 @@ public class JDBCHikariCPClient implements Client { ...@@ -44,6 +48,17 @@ public class JDBCHikariCPClient implements Client {
hikariConfig = new HikariConfig(properties); hikariConfig = new HikariConfig(properties);
} }
public void setHealthCheckListener(Consumer<Boolean> healthListener) {
ScheduledExecutorService asyncHealthScheduler = Executors.newSingleThreadScheduledExecutor();
asyncHealthScheduler.scheduleAtFixedRate(() -> {
try (Connection c = dataSource.getConnection()) {
healthListener.accept(true);
} catch (SQLException ignored) {
healthListener.accept(false);
}
}, 0, 3, TimeUnit.SECONDS);
}
@Override @Override
public void connect() { public void connect() {
dataSource = new HikariDataSource(hikariConfig); dataSource = new HikariDataSource(hikariConfig);
......
...@@ -33,6 +33,11 @@ ...@@ -33,6 +33,11 @@
<artifactId>server-core</artifactId> <artifactId>server-core</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>server-health-checker</artifactId>
<version>${project.version}</version>
</dependency>
<dependency> <dependency>
<groupId>com.graphql-java</groupId> <groupId>com.graphql-java</groupId>
<artifactId>graphql-java</artifactId> <artifactId>graphql-java</artifactId>
......
...@@ -23,6 +23,7 @@ import graphql.GraphQL; ...@@ -23,6 +23,7 @@ import graphql.GraphQL;
import graphql.schema.GraphQLSchema; import graphql.schema.GraphQLSchema;
import org.apache.skywalking.oap.query.graphql.resolver.AggregationQuery; import org.apache.skywalking.oap.query.graphql.resolver.AggregationQuery;
import org.apache.skywalking.oap.query.graphql.resolver.AlarmQuery; import org.apache.skywalking.oap.query.graphql.resolver.AlarmQuery;
import org.apache.skywalking.oap.query.graphql.resolver.HealthQuery;
import org.apache.skywalking.oap.query.graphql.resolver.LogQuery; import org.apache.skywalking.oap.query.graphql.resolver.LogQuery;
import org.apache.skywalking.oap.query.graphql.resolver.MetadataQuery; import org.apache.skywalking.oap.query.graphql.resolver.MetadataQuery;
import org.apache.skywalking.oap.query.graphql.resolver.MetricQuery; import org.apache.skywalking.oap.query.graphql.resolver.MetricQuery;
...@@ -72,7 +73,7 @@ public class GraphQLQueryProvider extends ModuleProvider { ...@@ -72,7 +73,7 @@ public class GraphQLQueryProvider extends ModuleProvider {
public void prepare() throws ServiceNotProvidedException, ModuleStartException { public void prepare() throws ServiceNotProvidedException, ModuleStartException {
GraphQLSchema schema = SchemaParser.newParser() GraphQLSchema schema = SchemaParser.newParser()
.file("query-protocol/common.graphqls") .file("query-protocol/common.graphqls")
.resolvers(new Query(), new Mutation()) .resolvers(new Query(), new Mutation(), new HealthQuery(getManager()))
.file("query-protocol/metadata.graphqls") .file("query-protocol/metadata.graphqls")
.resolvers(new MetadataQuery(getManager())) .resolvers(new MetadataQuery(getManager()))
.file("query-protocol/topology.graphqls") .file("query-protocol/topology.graphqls")
......
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.oap.query.graphql.resolver;
import com.coxautodev.graphql.tools.GraphQLQueryResolver;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import org.apache.skywalking.oap.server.core.query.type.HealthStatus;
import org.apache.skywalking.oap.server.health.checker.module.HealthCheckerModule;
import org.apache.skywalking.oap.server.health.checker.provider.HealthQueryService;
import org.apache.skywalking.oap.server.library.module.ModuleManager;
@RequiredArgsConstructor
public class HealthQuery implements GraphQLQueryResolver {
private final ModuleManager moduleManager;
private HealthQueryService service;
private HealthQueryService getService() {
return Optional.ofNullable(service)
.orElseGet(() -> {
service = moduleManager.find(HealthCheckerModule.NAME).provider().getService(HealthQueryService.class);
return service;
});
}
public HealthStatus checkHealth() {
return getService().checkHealth();
}
}
Subproject commit bea847b90e08c07a5407c4121fe4cec1eec77a78 Subproject commit 563bb51c71922f017911345d7cd5c62a7ac8995c
...@@ -63,6 +63,10 @@ import org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.dao.H2TopNRecords ...@@ -63,6 +63,10 @@ import org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.dao.H2TopNRecords
import org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.dao.H2TopologyQueryDAO; import org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.dao.H2TopologyQueryDAO;
import org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.dao.H2TraceQueryDAO; import org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.dao.H2TraceQueryDAO;
import org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.dao.H2UITemplateManagementDAO; import org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.dao.H2UITemplateManagementDAO;
import org.apache.skywalking.oap.server.telemetry.TelemetryModule;
import org.apache.skywalking.oap.server.telemetry.api.GaugeMetrics;
import org.apache.skywalking.oap.server.telemetry.api.MetricsCreator;
import org.apache.skywalking.oap.server.telemetry.api.MetricsTag;
/** /**
* H2 Storage provider is for demonstration and preview only. I will find that haven't implemented several interfaces, * H2 Storage provider is for demonstration and preview only. I will find that haven't implemented several interfaces,
...@@ -131,6 +135,9 @@ public class H2StorageProvider extends ModuleProvider { ...@@ -131,6 +135,9 @@ public class H2StorageProvider extends ModuleProvider {
@Override @Override
public void start() throws ServiceNotProvidedException, ModuleStartException { public void start() throws ServiceNotProvidedException, ModuleStartException {
MetricsCreator metricCreator = getManager().find(TelemetryModule.NAME).provider().getService(MetricsCreator.class);
GaugeMetrics healthChecker = metricCreator.createHealthCheckerGauge("storage_h2", MetricsTag.EMPTY_KEY, MetricsTag.EMPTY_VALUE);
healthChecker.setValue(1);
try { try {
h2Client.connect(); h2Client.connect();
...@@ -139,6 +146,13 @@ public class H2StorageProvider extends ModuleProvider { ...@@ -139,6 +146,13 @@ public class H2StorageProvider extends ModuleProvider {
} catch (StorageException e) { } catch (StorageException e) {
throw new ModuleStartException(e.getMessage(), e); throw new ModuleStartException(e.getMessage(), e);
} }
h2Client.setHealthCheckListener(isHealthy -> {
if (isHealthy) {
healthChecker.setValue(0);
} else {
healthChecker.setValue(1);
}
});
} }
@Override @Override
......
...@@ -46,4 +46,9 @@ public interface GaugeMetrics { ...@@ -46,4 +46,9 @@ public interface GaugeMetrics {
* Set the given value to the gauge * Set the given value to the gauge
*/ */
void setValue(double value); void setValue(double value);
/**
* Get the current value of the gauge
*/
double getValue();
} }
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
package org.apache.skywalking.oap.server.telemetry.api; package org.apache.skywalking.oap.server.telemetry.api;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import org.apache.skywalking.oap.server.library.module.Service; import org.apache.skywalking.oap.server.library.module.Service;
/** /**
...@@ -25,6 +27,8 @@ import org.apache.skywalking.oap.server.library.module.Service; ...@@ -25,6 +27,8 @@ import org.apache.skywalking.oap.server.library.module.Service;
* project, and plan to move to openmetrics APIs after it is ready. * project, and plan to move to openmetrics APIs after it is ready.
*/ */
public interface MetricsCreator extends Service { public interface MetricsCreator extends Service {
String HEALTH_METRIC_PREFIX = "health_check_";
/** /**
* Create a counter type metrics instance. * Create a counter type metrics instance.
*/ */
...@@ -42,4 +46,30 @@ public interface MetricsCreator extends Service { ...@@ -42,4 +46,30 @@ public interface MetricsCreator extends Service {
*/ */
HistogramMetrics createHistogramMetric(String name, String tips, MetricsTag.Keys tagKeys, HistogramMetrics createHistogramMetric(String name, String tips, MetricsTag.Keys tagKeys,
MetricsTag.Values tagValues, double... buckets); MetricsTag.Values tagValues, double... buckets);
/**
* Create a Health Check gauge.
*/
default GaugeMetrics createHealthCheckerGauge(String name, MetricsTag.Keys tagKeys, MetricsTag.Values tagValues) {
Preconditions.checkArgument(!Strings.isNullOrEmpty(name), "Require non-null or empty metric name");
return createGauge(Strings.lenientFormat("%s%s", HEALTH_METRIC_PREFIX, name),
Strings.lenientFormat("%s health check", name),
tagKeys, tagValues);
}
/**
* Find out whether it's a health check metric.
*/
default boolean isHealthCheckerMetrics(String name) {
Preconditions.checkArgument(!Strings.isNullOrEmpty(name), "Require non-null or empty metric name");
return name.startsWith(HEALTH_METRIC_PREFIX);
}
/**
* Extract the raw module name
*/
default String extractModuleName(String metricName) {
Preconditions.checkArgument(!Strings.isNullOrEmpty(metricName), "Require non-null or empty metric name");
return metricName.replace(HEALTH_METRIC_PREFIX, "");
}
} }
...@@ -71,6 +71,11 @@ public class MetricsCreatorNoop implements MetricsCreator { ...@@ -71,6 +71,11 @@ public class MetricsCreatorNoop implements MetricsCreator {
public void setValue(double value) { public void setValue(double value) {
} }
@Override
public double getValue() {
return 0;
}
}; };
} }
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
package org.apache.skywalking.oap.server.telemetry.prometheus; package org.apache.skywalking.oap.server.telemetry.prometheus;
import io.prometheus.client.Gauge; import io.prometheus.client.Gauge;
import java.util.Optional;
import org.apache.skywalking.oap.server.telemetry.api.GaugeMetrics; import org.apache.skywalking.oap.server.telemetry.api.GaugeMetrics;
import org.apache.skywalking.oap.server.telemetry.api.MetricsTag; import org.apache.skywalking.oap.server.telemetry.api.MetricsTag;
...@@ -70,6 +71,11 @@ public class PrometheusGaugeMetrics extends BaseMetrics<Gauge, Gauge.Child> impl ...@@ -70,6 +71,11 @@ public class PrometheusGaugeMetrics extends BaseMetrics<Gauge, Gauge.Child> impl
} }
} }
@Override
public double getValue() {
return Optional.ofNullable(this.getMetric()).orElse(new Gauge.Child()).get();
}
@Override @Override
protected Gauge create(String[] labelNames) { protected Gauge create(String[] labelNames) {
return Gauge.build().name(name).help(tips).labelNames(labelNames).register(); return Gauge.build().name(name).help(tips).labelNames(labelNames).register();
......
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.oap.server.telemetry.prometheus;
import io.prometheus.client.Collector;
import io.prometheus.client.CollectorRegistry;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.List;
import org.apache.skywalking.oap.server.telemetry.api.MetricFamily;
import org.apache.skywalking.oap.server.telemetry.api.MetricsCollector;
public class PrometheusMetricsCollector implements MetricsCollector {
@Override public Iterable<MetricFamily> collect() {
Enumeration<Collector.MetricFamilySamples> mfs = CollectorRegistry.defaultRegistry.metricFamilySamples();
List<MetricFamily> result = new LinkedList<>();
while (mfs.hasMoreElements()) {
Collector.MetricFamilySamples metricFamilySamples = mfs.nextElement();
List<MetricFamily.Sample> samples = new ArrayList<>(metricFamilySamples.samples.size());
MetricFamily m = new MetricFamily(metricFamilySamples.name, MetricFamily.Type.valueOf(metricFamilySamples.type
.name()), metricFamilySamples.help, samples);
result.add(m);
for (Collector.MetricFamilySamples.Sample sample : metricFamilySamples.samples) {
samples.add(new MetricFamily.Sample(sample.name, sample.labelNames, sample.labelValues, sample.value, sample.timestampMs));
}
}
return result;
}
}
...@@ -29,7 +29,6 @@ import org.apache.skywalking.oap.server.library.module.ServiceNotProvidedExcepti ...@@ -29,7 +29,6 @@ import org.apache.skywalking.oap.server.library.module.ServiceNotProvidedExcepti
import org.apache.skywalking.oap.server.telemetry.TelemetryModule; import org.apache.skywalking.oap.server.telemetry.TelemetryModule;
import org.apache.skywalking.oap.server.telemetry.api.MetricsCollector; import org.apache.skywalking.oap.server.telemetry.api.MetricsCollector;
import org.apache.skywalking.oap.server.telemetry.api.MetricsCreator; import org.apache.skywalking.oap.server.telemetry.api.MetricsCreator;
import org.apache.skywalking.oap.server.telemetry.none.MetricsCollectorNoop;
/** /**
* Start the Prometheus * Start the Prometheus
...@@ -59,7 +58,7 @@ public class PrometheusTelemetryProvider extends ModuleProvider { ...@@ -59,7 +58,7 @@ public class PrometheusTelemetryProvider extends ModuleProvider {
@Override @Override
public void prepare() throws ServiceNotProvidedException, ModuleStartException { public void prepare() throws ServiceNotProvidedException, ModuleStartException {
this.registerServiceImplementation(MetricsCreator.class, new PrometheusMetricsCreator()); this.registerServiceImplementation(MetricsCreator.class, new PrometheusMetricsCreator());
this.registerServiceImplementation(MetricsCollector.class, new MetricsCollectorNoop()); this.registerServiceImplementation(MetricsCollector.class, new PrometheusMetricsCollector());
try { try {
new HTTPServer(config.getHost(), config.getPort()); new HTTPServer(config.getHost(), config.getPort());
} catch (IOException e) { } catch (IOException e) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册