Skip to content

Commit

Permalink
Add handler helper to contain shared methods
Browse files Browse the repository at this point in the history
  • Loading branch information
jterapin committed Oct 1, 2024
1 parent 1e1a29e commit bb5cda6
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 108 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,17 @@ class Handler < Seahorse::Client::Handler
def call(context)
return super unless context

service_id = service_name(context)
operation = context.operation&.name
client_method = "#{service_id}.#{operation}"
service_id = HandlerHelper.service_id(context, legacy: true)
client_method = HandlerHelper.client_method(service_id, context)

tracer.in_span(
span_name(context, client_method, service_id),
attributes: attributes(context, client_method, service_id, operation),
kind: span_kind(client_method, service_id)
HandlerHelper.span_name(context, client_method, service_id, legacy: true),
attributes: HandlerHelper.span_attributes(context, client_method, service_id, legacy: true),
kind: HandlerHelper.span_kind(client_method, service_id)
) do |span|
if instrumentation_config[:inject_messaging_context] &&
%w[SQS SNS].include?(service_id)
MessagingHelper.inject_context(context, client_method)
end
MessagingHelper.inject_context_if_supported(context, client_method, service_id)

if instrumentation_config[:suppress_internal_instrumentation]
if HandlerHelper.instrumentation_config[:suppress_internal_instrumentation]
OpenTelemetry::Common::Utilities.untraced { super }
else
super
Expand All @@ -49,47 +45,6 @@ def call(context)
def tracer
AwsSdk::Instrumentation.instance.tracer
end

def instrumentation_config
AwsSdk::Instrumentation.instance.config
end

def service_name(context)
# Support aws-sdk v2.0.x, which 'metadata' has a setter method only
return context.client.class.to_s.split('::')[1] if ::Seahorse::Model::Api.instance_method(:metadata).parameters.length.positive?

context.client.class.api.metadata['serviceId'] || context.client.class.to_s.split('::')[1]
end

def span_kind(client_method, service_id)
case service_id
when 'SQS', 'SNS'
MessagingHelper.span_kind(client_method)
else
OpenTelemetry::Trace::SpanKind::CLIENT
end
end

def span_name(context, client_method, service_id)
case service_id
when 'SQS', 'SNS'
MessagingHelper.legacy_span_name(context, client_method)
else
client_method
end
end

def attributes(context, client_method, service_id, operation)
{
'aws.region' => context.config.region,
OpenTelemetry::SemanticConventions::Trace::RPC_SYSTEM => 'aws-api',
OpenTelemetry::SemanticConventions::Trace::RPC_METHOD => operation,
OpenTelemetry::SemanticConventions::Trace::RPC_SERVICE => service_id
}.tap do |attrs|
attrs[SemanticConventions::Trace::DB_SYSTEM] = 'dynamodb' if service_id == 'DynamoDB'
MessagingHelper.apply_span_attributes(context, attrs, client_method, service_id) if %w[SQS SNS].include?(service_id)
end
end
end

# A Seahorse::Client::Plugin that enables instrumentation for all AWS services
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# frozen_string_literal: true

# Copyright The OpenTelemetry Authors
#
# SPDX-License-Identifier: Apache-2.0

module OpenTelemetry
module Instrumentation
module AwsSdk
# Utility module that contains shared methods between AwsSdk and Telemetry handlers
module HandlerHelper
class << self
def instrumentation_config
AwsSdk::Instrumentation.instance.config
end

def client_method(service_id, context)
"#{service_id}.#{context.operation.name}".delete(' ')
end

def span_attributes(context, client_method, service_id, legacy: false)
{
'aws.region' => context.config.region,
OpenTelemetry::SemanticConventions::Trace::CODE_FUNCTION => context.operation_name.to_s,
OpenTelemetry::SemanticConventions::Trace::CODE_NAMESPACE => 'Aws::Plugins::Telemetry',
OpenTelemetry::SemanticConventions::Trace::RPC_METHOD => context.operation.name,
OpenTelemetry::SemanticConventions::Trace::RPC_SERVICE => service_id,
OpenTelemetry::SemanticConventions::Trace::RPC_SYSTEM => 'aws-api'
}.tap do |attrs|
attrs[OpenTelemetry::SemanticConventions::Trace::CODE_NAMESPACE] = 'Aws::Plugins::AwsSdk' if legacy

attrs[SemanticConventions::Trace::DB_SYSTEM] = 'dynamodb' if service_id == 'DynamoDB'
MessagingHelper.apply_span_attributes(context, attrs, client_method, service_id) if %w[SQS SNS].include?(service_id)
end
end

def span_kind(client_method, service_id)
case service_id
when *MessagingHelper.supported_services
MessagingHelper.span_kind(client_method)
else
OpenTelemetry::Trace::SpanKind::CLIENT
end
end

def span_name(context, client_method, service_id, legacy: false)
case service_id
when *MessagingHelper.supported_services
if legacy
MessagingHelper.legacy_span_name(context, client_method)
else
MessagingHelper.span_name(context, client_method)
end
else
client_method
end
end

