hoss-agent 1.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. checksums.yaml +7 -0
  2. data/.github/ISSUE_TEMPLATE/Bug_report.md +40 -0
  3. data/.github/ISSUE_TEMPLATE/Feature_request.md +17 -0
  4. data/.github/PULL_REQUEST_TEMPLATE.md +60 -0
  5. data/.gitignore +27 -0
  6. data/.rspec +2 -0
  7. data/Dockerfile +43 -0
  8. data/Gemfile +105 -0
  9. data/LICENSE +201 -0
  10. data/hoss-agent.gemspec +42 -0
  11. data/lib/hoss-agent.rb +210 -0
  12. data/lib/hoss.rb +21 -0
  13. data/lib/hoss/agent.rb +235 -0
  14. data/lib/hoss/central_config.rb +184 -0
  15. data/lib/hoss/central_config/cache_control.rb +51 -0
  16. data/lib/hoss/child_durations.rb +64 -0
  17. data/lib/hoss/config.rb +315 -0
  18. data/lib/hoss/config/bytes.rb +42 -0
  19. data/lib/hoss/config/duration.rb +40 -0
  20. data/lib/hoss/config/options.rb +154 -0
  21. data/lib/hoss/config/regexp_list.rb +30 -0
  22. data/lib/hoss/config/wildcard_pattern_list.rb +54 -0
  23. data/lib/hoss/context.rb +64 -0
  24. data/lib/hoss/context/request.rb +28 -0
  25. data/lib/hoss/context/request/socket.rb +36 -0
  26. data/lib/hoss/context/request/url.rb +59 -0
  27. data/lib/hoss/context/response.rb +47 -0
  28. data/lib/hoss/context/user.rb +59 -0
  29. data/lib/hoss/context_builder.rb +112 -0
  30. data/lib/hoss/deprecations.rb +39 -0
  31. data/lib/hoss/error.rb +49 -0
  32. data/lib/hoss/error/exception.rb +70 -0
  33. data/lib/hoss/error/log.rb +41 -0
  34. data/lib/hoss/error_builder.rb +90 -0
  35. data/lib/hoss/event.rb +131 -0
  36. data/lib/hoss/instrumenter.rb +107 -0
  37. data/lib/hoss/internal_error.rb +23 -0
  38. data/lib/hoss/logging.rb +70 -0
  39. data/lib/hoss/metadata.rb +36 -0
  40. data/lib/hoss/metadata/process_info.rb +35 -0
  41. data/lib/hoss/metadata/service_info.rb +76 -0
  42. data/lib/hoss/metadata/system_info.rb +47 -0
  43. data/lib/hoss/metadata/system_info/container_info.rb +136 -0
  44. data/lib/hoss/naively_hashable.rb +38 -0
  45. data/lib/hoss/rails.rb +68 -0
  46. data/lib/hoss/railtie.rb +42 -0
  47. data/lib/hoss/report.rb +9 -0
  48. data/lib/hoss/sinatra.rb +53 -0
  49. data/lib/hoss/spies.rb +104 -0
  50. data/lib/hoss/spies/faraday.rb +117 -0
  51. data/lib/hoss/spies/http.rb +93 -0
  52. data/lib/hoss/spies/net_http.rb +113 -0
  53. data/lib/hoss/stacktrace.rb +33 -0
  54. data/lib/hoss/stacktrace/frame.rb +66 -0
  55. data/lib/hoss/stacktrace_builder.rb +124 -0
  56. data/lib/hoss/transport/base.rb +191 -0
  57. data/lib/hoss/transport/connection.rb +55 -0
  58. data/lib/hoss/transport/connection/http.rb +139 -0
  59. data/lib/hoss/transport/connection/proxy_pipe.rb +94 -0
  60. data/lib/hoss/transport/filters.rb +60 -0
  61. data/lib/hoss/transport/filters/hash_sanitizer.rb +77 -0
  62. data/lib/hoss/transport/filters/secrets_filter.rb +48 -0
  63. data/lib/hoss/transport/headers.rb +74 -0
  64. data/lib/hoss/transport/serializers.rb +113 -0
  65. data/lib/hoss/transport/serializers/context_serializer.rb +112 -0
  66. data/lib/hoss/transport/serializers/error_serializer.rb +92 -0
  67. data/lib/hoss/transport/serializers/event_serializer.rb +73 -0
  68. data/lib/hoss/transport/serializers/metadata_serializer.rb +92 -0
  69. data/lib/hoss/transport/serializers/report_serializer.rb +33 -0
  70. data/lib/hoss/transport/user_agent.rb +48 -0
  71. data/lib/hoss/transport/worker.rb +330 -0
  72. data/lib/hoss/util.rb +54 -0
  73. data/lib/hoss/util/inflector.rb +110 -0
  74. data/lib/hoss/util/lru_cache.rb +65 -0
  75. data/lib/hoss/util/throttle.rb +52 -0
  76. data/lib/hoss/version.rb +22 -0
  77. metadata +147 -0
