Skip to content

Commit

Permalink
Merge branch 'googleapis:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
surbhigarg92 authored Oct 30, 2024
2 parents 4b2f196 + f08cf4b commit 207b382
Show file tree
Hide file tree
Showing 20 changed files with 539 additions and 675 deletions.
24 changes: 24 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,30 @@

[1]: https://www.npmjs.com/package/nodejs-spanner?activeTab=versions

## [7.15.0](https://github.com/googleapis/nodejs-spanner/compare/v7.14.0...v7.15.0) (2024-10-30)


### Features

* (observability, samples): add tracing end-to-end sample ([#2130](https://github.com/googleapis/nodejs-spanner/issues/2130)) ([66d99e8](https://github.com/googleapis/nodejs-spanner/commit/66d99e836cd2bfbb3b0f78980ec2b499f9e5e563))
* (observability) add spans for BatchTransaction and Table ([#2115](https://github.com/googleapis/nodejs-spanner/issues/2115)) ([d51aae9](https://github.com/googleapis/nodejs-spanner/commit/d51aae9c9c3c0e6319d81c2809573ae54675acf3)), closes [#2114](https://github.com/googleapis/nodejs-spanner/issues/2114)
* (observability) Add support for OpenTelemetry traces and allow observability options to be passed. ([#2131](https://github.com/googleapis/nodejs-spanner/issues/2131)) ([5237e11](https://github.com/googleapis/nodejs-spanner/commit/5237e118befb4b7fe4aea76a80a91e822d7a22e4)), closes [#2079](https://github.com/googleapis/nodejs-spanner/issues/2079)
* (observability) propagate database name for every span generated to aid in quick debugging ([#2155](https://github.com/googleapis/nodejs-spanner/issues/2155)) ([0342e74](https://github.com/googleapis/nodejs-spanner/commit/0342e74721a0684d8195a6299c3a634eefc2b522))
* (observability) trace Database.batchCreateSessions + SessionPool.createSessions ([#2145](https://github.com/googleapis/nodejs-spanner/issues/2145)) ([f489c94](https://github.com/googleapis/nodejs-spanner/commit/f489c9479fa5402f0c960cf896fd3be0e946f182))
* (observability): trace Database.runPartitionedUpdate ([#2176](https://github.com/googleapis/nodejs-spanner/issues/2176)) ([701e226](https://github.com/googleapis/nodejs-spanner/commit/701e22660d5ac9f0b3e940ad656b9ca6c479251d)), closes [#2079](https://github.com/googleapis/nodejs-spanner/issues/2079)
* (observability): trace Database.runTransactionAsync ([#2167](https://github.com/googleapis/nodejs-spanner/issues/2167)) ([d0fe178](https://github.com/googleapis/nodejs-spanner/commit/d0fe178623c1c48245d11bcea97fcd340b6615af)), closes [#207](https://github.com/googleapis/nodejs-spanner/issues/207)
* Allow multiple KMS keys to create CMEK database/backup ([#2099](https://github.com/googleapis/nodejs-spanner/issues/2099)) ([51bc8a7](https://github.com/googleapis/nodejs-spanner/commit/51bc8a7445ab8b3d2239493b69d9c271c1086dde))
* **observability:** Fix bugs found from product review + negative cases ([#2158](https://github.com/googleapis/nodejs-spanner/issues/2158)) ([cbc86fa](https://github.com/googleapis/nodejs-spanner/commit/cbc86fa80498af6bd745eebb9443612936e26d4e))
* **observability:** Trace Database methods ([#2119](https://github.com/googleapis/nodejs-spanner/issues/2119)) ([1f06871](https://github.com/googleapis/nodejs-spanner/commit/1f06871f7aca386756e8691013602b069697bb87)), closes [#2114](https://github.com/googleapis/nodejs-spanner/issues/2114)
* **observability:** Trace Database.batchWriteAtLeastOnce ([#2157](https://github.com/googleapis/nodejs-spanner/issues/2157)) ([2a19ef1](https://github.com/googleapis/nodejs-spanner/commit/2a19ef1af4f6fd1b81d08afc15db76007859a0b9)), closes [#2079](https://github.com/googleapis/nodejs-spanner/issues/2079)
* **observability:** Trace Transaction ([#2122](https://github.com/googleapis/nodejs-spanner/issues/2122)) ([a464bdb](https://github.com/googleapis/nodejs-spanner/commit/a464bdb5cbb7856b7a08dac3ff48132948b65792)), closes [#2114](https://github.com/googleapis/nodejs-spanner/issues/2114)


### Bug Fixes

* Exact staleness timebound ([#2143](https://github.com/googleapis/nodejs-spanner/issues/2143)) ([f01516e](https://github.com/googleapis/nodejs-spanner/commit/f01516ec6ba44730622cfb050c52cd93f30bba7a)), closes [#2129](https://github.com/googleapis/nodejs-spanner/issues/2129)
* GetMetadata for Session ([#2124](https://github.com/googleapis/nodejs-spanner/issues/2124)) ([2fd63ac](https://github.com/googleapis/nodejs-spanner/commit/2fd63acb87ce06a02d7fdfa78d836dbd7ad59a26)), closes [#2123](https://github.com/googleapis/nodejs-spanner/issues/2123)

## [7.14.0](https://github.com/googleapis/nodejs-spanner/compare/v7.13.0...v7.14.0) (2024-08-14)


Expand Down
102 changes: 102 additions & 0 deletions OBSERVABILITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
## Observability with OpenTelemetry

This Cloud Spanner client supports [OpenTelemetry Traces](https://opentelemetry.io/), which gives insight into the client internals and aids in debugging/troubleshooting production issues.

By default, the functionality is disabled. You shall need to add OpenTelemetry dependencies, and must configure and
enable OpenTelemetry with appropriate exporters at the startup of your application:

**Table of contents:**

* [Observability](#observability)
* [Tracing](#tracing)
* [OpenTelemetry Dependencies](#opentelemetry-dependencies)
* [OpenTelemetry Configuration](#opentelemetry-configuration)
* [SQL Statement span annotation](#sql-statement-span-annotation)
* [OpenTelemetry gRCP instrumentation](#opentelemetry-grpc-instrumentation)
* [Tracing Sample](#tracing-sample)

### Tracing

#### OpenTelemetry Dependencies

Add the following dependencies in your `package.json` or install them directly.
```javascript
// Required packages for OpenTelemetry SDKs
"@opentelemetry/sdk-trace-base": "^1.26.0",
"@opentelemetry/sdk-trace-node": "^1.26.0",

// Package to use Google Cloud Trace exporter
"@google-cloud/opentelemetry-cloud-trace-exporter": "^2.4.1",

// Packages to enable gRPC instrumentation
"@opentelemetry/instrumentation": "^0.53.0",
"@opentelemetry/instrumentation-grpc": "^0.53.0",
```

#### OpenTelemetry Configuration

```javascript
const {
NodeTracerProvider,
TraceIdRatioBasedSampler,
} = require('@opentelemetry/sdk-trace-node');
const {
BatchSpanProcessor,
} = require('@opentelemetry/sdk-trace-base');
const {
TraceExporter,
} = require('@google-cloud/opentelemetry-cloud-trace-exporter');
const exporter = new TraceExporter();

// Create the tracerProvider that the exporter shall be attached to.
const provider = new NodeTracerProvider({resource: resource});
provider.addSpanProcessor(new BatchSpanProcessor(exporter));

// Create the Cloud Spanner Client.
const {Spanner} = require('@google-cloud/spanner');
const spanner = new Spanner({
projectId: projectId,
observabilityOptions: {
// Inject the TracerProvider via SpannerOptions or
// register it as a global by invoking `provider.register()`
tracerProvider: provider,
},
});
```

#### SQL Statement span annotation

To allow your SQL statements to be annotated in the appropriate spans, you need to opt-in, because
SQL statements can contain sensitive personally-identifiable-information (PII).

You can opt-in by either:

* Setting the environment variable `SPANNER_ENABLE_EXTENDED_TRACING=true` before your application is started
* In code, setting `enableExtendedTracing: true` in your SpannerOptions before creating the Cloud Spanner client

```javascript
const spanner = new Spanner({
projectId: projectId,
observabilityOptions: {
tracerProvider: provider,
enableExtendedTracing: true,
},
```
#### OpenTelemetry gRPC instrumentation
Optionally, you can enable OpenTelemetry gRPC instrumentation which produces traces of executed remote procedure calls (RPCs)
in your programs by these imports and instantiation. You could pass in the traceProvider or register it globally
by invoking `tracerProvider.register()`
```javascript
const {registerInstrumentations} = require('@opentelemetry/instrumentation');
const {GrpcInstrumentation} = require('@opentelemetry/instrumentation-grpc');
registerInstrumentations({
tracerProvider: tracerProvider,
instrumentations: [new GrpcInstrumentation()],
});
```
#### Tracing Sample
For more information please see this [sample code](./samples/observability-traces.js)
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ Samples are in the [`samples/`](https://github.com/googleapis/nodejs-spanner/tre
| Numeric-add-column | [source code](https://github.com/googleapis/nodejs-spanner/blob/main/samples/numeric-add-column.js) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/nodejs-spanner&page=editor&open_in_editor=samples/numeric-add-column.js,samples/README.md) |
| Numeric-query-parameter | [source code](https://github.com/googleapis/nodejs-spanner/blob/main/samples/numeric-query-parameter.js) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/nodejs-spanner&page=editor&open_in_editor=samples/numeric-query-parameter.js,samples/README.md) |
| Numeric-update-data | [source code](https://github.com/googleapis/nodejs-spanner/blob/main/samples/numeric-update-data.js) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/nodejs-spanner&page=editor&open_in_editor=samples/numeric-update-data.js,samples/README.md) |
| Observability (Tracing) with OpenTelemetry | [source code](https://github.com/googleapis/nodejs-spanner/blob/main/samples/observability-traces.js) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/nodejs-spanner&page=editor&open_in_editor=samples/observability-traces.js,samples/README.md) |
| Adds a column to an existing table in a Spanner PostgreSQL database. | [source code](https://github.com/googleapis/nodejs-spanner/blob/main/samples/pg-add-column.js) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/nodejs-spanner&page=editor&open_in_editor=samples/pg-add-column.js,samples/README.md) |
| Showcase the rules for case-sensitivity and case folding for a Spanner PostgreSQL database. | [source code](https://github.com/googleapis/nodejs-spanner/blob/main/samples/pg-case-sensitivity.js) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/nodejs-spanner&page=editor&open_in_editor=samples/pg-case-sensitivity.js,samples/README.md) |
| Creates a PostgreSQL Database. | [source code](https://github.com/googleapis/nodejs-spanner/blob/main/samples/pg-database-create.js) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/nodejs-spanner&page=editor&open_in_editor=samples/pg-database-create.js,samples/README.md) |
Expand Down
174 changes: 83 additions & 91 deletions observability-test/batch-transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,103 +153,95 @@ describe('BatchTransaction', () => {
};

it('createQueryPartitions', done => {
const REQUEST = sandbox.stub();

const res = batchTransaction.createQueryPartitions(
QUERY,
(err, part, resp) => {
assert.ifError(err);
traceExporter.forceFlush();
const spans = traceExporter.getFinishedSpans();
assert.strictEqual(spans.length, 2, 'Exactly 2 spans expected');

// Sort the spans by duration.
spans.sort((spanA, spanB) => {
spanA.duration < spanB.duration;
});

const actualSpanNames: string[] = [];
spans.forEach(span => {
actualSpanNames.push(span.name);
});

const expectedSpanNames = [
'CloudSpanner.BatchTransaction.createPartitions_',
'CloudSpanner.BatchTransaction.createQueryPartitions',
];
assert.deepStrictEqual(
actualSpanNames,
expectedSpanNames,
`span names mismatch:\n\tGot: ${actualSpanNames}\n\tWant: ${expectedSpanNames}`
);

// Ensure that createPartitions_ is a child span of createQueryPartitions.
const spanCreatePartitions_ = spans[0];
const spanCreateQueryPartitions = spans[1];
assert.ok(
spanCreateQueryPartitions.spanContext().traceId,
'Expected that createQueryPartitions has a defined traceId'
);
assert.ok(
spanCreatePartitions_.spanContext().traceId,
'Expected that createPartitions_ has a defined traceId'
);
assert.deepStrictEqual(
spanCreatePartitions_.spanContext().traceId,
spanCreateQueryPartitions.spanContext().traceId,
'Expected that both spans share a traceId'
);
assert.ok(
spanCreateQueryPartitions.spanContext().spanId,
'Expected that createQueryPartitions has a defined spanId'
);
assert.ok(
spanCreatePartitions_.spanContext().spanId,
'Expected that createPartitions_ has a defined spanId'
);
assert.deepStrictEqual(
spanCreatePartitions_.parentSpanId,
spanCreateQueryPartitions.spanContext().spanId,
'Expected that createQueryPartitions is the parent to createPartitions_'
);
done();
}
);
batchTransaction.createQueryPartitions(QUERY, err => {
assert.ifError(err);
traceExporter.forceFlush();
const spans = traceExporter.getFinishedSpans();
assert.strictEqual(spans.length, 2, 'Exactly 2 spans expected');

// Sort the spans by duration.
spans.sort((spanA, spanB) => {
spanA.duration < spanB.duration;
});

const actualSpanNames: string[] = [];
spans.forEach(span => {
actualSpanNames.push(span.name);
});

const expectedSpanNames = [
'CloudSpanner.BatchTransaction.createPartitions_',
'CloudSpanner.BatchTransaction.createQueryPartitions',
];
assert.deepStrictEqual(
actualSpanNames,
expectedSpanNames,
`span names mismatch:\n\tGot: ${actualSpanNames}\n\tWant: ${expectedSpanNames}`
);

// Ensure that createPartitions_ is a child span of createQueryPartitions.
const spanCreatePartitions_ = spans[0];
const spanCreateQueryPartitions = spans[1];
assert.ok(
spanCreateQueryPartitions.spanContext().traceId,
'Expected that createQueryPartitions has a defined traceId'
);
assert.ok(
spanCreatePartitions_.spanContext().traceId,
'Expected that createPartitions_ has a defined traceId'
);
assert.deepStrictEqual(
spanCreatePartitions_.spanContext().traceId,
spanCreateQueryPartitions.spanContext().traceId,
'Expected that both spans share a traceId'
);
assert.ok(
spanCreateQueryPartitions.spanContext().spanId,
'Expected that createQueryPartitions has a defined spanId'
);
assert.ok(
spanCreatePartitions_.spanContext().spanId,
'Expected that createPartitions_ has a defined spanId'
);
assert.deepStrictEqual(
spanCreatePartitions_.parentSpanId,
spanCreateQueryPartitions.spanContext().spanId,
'Expected that createQueryPartitions is the parent to createPartitions_'
);
done();
});
});

it('createReadPartitions', done => {
const REQUEST = sandbox.stub();
const response = {};
REQUEST.callsFake((_, callback) => callback(null, response));

const res = batchTransaction.createReadPartitions(
QUERY,
(err, part, resp) => {
assert.ifError(err);
traceExporter.forceFlush();
const spans = traceExporter.getFinishedSpans();
assert.strictEqual(spans.length, 2, 'Exactly 2 spans expected');

// Sort the spans by duration.
spans.sort((spanA, spanB) => {
spanA.duration < spanB.duration;
});

const actualSpanNames: string[] = [];
spans.forEach(span => {
actualSpanNames.push(span.name);
});
const expectedSpanNames = [
'CloudSpanner.BatchTransaction.createPartitions_',
'CloudSpanner.BatchTransaction.createReadPartitions',
];
assert.deepStrictEqual(
actualSpanNames,
expectedSpanNames,
`span names mismatch:\n\tGot: ${actualSpanNames}\n\tWant: ${expectedSpanNames}`
);
done();
}
);
batchTransaction.createReadPartitions(QUERY, err => {
assert.ifError(err);
traceExporter.forceFlush();
const spans = traceExporter.getFinishedSpans();
assert.strictEqual(spans.length, 2, 'Exactly 2 spans expected');

// Sort the spans by duration.
spans.sort((spanA, spanB) => {
spanA.duration < spanB.duration;
});

const actualSpanNames: string[] = [];
spans.forEach(span => {
actualSpanNames.push(span.name);
});
const expectedSpanNames = [
'CloudSpanner.BatchTransaction.createPartitions_',
'CloudSpanner.BatchTransaction.createReadPartitions',
];
assert.deepStrictEqual(
actualSpanNames,
expectedSpanNames,
`span names mismatch:\n\tGot: ${actualSpanNames}\n\tWant: ${expectedSpanNames}`
);
done();
});
});
});
Loading

0 comments on commit 207b382

Please sign in to comment.