Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add grpc request and response metadata #3386

Merged
merged 29 commits into from
Nov 23, 2022
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
d03901d
feat(grpc-metadata): added grpc request response metadata for client …
samimusallam Nov 7, 2022
d6f6c2e
Merge branch 'main' into feat/grpc-metadata
samimusallam Nov 7, 2022
d0a53e1
feat(grpc-metadata): added separate method for testing
samimusallam Nov 7, 2022
57ae707
feat(grpc-metadata): added the same functionality for the 'grpc' impl…
samimusallam Nov 7, 2022
edbfa1a
feat(grpc-metadata): removed unnecessary server type
samimusallam Nov 7, 2022
d536570
feat(grpc-metadata): updated README.md
samimusallam Nov 7, 2022
cc84565
feat(grpc-metadata): updated CHANGELOG.md
samimusallam Nov 7, 2022
7226d8c
feat(grpc-metadata): removed unnecessary code
samimusallam Nov 7, 2022
f222bce
feat(grpc-metadata): removed unnecessary comment
samimusallam Nov 7, 2022
f670dff
Merge branch 'main' into feat/grpc-metadata
samimusallam Nov 8, 2022
045643e
Merge branch 'main' into feat/grpc-metadata
samimusallam Nov 9, 2022
de58ffe
Merge branch 'main' into feat/grpc-metadata
samimusallam Nov 13, 2022
530373d
Merge branch 'main' into feat/grpc-metadata
samimusallam Nov 13, 2022
764a919
feat(grpc-metadata): moved changes to experimental/CHANGELOG.md
samimusallam Nov 13, 2022
07222c8
feat(grpc-metadata): fixed CHANGELOG.md misplacement
samimusallam Nov 14, 2022
e1c9ad7
Merge branch 'main' into feat/grpc-metadata
samimusallam Nov 15, 2022
2dd115b
Merge branch 'main' into feat/grpc-metadata
samimusallam Nov 16, 2022
e48ca90
Merge branch 'main' into feat/grpc-metadata
samimusallam Nov 17, 2022
df6db61
Merge branch 'main' into feat/grpc-metadata
samimusallam Nov 19, 2022
146fbea
Merge branch 'main' into feat/grpc-metadata
samimusallam Nov 20, 2022
d6ea750
feat(grpc-metadata): fixed imports in utils.ts
samimusallam Nov 22, 2022
7232888
feat(grpc-metadata): removed unnecessary metadata getter
samimusallam Nov 22, 2022
14761c5
feat(grpc-metadata): declared metadata capture structure
samimusallam Nov 22, 2022
6fff4b8
Merge branch 'main' into feat/grpc-metadata
samimusallam Nov 22, 2022
a336483
feat(grpc-metadata): using the new declared structure
samimusallam Nov 22, 2022
28448a9
Merge branch 'main' into feat/grpc-metadata
samimusallam Nov 23, 2022
764ac43
feat(grpc-metadata): moved metadataCaptureType to the shared types.cs
samimusallam Nov 23, 2022
69cfddb
feat(grpc-metadata): fixed lint issue
samimusallam Nov 23, 2022
5b5441f
Merge branch 'main' into feat/grpc-metadata
samimusallam Nov 23, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions experimental/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ All notable changes to experimental packages in this project will be documented
* deps: remove unused proto-loader dependencies and update grpc-js and proto-loader versions [#3337](https://github.com/open-telemetry/opentelemetry-js/pull/3337) @seemk
* feat(metrics-exporters): configure temporality via environment variable [#3305](https://github.com/open-telemetry/opentelemetry-js/pull/3305) @pichlermarc
* feat(console-metric-exporter): add temporality configuration [#3387](https://github.com/open-telemetry/opentelemetry-js/pull/3387) @pichlermarc
* feat(instrumentation): added grpc metadata client side attributes in instrumentation [#3386](https://github.com/open-telemetry/opentelemetry-js/pull/3386)
vmarchaud marked this conversation as resolved.
Show resolved Hide resolved

### :bug: (Bug Fix)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,10 @@ See [examples/grpc](https://github.com/open-telemetry/opentelemetry-js/tree/main

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. |
| 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` |

## Useful links

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ export function getMethodsToWrap(
* span on callback or receiving an emitted event.
*/
export function makeGrpcClientRemoteCall(
metadataCapture: any,
legendecas marked this conversation as resolved.
Show resolved Hide resolved
original: GrpcClientFunc,
args: unknown[],
metadata: grpcJs.Metadata,
Expand Down Expand Up @@ -129,6 +130,14 @@ export function makeGrpcClientRemoteCall(
setSpanContext(metadata);
const call = original.apply(self, args);

call.on('metadata', responseMetadata => {
const metadataMap = responseMetadata.getMap();

metadataCapture.client.captureResponseMetadata(span, (metadataKey: string) => {
return metadataMap[metadataKey];
});
});

// if server stream or bidi
if (original.responseStream) {
// Both error and status events can be emitted
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,17 +49,20 @@ import {
getMetadata,
} from './clientUtils';
import { EventEmitter } from 'events';
import { _extractMethodAndService } from '../utils';
import {_extractMethodAndService, metadataCapture} from '../utils';
import { AttributeValues } from '../enums/AttributeValues';
import { SemanticAttributes } from '@opentelemetry/semantic-conventions';

export class GrpcJsInstrumentation extends InstrumentationBase {
private _metadataCapture;

constructor(
name: string,
version: string,
config?: GrpcInstrumentationConfig,
) {
super(name, version, config);
this._metadataCapture = this._createMetadataCapture();
}

init() {
Expand Down Expand Up @@ -122,6 +125,11 @@ export class GrpcJsInstrumentation extends InstrumentationBase {
return super.getConfig();
}

override setConfig(config?: GrpcInstrumentationConfig): void {
super.setConfig(config);
this._metadataCapture = this._createMetadataCapture();
}

/**
* Patch for grpc.Server.prototype.register(...) function. Provides auto-instrumentation for
* client_stream, server_stream, bidi, unary server handler calls.
Expand Down Expand Up @@ -298,8 +306,15 @@ export class GrpcJsInstrumentation extends InstrumentationBase {
[SemanticAttributes.RPC_METHOD]: method,
[SemanticAttributes.RPC_SERVICE]: service,
});

instrumentation._metadataCapture.client.captureRequestMetadata(span, (metadataKey: string) => {
const metadataMap = metadata.getMap();
samimusallam marked this conversation as resolved.
Show resolved Hide resolved

return metadataMap[metadataKey];
});

return context.with(trace.setSpan(context.active(), span), () =>
makeGrpcClientRemoteCall(original, args, metadata, this)(span)
makeGrpcClientRemoteCall(instrumentation._metadataCapture, original, args, metadata, this)(span)
);
}
Object.assign(clientMethodTrace, original);
Expand Down Expand Up @@ -334,4 +349,15 @@ export class GrpcJsInstrumentation extends InstrumentationBase {
}
});
}

private _createMetadataCapture() {
const config = this.getConfig();

return {
client: {
captureRequestMetadata: metadataCapture('request', config.metadataToSpanAttributes?.client?.requestMetadata ?? []),
captureResponseMetadata: metadataCapture('response', config.metadataToSpanAttributes?.client?.responseMetadata ?? [])
}
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import { AttributeNames } from '../enums/AttributeNames';
* This method handles the client remote call
*/
export const makeGrpcClientRemoteCall = function (
metadataCapture: any,
grpcClient: typeof grpcTypes,
original: GrpcClientFunc,
args: any[],
Expand Down Expand Up @@ -102,6 +103,16 @@ export const makeGrpcClientRemoteCall = function (
setSpanContext(metadata);
const call = original.apply(self, args);

((call as unknown) as events.EventEmitter).on(
'metadata',
responseMetadata => {
const metadataMap = responseMetadata.getMap();

metadataCapture.client.captureResponseMetadata(span, (metadataKey: string) => {
return metadataMap[metadataKey];
});
});

// if server stream or bidi
if (original.responseStream) {
// Both error and status events can be emitted
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ import {
serverStreamAndBidiHandler,
} from './serverUtils';
import { makeGrpcClientRemoteCall, getMetadata } from './clientUtils';
import { _extractMethodAndService, _methodIsIgnored } from '../utils';
import {_extractMethodAndService, _methodIsIgnored, metadataCapture} from '../utils';
import { SemanticAttributes } from '@opentelemetry/semantic-conventions';
import {AttributeValues} from '../enums/AttributeValues';

Expand All @@ -54,12 +54,15 @@ let grpcClient: typeof grpcTypes;
export class GrpcNativeInstrumentation extends InstrumentationBase<
typeof grpcTypes
> {
private _metadataCapture;

constructor(
name: string,
version: string,
config?: GrpcInstrumentationConfig
) {
super(name, version, config);
this._metadataCapture = this._createMetadataCapture();
}

init() {
Expand Down Expand Up @@ -105,6 +108,11 @@ export class GrpcNativeInstrumentation extends InstrumentationBase<
return super.getConfig();
}

override setConfig(config?: GrpcInstrumentationConfig): void {
super.setConfig(config);
this._metadataCapture = this._createMetadataCapture();
}

private _getInternalPatchs() {
const onPatch = (
moduleExports: GrpcInternalClientTypes,
Expand Down Expand Up @@ -306,8 +314,16 @@ export class GrpcNativeInstrumentation extends InstrumentationBase<
[SemanticAttributes.RPC_METHOD]: method,
[SemanticAttributes.RPC_SERVICE]: service,
});

instrumentation._metadataCapture.client.captureRequestMetadata(span, (metadataKey: string) => {
const metadataMap = metadata.getMap();

return metadataMap[metadataKey];
});

return context.with(trace.setSpan(context.active(), span), () =>
makeGrpcClientRemoteCall(
instrumentation._metadataCapture,
grpcClient,
original,
args,
Expand All @@ -320,4 +336,15 @@ export class GrpcNativeInstrumentation extends InstrumentationBase<
return clientMethodTrace;
};
}

private _createMetadataCapture() {
const config = this.getConfig();

return {
client: {
captureRequestMetadata: metadataCapture('request', config.metadataToSpanAttributes?.client?.requestMetadata ?? []),
captureResponseMetadata: metadataCapture('response', config.metadataToSpanAttributes?.client?.responseMetadata ?? [])
}
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,11 @@ export interface GrpcInstrumentationConfig extends InstrumentationConfig {
* the IgnoreMatchers in the ignoreGrpcMethods list
*/
ignoreGrpcMethods?: IgnoreMatcher[];
/** Map the following gRPC metadata to span attributes. */
metadataToSpanAttributes?: {
client?: {
responseMetadata?: string[],
requestMetadata?: string[];
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@
* limitations under the License.
*/

import { SpanStatusCode, SpanStatus } from '@opentelemetry/api';
import {SpanStatusCode, SpanStatus, Span} from '@opentelemetry/api';
import type * as grpcTypes from 'grpc';
import type * as grpcJsTypes from '@grpc/grpc-js';
import { IgnoreMatcher } from './types';
import {IgnoreMatcher} from './types';
samimusallam marked this conversation as resolved.
Show resolved Hide resolved

// Equivalent to lodash _.findIndex
export const findIndex: <T>(args: T[], fn: (arg: T) => boolean) => number = (
Expand Down Expand Up @@ -110,3 +110,29 @@ export const _extractMethodAndService = (name: string): { service: string, metho
method
});
};


export function metadataCapture(type: 'request' | 'response', metadata: string[]) {
const normalizedMetadataAttributes = new Map(metadata.map(value => [value.toLowerCase(), value.toLowerCase().replace(/-/g, '_')]));

return (span: Span, getMetadata: (key: string) => undefined | string | string[] | Buffer) => {
legendecas marked this conversation as resolved.
Show resolved Hide resolved
for (const [capturedMetadata, normalizedMetadata] of normalizedMetadataAttributes) {
const value = getMetadata(capturedMetadata);

if (value === undefined || value instanceof Buffer) {
continue;
}

const key = `rpc.${type}.metadata.${normalizedMetadata}`;

if (typeof value === 'string') {
span.setAttribute(key, [value]);
} else if (Array.isArray(value)) {
span.setAttribute(key, value);
} else {
span.setAttribute(key, [value]);
}
}
};
}

Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ syntax = "proto3";
package pkg_test;

service GrpcTester {
rpc unaryMethodWithMetadata (TestRequest) returns (TestReply) {}
rpc UnaryMethod (TestRequest) returns (TestReply) {}
rpc camelCaseMethod (TestRequest) returns (TestReply) {}
rpc ClientStreamMethod (stream TestRequest) returns (TestReply) {}
Expand Down
Loading