@@ -0,0 +1,59 @@
1
+ # Licensed to Elasticsearch B.V. under one or more contributor
2
+ # license agreements. See the NOTICE file distributed with
3
+ # this work for additional information regarding copyright
4
+ # ownership. Elasticsearch B.V. licenses this file to you under
5
+ # the Apache License, Version 2.0 (the "License"); you may
6
+ # not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ # frozen_string_literal: true
19
+
20
+ module Hoss
21
+ # @api private
22
+ class Context
23
+ # @api private
24
+ class Request
25
+ # @api private
26
+ class Url
27
+ SKIPPED_PORTS = {
28
+ 'http' => 80,
29
+ 'https' => 443
30
+ }.freeze
31
+
32
+ def initialize(req)
33
+ @protocol = req.scheme
34
+ @hostname = req.host
35
+ @port = req.port.to_s
36
+ @pathname = req.path
37
+ @search = req.query_string
38
+ @hash = nil
39
+ @full = build_full_url req
40
+ end
41
+
42
+ attr_reader :protocol, :hostname, :port, :pathname, :search, :hash,
43
+ :full
44
+
45
+ private
46
+
47
+ def build_full_url(req)
48
+ url = "#{req.scheme}://#{req.host}"
49
+
50
+ if req.port != SKIPPED_PORTS[req.scheme]
51
+ url += ":#{req.port}"
52
+ end
53
+
54
+ url + req.fullpath
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,47 @@
1
+ # Licensed to Elasticsearch B.V. under one or more contributor
2
+ # license agreements. See the NOTICE file distributed with
3
+ # this work for additional information regarding copyright
4
+ # ownership. Elasticsearch B.V. licenses this file to you under
5
+ # the Apache License, Version 2.0 (the "License"); you may
6
+ # not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ # frozen_string_literal: true
19
+
20
+ module Hoss
21
+ class Context
22
+ # @api private
23
+ class Response
24
+ def initialize(
25
+ status_code,
26
+ headers: {},
27
+ headers_sent: true,
28
+ finished: true
29
+ )
30
+ @status_code = status_code
31
+ @headers_sent = headers_sent
32
+ @finished = finished
33
+
34
+ self.headers = headers
35
+ end
36
+
37
+ attr_accessor :status_code, :headers_sent, :finished
38
+ attr_reader :headers
39
+
40
+ def headers=(headers)
41
+ @headers = headers&.each_with_object({}) do |(k, v), hsh|
42
+ hsh[k] = v.to_s
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,59 @@
1
+ # Licensed to Elasticsearch B.V. under one or more contributor
2
+ # license agreements. See the NOTICE file distributed with
3
+ # this work for additional information regarding copyright
4
+ # ownership. Elasticsearch B.V. licenses this file to you under
5
+ # the Apache License, Version 2.0 (the "License"); you may
6
+ # not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ # frozen_string_literal: true
19
+
20
+ module Hoss
21
+ class Context
22
+ # @api private
23
+ class User
24
+ def initialize(id: nil, email: nil, username: nil)
25
+ @id = id
26
+ @email = email
27
+ @username = username
28
+ end
29
+
30
+ def self.infer(config, record)
31
+ return unless record
32
+
33
+ new(
34
+ id: safe_get(record, config.current_user_id_method)&.to_s,
35
+ email: safe_get(record, config.current_user_email_method),
36
+ username: safe_get(record, config.current_user_username_method)
37
+ )
38
+ end
39
+
40
+ attr_accessor :id, :email, :username
41
+
42
+ def empty?
43
+ !id && !email && !username
44
+ end
45
+
46
+ def any?
47
+ !empty?
48
+ end
49
+
50
+ class << self
51
+ private
52
+
53
+ def safe_get(record, method_name)
54
+ record.respond_to?(method_name) ? record.send(method_name) : nil
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,112 @@
1
+ # Licensed to Elasticsearch B.V. under one or more contributor
2
+ # license agreements. See the NOTICE file distributed with
3
+ # this work for additional information regarding copyright
4
+ # ownership. Elasticsearch B.V. licenses this file to you under
5
+ # the Apache License, Version 2.0 (the "License"); you may
6
+ # not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ # frozen_string_literal: true
19
+
20
+ module Hoss
21
+ # @api private
22
+ class ContextBuilder
23
+ MAX_BODY_LENGTH = 2048
24
+ SKIPPED = '[SKIPPED]'
25
+
26
+ def initialize(config)
27
+ @config = config
28
+ end
29
+
30
+ attr_reader :config
31
+
32
+ def build(rack_env:, for_type:)
33
+ Context.new.tap do |context|
34
+ apply_to_request(context, rack_env: rack_env, for_type: for_type)
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ def apply_to_request(context, rack_env:, for_type:)
41
+ req = rails_req?(rack_env) ? rack_env : Rack::Request.new(rack_env)
42
+
43
+ context.request = Context::Request.new unless context.request
44
+ request = context.request
45
+
46
+ request.socket = Context::Request::Socket.new(req)
47
+ request.http_version = build_http_version rack_env
48
+ request.method = req.request_method
49
+ request.url = Context::Request::Url.new(req)
50
+
51
+ request.body = should_capture_body?(for_type) ? get_body(req) : SKIPPED
52
+
53
+ headers, env = get_headers_and_env(rack_env)
54
+ request.headers = headers if config.capture_headers?
55
+ request.env = env if config.capture_env?
56
+
57
+ request.cookies = req.cookies.dup
58
+
59
+ context
60
+ end
61
+
62
+ def should_capture_body?(for_type)
63
+ option = config.capture_body
64
+
65
+ return true if option == 'all'
66
+ return true if option == 'transactions' && for_type == :transaction
67
+ return true if option == 'errors' && for_type == :error
68
+
69
+ false
70
+ end
71
+
72
+ def get_body(req)
73
+ case req.media_type
74
+ when 'application/x-www-form-urlencoded', 'multipart/form-data'
75
+ req.POST.dup
76
+ else
77
+ body = req.body.read
78
+ req.body.rewind
79
+ body.byteslice(0, MAX_BODY_LENGTH).force_encoding('utf-8')
80
+ end
81
+ end
82
+
83
+ def rails_req?(env)
84
+ defined?(ActionDispatch::Request) && env.is_a?(ActionDispatch::Request)
85
+ end
86
+
87
+ def get_headers_and_env(rack_env)
88
+ # In Rails < 5 ActionDispatch::Request inherits from Hash
89
+ headers =
90
+ rack_env.respond_to?(:headers) ? rack_env.headers : rack_env
91
+
92
+ headers.each_with_object([{}, {}]) do |(key, value), (http, env)|
93
+ next unless key == key.upcase
94
+
95
+ if key.start_with?('HTTP_')
96
+ http[camel_key(key)] = value
97
+ else
98
+ env[key] = value
99
+ end
100
+ end
101
+ end
102
+
103
+ def camel_key(key)
104
+ key.gsub(/^HTTP_/, '').split('_').map(&:capitalize).join('-')
105
+ end
106
+
107
+ def build_http_version(rack_env)
108
+ return unless (http_version = rack_env['HTTP_VERSION'])
109
+ http_version.gsub(%r{HTTP/}, '')
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,39 @@
1
+ # Licensed to Elasticsearch B.V. under one or more contributor
2
+ # license agreements. See the NOTICE file distributed with
3
+ # this work for additional information regarding copyright
4
+ # ownership. Elasticsearch B.V. licenses this file to you under
5
+ # the Apache License, Version 2.0 (the "License"); you may
6
+ # not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ # frozen_string_literal: true
19
+
20
+ module Hoss
21
+ # @api private
22
+ module Deprecations
23
+ def deprecate(name, replacement = nil)
24
+ alias_name = "#{name.to_s.chomp('=')}__deprecated_"
25
+ alias_name += '=' if name.to_s.end_with?('=')
26
+
27
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
28
+ alias :"#{alias_name}" :"#{name}"
29
+
30
+ def #{name}(*args, &block)
31
+ warn "[HOSS] [DEPRECATED] `#{name}' is being removed. " \
32
+ "#{replacement && "See `#{replacement}'."}" \
33
+ "\nCalled from \#{caller.first}"
34
+ send("#{alias_name}", *args, &block)
35
+ end
36
+ RUBY
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,49 @@
1
+ # Licensed to Elasticsearch B.V. under one or more contributor
2
+ # license agreements. See the NOTICE file distributed with
3
+ # this work for additional information regarding copyright
4
+ # ownership. Elasticsearch B.V. licenses this file to you under
5
+ # the Apache License, Version 2.0 (the "License"); you may
6
+ # not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ # frozen_string_literal: true
19
+
20
+ require 'hoss/stacktrace'
21
+ require 'hoss/context'
22
+ require 'hoss/error/exception'
23
+ require 'hoss/error/log'
24
+
25
+ module Hoss
26
+ # @api private
27
+ class Error
28
+ def initialize(culprit: nil, context: nil)
29
+ @id = SecureRandom.hex(16)
30
+ @culprit = culprit
31
+ @timestamp = Util.micros
32
+ @context = context
33
+ end
34
+
35
+ attr_accessor :id, :culprit, :exception, :log, :transaction_id,
36
+ :transaction, :context, :parent_id, :trace_id
37
+ attr_reader :timestamp
38
+
39
+ def inspect
40
+ "<Hoss::Error id:#{id}" \
41
+ " culprit:#{culprit}" \
42
+ " timestamp:#{timestamp}" \
43
+ " transaction_id:#{transaction_id}" \
44
+ " trace_id:#{trace_id}" \
45
+ " exception:#{exception.inspect}" \
46
+ '>'
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,70 @@
1
+ # Licensed to Elasticsearch B.V. under one or more contributor
2
+ # license agreements. See the NOTICE file distributed with
3
+ # this work for additional information regarding copyright
4
+ # ownership. Elasticsearch B.V. licenses this file to you under
5
+ # the Apache License, Version 2.0 (the "License"); you may
6
+ # not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ # frozen_string_literal: true
19
+
20
+ module Hoss
21
+ class Error
22
+ # @api private
23
+ class Exception
24
+ MOD_SPLIT = '::'
25
+
26
+ def initialize(attrs = nil)
27
+ return unless attrs
28
+
29
+ attrs.each do |key, val|
30
+ send(:"#{key}=", val)
31
+ end
32
+ end
33
+
34
+ def self.from_exception(exception, **attrs)
35
+ new({
36
+ message: exception.message.to_s,
37
+ type: exception.class.to_s,
38
+ module: format_module(exception),
39
+ cause: exception.cause && Exception.from_exception(exception.cause)
40
+ }.merge(attrs))
41
+ end
42
+
43
+ attr_accessor(
44
+ :attributes,
45
+ :code,
46
+ :handled,
47
+ :message,
48
+ :module,
49
+ :stacktrace,
50
+ :type,
51
+ :cause
52
+ )
53
+
54
+ def inspect
55
+ '<Hoss::Error::Exception' \
56
+ " type:#{type}" \
57
+ " message:#{message}" \
58
+ '>'
59
+ end
60
+
61
+ class << self
62
+ private
63
+
64
+ def format_module(exception)
65
+ exception.class.to_s.split(MOD_SPLIT)[0...-1].join(MOD_SPLIT)
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,41 @@
1
+ # Licensed to Elasticsearch B.V. under one or more contributor
2
+ # license agreements. See the NOTICE file distributed with
3
+ # this work for additional information regarding copyright
4
+ # ownership. Elasticsearch B.V. licenses this file to you under
5
+ # the Apache License, Version 2.0 (the "License"); you may
6
+ # not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ # frozen_string_literal: true
19
+
20
+ module Hoss
21
+ class Error
22
+ # @api private
23
+ class Log
24
+ def initialize(message, attrs = {})
25
+ @message = message
26
+
27
+ attrs.each do |key, val|
28
+ send(:"#{key}=", val)
29
+ end
30
+ end
31
+
32
+ attr_accessor(
33
+ :level,
34
+ :logger_name,
35
+ :message,
36
+ :param_message,
37
+ :stacktrace
38
+ )
39
+ end
40
+ end
41
+ end