Skip to content

Commit fe477e8

Browse files
feat(instr-aws-sdk): support db semconv migration for dynamodb (#3312)
This adds support for using `OTEL_SEMCONV_STABILITY_OPT_IN` for controlled migration to stable `db.*` semconv. The `db.*` attributes are controlled by the `database[dup]` token. Refs: #2953
1 parent 062fb29 commit fe477e8

File tree

8 files changed

+245
-25
lines changed

8 files changed

+245
-25
lines changed

packages/instrumentation-aws-sdk/README.md

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ registerInstrumentations({
4949
aws-sdk instrumentation has few options available to choose from. You can set the following:
5050

5151
| Options | Type | Description |
52-
|-------------------------------------------|------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
52+
| ----------------------------------------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
5353
| `preRequestHook` | `AwsSdkRequestCustomAttributeFunction` | Hook called before request send, which allow to add custom attributes to span. |
5454
| `responseHook` | `AwsSdkResponseCustomAttributeFunction` | Hook for adding custom attributes when response is received from aws. |
5555
| `exceptionHook` | `AwsSdkExceptionCustomAttributeFunction` | Hook for adding custom attributes when exception is received from aws. |
@@ -62,7 +62,7 @@ aws-sdk instrumentation has few options available to choose from. You can set th
6262
The instrumentations are collecting the following attributes:
6363

6464
| Attribute Name | Type | Description | Example |
65-
|----------------|--------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------|
65+
| -------------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------- |
6666
| `rpc.system` | string | Always equals "aws-api" | |
6767
| `rpc.method` | string | The name of the operation corresponding to the request, as returned by the AWS SDK. If the SDK does not provide a way to retrieve a name, the name of the command SHOULD be used, removing the suffix `Command` if present, resulting in a PascalCase name with no spaces. | `PutObject` |
6868
| `rpc.service` | string | The name of the service to which a request is made, as returned by the AWS SDK. If the SDK does not provide a away to retrieve a name, the name of the SDK's client interface for a service SHOULD be used, removing the suffix `Client` if present, resulting in a PascalCase name with no spaces. | `S3`, `DynamoDB`, `Route53` |
@@ -111,7 +111,7 @@ This package emits telemetry using a mix of Semantic Convention versions. While
111111
Attributes collected (this list is currently not exhaustive):
112112

113113
| Attribute | Short Description | Service |
114-
|--------------------------------------------------|------------------------------------------------------------------------------------------------|----------|
114+
| ------------------------------------------------ | ---------------------------------------------------------------------------------------------- | -------- |
115115
| `http.status_code` / `http.response.status_code` | (aws-sdk) HTTP response status code. See "HTTP Semantic Convention migration" note below. | |
116116
| `rpc.method` | The name of the (logical) method being called. | |
117117
| `rpc.service` | The full (logical) name of the service being called. | |
@@ -138,10 +138,10 @@ Attributes collected (this list is currently not exhaustive):
138138
| `aws.dynamodb.table_count` | The number of items in the `TableNames` response parameter. | dynamodb |
139139
| `aws.dynamodb.table_names` | The keys in the `RequestItems` object field. | dynamodb |
140140
| `aws.dynamodb.total_segments` | The value of the `TotalSegments` request parameter. | dynamodb |
141-
| `db.name` | The name of the database being accessed. | dynamodb |
142-
| `db.operation` | The name of the operation being executed. | dynamodb |
143-
| `db.statement` | The database statement being executed. | dynamodb |
144-
| `db.system` | An identifier for the database management system (DBMS) product being used. | dynamodb |
141+
| `db.name` / `db.namespace` | The name of the database (TableName). See "Database Semantic Convention migration" note below. | dynamodb |
142+
| `db.operation` / `db.operation.name` | The name of the operation. See "Database Semantic Convention migration" note below. | dynamodb |
143+
| `db.statement` / `db.query.text` | The database statement. See "Database Semantic Convention migration" note below. | dynamodb |
144+
| `db.system` / `db.system.name` | Database system identifier. See "Database Semantic Convention migration" note below. | dynamodb |
145145
| `faas.execution` | The execution ID of the current function execution. | lambda |
146146
| `faas.invoked_name` | The name of the invoked function. | lambda |
147147
| `faas.invoked_provider` | The cloud provider of the invoked function. | lambda |
@@ -177,6 +177,30 @@ For this instrumentation, the only impacted attributes are as follows:
177177

178178
See the [HTTP semconv migration plan for OpenTelemetry JS instrumentations](https://github.com/open-telemetry/opentelemetry-js/issues/5646) for more details.
179179

180+
### Database Semantic Convention migration
181+
182+
Database semantic conventions (semconv) were stabilized in v1.33.0, and a [migration process](https://opentelemetry.io/docs/specs/semconv/non-normative/db-migration/)
183+
was defined. For DynamoDB operations, `instrumentation-aws-sdk` emits database-related
184+
attributes. The `OTEL_SEMCONV_STABILITY_OPT_IN` environment variable can be used to
185+
customize which database semantic conventions are used.
186+
187+
To select which semconv version(s) is emitted from this instrumentation, use the
188+
`OTEL_SEMCONV_STABILITY_OPT_IN` environment variable.
189+
190+
- `database`: emit the new (stable) v1.33.0+ semantics
191+
- `database/dup`: emit **both** the old v1.7.0 and the new (stable) v1.33.0+ semantics
192+
- By default, if `OTEL_SEMCONV_STABILITY_OPT_IN` includes neither of the above tokens, the old v1.7.0 semconv is used.
193+
194+
For DynamoDB instrumentation, the impacted attributes are as follows:
195+
196+
| v1.7.0 semconv | v1.33.0 semconv | Short Description |
197+
| -------------- | ------------------- | ------------------------------------------------- |
198+
| `db.system` | `db.system.name` | Database system identifier |
199+
| `db.name` | `db.namespace` | The database name (TableName for DynamoDB) |
200+
| `db.operation` | `db.operation.name` | The name of the operation being executed |
201+
| `db.statement` | `db.query.text` | The database statement (if serializer configured) |
202+
203+
See the [database migration guide](https://opentelemetry.io/docs/specs/semconv/non-normative/db-migration/) for details.
180204

181205
## Useful links
182206

packages/instrumentation-aws-sdk/src/aws-sdk.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -73,14 +73,19 @@ export class AwsInstrumentation extends InstrumentationBase<AwsSdkInstrumentatio
7373
// need declare since initialized in callbacks from super constructor
7474
declare private servicesExtensions: ServicesExtensions;
7575

76-
private _semconvStability: SemconvStability;
76+
private _httpSemconvStability: SemconvStability;
77+
private _dbSemconvStability: SemconvStability;
7778

7879
constructor(config: AwsSdkInstrumentationConfig = {}) {
7980
super(PACKAGE_NAME, PACKAGE_VERSION, config);
80-
this._semconvStability = semconvStabilityFromStr(
81+
this._httpSemconvStability = semconvStabilityFromStr(
8182
'http',
8283
process.env.OTEL_SEMCONV_STABILITY_OPT_IN
8384
);
85+
this._dbSemconvStability = semconvStabilityFromStr(
86+
'database',
87+
process.env.OTEL_SEMCONV_STABILITY_OPT_IN
88+
);
8489
}
8590

8691
protected init(): InstrumentationModuleDefinition[] {
@@ -373,7 +378,8 @@ export class AwsInstrumentation extends InstrumentationBase<AwsSdkInstrumentatio
373378
const requestMetadata = self.servicesExtensions.requestPreSpanHook(
374379
normalizedRequest,
375380
self.getConfig(),
376-
self._diag
381+
self._diag,
382+
self._dbSemconvStability
377383
);
378384
const startTime = hrTime();
379385
const span = self._startAwsV3Span(normalizedRequest, requestMetadata);
@@ -415,10 +421,10 @@ export class AwsInstrumentation extends InstrumentationBase<AwsSdkInstrumentatio
415421
const httpStatusCode =
416422
response.output?.$metadata?.httpStatusCode;
417423
if (httpStatusCode) {
418-
if (self._semconvStability & SemconvStability.OLD) {
424+
if (self._httpSemconvStability & SemconvStability.OLD) {
419425
span.setAttribute(ATTR_HTTP_STATUS_CODE, httpStatusCode);
420426
}
421-
if (self._semconvStability & SemconvStability.STABLE) {
427+
if (self._httpSemconvStability & SemconvStability.STABLE) {
422428
span.setAttribute(
423429
ATTR_HTTP_RESPONSE_STATUS_CODE,
424430
httpStatusCode
@@ -462,10 +468,10 @@ export class AwsInstrumentation extends InstrumentationBase<AwsSdkInstrumentatio
462468

463469
const httpStatusCode = err?.$metadata?.httpStatusCode;
464470
if (httpStatusCode) {
465-
if (self._semconvStability & SemconvStability.OLD) {
471+
if (self._httpSemconvStability & SemconvStability.OLD) {
466472
span.setAttribute(ATTR_HTTP_STATUS_CODE, httpStatusCode);
467473
}
468-
if (self._semconvStability & SemconvStability.STABLE) {
474+
if (self._httpSemconvStability & SemconvStability.STABLE) {
469475
span.setAttribute(
470476
ATTR_HTTP_RESPONSE_STATUS_CODE,
471477
httpStatusCode

packages/instrumentation-aws-sdk/src/semconv.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,9 +563,20 @@ export const ATTR_RPC_SYSTEM = 'rpc.system' as const;
563563
* Amazon DynamoDB
564564
*
565565
* @experimental This enum value is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
566+
*
567+
* @deprecated Replaced by `DB_SYSTEM_NAME_VALUE_DYNAMODB`.
566568
*/
567569
export const DB_SYSTEM_VALUE_DYNAMODB = 'dynamodb' as const;
568570

571+
/**
572+
* Enum value "dynamodb" for attribute ATTR_DB_SYSTEM_NAME.
573+
*
574+
* Amazon DynamoDB
575+
*
576+
* @experimental This enum value is experimental and is subject to breaking changes in minor releases of `@opentelemetry/semantic-conventions`.
577+
*/
578+
export const DB_SYSTEM_NAME_VALUE_DYNAMODB = 'dynamodb' as const;
579+
569580
/**
570581
* Enum value "chat" for attribute {@link ATTR_GEN_AI_OPERATION_NAME}.
571582
*

packages/instrumentation-aws-sdk/src/services/ServiceExtension.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222
SpanKind,
2323
Tracer,
2424
} from '@opentelemetry/api';
25+
import { SemconvStability } from '@opentelemetry/instrumentation';
2526
import {
2627
AwsSdkInstrumentationConfig,
2728
NormalizedRequest,
@@ -45,7 +46,8 @@ export interface ServiceExtension {
4546
requestPreSpanHook: (
4647
request: NormalizedRequest,
4748
config: AwsSdkInstrumentationConfig,
48-
diag: DiagLogger
49+
diag: DiagLogger,
50+
dbSemconvStability?: SemconvStability
4951
) => RequestMetadata;
5052

5153
// called before request is sent, and after span is started

packages/instrumentation-aws-sdk/src/services/ServicesExtensions.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
* limitations under the License.
1515
*/
1616
import { Tracer, Span, DiagLogger, Meter, HrTime } from '@opentelemetry/api';
17+
import { SemconvStability } from '@opentelemetry/instrumentation';
1718
import { ServiceExtension, RequestMetadata } from './ServiceExtension';
1819
import { SqsServiceExtension } from './sqs';
1920
import {
@@ -52,14 +53,20 @@ export class ServicesExtensions implements ServiceExtension {
5253
requestPreSpanHook(
5354
request: NormalizedRequest,
5455
config: AwsSdkInstrumentationConfig,
55-
diag: DiagLogger
56+
diag: DiagLogger,
57+
dbSemconvStability?: SemconvStability
5658
): RequestMetadata {
5759
const serviceExtension = this.services.get(request.serviceName);
5860
if (!serviceExtension)
5961
return {
6062
isIncoming: false,
6163
};
62-
return serviceExtension.requestPreSpanHook(request, config, diag);
64+
return serviceExtension.requestPreSpanHook(
65+
request,
66+
config,
67+
diag,
68+
dbSemconvStability
69+
);
6370
}
6471

6572
requestPostSpanHook(request: NormalizedRequest) {

packages/instrumentation-aws-sdk/src/services/dynamodb.ts

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,13 @@ import {
2020
SpanKind,
2121
Tracer,
2222
} from '@opentelemetry/api';
23+
import { SemconvStability } from '@opentelemetry/instrumentation';
24+
import {
25+
ATTR_DB_NAMESPACE,
26+
ATTR_DB_OPERATION_NAME,
27+
ATTR_DB_QUERY_TEXT,
28+
ATTR_DB_SYSTEM_NAME,
29+
} from '@opentelemetry/semantic-conventions';
2330
import { RequestMetadata, ServiceExtension } from './ServiceExtension';
2431
import {
2532
ATTR_AWS_DYNAMODB_ATTRIBUTE_DEFINITIONS,
@@ -47,6 +54,7 @@ import {
4754
ATTR_DB_OPERATION,
4855
ATTR_DB_STATEMENT,
4956
ATTR_DB_SYSTEM,
57+
DB_SYSTEM_NAME_VALUE_DYNAMODB,
5058
DB_SYSTEM_VALUE_DYNAMODB,
5159
} from '../semconv';
5260
import {
@@ -63,18 +71,33 @@ export class DynamodbServiceExtension implements ServiceExtension {
6371
requestPreSpanHook(
6472
normalizedRequest: NormalizedRequest,
6573
config: AwsSdkInstrumentationConfig,
66-
diag: DiagLogger
74+
diag: DiagLogger,
75+
dbSemconvStability?: SemconvStability
6776
): RequestMetadata {
6877
const spanKind: SpanKind = SpanKind.CLIENT;
6978
let spanName: string | undefined;
7079
const isIncoming = false;
7180
const operation = normalizedRequest.commandName;
81+
const tableName = normalizedRequest.commandInput?.TableName;
7282

73-
const spanAttributes: Attributes = {
74-
[ATTR_DB_SYSTEM]: DB_SYSTEM_VALUE_DYNAMODB,
75-
[ATTR_DB_NAME]: normalizedRequest.commandInput?.TableName,
76-
[ATTR_DB_OPERATION]: operation,
77-
};
83+
const spanAttributes: Attributes = {};
84+
85+
if (
86+
dbSemconvStability === undefined ||
87+
dbSemconvStability & SemconvStability.OLD
88+
) {
89+
spanAttributes[ATTR_DB_SYSTEM] = DB_SYSTEM_VALUE_DYNAMODB;
90+
spanAttributes[ATTR_DB_NAME] = tableName;
91+
spanAttributes[ATTR_DB_OPERATION] = operation;
92+
}
93+
if (
94+
dbSemconvStability !== undefined &&
95+
dbSemconvStability & SemconvStability.STABLE
96+
) {
97+
spanAttributes[ATTR_DB_SYSTEM_NAME] = DB_SYSTEM_NAME_VALUE_DYNAMODB;
98+
spanAttributes[ATTR_DB_NAMESPACE] = tableName;
99+
spanAttributes[ATTR_DB_OPERATION_NAME] = operation;
100+
}
78101

79102
if (config.dynamoDBStatementSerializer) {
80103
try {
@@ -84,7 +107,18 @@ export class DynamodbServiceExtension implements ServiceExtension {
84107
);
85108

86109
if (typeof sanitizedStatement === 'string') {
87-
spanAttributes[ATTR_DB_STATEMENT] = sanitizedStatement;
110+
if (
111+
dbSemconvStability === undefined ||
112+
dbSemconvStability & SemconvStability.OLD
113+
) {
114+
spanAttributes[ATTR_DB_STATEMENT] = sanitizedStatement;
115+
}
116+
if (
117+
dbSemconvStability !== undefined &&
118+
dbSemconvStability & SemconvStability.STABLE
119+
) {
120+
spanAttributes[ATTR_DB_QUERY_TEXT] = sanitizedStatement;
121+
}
88122
}
89123
} catch (err) {
90124
diag.error('failed to sanitize DynamoDB statement', err);

0 commit comments

Comments
 (0)