alec-gem 2.7.2

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 (79) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +1 -0
  3. data/.rubocop.yml +74 -0
  4. data/.travis.yml +47 -0
  5. data/Gemfile +38 -0
  6. data/Gemfile.lock +215 -0
  7. data/LICENSE +201 -0
  8. data/README.md +132 -0
  9. data/Rakefile +29 -0
  10. data/alec-gem.gemspec +22 -0
  11. data/changelog.md +442 -0
  12. data/docs/Makefile +130 -0
  13. data/docs/breadcrumbs.rst +51 -0
  14. data/docs/conf.py +228 -0
  15. data/docs/config.rst +260 -0
  16. data/docs/context.rst +141 -0
  17. data/docs/index.rst +113 -0
  18. data/docs/install.rst +40 -0
  19. data/docs/integrations/heroku.rst +11 -0
  20. data/docs/integrations/index.rst +59 -0
  21. data/docs/integrations/puma.rst +30 -0
  22. data/docs/integrations/rack.rst +27 -0
  23. data/docs/integrations/rails.rst +62 -0
  24. data/docs/make.bat +155 -0
  25. data/docs/processors.rst +124 -0
  26. data/docs/sentry-doc-config.json +31 -0
  27. data/docs/usage.rst +176 -0
  28. data/exe/raven +32 -0
  29. data/lib/raven.rb +3 -0
  30. data/lib/raven/backtrace.rb +137 -0
  31. data/lib/raven/base.rb +106 -0
  32. data/lib/raven/breadcrumbs.rb +76 -0
  33. data/lib/raven/breadcrumbs/activesupport.rb +19 -0
  34. data/lib/raven/breadcrumbs/logger.rb +93 -0
  35. data/lib/raven/cli.rb +59 -0
  36. data/lib/raven/client.rb +142 -0
  37. data/lib/raven/configuration.rb +434 -0
  38. data/lib/raven/context.rb +43 -0
  39. data/lib/raven/event.rb +259 -0
  40. data/lib/raven/instance.rb +221 -0
  41. data/lib/raven/integrations/delayed_job.rb +58 -0
  42. data/lib/raven/integrations/rack-timeout.rb +19 -0
  43. data/lib/raven/integrations/rack.rb +139 -0
  44. data/lib/raven/integrations/rails.rb +79 -0
  45. data/lib/raven/integrations/rails/active_job.rb +59 -0
  46. data/lib/raven/integrations/rails/controller_methods.rb +13 -0
  47. data/lib/raven/integrations/rails/controller_transaction.rb +13 -0
  48. data/lib/raven/integrations/rails/overrides/debug_exceptions_catcher.rb +31 -0
  49. data/lib/raven/integrations/rails/overrides/streaming_reporter.rb +23 -0
  50. data/lib/raven/integrations/railties.rb +1 -0
  51. data/lib/raven/integrations/rake.rb +18 -0
  52. data/lib/raven/integrations/sidekiq.rb +87 -0
  53. data/lib/raven/integrations/tasks.rb +11 -0
  54. data/lib/raven/interface.rb +25 -0
  55. data/lib/raven/interfaces/exception.rb +15 -0
  56. data/lib/raven/interfaces/http.rb +16 -0
  57. data/lib/raven/interfaces/message.rb +20 -0
  58. data/lib/raven/interfaces/single_exception.rb +14 -0
  59. data/lib/raven/interfaces/stack_trace.rb +69 -0
  60. data/lib/raven/linecache.rb +41 -0
  61. data/lib/raven/logger.rb +19 -0
  62. data/lib/raven/processor.rb +15 -0
  63. data/lib/raven/processor/cookies.rb +26 -0
  64. data/lib/raven/processor/http_headers.rb +55 -0
  65. data/lib/raven/processor/post_data.rb +22 -0
  66. data/lib/raven/processor/removecircularreferences.rb +17 -0
  67. data/lib/raven/processor/removestacktrace.rb +24 -0
  68. data/lib/raven/processor/sanitizedata.rb +88 -0
  69. data/lib/raven/processor/utf8conversion.rb +52 -0
  70. data/lib/raven/transports.rb +15 -0
  71. data/lib/raven/transports/dummy.rb +16 -0
  72. data/lib/raven/transports/http.rb +68 -0
  73. data/lib/raven/utils/deep_merge.rb +22 -0
  74. data/lib/raven/utils/real_ip.rb +62 -0
  75. data/lib/raven/version.rb +5 -0
  76. data/lib/sentry-raven-without-integrations.rb +1 -0
  77. data/lib/sentry-raven.rb +1 -0
  78. data/pkg/sentry-raven-2.7.2.gem +0 -0
  79. metadata +143 -0
