From 4d65da9dd53382983017ff8992af85cb9c5cdcc1 Mon Sep 17 00:00:00 2001 From: Ty Bekiares Date: Sun, 20 Nov 2022 09:17:42 -0600 Subject: [PATCH] feat(instrumentation-grpc): set peer.service on client spans --- CHANGELOG.md | 2 ++ .../src/grpc-js/index.ts | 7 ++++++- .../opentelemetry-instrumentation-grpc/src/grpc/index.ts | 7 ++++++- .../opentelemetry-instrumentation-grpc/src/utils.ts | 3 +++ .../opentelemetry-instrumentation-grpc/test/helper.ts | 4 ++++ .../test/utils/assertionUtils.ts | 7 ++++++- 6 files changed, 27 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d605eff3e12..b68628ab4fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ For experimental package changes, see the [experimental CHANGELOG](experimental/ ### :rocket: (Enhancement) +* feat(instrumentation-grpc): set peer.service on client spans [#3430](https://github.com/open-telemetry/opentelemetry-js/pull/3430) + ### :bug: (Bug Fix) * fix(sdk-metrics): use default Resource to comply with semantic conventions [#3411](https://github.com/open-telemetry/opentelemetry-js/pull/3411) @pichlermarc diff --git a/experimental/packages/opentelemetry-instrumentation-grpc/src/grpc-js/index.ts b/experimental/packages/opentelemetry-instrumentation-grpc/src/grpc-js/index.ts index 4a1c8e9f3aa..dc2b9d88247 100644 --- a/experimental/packages/opentelemetry-instrumentation-grpc/src/grpc-js/index.ts +++ b/experimental/packages/opentelemetry-instrumentation-grpc/src/grpc-js/index.ts @@ -49,7 +49,7 @@ import { getMetadata, } from './clientUtils'; import { EventEmitter } from 'events'; -import { _extractMethodAndService } from '../utils'; +import { _extractMethodAndService, URI_REGEX } from '../utils'; import { AttributeValues } from '../enums/AttributeValues'; import { SemanticAttributes } from '@opentelemetry/semantic-conventions'; @@ -298,6 +298,11 @@ export class GrpcJsInstrumentation extends InstrumentationBase { [SemanticAttributes.RPC_METHOD]: method, [SemanticAttributes.RPC_SERVICE]: service, }); + // set peer.service from target (e.g., "dns:otel-productcatalogservice:8080") as a hint to APMs + const parsedUri = URI_REGEX.exec(this.getChannel().getTarget()); + if (parsedUri != null && parsedUri.groups != null) { + span.setAttribute(SemanticAttributes.PEER_SERVICE, parsedUri.groups['addr']); + } return context.with(trace.setSpan(context.active(), span), () => makeGrpcClientRemoteCall(original, args, metadata, this)(span) ); diff --git a/experimental/packages/opentelemetry-instrumentation-grpc/src/grpc/index.ts b/experimental/packages/opentelemetry-instrumentation-grpc/src/grpc/index.ts index b31d9ef55c3..9631952df6a 100644 --- a/experimental/packages/opentelemetry-instrumentation-grpc/src/grpc/index.ts +++ b/experimental/packages/opentelemetry-instrumentation-grpc/src/grpc/index.ts @@ -41,7 +41,7 @@ import { serverStreamAndBidiHandler, } from './serverUtils'; import { makeGrpcClientRemoteCall, getMetadata } from './clientUtils'; -import { _extractMethodAndService, _methodIsIgnored } from '../utils'; +import { _extractMethodAndService, _methodIsIgnored, URI_REGEX } from '../utils'; import { SemanticAttributes } from '@opentelemetry/semantic-conventions'; import {AttributeValues} from '../enums/AttributeValues'; @@ -306,6 +306,11 @@ export class GrpcNativeInstrumentation extends InstrumentationBase< [SemanticAttributes.RPC_METHOD]: method, [SemanticAttributes.RPC_SERVICE]: service, }); + // set peer.service from target (e.g., "dns:otel-productcatalogservice:8080") as a hint to APMs + const parsedUri = URI_REGEX.exec(this.getChannel().getTarget()); + if (parsedUri != null && parsedUri.groups != null) { + span.setAttribute(SemanticAttributes.PEER_SERVICE, parsedUri.groups['addr']); + } return context.with(trace.setSpan(context.active(), span), () => makeGrpcClientRemoteCall( grpcClient, diff --git a/experimental/packages/opentelemetry-instrumentation-grpc/src/utils.ts b/experimental/packages/opentelemetry-instrumentation-grpc/src/utils.ts index 16bf81a7286..770862a1f27 100644 --- a/experimental/packages/opentelemetry-instrumentation-grpc/src/utils.ts +++ b/experimental/packages/opentelemetry-instrumentation-grpc/src/utils.ts @@ -19,6 +19,9 @@ import type * as grpcTypes from 'grpc'; import type * as grpcJsTypes from '@grpc/grpc-js'; import { IgnoreMatcher } from './types'; +// e.g., "dns:otel-productcatalogservice:8080" or "127.0.0.1:8080" +export const URI_REGEX = /(?:([A-Za-z0-9+.-]+):(?:\/\/)?)?(?[A-Za-z0-9+.-]+:[0-9+.-]+)$/; + // Equivalent to lodash _.findIndex export const findIndex: (args: T[], fn: (arg: T) => boolean) => number = ( args, diff --git a/experimental/packages/opentelemetry-instrumentation-grpc/test/helper.ts b/experimental/packages/opentelemetry-instrumentation-grpc/test/helper.ts index 5564c7c964f..fca64eceb9f 100644 --- a/experimental/packages/opentelemetry-instrumentation-grpc/test/helper.ts +++ b/experimental/packages/opentelemetry-instrumentation-grpc/test/helper.ts @@ -481,6 +481,7 @@ export const runTests = ( const validations = { name: `grpc.pkg_test.GrpcTester/${method.methodName}`, status: grpc.status.OK, + peerService: 'localhost:' + grpcPort, }; assert.strictEqual(spans.length, 2); @@ -530,6 +531,7 @@ export const runTests = ( const validations = { name: `grpc.pkg_test.GrpcTester/${method.methodName}`, status: grpc.status.OK, + peerService: 'localhost:' + grpcPort, }; assertSpan( moduleName, @@ -590,6 +592,7 @@ export const runTests = ( const validations = { name: `grpc.pkg_test.GrpcTester/${method.methodName}`, status: errorCode, + peerService: 'localhost:' + grpcPort, }; const serverRoot = spans[0]; const clientRoot = spans[1]; @@ -629,6 +632,7 @@ export const runTests = ( const validations = { name: `grpc.pkg_test.GrpcTester/${method.methodName}`, status: errorCode, + peerService: 'localhost:' + grpcPort, }; assertSpan(moduleName, serverSpan, SpanKind.SERVER, validations); assertSpan(moduleName, clientSpan, SpanKind.CLIENT, validations); diff --git a/experimental/packages/opentelemetry-instrumentation-grpc/test/utils/assertionUtils.ts b/experimental/packages/opentelemetry-instrumentation-grpc/test/utils/assertionUtils.ts index e399a4a5c52..61c01b8ff5d 100644 --- a/experimental/packages/opentelemetry-instrumentation-grpc/test/utils/assertionUtils.ts +++ b/experimental/packages/opentelemetry-instrumentation-grpc/test/utils/assertionUtils.ts @@ -23,6 +23,7 @@ import { hrTimeToMilliseconds, hrTimeToMicroseconds, } from '@opentelemetry/core'; +import { SemanticAttributes } from '@opentelemetry/semantic-conventions'; export const grpcStatusCodeToOpenTelemetryStatusCode = ( status: grpc.status | grpcJs.status @@ -37,7 +38,7 @@ export const assertSpan = ( component: string, span: ReadableSpan, kind: SpanKind, - validations: { name: string; status: grpc.status | grpcJs.status } + validations: { name: string; status: grpc.status | grpcJs.status; peerService?: string } ) => { assert.strictEqual(span.spanContext().traceId.length, 32); assert.strictEqual(span.spanContext().spanId.length, 16); @@ -55,6 +56,10 @@ export const assertSpan = ( assert.ok(span.spanContext()); } + if (span.kind === SpanKind.CLIENT && validations.peerService !== undefined) { + assert.strictEqual(span.attributes[SemanticAttributes.PEER_SERVICE], validations.peerService); + } + // validations assert.strictEqual(span.name, validations.name); assert.strictEqual(