Health Endpoint Metrics not being exported after Spring Boot 2 migration - spring

My Team migrated our Microservices from Spring Boot 1 to Version 2 and since the Actuator changed, our Health Endpoint Metrics exported via prometheus jmx exporter do not work anymore.
The usual /actuator/health is working as expected, but the prometheus-jmx-exporter won't pick it up although several things tried:
I changed the Metainformation in the exporter-config.yaml to reflect the name change in Spring Boot 2
I added the io.micrometer:micrometer-registry-prometheus to our build.gradle to see if this is the issue
I exposed web and jmx endpoints acording to the Spring Boot 2 Documentation
So now I run out of ideas and would appreciate any hints oyu might be able to give me
old prometheus-jmx-exporter exporter-config.yaml:
---
lowercaseOutputName: true
lowercaseOutputLabelNames: true
whitelistObjectNames: ["org.springframework.boot:type=Endpoint,name=healthEndpoint"]
rules:
- pattern: 'org.springframework.boot<type=Endpoint, name=healthEndpoint><(.*, )?(.*)>(.*):'
name: health_endpoint_$1$3
attrNameSnakeCase: true
new prometheus-jmx-exporter exporter-config.yaml:
---
lowercaseOutputName: true
lowercaseOutputLabelNames: true
whitelistObjectNames: ["org.springframework.boot:type=Endpoint,name=Health"]
rules:
- pattern: 'org.springframework.boot<type=Endpoint, name=Health>'
name: health_endpoint_$1$3
attrNameSnakeCase: true
current application properties about actuator endpoints:
management.endpoints.web.exposure.include=info, health, refresh, metrics, prometheus
management.endpoints.jmx.exposure.include=health, metrics, prometheus
in Spring Boot 1 with the old exporter-config.yaml I get results like this:
# HELP health_endpoint_hystrix_status Invoke the underlying endpoint (org.springframework.boot<type=Endpoint, name=healthEndpoint><hystrix, status>status)
# TYPE health_endpoint_hystrix_status untyped
health_endpoint_hystrix_status 1.0
# HELP health_endpoint_status Invoke the underlying endpoint (org.springframework.boot<type=Endpoint, name=healthEndpoint><status>status)
# TYPE health_endpoint_status untyped
health_endpoint_status 1.0
But with all the changes and in Spring Boot 2 I get nothing out of this.

You can cofigure your own health value and add it to the Prometheus Metrics endpoint:
#Configuration
public class HealthMetricsConfiguration {
#Bean
public MeterRegistryCustomizer prometheusHealthCheck(HealthEndpoint healthEndpoint) {
return registry -> registry.gauge("health", healthEndpoint, HealthMetricsConfiguration::healthToCode);
}
public static int healthToCode(HealthEndpoint ep) {
Status status = ep.health().getStatus();
return status.equals(Status.UP) ? 1 : 0;
}
}

Related

Configuring Swagger UI for OAuth 2.0 in Spring Boot with Kotlin

I am trying to configure OpenAPI 3 for OAuth 2.0 with a configuration class in Spring Boot with Kotlin.
Even though I set oauth2RedirectUrl in application.yml, when I click authorize in swagger UI to get new token to send a request, redirect url doesn't work as expected and I get the default redirect url called something like that(I believe it's a default redirectUrl): &redirect_uri=http://localhost:8080/oauth2-redirect.html instead of (what i configured in application.yaml)
Access the Swagger-UI at http://localhost:8080/swagger-ui/index.html?queryConfigEnabled=true&url=/v3/api-docs
Then click the authorize button and use the preconfigured values.
The IdentityProviderController prints then the configured values, e.g. redirect_uri.
The redirect_uri looks like http://localhost:8080/swagger-ui/oauth2-redirect.html and the swagger-ui:oauth2RedirectUrl path is missing. Even when it is configured in the application.yaml.
I added the following dependencies:
implementation("org.springdoc:springdoc-openapi-ui:1.6.14")
implementation("org.springdoc:springdoc-openapi-kotlin:1.6.14")
implementation("org.springdoc:springdoc-openapi-security:1.6.14")
and this is my application.yml
springdoc:
api-docs:
enabled: true
swagger-ui:
query-config-enabled: true
oauth:
client-id: <clientId>
client-secret: <clientSecret>
use-pkce-with-authorization-code-grant: true
oauth2RedirectUrl: <redirectUrl>
and this here is my configuration class:
#Configuration
#OpenAPIDefinition
#SecurityScheme(
name = "oauth2",
type = SecuritySchemeType.OAUTH2,
flows =
OAuthFlows(
authorizationCode =
OAuthFlow(
authorizationUrl = "<authorizationUrl>",
tokenUrl = "<tokenUrl>",
scopes =
[
OAuthScope(name = "test1"),
OAuthScope(name = "test2"),
OAuthScope(name = "test3")],
)))
open class OpenApiConfiguration {
#Bean
open fun customOpenAPI(): OpenAPI {
return OpenAPI()
.components(Components())
.info(
Info()
.title("ABC Service Rest API")
.description("description...")
.version("1.0.0"))
}
}
What am I missing here?
UPDATE: (17.02.2023)
After I am changing the redirect_uri in chrome with the correct one, then I can reach the Identity proverders' page, so I only need to find a way to set my redirectUrl configuration properly.

