Skip to content

Commit a83c981

Browse files
authored
Add Patching Mechanism with AWS SDK telemetry improvements (#13)
*Issue #, if available:* *Description of changes:* 1. `aws-attribute-keys.ts`: - Update values for keys: `AWS_BUCKET_NAME, AWS_QUEUE_URL, AWS_QUEUE_NAME, AWS_STREAM_NAME, AWS_TABLE_NAME` in order to match the actual attribute collected from AWS SDK auto-instrumentation 2. `aws-metric-attribute-generator.ts`: - [Similarly to Python](https://github.com/aws-observability/aws-otel-python-instrumentation/blob/2c00bd07eaaf703880a24a2fcfe874cdb4196678/aws-opentelemetry-distro/src/amazon/opentelemetry/distro/_aws_metric_attribute_generator.py#L378-L380), accommodates the fact that AWS_ATTRIBUTE_KEYS.AWS_TABLE_NAMES [has an array of table names](https://github.com/open-telemetry/opentelemetry-js-contrib/blob/931318cac21ee3707f3735a64ac751566ee37182/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/dynamodb.ts#L99-L105) from aws-sdk dynamodb client instrumentation 3. `aws-opentelemetry-configurator.ts`: - Takes and sets instrumentations in constructor. 4. `instrumentation-patch.ts`: - Applies patches for AWS SDK Instrumentation 5. `register.ts`: - Applies patches from (4.) by default, unless `AWS_APPLY_PATCHES` env var is not `'true'` The following files are copied from upstream: ``` aws-distro-opentelemetry-node-autoinstrumentation/src/patches/aws/services/ServiceExtension.ts ``` The following files are being contributed to upstream: See: open-telemetry/opentelemetry-js-contrib#2361 ``` aws-distro-opentelemetry-node-autoinstrumentation/src/patches/aws/services/kinesis.ts aws-distro-opentelemetry-node-autoinstrumentation/src/patches/aws/services/s3.ts ``` *Testing:* - Add unit tests By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.
1 parent a44f51e commit a83c981

18 files changed

+2603
-278
lines changed

aws-distro-opentelemetry-node-autoinstrumentation/package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,17 @@
3030
"prewatch": "npm run precompile",
3131
"prepublishOnly": "npm run compile",
3232
"tdd": "yarn test -- --watch-extensions ts --watch",
33-
"test": "nyc ts-mocha --timeout 10000 -p tsconfig.json 'test/**/*.ts'",
33+
"test": "nyc ts-mocha --timeout 10000 -p tsconfig.json --require '@opentelemetry/contrib-test-utils' 'test/**/*.ts'",
3434
"watch": "tsc -w"
3535
},
3636
"bugs": {
3737
"url": "https://github.com/aws-observability/aws-otel-js-instrumentation/issues"
3838
},
3939
"devDependencies": {
40+
"@aws-sdk/client-kinesis": "3.85.0",
41+
"@aws-sdk/client-s3": "3.85.0",
42+
"@aws-sdk/client-sqs": "3.85.0",
43+
"@opentelemetry/contrib-test-utils": "^0.40.0",
4044
"@types/mocha": "7.0.2",
4145
"@types/node": "18.6.5",
4246
"@types/sinon": "10.0.18",

aws-distro-opentelemetry-node-autoinstrumentation/src/aws-attribute-keys.ts

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
// SPDX-License-Identifier: Apache-2.0
33

4+
import { SEMATTRS_AWS_DYNAMODB_TABLE_NAMES } from '@opentelemetry/semantic-conventions';
5+
46
// Utility class holding attribute keys with special meaning to AWS components
57
export const AWS_ATTRIBUTE_KEYS: { [key: string]: string } = {
68
AWS_SPAN_KIND: 'aws.span.kind',
@@ -19,14 +21,11 @@ export const AWS_ATTRIBUTE_KEYS: { [key: string]: string } = {
1921
// Used for JavaScript workaround - attribute for pre-calculated value of isLocalRoot
2022
AWS_IS_LOCAL_ROOT: 'aws.is.local.root',
2123

22-
// Divergence from Java/Python
23-
// TODO: Audit this: These will most definitely be different in JavaScript.
24-
// For example:
25-
// - `messaging.url` for AWS_QUEUE_URL
26-
// - `aws.dynamodb.table_names` for AWS_TABLE_NAME
27-
AWS_BUCKET_NAME: 'aws.bucket.name',
28-
AWS_QUEUE_URL: 'aws.queue.url',
29-
AWS_QUEUE_NAME: 'aws.queue.name',
30-
AWS_STREAM_NAME: 'aws.stream.name',
31-
AWS_TABLE_NAME: 'aws.table.name',
24+
// AWS_#_NAME attributes are not supported in JavaScript as they are not part of the Semantic Conventions.
25+
// TODO:Move to Semantic Conventions when these attributes are added.
26+
AWS_S3_BUCKET: 'aws.s3.bucket',
27+
AWS_SQS_QUEUE_URL: 'aws.sqs.queue.url',
28+
AWS_SQS_QUEUE_NAME: 'aws.sqs.queue.name',
29+
AWS_KINESIS_STREAM_NAME: 'aws.kinesis.stream.name',
30+
AWS_DYNAMODB_TABLE_NAMES: SEMATTRS_AWS_DYNAMODB_TABLE_NAMES,
3231
};

aws-distro-opentelemetry-node-autoinstrumentation/src/aws-metric-attribute-generator.ts

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// SPDX-License-Identifier: Apache-2.0
33

44
import { Attributes, AttributeValue, diag, SpanKind } from '@opentelemetry/api';
5-
import { Resource, defaultServiceName } from '@opentelemetry/resources';
5+
import { defaultServiceName, Resource } from '@opentelemetry/resources';
66
import { ReadableSpan } from '@opentelemetry/sdk-trace-base';
77
import {
88
SEMATTRS_DB_CONNECTION_STRING,
@@ -340,30 +340,33 @@ export class AwsMetricAttributeGenerator implements MetricAttributeGenerator {
340340
let remoteResourceIdentifier: AttributeValue | undefined;
341341

342342
if (AwsSpanProcessingUtil.isAwsSDKSpan(span)) {
343-
if (AwsSpanProcessingUtil.isKeyPresent(span, AWS_ATTRIBUTE_KEYS.AWS_TABLE_NAME)) {
343+
const awsTableNames: AttributeValue | undefined = span.attributes[AWS_ATTRIBUTE_KEYS.AWS_DYNAMODB_TABLE_NAMES];
344+
if (
345+
AwsSpanProcessingUtil.isKeyPresent(span, AWS_ATTRIBUTE_KEYS.AWS_DYNAMODB_TABLE_NAMES) &&
346+
Array.isArray(awsTableNames) &&
347+
awsTableNames.length === 1
348+
) {
344349
remoteResourceType = NORMALIZED_DYNAMO_DB_SERVICE_NAME + '::Table';
345-
remoteResourceIdentifier = AwsMetricAttributeGenerator.escapeDelimiters(
346-
span.attributes[AWS_ATTRIBUTE_KEYS.AWS_TABLE_NAME]
347-
);
348-
} else if (AwsSpanProcessingUtil.isKeyPresent(span, AWS_ATTRIBUTE_KEYS.AWS_STREAM_NAME)) {
350+
remoteResourceIdentifier = AwsMetricAttributeGenerator.escapeDelimiters(awsTableNames[0]);
351+
} else if (AwsSpanProcessingUtil.isKeyPresent(span, AWS_ATTRIBUTE_KEYS.AWS_KINESIS_STREAM_NAME)) {
349352
remoteResourceType = NORMALIZED_KINESIS_SERVICE_NAME + '::Stream';
350353
remoteResourceIdentifier = AwsMetricAttributeGenerator.escapeDelimiters(
351-
span.attributes[AWS_ATTRIBUTE_KEYS.AWS_STREAM_NAME]
354+
span.attributes[AWS_ATTRIBUTE_KEYS.AWS_KINESIS_STREAM_NAME]
352355
);
353-
} else if (AwsSpanProcessingUtil.isKeyPresent(span, AWS_ATTRIBUTE_KEYS.AWS_BUCKET_NAME)) {
356+
} else if (AwsSpanProcessingUtil.isKeyPresent(span, AWS_ATTRIBUTE_KEYS.AWS_S3_BUCKET)) {
354357
remoteResourceType = NORMALIZED_S3_SERVICE_NAME + '::Bucket';
355358
remoteResourceIdentifier = AwsMetricAttributeGenerator.escapeDelimiters(
356-
span.attributes[AWS_ATTRIBUTE_KEYS.AWS_BUCKET_NAME]
359+
span.attributes[AWS_ATTRIBUTE_KEYS.AWS_S3_BUCKET]
357360
);
358-
} else if (AwsSpanProcessingUtil.isKeyPresent(span, AWS_ATTRIBUTE_KEYS.AWS_QUEUE_NAME)) {
361+
} else if (AwsSpanProcessingUtil.isKeyPresent(span, AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_NAME)) {
359362
remoteResourceType = NORMALIZED_SQS_SERVICE_NAME + '::Queue';
360363
remoteResourceIdentifier = AwsMetricAttributeGenerator.escapeDelimiters(
361-
span.attributes[AWS_ATTRIBUTE_KEYS.AWS_QUEUE_NAME]
364+
span.attributes[AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_NAME]
362365
);
363-
} else if (AwsSpanProcessingUtil.isKeyPresent(span, AWS_ATTRIBUTE_KEYS.AWS_QUEUE_URL)) {
366+
} else if (AwsSpanProcessingUtil.isKeyPresent(span, AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_URL)) {
364367
remoteResourceType = NORMALIZED_SQS_SERVICE_NAME + '::Queue';
365368
remoteResourceIdentifier = SqsUrlParser.getQueueName(
366-
AwsMetricAttributeGenerator.escapeDelimiters(span.attributes[AWS_ATTRIBUTE_KEYS.AWS_QUEUE_URL])
369+
AwsMetricAttributeGenerator.escapeDelimiters(span.attributes[AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_URL])
367370
);
368371
}
369372
} else if (AwsSpanProcessingUtil.isDBSpan(span)) {
@@ -479,8 +482,8 @@ export class AwsMetricAttributeGenerator implements MetricAttributeGenerator {
479482
return AwsMetricAttributeGenerator.escapeDelimiters(address) + (port !== '' ? '|' + port : '');
480483
}
481484

482-
private static escapeDelimiters(input: string | AttributeValue | undefined): string | undefined {
483-
if (input === undefined) {
485+
private static escapeDelimiters(input: string | AttributeValue | undefined | null): string | undefined {
486+
if (typeof input !== 'string') {
484487
return undefined;
485488
}
486489

aws-distro-opentelemetry-node-autoinstrumentation/src/aws-opentelemetry-configurator.ts

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,7 @@
44

55
import { TextMapPropagator, diag } from '@opentelemetry/api';
66
import { getPropagator } from '@opentelemetry/auto-configuration-propagators';
7-
import {
8-
getNodeAutoInstrumentations,
9-
getResourceDetectors as getResourceDetectorsFromEnv,
10-
} from '@opentelemetry/auto-instrumentations-node';
7+
import { getResourceDetectors as getResourceDetectorsFromEnv } from '@opentelemetry/auto-instrumentations-node';
118
import { ENVIRONMENT, TracesSamplerValues, getEnv, getEnvWithoutDefaults } from '@opentelemetry/core';
129
import { OTLPMetricExporter as OTLPGrpcOTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-grpc';
1310
import {
@@ -85,7 +82,18 @@ export class AwsOpentelemetryConfigurator {
8582
private spanProcessors: SpanProcessor[];
8683
private propagator: TextMapPropagator;
8784

88-
constructor() {
85+
/**
86+
* The constructor will setup the AwsOpentelemetryConfigurator object to be able to provide a
87+
* configuration for ADOT JavaScript Auto-Instrumentation.
88+
*
89+
* The `instrumentations` are the desired Node auto-instrumentations to be used when using ADOT JavaScript.
90+
* The auto-Instrumentions are usually populated from OTel's `getNodeAutoInstrumentations()` method from the
91+
* `@opentelemetry/auto-instrumentations-node` NPM package, and may have instrumentation patching applied.
92+
*
93+
* @constructor
94+
* @param {Instrumentation[]} instrumentations - Auto-Instrumentations to be added to the ADOT Config
95+
*/
96+
public constructor(instrumentations: Instrumentation[]) {
8997
/*
9098
* Set and Detect Resources via Resource Detectors
9199
*
@@ -135,7 +143,7 @@ export class AwsOpentelemetryConfigurator {
135143
autoResource = autoResource.merge(detectResourcesSync(internalConfig));
136144
this.resource = autoResource;
137145

138-
this.instrumentations = getNodeAutoInstrumentations();
146+
this.instrumentations = instrumentations;
139147
this.propagator = getPropagator();
140148

141149
// TODO: Consider removing AWSXRayIdGenerator as it is not needed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
import { Attributes, SpanKind } from '@opentelemetry/api';
5+
import { AwsSdkInstrumentationConfig, NormalizedRequest } from '@opentelemetry/instrumentation-aws-sdk';
6+
import { AWS_ATTRIBUTE_KEYS } from '../../../aws-attribute-keys';
7+
import { RequestMetadata, ServiceExtension } from '../../../third-party/otel/aws/services/ServiceExtension';
8+
9+
/*
10+
This file's contents are being contributed to upstream
11+
- https://github.com/open-telemetry/opentelemetry-js-contrib/pull/2361
12+
13+
This class is a service extension to be used for the AWS JavaScript SDK instrumentation patch for Kinesis.
14+
The instrumentation patch adds this extension to the upstream's Map of known extension for Kinesis.
15+
Extensions allow for custom logic for adding service-specific information to spans, such as attributes.
16+
Specifically, we are adding logic to add the `aws.kinesis.stream.name` attribute, to be used to generate
17+
RemoteTarget and achieve parity with the Java/Python instrumentation.
18+
*/
19+
export class KinesisServiceExtension implements ServiceExtension {
20+
requestPreSpanHook(request: NormalizedRequest, _config: AwsSdkInstrumentationConfig): RequestMetadata {
21+
const streamName = request.commandInput?.StreamName;
22+
23+
const spanKind: SpanKind = SpanKind.CLIENT;
24+
let spanName: string | undefined;
25+
26+
const spanAttributes: Attributes = {};
27+
28+
if (streamName) {
29+
spanAttributes[AWS_ATTRIBUTE_KEYS.AWS_KINESIS_STREAM_NAME] = streamName;
30+
}
31+
32+
const isIncoming = false;
33+
34+
return {
35+
isIncoming,
36+
spanAttributes,
37+
spanKind,
38+
spanName,
39+
};
40+
}
41+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
import { Attributes, SpanKind } from '@opentelemetry/api';
5+
import { AwsSdkInstrumentationConfig, NormalizedRequest } from '@opentelemetry/instrumentation-aws-sdk';
6+
import { AWS_ATTRIBUTE_KEYS } from '../../../aws-attribute-keys';
7+
import { RequestMetadata, ServiceExtension } from '../../../third-party/otel/aws/services/ServiceExtension';
8+
9+
/*
10+
This file's contents are being contributed to upstream
11+
- https://github.com/open-telemetry/opentelemetry-js-contrib/pull/2361
12+
13+
This class is a service extension to be used for the AWS JavaScript SDK instrumentation patch for S3.
14+
The instrumentation patch adds this extension to the upstream's Map of known extension for S3.
15+
Extensions allow for custom logic for adding service-specific information to spans, such as attributes.
16+
Specifically, we are adding logic to add the `aws.s3.bucket` attribute, to be used to generate
17+
RemoteTarget and achieve parity with the Java/Python instrumentation.
18+
*/
19+
export class S3ServiceExtension implements ServiceExtension {
20+
requestPreSpanHook(request: NormalizedRequest, _config: AwsSdkInstrumentationConfig): RequestMetadata {
21+
const bucketName = request.commandInput?.Bucket;
22+
23+
const spanKind: SpanKind = SpanKind.CLIENT;
24+
let spanName: string | undefined;
25+
26+
const spanAttributes: Attributes = {};
27+
28+
if (bucketName) {
29+
spanAttributes[AWS_ATTRIBUTE_KEYS.AWS_S3_BUCKET] = bucketName;
30+
}
31+
32+
const isIncoming = false;
33+
34+
return {
35+
isIncoming,
36+
spanAttributes,
37+
spanKind,
38+
spanName,
39+
};
40+
}
41+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
import { Instrumentation } from '@opentelemetry/instrumentation';
5+
import { AwsSdkInstrumentationConfig, NormalizedRequest } from '@opentelemetry/instrumentation-aws-sdk';
6+
import { AWS_ATTRIBUTE_KEYS } from '../aws-attribute-keys';
7+
import { RequestMetadata } from '../third-party/otel/aws/services/ServiceExtension';
8+
import { KinesisServiceExtension } from './aws/services/kinesis';
9+
import { S3ServiceExtension } from './aws/services/s3';
10+
11+
export function applyInstrumentationPatches(instrumentations: Instrumentation[]): void {
12+
/*
13+
Apply patches to upstream instrumentation libraries.
14+
15+
This method is invoked to apply changes to upstream instrumentation libraries, typically when changes to upstream
16+
are required on a timeline that cannot wait for upstream release. Generally speaking, patches should be short-term
17+
local solutions that are comparable to long-term upstream solutions.
18+
19+
Where possible, automated testing should be run to catch upstream changes resulting in broken patches
20+
*/
21+
instrumentations.forEach(instrumentation => {
22+
if (instrumentation.instrumentationName === '@opentelemetry/instrumentation-aws-sdk') {
23+
// Access private property servicesExtensions of AwsInstrumentation
24+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
25+
// @ts-ignore
26+
const services: Map<string, ServiceExtension> | undefined = (instrumentation as any).servicesExtensions?.services;
27+
if (services) {
28+
services.set('S3', new S3ServiceExtension());
29+
services.set('Kinesis', new KinesisServiceExtension());
30+
patchSqsServiceExtension(services.get('SQS'));
31+
}
32+
}
33+
});
34+
}
35+
36+
/*
37+
* This patch extends the existing upstream extension for SQS. Extensions allow for custom logic for adding
38+
* service-specific information to spans, such as attributes. Specifically, we are adding logic to add
39+
* `aws.sqs.queue.url` and `aws.sqs.queue.name` attributes, to be used to generate RemoteTarget and achieve parity
40+
* with the Java/Python instrumentation.
41+
*
42+
* Callout that today, the upstream logic adds `messaging.url` and `messaging.destination` but we feel that
43+
* `aws.sqs` is more in line with existing AWS Semantic Convention attributes like `AWS_S3_BUCKET`, etc.
44+
*
45+
* @param sqsServiceExtension SQS Service Extension obtained the service extension list from the AWS SDK OTel Instrumentation
46+
*/
47+
function patchSqsServiceExtension(sqsServiceExtension: any): void {
48+
// It is not expected that `sqsServiceExtension` is undefined
49+
if (sqsServiceExtension) {
50+
const requestPreSpanHook = sqsServiceExtension.requestPreSpanHook;
51+
// Save original `requestPreSpanHook` under a similar name, to be invoked by the patched hook
52+
sqsServiceExtension._requestPreSpanHook = requestPreSpanHook;
53+
// The patched hook will populate the 'aws.sqs.queue.url' and 'aws.sqs.queue.name' attributes according to spec
54+
// from the 'messaging.url' attribute
55+
const patchedRequestPreSpanHook = (
56+
request: NormalizedRequest,
57+
_config: AwsSdkInstrumentationConfig
58+
): RequestMetadata => {
59+
const requestMetadata: RequestMetadata = sqsServiceExtension._requestPreSpanHook(request, _config);
60+
// It is not expected that `requestMetadata.spanAttributes` can possibly be undefined, but still be careful anyways
61+
if (requestMetadata.spanAttributes) {
62+
if (request.commandInput?.QueueUrl) {
63+
requestMetadata.spanAttributes[AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_URL] = request.commandInput.QueueUrl;
64+
}
65+
if (request.commandInput?.QueueName) {
66+
requestMetadata.spanAttributes[AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_NAME] = request.commandInput.QueueName;
67+
}
68+
}
69+
return requestMetadata;
70+
};
71+
sqsServiceExtension.requestPreSpanHook = patchedRequestPreSpanHook;
72+
}
73+
}

aws-distro-opentelemetry-node-autoinstrumentation/src/register.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@
33
// Modifications Copyright The OpenTelemetry Authors. Licensed under the Apache License 2.0 License.
44

55
import { DiagConsoleLogger, diag } from '@opentelemetry/api';
6+
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
7+
import { Instrumentation } from '@opentelemetry/instrumentation';
68
import * as opentelemetry from '@opentelemetry/sdk-node';
79
import { AwsOpentelemetryConfigurator } from './aws-opentelemetry-configurator';
10+
import { applyInstrumentationPatches } from './patches/instrumentation-patch';
811

912
diag.setLogger(new DiagConsoleLogger(), opentelemetry.core.getEnv().OTEL_LOG_LEVEL);
1013

@@ -40,7 +43,12 @@ export function setAwsDefaultEnvironmentVariables(): void {
4043
}
4144
setAwsDefaultEnvironmentVariables();
4245

43-
const configurator: AwsOpentelemetryConfigurator = new AwsOpentelemetryConfigurator();
46+
const instrumentations: Instrumentation[] = getNodeAutoInstrumentations();
47+
48+
// Apply instrumentation patches
49+
applyInstrumentationPatches(instrumentations);
50+
51+
const configurator: AwsOpentelemetryConfigurator = new AwsOpentelemetryConfigurator(instrumentations);
4452
const configuration: Partial<opentelemetry.NodeSDKConfiguration> = configurator.configure();
4553

4654
const sdk: opentelemetry.NodeSDK = new opentelemetry.NodeSDK(configuration);

aws-distro-opentelemetry-node-autoinstrumentation/src/sqs-url-parser.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
// SPDX-License-Identifier: Apache-2.0
33

4+
import { AttributeValue } from '@opentelemetry/api';
5+
46
const HTTP_SCHEMA: string = 'http://';
57
const HTTPS_SCHEMA: string = 'https://';
68

@@ -16,8 +18,8 @@ export class SqsUrlParser {
1618
* /'s (excluding schema), the second part should be a 12-digit account id, and the third part
1719
* should be a valid queue name, per SQS naming conventions.
1820
*/
19-
public static getQueueName(url: string | undefined): string | undefined {
20-
if (url === undefined) {
21+
public static getQueueName(url: AttributeValue | undefined): string | undefined {
22+
if (typeof url !== 'string') {
2123
return undefined;
2224
}
2325
url = url.replace(HTTP_SCHEMA, '').replace(HTTPS_SCHEMA, '');

0 commit comments

Comments
 (0)