alec-gem 2.7.2

Sign up to get free protection for your applications and to get access to all the features.
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