ddtrace 0.8.2 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.env +3 -1
  3. data/.gitignore +1 -0
  4. data/Appraisals +10 -0
  5. data/Rakefile +27 -1
  6. data/ddtrace.gemspec +2 -2
  7. data/docker-compose.yml +10 -0
  8. data/docs/GettingStarted.md +119 -0
  9. data/gemfiles/contrib.gemfile +5 -0
  10. data/gemfiles/contrib_old.gemfile +4 -0
  11. data/lib/ddtrace.rb +4 -11
  12. data/lib/ddtrace/buffer.rb +14 -0
  13. data/lib/ddtrace/contrib/aws/instrumentation.rb +43 -0
  14. data/lib/ddtrace/contrib/aws/parsed_context.rb +56 -0
  15. data/lib/ddtrace/contrib/aws/patcher.rb +56 -0
  16. data/lib/ddtrace/contrib/aws/services.rb +115 -0
  17. data/lib/ddtrace/contrib/dalli/instrumentation.rb +35 -0
  18. data/lib/ddtrace/contrib/dalli/patcher.rb +50 -0
  19. data/lib/ddtrace/contrib/dalli/quantize.rb +17 -0
  20. data/lib/ddtrace/contrib/faraday/middleware.rb +75 -0
  21. data/lib/ddtrace/contrib/faraday/patcher.rb +52 -0
  22. data/lib/ddtrace/contrib/mongodb/parsers.rb +57 -0
  23. data/lib/ddtrace/contrib/mongodb/patcher.rb +93 -0
  24. data/lib/ddtrace/contrib/mongodb/subscribers.rb +71 -0
  25. data/lib/ddtrace/contrib/rails/action_controller.rb +18 -19
  26. data/lib/ddtrace/contrib/rails/action_view.rb +51 -61
  27. data/lib/ddtrace/contrib/rails/active_support.rb +29 -73
  28. data/lib/ddtrace/contrib/rails/core_extensions.rb +191 -53
  29. data/lib/ddtrace/contrib/redis/quantize.rb +4 -6
  30. data/lib/ddtrace/contrib/resque/patcher.rb +38 -0
  31. data/lib/ddtrace/contrib/resque/resque_job.rb +31 -0
  32. data/lib/ddtrace/contrib/sucker_punch/exception_handler.rb +26 -0
  33. data/lib/ddtrace/contrib/sucker_punch/instrumentation.rb +60 -0
  34. data/lib/ddtrace/contrib/sucker_punch/patcher.rb +50 -0
  35. data/lib/ddtrace/ext/http.rb +1 -0
  36. data/lib/ddtrace/ext/mongo.rb +12 -0
  37. data/lib/ddtrace/monkey.rb +18 -0
  38. data/lib/ddtrace/pipeline.rb +46 -0
  39. data/lib/ddtrace/pipeline/span_filter.rb +38 -0
  40. data/lib/ddtrace/pipeline/span_processor.rb +20 -0
  41. data/lib/ddtrace/tracer.rb +18 -0
  42. data/lib/ddtrace/utils.rb +23 -3
  43. data/lib/ddtrace/version.rb +2 -2
  44. data/lib/ddtrace/workers.rb +30 -22
  45. data/lib/ddtrace/writer.rb +5 -7
  46. metadata +30 -9
