chore: Implement Default Client Side Metrics Otel #12718
chore: Implement Default Client Side Metrics Otel #12718
Conversation
Update DatastoreAdminStubSettings and DatastoreStubSettings to include the library version via Version.VERSION. Add the two new Version.java files that hold the library version constant. Update native image reflect-config.json for both the admin and core stub packages.
…gRPC transport coverage Replace the old MetricsRecorder / OpenTelemetryMetricsRecorder / NoOpMetricsRecorder types with the new DatastoreMetricsRecorder family, which extends GAX's MetricsRecorder interface for a unified recording contract. Key changes: - Delete MetricsRecorder.java, OpenTelemetryMetricsRecorder.java, NoOpMetricsRecorder.java and their tests - Add DatastoreMetricsRecorder interface (with simple getInstance() that returns an OTel recorder when metrics are enabled, NoOp otherwise) - Add NoOpDatastoreMetricsRecorder, OpenTelemetryDatastoreMetricsRecorder, and DatastoreMetricsRecorderTest - Remove the !GRPC transport guard from TelemetryUtils.recordOperationMetrics() and attemptMetricsCallable() so all transports record metrics uniformly - Remove the isHttpTransport field from RetryAndTraceDatastoreRpcDecorator and DatastoreImpl; remove buildMetricsTracerFactory() from GrpcDatastoreRpc - Update TelemetryConstants with the new METRIC_PREFIX, DATASTORE_METER_NAME, and typed AttributeKey constants needed by the new recorder classes - Update DatastoreOptions to pass the full DatastoreOptions to getInstance() so the recorder factory can inspect credentials and project at creation time
…atastore-csm-impl-1
Add a default-on, private OpenTelemetry SDK pipeline that automatically exports Datastore client-side metrics to Google Cloud Monitoring without requiring any user configuration. Key additions: - DatastoreBuiltInMetricsView: registers OTel views for metric renaming (GAX prefix → custom.googleapis.com/internal/client), custom histogram bucket boundaries, and an attribute allowlist that prevents unexpected labels from reaching Cloud Monitoring - DatastoreCloudMonitoringExporter: MetricExporter impl that batches TimeSeries and calls MetricServiceClient.createTimeSeries(); graceful degradation (logs warnings, never crashes); best-effort flush() - DatastoreCloudMonitoringExporterUtils: converts OTel MetricData to Cloud Monitoring TimeSeries protos - BuiltInDatastoreMetricsProvider: creates a private OpenTelemetrySdk per Datastore client; computes stable client_uid and client_name attributes; registers a shutdown hook as a last-resort safety net - CompositeDatastoreMetricsRecorder: fans out all record*() calls to both the built-in and any user-provided backends simultaneously - DatastoreMetricsRecorder.getInstance(): updated to composite factory that wires up the built-in path (unless emulator or env-var disabled) alongside any custom OTel backend; adds default close() for lifecycle - OpenTelemetryDatastoreMetricsRecorder: add ownsOpenTelemetry flag and close() so the built-in SDK is flushed when DatastoreImpl.close() runs - DatastoreOpenTelemetryOptions: add exportBuiltinMetricsToGoogleCloudMonitoring flag (default true) with @BetaApi getter and setter; clarify isEnabled() Javadoc to note it does not cover the built-in path - DatastoreImpl.close(): call getMetricsRecorder().close() after RPC channel teardown so the built-in SDK flushes buffered metrics - pom.xml: promote opentelemetry-sdk, opentelemetry-sdk-common, and opentelemetry-sdk-metrics from test→compile scope; add google-cloud-monitoring and proto-google-cloud-monitoring-v3 compile deps - New tests: DatastoreCloudMonitoringExporterTest, BuiltInDatastoreMetricsProviderTest, DatastoreMetricsRecorderTest (updated), DatastoreBuiltInAndCustomMetricsIT
…ne after impl-1 refactor
There was a problem hiding this comment.
Code Review
This pull request introduces built-in metrics support for the Datastore SDK, allowing client-side metrics to be exported to Google Cloud Monitoring. It adds a new BuiltInDatastoreMetricsProvider, a DatastoreCloudMonitoringExporter, and updates DatastoreOpenTelemetryOptions to manage this feature. My review identified several critical issues: creating a new MetricServiceClient per client instance is inefficient, registering individual shutdown hooks for each client causes a memory leak, the Javadoc for the default metrics export state is contradictory, and the CompositeDatastoreMetricsRecorder.close() method lacks proper exception handling and LIFO ordering for resource cleanup.
…loud-java into datastore-csm-impl-2
1ab752f to
7418242
Compare
| /** Shuts down the exporter and the underlying {@link MetricServiceClient}. */ | ||
| @Override | ||
| public CompletableResultCode shutdown() { | ||
| if (client.isShutdown()) { |
There was a problem hiding this comment.
Would this be an issue since client is shared among multiple Datastore clients? E.g. there are 2 Datastore clients, and one of them calls shutdown twice. client.isShutdown() would be false both times.
If so, would it make sense to use something like this?
private final AtomicBoolean isShutDown = new AtomicBoolean(false);
| * @param resource the OTel resource. | ||
| * @return the project ID string, or null if not present. | ||
| */ | ||
| static String getProjectId(Resource resource) { |
No description provided.