diff --git a/examples/grpc/README.md b/examples/grpc/README.md deleted file mode 100644 index 1ec7a42a0e..0000000000 --- a/examples/grpc/README.md +++ /dev/null @@ -1,71 +0,0 @@ -# Overview - -OpenTelemetry gRPC Instrumentation allows the user to automatically collect trace data and export them to the backend of choice (we can use Zipkin or Jaeger for this example), to give observability to distributed systems. - -## Installation - -```sh -# from this directory -npm install -``` - -Setup [Zipkin Tracing](https://zipkin.io/pages/quickstart.html) -or -Setup [Jaeger Tracing](https://www.jaegertracing.io/docs/latest/getting-started/#all-in-one) - -## Run the Application - -### Zipkin - -- Run the server - - ```sh - # from this directory - npm run zipkin:server - ``` - -- Run the client - - ```sh - # from this directory - npm run zipkin:client - ``` - -#### Zipkin UI - -`zipkin:server` script should output the `traceid` in the terminal (e.g `traceid: 4815c3d576d930189725f1f1d1bdfcc6`). -Go to Zipkin with your browser (e.g - -

- -### Jaeger - -- Run the server - - ```sh - # from this directory - npm run jaeger:server - ``` - -- Run the client - - ```sh - # from this directory - npm run jaeger:client - ``` - -#### Jaeger UI - -`jaeger:server` script should output the `traceid` in the terminal (e.g `traceid: 4815c3d576d930189725f1f1d1bdfcc6`). -Go to Jaeger with your browser (e.g - -