@@ -0,0 +1,18 @@
1
+ require 'rake'
2
+ require 'rake/task'
3
+ require 'raven/integrations/tasks'
4
+
5
+ module Rake
6
+ class Application
7
+ alias orig_display_error_messsage display_error_message
8
+ def display_error_message(ex)
9
+ Raven.capture_exception(
10
+ ex,
11
+ :transaction => top_level_tasks.join(' '),
12
+ :logger => 'rake',
13
+ :tags => { 'rake_task' => top_level_tasks.join(' ') }
14
+ )
15
+ orig_display_error_messsage(ex)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,87 @@
1
+ require 'time'
2
+ require 'sidekiq'
3
+
4
+ module Raven
5
+ class SidekiqCleanupMiddleware
6
+ def call(_worker, job, queue)
7
+ Raven.context.transaction.push "Sidekiq/#{job['class']}"
8
+ Raven.extra_context(:sidekiq => job.merge("queue" => queue))
9
+ yield
10
+ Context.clear!
11
+ BreadcrumbBuffer.clear!
12
+ end
13
+ end
14
+
15
+ class SidekiqErrorHandler
16
+ ACTIVEJOB_RESERVED_PREFIX = "_aj_".freeze
17
+ HAS_GLOBALID = const_defined?('GlobalID')
18
+
19
+ def call(ex, context)
20
+ context = filter_context(context)
21
+ Raven.context.transaction.push transaction_from_context(context)
22
+ Raven.capture_exception(
23
+ ex,
24
+ :message => ex.message,
25
+ :extra => { :sidekiq => context }
26
+ )
27
+ Context.clear!
28
+ BreadcrumbBuffer.clear!
29
+ end
30
+
31
+ private
32
+
33
+ # Once an ActiveJob is queued, ActiveRecord references get serialized into
34
+ # some internal reserved keys, such as _aj_globalid.
35
+ #
36
+ # The problem is, if this job in turn gets queued back into ActiveJob with
37
+ # these magic reserved keys, ActiveJob will throw up and error. We want to
38
+ # capture these and mutate the keys so we can sanely report it.
39
+ def filter_context(context)
40
+ case context
41
+ when Array
42
+ context.map { |arg| filter_context(arg) }
43
+ when Hash
44
+ Hash[context.map { |key, value| filter_context_hash(key, value) }]
45
+ else
46
+ format_globalid(context)
47
+ end
48
+ end
49
+
50
+ def filter_context_hash(key, value)
51
+ (key = key[3..-1]) if key [0..3] == ACTIVEJOB_RESERVED_PREFIX
52
+ [key, filter_context(value)]
53
+ end
54
+
55
+ # this will change in the future:
56
+ # https://github.com/mperham/sidekiq/pull/3161
57
+ def transaction_from_context(context)
58
+ classname = (context["wrapped"] || context["class"] ||
59
+ (context[:job] && (context[:job]["wrapped"] || context[:job]["class"]))
60
+ )
61
+ if classname
62
+ "Sidekiq/#{classname}"
63
+ elsif context[:event]
64
+ "Sidekiq/#{context[:event]}"
65
+ else
66
+ "Sidekiq"
67
+ end
68
+ end
69
+
70
+ def format_globalid(context)
71
+ if HAS_GLOBALID && context.is_a?(GlobalID)
72
+ context.to_s
73
+ else
74
+ context
75
+ end
76
+ end
77
+ end
78
+ end
79
+
80
+ if Sidekiq::VERSION > '3'
81
+ Sidekiq.configure_server do |config|
82
+ config.error_handlers << Raven::SidekiqErrorHandler.new
83
+ config.server_middleware do |chain|
84
+ chain.add Raven::SidekiqCleanupMiddleware
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,11 @@
1
+ require 'rake'
2
+ require 'raven/cli'
3
+
4
+ namespace :raven do
5
+ desc "Send a test event to the remote Sentry server"
6
+ task :test, [:dsn] do |_t, args|
7
+ Rake::Task["environment"].invoke if Rake::Task.tasks.map(&:to_s).include?("environment")
8
+
9
+ Raven::CLI.test(args.dsn)
10
+ end
11
+ end
@@ -0,0 +1,25 @@
1
+ module Raven
2
+ class Interface
3
+ def initialize(attributes = nil)
4
+ attributes.each do |attr, value|
5
+ public_send "#{attr}=", value
6
+ end if attributes
7
+
8
+ yield self if block_given?
9
+ end
10
+
11
+ def self.inherited(klass)
12
+ name = klass.name.split("::").last.downcase.gsub("interface", "")
13
+ registered[name.to_sym] = klass
14
+ super
15
+ end
16
+
17
+ def self.registered
18
+ @@registered ||= {} # rubocop:disable Style/ClassVars
19
+ end
20
+
21
+ def to_hash
22
+ Hash[instance_variables.map { |name| [name[1..-1].to_sym, instance_variable_get(name)] }]
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,15 @@
1
+ module Raven
2
+ class ExceptionInterface < Interface
3
+ attr_accessor :values
4
+
5
+ def self.sentry_alias
6
+ :exception
7
+ end
8
+
9
+ def to_hash(*args)
10
+ data = super(*args)
11
+ data[:values] = data[:values].map(&:to_hash) if data[:values]
12
+ data
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,16 @@
1
+ module Raven
2
+ class HttpInterface < Interface
3
+ attr_accessor :url, :method, :data, :query_string, :cookies, :headers, :env
4
+
5
+ def initialize(*arguments)
6
+ self.headers = {}
7
+ self.env = {}
8
+ self.cookies = nil
9
+ super(*arguments)
10
+ end
11
+
12
+ def self.sentry_alias
13
+ :request
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,20 @@
1
+ require 'raven/interface'
2
+
3
+ module Raven
4
+ class MessageInterface < Interface
5
+ attr_accessor :message, :params
6
+
7
+ def initialize(*arguments)
8
+ self.params = []
9
+ super(*arguments)
10
+ end
11
+
12
+ def unformatted_message
13
+ Array(params).empty? ? message : message % params
14
+ end
15
+
16
+ def self.sentry_alias
17
+ :logentry
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,14 @@
1
+ module Raven
2
+ class SingleExceptionInterface < Interface
3
+ attr_accessor :type
4
+ attr_accessor :value
5
+ attr_accessor :module
6
+ attr_accessor :stacktrace
7
+
8
+ def to_hash(*args)
9
+ data = super(*args)
10
+ data[:stacktrace] = data[:stacktrace].to_hash if data[:stacktrace]
11
+ data
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,69 @@
1
+ module Raven
2
+ class StacktraceInterface < Interface
3
+ attr_accessor :frames
4
+
5
+ def initialize(*arguments)
6
+ super(*arguments)
7
+ end
8
+
9
+ def self.sentry_alias
10
+ :stacktrace
11
+ end
12
+
13
+ def to_hash(*args)
14
+ data = super(*args)
15
+ data[:frames] = data[:frames].map(&:to_hash)
16
+ data
17
+ end
18
+
19
+ # Not actually an interface, but I want to use the same style
20
+ class Frame < Interface
21
+ attr_accessor :abs_path, :context_line, :function, :in_app,
22
+ :lineno, :module, :pre_context, :post_context, :vars
23
+
24
+ def initialize(*arguments)
25
+ super(*arguments)
26
+ end
27
+
28
+ def filename
29
+ return if abs_path.nil?
30
+ return @filename if instance_variable_defined?(:@filename)
31
+
32
+ prefix =
33
+ if under_project_root? && in_app
34
+ project_root
35
+ elsif under_project_root?
36
+ longest_load_path || project_root
37
+ else
38
+ longest_load_path
39
+ end
40
+
41
+ @filename = prefix ? abs_path[prefix.to_s.chomp(File::SEPARATOR).length + 1..-1] : abs_path
42
+ end
43
+
44
+ def to_hash(*args)
45
+ data = super(*args)
46
+ data[:filename] = filename
47
+ data.delete(:vars) unless vars && !vars.empty?
48
+ data.delete(:pre_context) unless pre_context && !pre_context.empty?
49
+ data.delete(:post_context) unless post_context && !post_context.empty?
50
+ data.delete(:context_line) unless context_line && !context_line.empty?
51
+ data
52
+ end
53
+
54
+ private
55
+
56
+ def under_project_root?
57
+ project_root && abs_path.start_with?(project_root)
58
+ end
59
+
60
+ def project_root
61
+ @project_root ||= Raven.configuration.project_root && Raven.configuration.project_root.to_s
62
+ end
63
+
64
+ def longest_load_path
65
+ $LOAD_PATH.select { |path| abs_path.start_with?(path.to_s) }.max_by(&:size)
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,41 @@
1
+ module Raven
2
+ class LineCache
3
+ def initialize
4
+ @cache = {}
5
+ end
6
+
7
+ # Any linecache you provide to Raven must implement this method.
8
+ # Returns an Array of Strings representing the lines in the source
9
+ # file. The number of lines retrieved is (2 * context) + 1, the middle
10
+ # line should be the line requested by lineno. See specs for more information.
11
+ def get_file_context(filename, lineno, context)
12
+ return nil, nil, nil unless valid_path?(filename)
13
+ lines = Array.new(2 * context + 1) do |i|
14
+ getline(filename, lineno - context + i)
15
+ end
16
+ [lines[0..(context - 1)], lines[context], lines[(context + 1)..-1]]
17
+ end
18
+
19
+ private
20
+
21
+ def valid_path?(path)
22
+ lines = getlines(path)
23
+ !lines.nil?
24
+ end
25
+
26
+ def getlines(path)
27
+ @cache[path] ||= begin
28
+ IO.readlines(path)
29
+ rescue
30
+ nil
31
+ end
32
+ end
33
+
34
+ def getline(path, n)
35
+ return nil if n < 1
36
+ lines = getlines(path)
37
+ return nil if lines.nil?
38
+ lines[n - 1]
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+ require 'logger'
3
+
4
+ module Raven
5
+ class Logger < ::Logger
6
+ LOG_PREFIX = "** [Raven] ".freeze
7
+ PROGNAME = "sentry".freeze
8
+
9
+ def initialize(*)
10
+ super
11
+ @level = ::Logger::INFO
12
+ original_formatter = ::Logger::Formatter.new
13
+ @default_formatter = proc do |severity, datetime, _progname, msg|
14
+ msg = "#{LOG_PREFIX}#{msg}"
15
+ original_formatter.call(severity, datetime, PROGNAME, msg)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,15 @@
1
+ module Raven
2
+ class Processor
3
+ STRING_MASK = '********'.freeze
4
+ INT_MASK = 0
5
+ REGEX_SPECIAL_CHARACTERS = %w(. $ ^ { [ ( | ) * + ?).freeze
6
+
7
+ def initialize(client = nil)
8
+ @client = client
9
+ end
10
+
11
+ def process(_data)
12
+ raise NotImplementedError
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,26 @@
1
+ module Raven
2
+ class Processor::Cookies < Processor
3
+ def process(data)
4
+ process_if_symbol_keys(data) if data[:request]
5
+ process_if_string_keys(data) if data["request"]
6
+
7
+ data
8
+ end
9
+
10
+ private
11
+
12
+ def process_if_symbol_keys(data)
13
+ data[:request][:cookies] = STRING_MASK if data[:request][:cookies]
14
+
15
+ return unless data[:request][:headers] && data[:request][:headers]["Cookie"]
16
+ data[:request][:headers]["Cookie"] = STRING_MASK
17
+ end
18
+
19
+ def process_if_string_keys(data)
20
+ data["request"]["cookies"] = STRING_MASK if data["request"]["cookies"]
21
+
22
+ return unless data["request"]["headers"] && data["request"]["headers"]["Cookie"]
23
+ data["request"]["headers"]["Cookie"] = STRING_MASK
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,55 @@
1
+ module Raven
2
+ class Processor::HTTPHeaders < Processor
3
+ DEFAULT_FIELDS = ["Authorization"].freeze
4
+
5
+ attr_accessor :sanitize_http_headers
6
+
7
+ def initialize(client)
8
+ super
9
+ self.sanitize_http_headers = client.configuration.sanitize_http_headers
10
+ end
11
+
12
+ def process(data)
13
+ process_if_symbol_keys(data) if data[:request]
14
+ process_if_string_keys(data) if data["request"]
15
+
16
+ data
17
+ end
18
+
19
+ private
20
+
21
+ def process_if_symbol_keys(data)
22
+ return unless data[:request][:headers]
23
+
24
+ data[:request][:headers].keys.select { |k| fields_re.match(k.to_s) }.each do |k|
25
+ data[:request][:headers][k] = STRING_MASK
26
+ end
27
+ end
28
+
29
+ def process_if_string_keys(data)
30
+ return unless data["request"]["headers"]
31
+
32
+ data["request"]["headers"].keys.select { |k| fields_re.match(k) }.each do |k|
33
+ data["request"]["headers"][k] = STRING_MASK
34
+ end
35
+ end
36
+
37
+ def matches_regexes?(k)
38
+ fields_re.match(k.to_s)
39
+ end
40
+
41
+ def fields_re
42
+ @fields_re ||= /#{(DEFAULT_FIELDS | sanitize_http_headers).map do |f|
43
+ use_boundary?(f) ? "\\b#{f}\\b" : f
44
+ end.join("|")}/i
45
+ end
46
+
47
+ def use_boundary?(string)
48
+ !DEFAULT_FIELDS.include?(string) && !special_characters?(string)
49
+ end
50
+
51
+ def special_characters?(string)
52
+ REGEX_SPECIAL_CHARACTERS.select { |r| string.include?(r) }.any?
53
+ end
54
+ end
55
+ end