diff --git a/experimental/CHANGELOG.md b/experimental/CHANGELOG.md index d025c4d4b7..7d5a24082a 100644 --- a/experimental/CHANGELOG.md +++ b/experimental/CHANGELOG.md @@ -12,6 +12,7 @@ All notable changes to experimental packages in this project will be documented * feat: use HTTP_ROUTE in span name [#3603](https://github.com/open-telemetry/opentelemetry-js/pull/3603) @Flarna * feat: add HTTP_ROUTE attribute to http incoming metrics if present [#3581](https://github.com/open-telemetry/opentelemetry-js/pull/3581) @hermogenes +* feat(opentelemetry-instrumentation-grpc): allow to add attributes from grpc metadata in the patched server [#3589](https://github.com/open-telemetry/opentelemetry-js/pull/3589) @zombispormedio * feat(sdk-node): install diag logger with OTEL_LOG_LEVEL [#3627](https://github.com/open-telemetry/opentelemetry-js/pull/3627) @legendecas * feat(otlp-exporter-base): add retries [#3207](https://github.com/open-telemetry/opentelemetry-js/pull/3207) @svetlanabrennan * feat(sdk-node): override IdGenerator when using NodeSDK [#3645](https://github.com/open-telemetry/opentelemetry-js/pull/3645) @haddasbronfman diff --git a/experimental/packages/opentelemetry-instrumentation-grpc/README.md b/experimental/packages/opentelemetry-instrumentation-grpc/README.md index 0ea8330438..2aa6038c03 100644 --- a/experimental/packages/opentelemetry-instrumentation-grpc/README.md +++ b/experimental/packages/opentelemetry-instrumentation-grpc/README.md @@ -47,7 +47,7 @@ gRPC instrumentation accepts the following configuration: | Options | Type | Description | |----------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | [`ignoreGrpcMethods`](https://github.com/open-telemetry/opentelemetry-js/blob/main/experimental/packages/opentelemetry-instrumentation-grpc/src/types.ts#L25) | `IgnoreMatcher[]` | gRPC instrumentation will not trace any methods that match anything in this list. You may pass a string (case-insensitive match), a `RegExp` object, or a filter function. | -| [`metadataToSpanAttributes`](https://github.com/open-telemetry/opentelemetry-js/blob/main/experimental/packages/opentelemetry-instrumentation-grpc/src/types.ts#L27) | `object` | List of case insensitive metadata to convert to span attributes. Client (outgoing requests, incoming responses) metadata attributes will be converted to span attributes in the form of `rpc.{request\response}.metadata.metadata_key`, e.g. `rpc.response.metadata.date` | +| [`metadataToSpanAttributes`](https://github.com/open-telemetry/opentelemetry-js/blob/main/experimental/packages/opentelemetry-instrumentation-grpc/src/types.ts#L27) | `object` | List of case insensitive metadata to convert to span attributes. Client and server (outgoing requests, incoming responses) metadata attributes will be converted to span attributes in the form of `rpc.{request\response}.metadata.metadata_key`, e.g. `rpc.response.metadata.date` | ## Useful links 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 2e5c833b19..6608521bd6 100644 --- a/experimental/packages/opentelemetry-instrumentation-grpc/src/grpc-js/index.ts +++ b/experimental/packages/opentelemetry-instrumentation-grpc/src/grpc-js/index.ts @@ -212,6 +212,24 @@ export class GrpcJsInstrumentation extends InstrumentationBase { [SemanticAttributes.RPC_SERVICE]: service, }); + instrumentation._metadataCapture.server.captureRequestMetadata( + span, + call.metadata + ); + + instrumentation._wrap( + call, + 'sendMetadata', + originalSendMetadata => + (responseMetadata: grpcJs.Metadata) => { + instrumentation._metadataCapture.server.captureResponseMetadata( + span, + responseMetadata + ); + originalSendMetadata.call(call, responseMetadata); + } + ); + context.with(trace.setSpan(context.active(), span), () => { handleServerFunction.call( self, @@ -385,6 +403,16 @@ export class GrpcJsInstrumentation extends InstrumentationBase { config.metadataToSpanAttributes?.client?.responseMetadata ?? [] ), }, + server: { + captureRequestMetadata: metadataCapture( + 'request', + config.metadataToSpanAttributes?.server?.requestMetadata ?? [] + ), + captureResponseMetadata: metadataCapture( + 'response', + config.metadataToSpanAttributes?.server?.responseMetadata ?? [] + ), + }, }; } } diff --git a/experimental/packages/opentelemetry-instrumentation-grpc/src/grpc/index.ts b/experimental/packages/opentelemetry-instrumentation-grpc/src/grpc/index.ts index 4df381eb66..fbeac0395e 100644 --- a/experimental/packages/opentelemetry-instrumentation-grpc/src/grpc/index.ts +++ b/experimental/packages/opentelemetry-instrumentation-grpc/src/grpc/index.ts @@ -223,6 +223,24 @@ export class GrpcNativeInstrumentation extends InstrumentationBase< [SemanticAttributes.RPC_SERVICE]: service, }); + instrumentation._metadataCapture.server.captureRequestMetadata( + span, + call.metadata + ); + + instrumentation._wrap( + call as any, + 'sendMetadata', + originalSendMetadata => + (responseMetadata: grpcTypes.Metadata) => { + instrumentation._metadataCapture.server.captureResponseMetadata( + span, + responseMetadata + ); + originalSendMetadata.call(call, responseMetadata); + } + ); + context.with(trace.setSpan(context.active(), span), () => { switch (type) { case 'unary': @@ -370,6 +388,16 @@ export class GrpcNativeInstrumentation extends InstrumentationBase< config.metadataToSpanAttributes?.client?.responseMetadata ?? [] ), }, + server: { + captureRequestMetadata: metadataCapture( + 'request', + config.metadataToSpanAttributes?.server?.requestMetadata ?? [] + ), + captureResponseMetadata: metadataCapture( + 'response', + config.metadataToSpanAttributes?.server?.responseMetadata ?? [] + ), + }, }; } } diff --git a/experimental/packages/opentelemetry-instrumentation-grpc/src/internal-types.ts b/experimental/packages/opentelemetry-instrumentation-grpc/src/internal-types.ts index d0052f7643..ebc17ae1d4 100644 --- a/experimental/packages/opentelemetry-instrumentation-grpc/src/internal-types.ts +++ b/experimental/packages/opentelemetry-instrumentation-grpc/src/internal-types.ts @@ -29,4 +29,14 @@ export type metadataCaptureType = { metadata: grpcJsTypes.Metadata | grpcTypes.Metadata ) => void; }; + server: { + captureRequestMetadata: ( + span: Span, + metadata: grpcJsTypes.Metadata | grpcTypes.Metadata + ) => void; + captureResponseMetadata: ( + span: Span, + metadata: grpcJsTypes.Metadata | grpcTypes.Metadata + ) => void; + }; }; diff --git a/experimental/packages/opentelemetry-instrumentation-grpc/src/types.ts b/experimental/packages/opentelemetry-instrumentation-grpc/src/types.ts index dd08d8224b..430476b7a4 100644 --- a/experimental/packages/opentelemetry-instrumentation-grpc/src/types.ts +++ b/experimental/packages/opentelemetry-instrumentation-grpc/src/types.ts @@ -29,5 +29,9 @@ export interface GrpcInstrumentationConfig extends InstrumentationConfig { responseMetadata?: string[]; requestMetadata?: string[]; }; + server?: { + responseMetadata?: string[]; + requestMetadata?: string[]; + }; }; } diff --git a/experimental/packages/opentelemetry-instrumentation-grpc/test/helper.ts b/experimental/packages/opentelemetry-instrumentation-grpc/test/helper.ts index 85b6a1c64e..58855a6a5f 100644 --- a/experimental/packages/opentelemetry-instrumentation-grpc/test/helper.ts +++ b/experimental/packages/opentelemetry-instrumentation-grpc/test/helper.ts @@ -978,6 +978,10 @@ export const runTests = ( requestMetadata: ['client_metadata_key'], responseMetadata: ['server_metadata_key'], }, + server: { + requestMetadata: ['client_metadata_key'], + responseMetadata: ['server_metadata_key'], + }, }, }); @@ -999,13 +1003,18 @@ export const runTests = ( }); }); - describe('Capture request/response metadata in client span', () => { + describe('Capture request/response metadata in client and server spans', () => { const attributeValidation = { clientAttributes: { 'rpc.request.metadata.client_metadata_key': 'client_metadata_value', 'rpc.response.metadata.server_metadata_key': 'server_metadata_value', }, + serverAttributes: { + 'rpc.request.metadata.client_metadata_key': 'client_metadata_value', + 'rpc.response.metadata.server_metadata_key': + 'server_metadata_value', + }, }; runTestWithAttributeValidation(