require 'ddtrace/ext/http' require 'ddtrace/ext/integration' require 'ddtrace/contrib/analytics' require 'ddtrace/contrib/grpc/ext' module Datadog module Contrib module GRPC module DatadogInterceptor # The DatadogInterceptor::Server implements the tracing strategy # for gRPC server-side endpoints. When the datadog fields have been # added to the gRPC call metadata, this middleware component will # extract any client-side tracing information, attempting to associate # its tracing context with a parent client-side context class Server < Base def trace(keywords) options = { span_type: Datadog::Ext::HTTP::TYPE_INBOUND, service: service_name, resource: format_resource(keywords[:method]) } metadata = keywords[:call].metadata set_distributed_context!(tracer, metadata) tracer.trace(Ext::SPAN_SERVICE, options) do |span| annotate!(span, metadata) yield end end private def set_distributed_context!(tracer, metadata) tracer.provider.context = Datadog::GRPCPropagator .extract(metadata) rescue StandardError => e Datadog.logger.debug( "unable to propagate GRPC metadata to context: #{e}" ) end def annotate!(span, metadata) metadata.each do |header, value| next if reserved_headers.include?(header) span.set_tag(header, value) end # Tag as an external peer service span.set_tag(Datadog::Ext::Integration::TAG_PEER_SERVICE, span.service) # Set analytics sample rate Contrib::Analytics.set_sample_rate(span, analytics_sample_rate) if analytics_enabled? # Measure service stats Contrib::Analytics.set_measured(span) rescue StandardError => e Datadog.logger.debug("GRPC client trace failed: #{e}") end def reserved_headers [Datadog::Ext::DistributedTracing::GRPC_METADATA_TRACE_ID, Datadog::Ext::DistributedTracing::GRPC_METADATA_PARENT_ID, Datadog::Ext::DistributedTracing::GRPC_METADATA_SAMPLING_PRIORITY] end def format_resource(proto_method) proto_method.owner .to_s .downcase .split('::') .<<(proto_method.name) .join('.') end end end end end end