def service_id(context, legacy: false)
if legacy
legacy_service_id(context)
else
context.config.api.metadata['serviceId'] ||
context.config.api.metadata['serviceAbbreviation'] ||
context.config.api.metadata['serviceFullName']
end
end

private

def legacy_service_id(context)
# Support aws-sdk v2.0.x, which 'metadata' has a setter method only
return context.client.class.to_s.split('::')[1] if ::Seahorse::Model::Api.instance_method(:metadata).parameters.length.positive?

context.client.class.api.metadata['serviceId'] || context.client.class.to_s.split('::')[1]
end
end
end
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ def gem_version

def require_dependencies
require_relative 'handler'
require_relative 'handler_helper'
require_relative 'message_attributes'
require_relative 'messaging_helper'
require_relative 'patches/telemetry'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,17 @@ module AwsSdk
# An utility class to help SQS/SNS-related span attributes/context injection
class MessagingHelper
class << self
SUPPORTED_SERVICES = %w[SQS SNS].freeze
SQS_SEND_MESSAGE = 'SQS.SendMessage'
SQS_SEND_MESSAGE_BATCH = 'SQS.SendMessageBatch'
SQS_RECEIVE_MESSAGE = 'SQS.ReceiveMessage'
SNS_PUBLISH = 'SNS.Publish'
SEND_MESSAGE_CLIENT_METHODS = [SQS_SEND_MESSAGE, SQS_SEND_MESSAGE_BATCH, SNS_PUBLISH].freeze

def supported_services
SUPPORTED_SERVICES
end

def queue_name(context)
topic_arn = context.params[:topic_arn]
target_arn = context.params[:target_arn]
Expand Down Expand Up @@ -76,6 +81,13 @@ def span_kind(client_method)
end
end

def inject_context_if_supported(context, client_method, service_id)
if HandlerHelper.instrumentation_config[:inject_messaging_context] &&
SUPPORTED_SERVICES.include?(service_id)
inject_context(context, client_method)
end
end

def inject_context(context, client_method)
return unless SEND_MESSAGE_CLIENT_METHODS.include?(client_method)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,71 +17,22 @@ def call(context)
private

def span_wrapper(context, &block)
service_id = service_id(context)
client_method = client_method(service_id, context)
service_id = HandlerHelper.service_id(context)
client_method = HandlerHelper.client_method(service_id, context)
context.tracer.in_span(
span_name(context, client_method, service_id),
attributes: attributes(context, client_method, service_id),
kind: span_kind(client_method, service_id)
HandlerHelper.span_name(context, client_method, service_id),
attributes: HandlerHelper.span_attributes(context, client_method, service_id),
kind: HandlerHelper.span_kind(client_method, service_id)
) do |span|
if instrumentation_config[:inject_messaging_context] &&
%w[SQS SNS].include?(service_id)
MessagingHelper.inject_context(context, client_method)
end
MessagingHelper.inject_context_if_supported(context, client_method, service_id)

if instrumentation_config[:suppress_internal_instrumentation]
if HandlerHelper.instrumentation_config[:suppress_internal_instrumentation]
OpenTelemetry::Common::Utilities.untraced { super }
else
yield span
end
end
end

def instrumentation_config
AwsSdk::Instrumentation.instance.config
end

def service_id(context)
context.config.api.metadata['serviceId'] ||
context.config.api.metadata['serviceAbbreviation'] ||
context.config.api.metadata['serviceFullName']
end

def client_method(service_id, context)
"#{service_id}.#{context.operation.name}".delete(' ')
end

def attributes(context, client_method, service_id)
{
'aws.region' => context.config.region,
OpenTelemetry::SemanticConventions::Trace::RPC_SYSTEM => 'aws-api',
OpenTelemetry::SemanticConventions::Trace::RPC_SERVICE => service_id,
OpenTelemetry::SemanticConventions::Trace::RPC_METHOD => context.operation.name,
OpenTelemetry::SemanticConventions::Trace::CODE_FUNCTION => context.operation_name.to_s,
OpenTelemetry::SemanticConventions::Trace::CODE_NAMESPACE => 'Aws::Plugins::Telemetry'
}.tap do |attrs|
attrs[SemanticConventions::Trace::DB_SYSTEM] = 'dynamodb' if service_id == 'DynamoDB'
MessagingHelper.apply_span_attributes(context, attrs, client_method, service_id) if %w[SQS SNS].include?(service_id)
end
end

def span_name(context, client_method, service_id)
case service_id
when 'SQS', 'SNS'
MessagingHelper.span_name(context, client_method)
else
client_method
end
end

def span_kind(client_method, service_id)
case service_id
when 'SQS', 'SNS'
MessagingHelper.span_kind(client_method)
else
OpenTelemetry::Trace::SpanKind::CLIENT
end
end
end
end
end
Expand Down

0 comments on commit bb5cda6

Please sign in to comment.