-
Notifications
You must be signed in to change notification settings - Fork 398
feat: add process tags to traces #5033
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 42 commits
1d8bab2
58592a3
7dc9184
cad26a6
f31440a
cfec602
8dae705
055586f
cacb500
7661a3f
7825940
5de6efd
f5ca84a
9ad5be5
a66e635
ec1e930
4073ab5
22a3680
5784833
2b705e3
e3deb4c
4747259
41bc6c0
c3605c0
adfa416
0dff545
7d8da40
31d9796
3672a8a
23d9769
7615906
d4c6a91
433b250
47efb90
a2643a6
ccd4971
be9587d
6042830
4210d74
f9af946
381fbe2
138dff8
2449153
5252259
0eaf302
fbfecfe
cc2225f
62822ab
a77e63b
439e81a
9e45ade
0ab4fef
6577d3f
a336c66
0d229de
e83bc4a
ce1759f
8b978c6
f4c9d49
eae4eb9
f3f1480
b48d20d
3d33291
4e3f8f4
5f6908c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| require_relative 'ext' | ||
| require_relative '../normalizer' | ||
|
|
||
| module Datadog | ||
| module Core | ||
| module Environment | ||
| # Retrieves process level information such that it can be attached to various payloads | ||
wantsui marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| module Process | ||
| extend self | ||
|
||
|
|
||
| # This method returns a key/value part of serialized tags in the format of k1:v1,k2:v2,k3:v3 | ||
| # @return [String] comma-separated normalized key:value pairs | ||
| def serialized | ||
| return @serialized if defined?(@serialized) | ||
| tags = [] | ||
| tags << "#{Environment::Ext::TAG_ENTRYPOINT_WORKDIR}:#{Normalizer.normalize(entrypoint_workdir, remove_digit_start_char: false)}" if entrypoint_workdir | ||
| tags << "#{Environment::Ext::TAG_ENTRYPOINT_NAME}:#{Normalizer.normalize(entrypoint_name, remove_digit_start_char: false)}" if entrypoint_name | ||
| tags << "#{Environment::Ext::TAG_ENTRYPOINT_BASEDIR}:#{Normalizer.normalize(entrypoint_basedir, remove_digit_start_char: false)}" if entrypoint_basedir | ||
| tags << "#{Environment::Ext::TAG_ENTRYPOINT_TYPE}:#{Normalizer.normalize(entrypoint_type, remove_digit_start_char: false)}" if entrypoint_type | ||
| @serialized = tags.join(',').freeze | ||
| end | ||
|
|
||
| private | ||
|
|
||
| # Returns the last segment of the working directory of the process | ||
| # Example: /app/myapp -> myapp | ||
| # @return [String] the last segment of the working directory | ||
| def entrypoint_workdir | ||
marcotc marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| File.basename(Dir.pwd) | ||
| end | ||
|
|
||
| # Returns the entrypoint type of the process | ||
| # In Ruby, the entrypoint type is always 'script' | ||
| # @return [String] the type of the process, which is fixed in Ruby | ||
| def entrypoint_type | ||
| Environment::Ext::PROCESS_TYPE | ||
| end | ||
|
|
||
| # Returns the last segment of the base directory of the process | ||
| # Example 1: /bin/mybin -> mybin | ||
| # Example 2: ruby /test/myapp.rb -> myapp | ||
| # @return [String] the last segment of base directory of the script | ||
| def entrypoint_name | ||
| File.basename($0) | ||
| end | ||
|
|
||
| # Returns the last segment of the base directory of the process | ||
| # Example 1: /bin/mybin -> bin | ||
| # Example 2: ruby /test/myapp.js -> test | ||
| # @return [String] the last segment of the base directory of the script | ||
| def entrypoint_basedir | ||
| File.basename(File.expand_path(File.dirname($0))) | ||
| end | ||
| end | ||
| end | ||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| module Datadog | ||
| module Core | ||
| module Normalizer | ||
wantsui marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
wantsui marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| module_function | ||
|
|
||
| INVALID_TAG_CHARACTERS = %r{[^\p{L}0-9_\-:./]} | ||
| LEADING_INVALID_CHARS_NO_DIGITS = %r{\A[^\p{L}:]++} | ||
| LEADING_INVALID_CHARS_WITH_DIGITS = %r{\A[^\p{L}0-9:./\-]++} | ||
| MAX_BYTE_SIZE = 200 | ||
| MAX_BYTE_SIZE_BUFFER = MAX_BYTE_SIZE * 2 | ||
p-datadog marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| TRAILING_UNDERSCORES = %r{_++\z} | ||
| VALID_ASCII_TAG = %r{\A[a-z:][a-z0-9:./-]*\z} | ||
|
|
||
| # Based on https://github.com/DataDog/datadog-agent/blob/45799c842bbd216bcda208737f9f11cade6fdd95/pkg/trace/traceutil/normalize.go#L131 | ||
| # Specifically: | ||
| # - Must be valid UTF-8 | ||
| # - Invalid characters are replaced with an underscore | ||
| # - Leading non-letter characters are removed but colons are kept | ||
| # - Trailing non-letter characters are removed | ||
| # - Trailing underscores are removed | ||
| # - Consecutive underscores are merged into a single underscore | ||
| # - Maximum length is 200 characters | ||
| # If it's a tag value, allow it to start with a digit | ||
| def self.normalize(original_value, remove_digit_start_char: false) | ||
| transformed_value = original_value.to_s.encode('UTF-8', invalid: :replace, undef: :replace) | ||
| transformed_value.strip! | ||
| return "" if transformed_value.empty? | ||
|
|
||
| return transformed_value if transformed_value.bytesize <= MAX_BYTE_SIZE && | ||
| transformed_value.match?(VALID_ASCII_TAG) | ||
|
|
||
| if transformed_value.ascii_only? && transformed_value.length <= MAX_BYTE_SIZE | ||
| normalized_value = transformed_value | ||
| else | ||
| byte_position = 0 | ||
| character_count = 0 | ||
| normalized_value = String.new(encoding: 'UTF-8') | ||
|
|
||
| transformed_value.each_char do |char| | ||
| byte_width = char.bytesize | ||
| break if byte_position + byte_width > MAX_BYTE_SIZE | ||
| break if character_count >= MAX_BYTE_SIZE | ||
|
|
||
| normalized_value << char | ||
| byte_position += byte_width | ||
| character_count += 1 | ||
| end | ||
wantsui marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| end | ||
|
|
||
| normalized_value.downcase! | ||
| normalized_value.gsub!(INVALID_TAG_CHARACTERS, '_') | ||
|
|
||
| # The Trace Agent allows tag values to start with a number so this logic is here too | ||
| leading_invalid_regex = remove_digit_start_char ? LEADING_INVALID_CHARS_NO_DIGITS : LEADING_INVALID_CHARS_WITH_DIGITS | ||
| normalized_value.sub!(leading_invalid_regex, "") | ||
|
|
||
| normalized_value.squeeze!('_') if normalized_value.include?('__') | ||
| normalized_value.sub!(TRAILING_UNDERSCORES, "") | ||
|
|
||
| normalized_value | ||
| end | ||
| end | ||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| module Datadog | ||
| module Core | ||
| module Environment | ||
| module Process | ||
| @serialized: ::String | ||
|
|
||
| def serialized: () -> ::String | ||
|
|
||
| private | ||
|
|
||
| def entrypoint_workdir: () -> ::String | ||
|
|
||
| def entrypoint_type: () -> ::String | ||
|
|
||
| def entrypoint_name: () -> ::String | ||
|
|
||
| def entrypoint_basedir: () -> ::String | ||
| end | ||
| end | ||
| end | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| module Datadog | ||
| module Core | ||
| module Normalizer | ||
| INVALID_TAG_CHARACTERS: ::Regexp | ||
| LEADING_INVALID_CHARS_NO_DIGITS: ::Regexp | ||
| LEADING_INVALID_CHARS_WITH_DIGITS: ::Regexp | ||
| TRAILING_UNDERSCORES: ::Regexp | ||
| MAX_BYTE_SIZE: ::Integer | ||
| MAX_BYTE_SIZE_BUFFER: ::Integer | ||
| VALID_ASCII_TAG: ::Regexp | ||
|
|
||
| def self.normalize: (untyped original_value, ?remove_digit_start_char: bool) -> ::String | ||
| end | ||
| end | ||
| end |
Uh oh!
There was an error while loading. Please reload this page.