- -## Useful links - -- For more information on OpenTelemetry, visit: -- For more information on OpenTelemetry for Node.js, visit: - -## LICENSE - -Apache License 2.0 diff --git a/examples/grpc/client.js b/examples/grpc/client.js deleted file mode 100644 index 18c7cf7354..0000000000 --- a/examples/grpc/client.js +++ /dev/null @@ -1,46 +0,0 @@ -'use strict'; - -const api = require('@opentelemetry/api'); -const tracer = require('./tracer')('example-grpc-client'); -const grpc = require('grpc'); -const messages = require('./helloworld_pb'); -const services = require('./helloworld_grpc_pb'); - -const PORT = 50051; - -/** A function which makes requests and handles response. */ -function main() { - // span corresponds to outgoing requests. Here, we have manually created - // the span, which is created to track work that happens outside of the - // request lifecycle entirely. - const span = tracer.startSpan('client.js:main()'); - api.context.with(api.trace.setSpan(api.context.active(), span), () => { - console.log('Client traceId ', span.spanContext().traceId); - const client = new services.GreeterClient( - `localhost:${PORT}`, - grpc.credentials.createInsecure(), - ); - const request = new messages.HelloRequest(); - let user; - if (process.argv.length >= 3) { - // eslint-disable-next-line prefer-destructuring - user = process.argv[2]; - } else { - user = 'world'; - } - request.setName(user); - client.sayHello(request, (err, response) => { - span.end(); - if (err) throw err; - console.log('Greeting:', response.getMessage()); - }); - }); - - // The process must live for at least the interval past any traces that - // must be exported, or some risk being lost if they are recorded after the - // last export. - console.log('Sleeping 5 seconds before shutdown to ensure all records are flushed.'); - setTimeout(() => { console.log('Completed.'); }, 5000); -} - -main(); diff --git a/examples/grpc/helloworld_grpc_pb.js b/examples/grpc/helloworld_grpc_pb.js deleted file mode 100644 index 1e39a0f46a..0000000000 --- a/examples/grpc/helloworld_grpc_pb.js +++ /dev/null @@ -1,64 +0,0 @@ -// GENERATED CODE -- DO NOT EDIT! - -// Original file comments: -// Copyright 2015 gRPC authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -'use strict'; - -const grpc = require('grpc'); -const helloworld_pb = require('./helloworld_pb.js'); - -function serialize_HelloReply(arg) { - if (!(arg instanceof helloworld_pb.HelloReply)) { - throw new Error('Expected argument of type HelloReply'); - } - return Buffer.from(arg.serializeBinary()); -} - -function deserialize_HelloReply(buffer_arg) { - return helloworld_pb.HelloReply.deserializeBinary(new Uint8Array(buffer_arg)); -} - -function serialize_HelloRequest(arg) { - if (!(arg instanceof helloworld_pb.HelloRequest)) { - throw new Error('Expected argument of type HelloRequest'); - } - return Buffer.from(arg.serializeBinary()); -} - -function deserialize_HelloRequest(buffer_arg) { - return helloworld_pb.HelloRequest.deserializeBinary( - new Uint8Array(buffer_arg), - ); -} - -// The greeting service definition. -const GreeterService = (exports.GreeterService = { - // Sends a greeting - sayHello: { - path: '/helloworld.Greeter/SayHello', - requestStream: false, - responseStream: false, - requestType: helloworld_pb.HelloRequest, - responseType: helloworld_pb.HelloReply, - requestSerialize: serialize_HelloRequest, - requestDeserialize: deserialize_HelloRequest, - responseSerialize: serialize_HelloReply, - responseDeserialize: deserialize_HelloReply, - }, -}); - -exports.GreeterClient = grpc.makeGenericClientConstructor(GreeterService); diff --git a/examples/grpc/helloworld_pb.js b/examples/grpc/helloworld_pb.js deleted file mode 100644 index 066acd68e8..0000000000 --- a/examples/grpc/helloworld_pb.js +++ /dev/null @@ -1,332 +0,0 @@ -/** - * @fileoverview - * @enhanceable - * @public - */ -// GENERATED CODE -- DO NOT EDIT! - -const jspb = require('google-protobuf'); - -const goog = jspb; -const global = Function('return this')(); - -goog.exportSymbol('proto.helloworld.HelloReply', null, global); -goog.exportSymbol('proto.helloworld.HelloRequest', null, global); - -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.helloworld.HelloRequest = function (opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.helloworld.HelloRequest, jspb.Message); -if (goog.DEBUG && !COMPILED) { - proto.helloworld.HelloRequest.displayName = 'proto.helloworld.HelloRequest'; -} - -if (jspb.Message.GENERATE_TO_OBJECT) { - /** - * Creates an object representation of this proto suitable for use in Soy templates. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS. - * @param {boolean=} opt_includeInstance Whether to include the JSPB instance - * for transitional soy proto support: http://goto/soy-param-migration - * @return {!Object} - */ - proto.helloworld.HelloRequest.prototype.toObject = function ( - opt_includeInstance, - ) { - return proto.helloworld.HelloRequest.toObject(opt_includeInstance, this); - }; - - /** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Whether to include the JSPB - * instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.helloworld.HelloRequest} msg The msg instance to transform. - * @return {!Object} - */ - proto.helloworld.HelloRequest.toObject = function (includeInstance, msg) { - let f; - - const obj = { - name: msg.getName(), - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; - }; -} - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.helloworld.HelloRequest} - */ -proto.helloworld.HelloRequest.deserializeBinary = function (bytes) { - const reader = new jspb.BinaryReader(bytes); - const msg = new proto.helloworld.HelloRequest(); - return proto.helloworld.HelloRequest.deserializeBinaryFromReader(msg, reader); -}; - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.helloworld.HelloRequest} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.helloworld.HelloRequest} - */ -proto.helloworld.HelloRequest.deserializeBinaryFromReader = function ( - msg, - reader, -) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - const field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = /** @type {string} */ (reader.readString()); - msg.setName(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - -/** - * Class method variant: serializes the given message to binary data - * (in protobuf wire format), writing to the given BinaryWriter. - * @param {!proto.helloworld.HelloRequest} message - * @param {!jspb.BinaryWriter} writer - */ -proto.helloworld.HelloRequest.serializeBinaryToWriter = function ( - message, - writer, -) { - message.serializeBinaryToWriter(writer); -}; - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.helloworld.HelloRequest.prototype.serializeBinary = function () { - const writer = new jspb.BinaryWriter(); - this.serializeBinaryToWriter(writer); - return writer.getResultBuffer(); -}; - -/** - * Serializes the message to binary data (in protobuf wire format), - * writing to the given BinaryWriter. - * @param {!jspb.BinaryWriter} writer - */ -proto.helloworld.HelloRequest.prototype.serializeBinaryToWriter = function ( - writer, -) { - let f; - f = this.getName(); - if (f.length > 0) { - writer.writeString(1, f); - } -}; - -/** - * Creates a deep clone of this proto. No data is shared with the original. - * @return {!proto.helloworld.HelloRequest} The clone. - */ -proto.helloworld.HelloRequest.prototype.cloneMessage = function () { - return /** @type {!proto.helloworld.HelloRequest} */ (jspb.Message.cloneMessage( - this, - )); -}; - -/** - * optional string name = 1; - * @return {string} - */ -proto.helloworld.HelloRequest.prototype.getName = function () { - return /** @type {string} */ (jspb.Message.getFieldProto3(this, 1, '')); -}; - -/** @param {string} value */ -proto.helloworld.HelloRequest.prototype.setName = function (value) { - jspb.Message.setField(this, 1, value); -}; - -/** - * Generated by JsPbCodeGenerator. - * @param {Array=} opt_data Optional initial data array, typically from a - * server response, or constructed directly in Javascript. The array is used - * in place and becomes part of the constructed object. It is not cloned. - * If no data is provided, the constructed object will be empty, but still - * valid. - * @extends {jspb.Message} - * @constructor - */ -proto.helloworld.HelloReply = function (opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.helloworld.HelloReply, jspb.Message); -if (goog.DEBUG && !COMPILED) { - proto.helloworld.HelloReply.displayName = 'proto.helloworld.HelloReply'; -} - -if (jspb.Message.GENERATE_TO_OBJECT) { - /** - * Creates an object representation of this proto suitable for use in Soy templates. - * Field names that are reserved in JavaScript and will be renamed to pb_name. - * To access a reserved field use, foo.pb_, eg, foo.pb_default. - * For the list of reserved names please see: - * com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS. - * @param {boolean=} opt_includeInstance Whether to include the JSPB instance - * for transitional soy proto support: http://goto/soy-param-migration - * @return {!Object} - */ - proto.helloworld.HelloReply.prototype.toObject = function ( - opt_includeInstance, - ) { - return proto.helloworld.HelloReply.toObject(opt_includeInstance, this); - }; - - /** - * Static version of the {@see toObject} method. - * @param {boolean|undefined} includeInstance Whether to include the JSPB - * instance for transitional soy proto support: - * http://goto/soy-param-migration - * @param {!proto.helloworld.HelloReply} msg The msg instance to transform. - * @return {!Object} - */ - proto.helloworld.HelloReply.toObject = function (includeInstance, msg) { - let f; - - const obj = { - message: msg.getMessage(), - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; - }; -} - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.helloworld.HelloReply} - */ -proto.helloworld.HelloReply.deserializeBinary = function (bytes) { - const reader = new jspb.BinaryReader(bytes); - const msg = new proto.helloworld.HelloReply(); - return proto.helloworld.HelloReply.deserializeBinaryFromReader(msg, reader); -}; - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.helloworld.HelloReply} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.helloworld.HelloReply} - */ -proto.helloworld.HelloReply.deserializeBinaryFromReader = function ( - msg, - reader, -) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - const field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = /** @type {string} */ (reader.readString()); - msg.setMessage(value); - break; - default: - reader.skipField(); - break; - } - } - return msg; -}; - -/** - * Class method variant: serializes the given message to binary data - * (in protobuf wire format), writing to the given BinaryWriter. - * @param {!proto.helloworld.HelloReply} message - * @param {!jspb.BinaryWriter} writer - */ -proto.helloworld.HelloReply.serializeBinaryToWriter = function ( - message, - writer, -) { - message.serializeBinaryToWriter(writer); -}; - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.helloworld.HelloReply.prototype.serializeBinary = function () { - const writer = new jspb.BinaryWriter(); - this.serializeBinaryToWriter(writer); - return writer.getResultBuffer(); -}; - -/** - * Serializes the message to binary data (in protobuf wire format), - * writing to the given BinaryWriter. - * @param {!jspb.BinaryWriter} writer - */ -proto.helloworld.HelloReply.prototype.serializeBinaryToWriter = function ( - writer, -) { - let f; - f = this.getMessage(); - if (f.length > 0) { - writer.writeString(1, f); - } -}; - -/** - * Creates a deep clone of this proto. No data is shared with the original. - * @return {!proto.helloworld.HelloReply} The clone. - */ -proto.helloworld.HelloReply.prototype.cloneMessage = function () { - return /** @type {!proto.helloworld.HelloReply} */ (jspb.Message.cloneMessage( - this, - )); -}; - -/** - * optional string message = 1; - * @return {string} - */ -proto.helloworld.HelloReply.prototype.getMessage = function () { - return /** @type {string} */ (jspb.Message.getFieldProto3(this, 1, '')); -}; - -/** @param {string} value */ -proto.helloworld.HelloReply.prototype.setMessage = function (value) { - jspb.Message.setField(this, 1, value); -}; - -goog.object.extend(exports, proto.helloworld); diff --git a/examples/grpc/images/jaeger.png b/examples/grpc/images/jaeger.png deleted file mode 100644 index 20eead3ba3..0000000000 Binary files a/examples/grpc/images/jaeger.png and /dev/null differ diff --git a/examples/grpc/images/zipkin.png b/examples/grpc/images/zipkin.png deleted file mode 100644 index d1dcd125a7..0000000000 Binary files a/examples/grpc/images/zipkin.png and /dev/null differ diff --git a/examples/grpc/package.json b/examples/grpc/package.json deleted file mode 100644 index d33861fccf..0000000000 --- a/examples/grpc/package.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "name": "grpc-example", - "private": true, - "version": "0.25.0", - "description": "Example of gRPC integration with OpenTelemetry", - "main": "index.js", - "scripts": { - "zipkin:server": "cross-env EXPORTER=zipkin node ./server.js", - "zipkin:client": "cross-env EXPORTER=zipkin node ./client.js", - "jaeger:server": "cross-env EXPORTER=jaeger node ./server.js", - "jaeger:client": "cross-env EXPORTER=jaeger node ./client.js" - }, - "repository": { - "type": "git", - "url": "git+ssh://git@github.com/open-telemetry/opentelemetry-js.git" - }, - "keywords": [ - "opentelemetry", - "grpc", - "tracing" - ], - "engines": { - "node": ">=14" - }, - "author": "OpenTelemetry Authors", - "license": "Apache-2.0", - "bugs": { - "url": "https://github.com/open-telemetry/opentelemetry-js/issues" - }, - "dependencies": { - "@opentelemetry/api": "^1.0.2", - "@opentelemetry/exporter-jaeger": "^1.0.1", - "@opentelemetry/exporter-zipkin": "^1.0.1", - "@opentelemetry/instrumentation": "^0.27.0", - "@opentelemetry/instrumentation-grpc": "^0.27.0", - "@opentelemetry/resources": "^1.0.1", - "@opentelemetry/semantic-conventions": "^1.0.1", - "@opentelemetry/sdk-trace-base": "^1.0.1", - "@opentelemetry/sdk-trace-node": "^1.0.1", - "google-protobuf": "^3.9.2", - "grpc": "^1.23.3", - "node-pre-gyp": "0.14.0" - }, - "homepage": "https://github.com/open-telemetry/opentelemetry-js/tree/main/examples/grpc", - "devDependencies": { - "cross-env": "^6.0.0" - } -} diff --git a/examples/grpc/server.js b/examples/grpc/server.js deleted file mode 100644 index 6cb34dee5e..0000000000 --- a/examples/grpc/server.js +++ /dev/null @@ -1,38 +0,0 @@ -'use strict'; - -const api = require('@opentelemetry/api'); -const tracer = require('./tracer')(('example-grpc-server')); -const grpc = require('grpc'); - -const messages = require('./helloworld_pb'); -const services = require('./helloworld_grpc_pb'); - -const PORT = 50051; - -/** Starts a gRPC server that receives requests on sample server port. */ -function startServer() { - // Creates a server - const server = new grpc.Server(); - server.addService(services.GreeterService, { sayHello }); - server.bind(`0.0.0.0:${PORT}`, grpc.ServerCredentials.createInsecure()); - console.log(`binding server on 0.0.0.0:${PORT}`); - server.start(); -} - -function sayHello(call, callback) { - const currentSpan = api.trace.getSpan(api.context.active()); - // display traceid in the terminal - console.log(`traceid: ${currentSpan.spanContext().traceId}`); - const span = tracer.startSpan('server.js:sayHello()', { - parent: currentSpan, - kind: 1, // server - attributes: { key: 'value' }, - }); - span.addEvent(`invoking sayHello() to ${call.request.getName()}`); - const reply = new messages.HelloReply(); - reply.setMessage(`Hello ${call.request.getName()}`); - callback(null, reply); - span.end(); -} - -startServer(); diff --git a/examples/grpc/tracer.js b/examples/grpc/tracer.js deleted file mode 100644 index 3dd3adddc7..0000000000 --- a/examples/grpc/tracer.js +++ /dev/null @@ -1,41 +0,0 @@ -'use strict'; - -const opentelemetry = require('@opentelemetry/api'); -const { registerInstrumentations } = require('@opentelemetry/instrumentation'); -const { NodeTracerProvider } = require('@opentelemetry/sdk-trace-node'); -const { Resource } = require('@opentelemetry/resources'); -const { SemanticResourceAttributes } = require('@opentelemetry/semantic-conventions'); -const { SimpleSpanProcessor } = require('@opentelemetry/sdk-trace-base'); -const { JaegerExporter } = require('@opentelemetry/exporter-jaeger'); -const { ZipkinExporter } = require('@opentelemetry/exporter-zipkin'); -const { GrpcInstrumentation } = require('@opentelemetry/instrumentation-grpc'); - -const EXPORTER = process.env.EXPORTER || ''; - -module.exports = (serviceName) => { - const provider = new NodeTracerProvider({ - resource: new Resource({ - [SemanticResourceAttributes.SERVICE_NAME]: serviceName, - }), - }); - - let exporter; - if (EXPORTER.toLowerCase().startsWith('z')) { - exporter = new ZipkinExporter(); - } else { - exporter = new JaegerExporter(); - } - - provider.addSpanProcessor(new SimpleSpanProcessor(exporter)); - - // Initialize the OpenTelemetry APIs to use the NodeTracerProvider bindings - provider.register(); - - registerInstrumentations({ - instrumentations: [ - new GrpcInstrumentation(), - ], - }); - - return opentelemetry.trace.getTracer('grpc-example'); -}; diff --git a/experimental/CHANGELOG.md b/experimental/CHANGELOG.md index ff64e920fd..4d7da0576e 100644 --- a/experimental/CHANGELOG.md +++ b/experimental/CHANGELOG.md @@ -6,6 +6,8 @@ All notable changes to experimental packages in this project will be documented ### :boom: Breaking Change +* chore(instrumentation-grpc): Drop support for package `grpc`. [#3807](https://github.com/open-telemetry/opentelemetry-js/pull/3807) @llc1123 + ### :rocket: (Enhancement) ### :bug: (Bug Fix) diff --git a/experimental/packages/opentelemetry-instrumentation-grpc/README.md b/experimental/packages/opentelemetry-instrumentation-grpc/README.md index 2aa6038c03..8916054eb4 100644 --- a/experimental/packages/opentelemetry-instrumentation-grpc/README.md +++ b/experimental/packages/opentelemetry-instrumentation-grpc/README.md @@ -5,7 +5,7 @@ **Note: This is an experimental package under active development. New releases may include breaking changes.** -This module provides automatic instrumentation for [`grpc`](https://grpc.github.io/grpc/node/) and [`@grpc/grpc-js`](https://grpc.io/blog/grpc-js-1.0/). Currently, version [`1.x`](https://www.npmjs.com/package/grpc?activeTab=versions) of `grpc` and version [`1.x`](https://www.npmjs.com/package/@grpc/grpc-js?activeTab=versions) of `@grpc/grpc-js` is supported. +This module provides automatic instrumentation for [`@grpc/grpc-js`](https://grpc.io/blog/grpc-js-1.0/). Currently, version [`1.x`](https://www.npmjs.com/package/@grpc/grpc-js?activeTab=versions) of `@grpc/grpc-js` is supported. For automatic instrumentation see the [@opentelemetry/sdk-trace-node](https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-sdk-trace-node) package. @@ -18,7 +18,7 @@ npm install --save @opentelemetry/instrumentation-grpc ## Usage -OpenTelemetry gRPC Instrumentation allows the user to automatically collect trace data and export them to the backend of choice, to give observability to distributed systems when working with [gRPC](https://www.npmjs.com/package/grpc) or ([grpc-js](https://www.npmjs.com/package/@grpc/grpc-js)). +OpenTelemetry gRPC Instrumentation allows the user to automatically collect trace data and export them to the backend of choice, to give observability to distributed systems when working with ([grpc-js](https://www.npmjs.com/package/@grpc/grpc-js)). To load a specific instrumentation (**gRPC** in this case), specify it in the Node Tracer's configuration. @@ -38,15 +38,15 @@ registerInstrumentations({ ``` -See [examples/grpc](https://github.com/open-telemetry/opentelemetry-js/tree/main/examples/grpc) or [examples/grpc-js](https://github.com/open-telemetry/opentelemetry-js/tree/main/examples/grpc-js) for examples. +See [examples/grpc-js](https://github.com/open-telemetry/opentelemetry-js/tree/main/examples/grpc-js) for examples. ### gRPC Instrumentation Options 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 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/package.json b/experimental/packages/opentelemetry-instrumentation-grpc/package.json index 7bbfdb8b1d..3bba4ddee3 100644 --- a/experimental/packages/opentelemetry-instrumentation-grpc/package.json +++ b/experimental/packages/opentelemetry-instrumentation-grpc/package.json @@ -18,8 +18,7 @@ "watch": "tsc --build --watch", "precompile": "cross-var lerna run version --scope $npm_package_name --include-dependencies", "prewatch": "node ../../../scripts/version-update.js", - "peer-api-check": "node ../../../scripts/peer-api-check.js", - "postinstall": "node -e \"console.log(\\\"\\x1b[95m%s\\x1b[0m\\\", \\\"@opentelemetry/instrumentation-grpc - warning: The package 'grpc' (https://www.npmjs.com/package/grpc) is deprecated. It will no longer be instrumented in the next release of '@opentelemetry/instrumentation-grpc'. Please migrate to '@grpc/grpc-js' (https://www.npmjs.com/package/@grpc/grpc-js) to continue receiving telemetry.\\\");\"" + "peer-api-check": "node ../../../scripts/peer-api-check.js" }, "keywords": [ "opentelemetry", @@ -59,7 +58,6 @@ "@types/sinon": "10.0.15", "codecov": "3.8.3", "cross-var": "1.1.0", - "grpc": "1.24.11", "mocha": "10.2.0", "node-pre-gyp": "0.17.0", "nyc": "15.1.0", diff --git a/experimental/packages/opentelemetry-instrumentation-grpc/src/grpc-js/clientUtils.ts b/experimental/packages/opentelemetry-instrumentation-grpc/src/grpc-js/clientUtils.ts index 8c98a10936..1ffaab39bb 100644 --- a/experimental/packages/opentelemetry-instrumentation-grpc/src/grpc-js/clientUtils.ts +++ b/experimental/packages/opentelemetry-instrumentation-grpc/src/grpc-js/clientUtils.ts @@ -87,7 +87,7 @@ export function makeGrpcClientRemoteCall( ) { const wrappedFn: SendUnaryDataCallback = ( err: grpcJs.ServiceError | null, - res: any + res?: ResponseType ) => { if (err) { if (err.code) { @@ -226,6 +226,6 @@ export function getMetadata( */ export function setSpanContext(metadata: grpcJs.Metadata): void { propagation.inject(context.active(), metadata, { - set: (metadata, k, v) => metadata.set(k, v as grpcJs.MetadataValue), + set: (meta, k, v) => meta.set(k, v), }); } 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 6608521bd6..eaae47c8ef 100644 --- a/experimental/packages/opentelemetry-instrumentation-grpc/src/grpc-js/index.ts +++ b/experimental/packages/opentelemetry-instrumentation-grpc/src/grpc-js/index.ts @@ -80,7 +80,7 @@ export class GrpcJsInstrumentation extends InstrumentationBase { this._wrap( moduleExports.Server.prototype, 'register', - this._patchServer() as any + this._patchServer() ); // Patch Client methods if (isWrapped(moduleExports.makeGenericClientConstructor)) { diff --git a/experimental/packages/opentelemetry-instrumentation-grpc/src/grpc/clientUtils.ts b/experimental/packages/opentelemetry-instrumentation-grpc/src/grpc/clientUtils.ts deleted file mode 100644 index af56330a85..0000000000 --- a/experimental/packages/opentelemetry-instrumentation-grpc/src/grpc/clientUtils.ts +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type * as grpcTypes from 'grpc'; -import type * as events from 'events'; -import { SendUnaryDataCallback, GrpcClientFunc } from './types'; -import { SemanticAttributes } from '@opentelemetry/semantic-conventions'; -import { context, Span, SpanStatusCode, propagation } from '@opentelemetry/api'; -import { - _grpcStatusCodeToSpanStatus, - _grpcStatusCodeToOpenTelemetryStatusCode, - findIndex, -} from '../utils'; -import { AttributeNames } from '../enums/AttributeNames'; -import { metadataCaptureType } from '../internal-types'; -import { GRPC_STATUS_CODE_OK } from '../status-code'; - -/** - * This method handles the client remote call - */ -export const makeGrpcClientRemoteCall = function ( - metadataCapture: metadataCaptureType, - original: GrpcClientFunc, - args: any[], - metadata: grpcTypes.Metadata, - self: grpcTypes.Client -) { - /** - * Patches a callback so that the current span for this trace is also ended - * when the callback is invoked. - */ - function patchedCallback( - span: Span, - callback: SendUnaryDataCallback, - _metadata: grpcTypes.Metadata - ) { - const wrappedFn = (err: grpcTypes.ServiceError, res: any) => { - if (err) { - if (err.code) { - span.setStatus(_grpcStatusCodeToSpanStatus(err.code)); - span.setAttribute(SemanticAttributes.RPC_GRPC_STATUS_CODE, err.code); - } - span.setAttributes({ - [AttributeNames.GRPC_ERROR_NAME]: err.name, - [AttributeNames.GRPC_ERROR_MESSAGE]: err.message, - }); - } else { - span.setStatus({ code: SpanStatusCode.UNSET }); - span.setAttribute( - SemanticAttributes.RPC_GRPC_STATUS_CODE, - GRPC_STATUS_CODE_OK - ); - } - - span.end(); - callback(err, res); - }; - return context.bind(context.active(), wrappedFn); - } - - return (span: Span) => { - if (!span) { - return original.apply(self, args); - } - - // if unary or clientStream - if (!original.responseStream) { - const callbackFuncIndex = findIndex(args, arg => { - return typeof arg === 'function'; - }); - if (callbackFuncIndex !== -1) { - args[callbackFuncIndex] = patchedCallback( - span, - args[callbackFuncIndex], - metadata - ); - } - } - - span.addEvent('sent'); - - setSpanContext(metadata); - const call = original.apply(self, args); - - (call as unknown as events.EventEmitter).on( - 'metadata', - responseMetadata => { - metadataCapture.client.captureResponseMetadata(span, responseMetadata); - } - ); - - // if server stream or bidi - 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; - } - }; - context.bind(context.active(), call); - (call as unknown as events.EventEmitter).on( - 'error', - (err: grpcTypes.ServiceError) => { - span.setStatus({ - code: _grpcStatusCodeToOpenTelemetryStatusCode(err.code), - message: err.message, - }); - span.setAttributes({ - [AttributeNames.GRPC_ERROR_NAME]: err.name, - [AttributeNames.GRPC_ERROR_MESSAGE]: err.message, - }); - if (err.code != null) { - span.setAttribute( - SemanticAttributes.RPC_GRPC_STATUS_CODE, - err.code - ); - } - endSpan(); - } - ); - - (call as unknown as events.EventEmitter).on( - 'status', - (status: grpcTypes.StatusObject) => { - span.setStatus({ code: SpanStatusCode.UNSET }); - span.setAttribute( - SemanticAttributes.RPC_GRPC_STATUS_CODE, - status.code - ); - endSpan(); - } - ); - } - return call; - }; -}; - -export const getMetadata = function ( - grpcClient: typeof grpcTypes, - original: GrpcClientFunc, - args: any[] -): grpcTypes.Metadata { - let metadata: grpcTypes.Metadata; - - // This finds an instance of Metadata among the arguments. - // A possible issue that could occur is if the 'options' parameter from - // the user contains an '_internal_repr' as well as a 'getMap' function, - // but this is an extremely rare case. - let metadataIndex = findIndex(args, (arg: any) => { - return ( - arg && - typeof arg === 'object' && - arg._internal_repr && - typeof arg.getMap === 'function' - ); - }); - if (metadataIndex === -1) { - metadata = new grpcClient.Metadata(); - if (!original.requestStream) { - // unary or server stream - if (args.length === 0) { - // No argument (for the gRPC call) was provided, so we will have to - // provide one, since metadata cannot be the first argument. - // The internal representation of argument defaults to undefined - // in its non-presence. - // Note that we can't pass null instead of undefined because the - // serializer within gRPC doesn't accept it. - args.push(undefined); - } - metadataIndex = 1; - } else { - // client stream or bidi - metadataIndex = 0; - } - args.splice(metadataIndex, 0, metadata); - } else { - metadata = args[metadataIndex]; - } - return metadata; -}; - -const setSpanContext = function (metadata: grpcTypes.Metadata): void { - propagation.inject(context.active(), metadata, { - set: (metadata, k, v) => metadata.set(k, v as grpcTypes.MetadataValue), - }); -}; diff --git a/experimental/packages/opentelemetry-instrumentation-grpc/src/grpc/index.ts b/experimental/packages/opentelemetry-instrumentation-grpc/src/grpc/index.ts deleted file mode 100644 index fbeac0395e..0000000000 --- a/experimental/packages/opentelemetry-instrumentation-grpc/src/grpc/index.ts +++ /dev/null @@ -1,403 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type * as grpcTypes from 'grpc'; -import { - InstrumentationNodeModuleDefinition, - InstrumentationNodeModuleFile, - InstrumentationBase, - isWrapped, -} from '@opentelemetry/instrumentation'; -import { - GrpcInternalClientTypes, - ServerCallWithMeta, - SendUnaryDataCallback, - GrpcClientFunc, -} from './types'; -import { GrpcInstrumentationConfig } from '../types'; -import { metadataCaptureType } from '../internal-types'; -import { - context, - propagation, - SpanOptions, - SpanKind, - trace, -} from '@opentelemetry/api'; -import { - clientStreamAndUnaryHandler, - shouldNotTraceServerCall, - serverStreamAndBidiHandler, -} from './serverUtils'; -import { makeGrpcClientRemoteCall, getMetadata } from './clientUtils'; -import { - _extractMethodAndService, - _methodIsIgnored, - metadataCapture, - URI_REGEX, -} from '../utils'; -import { SemanticAttributes } from '@opentelemetry/semantic-conventions'; -import { AttributeValues } from '../enums/AttributeValues'; - -/** - * Holding reference to grpc module here to access constant of grpc modules - * instead of just requiring it avoid directly depending on grpc itself. - */ -let grpcClient: typeof grpcTypes; - -export class GrpcNativeInstrumentation extends InstrumentationBase< - typeof grpcTypes -> { - private _metadataCapture: metadataCaptureType; - - constructor( - name: string, - version: string, - config?: GrpcInstrumentationConfig - ) { - super(name, version, config); - this._metadataCapture = this._createMetadataCapture(); - } - - init() { - return [ - new InstrumentationNodeModuleDefinition( - 'grpc', - ['1.*'], - (moduleExports, version) => { - this._diag.debug(`Applying patch for grpc@${version}`); - grpcClient = moduleExports; - - if (isWrapped(moduleExports.Server.prototype.register)) { - this._unwrap(moduleExports.Server.prototype, 'register'); - } - this._wrap( - moduleExports.Server.prototype, - 'register', - this._patchServer() as any - ); - // Wrap the externally exported client constructor - if (isWrapped(moduleExports.makeGenericClientConstructor)) { - this._unwrap(moduleExports, 'makeGenericClientConstructor'); - } - this._wrap( - moduleExports, - 'makeGenericClientConstructor', - this._patchClient() - ); - return moduleExports; - }, - (moduleExports, version) => { - if (moduleExports === undefined) return; - this._diag.debug(`Removing patch for grpc@${version}`); - - this._unwrap(moduleExports.Server.prototype, 'register'); - }, - this._getInternalPatchs() - ), - ]; - } - - override getConfig(): GrpcInstrumentationConfig { - return super.getConfig(); - } - - override setConfig(config?: GrpcInstrumentationConfig): void { - super.setConfig(config); - this._metadataCapture = this._createMetadataCapture(); - } - - private _getInternalPatchs() { - const onPatch = ( - moduleExports: GrpcInternalClientTypes, - version?: string - ) => { - this._diag.debug(`Applying internal patch for grpc@${version}`); - if (isWrapped(moduleExports.makeClientConstructor)) { - this._unwrap(moduleExports, 'makeClientConstructor'); - } - this._wrap(moduleExports, 'makeClientConstructor', this._patchClient()); - return moduleExports; - }; - const onUnPatch = ( - moduleExports?: GrpcInternalClientTypes, - version?: string - ) => { - if (moduleExports === undefined) return; - this._diag.debug(`Removing internal patch for grpc@${version}`); - this._unwrap(moduleExports, 'makeClientConstructor'); - }; - return [ - new InstrumentationNodeModuleFile( - 'grpc/src/node/src/client.js', - ['0.13 - 1.6'], - onPatch, - onUnPatch - ), - new InstrumentationNodeModuleFile( - 'grpc/src/client.js', - ['^1.7'], - onPatch, - onUnPatch - ), - ]; - } - - private _patchServer() { - const instrumentation = this; - return (originalRegister: typeof grpcTypes.Server.prototype.register) => { - instrumentation._diag.debug('patched gRPC server'); - - return function register( - this: grpcTypes.Server & { handlers: any }, - name: string, - handler: grpcTypes.handleCall, - serialize: grpcTypes.serialize, - deserialize: grpcTypes.deserialize, - type: string - ) { - const originalResult = originalRegister.apply(this, arguments as any); - const handlerSet = this.handlers[name]; - - instrumentation._wrap( - handlerSet, - 'func', - (originalFunc: grpcTypes.handleCall) => { - return function func( - this: typeof handlerSet, - call: ServerCallWithMeta, - callback: SendUnaryDataCallback - ) { - const self = this; - if (shouldNotTraceServerCall.call(instrumentation, call, name)) { - switch (type) { - case 'unary': - case 'client_stream': - return (originalFunc as Function).call( - self, - call, - callback - ); - case 'server_stream': - case 'bidi': - return (originalFunc as Function).call(self, call); - default: - return originalResult; - } - } - const spanName = `grpc.${name.replace('/', '')}`; - const spanOptions: SpanOptions = { - kind: SpanKind.SERVER, - }; - - instrumentation._diag.debug( - `patch func: ${JSON.stringify(spanOptions)}` - ); - - context.with( - propagation.extract(context.active(), call.metadata, { - get: (metadata, key) => metadata.get(key).map(String), - keys: metadata => Object.keys(metadata.getMap()), - }), - () => { - const { service, method } = _extractMethodAndService(name); - - const span = instrumentation.tracer - .startSpan(spanName, spanOptions) - .setAttributes({ - [SemanticAttributes.RPC_SYSTEM]: - AttributeValues.RPC_SYSTEM, - [SemanticAttributes.RPC_METHOD]: method, - [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': - case 'client_stream': - return clientStreamAndUnaryHandler( - span, - call, - callback, - originalFunc, - self - ); - case 'server_stream': - case 'bidi': - return serverStreamAndBidiHandler( - span, - call, - originalFunc, - self - ); - default: - break; - } - }); - } - ); - }; - } - ); - - return originalResult; - }; - }; - } - - private _patchClient() { - const instrumentation = this; - return (original: typeof grpcTypes.makeGenericClientConstructor): never => { - instrumentation._diag.debug('patching client'); - return function makeClientConstructor( - this: typeof grpcTypes.Client, - methods: { [key: string]: { originalName?: string } }, - _serviceName: string, - _options: grpcTypes.GenericClientOptions - ) { - const client = original.apply(this, arguments as any); - instrumentation._massWrap( - client.prototype as never, - instrumentation._getMethodsToWrap(client, methods) as never[], - instrumentation._getPatchedClientMethods() as any - ); - return client; - } as never; - }; - } - - private _getMethodsToWrap( - client: typeof grpcTypes.Client, - methods: { [key: string]: { originalName?: string } } - ): string[] { - const methodList: string[] = []; - - // For a method defined in .proto as "UnaryMethod" - Object.entries(methods).forEach(([name, { originalName }]) => { - if (!_methodIsIgnored(name, this.getConfig().ignoreGrpcMethods)) { - methodList.push(name); // adds camel case method name: "unaryMethod" - if ( - originalName && - // eslint-disable-next-line no-prototype-builtins - client.prototype.hasOwnProperty(originalName) && - name !== originalName // do not add duplicates - ) { - // adds original method name: "UnaryMethod", - methodList.push(originalName); - } - } - }); - return methodList; - } - - private _getPatchedClientMethods() { - const instrumentation = this; - return (original: GrpcClientFunc) => { - instrumentation._diag.debug('patch all client methods'); - function clientMethodTrace(this: grpcTypes.Client) { - const name = `grpc.${(original.path as string | undefined)?.replace( - '/', - '' - )}`; - const args = Array.prototype.slice.call(arguments); - const metadata = getMetadata(grpcClient, original, args); - const { service, method } = _extractMethodAndService(original.path); - const span = instrumentation.tracer - .startSpan(name, { - kind: SpanKind.CLIENT, - }) - .setAttributes({ - [SemanticAttributes.RPC_SYSTEM]: AttributeValues.RPC_SYSTEM, - [SemanticAttributes.RPC_METHOD]: method, - [SemanticAttributes.RPC_SERVICE]: service, - }); - // set net.peer.* 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.NET_PEER_NAME, - parsedUri.groups['name'] - ); - span.setAttribute( - SemanticAttributes.NET_PEER_PORT, - parseInt(parsedUri.groups['port']) - ); - } - - instrumentation._metadataCapture.client.captureRequestMetadata( - span, - metadata - ); - - return context.with(trace.setSpan(context.active(), span), () => - makeGrpcClientRemoteCall( - instrumentation._metadataCapture, - original, - args, - metadata, - this - )(span) - ); - } - Object.assign(clientMethodTrace, original); - return clientMethodTrace; - }; - } - - private _createMetadataCapture(): metadataCaptureType { - const config = this.getConfig(); - - return { - client: { - captureRequestMetadata: metadataCapture( - 'request', - config.metadataToSpanAttributes?.client?.requestMetadata ?? [] - ), - captureResponseMetadata: metadataCapture( - 'response', - 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/serverUtils.ts b/experimental/packages/opentelemetry-instrumentation-grpc/src/grpc/serverUtils.ts deleted file mode 100644 index d97a947443..0000000000 --- a/experimental/packages/opentelemetry-instrumentation-grpc/src/grpc/serverUtils.ts +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type * as grpcTypes from 'grpc'; -import { SendUnaryDataCallback, ServerCallWithMeta } from './types'; -import { GrpcNativeInstrumentation } from './'; -import { context, Span, SpanStatusCode } from '@opentelemetry/api'; -import { - _grpcStatusCodeToOpenTelemetryStatusCode, - _grpcStatusCodeToSpanStatus, - _methodIsIgnored, -} from '../utils'; -import { AttributeNames } from '../enums/AttributeNames'; -import { SemanticAttributes } from '@opentelemetry/semantic-conventions'; -import { GRPC_STATUS_CODE_OK } from '../status-code'; - -export const clientStreamAndUnaryHandler = function ( - span: Span, - call: ServerCallWithMeta, - callback: SendUnaryDataCallback, - original: - | grpcTypes.handleCall - | grpcTypes.ClientReadableStream, - self: {} -) { - function patchedCallback( - err: grpcTypes.ServiceError, - value: any, - trailer: grpcTypes.Metadata, - flags: grpcTypes.writeFlags - ) { - if (err) { - if (err.code) { - span.setStatus({ - code: _grpcStatusCodeToOpenTelemetryStatusCode(err.code), - message: err.message, - }); - span.setAttribute(SemanticAttributes.RPC_GRPC_STATUS_CODE, err.code); - } - span.setAttributes({ - [AttributeNames.GRPC_ERROR_NAME]: err.name, - [AttributeNames.GRPC_ERROR_MESSAGE]: err.message, - }); - } else { - span.setStatus({ code: SpanStatusCode.UNSET }); - span.setAttribute( - SemanticAttributes.RPC_GRPC_STATUS_CODE, - GRPC_STATUS_CODE_OK - ); - } - span.addEvent('received'); - - // end the span - span.end(); - return callback(err, value, trailer, flags); - } - - context.bind(context.active(), call); - return (original as Function).call(self, call, patchedCallback); -}; - -export const serverStreamAndBidiHandler = function ( - span: Span, - call: ServerCallWithMeta, - original: grpcTypes.handleCall, - self: {} -) { - let spanEnded = false; - const endSpan = () => { - if (!spanEnded) { - spanEnded = true; - span.end(); - } - }; - - context.bind(context.active(), call); - call.on('finish', () => { - span.setStatus(_grpcStatusCodeToSpanStatus(call.status.code)); - span.setAttribute( - SemanticAttributes.RPC_GRPC_STATUS_CODE, - call.status.code - ); - - // if there is an error, span will be ended on error event, otherwise end it here - if (call.status.code === 0) { - span.addEvent('finished'); - endSpan(); - } - }); - - call.on('error', (err: grpcTypes.ServiceError) => { - span.setStatus({ - code: _grpcStatusCodeToOpenTelemetryStatusCode(err.code), - message: err.message, - }); - span.addEvent('finished with error'); - span.setAttributes({ - [AttributeNames.GRPC_ERROR_NAME]: err.name, - [AttributeNames.GRPC_ERROR_MESSAGE]: err.message, - }); - if (err.code != null) { - span.setAttribute(SemanticAttributes.RPC_GRPC_STATUS_CODE, err.code); - } - endSpan(); - }); - - return (original as any).call(self, call); -}; - -/** - * Returns true if the server call should not be traced. - */ -export const shouldNotTraceServerCall = function ( - this: GrpcNativeInstrumentation, - call: ServerCallWithMeta, - name: string -): boolean { - const parsedName = name.split('/'); - return _methodIsIgnored( - parsedName[parsedName.length - 1] || name, - this.getConfig().ignoreGrpcMethods - ); -}; diff --git a/experimental/packages/opentelemetry-instrumentation-grpc/src/grpc/types.ts b/experimental/packages/opentelemetry-instrumentation-grpc/src/grpc/types.ts deleted file mode 100644 index ef3e4ef9bb..0000000000 --- a/experimental/packages/opentelemetry-instrumentation-grpc/src/grpc/types.ts +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type * as grpcTypes from 'grpc'; -import * as events from 'events'; - -export type SendUnaryDataCallback = ( - error: grpcTypes.ServiceError | null, - value?: any, - trailer?: grpcTypes.Metadata, - flags?: grpcTypes.writeFlags -) => void; - -interface GrpcStatus { - code: number; - details: string; - metadata: grpcTypes.Metadata; -} - -export type ServerCall = - | typeof grpcTypes.ServerUnaryCall - | typeof grpcTypes.ServerReadableStream - | typeof grpcTypes.ServerWritableStream - | typeof grpcTypes.ServerDuplexStream; - -export type ServerCallWithMeta = ServerCall & { - metadata: grpcTypes.Metadata; - status: GrpcStatus; - request?: unknown; -} & events.EventEmitter; - -export type GrpcClientFunc = typeof Function & { - path: string; - requestStream: boolean; - responseStream: boolean; -}; - -export type GrpcInternalClientTypes = { - makeClientConstructor: typeof grpcTypes.makeGenericClientConstructor; -}; diff --git a/experimental/packages/opentelemetry-instrumentation-grpc/src/instrumentation.ts b/experimental/packages/opentelemetry-instrumentation-grpc/src/instrumentation.ts index c2a8946f97..d597beaae2 100644 --- a/experimental/packages/opentelemetry-instrumentation-grpc/src/instrumentation.ts +++ b/experimental/packages/opentelemetry-instrumentation-grpc/src/instrumentation.ts @@ -16,7 +16,6 @@ import { GrpcInstrumentationConfig } from './types'; import { VERSION } from './version'; -import { GrpcNativeInstrumentation } from './grpc'; import { GrpcJsInstrumentation } from './grpc-js'; import * as api from '@opentelemetry/api'; @@ -24,7 +23,6 @@ import * as api from '@opentelemetry/api'; export const GRPC_TRACE_KEY = 'grpc-trace-bin'; export class GrpcInstrumentation { - private _grpcNativeInstrumentation: GrpcNativeInstrumentation; private _grpcJsInstrumentation: GrpcJsInstrumentation; public readonly instrumentationName: string = @@ -37,16 +35,10 @@ export class GrpcInstrumentation { this.instrumentationVersion, config ); - this._grpcNativeInstrumentation = new GrpcNativeInstrumentation( - this.instrumentationName, - this.instrumentationVersion, - config - ); } public setConfig(config?: GrpcInstrumentationConfig) { this._grpcJsInstrumentation.setConfig(config); - this._grpcNativeInstrumentation.setConfig(config); } /** @@ -66,12 +58,10 @@ export class GrpcInstrumentation { enable() { this._grpcJsInstrumentation.enable(); - this._grpcNativeInstrumentation.enable(); } disable() { this._grpcJsInstrumentation.disable(); - this._grpcNativeInstrumentation.disable(); } /** @@ -80,7 +70,6 @@ export class GrpcInstrumentation { */ public setMeterProvider(meterProvider: api.MeterProvider) { this._grpcJsInstrumentation.setMeterProvider(meterProvider); - this._grpcNativeInstrumentation.setMeterProvider(meterProvider); } /** @@ -89,6 +78,5 @@ export class GrpcInstrumentation { */ public setTracerProvider(tracerProvider: api.TracerProvider) { this._grpcJsInstrumentation.setTracerProvider(tracerProvider); - this._grpcNativeInstrumentation.setTracerProvider(tracerProvider); } } diff --git a/experimental/packages/opentelemetry-instrumentation-grpc/src/internal-types.ts b/experimental/packages/opentelemetry-instrumentation-grpc/src/internal-types.ts index ebc17ae1d4..594ad7ce0a 100644 --- a/experimental/packages/opentelemetry-instrumentation-grpc/src/internal-types.ts +++ b/experimental/packages/opentelemetry-instrumentation-grpc/src/internal-types.ts @@ -16,27 +16,26 @@ import { Span } from '@opentelemetry/api'; import type * as grpcJsTypes from '@grpc/grpc-js'; -import type * as grpcTypes from 'grpc'; export type metadataCaptureType = { client: { captureRequestMetadata: ( span: Span, - metadata: grpcJsTypes.Metadata | grpcTypes.Metadata + metadata: grpcJsTypes.Metadata ) => void; captureResponseMetadata: ( span: Span, - metadata: grpcJsTypes.Metadata | grpcTypes.Metadata + metadata: grpcJsTypes.Metadata ) => void; }; server: { captureRequestMetadata: ( span: Span, - metadata: grpcJsTypes.Metadata | grpcTypes.Metadata + metadata: grpcJsTypes.Metadata ) => void; captureResponseMetadata: ( span: Span, - metadata: grpcJsTypes.Metadata | grpcTypes.Metadata + metadata: grpcJsTypes.Metadata ) => void; }; }; diff --git a/experimental/packages/opentelemetry-instrumentation-grpc/src/utils.ts b/experimental/packages/opentelemetry-instrumentation-grpc/src/utils.ts index 8d031107dd..d9e542f509 100644 --- a/experimental/packages/opentelemetry-instrumentation-grpc/src/utils.ts +++ b/experimental/packages/opentelemetry-instrumentation-grpc/src/utils.ts @@ -15,7 +15,6 @@ */ 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'; @@ -26,7 +25,7 @@ export const URI_REGEX = // Equivalent to lodash _.findIndex export const findIndex: (args: T[], fn: (arg: T) => boolean) => number = ( args, - fn: Function + fn ) => { let index = -1; for (const arg of args) { @@ -43,7 +42,7 @@ export const findIndex: (args: T[], fn: (arg: T) => boolean) => number = ( * @param status */ export const _grpcStatusCodeToOpenTelemetryStatusCode = ( - status?: grpcTypes.status | grpcJsTypes.status + status?: grpcJsTypes.status ): SpanStatusCode => { if (status !== undefined && status === 0) { return SpanStatusCode.UNSET; @@ -128,7 +127,7 @@ export function metadataCapture( ]) ); - return (span: Span, metadata: grpcJsTypes.Metadata | grpcTypes.Metadata) => { + return (span: Span, metadata: grpcJsTypes.Metadata) => { for (const [ capturedMetadata, normalizedMetadata, @@ -137,7 +136,7 @@ export function metadataCapture( .get(capturedMetadata) .flatMap(value => (typeof value === 'string' ? value.toString() : [])); - if (metadataValues === undefined || metadataValues === []) { + if (metadataValues === undefined || metadataValues.length === 0) { continue; } diff --git a/experimental/packages/opentelemetry-instrumentation-grpc/test/grpc.test.ts b/experimental/packages/opentelemetry-instrumentation-grpc/test/grpc.test.ts deleted file mode 100644 index 453c6d6ef9..0000000000 --- a/experimental/packages/opentelemetry-instrumentation-grpc/test/grpc.test.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { runTests } from './helper'; -import { GrpcInstrumentation } from '../src/instrumentation'; - -const instrumentation = new GrpcInstrumentation(); -instrumentation.enable(); -instrumentation.disable(); - -import * as grpc from 'grpc'; - -describe('#grpc', () => { - runTests(instrumentation, 'grpc', grpc, 12345); -}); diff --git a/experimental/packages/opentelemetry-instrumentation-grpc/test/helper.ts b/experimental/packages/opentelemetry-instrumentation-grpc/test/helper.ts index 58855a6a5f..661b309e90 100644 --- a/experimental/packages/opentelemetry-instrumentation-grpc/test/helper.ts +++ b/experimental/packages/opentelemetry-instrumentation-grpc/test/helper.ts @@ -32,7 +32,6 @@ import { } from '@opentelemetry/sdk-trace-base'; import * as assert from 'assert'; import * as protoLoader from '@grpc/proto-loader'; -import type * as grpcNapi from 'grpc'; import type * as grpcJs from '@grpc/grpc-js'; import { assertPropagation, assertSpan } from './utils/assertionUtils'; import { promisify } from 'util'; @@ -54,25 +53,17 @@ interface TestRequestResponse { num: number; } -type ServiceError = grpcNapi.ServiceError | grpcJs.ServiceError; -type Client = grpcNapi.Client | grpcJs.Client; -type Server = grpcNapi.Server | grpcJs.Server; -type ServerUnaryCall = - | grpcNapi.ServerUnaryCall - | grpcJs.ServerUnaryCall; +type ServiceError = grpcJs.ServiceError; +type Client = grpcJs.Client; +type Server = grpcJs.Server; +type ServerUnaryCall = grpcJs.ServerUnaryCall; type RequestCallback = grpcJs.requestCallback; -type ServerReadableStream = - | grpcNapi.ServerReadableStream - | grpcJs.ServerReadableStream; -type ServerWriteableStream = - | grpcNapi.ServerWriteableStream - | grpcJs.ServerWritableStream; -type ServerDuplexStream = - | grpcNapi.ServerDuplexStream - | grpcJs.ServerDuplexStream; -type Metadata = grpcNapi.Metadata | grpcJs.Metadata; - -type TestGrpcClient = (typeof grpcJs | typeof grpcNapi)['Client'] & { +type ServerReadableStream = grpcJs.ServerReadableStream; +type ServerWriteableStream = grpcJs.ServerWritableStream; +type ServerDuplexStream = grpcJs.ServerDuplexStream; +type Metadata = grpcJs.Metadata; + +type TestGrpcClient = typeof grpcJs['Client'] & { unaryMethodWithMetadata: any; unaryMethod: any; UnaryMethod: any; @@ -117,7 +108,7 @@ const checkEqual = export const runTests = ( plugin: GrpcInstrumentation, moduleName: string, - grpc: typeof grpcNapi | typeof grpcJs, + grpc: typeof grpcJs, grpcPort: number ) => { const MAX_ERROR_STATUS = grpc.status.UNAUTHENTICATED; @@ -289,10 +280,7 @@ export const runTests = ( return result; }; - async function startServer( - grpc: typeof grpcJs | typeof grpcNapi, - proto: any - ) { + async function startServer(grpc: typeof grpcJs, proto: any) { const server = new grpc.Server(); function getError(msg: string, code: number): ServiceError | null { @@ -302,6 +290,7 @@ export const runTests = ( message: msg, code, details: msg, + metadata: new grpc.Metadata(), }; return err; } @@ -422,7 +411,7 @@ export const runTests = ( return server; } - function createClient(grpc: typeof grpcJs | typeof grpcNapi, proto: any) { + function createClient(grpc: typeof grpcJs, proto: any) { return new proto.GrpcTester( 'localhost:' + grpcPort, grpc.credentials.createInsecure() diff --git a/experimental/packages/opentelemetry-instrumentation-grpc/test/utils/assertionUtils.ts b/experimental/packages/opentelemetry-instrumentation-grpc/test/utils/assertionUtils.ts index 24d4bf7af8..fcdd546b32 100644 --- a/experimental/packages/opentelemetry-instrumentation-grpc/test/utils/assertionUtils.ts +++ b/experimental/packages/opentelemetry-instrumentation-grpc/test/utils/assertionUtils.ts @@ -16,7 +16,6 @@ import { SpanKind, SpanStatusCode } from '@opentelemetry/api'; import * as assert from 'assert'; -import type * as grpc from 'grpc'; import type * as grpcJs from '@grpc/grpc-js'; import { ReadableSpan } from '@opentelemetry/sdk-trace-base'; import { @@ -26,7 +25,7 @@ import { import { SemanticAttributes } from '@opentelemetry/semantic-conventions'; export const grpcStatusCodeToOpenTelemetryStatusCode = ( - status: grpc.status | grpcJs.status + status: grpcJs.status ): SpanStatusCode => { if (status !== undefined && status === 0) { return SpanStatusCode.UNSET; @@ -40,7 +39,7 @@ export const assertSpan = ( kind: SpanKind, validations: { name: string; - status: grpc.status | grpcJs.status; + status: grpcJs.status; netPeerName?: string; netPeerPort?: number; }