Reputation: 2190
I am currently migrating one of our clojure services to vert.x, using kotlin as main language. Most things work like a charm, but there is one issue I am struggling with for quite some time now.
All of our services use micrometer.io and prometheus to collect metrics. According to the documentation, integrating micrometer is straight-forward:
val vertx = Vertx.vertx(
VertxOptions().setMetricsOptions(
MicrometerMetricsOptions()
.setPrometheusOptions(VertxPrometheusOptions().setEnabled(true))
.setEnabled(true)
)
)
In general, this approach works nicely - metrics are gathered and exposed by adding a separate route:
router.get("/metrics").handler(PrometheusScrapingHandler.create())
The problem I am struggling with is, that there is no way I am aware of to define these vert.x-related settings (VertxOptions
) only once and publish them globally - basically whenever a new Vertx
instance is created.
This is an issue, because currently I have to define these settings on three different places:
1.) Server.kt
Allows to start the service with my IDE
2.) ServerLauncher
The purpose of this class is to start the server from the commandline with gradle.
3.) Integration tests
Vert.x provides a nifty junit5 extension (VertxExtension
) which automatically injects the Vertx
and VertxTestContext
instances in your test methods. The downside is that there is no way to configure the injected Vertx
instance as it always injects it with default settings.
Thus you have to wire everything on your own in your test method:
@Test
@DisplayName("Call prometheus endpoint and verify core metrics are present")
fun callPrometheusEndpoint(testCtx: VertxTestContext) {
val vertx = Vertx.vertx(
VertxOptions().setMetricsOptions(
MicrometerMetricsOptions()
.setPrometheusOptions(VertxPrometheusOptions().setEnabled(true))
.setEnabled(true)
)
)
vertx.deployVerticle(
MyVerticle(),
testCtx.completing()
)
WebClient.create(vertx)
.get(8080, "localhost", "/internal/prometheus")
.`as`(BodyCodec.string())
.send(testCtx.succeeding { resp ->
testCtx.verify {
// assertions to follow...
testCtx.completeNow()
}
})
}
I am wondering, if there is any way to define the VertxOptions
only once and thus override/complement the default settings used, whenever a Vertx
instance is created?
Update 1
I decided to extract a separate Application
class in order to configure the Vertx
instance and get rid of Server.kt
and ServerLauncher.kt
.
class Application(
private val profileSetting: String? = System.getenv("ACTIVE_PROFILES"),
private val logger: Logger = LoggerFactory.getLogger(Application::class.java)!!
) {
fun bootstrap() {
val profiles = activeProfiles()
val vertx = bootstrapVertx(profiles)
val configRetriever = bootstrapConfigRetriever(vertx, profiles)
val myVerticle = MyVerticle(configRetriever)
vertx.deployVerticle(myVerticle) { startup ->
if (startup.succeeded()) {
logger.info("Application startup finished")
} else {
logger.error("Application startup failed", startup.cause())
vertx.close()
}
}
}
internal fun activeProfiles(): List<String> {
logger.info("Configured profiles: {}", profileSetting)
return profileSetting
?.let { it.split(',').map { p -> p.trim() }.filter { p -> p.isNotBlank() } }
?: emptyList()
}
internal fun bootstrapVertx(profiles: List<String>): Vertx {
registerModules()
val vertxOptions = VertxOptionsFactory(profiles).create()
return Vertx.vertx(vertxOptions)
}
internal fun bootstrapConfigRetriever(vertx: Vertx, profiles: List<String>): ConfigRetriever {
return ConfigRetrieverFactory(profiles).create(vertx)
}
private fun registerModules() {
Json.mapper.apply { registerKotlinModule() }
Json.prettyMapper.apply { registerKotlinModule() }
}
companion object {
@JvmStatic
fun main(args: Array<String>) = Application().bootstrap()
}
}
I found no way to pass the configured Vertx
instance to the VertxExtention
though.
Update 2
I created a pull request that addresses the issue of pre-configuring vertx instances in tests.
Upvotes: 1
Views: 1529
Reputation: 380
I'd like to share some more info to @tsegismont answer.
To use prometheus metrics you can define options.json
as following (after adding necessary includes to your pom or build.gradle):
{ "metricsOptions": {
"enabled": true,
"prometheusOptions" : {
"enabled": true,
"embeddedServerOptions": {"port": 8080},
"startEmbeddedServer": true
} } }
it will expose metrices on host:8080/metrics
To put more options into options.json
- I just scanned source code of
BareCommand.getMetricsOptions
MicrometerMetricsOptionsConverter.fromJson
There are easy to read json parsing functions.
To add options to your jar:
java -jar your-vertx-app.jar -options options.json
To use it from IDE, you may use Launcher.executeCommand
:
java:
public static void main(final String[] args) {
Launcher.executeCommand("run", args);
}
kotlin:
fun main(args: Array<String>) {
Launcher.executeCommand("run", "com.your.LauncherVerticle", *args)
}
Afther that you can pass -options options.json
parameters in case of kotlin or com.your.LauncherVerticle -options options.json
in case of java to program arguments of your run configuration. Launcher.executeCommand
will use this file.
Upvotes: 0
Reputation: 9128
Since Vert.x 3.6.0, you can put Vert.x options in a file and load them with -options
. That works if you are using the CLI or a Launcher
class.
When you have to start Vert.x in embedded mode (eg tests), you can read the file content, and create the VertxOptions
instance from a JsonObject
.
Upvotes: 2