UNPKG

dd-trace

Version:

Datadog APM tracing client for JavaScript

130 lines (105 loc) 3.48 kB
'use strict' const { storage } = require('../../datadog-core') const ClientPlugin = require('../../dd-trace/src/plugins/client') const { TEXT_MAP } = require('../../../ext/formats') const { addMetadataTags, getFilter, getMethodMetadata } = require('./util') class GrpcClientPlugin extends ClientPlugin { static id = 'grpc' static operation = 'client:request' static prefix = 'apm:grpc:client:request' static peerServicePrecursors = ['rpc.service'] constructor (...args) { super(...args) this.addTraceBind('emit', ({ parentStore }) => { return parentStore }) } bindStart (message) { const store = storage('legacy').getStore() const { metadata, path, type } = message const metadataFilter = this.config.metadataFilter const method = getMethodMetadata(path, type) const span = this.startSpan(this.operationName(), { service: this.config.service || this.serviceName(), resource: path, kind: 'client', type: 'http', meta: { component: 'grpc', 'grpc.method.kind': method.kind, 'grpc.method.path': method.path, 'grpc.method.name': method.name, 'grpc.method.service': method.service, 'grpc.method.package': method.package }, metrics: { 'grpc.status.code': 0 } }, false) // needed as precursor for peer.service if (method.service && method.package) { span.setTag('rpc.service', method.package + '.' + method.service) } if (metadata) { addMetadataTags(span, metadata, metadataFilter, 'request') inject(this.tracer, span, metadata) } message.span = span message.parentStore = store message.currentStore = { ...store, span } return message.currentStore } bindAsyncStart ({ parentStore }) { return parentStore } error ({ span = this.activeSpan, error }) { this.addCode(span, error.code) if (error.code && !this._tracerConfig.grpc.client.error.statuses.includes(error.code)) { return } this.addError(error, span) } finish ({ span, result, peer }) { if (!span) return const { code, metadata } = result || {} const metadataFilter = this.config.metadataFilter this.addCode(span, code) if (metadata && metadataFilter) { addMetadataTags(span, metadata, metadataFilter, 'response') } if (peer) { // The only scheme we want to support here is ipv[46]:port, although // more are supported by the library // https://github.com/grpc/grpc/blob/v1.60.0/doc/naming.md const parts = peer.split(':') if (/^\d+/.test(parts.at(-1))) { const port = parts.at(-1) const ip = parts.slice(0, -1).join(':') span.setTag('network.destination.ip', ip) span.setTag('network.destination.port', port) } else { span.setTag('network.destination.ip', peer) } } this.tagPeerService(span) span.finish() } configure (config) { const metadataFilter = getFilter(config, 'metadata') return super.configure({ ...config, metadataFilter }) } addCode (span, code) { if (code !== undefined && span) { span.setTag('grpc.status.code', code) } } } function inject (tracer, span, metadata) { if (typeof metadata.set !== 'function') return const carrier = {} tracer.inject(span, TEXT_MAP, carrier) for (const key in carrier) { metadata.set(key, carrier[key]) } } module.exports = GrpcClientPlugin