diff --git a/handwritten/spanner/google-cloud-spanner-executor/src/cloud-util.ts b/handwritten/spanner/google-cloud-spanner-executor/src/cloud-util.ts index d6e3e1d042ca..4feb267f4ca5 100644 --- a/handwritten/spanner/google-cloud-spanner-executor/src/cloud-util.ts +++ b/handwritten/spanner/google-cloud-spanner-executor/src/cloud-util.ts @@ -21,7 +21,7 @@ import {SpannerOptions} from '../../src'; import {trace} from '@opentelemetry/api'; import {NodeTracerProvider} from '@opentelemetry/sdk-trace-node'; import {OTLPTraceExporter} from '@opentelemetry/exporter-trace-otlp-grpc'; -import {Resource} from '@opentelemetry/resources'; +import {resourceFromAttributes} from '@opentelemetry/resources'; import {ATTR_SERVICE_NAME} from '@opentelemetry/semantic-conventions'; import { BatchSpanProcessor, @@ -50,7 +50,7 @@ export class CloudUtil { }); const provider = new NodeTracerProvider({ - resource: new Resource({ + resource: resourceFromAttributes({ [ATTR_SERVICE_NAME]: 'spanner-node-worker-proxy', 'gcp.project_id': WorkerProxy.PROJECT_ID, }) as any, diff --git a/handwritten/spanner/package.json b/handwritten/spanner/package.json index bdfc44a0ef09..f93f2ad47182 100644 --- a/handwritten/spanner/package.json +++ b/handwritten/spanner/package.json @@ -5,7 +5,7 @@ "license": "Apache-2.0", "author": "Google Inc.", "engines": { - "node": ">=18" + "node": ">=22" }, "repository": { "type": "git", @@ -56,7 +56,6 @@ "@babel/traverse": "7.27.7", "@google-cloud/common": "^6.0.0", "@google-cloud/monitoring": "^5.0.0", - "@google-cloud/opentelemetry-resource-util": "^2.4.0", "@google-cloud/precise-date": "^5.0.0", "@google-cloud/promisify": "^5.0.0", "@google-cloud/spanner-api": "^0.2.0", @@ -65,8 +64,9 @@ "@opentelemetry/api": "^1.9.0", "@opentelemetry/context-async-hooks": "^2.0.0", "@opentelemetry/core": "^2.0.0", - "@opentelemetry/resources": "^1.8.0", - "@opentelemetry/sdk-metrics": "^1.30.1", + "@opentelemetry/resource-detector-gcp": "^0.57.0", + "@opentelemetry/resources": "^2.11.0", + "@opentelemetry/sdk-metrics": "^2.11.0", "@opentelemetry/semantic-conventions": "^1.30.0", "@types/big.js": "^6.2.2", "@types/stack-trace": "^0.0.33", @@ -87,9 +87,9 @@ }, "devDependencies": { "@grpc/reflection": "^1.0.4", - "@opentelemetry/sdk-trace-base": "^2.0.0", + "@opentelemetry/sdk-trace-base": "^2.11.0", "@opentelemetry/sdk-trace-node": "^2.0.0", - "@opentelemetry/exporter-trace-otlp-grpc": "^0.57.0", + "@opentelemetry/exporter-trace-otlp-grpc": "^0.222.0", "@types/concat-stream": "^2.0.3", "@types/extend": "^3.0.4", "@types/is": "^0.0.25", diff --git a/handwritten/spanner/src/metrics/constants.ts b/handwritten/spanner/src/metrics/constants.ts index 959eeb3d817b..215270bc8e1a 100644 --- a/handwritten/spanner/src/metrics/constants.ts +++ b/handwritten/spanner/src/metrics/constants.ts @@ -11,10 +11,7 @@ // 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. -import { - View, - ExplicitBucketHistogramAggregation, -} from '@opentelemetry/sdk-metrics'; +import {AggregationType, ViewOptions} from '@opentelemetry/sdk-metrics'; export const SPANNER_METER_NAME = 'spanner-nodejs'; export const CLIENT_METRICS_PREFIX = 'spanner.googleapis.com/internal/client'; @@ -91,33 +88,30 @@ export const HISTOGRAM_BUCKET_BOUNDARIES = [ ]; // Defined Views for metric aggregation -export const OPERATION_LATENCY_VIEW = new View({ +const HISTOGRAM_AGGREGATION = { + type: AggregationType.EXPLICIT_BUCKET_HISTOGRAM as const, + options: {boundaries: HISTOGRAM_BUCKET_BOUNDARIES}, +}; + +export const OPERATION_LATENCY_VIEW: ViewOptions = { instrumentName: METRIC_NAME_OPERATION_LATENCIES, - aggregation: new ExplicitBucketHistogramAggregation( - HISTOGRAM_BUCKET_BOUNDARIES, - ), -}); + aggregation: HISTOGRAM_AGGREGATION, +}; -export const ATTEMPT_LATENCY_VIEW = new View({ +export const ATTEMPT_LATENCY_VIEW: ViewOptions = { instrumentName: METRIC_NAME_ATTEMPT_LATENCIES, - aggregation: new ExplicitBucketHistogramAggregation( - HISTOGRAM_BUCKET_BOUNDARIES, - ), -}); + aggregation: HISTOGRAM_AGGREGATION, +}; -export const GFE_LATENCY_VIEW = new View({ +export const GFE_LATENCY_VIEW: ViewOptions = { instrumentName: METRIC_NAME_GFE_LATENCIES, - aggregation: new ExplicitBucketHistogramAggregation( - HISTOGRAM_BUCKET_BOUNDARIES, - ), -}); + aggregation: HISTOGRAM_AGGREGATION, +}; -export const AFE_LATENCY_VIEW = new View({ +export const AFE_LATENCY_VIEW: ViewOptions = { instrumentName: METRIC_NAME_AFE_LATENCIES, - aggregation: new ExplicitBucketHistogramAggregation( - HISTOGRAM_BUCKET_BOUNDARIES, - ), -}); + aggregation: HISTOGRAM_AGGREGATION, +}; export const METRIC_VIEWS = [ OPERATION_LATENCY_VIEW, diff --git a/handwritten/spanner/src/metrics/external-types.ts b/handwritten/spanner/src/metrics/external-types.ts index 07c08f9b08ba..ac8f994cea79 100644 --- a/handwritten/spanner/src/metrics/external-types.ts +++ b/handwritten/spanner/src/metrics/external-types.ts @@ -35,3 +35,16 @@ export enum ValueType { DOUBLE = 'DOUBLE', DISTRIBUTION = 'DISTRIBUTION', } + +/** + * A Google Cloud Monitoring monitored resource. + * + * Previously imported from `@google-cloud/opentelemetry-resource-util`, which is + * deprecated and scheduled for archival. The interface is a plain data shape, so + * it is declared locally instead. + * See https://cloud.google.com/monitoring/api/ref_v3/rest/v3/MonitoredResource + */ +export interface MonitoredResource { + type: string; + labels: {[key: string]: string}; +} diff --git a/handwritten/spanner/src/metrics/metrics-tracer-factory.ts b/handwritten/spanner/src/metrics/metrics-tracer-factory.ts index d4de5f4c234b..3fac91ed4351 100644 --- a/handwritten/spanner/src/metrics/metrics-tracer-factory.ts +++ b/handwritten/spanner/src/metrics/metrics-tracer-factory.ts @@ -17,8 +17,11 @@ import * as os from 'os'; import * as process from 'process'; import {MeterProvider, MetricReader} from '@opentelemetry/sdk-metrics'; import {Counter, Histogram, context, ROOT_CONTEXT} from '@opentelemetry/api'; -import {detectResources, Resource} from '@opentelemetry/resources'; -import {GcpDetectorSync} from '@google-cloud/opentelemetry-resource-util'; +import { + detectResources, + resourceFromAttributes, +} from '@opentelemetry/resources'; +import {gcpDetector} from '@opentelemetry/resource-detector-gcp'; import * as Constants from './constants'; import {MetricsTracer} from './metrics-tracer'; const version = require('../../../package.json').version; @@ -122,7 +125,7 @@ export class MetricsTracerFactory { */ public getMeterProvider(readers: MetricReader[] = []): MeterProvider { if (this._meterProvider === null) { - const resource = new Resource({ + const resource = resourceFromAttributes({ [Constants.MONITORED_RES_LABEL_KEY_PROJECT]: this._projectId, [Constants.MONITORED_RES_LABEL_KEY_CLIENT_HASH]: this._clientHash, [Constants.MONITORED_RES_LABEL_KEY_LOCATION]: this._location, @@ -454,14 +457,14 @@ export class MetricsTracerFactory { /** * Gets the location (region) of the client, otherwise returns to the "global" region. - * Uses GcpDetectorSync to detect the region from the environment. + * Uses the GCP resource detector to detect the region from the environment. * @returns The detected region string, or "global" if not found. */ private static async _detectClientLocation(): Promise { const defaultRegion = 'global'; try { const resource = await detectResources({ - detectors: [new GcpDetectorSync()], + detectors: [gcpDetector], }); await resource?.waitForAsyncAttributes?.(); diff --git a/handwritten/spanner/src/metrics/transform.ts b/handwritten/spanner/src/metrics/transform.ts index 71a0052c1eee..b1620a95ab60 100644 --- a/handwritten/spanner/src/metrics/transform.ts +++ b/handwritten/spanner/src/metrics/transform.ts @@ -21,9 +21,8 @@ import { ResourceMetrics, } from '@opentelemetry/sdk-metrics'; import {Resource} from '@opentelemetry/resources'; -import {MonitoredResource} from '@google-cloud/opentelemetry-resource-util'; import * as path from 'path'; -import {MetricKind, ValueType} from './external-types'; +import {MetricKind, MonitoredResource, ValueType} from './external-types'; import { SPANNER_METER_NAME, CLIENT_METRICS_PREFIX, diff --git a/handwritten/spanner/test/metrics/metrics-tracer-factory.ts b/handwritten/spanner/test/metrics/metrics-tracer-factory.ts index 78dc1d27a132..241d14706b61 100644 --- a/handwritten/spanner/test/metrics/metrics-tracer-factory.ts +++ b/handwritten/spanner/test/metrics/metrics-tracer-factory.ts @@ -79,13 +79,11 @@ describe('MetricsTracerFactory', () => { MetricsTracerFactory.enabled = true; sandbox.resetHistory(); await MetricsTracerFactory.resetInstance(); - const provider = - MetricsTracerFactory.getInstance('project-id')!.getMeterProvider(); const reader = new PeriodicExportingMetricReader({ exporter: mockExporter, exportIntervalMillis: 60000, }); - provider.addMetricReader(reader); + MetricsTracerFactory.getInstance('project-id')!.getMeterProvider([reader]); }); afterEach(async () => { diff --git a/handwritten/spanner/test/metrics/spanner-metrics-exporter.ts b/handwritten/spanner/test/metrics/spanner-metrics-exporter.ts index cd1bb1787052..5c7d6e009021 100644 --- a/handwritten/spanner/test/metrics/spanner-metrics-exporter.ts +++ b/handwritten/spanner/test/metrics/spanner-metrics-exporter.ts @@ -31,7 +31,7 @@ import { } from '../../src/metrics/constants'; import {Counter, Meter, Histogram} from '@opentelemetry/api'; import {ExportResult, ExportResultCode} from '@opentelemetry/core'; -import {Resource} from '@opentelemetry/resources'; +import {resourceFromAttributes} from '@opentelemetry/resources'; const PROJECT_ID = 'test-project'; const INSTANCE_ID = 'test-instance'; @@ -95,7 +95,7 @@ describe('Export', () => { beforeEach(() => { exporter = new CloudMonitoringMetricsExporter({auth}, PROJECT_ID); reader = new InMemoryMetricReader(); - const resource = new Resource({ + const resource = resourceFromAttributes({ ['project_id']: PROJECT_ID, ['client_hash']: CLIENT_HASH, ['location']: LOCATION, diff --git a/handwritten/spanner/test/metrics/transform.ts b/handwritten/spanner/test/metrics/transform.ts index c9cadd05044a..03c7f006f13e 100644 --- a/handwritten/spanner/test/metrics/transform.ts +++ b/handwritten/spanner/test/metrics/transform.ts @@ -28,7 +28,7 @@ import { MeterProvider, MetricReader, } from '@opentelemetry/sdk-metrics'; -import {Resource} from '@opentelemetry/resources'; +import {Resource, resourceFromAttributes} from '@opentelemetry/resources'; import { Attributes, Counter, @@ -84,7 +84,7 @@ describe('transform', () => { sandbox.stub(MetricsTracerFactory, 'getInstance').returns(mockFactory); reader = new InMemoryMetricReader(); - resource = new Resource({ + resource = resourceFromAttributes({ ['project_id']: 'project_id', ['client_hash']: 'test_hash', ['location']: 'test_location',