From 5ed22b368b4ea4d3e6d850d5bf66bb4d9e2bc566 Mon Sep 17 00:00:00 2001 From: Igor Artamonov Date: Wed, 3 Feb 2021 23:08:44 -0500 Subject: [PATCH] solution: monitoring config --- .../dshackle/config/MainConfigReader.kt | 4 ++ .../dshackle/config/MonitoringConfig.kt | 9 ++- .../dshackle/config/MonitoringConfigReader.kt | 64 +++++++++++++++++++ .../dshackle/monitoring/MonitoringSetup.kt | 2 +- .../config/MonitoringConfigReaderSpec.groovy | 40 ++++++++++++ .../resources/dshackle-monitoring-basic.yaml | 7 ++ 6 files changed, 124 insertions(+), 2 deletions(-) create mode 100644 src/main/kotlin/io/emeraldpay/dshackle/config/MonitoringConfigReader.kt create mode 100644 src/test/groovy/io/emeraldpay/dshackle/config/MonitoringConfigReaderSpec.groovy create mode 100644 src/test/resources/dshackle-monitoring-basic.yaml diff --git a/src/main/kotlin/io/emeraldpay/dshackle/config/MainConfigReader.kt b/src/main/kotlin/io/emeraldpay/dshackle/config/MainConfigReader.kt index 2af182b8..84c82119 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/config/MainConfigReader.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/config/MainConfigReader.kt @@ -33,6 +33,7 @@ class MainConfigReader( private val upstreamsConfigReader = UpstreamsConfigReader(fileResolver) private val cacheConfigReader = CacheConfigReader() private val tokensConfigReader = TokensConfigReader() + private val monitoringConfigReader = MonitoringConfigReader() fun read(input: InputStream): MainConfig? { val configNode = readNode(input) @@ -63,6 +64,9 @@ class MainConfigReader( tokensConfigReader.read(input)?.let { config.tokens = it } + monitoringConfigReader.read(input).let { + config.monitoring = it + } return config } diff --git a/src/main/kotlin/io/emeraldpay/dshackle/config/MonitoringConfig.kt b/src/main/kotlin/io/emeraldpay/dshackle/config/MonitoringConfig.kt index 30d51797..b8b4a7b3 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/config/MonitoringConfig.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/config/MonitoringConfig.kt @@ -24,17 +24,24 @@ class MonitoringConfig( fun default(): MonitoringConfig { return MonitoringConfig(true, PrometheusConfig.default()) } + fun disabled(): MonitoringConfig { + return MonitoringConfig(false, PrometheusConfig.disabled()) + } } data class PrometheusConfig( val enabled: Boolean, val path: String, + val host: String, val port: Int ) { companion object { fun default(): PrometheusConfig { - return PrometheusConfig(true, "/prometheus", 8081) + return PrometheusConfig(true, "/metrics", "127.0.0.1", 8081) + } + fun disabled(): PrometheusConfig { + return PrometheusConfig(false, "/", "127.0.0.1", 0) } } } diff --git a/src/main/kotlin/io/emeraldpay/dshackle/config/MonitoringConfigReader.kt b/src/main/kotlin/io/emeraldpay/dshackle/config/MonitoringConfigReader.kt new file mode 100644 index 00000000..65d8d09e --- /dev/null +++ b/src/main/kotlin/io/emeraldpay/dshackle/config/MonitoringConfigReader.kt @@ -0,0 +1,64 @@ +/** + * Copyright (c) 2021 EmeraldPay, Inc + * + * Licensed 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 io.emeraldpay.dshackle.config + +import org.slf4j.LoggerFactory +import org.yaml.snakeyaml.nodes.MappingNode +import java.io.InputStream + +class MonitoringConfigReader: YamlConfigReader(), ConfigReader { + + companion object { + private val log = LoggerFactory.getLogger(MonitoringConfigReader::class.java) + } + + fun read(input: InputStream): MonitoringConfig { + val configNode = readNode(input) + return read(configNode) + } + + override fun read(input: MappingNode?): MonitoringConfig { + return readInternal(getMapping(input, "monitoring")) + } + + fun readInternal(input: MappingNode?): MonitoringConfig { + if (input == null) { + return MonitoringConfig.default() + } + val enabled = getValueAsBool(input, "enabled") ?: false + if (!enabled) { + return MonitoringConfig.disabled() + } + val prometheus = readPrometheus(getMapping(input, "prometheus")) + return MonitoringConfig(enabled, prometheus) + } + + private fun readPrometheus(input: MappingNode?): MonitoringConfig.PrometheusConfig { + if (input == null) { + return MonitoringConfig.PrometheusConfig.default() + } + val enabled = getValueAsBool(input, "enabled") ?: true + if (!enabled) { + return MonitoringConfig.PrometheusConfig.disabled() + } + val default = MonitoringConfig.PrometheusConfig.default() + val path = getValueAsString(input, "path") ?: default.path + val host = getValueAsString(input, "bind") ?: getValueAsString(input, "host") ?: default.host + val port = getValueAsInt(input, "port") ?: default.port + return MonitoringConfig.PrometheusConfig(enabled, path, host, port) + } + +} \ No newline at end of file diff --git a/src/main/kotlin/io/emeraldpay/dshackle/monitoring/MonitoringSetup.kt b/src/main/kotlin/io/emeraldpay/dshackle/monitoring/MonitoringSetup.kt index c73164a5..ead272d4 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/monitoring/MonitoringSetup.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/monitoring/MonitoringSetup.kt @@ -57,7 +57,7 @@ class MonitoringSetup( // use standard JVM server with a single thread blocking processing // prometheus is a single thread periodic call, no reason to setup anything complex try { - val server = HttpServer.create(InetSocketAddress(monitoringConfig.prometheus.port), 0); + val server = HttpServer.create(InetSocketAddress(monitoringConfig.prometheus.host, monitoringConfig.prometheus.port), 0); server.createContext(monitoringConfig.prometheus.path) { httpExchange -> val response = prometheusRegistry.scrape() httpExchange.sendResponseHeaders(200, response.toByteArray().size.toLong()); diff --git a/src/test/groovy/io/emeraldpay/dshackle/config/MonitoringConfigReaderSpec.groovy b/src/test/groovy/io/emeraldpay/dshackle/config/MonitoringConfigReaderSpec.groovy new file mode 100644 index 00000000..a1fa8f67 --- /dev/null +++ b/src/test/groovy/io/emeraldpay/dshackle/config/MonitoringConfigReaderSpec.groovy @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2021 EmeraldPay, Inc + * + * Licensed 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 io.emeraldpay.dshackle.config + +import spock.lang.Specification + +class MonitoringConfigReaderSpec extends Specification { + + MonitoringConfigReader reader = new MonitoringConfigReader() + + def "Read basic monitoring config"() { + setup: + def config = this.class.getClassLoader().getResourceAsStream("dshackle-monitoring-basic.yaml") + when: + def act = reader.read(config) + + then: + act.enabled + act.prometheus != null + with(act.prometheus) { + enabled + port == 8000 + host == "192.168.0.1" + path == "/status/prometheus" + } + } +} diff --git a/src/test/resources/dshackle-monitoring-basic.yaml b/src/test/resources/dshackle-monitoring-basic.yaml new file mode 100644 index 00000000..1748c26b --- /dev/null +++ b/src/test/resources/dshackle-monitoring-basic.yaml @@ -0,0 +1,7 @@ +monitoring: + enabled: true + prometheus: + enabled: true + bind: 192.168.0.1 + port: 8000 + path: /status/prometheus