-
Notifications
You must be signed in to change notification settings - Fork 375
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added:HTTP header tagging with DD_TRACE_HEADER_TAGS
- Loading branch information
Showing
23 changed files
with
488 additions
and
101 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
# frozen_string_literal: true | ||
|
||
module Datadog | ||
module Tracing | ||
module Configuration | ||
module HTTP | ||
# Datadog tracing supports capturing HTTP request and response headers as span tags. | ||
# | ||
# The provided configuration String for this feature has to be pre-processed to | ||
# allow for ease of utilization by each HTTP integration. | ||
# | ||
# This class process configuration, stores the result, and provides methods to | ||
# utilize this configuration. | ||
class HeaderTags | ||
# @param header_tags [Array<String>] The list of strings from DD_TRACE_HEADER_TAGS. | ||
def initialize(header_tags) | ||
@request_headers = {} | ||
@response_headers = {} | ||
@header_tags = header_tags | ||
|
||
header_tags.each do |header_tag| | ||
header, tag = header_tag.split(':', 2) | ||
|
||
next unless header # RBS type guard for `nil` | ||
|
||
if tag | ||
# When a custom tag name is provided, use that name for both | ||
# request and response tags. | ||
normalized_tag = Tracing::Metadata::Ext::HTTP::Headers.to_tag(tag, allow_nested: true) | ||
request = response = normalized_tag | ||
else | ||
# Otherwise, use our internal pattern of | ||
# "http.{request|response}.headers.{header}" as tag name. | ||
request = Tracing::Metadata::Ext::HTTP::RequestHeaders.to_tag(header) | ||
response = Tracing::Metadata::Ext::HTTP::ResponseHeaders.to_tag(header) | ||
end | ||
|
||
@request_headers[header] = request | ||
@response_headers[header] = response | ||
end | ||
end | ||
|
||
# Receives a {RequestHeaderCollection} with the request headers and returns | ||
# a list of tag names and values that can be set in a span. | ||
def request_tags(headers) | ||
@request_headers.map do |header_name, span_tag| | ||
# Case-insensitive search. {RequestHeaderCollection} already ensures case-insensitiveness. | ||
header_value = headers[header_name] | ||
|
||
[span_tag, header_value] if header_value | ||
end.compact | ||
end | ||
|
||
# Receives a Hash with the response headers and returns | ||
# a list of tag names and values that can be set in a span. | ||
def response_tags(headers) | ||
@response_headers.map do |header_name, span_tag| | ||
# Case-insensitive search | ||
# DEV: `String#casecmp?` can be used starting with Ruby 2.4. It's measurable faster than `String#casecmp`. | ||
_, header_value = headers.find { |h, _| header_name.casecmp(h) == 0 } | ||
|
||
[span_tag, header_value] if header_value | ||
end.compact | ||
end | ||
|
||
# For easy configuration inspection, | ||
# print the original configuration setting. | ||
def to_s | ||
@header_tags.join(',').to_s | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
# frozen_string_literal: true | ||
|
||
module Datadog | ||
module Tracing | ||
module Contrib | ||
module Rack | ||
# Matches Rack-style headers with a matcher and sets matching headers into a span. | ||
module HeaderTagging | ||
def self.tag_request_headers(span, env, configuration) | ||
headers = Header::RequestHeaderCollection.new(env) | ||
|
||
# Use global DD_TRACE_HEADER_TAGS if integration-level configuration is not provided | ||
tags = if configuration.using_default?(:headers) && Datadog.configuration.tracing.header_tags | ||
Datadog.configuration.tracing.header_tags.request_tags(headers) | ||
else | ||
whitelist = configuration[:headers][:request] || [] | ||
whitelist.each_with_object({}) do |header, result| | ||
header_value = headers.get(header) | ||
unless header_value.nil? | ||
header_tag = Tracing::Metadata::Ext::HTTP::RequestHeaders.to_tag(header) | ||
result[header_tag] = header_value | ||
end | ||
end | ||
end | ||
|
||
span.set_tags(tags) | ||
end | ||
|
||
def self.tag_response_headers(span, headers, configuration) | ||
# Use global DD_TRACE_HEADER_TAGS if integration-level configuration is not provided | ||
tags = if configuration.using_default?(:headers) && Datadog.configuration.tracing.header_tags | ||
Datadog.configuration.tracing.header_tags.response_tags(headers) | ||
else | ||
whitelist = configuration[:headers][:response] || [] | ||
whitelist.each_with_object({}) do |header, result| | ||
if headers.key?(header) | ||
result[Tracing::Metadata::Ext::HTTP::ResponseHeaders.to_tag(header)] = headers[header] | ||
else | ||
# Try a case-insensitive lookup | ||
uppercased_header = header.to_s.upcase | ||
matching_header = headers.keys.find { |h| h.upcase == uppercased_header } | ||
if matching_header | ||
result[Tracing::Metadata::Ext::HTTP::ResponseHeaders.to_tag(header)] = headers[matching_header] | ||
end | ||
end | ||
end | ||
end | ||
|
||
span.set_tags(tags) | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.