Serializer for custom type 'janusgraph.RelationIdentifier' not found

Janus Server config
serializers:
- { className: org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1, config: { ioRegistries: [org.janusgraph.graphdb.tinkerpop.JanusGraphIoRegistry] }}
- { className: org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1, config: { serializeResultToString: true }}
Java/Spring boot config
#Bean
public Cluster cluster() {
return Cluster.build()
.addContactPoint(dbUrl)
.port(dbPort)
.serializer(new GraphBinaryMessageSerializerV1())
.maxConnectionPoolSize(5)
.maxInProcessPerConnection(1)
.maxSimultaneousUsagePerConnection(10)
.create();
}
Getting the following error,
Caused by: org.apache.tinkerpop.gremlin.driver.ser.SerializationException: java.io.IOException: Serializer for custom type 'janusgraph.RelationIdentifier' not found
at org.apache.tinkerpop.gremlin.driver.ser.binary.ResponseMessageSerializer.readValue(ResponseMessageSerializer.java:59) ~[gremlin-driver-3.6.1.jar:3.6.1]
at org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1.deserializeResponse(GraphBinaryMessageSerializerV1.java:180) ~[gremlin-driver-3.6.1.jar:3.6.1]
at org.apache.tinkerpop.gremlin.driver.handler.WebSocketGremlinResponseDecoder.decode(WebSocketGremlinResponseDecoder.java:47) ~[gremlin-driver-3.6.1.jar:3.6.1]
at org.apache.tinkerpop.gremlin.driver.handler.WebSocketGremlinResponseDecoder.decode(WebSocketGremlinResponseDecoder.java:35) ~[gremlin-driver-3.6.1.jar:3.6.1]
Note: I didn't define the schema. Migrating the code from AWS NEPTUNE (working code) to JanusGraph.
Any help on why I am getting the above error?
Get queries are working and a few mutations queries also working,...
It looks like you have only defined the serializer for JanusGraph types on the server, but not on the client side. You also need to add the JanusGraphIoRegistry on the client side.
This can be done like this:
TypeSerializerRegistry typeSerializerRegistry = TypeSerializerRegistry.build()
.addRegistry(JanusGraphIoRegistry.instance())
.create();
Cluster.build()
.addContactPoint(dbUrl)
.port(dbPort)
.serializer(new GraphBinaryMessageSerializerV1(typeSerializerRegistry))
.maxConnectionPoolSize(5)
.maxInProcessPerConnection(1)
.maxSimultaneousUsagePerConnection(10)
.create();
or you can alternatively use a config file for it which simplifies the code down to:
import static org.apache.tinkerpop.gremlin.process.traversal.AnonymousTraversalSource.traversal;
GraphTraversalSource g = traversal().withRemote("conf/remote-graph.properties");
(I have already created the GraphTraversalSource here because the client is directly created internally by withRemote().)
This is also described in the JanusGraph documentation under Connecting from Java. Note that I've linked to a version of the docs for the upcoming 1.0.0 release because the documentation for the latest released version right now still uses Gryo instead of GraphBinary. But you can still use this with JanusGraph 0.6 already and it also makes sense to use GraphBinary instead of Gryo, because support for Gryo will be dropped in version 1.0.0.
The config file conf/remote-graph.properties looks then like this (also taken from the JanusGraph documentation):
hosts: [localhost]
port: 8182
serializer: {
className: org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1,
config: { ioRegistries: [org.janusgraph.graphdb.tinkerpop.JanusGraphIoRegistry] }}
You can also specify the various options that you are currently specifying via the builder. This configuration is documented in the TinkerPop reference docs.

Spring reactive Mono:blockOptional conflict with spring actuator

