-
Notifications
You must be signed in to change notification settings - Fork 284
Expand file tree
/
Copy pathtext_map_propagator.rb
More file actions
121 lines (102 loc) · 4.56 KB
/
Copy pathtext_map_propagator.rb
File metadata and controls
121 lines (102 loc) · 4.56 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# frozen_string_literal: true
# Copyright The OpenTelemetry Authors
#
# SPDX-License-Identifier: Apache-2.0
require 'uri'
module OpenTelemetry
module Baggage
module Propagation
# Propagates baggage using the W3C Baggage format
class TextMapPropagator
# Maximums according to W3C Baggage spec
MAX_ENTRIES = 180
MAX_ENTRY_LENGTH = 4096
MAX_TOTAL_LENGTH = 8192
BAGGAGE_KEY = 'baggage'
FIELDS = [BAGGAGE_KEY].freeze
private_constant :BAGGAGE_KEY, :FIELDS, :MAX_ENTRIES, :MAX_ENTRY_LENGTH, :MAX_TOTAL_LENGTH
# Inject in-process baggage into the supplied carrier.
#
# @param [Carrier] carrier The mutable carrier to inject baggage into
# @param [Context] context The context to read baggage from
# @param [optional Setter] setter If the optional setter is provided, it
# will be used to write context into the carrier, otherwise the default
# text map setter will be used.
def inject(carrier, context: Context.current, setter: Context::Propagation.text_map_setter)
baggage = OpenTelemetry::Baggage.raw_entries(context: context)
return if baggage.nil? || baggage.empty?
encoded_baggage = encode(baggage)
setter.set(carrier, BAGGAGE_KEY, encoded_baggage) unless encoded_baggage&.empty?
nil
end
# Extract remote baggage from the supplied carrier.
# If extraction fails or there is no baggage to extract,
# then the original context will be returned
#
# @param [Carrier] carrier The carrier to get the header from
# @param [optional Context] context Context to be updated with the baggage
# extracted from the carrier. Defaults to +Context.current+.
# @param [optional Getter] getter If the optional getter is provided, it
# will be used to read the header from the carrier, otherwise the default
# text map getter will be used.
#
# @return [Context] context updated with extracted baggage, or the original context
# if extraction fails
def extract(carrier, context: Context.current, getter: Context::Propagation.text_map_getter)
header = getter.get(carrier, BAGGAGE_KEY)
return context if header.nil? || header.empty?
return context if header.bytesize > MAX_TOTAL_LENGTH
entries = header.gsub(/\s/, '').split(',')
OpenTelemetry::Baggage.build(context: context) do |builder|
decode_entries(entries, builder)
end
rescue StandardError => e
OpenTelemetry.logger.debug "Error extracting W3C baggage: #{e.message}"
context
end
# Returns the predefined propagation fields. If your carrier is reused, you
# should delete the fields returned by this method before calling +inject+.
#
# @return [Array<String>] a list of fields that will be used by this propagator.
def fields
FIELDS
end
private
def decode_entries(entries, builder)
decoded_count = 0
entries.each do |entry|
break if decoded_count >= MAX_ENTRIES
next if entry.bytesize > MAX_ENTRY_LENGTH
# Note metadata is currently unused in OpenTelemetry, but is part
# the W3C spec where it's referred to as properties. We preserve
# the properties (as-is) so that they can be propagated elsewhere.
kv, meta = entry.split(';', 2)
k, v = kv.split('=').map!(&URI.method(:decode_uri_component))
builder.set_value(k, v, metadata: meta)
decoded_count += 1
end
end
def encode(baggage)
result = +''
encoded_count = 0
baggage.each_pair do |key, entry|
break unless encoded_count < MAX_ENTRIES
encoded_entry = encode_value(key, entry)
next unless encoded_entry.size <= MAX_ENTRY_LENGTH &&
encoded_entry.size + result.size <= MAX_TOTAL_LENGTH
result << encoded_entry << ','
encoded_count += 1
end
result.chop!
end
def encode_value(key, entry)
result = +"#{URI.encode_uri_component(key.to_s)}=#{URI.encode_uri_component(entry.value.to_s)}"
# We preserve metadata received on extract and assume it's already formatted
# for transport. It's sent as-is without further processing.
result << ";#{entry.metadata}" if entry.metadata
result
end
end
end
end
end