Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@opentelemetry/instrumentation-grpc

Package Overview
Dependencies
Maintainers
3
Versions
186
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@opentelemetry/instrumentation-grpc - npm Package Compare versions

Comparing version 0.41.1 to 0.41.2

20

build/src/grpc-js/clientUtils.d.ts

@@ -7,3 +7,3 @@ /// <reference types="node" />

import type { GrpcJsInstrumentation } from './';
import type { GrpcClientFunc } from './types';
import type { GrpcClientFunc, SendUnaryDataCallback } from './types';
import type { metadataCaptureType } from '../internal-types';

@@ -20,11 +20,25 @@ /**

/**
* Patches a callback so that the current span for this trace is also ended
* when the callback is invoked.
*/
export declare function patchedCallback(span: Span, callback: SendUnaryDataCallback<ResponseType>): SendUnaryDataCallback<ResponseType>;
export declare function patchResponseMetadataEvent(span: Span, call: EventEmitter, metadataCapture: metadataCaptureType): void;
export declare function patchResponseStreamEvents(span: Span, call: EventEmitter): void;
/**
* Execute grpc client call. Apply completitionspan properties and end the
* span on callback or receiving an emitted event.
*/
export declare function makeGrpcClientRemoteCall(metadataCapture: metadataCaptureType, original: GrpcClientFunc, args: unknown[], metadata: Metadata, self: Client): (span: Span) => EventEmitter;
export declare function makeGrpcClientRemoteCall(metadataCapture: metadataCaptureType, original: GrpcClientFunc, args: unknown[], metadata: grpcJs.Metadata, self: grpcJs.Client): (span: Span) => EventEmitter;
export declare function getMetadataIndex(args: Array<unknown | Metadata>): number;
/**
* Returns the metadata argument from user provided arguments (`args`)
* If no metadata is provided in `args`: adds empty metadata to `args` and returns that empty metadata
*/
export declare function getMetadata(this: GrpcJsInstrumentation, original: GrpcClientFunc, grpcClient: typeof grpcJs, args: Array<unknown | Metadata>): Metadata;
export declare function extractMetadataOrSplice(grpcLib: typeof grpcJs, args: Array<unknown | grpcJs.Metadata>, spliceIndex: number): Metadata;
/**
* Returns the metadata argument from user provided arguments (`args`)
* Adds empty metadata to arguments if the default is used.
*/
export declare function extractMetadataOrSpliceDefault(grpcClient: typeof grpcJs, original: GrpcClientFunc, args: Array<unknown | grpcJs.Metadata>): grpcJs.Metadata;
/**
* Inject opentelemetry trace context into `metadata` for use by another

@@ -31,0 +45,0 @@ * grpc receiver

172

build/src/grpc-js/clientUtils.js

@@ -18,9 +18,9 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.setSpanContext = exports.getMetadata = exports.makeGrpcClientRemoteCall = exports.getMethodsToWrap = void 0;
exports.setSpanContext = exports.extractMetadataOrSpliceDefault = exports.extractMetadataOrSplice = exports.getMetadataIndex = exports.makeGrpcClientRemoteCall = exports.patchResponseStreamEvents = exports.patchResponseMetadataEvent = exports.patchedCallback = exports.getMethodsToWrap = void 0;
const api_1 = require("@opentelemetry/api");
const semantic_conventions_1 = require("@opentelemetry/semantic-conventions");
const serverUtils_1 = require("./serverUtils");
const AttributeNames_1 = require("../enums/AttributeNames");
const status_code_1 = require("../status-code");
const utils_1 = require("../utils");
const events_1 = require("events");
/**

@@ -50,2 +50,69 @@ * Parse a package method list and return a list of methods to patch

/**
* Patches a callback so that the current span for this trace is also ended
* when the callback is invoked.
*/
function patchedCallback(span, callback) {
const wrappedFn = (err, res) => {
if (err) {
if (err.code) {
span.setStatus((0, utils_1._grpcStatusCodeToSpanStatus)(err.code));
span.setAttribute(semantic_conventions_1.SemanticAttributes.RPC_GRPC_STATUS_CODE, err.code);
}
span.setAttributes({
[AttributeNames_1.AttributeNames.GRPC_ERROR_NAME]: err.name,
[AttributeNames_1.AttributeNames.GRPC_ERROR_MESSAGE]: err.message,
});
}
else {
span.setAttribute(semantic_conventions_1.SemanticAttributes.RPC_GRPC_STATUS_CODE, status_code_1.GRPC_STATUS_CODE_OK);
}
span.end();
callback(err, res);
};
return api_1.context.bind(api_1.context.active(), wrappedFn);
}
exports.patchedCallback = patchedCallback;
function patchResponseMetadataEvent(span, call, metadataCapture) {
call.on('metadata', (responseMetadata) => {
metadataCapture.client.captureResponseMetadata(span, responseMetadata);
});
}
exports.patchResponseMetadataEvent = patchResponseMetadataEvent;
function patchResponseStreamEvents(span, call) {
// Both error and status events can be emitted
// the first one emitted set spanEnded to true
let spanEnded = false;
const endSpan = () => {
if (!spanEnded) {
span.end();
spanEnded = true;
}
};
api_1.context.bind(api_1.context.active(), call);
call.on(events_1.errorMonitor, (err) => {
if (spanEnded) {
return;
}
span.setStatus({
code: (0, utils_1._grpcStatusCodeToOpenTelemetryStatusCode)(err.code),
message: err.message,
});
span.setAttributes({
[AttributeNames_1.AttributeNames.GRPC_ERROR_NAME]: err.name,
[AttributeNames_1.AttributeNames.GRPC_ERROR_MESSAGE]: err.message,
[semantic_conventions_1.SemanticAttributes.RPC_GRPC_STATUS_CODE]: err.code,
});
endSpan();
});
call.on('status', (status) => {
if (spanEnded) {
return;
}
span.setStatus((0, utils_1._grpcStatusCodeToSpanStatus)(status.code));
span.setAttribute(semantic_conventions_1.SemanticAttributes.RPC_GRPC_STATUS_CODE, status.code);
endSpan();
});
}
exports.patchResponseStreamEvents = patchResponseStreamEvents;
/**
* Execute grpc client call. Apply completitionspan properties and end the

@@ -55,27 +122,2 @@ * span on callback or receiving an emitted event.

function makeGrpcClientRemoteCall(metadataCapture, original, args, metadata, self) {
/**
* Patches a callback so that the current span for this trace is also ended
* when the callback is invoked.
*/
function patchedCallback(span, callback) {
const wrappedFn = (err, res) => {
if (err) {
if (err.code) {
span.setStatus((0, utils_1._grpcStatusCodeToSpanStatus)(err.code));
span.setAttribute(semantic_conventions_1.SemanticAttributes.RPC_GRPC_STATUS_CODE, err.code);
}
span.setAttributes({
[AttributeNames_1.AttributeNames.GRPC_ERROR_NAME]: err.name,
[AttributeNames_1.AttributeNames.GRPC_ERROR_MESSAGE]: err.message,
});
}
else {
span.setStatus({ code: api_1.SpanStatusCode.UNSET });
span.setAttribute(semantic_conventions_1.SemanticAttributes.RPC_GRPC_STATUS_CODE, status_code_1.GRPC_STATUS_CODE_OK);
}
span.end();
callback(err, res);
};
return api_1.context.bind(api_1.context.active(), wrappedFn);
}
return (span) => {

@@ -98,37 +140,3 @@ // if unary or clientStream

if (original.responseStream) {
// Both error and status events can be emitted
// the first one emitted set spanEnded to true
let spanEnded = false;
const endSpan = () => {
if (!spanEnded) {
span.end();
spanEnded = true;
}
};
api_1.context.bind(api_1.context.active(), call);
call.on('error', (err) => {
if (call[serverUtils_1.CALL_SPAN_ENDED]) {
return;
}
call[serverUtils_1.CALL_SPAN_ENDED] = true;
span.setStatus({
code: (0, utils_1._grpcStatusCodeToOpenTelemetryStatusCode)(err.code),
message: err.message,
});
span.setAttributes({
[AttributeNames_1.AttributeNames.GRPC_ERROR_NAME]: err.name,
[AttributeNames_1.AttributeNames.GRPC_ERROR_MESSAGE]: err.message,
[semantic_conventions_1.SemanticAttributes.RPC_GRPC_STATUS_CODE]: err.code,
});
endSpan();
});
call.on('status', (status) => {
if (call[serverUtils_1.CALL_SPAN_ENDED]) {
return;
}
call[serverUtils_1.CALL_SPAN_ENDED] = true;
span.setStatus((0, utils_1._grpcStatusCodeToSpanStatus)(status.code));
span.setAttribute(semantic_conventions_1.SemanticAttributes.RPC_GRPC_STATUS_CODE, status.code);
endSpan();
});
patchResponseStreamEvents(span, call);
}

@@ -139,7 +147,3 @@ return call;

exports.makeGrpcClientRemoteCall = makeGrpcClientRemoteCall;
/**
* Returns the metadata argument from user provided arguments (`args`)
*/
function getMetadata(original, grpcClient, args) {
let metadata;
function getMetadataIndex(args) {
// This finds an instance of Metadata among the arguments.

@@ -149,3 +153,3 @@ // A possible issue that could occur is if the 'options' parameter from

// but this is an extremely rare case.
let metadataIndex = args.findIndex((arg) => {
return args.findIndex((arg) => {
return (arg &&

@@ -156,13 +160,15 @@ typeof arg === 'object' &&

});
}
exports.getMetadataIndex = getMetadataIndex;
/**
* Returns the metadata argument from user provided arguments (`args`)
* If no metadata is provided in `args`: adds empty metadata to `args` and returns that empty metadata
*/
function extractMetadataOrSplice(grpcLib, args, spliceIndex) {
let metadata;
const metadataIndex = getMetadataIndex(args);
if (metadataIndex === -1) {
metadata = new grpcClient.Metadata();
if (!original.requestStream) {
// unary or server stream
metadataIndex = 1;
}
else {
// client stream or bidi
metadataIndex = 0;
}
args.splice(metadataIndex, 0, metadata);
// Create metadata if it does not exist
metadata = new grpcLib.Metadata();
args.splice(spliceIndex, 0, metadata);
}

@@ -174,4 +180,12 @@ else {

}
exports.getMetadata = getMetadata;
exports.extractMetadataOrSplice = extractMetadataOrSplice;
/**
* Returns the metadata argument from user provided arguments (`args`)
* Adds empty metadata to arguments if the default is used.
*/
function extractMetadataOrSpliceDefault(grpcClient, original, args) {
return extractMetadataOrSplice(grpcClient, args, original.requestStream ? 0 : 1);
}
exports.extractMetadataOrSpliceDefault = extractMetadataOrSpliceDefault;
/**
* Inject opentelemetry trace context into `metadata` for use by another

@@ -178,0 +192,0 @@ * grpc receiver

@@ -16,2 +16,8 @@ import type * as grpcJs from '@grpc/grpc-js';

/**
* Patch for grpc.Client.make*Request(...) functions.
* Provides auto-instrumentation for client requests when using a Client without
* makeGenericClientConstructor/makeClientConstructor
*/
private _patchClientRequestMethod;
/**
* Entry point for applying client patches to `grpc.makeClientConstructor(...)` equivalents

@@ -30,2 +36,5 @@ * @param this GrpcJsPlugin

private _getPatchedClientMethods;
private _splitMethodString;
private createClientSpan;
private extractNetMetadata;
/**

@@ -32,0 +41,0 @@ * Utility function to patch *all* functions loaded through a proto file.

@@ -53,2 +53,12 @@ "use strict";

this._wrap(moduleExports, 'loadPackageDefinition', this._patchLoadPackageDefinition(moduleExports));
if ((0, instrumentation_1.isWrapped)(moduleExports.Client.prototype)) {
this._unwrap(moduleExports.Client.prototype, 'makeUnaryRequest');
this._unwrap(moduleExports.Client.prototype, 'makeClientStreamRequest');
this._unwrap(moduleExports.Client.prototype, 'makeServerStreamRequest');
this._unwrap(moduleExports.Client.prototype, 'makeBidiStreamRequest');
}
this._wrap(moduleExports.Client.prototype, 'makeUnaryRequest', this._patchClientRequestMethod(moduleExports, false));
this._wrap(moduleExports.Client.prototype, 'makeClientStreamRequest', this._patchClientRequestMethod(moduleExports, false));
this._wrap(moduleExports.Client.prototype, 'makeServerStreamRequest', this._patchClientRequestMethod(moduleExports, true));
this._wrap(moduleExports.Client.prototype, 'makeBidiStreamRequest', this._patchClientRequestMethod(moduleExports, true));
return moduleExports;

@@ -63,2 +73,6 @@ }, (moduleExports, version) => {

this._unwrap(moduleExports, 'loadPackageDefinition');
this._unwrap(moduleExports.Client.prototype, 'makeUnaryRequest');
this._unwrap(moduleExports.Client.prototype, 'makeClientStreamRequest');
this._unwrap(moduleExports.Client.prototype, 'makeServerStreamRequest');
this._unwrap(moduleExports.Client.prototype, 'makeBidiStreamRequest');
}),

@@ -125,2 +139,48 @@ ];

/**
* Patch for grpc.Client.make*Request(...) functions.
* Provides auto-instrumentation for client requests when using a Client without
* makeGenericClientConstructor/makeClientConstructor
*/
_patchClientRequestMethod(grpcLib, hasResponseStream) {
const instrumentation = this;
return (original) => {
instrumentation._diag.debug('patched makeClientStreamRequest on grpc client');
return function makeClientStreamRequest() {
// method must always be at first position
const method = arguments[0];
const { name, service, methodAttributeValue } = instrumentation._splitMethodString(method);
// Do not attempt to trace/inject context if method is ignored
if (method != null &&
(0, utils_1._methodIsIgnored)(methodAttributeValue, instrumentation.getConfig().ignoreGrpcMethods)) {
return original.apply(this, [...arguments]);
}
const modifiedArgs = [...arguments];
const metadata = (0, clientUtils_1.extractMetadataOrSplice)(grpcLib, modifiedArgs, 4);
const span = instrumentation.createClientSpan(name, methodAttributeValue, service, metadata);
instrumentation.extractNetMetadata(this, span);
// Callback is only present when there is no responseStream
if (!hasResponseStream) {
// Replace the callback with the patched one if it is there.
// If the callback arg is not a function on the last position then the client will throw
// and never call the callback -> so there's nothing to patch
const lastArgIndex = modifiedArgs.length - 1;
const callback = modifiedArgs[lastArgIndex];
if (typeof callback === 'function') {
modifiedArgs[lastArgIndex] = (0, clientUtils_1.patchedCallback)(span, callback);
}
}
return api_1.context.with(api_1.trace.setSpan(api_1.context.active(), span), () => {
(0, clientUtils_1.setSpanContext)(metadata);
const call = original.apply(this, [...modifiedArgs]);
(0, clientUtils_1.patchResponseMetadataEvent)(span, call, instrumentation._metadataCapture);
// Subscribe to response stream events when there's a response stream.
if (hasResponseStream) {
(0, clientUtils_1.patchResponseStreamEvents)(span, call);
}
return call;
});
};
};
}
/**
* Entry point for applying client patches to `grpc.makeClientConstructor(...)` equivalents

@@ -165,3 +225,3 @@ * @param this GrpcJsPlugin

const args = [...arguments];
const metadata = clientUtils_1.getMetadata.call(instrumentation, original, grpcClient, args);
const metadata = clientUtils_1.extractMetadataOrSpliceDefault.call(instrumentation, grpcClient, original, args);
const { service, method } = (0, utils_1._extractMethodAndService)(original.path);

@@ -175,8 +235,3 @@ const span = instrumentation.tracer

});
// set net.peer.* from target (e.g., "dns:otel-productcatalogservice:8080") as a hint to APMs
const parsedUri = utils_1.URI_REGEX.exec(this.getChannel().getTarget());
if (parsedUri != null && parsedUri.groups != null) {
span.setAttribute(semantic_conventions_1.SemanticAttributes.NET_PEER_NAME, parsedUri.groups['name']);
span.setAttribute(semantic_conventions_1.SemanticAttributes.NET_PEER_PORT, parseInt(parsedUri.groups['port']));
}
instrumentation.extractNetMetadata(this, span);
instrumentation._metadataCapture.client.captureRequestMetadata(span, metadata);

@@ -189,2 +244,31 @@ return api_1.context.with(api_1.trace.setSpan(api_1.context.active(), span), () => (0, clientUtils_1.makeGrpcClientRemoteCall)(instrumentation._metadataCapture, original, args, metadata, this)(span));

}
_splitMethodString(method) {
if (method == null) {
return { name: '', service: '', methodAttributeValue: '' };
}
const name = `grpc.${method.replace('/', '')}`;
const { service, method: methodAttributeValue } = (0, utils_1._extractMethodAndService)(method);
return { name, service, methodAttributeValue };
}
createClientSpan(name, methodAttributeValue, service, metadata) {
const span = this.tracer
.startSpan(name, { kind: api_1.SpanKind.CLIENT })
.setAttributes({
[semantic_conventions_1.SemanticAttributes.RPC_SYSTEM]: 'grpc',
[semantic_conventions_1.SemanticAttributes.RPC_METHOD]: methodAttributeValue,
[semantic_conventions_1.SemanticAttributes.RPC_SERVICE]: service,
});
if (metadata != null) {
this._metadataCapture.client.captureRequestMetadata(span, metadata);
}
return span;
}
extractNetMetadata(client, span) {
// set net.peer.* from target (e.g., "dns:otel-productcatalogservice:8080") as a hint to APMs
const parsedUri = utils_1.URI_REGEX.exec(client.getChannel().getTarget());
if (parsedUri != null && parsedUri.groups != null) {
span.setAttribute(semantic_conventions_1.SemanticAttributes.NET_PEER_NAME, parsedUri.groups['name']);
span.setAttribute(semantic_conventions_1.SemanticAttributes.NET_PEER_PORT, parseInt(parsedUri.groups['port']));
}
}
/**

@@ -191,0 +275,0 @@ * Utility function to patch *all* functions loaded through a proto file.

@@ -34,2 +34,3 @@ /// <reference types="node" />

export declare type ServerRegisterFunction = typeof Server.prototype.register;
export declare type ClientRequestFunction<ReturnType> = (...args: unknown[]) => ReturnType;
export declare type MakeClientConstructorFunction = typeof makeGenericClientConstructor;

@@ -36,0 +37,0 @@ export type { HandleCall } from '@grpc/grpc-js/build/src/server-call';

@@ -1,2 +0,2 @@

export declare const VERSION = "0.41.1";
export declare const VERSION = "0.41.2";
//# sourceMappingURL=version.d.ts.map

@@ -20,3 +20,3 @@ "use strict";

// this is autogenerated file, see scripts/version-update.js
exports.VERSION = '0.41.1';
exports.VERSION = '0.41.2';
//# sourceMappingURL=version.js.map
{
"name": "@opentelemetry/instrumentation-grpc",
"version": "0.41.1",
"version": "0.41.2",
"description": "OpenTelemetry grpc automatic instrumentation package.",

@@ -12,3 +12,3 @@ "main": "build/src/index.js",

"clean": "tsc --build --clean",
"test": "nyc ts-mocha -p tsconfig.json test/**/*.test.ts",
"test": "npm run protos:generate && nyc ts-mocha -p tsconfig.json test/**/*.test.ts",
"tdd": "npm run test -- --watch-extensions ts --watch",

@@ -22,3 +22,4 @@ "lint": "eslint . --ext .ts",

"prewatch": "node ../../../scripts/version-update.js",
"peer-api-check": "node ../../../scripts/peer-api-check.js"
"peer-api-check": "node ../../../scripts/peer-api-check.js",
"protos:generate": "cd test/fixtures && buf generate"
},

@@ -50,16 +51,20 @@ "keywords": [

"devDependencies": {
"@bufbuild/buf": "1.21.0-1",
"@grpc/grpc-js": "^1.7.1",
"@grpc/proto-loader": "^0.7.3",
"@opentelemetry/api": "1.4.1",
"@opentelemetry/context-async-hooks": "1.15.1",
"@opentelemetry/core": "1.15.1",
"@opentelemetry/sdk-trace-base": "1.15.1",
"@opentelemetry/sdk-trace-node": "1.15.1",
"@opentelemetry/context-async-hooks": "1.15.2",
"@opentelemetry/core": "1.15.2",
"@opentelemetry/sdk-trace-base": "1.15.2",
"@opentelemetry/sdk-trace-node": "1.15.2",
"@protobuf-ts/grpc-transport": "2.9.1",
"@protobuf-ts/runtime": "2.9.1",
"@protobuf-ts/runtime-rpc": "2.9.1",
"@types/mocha": "10.0.1",
"@types/node": "18.6.5",
"@types/semver": "7.5.0",
"@types/sinon": "10.0.15",
"@types/sinon": "10.0.16",
"codecov": "3.8.3",
"cross-var": "1.1.0",
"lerna": "7.1.3",
"lerna": "7.1.4",
"mocha": "10.2.0",

@@ -76,8 +81,8 @@ "nyc": "15.1.0",

"dependencies": {
"@opentelemetry/instrumentation": "0.41.1",
"@opentelemetry/semantic-conventions": "1.15.1"
"@opentelemetry/instrumentation": "0.41.2",
"@opentelemetry/semantic-conventions": "1.15.2"
},
"homepage": "https://github.com/open-telemetry/opentelemetry-js/tree/main/experimental/packages/opentelemetry-instrumentation-grpc",
"sideEffects": false,
"gitHead": "9f71800fdc2a5ee5055684037a12498af71955f2"
"gitHead": "48fb15862e801b742059a3e39dbcc8ef4c10b2e2"
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc