aws-xray-sdk 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/aws-xray-sdk.rb +10 -0
- data/lib/aws-xray-sdk/configuration.rb +158 -0
- data/lib/aws-xray-sdk/context/context.rb +26 -0
- data/lib/aws-xray-sdk/context/default_context.rb +81 -0
- data/lib/aws-xray-sdk/emitter/default_emitter.rb +53 -0
- data/lib/aws-xray-sdk/emitter/emitter.rb +24 -0
- data/lib/aws-xray-sdk/exceptions.rb +31 -0
- data/lib/aws-xray-sdk/facets/aws_sdk.rb +127 -0
- data/lib/aws-xray-sdk/facets/helper.rb +61 -0
- data/lib/aws-xray-sdk/facets/net_http.rb +61 -0
- data/lib/aws-xray-sdk/facets/rack.rb +87 -0
- data/lib/aws-xray-sdk/facets/rails/active_record.rb +66 -0
- data/lib/aws-xray-sdk/facets/rails/ex_middleware.rb +24 -0
- data/lib/aws-xray-sdk/facets/rails/railtie.rb +23 -0
- data/lib/aws-xray-sdk/facets/resources/aws_params_whitelist.rb +340 -0
- data/lib/aws-xray-sdk/facets/resources/aws_services_whitelist.rb +147 -0
- data/lib/aws-xray-sdk/logger.rb +19 -0
- data/lib/aws-xray-sdk/model/annotations.rb +97 -0
- data/lib/aws-xray-sdk/model/cause.rb +70 -0
- data/lib/aws-xray-sdk/model/dummy_entities.rb +72 -0
- data/lib/aws-xray-sdk/model/entity.rb +187 -0
- data/lib/aws-xray-sdk/model/metadata.rb +77 -0
- data/lib/aws-xray-sdk/model/segment.rb +63 -0
- data/lib/aws-xray-sdk/model/subsegment.rb +67 -0
- data/lib/aws-xray-sdk/model/trace_header.rb +54 -0
- data/lib/aws-xray-sdk/patcher.rb +21 -0
- data/lib/aws-xray-sdk/plugins/ec2.rb +39 -0
- data/lib/aws-xray-sdk/plugins/ecs.rb +23 -0
- data/lib/aws-xray-sdk/plugins/elastic_beanstalk.rb +25 -0
- data/lib/aws-xray-sdk/recorder.rb +209 -0
- data/lib/aws-xray-sdk/sampling/default_sampler.rb +105 -0
- data/lib/aws-xray-sdk/sampling/reservoir.rb +35 -0
- data/lib/aws-xray-sdk/sampling/sampler.rb +27 -0
- data/lib/aws-xray-sdk/sampling/sampling_rule.rb +57 -0
- data/lib/aws-xray-sdk/search_pattern.rb +82 -0
- data/lib/aws-xray-sdk/segment_naming/dynamic_naming.rb +26 -0
- data/lib/aws-xray-sdk/segment_naming/segment_naming.rb +10 -0
- data/lib/aws-xray-sdk/streaming/default_streamer.rb +53 -0
- data/lib/aws-xray-sdk/streaming/streamer.rb +17 -0
- data/lib/aws-xray-sdk/version.rb +3 -0
- metadata +224 -0
@@ -0,0 +1,147 @@
|
|
1
|
+
module XRay
|
2
|
+
# AWS Services listed below will be recorded as subsegments
|
3
|
+
module AwsServices
|
4
|
+
# exausted list can be tracked at http://docs.aws.amazon.com/sdk-for-ruby/v3/api/Seahorse/Client/Base.html
|
5
|
+
@whitelist = %I[
|
6
|
+
ACM
|
7
|
+
APIGateway
|
8
|
+
AlexaForBusiness
|
9
|
+
AppStream
|
10
|
+
AppSync
|
11
|
+
ApplicationAutoScaling
|
12
|
+
ApplicationDiscoveryService
|
13
|
+
Athena
|
14
|
+
AutoScaling
|
15
|
+
Batch
|
16
|
+
Budgets
|
17
|
+
Cloud9
|
18
|
+
CloudDirectory
|
19
|
+
CloudFormatioin
|
20
|
+
CloudFront
|
21
|
+
CloudHSM
|
22
|
+
CloudHSMV2
|
23
|
+
CloudSearch
|
24
|
+
CloudSearchDomain
|
25
|
+
CloudTrail
|
26
|
+
CloudWatch
|
27
|
+
CloudWatchEvents
|
28
|
+
CloudWatchLogs
|
29
|
+
CodeBuild
|
30
|
+
CodeCommit
|
31
|
+
CodeDeploy
|
32
|
+
CodePipeline
|
33
|
+
CodeStar
|
34
|
+
CognitoIdentity
|
35
|
+
CognitoIdentityProvider
|
36
|
+
CognitoSync
|
37
|
+
Comprehend
|
38
|
+
ConfigService
|
39
|
+
CostExplore
|
40
|
+
CostandUsageReportService
|
41
|
+
DAX
|
42
|
+
DataPipeline
|
43
|
+
DatabaseMigrationService
|
44
|
+
DeviceFarm
|
45
|
+
DirectConnect
|
46
|
+
DirectoryService
|
47
|
+
DynamoDB
|
48
|
+
DynamoDBStreams
|
49
|
+
EC2
|
50
|
+
ECR
|
51
|
+
ECS
|
52
|
+
EFS
|
53
|
+
EMR
|
54
|
+
ElastiCache
|
55
|
+
ElasticBeanstalk
|
56
|
+
ElasticLoadBalancing
|
57
|
+
ElasticLoadBalancingV2
|
58
|
+
ElasticTranscoder
|
59
|
+
ElasticsearchService
|
60
|
+
Firehost
|
61
|
+
GameLift
|
62
|
+
Glacier
|
63
|
+
Glue
|
64
|
+
Greengrass
|
65
|
+
GuardDuty
|
66
|
+
Health
|
67
|
+
IAM
|
68
|
+
ImportExport
|
69
|
+
Inspector
|
70
|
+
IoT
|
71
|
+
IoTDataPlane
|
72
|
+
IoTJobsDataPlane
|
73
|
+
KMS
|
74
|
+
Kinesis
|
75
|
+
KinesisAnalytics
|
76
|
+
KinesisVideo
|
77
|
+
KinesisVideoArchiveMedia
|
78
|
+
KinesisVideoMedia
|
79
|
+
Lambda
|
80
|
+
LambdaPreview
|
81
|
+
Lex
|
82
|
+
LexModelBuildingService
|
83
|
+
LexRuntimeService
|
84
|
+
Lightsail
|
85
|
+
MQ
|
86
|
+
MTurk
|
87
|
+
MachineLearning
|
88
|
+
MarketplaceCommerceAnalytics
|
89
|
+
MarketplaceEntitlementService
|
90
|
+
MarketplaceMetering
|
91
|
+
MediaConvert
|
92
|
+
MediaLive
|
93
|
+
MediaPackage
|
94
|
+
MediaStore
|
95
|
+
MediaStoreData
|
96
|
+
MigrationHub
|
97
|
+
Mobile
|
98
|
+
OpsWorks
|
99
|
+
OpsWorksCM
|
100
|
+
Organizations
|
101
|
+
Pinpoint
|
102
|
+
Polly
|
103
|
+
Pricing
|
104
|
+
RDS
|
105
|
+
Redshift
|
106
|
+
Rekognition
|
107
|
+
ResourceGroups
|
108
|
+
ResourceGroupsTaggingAPI
|
109
|
+
Route53
|
110
|
+
Route53Domains
|
111
|
+
S3
|
112
|
+
SES
|
113
|
+
SFN
|
114
|
+
SMS
|
115
|
+
SNS
|
116
|
+
SQS
|
117
|
+
SSM
|
118
|
+
STS
|
119
|
+
SWF
|
120
|
+
SageMaker
|
121
|
+
SageMakerRuntime
|
122
|
+
ServerlessApplicationRepository
|
123
|
+
ServiceCatalog
|
124
|
+
ServiceDiscovery
|
125
|
+
Shield
|
126
|
+
SimpleDB
|
127
|
+
Snowball
|
128
|
+
States
|
129
|
+
StorageGateway
|
130
|
+
Support
|
131
|
+
Translate
|
132
|
+
WAF
|
133
|
+
WAFRegional
|
134
|
+
WorkDocs
|
135
|
+
WorkSpaces
|
136
|
+
XRay
|
137
|
+
]
|
138
|
+
|
139
|
+
def self.whitelist
|
140
|
+
@whitelist
|
141
|
+
end
|
142
|
+
|
143
|
+
def self.whitelist=(v)
|
144
|
+
@whitelist = v
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module XRay
|
4
|
+
# Provide global logger for classes that include this module.
|
5
|
+
# It serves as a proxy to global recorder's logger.
|
6
|
+
module Logging
|
7
|
+
def logger
|
8
|
+
Logging.logger
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.logger
|
12
|
+
@logger ||= Logger.new($stdout).tap { |l| l.level = Logger::INFO }
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.logger=(v)
|
16
|
+
@logger = v
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'aws-xray-sdk/logger'
|
2
|
+
require 'aws-xray-sdk/exceptions'
|
3
|
+
|
4
|
+
module XRay
|
5
|
+
# Annotations are simple key-value pairs that are indexed for use with filter expressions.
|
6
|
+
# Use annotations to record data that you want to use to group traces in the console,
|
7
|
+
# or when calling the GetTraceSummaries API.
|
8
|
+
class Annotations
|
9
|
+
include Logging
|
10
|
+
|
11
|
+
def initialize(entity)
|
12
|
+
@entity = entity
|
13
|
+
@data = {}
|
14
|
+
end
|
15
|
+
|
16
|
+
def [](key)
|
17
|
+
@data[key]
|
18
|
+
end
|
19
|
+
|
20
|
+
# @param [Symbol] k Only characters in `A-Za-z0-9_` are supported.
|
21
|
+
# @param v Only `Numeric`, `String` true/false is supported.
|
22
|
+
def []=(k, v)
|
23
|
+
raise EntityClosedError if @entity.closed?
|
24
|
+
if key_supported?(k) && value_supported?(v)
|
25
|
+
@data[k] = v
|
26
|
+
else
|
27
|
+
logger.warn %(Dropping annotation with key #{k} due to invalid characters.)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# @param [Hash] h Update annotations with a single input hash.
|
32
|
+
def update(h)
|
33
|
+
raise EntityClosedError if @entity.closed?
|
34
|
+
filtered = filter_annotations(h)
|
35
|
+
@data.merge!(filtered)
|
36
|
+
end
|
37
|
+
|
38
|
+
def to_h
|
39
|
+
sanitize_values(@data)
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def filter_annotations(h)
|
45
|
+
h.delete_if do |k, v|
|
46
|
+
drop = !key_supported?(k) || !value_supported?(v)
|
47
|
+
logger.warn %(Dropping annotation with key #{k} due to invalid characters.) if drop
|
48
|
+
drop
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def sanitize_values(h)
|
53
|
+
h.each_pair do |k, v|
|
54
|
+
if v.is_a?(Float)
|
55
|
+
h[k] = v.to_s if v.nan? || v.infinite? == 1 || v.infinite? == -1
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def key_supported?(k)
|
61
|
+
k.match(/[A-Za-z0-9_]+/)
|
62
|
+
end
|
63
|
+
|
64
|
+
def value_supported?(v)
|
65
|
+
case v
|
66
|
+
when Numeric
|
67
|
+
true
|
68
|
+
when true, false
|
69
|
+
true
|
70
|
+
else
|
71
|
+
v.is_a?(String)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Singleton facade annotations class doing no-op for performance
|
77
|
+
# in case of not sampled X-Ray entities.
|
78
|
+
module FacadeAnnotations
|
79
|
+
class << self
|
80
|
+
def [](key)
|
81
|
+
# no-op
|
82
|
+
end
|
83
|
+
|
84
|
+
def []=(k, v)
|
85
|
+
# no-op
|
86
|
+
end
|
87
|
+
|
88
|
+
def update(h)
|
89
|
+
# no-op
|
90
|
+
end
|
91
|
+
|
92
|
+
def to_h
|
93
|
+
# no-op
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'oj'
|
2
|
+
|
3
|
+
module XRay
|
4
|
+
# Represents cause section in segment and subsegment document.
|
5
|
+
# It records information about application runtime exceptions.
|
6
|
+
class Cause
|
7
|
+
attr_reader :id
|
8
|
+
@@depth = 15
|
9
|
+
|
10
|
+
def initialize(exception: nil, id: nil, remote: false)
|
11
|
+
if exception
|
12
|
+
@exception_h = normalize e: exception, remote: remote
|
13
|
+
end
|
14
|
+
@id = id
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_h
|
18
|
+
return id if id
|
19
|
+
h = {
|
20
|
+
working_directory: Dir.pwd,
|
21
|
+
paths: Gem.paths.path,
|
22
|
+
exceptions: @exception_h
|
23
|
+
}
|
24
|
+
h
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_json
|
28
|
+
@to_json ||= begin
|
29
|
+
Oj.dump to_h, mode: :compat, use_as_json: true
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def normalize(e:, remote: false)
|
36
|
+
exceptions = []
|
37
|
+
exceptions << normalize_exception(e: e, remote: remote)
|
38
|
+
|
39
|
+
# don't propagate remote flag
|
40
|
+
while e.cause
|
41
|
+
exceptions << normalize_exception(e: e.cause)
|
42
|
+
e = e.cause
|
43
|
+
end
|
44
|
+
|
45
|
+
exceptions
|
46
|
+
end
|
47
|
+
|
48
|
+
def normalize_exception(e:, remote: false)
|
49
|
+
h = {
|
50
|
+
message: e.to_s,
|
51
|
+
type: e.class.to_s
|
52
|
+
}
|
53
|
+
h[:remote] = true if remote
|
54
|
+
|
55
|
+
backtrace = e.backtrace_locations
|
56
|
+
return h unless backtrace
|
57
|
+
h[:stack] = backtrace.first(@@depth).collect do |t|
|
58
|
+
{
|
59
|
+
path: t.path,
|
60
|
+
line: t.lineno,
|
61
|
+
label: t.label
|
62
|
+
}
|
63
|
+
end
|
64
|
+
|
65
|
+
truncated = backtrace.size - @@depth
|
66
|
+
h[:truncated] = truncated if truncated > 0
|
67
|
+
h
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'aws-xray-sdk/model/segment'
|
2
|
+
require 'aws-xray-sdk/model/subsegment'
|
3
|
+
require 'aws-xray-sdk/model/annotations'
|
4
|
+
require 'aws-xray-sdk/model/metadata'
|
5
|
+
|
6
|
+
module XRay
|
7
|
+
# defines common no-op methods for dummy segments/subsegments
|
8
|
+
module DummyEntity
|
9
|
+
def sampled
|
10
|
+
false
|
11
|
+
end
|
12
|
+
|
13
|
+
def annotations
|
14
|
+
FacadeAnnotations
|
15
|
+
end
|
16
|
+
|
17
|
+
def metadata(namespace: :default)
|
18
|
+
FacadeMetadata
|
19
|
+
end
|
20
|
+
|
21
|
+
def apply_status_code(status:)
|
22
|
+
# no-op
|
23
|
+
end
|
24
|
+
|
25
|
+
def merge_http_request(request:)
|
26
|
+
# no-op
|
27
|
+
end
|
28
|
+
|
29
|
+
def merge_http_response(response:)
|
30
|
+
# no-op
|
31
|
+
end
|
32
|
+
|
33
|
+
def add_exception(exception:, remote: false)
|
34
|
+
# no-op
|
35
|
+
end
|
36
|
+
|
37
|
+
def aws=(v)
|
38
|
+
# no-op
|
39
|
+
end
|
40
|
+
|
41
|
+
def to_h
|
42
|
+
# no-op
|
43
|
+
end
|
44
|
+
|
45
|
+
def to_json
|
46
|
+
# no-op
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# A dummy segment is created when ``xray_recorder`` decides to not sample
|
51
|
+
# the segment based on sampling decisions.
|
52
|
+
# Adding data to a dummy segment becomes a no-op except for
|
53
|
+
# subsegments. This is to reduce the memory footprint of the SDK.
|
54
|
+
# A dummy segment will not be sent to the X-Ray daemon by the default emitter.
|
55
|
+
# Manually create dummy segments is not recommended.
|
56
|
+
class DummySegment < Segment
|
57
|
+
include DummyEntity
|
58
|
+
end
|
59
|
+
|
60
|
+
# A dummy subsegment will be created when ``xray_recorder`` tries
|
61
|
+
# to create a subsegment under a not sampled segment. Adding data
|
62
|
+
# to a dummy subsegment becomes no-op except for child subsegments.
|
63
|
+
# Dummy subsegment will not be sent to the X-Ray daemon by the default emitter.
|
64
|
+
# Manually create dummy subsegments is not recommended.
|
65
|
+
class DummySubsegment < Subsegment
|
66
|
+
include DummyEntity
|
67
|
+
|
68
|
+
def sql=(v)
|
69
|
+
# no-op
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,187 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
require 'bigdecimal'
|
3
|
+
require 'oj'
|
4
|
+
require 'aws-xray-sdk/exceptions'
|
5
|
+
require 'aws-xray-sdk/model/cause'
|
6
|
+
require 'aws-xray-sdk/model/annotations'
|
7
|
+
require 'aws-xray-sdk/model/metadata'
|
8
|
+
|
9
|
+
module XRay
|
10
|
+
# This module contains common properties and methods
|
11
|
+
# used by segment and subsegment class.
|
12
|
+
module Entity
|
13
|
+
attr_reader :name, :exception, :cause, :namespace,
|
14
|
+
:http_request, :http_response
|
15
|
+
attr_accessor :parent, :throttle, :error, :fault, :sampled, :aws,
|
16
|
+
:start_time, :end_time
|
17
|
+
|
18
|
+
HTTP_REQUEST_KEY = %I[url method user_agent client_ip x_forwarded_for].freeze
|
19
|
+
HTTP_RESPONSE_KEY = %I[status content_length].freeze
|
20
|
+
|
21
|
+
# Generates a random 8-digit hex number as the entity id and returns it.
|
22
|
+
def id
|
23
|
+
@id ||= begin
|
24
|
+
SecureRandom.hex(8)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def closed?
|
29
|
+
@closed ||= false
|
30
|
+
end
|
31
|
+
|
32
|
+
# @param [Float] end_time End time on epoch.
|
33
|
+
def close(end_time: nil)
|
34
|
+
raise EntityClosedError if closed?
|
35
|
+
@end_time = end_time || Time.now.to_f
|
36
|
+
@closed = true
|
37
|
+
end
|
38
|
+
|
39
|
+
# @return [Array] The children subsegments of this entity.
|
40
|
+
def subsegments
|
41
|
+
@subsegments ||= []
|
42
|
+
end
|
43
|
+
|
44
|
+
# @param [Subsegment] subsegment Append the provided subsegment to children subsegments.
|
45
|
+
def add_subsegment(subsegment:)
|
46
|
+
raise EntityClosedError if closed?
|
47
|
+
subsegment.sampled = sampled
|
48
|
+
subsegment.parent = self
|
49
|
+
subsegments << subsegment
|
50
|
+
nil
|
51
|
+
end
|
52
|
+
|
53
|
+
# @param [Subsegment] subsegment Remove the provided subsegment from children subsegments.
|
54
|
+
# @return [Subsegment] The deleted subsegment if the deletion is successful.
|
55
|
+
def remove_subsegment(subsegment:)
|
56
|
+
subsegments.delete(subsegment)
|
57
|
+
subsegment
|
58
|
+
end
|
59
|
+
|
60
|
+
def annotations
|
61
|
+
@annotations ||= Annotations.new(self)
|
62
|
+
end
|
63
|
+
|
64
|
+
def metadata(namespace: :default)
|
65
|
+
@metadata ||= Metadata.new(self)
|
66
|
+
@metadata.sub_meta(namespace)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Set error/fault/throttle flags based on http status code.
|
70
|
+
# This method is idempotent.
|
71
|
+
# @param [Integer] status
|
72
|
+
def apply_status_code(status:)
|
73
|
+
raise EntityClosedError if closed?
|
74
|
+
case status.to_i
|
75
|
+
when 429
|
76
|
+
@throttle = true
|
77
|
+
@error = true
|
78
|
+
@fault = false
|
79
|
+
when 400..499
|
80
|
+
@error = true
|
81
|
+
@throttle = false
|
82
|
+
@fault = false
|
83
|
+
when 500..599
|
84
|
+
@fault = true
|
85
|
+
@error = false
|
86
|
+
@throttle = false
|
87
|
+
end
|
88
|
+
|
89
|
+
@http_response ||= {}
|
90
|
+
@http_response[:status] = status.to_i
|
91
|
+
end
|
92
|
+
|
93
|
+
# @param [Hash] request Supported keys are `:url`, `:user_agent`, `:client_ip`,
|
94
|
+
# `:x_forwarded_for`, `:method`. Value can be one of
|
95
|
+
# String or Integer or Boolean types depend on the key.
|
96
|
+
def merge_http_request(request:)
|
97
|
+
raise EntityClosedError if closed?
|
98
|
+
request.delete_if { |k| !HTTP_REQUEST_KEY.include?(k) }
|
99
|
+
@http_request ||= {}
|
100
|
+
@http_request.merge!(request)
|
101
|
+
end
|
102
|
+
|
103
|
+
# @param [Hash] response Supported keys are `:status`, `:content_length`.
|
104
|
+
# Value can be one of String or Integer types depend on the key.
|
105
|
+
def merge_http_response(response:)
|
106
|
+
raise EntityClosedError if closed?
|
107
|
+
response.delete_if { |k| !HTTP_RESPONSE_KEY.include?(k) }
|
108
|
+
@http_response ||= {}
|
109
|
+
@http_response.merge!(response)
|
110
|
+
apply_status_code status: response[:status] if response.key?(:status)
|
111
|
+
end
|
112
|
+
|
113
|
+
# @param [Exception] exception The exception object to capture.
|
114
|
+
# @param remote A boolean flag indicates whether the exception is
|
115
|
+
# returned from the downstream service.
|
116
|
+
def add_exception(exception:, remote: false)
|
117
|
+
raise EntityClosedError if closed?
|
118
|
+
@fault = true
|
119
|
+
@exception = exception
|
120
|
+
if cause_id = find_root_cause(exception)
|
121
|
+
@cause = Cause.new id: cause_id
|
122
|
+
else
|
123
|
+
@cause = Cause.new exception: exception, remote: remote
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# @return [String] Cause id is the id of the subsegment where
|
128
|
+
# the exception originally comes from.
|
129
|
+
def cause_id
|
130
|
+
return @cause.id if @cause
|
131
|
+
end
|
132
|
+
|
133
|
+
# @return [Hash] The hash that contains all attributes that will
|
134
|
+
# be later serialized and sent out.
|
135
|
+
def to_h
|
136
|
+
h = {
|
137
|
+
name: name,
|
138
|
+
id: id,
|
139
|
+
start_time: start_time
|
140
|
+
}
|
141
|
+
if closed?
|
142
|
+
h[:end_time] = end_time
|
143
|
+
else
|
144
|
+
h[:in_progress] = true
|
145
|
+
end
|
146
|
+
h[:subsegments] = subsegments unless subsegments.empty?
|
147
|
+
h[:aws] = aws if aws
|
148
|
+
if http_request || http_response
|
149
|
+
h[:http] = {}
|
150
|
+
h[:http][:request] = http_request if http_request
|
151
|
+
h[:http][:response] = http_response if http_response
|
152
|
+
end
|
153
|
+
if (a = annotations.to_h) && !a.empty?
|
154
|
+
h[:annotations] = a
|
155
|
+
end
|
156
|
+
if (m = @metadata) && !m.to_h.empty?
|
157
|
+
h[:metadata] = m.to_h
|
158
|
+
end
|
159
|
+
|
160
|
+
h[:parent_id] = parent.id if parent
|
161
|
+
# make sure the value in hash can only be boolean true
|
162
|
+
h[:fault] = !!fault if fault
|
163
|
+
h[:error] = !!error if error
|
164
|
+
h[:throttle] = !!throttle if throttle
|
165
|
+
h[:cause] = cause.to_h if cause
|
166
|
+
h
|
167
|
+
end
|
168
|
+
|
169
|
+
def to_json
|
170
|
+
@to_json ||= begin
|
171
|
+
Oj.dump to_h, mode: :compat, use_as_json: true
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
private
|
176
|
+
|
177
|
+
def find_root_cause(e)
|
178
|
+
subsegment = subsegments.find { |i| i.exception.hash == e.hash }
|
179
|
+
return nil unless subsegment
|
180
|
+
if cause_id = subsegment.cause_id
|
181
|
+
cause_id
|
182
|
+
else
|
183
|
+
subsegment.id
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|