Skip to content

Commit

Permalink
feat: Enable e2e tracing (#2202)
Browse files Browse the repository at this point in the history
* e2eTracing

* context propagation

* 🦉 Updates from OwlBot post-processor

See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md

* 🦉 Updates from OwlBot post-processor

See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md

* Add end to end tracing header and refactore resource header

* Add end to end tracing header and refactore resource header

---------

Co-authored-by: Owl Bot <gcf-owl-bot[bot]@users.noreply.github.com>
  • Loading branch information
surbhigarg92 and gcf-owl-bot[bot] authored Dec 24, 2024
1 parent 92248c1 commit 3cc257e
Show file tree
Hide file tree
Showing 16 changed files with 260 additions and 126 deletions.
22 changes: 21 additions & 1 deletion OBSERVABILITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,27 @@ const spanner = new Spanner({
observabilityOptions: {
tracerProvider: provider,
enableExtendedTracing: true,
},
}
}),
```

#### End to end tracing

In addition to client-side tracing, you can opt in for end-to-end tracing. End-to-end tracing helps you understand and debug latency issues that are specific to Spanner. Refer [here](https://cloud.google.com/spanner/docs/tracing-overview) for more information.

You can opt-in by either:

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

```javascript
const spanner = new Spanner({
projectId: projectId,
observabilityOptions: {
tracerProvider: provider,
enableEndToEndTracing: true,
}
}),
```

#### OpenTelemetry gRPC instrumentation
Expand Down
57 changes: 57 additions & 0 deletions observability-test/spanner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import * as mockInstanceAdmin from '../test/mockserver/mockinstanceadmin';
import * as mockDatabaseAdmin from '../test/mockserver/mockdatabaseadmin';
import * as sinon from 'sinon';
import {Row} from '../src/partial-result-stream';
import {END_TO_END_TRACING_HEADER} from '../src/common';
const {
AlwaysOnSampler,
NodeTracerProvider,
Expand Down Expand Up @@ -1930,3 +1931,59 @@ describe('Traces for ExecuteStream broken stream retries', () => {
);
});
});

describe('End to end tracing headers', () => {
let server: grpc.Server;
let spanner: Spanner;
let spannerMock: mock.MockSpanner;
let observabilityOptions: typeof ObservabilityOptions;

beforeEach(async () => {
observabilityOptions = {
enableEndToEndTracing: true,
};

const setupResult = await setup(observabilityOptions);
spanner = setupResult.spanner;
server = setupResult.server;
spannerMock = setupResult.spannerMock;
});

afterEach(async () => {
spannerMock.resetRequests();
spanner.close();
server.tryShutdown(() => {});
});

it('run', done => {
const instance = spanner.instance('instance');
const database = instance.database('database');
database.getTransaction((err, tx) => {
assert.ifError(err);

tx!.run('SELECT 1', async () => {
tx!.end();
let metadataCountWithE2EHeader = 0;
let metadataCountWithTraceParent = 0;
spannerMock.getMetadata().forEach(metadata => {
if (metadata.get(END_TO_END_TRACING_HEADER)[0] !== undefined) {
metadataCountWithE2EHeader++;
assert.strictEqual(
metadata.get(END_TO_END_TRACING_HEADER)[0],
'true'
);
}
if (metadata.get('traceparent')[0] !== undefined) {
metadataCountWithTraceParent++;
}
});

// Batch Create Session request and Select 1 request.
assert.strictEqual(spannerMock.getRequests().length, 2);
assert.strictEqual(metadataCountWithE2EHeader, 2);
assert.strictEqual(metadataCountWithTraceParent, 2);
done();
});
});
});
});
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
"@google-cloud/promisify": "^4.0.0",
"@grpc/proto-loader": "^0.7.0",
"@opentelemetry/api": "^1.9.0",
"@opentelemetry/core": "^1.27.0",
"@opentelemetry/context-async-hooks": "^1.26.0",
"@opentelemetry/semantic-conventions": "^1.25.1",
"@types/big.js": "^6.0.0",
Expand Down
1 change: 1 addition & 0 deletions samples/observability-traces.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ async function main(
observabilityOptions: {
tracerProvider: provider,
enableExtendedTracing: true,
enableEndToEndTracing: true,
},
});

Expand Down
27 changes: 27 additions & 0 deletions src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,37 @@ export const CLOUD_RESOURCE_HEADER = 'google-cloud-resource-prefix';
*/
export const LEADER_AWARE_ROUTING_HEADER = 'x-goog-spanner-route-to-leader';

/*
* END TO END TRACING header.
*/
export const END_TO_END_TRACING_HEADER = 'x-goog-spanner-end-to-end-tracing';

/**
* Add Leader aware routing header to existing header list.
* @param headers Existing header list.
*/
export function addLeaderAwareRoutingHeader(headers: {[k: string]: string}) {
headers[LEADER_AWARE_ROUTING_HEADER] = 'true';
}

/**
* Returns common headers to add.
* @param headers Common header list.
*/
export function getCommonHeaders(
resourceName: string,
enableTracing?: boolean
) {
const headers: {[k: string]: string} = {};

if (
process.env.SPANNER_ENABLE_END_TO_END_TRACING === 'true' ||
enableTracing
) {
headers[END_TO_END_TRACING_HEADER] = 'true';
}

headers[CLOUD_RESOURCE_HEADER] = resourceName;

return headers;
}
39 changes: 21 additions & 18 deletions src/database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ import {
ResourceCallback,
Schema,
addLeaderAwareRoutingHeader,
getCommonHeaders,
} from './common';
import {finished, Duplex, Readable, Transform} from 'stream';
import {PreciseDate} from '@google-cloud/precise-date';
Expand Down Expand Up @@ -340,7 +341,7 @@ class Database extends common.GrpcServiceObject {
formattedName_: string;
pool_: SessionPoolInterface;
queryOptions_?: spannerClient.spanner.v1.ExecuteSqlRequest.IQueryOptions;
resourceHeader_: {[k: string]: string};
commonHeaders_: {[k: string]: string};
request: DatabaseRequest;
databaseRole?: string | null;
labels?: {[k: string]: string} | null;
Expand Down Expand Up @@ -471,11 +472,13 @@ class Database extends common.GrpcServiceObject {
dbName: this.formattedName_,
};

this.resourceHeader_ = {
[CLOUD_RESOURCE_HEADER]: this.formattedName_,
};
this.request = instance.request;
this._observabilityOptions = instance._observabilityOptions;
this.commonHeaders_ = getCommonHeaders(
this.formattedName_,
this._observabilityOptions?.enableEndToEndTracing
);

// eslint-disable-next-line @typescript-eslint/no-explicit-any
this.requestStream = instance.requestStream as any;
this.pool_.on('error', this.emit.bind(this, 'error'));
Expand Down Expand Up @@ -582,7 +585,7 @@ class Database extends common.GrpcServiceObject {
method: 'updateDatabase',
reqOpts,
gaxOpts,
headers: this.resourceHeader_,
headers: this.commonHeaders_,
},
callback!
);
Expand Down Expand Up @@ -688,7 +691,7 @@ class Database extends common.GrpcServiceObject {
sessionCount: count,
};

const headers = this.resourceHeader_;
const headers = this.commonHeaders_;
if (this._getSpanner().routeToLeaderEnabled) {
addLeaderAwareRoutingHeader(headers);
}
Expand Down Expand Up @@ -989,7 +992,7 @@ class Database extends common.GrpcServiceObject {
reqOpts.session.creatorRole =
options.databaseRole || this.databaseRole || null;

const headers = this.resourceHeader_;
const headers = this.commonHeaders_;
if (this._getSpanner().routeToLeaderEnabled) {
addLeaderAwareRoutingHeader(headers);
}
Expand Down Expand Up @@ -1215,7 +1218,7 @@ class Database extends common.GrpcServiceObject {
method: 'dropDatabase',
reqOpts,
gaxOpts,
headers: this.resourceHeader_,
headers: this.commonHeaders_,
},
callback!
);
Expand Down Expand Up @@ -1447,7 +1450,7 @@ class Database extends common.GrpcServiceObject {
method: 'getDatabase',
reqOpts,
gaxOpts,
headers: this.resourceHeader_,
headers: this.commonHeaders_,
},
(err, resp) => {
if (resp) {
Expand Down Expand Up @@ -1701,7 +1704,7 @@ class Database extends common.GrpcServiceObject {
method: 'getDatabaseDdl',
reqOpts,
gaxOpts,
headers: this.resourceHeader_,
headers: this.commonHeaders_,
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(err, statements, ...args: any[]) => {
Expand Down Expand Up @@ -1781,7 +1784,7 @@ class Database extends common.GrpcServiceObject {
method: 'getIamPolicy',
reqOpts,
gaxOpts: options.gaxOptions,
headers: this.resourceHeader_,
headers: this.commonHeaders_,
},
(err, resp) => {
callback!(err, resp);
Expand Down Expand Up @@ -1920,7 +1923,7 @@ class Database extends common.GrpcServiceObject {
method: 'listSessions',
reqOpts,
gaxOpts,
headers: this.resourceHeader_,
headers: this.commonHeaders_,
},
(err, sessions, nextPageRequest, ...args) => {
if (err) {
Expand Down Expand Up @@ -2013,7 +2016,7 @@ class Database extends common.GrpcServiceObject {
method: 'listSessionsStream',
reqOpts,
gaxOpts,
headers: this.resourceHeader_,
headers: this.commonHeaders_,
});
}

Expand Down Expand Up @@ -2405,7 +2408,7 @@ class Database extends common.GrpcServiceObject {
method: 'listDatabaseRoles',
reqOpts,
gaxOpts,
headers: this.resourceHeader_,
headers: this.commonHeaders_,
},
(err, roles, nextPageRequest, ...args) => {
const nextQuery = nextPageRequest!
Expand Down Expand Up @@ -2615,7 +2618,7 @@ class Database extends common.GrpcServiceObject {
method: 'restoreDatabase',
reqOpts,
gaxOpts,
headers: this.resourceHeader_,
headers: this.commonHeaders_,
},
(err, operation, resp) => {
if (err) {
Expand Down Expand Up @@ -3514,7 +3517,7 @@ class Database extends common.GrpcServiceObject {
method: 'batchWrite',
reqOpts,
gaxOpts,
headers: this.resourceHeader_,
headers: this.commonHeaders_,
});
dataStream
.once('data', () => (dataReceived = true))
Expand Down Expand Up @@ -3796,7 +3799,7 @@ class Database extends common.GrpcServiceObject {
method: 'setIamPolicy',
reqOpts,
gaxOpts: gaxOpts,
headers: this.resourceHeader_,
headers: this.commonHeaders_,
},
(err, resp) => {
callback!(err, resp);
Expand Down Expand Up @@ -3926,7 +3929,7 @@ class Database extends common.GrpcServiceObject {
method: 'updateDatabaseDdl',
reqOpts,
gaxOpts,
headers: this.resourceHeader_,
headers: this.commonHeaders_,
},
callback!
);
Expand Down
Loading

0 comments on commit 3cc257e

Please sign in to comment.