@@ -0,0 +1,56 @@
1
+ module Datadog
2
+ module Contrib
3
+ module Aws
4
+ # A wrapper around Seahorse::Client::RequestContext
5
+ class ParsedContext
6
+ def initialize(context)
7
+ @context = context
8
+ end
9
+
10
+ def safely(attr, fallback = nil)
11
+ public_send(attr) rescue fallback
12
+ end
13
+
14
+ def resource
15
+ "#{service}.#{operation}"
16
+ end
17
+
18
+ def operation
19
+ context.operation_name
20
+ end
21
+
22
+ def status_code
23
+ context.http_response.status_code
24
+ end
25
+
26
+ def http_method
27
+ context.http_request.http_method
28
+ end
29
+
30
+ def region
31
+ context.client.config.region
32
+ end
33
+
34
+ def retry_attempts
35
+ context.retries
36
+ end
37
+
38
+ def path
39
+ context.http_request.endpoint.path
40
+ end
41
+
42
+ def host
43
+ context.http_request.endpoint.host
44
+ end
45
+
46
+ private
47
+
48
+ attr_reader :context
49
+
50
+ def service
51
+ context.client.class.to_s.split('::')[1].downcase
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,56 @@
1
+ module Datadog
2
+ module Contrib
3
+ module Aws
4
+ SERVICE = 'aws'.freeze
5
+ AGENT = 'aws-sdk-ruby'.freeze
6
+ RESOURCE = 'aws.command'.freeze
7
+
8
+ # Responsible for hooking the instrumentation into aws-sdk
9
+ module Patcher
10
+ @patched = false
11
+
12
+ class << self
13
+ def patch
14
+ return @patched if patched? || !defined?(Seahorse::Client::Base)
15
+
16
+ require 'ddtrace/ext/app_types'
17
+ require 'ddtrace/contrib/aws/parsed_context'
18
+ require 'ddtrace/contrib/aws/instrumentation'
19
+ require 'ddtrace/contrib/aws/services'
20
+
21
+ add_pin
22
+ add_plugin(Seahorse::Client::Base, *loaded_constants)
23
+
24
+ @patched = true
25
+ rescue => e
26
+ Datadog::Tracer.log.error("Unable to apply AWS integration: #{e}")
27
+ @patched
28
+ end
29
+
30
+ def patched?
31
+ @patched
32
+ end
33
+
34
+ private
35
+
36
+ def add_pin
37
+ Pin.new(SERVICE, app_type: Ext::AppTypes::WEB).tap do |pin|
38
+ pin.onto(::Aws)
39
+ end
40
+ end
41
+
42
+ def add_plugin(*targets)
43
+ targets.each { |klass| klass.add_plugin(Instrumentation) }
44
+ end
45
+
46
+ def loaded_constants
47
+ SERVICES.each_with_object([]) do |service, constants|
48
+ next if ::Aws.autoload?(service)
49
+ constants << ::Aws.const_get(service).const_get(:Client) rescue next
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,115 @@
1
+ module Datadog
2
+ module Contrib
3
+ # rubocop:disable Metrics/ModuleLength:
4
+ module Aws
5
+ SERVICES = %w[
6
+ ACM
7
+ APIGateway
8
+ AppStream
9
+ ApplicationAutoScaling
10
+ ApplicationDiscoveryService
11
+ Athena
12
+ AutoScaling
13
+ Batch
14
+ Budgets
15
+ CloudDirectory
16
+ CloudFormation
17
+ CloudFront
18
+ CloudHSM
19
+ CloudHSMV2
20
+ CloudSearch
21
+ CloudSearchDomain
22
+ CloudTrail
23
+ CloudWatch
24
+ CloudWatchEvents
25
+ CloudWatchLogs
26
+ CodeBuild
27
+ CodeCommit
28
+ CodeDeploy
29
+ CodePipeline
30
+ CodeStar
31
+ CognitoIdentity
32
+ CognitoIdentityProvider
33
+ CognitoSync
34
+ ConfigService
35
+ CostandUsageReportService
36
+ DAX
37
+ DataPipeline
38
+ DatabaseMigrationService
39
+ DeviceFarm
40
+ DirectConnect
41
+ DirectoryService
42
+ DynamoDB
43
+ DynamoDBStreams
44
+ EC2
45
+ ECR
46
+ ECS
47
+ EFS
48
+ EMR
49
+ ElastiCache
50
+ ElasticBeanstalk
51
+ ElasticLoadBalancing
52
+ ElasticLoadBalancingV2
53
+ ElasticTranscoder
54
+ ElasticsearchService
55
+ Firehose
56
+ GameLift
57
+ Glacier
58
+ Glue
59
+ Greengrass
60
+ Health
61
+ IAM
62
+ ImportExport
63
+ Inspector
64
+ IoT
65
+ IoTDataPlane
66
+ KMS
67
+ Kinesis
68
+ KinesisAnalytics
69
+ Lambda
70
+ LambdaPreview
71
+ Lex
72
+ LexModelBuildingService
73
+ Lightsail
74
+ MTurk
75
+ MachineLearning
76
+ MarketplaceCommerceAnalytics
77
+ MarketplaceEntitlementService
78
+ MarketplaceMetering
79
+ MigrationHub
80
+ Mobile
81
+ OpsWorks
82
+ OpsWorksCM
83
+ Organizations
84
+ Pinpoint
85
+ Polly
86
+ RDS
87
+ Redshift
88
+ Rekognition
89
+ ResourceGroupsTaggingAPI
90
+ Route53
91
+ Route53Domains
92
+ S3
93
+ SES
94
+ SMS
95
+ SNS
96
+ SQS
97
+ SSM
98
+ STS
99
+ SWF
100
+ ServiceCatalog
101
+ Shield
102
+ SimpleDB
103
+ Snowball
104
+ States
105
+ StorageGateway
106
+ Support
107
+ WAF
108
+ WAFRegional
109
+ WorkDocs
110
+ WorkSpaces
111
+ XRay
112
+ ].freeze
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,35 @@
1
+ require_relative 'quantize'
2
+ require 'ddtrace/ext/net'
3
+
4
+ module Datadog
5
+ module Contrib
6
+ module Dalli
7
+ # Instruments every interaction with the memcached server
8
+ module Instrumentation
9
+ module_function
10
+
11
+ def patch!
12
+ ::Dalli::Server.class_eval do
13
+ alias_method :__request, :request
14
+
15
+ def request(op, *args)
16
+ pin = Datadog::Pin.get_from(::Dalli)
17
+
18
+ pin.tracer.trace(Datadog::Contrib::Dalli::NAME) do |span|
19
+ span.resource = op.to_s.upcase
20
+ span.service = pin.service
21
+ span.span_type = pin.app_type
22
+ span.set_tag(Datadog::Ext::NET::TARGET_HOST, hostname)
23
+ span.set_tag(Datadog::Ext::NET::TARGET_PORT, port)
24
+ cmd = Datadog::Contrib::Dalli::Quantize.format_command(op, args)
25
+ span.set_tag(Datadog::Contrib::Dalli::CMD_TAG, cmd)
26
+
27
+ __request(op, *args)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,50 @@
1
+ module Datadog
2
+ module Contrib
3
+ module Dalli
4
+ COMPATIBLE_WITH = Gem::Version.new('2.0.0')
5
+ SERVICE = 'memcached'.freeze
6
+ NAME = 'memcached.command'.freeze
7
+ CMD_TAG = 'memcached.command'.freeze
8
+
9
+ # Responsible for hooking the instrumentation into `dalli`
10
+ module Patcher
11
+ @patched = false
12
+
13
+ class << self
14
+ def patch
15
+ return @patched if patched? || !compatible?
16
+
17
+ require 'ddtrace/ext/app_types'
18
+ require_relative 'instrumentation'
19
+
20
+ add_pin!
21
+ Instrumentation.patch!
22
+
23
+ @patched = true
24
+ rescue => e
25
+ Tracer.log.error("Unable to apply Dalli integration: #{e}")
26
+ @patched
27
+ end
28
+
29
+ def patched?
30
+ @patched
31
+ end
32
+
33
+ private
34
+
35
+ def compatible?
36
+ return unless defined?(::Dalli::VERSION)
37
+
38
+ Gem::Version.new(::Dalli::VERSION) > COMPATIBLE_WITH
39
+ end
40
+
41
+ def add_pin!
42
+ Pin.new(SERVICE, app_type: Ext::AppTypes::DB).tap do |pin|
43
+ pin.onto(::Dalli)
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,17 @@
1
+ module Datadog
2
+ module Contrib
3
+ module Dalli
4
+ # Quantize contains dalli-specic quantization tools.
5
+ module Quantize
6
+ MAX_CMD_LENGTH = 100
7
+
8
+ module_function
9
+
10
+ def format_command(operation, args)
11
+ command = [operation, *args].join(' ').strip
12
+ Utils.truncate(command, MAX_CMD_LENGTH)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,75 @@
1
+ require 'faraday'
2
+ require 'ddtrace/ext/http'
3
+ require 'ddtrace/ext/net'
4
+ require 'ddtrace/ext/distributed'
5
+
6
+ module Datadog
7
+ module Contrib
8
+ module Faraday
9
+ # Middleware implements a faraday-middleware for ddtrace instrumentation
10
+ class Middleware < ::Faraday::Middleware
11
+ DEFAULT_ERROR_HANDLER = lambda do |env|
12
+ Ext::HTTP::ERROR_RANGE.cover?(env[:status])
13
+ end
14
+
15
+ DEFAULT_OPTIONS = {
16
+ distributed_tracing: false,
17
+ split_by_domain: false,
18
+ error_handler: DEFAULT_ERROR_HANDLER
19
+ }.freeze
20
+
21
+ def initialize(app, options = {})
22
+ super(app)
23
+ @options = DEFAULT_OPTIONS.merge(options)
24
+ end
25
+
26
+ def call(env)
27
+ dd_pin.tracer.trace(SERVICE) do |span|
28
+ annotate!(span, env)
29
+ propagate!(span, env) if options[:distributed_tracing]
30
+ app.call(env).on_complete { |resp| handle_response(span, resp) }
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ attr_reader :app, :options
37
+
38
+ def annotate!(span, env)
39
+ span.resource = env[:method].to_s.upcase
40
+ span.service = service_name(env)
41
+ span.span_type = Ext::HTTP::TYPE
42
+ span.set_tag(Ext::HTTP::URL, env[:url].path)
43
+ span.set_tag(Ext::HTTP::METHOD, env[:method].to_s.upcase)
44
+ span.set_tag(Ext::NET::TARGET_HOST, env[:url].host)
45
+ span.set_tag(Ext::NET::TARGET_PORT, env[:url].port)
46
+ end
47
+
48
+ def handle_response(span, env)
49
+ if options.fetch(:error_handler).call(env)
50
+ span.set_error(["Error #{env[:status]}", env[:body]])
51
+ end
52
+
53
+ span.set_tag(Ext::HTTP::STATUS_CODE, env[:status])
54
+ end
55
+
56
+ def propagate!(span, env)
57
+ env[:request_headers].merge!(
58
+ Ext::DistributedTracing::HTTP_HEADER_TRACE_ID => span.trace_id.to_s,
59
+ Ext::DistributedTracing::HTTP_HEADER_PARENT_ID => span.span_id.to_s
60
+ )
61
+ end
62
+
63
+ def dd_pin
64
+ Pin.get_from(::Faraday)
65
+ end
66
+
67
+ def service_name(env)
68
+ return env[:url].host if options[:split_by_domain]
69
+
70
+ dd_pin.service
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,52 @@
1
+ module Datadog
2
+ module Contrib
3
+ module Faraday
4
+ COMPATIBLE_UNTIL = Gem::Version.new('1.0.0')
5
+ SERVICE = 'faraday-request'.freeze
6
+
7
+ # Responsible for hooking the instrumentation into faraday
8
+ module Patcher
9
+ @patched = false
10
+
11
+ class << self
12
+ def patch
13
+ return @patched if patched? || !compatible?
14
+
15
+ require 'ddtrace/ext/app_types'
16
+ require 'ddtrace/contrib/faraday/middleware'
17
+
18
+ add_pin
19
+ add_middleware
20
+
21
+ @patched = true
22
+ rescue => e
23
+ Tracer.log.error("Unable to apply Faraday integration: #{e}")
24
+ @patched
25
+ end
26
+
27
+ def patched?
28
+ @patched
29
+ end
30
+
31
+ private
32
+
33
+ def compatible?
34
+ return unless defined?(::Faraday::VERSION)
35
+
36
+ Gem::Version.new(::Faraday::VERSION) < COMPATIBLE_UNTIL
37
+ end
38
+
39
+ def add_pin
40
+ Pin.new(SERVICE, app_type: Ext::AppTypes::WEB).tap do |pin|
41
+ pin.onto(::Faraday)
42
+ end
43
+ end
44
+
45
+ def add_middleware
46
+ ::Faraday::Middleware.register_middleware(ddtrace: Middleware)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end