I'm mapping json array response to reactor world but have an issue like:
val responses = configurationClient.getData() // return json array object
.flatMap { it.bodyToMono(object : ParameterizedTypeReference<GeneralResponse<Array<ObjectResponse>>>() {})
}
.map { it.data }
.blockOptional() // exception this line
.orElse(emptyArray())!!
This snipcode doesn't work if I add this property of spring actuator
management.endpoints.enabled-by-default=true
Netty server cannot start without any exceptions.
But It works when I change to
management.endpoints.enabled-by-default=false
The Netty started well
Any ideas this issue please?
** Updated **
When I add some timeout value .blockOptional(Duration.ofSeconds(60)) //60 seconds
val responses = configurationClient.getData() // return json array object
.flatMap { it.bodyToMono(object : ParameterizedTypeReference<GeneralResponse<Array<ObjectResponse>>>() {})
}
.map { it.data }
.blockOptional(Duration.ofSeconds(60))
.get()
I pretty sure conflict somewhere between Mono and Spring actuator management.endpoints.enabled-by-default=true
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:886)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:790)
... 20 common frames omitted
Caused by: java.lang.IllegalStateException: Timeout on blocking read for 60000 MILLISECONDS
at reactor.core.publisher.BlockingOptionalMonoSubscriber.blockingGet(BlockingOptionalMonoSubscriber.java:162)
at reactor.core.publisher.Mono.blockOptional(Mono.java:1755)
Note
configurationClient.getData() this just a GET request return 200-[{...}]
Everything work if I use
management.endpoints.enabled-by-default=false
problem is solved.
Root cause:
It's not a bug of Mono:blockOptional or Spring actuator individually.
This configuration management.endpoints.enabled-by-default=true is conflict with existing actuator endpoint configurations
Solution:
Cleanup spring actuator configuration properties to avoid this conflict then Mono:blockOptional work well

Hide details for health indicators in Spring Boot Actuator

I'm using Spring Boot health indicator from an actuator. So far example response looks like:
{
"status":"DOWN",
"details": {
"diskSpace": {
"status":"UP",
"details": {
"total":499963170816,
"free":250067189760,
"threshold":10485760
}
}
}
}
Because I need to make /actuator/health endpoint public, I need to hide details for health indicators, so I expect to get something like this:
{
"status":"DOWN",
"details": {
"diskSpace": {
"status":"UP"
}
}
}
For disk space it's not a big problem but e.g. for database I don't want to share exception message and details in case of it's outage. Also (as I mentioned at the beginning) it must be public so I don't want to make this endpoint 'when-authorized'. And at the end - it would be great if it's possible to do that without writing my own custom endpoint.
Is it possible at all?
This isn't possible at the time of writing (in Spring Boot 2.1 and earlier) without writing your own custom endpoint. I've opened an issue to consider it as an enhancement for a future version of Spring Boot.
There is a way to achieve this in Spring Boot 2.X
management:
health:
db:
enabled: false
diskspace:
enabled: false
mongo:
enabled: false
refresh:
enabled: false
More information can be found here https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-endpoints.html#_auto_configured_healthindicators

Spring Boot - Change the location of the /health endpoint to /ping/me

I set the endpoints.health.path property to /ping/me. But I cannot access the endpoint using http://localhost:9000/ping/me
It only works with http://localhost:9000/health. What am I missing ?
Here is the code in app properties file.
#Configuration for Health endpoint
endpoints.health.id=health
endpoints.health.path=/ping/me
endpoints.health.enabled=true
endpoints.health.sensitive=false
#Manage endpoints
management.port=9000
management.health.diskspace.enabled=false
The response I get is :
{
"timestamp" : 1455736069839,
"status" : 404,
"error" : "Not Found",
"message" : "Not Found",
"path" : "/ping/me"
}
The Actuator became technology-agnostic in Spring Boot 2.0.0, so it's not tied to MVC now. Thus if you use Spring Boot 2.0.x, you can just add the following config properties:
# custom actuator base path: use root mapping `/` instead of default `/actuator/`
management.endpoints.web.base-path=
# override endpoint name for health check: `/health` => `/ping/me`
management.endpoints.web.path-mapping.health=/ping/me
If you don't override the management.endpoints.web.base-path, your health-check will be available at /actuator/ping/me.
The properties like endpoints.* became deprecated in Spring Boot 2.0.0.
See below for Spring Boot 2.*
https://stackoverflow.com/a/50364513/2193477
MvcEndpoints is responsible for reading endpoints.{name}.path configurations and somehow in its afterPropertiesSet method:
for (Endpoint<?> endpoint : delegates) {
if (isGenericEndpoint(endpoint.getClass()) && endpoint.isEnabled()) {
EndpointMvcAdapter adapter = new EndpointMvcAdapter(endpoint);
String path = this.applicationContext.getEnvironment()
.getProperty("endpoints." + endpoint.getId() + ".path");
if (path != null) {
adapter.setPath(path);
}
this.endpoints.add(adapter);
}
}
It refusing from setting the endpoints.health.path, since isGenericEndpoint(...) is returning false for HealthEndpoint. Maybe it's a bug or something.
Update: Apparently this was a bug and got fixed in 1.3.3.RELEASE version. So, you can use the /ping/me as your health monitoring path in this version.

Resources