-
Notifications
You must be signed in to change notification settings - Fork 1.1k
chore: Add MetricsRecorder interface to Datastore #12028
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
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
bf33238
chore: Add OpenTelemetry Metrics enable/disable configuration
lqiu96 ca9793d
chore: Refactor the telemetry constants
lqiu96 e8eb8ac
Merge remote-tracking branch 'origin' into feat/datastore-metrics-rec…
lqiu96 22d9387
chore: optimize fmt check to only evaluate modified modules
lqiu96 7a62c9e
chore: Fix compilation issue
lqiu96 f0dfc65
chore: Fix lint issues
lqiu96 5a1819c
Merge branch 'main' into feat/datastore-metrics-recorder
lqiu96 d061eb9
chore: Fix typo in ATTRIBUTES_KEY_MORE_RESULTS constant
lqiu96 b518a19
chore: Address PR feedback
lqiu96 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
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
54 changes: 54 additions & 0 deletions
54
...e-cloud-datastore/src/main/java/com/google/cloud/datastore/telemetry/MetricsRecorder.java
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,54 @@ | ||
| /* | ||
| * Copyright 2026 Google LLC | ||
| * | ||
| * 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 com.google.cloud.datastore.telemetry; | ||
|
|
||
| import com.google.cloud.datastore.DatastoreOpenTelemetryOptions; | ||
| import io.opentelemetry.api.GlobalOpenTelemetry; | ||
| import io.opentelemetry.api.OpenTelemetry; | ||
| import java.util.Map; | ||
| import javax.annotation.Nonnull; | ||
|
|
||
| /** Interface to record specific metric operations. */ | ||
| public interface MetricsRecorder { | ||
| /** Records the total latency of a transaction in milliseconds. */ | ||
| void recordTransactionLatency(double latencyMs, Map<String, String> attributes); | ||
|
|
||
| /** Records the number of attempts a transaction took. */ | ||
| void recordTransactionAttemptCount(long count, Map<String, String> attributes); | ||
|
|
||
| /** | ||
| * Returns a {@link MetricsRecorder} instance based on the provided OpenTelemetry options. | ||
| * | ||
| * @param options The {@link com.google.cloud.datastore.DatastoreOpenTelemetryOptions} configuring | ||
| * telemetry. | ||
| * @return An {@link OpenTelemetryMetricsRecorder} if metrics are enabled, otherwise a {@link | ||
| * NoOpMetricsRecorder}. | ||
| */ | ||
| static MetricsRecorder getInstance(@Nonnull DatastoreOpenTelemetryOptions options) { | ||
| boolean isMetricsEnabled = options.isMetricsEnabled(); | ||
|
|
||
| if (isMetricsEnabled) { | ||
| OpenTelemetry openTelemetry = options.getOpenTelemetry(); | ||
| if (openTelemetry == null) { | ||
| return new OpenTelemetryMetricsRecorder(GlobalOpenTelemetry.get()); | ||
| } | ||
| return new OpenTelemetryMetricsRecorder(openTelemetry); | ||
| } else { | ||
| return new NoOpMetricsRecorder(); | ||
| } | ||
| } | ||
| } | ||
36 changes: 36 additions & 0 deletions
36
...oud-datastore/src/main/java/com/google/cloud/datastore/telemetry/NoOpMetricsRecorder.java
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 2026 Google LLC | ||
| * | ||
| * 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 com.google.cloud.datastore.telemetry; | ||
|
|
||
| import java.util.Map; | ||
|
|
||
| /** | ||
| * Metrics recorder implementation, used to stub out metrics instrumentation when metrics are | ||
| * disabled. | ||
| */ | ||
| class NoOpMetricsRecorder implements MetricsRecorder { | ||
|
|
||
| @Override | ||
| public void recordTransactionLatency(double latencyMs, Map<String, String> attributes) { | ||
| /* No-Op OTel Operation */ | ||
| } | ||
|
|
||
| @Override | ||
| public void recordTransactionAttemptCount(long count, Map<String, String> attributes) { | ||
| /* No-Op OTel Operation */ | ||
| } | ||
| } |
77 changes: 77 additions & 0 deletions
77
...tore/src/main/java/com/google/cloud/datastore/telemetry/OpenTelemetryMetricsRecorder.java
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,77 @@ | ||
| /* | ||
| * Copyright 2026 Google LLC | ||
| * | ||
| * 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 com.google.cloud.datastore.telemetry; | ||
|
|
||
| import io.opentelemetry.api.OpenTelemetry; | ||
| import io.opentelemetry.api.common.Attributes; | ||
| import io.opentelemetry.api.common.AttributesBuilder; | ||
| import io.opentelemetry.api.metrics.DoubleHistogram; | ||
| import io.opentelemetry.api.metrics.LongCounter; | ||
| import io.opentelemetry.api.metrics.Meter; | ||
| import java.util.Map; | ||
| import javax.annotation.Nonnull; | ||
|
|
||
| /** | ||
| * OpenTelemetry metrics recorder implementation, used to record metrics when metrics are enabled. | ||
| */ | ||
| class OpenTelemetryMetricsRecorder implements MetricsRecorder { | ||
| private final OpenTelemetry openTelemetry; | ||
|
|
||
| private final DoubleHistogram transactionLatency; | ||
| private final LongCounter transactionAttemptCount; | ||
|
|
||
| OpenTelemetryMetricsRecorder(@Nonnull OpenTelemetry openTelemetry) { | ||
| this.openTelemetry = openTelemetry; | ||
|
|
||
| Meter meter = openTelemetry.getMeter(TelemetryConstants.METER_NAME); | ||
|
|
||
| this.transactionLatency = | ||
| meter | ||
| .histogramBuilder(TelemetryConstants.SERVICE_NAME + "/transaction_latency") | ||
|
jinseopkim0 marked this conversation as resolved.
|
||
| .setDescription("Total latency for successful transaction operations") | ||
| .setUnit("ms") | ||
| .build(); | ||
|
|
||
| this.transactionAttemptCount = | ||
| meter | ||
| .counterBuilder(TelemetryConstants.SERVICE_NAME + "/transaction_attempt_count") | ||
| .setDescription("Number of attempts to commit a transaction") | ||
| .build(); | ||
| } | ||
|
|
||
| OpenTelemetry getOpenTelemetry() { | ||
| return openTelemetry; | ||
| } | ||
|
|
||
| @Override | ||
| public void recordTransactionLatency(double latencyMs, Map<String, String> attributes) { | ||
| transactionLatency.record(latencyMs, toOtelAttributes(attributes)); | ||
| } | ||
|
|
||
| @Override | ||
| public void recordTransactionAttemptCount(long count, Map<String, String> attributes) { | ||
| transactionAttemptCount.add(count, toOtelAttributes(attributes)); | ||
| } | ||
|
|
||
| private static Attributes toOtelAttributes(Map<String, String> attributes) { | ||
| AttributesBuilder builder = Attributes.builder(); | ||
| if (attributes != null) { | ||
| attributes.forEach(builder::put); | ||
| } | ||
| return builder.build(); | ||
| } | ||
| } | ||
58 changes: 58 additions & 0 deletions
58
...loud-datastore/src/main/java/com/google/cloud/datastore/telemetry/TelemetryConstants.java
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,58 @@ | ||
| /* | ||
| * Copyright 2026 Google LLC | ||
| * | ||
| * 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 com.google.cloud.datastore.telemetry; | ||
|
|
||
| import com.google.api.core.InternalApi; | ||
|
|
||
| /** Internal telemetry constants shared between OpenTelemetry tracing and metrics. */ | ||
| @InternalApi | ||
| public class TelemetryConstants { | ||
| static final String SERVICE_NAME = "datastore.googleapis.com"; | ||
| static final String METER_NAME = "com.google.cloud.datastore"; | ||
|
|
||
| public static final String ATTRIBUTES_KEY_DOCUMENT_COUNT = "doc_count"; | ||
| public static final String ATTRIBUTES_KEY_TRANSACTIONAL = "transactional"; | ||
| public static final String ATTRIBUTES_KEY_TRANSACTION_ID = "transaction_id"; | ||
| public static final String ATTRIBUTES_KEY_READ_CONSISTENCY = "read_consistency"; | ||
| public static final String ATTRIBUTES_KEY_RECEIVED = "Received"; | ||
| public static final String ATTRIBUTES_KEY_MISSING = "Missing"; | ||
| public static final String ATTRIBUTES_KEY_DEFERRED = "Deferred"; | ||
| public static final String ATTRIBUTES_KEY_MORE_RESULTS = "more_results"; | ||
|
|
||
| /* TODO(lawrenceqiu): For now, these are a duplicate of method names in TraceUtil. Those will use these eventually */ | ||
| // Format is not SnakeCase to keep backward compatibility with the existing values TraceUtil spans | ||
| public static final String METHOD_ALLOCATE_IDS = "AllocateIds"; | ||
|
lqiu96 marked this conversation as resolved.
|
||
| public static final String METHOD_BEGIN_TRANSACTION = "Transaction.Begin"; | ||
| public static final String METHOD_COMMIT = "Commit"; | ||
| public static final String METHOD_LOOKUP = "Lookup"; | ||
| public static final String METHOD_RESERVE_IDS = "ReserveIds"; | ||
| public static final String METHOD_RUN_QUERY = "RunQuery"; | ||
| public static final String METHOD_TRANSACTION_COMMIT = "Transaction.Commit"; | ||
| public static final String METHOD_TRANSACTION_LOOKUP = "Transaction.Lookup"; | ||
| public static final String METHOD_TRANSACTION_RUN = "Transaction.Run"; | ||
| public static final String METHOD_TRANSACTION_RUN_QUERY = "Transaction.RunQuery"; | ||
| public static final String METHOD_TRANSACTION_ROLLBACK = "Transaction.Rollback"; | ||
| public static final String METHOD_TRANSACTION_RUN_AGGREGATION_QUERY = | ||
| "Transaction.RunAggregationQuery"; | ||
| public static final String METHOD_ADD = "add"; | ||
| public static final String METHOD_PUT = "put"; | ||
| public static final String METHOD_UPDATE = "update"; | ||
| public static final String METHOD_DELETE = "delete"; | ||
| public static final String METHOD_SUBMIT = "submit"; | ||
|
|
||
| private TelemetryConstants() {} | ||
| } | ||
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.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two questions:
OpenTemeletryMetricsRecorderdirectly?Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, oops. I didn't realize this was public. I will create a PR to remove this visibility before a new version is cut.
I was thinking there would be something like (names not set in stone):
MetricsRecorder
-> CompositeMetricsRecorder (will take any number of MetricRecorder impls)
-> OpenTelemetryMetricsRecorder (takes in otel object so this can be configured to be built-in or customer supplied)
I'm still thinking through the built-in aspect and I'll reduce visibility to allow for change in the future.