-
Notifications
You must be signed in to change notification settings - Fork 12
feat: cdc metrics #518
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
feat: cdc metrics #518
Changes from 18 commits
Commits
Show all changes
24 commits
Select commit
Hold shift + click to select a range
55d08d9
feat: add kafak metrics to apoc cdc handler
venikkin d2d7b7a
feat: add metrics data class
venikkin 7bdb98c
Merge remote-tracking branch 'origin/main' into cdc-metrics-native
venikkin 9b98c9c
feat: update cdc sink handler
venikkin 94a8d08
feat: add source metrics
venikkin d20ca20
feat: implement jmx reporter
venikkin cc01c15
refactor: clean up
venikkin f5fed7c
chore: spotless
venikkin 8cd6cfd
refactor: use write access mode to retrieve last db tx id from a leader
venikkin 053fe21
refactor: parameterize last db metric
venikkin b51e87e
fix: update unit tests
venikkin a666fc1
refactor: downgrade to kafka 3.8
venikkin b8abc09
Merge branch 'main' into cdc-metrics-native
venikkin 39d659d
test: add metric tests
venikkin bf7b24b
chore: udate test description
venikkin ba7bdf0
chore: spotless apply
venikkin 5d464ad
refactor: move tx id properties to source config
venikkin 167f58a
chore: update default value
venikkin a0e4635
refactor: review fixes
venikkin bfa81f6
refactor: pass databaseName to db tx metric data
venikkin d3356cb
fix: update unit test
venikkin c6d906b
fix: typo
venikkin d2a1084
Merge branch 'main' into cdc-metrics-native
venikkin 1f3e3fe
refactor: update metrics description
venikkin File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
59 changes: 59 additions & 0 deletions
59
common/src/main/kotlin/org/neo4j/connectors/kafka/metrics/CdcMetricsData.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| /* | ||
| * Copyright (c) "Neo4j" | ||
| * Neo4j Sweden AB [https://neo4j.com] | ||
| * | ||
| * 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 org.neo4j.connectors.kafka.metrics | ||
|
|
||
| import java.util.concurrent.atomic.AtomicLong | ||
| import org.neo4j.cdc.client.model.ChangeEvent | ||
|
|
||
| class CdcMetricsData(metrics: Metrics, tags: LinkedHashMap<String, String> = linkedMapOf()) { | ||
|
|
||
| private var lastTxCommitTs: AtomicLong = AtomicLong(0L) | ||
| private var lastTxStartTs: AtomicLong = AtomicLong(0L) | ||
| private var lastTxId: AtomicLong = AtomicLong(0L) | ||
|
|
||
| init { | ||
| metrics.addGauge( | ||
| "last_cdc_tx_commit_timestamp", | ||
| "The transaction commit timestamp of the last processed CDC message", | ||
| tags, | ||
| ) { | ||
| lastTxCommitTs.get() | ||
| } | ||
| metrics.addGauge( | ||
| "last_cdc_tx_start_timestamp", | ||
| "The transaction start timestamp of the last processed CDC message", | ||
venikkin marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| tags, | ||
| ) { | ||
| lastTxStartTs.get() | ||
| } | ||
| metrics.addGauge( | ||
| "last_cdc_tx_id", | ||
| "The transaction id of the last processed CDC message", | ||
venikkin marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| tags, | ||
| ) { | ||
| lastTxId.get() | ||
| } | ||
| } | ||
|
|
||
| fun update(event: ChangeEvent) { | ||
| event.metadata?.let { | ||
| lastTxCommitTs.set(it.txCommitTime.toEpochSecond()) | ||
| lastTxStartTs.set(it.txStartTime.toEpochSecond()) | ||
| } | ||
| lastTxId.set(event.txId) | ||
| } | ||
| } | ||
93 changes: 93 additions & 0 deletions
93
common/src/main/kotlin/org/neo4j/connectors/kafka/metrics/DbTransactionMetricsData.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,93 @@ | ||
| /* | ||
| * Copyright (c) "Neo4j" | ||
| * Neo4j Sweden AB [https://neo4j.com] | ||
| * | ||
| * 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 org.neo4j.connectors.kafka.metrics | ||
|
|
||
| import java.io.Closeable | ||
| import java.util.concurrent.atomic.AtomicLong | ||
| import kotlin.time.Duration | ||
| import kotlinx.coroutines.CoroutineDispatcher | ||
| import kotlinx.coroutines.CoroutineScope | ||
| import kotlinx.coroutines.Dispatchers | ||
| import kotlinx.coroutines.Job | ||
| import kotlinx.coroutines.cancel | ||
| import kotlinx.coroutines.delay | ||
| import kotlinx.coroutines.isActive | ||
| import kotlinx.coroutines.launch | ||
| import org.neo4j.driver.AccessMode | ||
| import org.neo4j.driver.Driver | ||
| import org.neo4j.driver.SessionConfig | ||
| import org.neo4j.driver.TransactionConfig | ||
|
|
||
| class DbTransactionMetricsData( | ||
| metrics: Metrics, | ||
| tags: LinkedHashMap<String, String> = linkedMapOf(), | ||
| refreshInterval: Duration, | ||
| neo4jDriver: Driver, | ||
| sessionConfig: SessionConfig, | ||
| transactionConfig: TransactionConfig, | ||
| dispatcher: CoroutineDispatcher = Dispatchers.Default, | ||
| ) : Closeable { | ||
|
|
||
| private val writeAccessModeSessionConfig: SessionConfig by lazy { | ||
| val builder = SessionConfig.builder() | ||
|
|
||
| sessionConfig.database().ifPresent { builder.withDatabase(it) } | ||
| sessionConfig.fetchSize().ifPresent { builder.withFetchSize(it) } | ||
| sessionConfig.impersonatedUser().ifPresent { builder.withImpersonatedUser(it) } | ||
| sessionConfig.bookmarks()?.let { builder.withBookmarks(it) } | ||
|
|
||
| builder.withDefaultAccessMode(AccessMode.WRITE) | ||
| builder.build() | ||
| } | ||
|
|
||
| private val lastTransactionId = AtomicLong(0) | ||
| private val scope = CoroutineScope(dispatcher + Job()) | ||
|
|
||
| init { | ||
| metrics.addGauge( | ||
| "last_db_tx_id", | ||
| "The transaction commit timestamp of the last processed CDC message", | ||
venikkin marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| tags, | ||
| ) { | ||
| lastTransactionId.get() | ||
| } | ||
|
|
||
| scope.launch { | ||
| val databaseName = writeAccessModeSessionConfig.database().orElse("neo4j") | ||
| while (isActive) { | ||
| val txId = | ||
| neo4jDriver.session(writeAccessModeSessionConfig).use { session -> | ||
| session | ||
| .run( | ||
venikkin marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| "SHOW DATABASE $databaseName YIELD lastCommittedTxn RETURN lastCommittedTxn as txId", | ||
| transactionConfig, | ||
| ) | ||
| .single() | ||
| .get("txId") | ||
| .asLong() | ||
| } | ||
| lastTransactionId.set(txId) | ||
|
|
||
| delay(refreshInterval) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| override fun close() { | ||
| scope.cancel() | ||
| } | ||
| } | ||
118 changes: 118 additions & 0 deletions
118
common/src/main/kotlin/org/neo4j/connectors/kafka/metrics/JmxMetrics.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,118 @@ | ||
| /* | ||
| * Copyright (c) "Neo4j" | ||
| * Neo4j Sweden AB [https://neo4j.com] | ||
| * | ||
| * 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 org.neo4j.connectors.kafka.metrics | ||
|
|
||
| import java.lang.management.ManagementFactory | ||
| import java.util.Hashtable | ||
| import java.util.concurrent.ConcurrentHashMap | ||
| import javax.management.Attribute | ||
| import javax.management.AttributeList | ||
| import javax.management.DynamicMBean | ||
| import javax.management.MBeanAttributeInfo | ||
| import javax.management.MBeanInfo | ||
| import javax.management.ObjectName | ||
| import org.neo4j.connectors.kafka.configuration.Neo4jConfiguration | ||
|
|
||
| class JmxMetrics(config: Neo4jConfiguration) : Metrics, DynamicMBean { | ||
|
|
||
| private val connectorName: String = config.connectorName | ||
| private val taskId: String = config.taskId | ||
| private val objectName: ObjectName = | ||
| ObjectName( | ||
| "kafka.connect", | ||
| Hashtable<String, String>().apply { | ||
| put("type", "plugins") | ||
| put("connector", connectorName) | ||
| put("task", taskId) | ||
| }, | ||
| ) | ||
|
|
||
| private val gauges = ConcurrentHashMap<String, Gauge<*>>() | ||
| private val mbs = ManagementFactory.getPlatformMBeanServer() | ||
|
|
||
| init { | ||
| if (mbs.isRegistered(objectName)) { | ||
| mbs.unregisterMBean(objectName) | ||
| } | ||
| mbs.registerMBean(this, objectName) | ||
| } | ||
|
|
||
| override fun <T : Number> addGauge( | ||
| name: String, | ||
| description: String, | ||
| tags: LinkedHashMap<String, String>, | ||
| valueProvider: () -> T?, | ||
| ) { | ||
| gauges[name] = Gauge(name, description, valueProvider) | ||
| } | ||
|
|
||
| override fun getAttribute(attribute: String?): Any? { | ||
| return gauges[attribute]?.valueProvider?.invoke() | ||
| } | ||
|
|
||
| override fun setAttribute(attribute: Attribute?) { | ||
| throw UnsupportedOperationException("Attributes are read-only") | ||
| } | ||
|
|
||
| override fun getAttributes(attributes: Array<out String>?): AttributeList { | ||
| val list = AttributeList() | ||
| attributes?.forEach { name -> | ||
| getAttribute(name)?.let { value -> list.add(Attribute(name, value)) } | ||
| } | ||
| return list | ||
| } | ||
|
|
||
| override fun setAttributes(attributes: AttributeList?): AttributeList { | ||
| throw UnsupportedOperationException("Attributes are read-only") | ||
| } | ||
|
|
||
| override fun invoke( | ||
| actionName: String?, | ||
| params: Array<out Any>?, | ||
| signature: Array<out String>?, | ||
| ): Any { | ||
| throw UnsupportedOperationException("Operations are not supported") | ||
| } | ||
|
|
||
| override fun getMBeanInfo(): MBeanInfo { | ||
| val attrs = | ||
| gauges.values.map { gauge -> | ||
| MBeanAttributeInfo(gauge.name, "java.lang.Number", gauge.description, true, false, false) | ||
| } | ||
|
|
||
| return MBeanInfo( | ||
| this.javaClass.name, | ||
| "Neo4j Kafka Connector JMX Metrics", | ||
| attrs.toTypedArray(), | ||
| null, | ||
| null, | ||
| null, | ||
| ) | ||
| } | ||
|
|
||
| private class Gauge<T : Number>( | ||
| val name: String, | ||
| val description: String, | ||
| val valueProvider: () -> T?, | ||
| ) | ||
|
|
||
| override fun close() { | ||
| if (mbs.isRegistered(objectName)) { | ||
| mbs.unregisterMBean(objectName) | ||
| } | ||
| } | ||
| } |
36 changes: 36 additions & 0 deletions
36
common/src/main/kotlin/org/neo4j/connectors/kafka/metrics/MetricsFactory.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| /* | ||
| * Copyright (c) "Neo4j" | ||
| * Neo4j Sweden AB [https://neo4j.com] | ||
| * | ||
| * 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 org.neo4j.connectors.kafka.metrics | ||
|
|
||
| import java.io.Closeable | ||
| import org.neo4j.connectors.kafka.configuration.Neo4jConfiguration | ||
|
|
||
| class MetricsFactory { | ||
|
|
||
| fun createMetrics(config: Neo4jConfiguration): Metrics { | ||
| return JmxMetrics(config) | ||
| } | ||
| } | ||
|
|
||
| interface Metrics : Closeable { | ||
| fun <T : Number> addGauge( | ||
| name: String, | ||
| description: String, | ||
| tags: LinkedHashMap<String, String>, | ||
| valueProvider: () -> T?, | ||
| ) | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.