validation_tracker_client 2.4.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.
- data/.gitignore +41 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +29 -0
- data/Rakefile +2 -0
- data/lib/validation_tracker_client.rb +136 -0
- data/lib/validation_tracker_client/configuration.rb +175 -0
- data/lib/validation_tracker_client/notice.rb +329 -0
- data/lib/validation_tracker_client/rails.rb +34 -0
- data/lib/validation_tracker_client/rails/controller_methods.rb +62 -0
- data/lib/validation_tracker_client/railtie.rb +22 -0
- data/lib/validation_tracker_client/sender.rb +76 -0
- data/lib/validation_tracker_client/version.rb +3 -0
- data/rails/init.rb +1 -0
- data/test.rb +7 -0
- data/validation_tracker_client.gemspec +17 -0
- metadata +61 -0
data/.gitignore
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
/.idea/*
|
2
|
+
.rvmrc
|
3
|
+
app/views/**/.tmp_*
|
4
|
+
public/images/Thumbs.db
|
5
|
+
public/system
|
6
|
+
tmp
|
7
|
+
public/blank.html
|
8
|
+
/.project
|
9
|
+
/.loadpath
|
10
|
+
/db/sphinx/test
|
11
|
+
/db/sphinx/test2
|
12
|
+
/db/sphinx/test3
|
13
|
+
/db/sphinx/test4
|
14
|
+
/db/sphinx/cucumber
|
15
|
+
/db/sphinx/development
|
16
|
+
/tmp
|
17
|
+
/log
|
18
|
+
/config/development.sphinx.conf
|
19
|
+
/config/test.sphinx.conf
|
20
|
+
/config/test2.sphinx.conf
|
21
|
+
/config/test3.sphinx.conf
|
22
|
+
/config/test4.sphinx.conf
|
23
|
+
/config/cucumber.sphinx.conf
|
24
|
+
nbproject
|
25
|
+
db/development_structure.sql
|
26
|
+
db/test_structure.sql
|
27
|
+
/results
|
28
|
+
cities.txt
|
29
|
+
states.txt
|
30
|
+
countries.txt
|
31
|
+
GPATH
|
32
|
+
GRTAGS
|
33
|
+
GSYMS
|
34
|
+
GTAGS
|
35
|
+
webrat.log
|
36
|
+
test/fixtures
|
37
|
+
.rvmrc
|
38
|
+
.gemtags
|
39
|
+
.tags
|
40
|
+
.tags_sorted_by_file
|
41
|
+
pkg
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 arun.kumar.arjunan
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# ValidationTrackerClient
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'validation_tracker_client'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install validation_tracker_client
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,136 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'net/https'
|
3
|
+
require 'rubygems'
|
4
|
+
begin
|
5
|
+
require 'active_support'
|
6
|
+
rescue LoadError
|
7
|
+
require 'activesupport'
|
8
|
+
end
|
9
|
+
require 'validation_tracker_client/version'
|
10
|
+
require 'validation_tracker_client/configuration'
|
11
|
+
require 'validation_tracker_client/notice'
|
12
|
+
require 'validation_tracker_client/sender'
|
13
|
+
|
14
|
+
require 'validation_tracker_client/railtie' if defined?(Rails::Railtie)
|
15
|
+
|
16
|
+
# Gem for applications to automatically post errors to the Validation Tracker of their choice.
|
17
|
+
module ValidationTrackerClient
|
18
|
+
|
19
|
+
API_VERSION = "2.0"
|
20
|
+
LOG_PREFIX = "** [Validation Tracker] "
|
21
|
+
|
22
|
+
HEADERS = {
|
23
|
+
'Content-type' => 'text/xml',
|
24
|
+
'Accept' => 'text/xml, application/xml'
|
25
|
+
}
|
26
|
+
|
27
|
+
class << self
|
28
|
+
# The sender object is responsible for delivering formatted data to the Validation Tracker server.
|
29
|
+
# Must respond to #send_to_validation_tracker. See ValidationTrackerClient::Sender.
|
30
|
+
attr_accessor :sender
|
31
|
+
|
32
|
+
# A Validation Tracker configuration object. Must act like a hash and return sensible
|
33
|
+
# values for all Validation Tracker configuration options. See ValidationTrackerClient::Configuration.
|
34
|
+
attr_accessor :configuration
|
35
|
+
|
36
|
+
# Tell the log that the Notifier is good to go
|
37
|
+
def report_ready
|
38
|
+
write_verbose_log("Notifier #{VERSION} ready to catch errors")
|
39
|
+
end
|
40
|
+
|
41
|
+
# Prints out the environment info to the log for debugging help
|
42
|
+
def report_environment_info
|
43
|
+
write_verbose_log("Environment Info: #{environment_info}")
|
44
|
+
end
|
45
|
+
|
46
|
+
# Prints out the response body from Validation Tracker for debugging help
|
47
|
+
def report_response_body(response)
|
48
|
+
write_verbose_log("Response from Validation Tracker: \n#{response}")
|
49
|
+
end
|
50
|
+
|
51
|
+
# Returns the Ruby version, Rails version, and current Rails environment
|
52
|
+
def environment_info
|
53
|
+
info = "[Ruby: #{RUBY_VERSION}]"
|
54
|
+
info << " [#{configuration.framework}]"
|
55
|
+
info << " [Env: #{configuration.environment_name}]"
|
56
|
+
end
|
57
|
+
|
58
|
+
# Writes out the given message to the #logger
|
59
|
+
def write_verbose_log(message)
|
60
|
+
logger.info LOG_PREFIX + message if logger
|
61
|
+
end
|
62
|
+
|
63
|
+
# Look for the Rails logger currently defined
|
64
|
+
def logger
|
65
|
+
self.configuration.logger
|
66
|
+
end
|
67
|
+
|
68
|
+
# Call this method to modify defaults in your initializers.
|
69
|
+
#
|
70
|
+
# @example
|
71
|
+
# ValidationTrackerClient.configure do |config|
|
72
|
+
# config.api_key = '1234567890abcdef'
|
73
|
+
# config.secure = false
|
74
|
+
# end
|
75
|
+
def configure(silent = false)
|
76
|
+
self.configuration ||= Configuration.new
|
77
|
+
yield(configuration)
|
78
|
+
self.sender = Sender.new(configuration)
|
79
|
+
report_ready unless silent
|
80
|
+
end
|
81
|
+
|
82
|
+
# Sends an exception manually using this method, even when you are not in a controller.
|
83
|
+
#
|
84
|
+
# @param [Exception] exception The exception you want to notify Validation Tracker about.
|
85
|
+
# @param [Hash] opts Data that will be sent to Validation Tracker.
|
86
|
+
#
|
87
|
+
# @option opts [String] :api_key The API key for this project. The API key is a unique identifier that Validation Tracker uses for identification.
|
88
|
+
# @option opts [String] :error_message The error returned by the exception (or the message you want to log).
|
89
|
+
# @option opts [String] :backtrace A backtrace, usually obtained with +caller+.
|
90
|
+
# @option opts [String] :request The controller's request object.
|
91
|
+
# @option opts [String] :session The contents of the user's session.
|
92
|
+
# @option opts [String] :environment ENV merged with the contents of the request's environment.
|
93
|
+
def notify(error_message, opts = {})
|
94
|
+
send_notice(build_notice_for(error_message, opts))
|
95
|
+
end
|
96
|
+
|
97
|
+
# Sends the notice unless it is one of the default ignored exceptions
|
98
|
+
# @see ValidationTrackerClient.notify
|
99
|
+
def notify_or_ignore(exception, opts = {})
|
100
|
+
notice = build_notice_for(exception, opts)
|
101
|
+
send_notice(notice) unless notice.ignore?
|
102
|
+
end
|
103
|
+
|
104
|
+
def build_lookup_hash_for(exception, options = {})
|
105
|
+
notice = build_notice_for(exception, options)
|
106
|
+
|
107
|
+
result = {}
|
108
|
+
result[:action] = notice.action rescue nil
|
109
|
+
result[:component] = notice.component rescue nil
|
110
|
+
result[:error_class] = notice.error_class if notice.error_class
|
111
|
+
result[:environment_name] = 'production'
|
112
|
+
|
113
|
+
unless notice.backtrace.lines.empty?
|
114
|
+
result[:file] = notice.backtrace.lines.first.file
|
115
|
+
result[:line_number] = notice.backtrace.lines.first.number
|
116
|
+
end
|
117
|
+
|
118
|
+
result
|
119
|
+
end
|
120
|
+
|
121
|
+
private
|
122
|
+
|
123
|
+
def send_notice(notice)
|
124
|
+
if configuration.public?
|
125
|
+
sender.send_to_validation_tracker(notice.to_xml)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def build_notice_for(error_message, opts = {})
|
130
|
+
opts = opts.merge(:error_message => error_message)
|
131
|
+
Notice.new(configuration.merge(opts))
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
@@ -0,0 +1,175 @@
|
|
1
|
+
module ValidationTrackerClient
|
2
|
+
# Used to set up and modify settings for the notifier.
|
3
|
+
class Configuration
|
4
|
+
|
5
|
+
OPTIONS = [:api_key, :development_environments,
|
6
|
+
:development_lookup, :environment_name, :host,
|
7
|
+
:http_open_timeout, :http_read_timeout,
|
8
|
+
:notifier_name, :notifier_url, :notifier_version,
|
9
|
+
:params_filters, :project_root, :port, :protocol, :proxy_host,
|
10
|
+
:proxy_pass, :proxy_port, :proxy_user, :secure, :framework,
|
11
|
+
:user_information].freeze
|
12
|
+
|
13
|
+
# The API key for your project, found on the project edit form.
|
14
|
+
attr_accessor :api_key
|
15
|
+
|
16
|
+
# The host to connect to (defaults to validation-tracker.heroku.com).
|
17
|
+
attr_accessor :host
|
18
|
+
|
19
|
+
# The port on which your Validation Tracker server runs (defaults to 443 for secure
|
20
|
+
# connections, 80 for insecure connections).
|
21
|
+
attr_accessor :port
|
22
|
+
|
23
|
+
# +true+ for https connections, +false+ for http connections.
|
24
|
+
attr_accessor :secure
|
25
|
+
|
26
|
+
# The HTTP open timeout in seconds (defaults to 2).
|
27
|
+
attr_accessor :http_open_timeout
|
28
|
+
|
29
|
+
# The HTTP read timeout in seconds (defaults to 5).
|
30
|
+
attr_accessor :http_read_timeout
|
31
|
+
|
32
|
+
# The hostname of your proxy server (if using a proxy)
|
33
|
+
attr_accessor :proxy_host
|
34
|
+
|
35
|
+
# The port of your proxy server (if using a proxy)
|
36
|
+
attr_accessor :proxy_port
|
37
|
+
|
38
|
+
# The username to use when logging into your proxy server (if using a proxy)
|
39
|
+
attr_accessor :proxy_user
|
40
|
+
|
41
|
+
# The password to use when logging into your proxy server (if using a proxy)
|
42
|
+
attr_accessor :proxy_pass
|
43
|
+
|
44
|
+
# A list of parameters that should be filtered out of what is sent to Validation Tracker.
|
45
|
+
# By default, all "password" attributes will have their contents replaced.
|
46
|
+
attr_reader :params_filters
|
47
|
+
|
48
|
+
# A list of environments in which notifications should not be sent.
|
49
|
+
attr_accessor :development_environments
|
50
|
+
|
51
|
+
# +true+ if you want to check for production errors matching development errors, +false+ otherwise.
|
52
|
+
attr_accessor :development_lookup
|
53
|
+
|
54
|
+
# The name of the environment the application is running in
|
55
|
+
attr_accessor :environment_name
|
56
|
+
|
57
|
+
# The path to the project in which the error occurred, such as the RAILS_ROOT
|
58
|
+
attr_accessor :project_root
|
59
|
+
|
60
|
+
# The name of the notifier library being used to send notifications (such as "Validation Tracker Notifier")
|
61
|
+
attr_accessor :notifier_name
|
62
|
+
|
63
|
+
# The version of the notifier library being used to send notifications (such as "1.0.2")
|
64
|
+
attr_accessor :notifier_version
|
65
|
+
|
66
|
+
# The url of the notifier library being used to send notifications
|
67
|
+
attr_accessor :notifier_url
|
68
|
+
|
69
|
+
# The logger used by ValidationTrackerClient
|
70
|
+
attr_accessor :logger
|
71
|
+
|
72
|
+
# The text that the placeholder is replaced with. {{error_id}} is the actual error number.
|
73
|
+
attr_accessor :user_information
|
74
|
+
|
75
|
+
# The framework ValidationTrackerClient is configured to use
|
76
|
+
attr_accessor :framework
|
77
|
+
|
78
|
+
DEFAULT_PARAMS_FILTERS = %w(password password_confirmation).freeze
|
79
|
+
|
80
|
+
DEFAULT_BACKTRACE_FILTERS = [
|
81
|
+
lambda { |line|
|
82
|
+
if defined?(ValidationTrackerClient.configuration.project_root) && ValidationTrackerClient.configuration.project_root.to_s != ''
|
83
|
+
line.gsub(/#{ValidationTrackerClient.configuration.project_root}/, "[PROJECT_ROOT]")
|
84
|
+
else
|
85
|
+
line
|
86
|
+
end
|
87
|
+
},
|
88
|
+
lambda { |line| line.gsub(/^\.\//, "") },
|
89
|
+
lambda { |line|
|
90
|
+
if defined?(Gem)
|
91
|
+
Gem.path.inject(line) do |line, path|
|
92
|
+
line.gsub(/#{path}/, "[GEM_ROOT]")
|
93
|
+
end
|
94
|
+
end
|
95
|
+
},
|
96
|
+
lambda { |line| line if line !~ %r{lib/validation_tracker_client} }
|
97
|
+
].freeze
|
98
|
+
|
99
|
+
|
100
|
+
alias_method :secure?, :secure
|
101
|
+
|
102
|
+
def initialize
|
103
|
+
@secure = false
|
104
|
+
@host = 'validation-tracker.heroku.com'
|
105
|
+
@http_open_timeout = 2
|
106
|
+
@http_read_timeout = 5
|
107
|
+
@params_filters = DEFAULT_PARAMS_FILTERS.dup
|
108
|
+
@ignore_user_agent = []
|
109
|
+
@development_environments = %w(development test cucumber)
|
110
|
+
@development_lookup = true
|
111
|
+
@notifier_name = 'Validation Tracker Notifier'
|
112
|
+
@notifier_version = VERSION
|
113
|
+
@notifier_url = 'http://validation-tracker.heroku.com'
|
114
|
+
@framework = 'Standalone'
|
115
|
+
@user_information = 'Validation Tracker Error {{error_id}}'
|
116
|
+
end
|
117
|
+
|
118
|
+
|
119
|
+
# Allows config options to be read like a hash
|
120
|
+
#
|
121
|
+
# @param [Symbol] option Key for a given attribute
|
122
|
+
def [](option)
|
123
|
+
send(option)
|
124
|
+
end
|
125
|
+
|
126
|
+
# Returns a hash of all configurable options
|
127
|
+
def to_hash
|
128
|
+
OPTIONS.inject({}) do |hash, option|
|
129
|
+
hash.merge(option.to_sym => send(option))
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
# Returns a hash of all configurable options merged with +hash+
|
134
|
+
#
|
135
|
+
# @param [Hash] hash A set of configuration options that will take precedence over the defaults
|
136
|
+
def merge(hash)
|
137
|
+
to_hash.merge(hash)
|
138
|
+
end
|
139
|
+
|
140
|
+
# Determines if the notifier will send notices.
|
141
|
+
# @return [Boolean] Returns +false+ if in a development environment, +true+ otherwise.
|
142
|
+
def public?
|
143
|
+
!development_environments.include?(environment_name)
|
144
|
+
end
|
145
|
+
|
146
|
+
def port
|
147
|
+
@port || default_port
|
148
|
+
end
|
149
|
+
|
150
|
+
def protocol
|
151
|
+
if secure?
|
152
|
+
'https'
|
153
|
+
else
|
154
|
+
'http'
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def environment_filters
|
159
|
+
warn 'config.environment_filters has been deprecated and has no effect.'
|
160
|
+
[]
|
161
|
+
end
|
162
|
+
|
163
|
+
private
|
164
|
+
|
165
|
+
def default_port
|
166
|
+
if secure?
|
167
|
+
443
|
168
|
+
else
|
169
|
+
80
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
end
|
174
|
+
|
175
|
+
end
|
@@ -0,0 +1,329 @@
|
|
1
|
+
require 'builder'
|
2
|
+
require 'socket'
|
3
|
+
|
4
|
+
module ValidationTrackerClient
|
5
|
+
class Notice
|
6
|
+
|
7
|
+
# The API key for the project to which this notice should be sent
|
8
|
+
attr_reader :api_key
|
9
|
+
|
10
|
+
|
11
|
+
# The name of the server environment (such as "production")
|
12
|
+
attr_reader :environment_name
|
13
|
+
|
14
|
+
# CGI variables such as HTTP_METHOD
|
15
|
+
attr_reader :cgi_data
|
16
|
+
|
17
|
+
# The message from the exception, or a general description of the error
|
18
|
+
attr_reader :error_message
|
19
|
+
|
20
|
+
# See Configuration#backtrace_filters
|
21
|
+
attr_reader :backtrace_filters
|
22
|
+
|
23
|
+
# See Configuration#params_filters
|
24
|
+
attr_reader :params_filters
|
25
|
+
|
26
|
+
# A hash of parameters from the query string or post body.
|
27
|
+
attr_reader :parameters
|
28
|
+
alias_method :params, :parameters
|
29
|
+
|
30
|
+
# The component (if any) which was used in this request (usually the controller)
|
31
|
+
attr_reader :component
|
32
|
+
alias_method :controller, :component
|
33
|
+
|
34
|
+
# The action (if any) that was called in this request
|
35
|
+
attr_reader :action
|
36
|
+
|
37
|
+
# A hash of session data from the request
|
38
|
+
attr_reader :session_data
|
39
|
+
|
40
|
+
# The path to the project that caused the error (usually RAILS_ROOT)
|
41
|
+
attr_reader :project_root
|
42
|
+
|
43
|
+
# The URL at which the error occurred (if any)
|
44
|
+
attr_reader :url
|
45
|
+
|
46
|
+
# The name of the notifier library sending this notice, such as "Validation Tracker Notifier"
|
47
|
+
attr_reader :notifier_name
|
48
|
+
|
49
|
+
# The version number of the notifier library sending this notice, such as "2.1.3"
|
50
|
+
attr_reader :notifier_version
|
51
|
+
|
52
|
+
# A URL for more information about the notifier library sending this notice
|
53
|
+
attr_reader :notifier_url
|
54
|
+
|
55
|
+
# The host name where this error occurred (if any)
|
56
|
+
attr_reader :hostname
|
57
|
+
|
58
|
+
def initialize(args)
|
59
|
+
self.args = args
|
60
|
+
self.exception = args[:exception]
|
61
|
+
self.api_key = args[:api_key]
|
62
|
+
self.project_root = args[:project_root]
|
63
|
+
self.url = args[:url] || rack_env(:url)
|
64
|
+
|
65
|
+
self.notifier_name = args[:notifier_name]
|
66
|
+
self.notifier_version = args[:notifier_version]
|
67
|
+
self.notifier_url = args[:notifier_url]
|
68
|
+
|
69
|
+
self.params_filters = args[:params_filters] || []
|
70
|
+
self.parameters = args[:parameters] ||
|
71
|
+
action_dispatch_params ||
|
72
|
+
rack_env(:params) ||
|
73
|
+
{}
|
74
|
+
self.component = args[:component] || args[:controller] || parameters['controller']
|
75
|
+
self.action = args[:action] || parameters['action']
|
76
|
+
|
77
|
+
self.environment_name = args[:environment_name]
|
78
|
+
self.cgi_data = args[:cgi_data] || args[:rack_env]
|
79
|
+
self.error_message = exception_attribute(:error_message, 'Notification') do |exception|
|
80
|
+
"#{exception.class.name}: #{exception.message}"
|
81
|
+
end
|
82
|
+
|
83
|
+
self.hostname = local_hostname
|
84
|
+
|
85
|
+
also_use_rack_params_filters
|
86
|
+
find_session_data
|
87
|
+
clean_params
|
88
|
+
clean_rack_request_data
|
89
|
+
end
|
90
|
+
|
91
|
+
# Converts the given notice to XML
|
92
|
+
def to_xml
|
93
|
+
builder = Builder::XmlMarkup.new
|
94
|
+
builder.instruct!
|
95
|
+
xml = builder.notice(:version => ValidationTrackerClient::API_VERSION) do |notice|
|
96
|
+
notice.tag!("api-key", api_key)
|
97
|
+
notice.notifier do |notifier|
|
98
|
+
notifier.name(notifier_name)
|
99
|
+
notifier.version(notifier_version)
|
100
|
+
notifier.url(notifier_url)
|
101
|
+
end
|
102
|
+
notice.error do |error|
|
103
|
+
error.tag!('class', error_class)
|
104
|
+
error.message(error_message)
|
105
|
+
error.backtrace do |backtrace|
|
106
|
+
self.backtrace.lines.each do |line|
|
107
|
+
backtrace.line(:number => line.number,
|
108
|
+
:file => line.file,
|
109
|
+
:method => line.method)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
if url ||
|
114
|
+
controller ||
|
115
|
+
action ||
|
116
|
+
!parameters.blank? ||
|
117
|
+
!cgi_data.blank? ||
|
118
|
+
!session_data.blank?
|
119
|
+
notice.request do |request|
|
120
|
+
request.url(url)
|
121
|
+
request.component(controller)
|
122
|
+
request.action(action)
|
123
|
+
unless parameters.nil? || parameters.empty?
|
124
|
+
request.params do |params|
|
125
|
+
xml_vars_for(params, parameters)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
unless session_data.nil? || session_data.empty?
|
129
|
+
request.session do |session|
|
130
|
+
xml_vars_for(session, session_data)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
unless cgi_data.nil? || cgi_data.empty?
|
134
|
+
request.tag!("cgi-data") do |cgi_datum|
|
135
|
+
xml_vars_for(cgi_datum, cgi_data)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
notice.tag!("server-environment") do |env|
|
141
|
+
env.tag!("project-root", project_root)
|
142
|
+
env.tag!("environment-name", environment_name)
|
143
|
+
env.tag!("hostname", hostname)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
xml.to_s
|
147
|
+
end
|
148
|
+
|
149
|
+
# Determines if this notice should be ignored
|
150
|
+
def ignore?
|
151
|
+
ignored_class_names.include?(error_class) ||
|
152
|
+
ignore_by_filters.any? {|filter| filter.call(self) }
|
153
|
+
end
|
154
|
+
|
155
|
+
# Allows properties to be accessed using a hash-like syntax
|
156
|
+
#
|
157
|
+
# @example
|
158
|
+
# notice[:error_message]
|
159
|
+
# @param [String] method The given key for an attribute
|
160
|
+
# @return The attribute value, or self if given +:request+
|
161
|
+
def [](method)
|
162
|
+
case method
|
163
|
+
when :request
|
164
|
+
self
|
165
|
+
else
|
166
|
+
send(method)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
private
|
171
|
+
|
172
|
+
attr_writer :exception, :api_key, :backtrace, :error_class, :error_message,
|
173
|
+
:backtrace_filters, :parameters, :params_filters,
|
174
|
+
:environment_filters, :session_data, :project_root, :url, :ignore,
|
175
|
+
:ignore_by_filters, :notifier_name, :notifier_url, :notifier_version,
|
176
|
+
:component, :action, :cgi_data, :environment_name, :hostname
|
177
|
+
|
178
|
+
# Arguments given in the initializer
|
179
|
+
attr_accessor :args
|
180
|
+
|
181
|
+
# Gets a property named +attribute+ of an exception, either from an actual
|
182
|
+
# exception or a hash.
|
183
|
+
#
|
184
|
+
# If an exception is available, #from_exception will be used. Otherwise,
|
185
|
+
# a key named +attribute+ will be used from the #args.
|
186
|
+
#
|
187
|
+
# If no exception or hash key is available, +default+ will be used.
|
188
|
+
def exception_attribute(attribute, default = nil, &block)
|
189
|
+
(exception && from_exception(attribute, &block)) || args[attribute] || default
|
190
|
+
end
|
191
|
+
|
192
|
+
# Gets a property named +attribute+ from an exception.
|
193
|
+
#
|
194
|
+
# If a block is given, it will be used when getting the property from an
|
195
|
+
# exception. The block should accept and exception and return the value for
|
196
|
+
# the property.
|
197
|
+
#
|
198
|
+
# If no block is given, a method with the same name as +attribute+ will be
|
199
|
+
# invoked for the value.
|
200
|
+
def from_exception(attribute)
|
201
|
+
if block_given?
|
202
|
+
yield(exception)
|
203
|
+
else
|
204
|
+
exception.send(attribute)
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
# Removes non-serializable data from the given attribute.
|
209
|
+
# See #clean_unserializable_data
|
210
|
+
def clean_unserializable_data_from(attribute)
|
211
|
+
self.send(:"#{attribute}=", clean_unserializable_data(send(attribute)))
|
212
|
+
end
|
213
|
+
|
214
|
+
# Removes non-serializable data. Allowed data types are strings, arrays,
|
215
|
+
# and hashes. All other types are converted to strings.
|
216
|
+
# TODO: move this onto Hash
|
217
|
+
def clean_unserializable_data(data, stack = [])
|
218
|
+
return "[possible infinite recursion halted]" if stack.any?{|item| item == data.object_id }
|
219
|
+
|
220
|
+
if data.respond_to?(:to_hash)
|
221
|
+
data.to_hash.inject({}) do |result, (key, value)|
|
222
|
+
result.merge(key => clean_unserializable_data(value, stack + [data.object_id]))
|
223
|
+
end
|
224
|
+
elsif data.respond_to?(:to_ary)
|
225
|
+
data.collect do |value|
|
226
|
+
clean_unserializable_data(value, stack + [data.object_id])
|
227
|
+
end
|
228
|
+
else
|
229
|
+
data.to_s
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
# Replaces the contents of params that match params_filters.
|
234
|
+
# TODO: extract this to a different class
|
235
|
+
def clean_params
|
236
|
+
clean_unserializable_data_from(:parameters)
|
237
|
+
filter(parameters)
|
238
|
+
if cgi_data
|
239
|
+
clean_unserializable_data_from(:cgi_data)
|
240
|
+
filter(cgi_data)
|
241
|
+
end
|
242
|
+
if session_data
|
243
|
+
clean_unserializable_data_from(:session_data)
|
244
|
+
filter(session_data)
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
def clean_rack_request_data
|
249
|
+
if cgi_data
|
250
|
+
cgi_data.delete("rack.request.form_vars")
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
def filter(hash)
|
255
|
+
if params_filters
|
256
|
+
hash.each do |key, value|
|
257
|
+
if filter_key?(key)
|
258
|
+
hash[key] = "[FILTERED]"
|
259
|
+
elsif value.respond_to?(:to_hash)
|
260
|
+
filter(hash[key])
|
261
|
+
end
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
def filter_key?(key)
|
267
|
+
params_filters.any? do |filter|
|
268
|
+
key.to_s.include?(filter.to_s)
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
def find_session_data
|
273
|
+
self.session_data = args[:session_data] || args[:session] || rack_session || {}
|
274
|
+
self.session_data = session_data[:data] if session_data[:data]
|
275
|
+
end
|
276
|
+
|
277
|
+
# Converts the mixed class instances and class names into just names
|
278
|
+
# TODO: move this into Configuration or another class
|
279
|
+
def ignored_class_names
|
280
|
+
ignore.collect do |string_or_class|
|
281
|
+
if string_or_class.respond_to?(:name)
|
282
|
+
string_or_class.name
|
283
|
+
else
|
284
|
+
string_or_class
|
285
|
+
end
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
def xml_vars_for(builder, hash)
|
290
|
+
hash.each do |key, value|
|
291
|
+
if value.respond_to?(:to_hash)
|
292
|
+
builder.var(:key => key){|b| xml_vars_for(b, value.to_hash) }
|
293
|
+
else
|
294
|
+
builder.var(value.to_s, :key => key)
|
295
|
+
end
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
def rack_env(method)
|
300
|
+
rack_request.send(method) if rack_request
|
301
|
+
end
|
302
|
+
|
303
|
+
def rack_request
|
304
|
+
@rack_request ||= if args[:rack_env]
|
305
|
+
::Rack::Request.new(args[:rack_env])
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
def action_dispatch_params
|
310
|
+
args[:rack_env]['action_dispatch.request.parameters'] if args[:rack_env]
|
311
|
+
end
|
312
|
+
|
313
|
+
def rack_session
|
314
|
+
args[:rack_env]['rack.session'] if args[:rack_env]
|
315
|
+
end
|
316
|
+
|
317
|
+
def also_use_rack_params_filters
|
318
|
+
if args[:rack_env]
|
319
|
+
@params_filters ||= []
|
320
|
+
@params_filters += rack_request.env["action_dispatch.parameter_filter"] || []
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
def local_hostname
|
325
|
+
Socket.gethostname
|
326
|
+
end
|
327
|
+
|
328
|
+
end
|
329
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'validation_tracker_client'
|
2
|
+
require 'validation_tracker_client/rails/controller_methods'
|
3
|
+
require 'validation_tracker_client/rails/action_controller_catcher'
|
4
|
+
require 'validation_tracker_client/rails/error_lookup'
|
5
|
+
require 'validation_tracker_client/rails/javascript_notifier'
|
6
|
+
|
7
|
+
module ValidationTrackerClient
|
8
|
+
module Rails
|
9
|
+
def self.initialize
|
10
|
+
if defined?(ActionController::Base)
|
11
|
+
ActionController::Base.send(:include, ValidationTrackerClient::Rails::ActionControllerCatcher)
|
12
|
+
ActionController::Base.send(:include, ValidationTrackerClient::Rails::ErrorLookup)
|
13
|
+
ActionController::Base.send(:include, ValidationTrackerClient::Rails::ControllerMethods)
|
14
|
+
ActionController::Base.send(:include, ValidationTrackerClient::Rails::JavascriptNotifier)
|
15
|
+
end
|
16
|
+
|
17
|
+
rails_logger = if defined?(::Rails.logger)
|
18
|
+
::Rails.logger
|
19
|
+
elsif defined?(RAILS_DEFAULT_LOGGER)
|
20
|
+
RAILS_DEFAULT_LOGGER
|
21
|
+
end
|
22
|
+
|
23
|
+
ValidationTrackerClient.configure(true) do |config|
|
24
|
+
config.logger = rails_logger
|
25
|
+
config.environment_name = RAILS_ENV if defined?(RAILS_ENV)
|
26
|
+
config.project_root = RAILS_ROOT if defined?(RAILS_ROOT)
|
27
|
+
config.framework = "Rails: #{::Rails::VERSION::STRING}" if defined?(::Rails::VERSION)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
ValidationTrackerClient::Rails.initialize
|
34
|
+
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module ValidationTrackerClient
|
2
|
+
module Rails
|
3
|
+
module ControllerMethods
|
4
|
+
private
|
5
|
+
|
6
|
+
# This method should be used for sending manual notifications while you are still
|
7
|
+
# inside the controller. Otherwise it works like ValidationTrackerClient.notify.
|
8
|
+
def notify_validation_message(hash_or_exception)
|
9
|
+
unless validation_tracker_local_request?
|
10
|
+
ValidationTrackerClient.notify(hash_or_exception, validation_tracker_request_data)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def validation_tracker_local_request?
|
15
|
+
if defined?(::Rails.application.config)
|
16
|
+
::Rails.application.config.consider_all_requests_local || request.local?
|
17
|
+
else
|
18
|
+
consider_all_requests_local || local_request?
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def validation_tracker_request_data
|
23
|
+
{ :parameters => validation_tracker_filter_if_filtering(params.to_hash),
|
24
|
+
:session_data => validation_tracker_filter_if_filtering(validation_tracker_session_data),
|
25
|
+
:controller => params[:controller],
|
26
|
+
:action => params[:action],
|
27
|
+
:url => validation_tracker_request_url,
|
28
|
+
:cgi_data => validation_tracker_filter_if_filtering(request.env) }
|
29
|
+
end
|
30
|
+
|
31
|
+
def validation_tracker_filter_if_filtering(hash)
|
32
|
+
return hash if ! hash.is_a?(Hash)
|
33
|
+
|
34
|
+
if respond_to?(:filter_parameters)
|
35
|
+
filter_parameters(hash) rescue hash
|
36
|
+
else
|
37
|
+
hash
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def validation_tracker_session_data
|
42
|
+
if session.respond_to?(:to_hash)
|
43
|
+
session.to_hash
|
44
|
+
else
|
45
|
+
session.data
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def validation_tracker_request_url
|
50
|
+
url = "#{request.protocol}#{request.host}"
|
51
|
+
|
52
|
+
unless [80, 443].include?(request.port)
|
53
|
+
url << ":#{request.port}"
|
54
|
+
end
|
55
|
+
|
56
|
+
url << request.fullpath
|
57
|
+
url
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'validation_tracker_client'
|
2
|
+
require 'rails'
|
3
|
+
|
4
|
+
module ValidationTrackerClient
|
5
|
+
class Railtie < Rails::Railtie
|
6
|
+
|
7
|
+
config.after_initialize do
|
8
|
+
ValidationTrackerClient.configure(true) do |config|
|
9
|
+
config.logger ||= Rails.logger
|
10
|
+
config.environment_name ||= Rails.env
|
11
|
+
config.project_root ||= Rails.root
|
12
|
+
config.framework = "Rails: #{::Rails::VERSION::STRING}"
|
13
|
+
end
|
14
|
+
|
15
|
+
if defined?(::ActionController::Base)
|
16
|
+
require 'validation_tracker_client/rails/controller_methods'
|
17
|
+
|
18
|
+
::ActionController::Base.send(:include, ValidationTrackerClient::Rails::ControllerMethods)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module ValidationTrackerClient
|
2
|
+
# Sends out the notice to Validation Tracker
|
3
|
+
class Sender
|
4
|
+
|
5
|
+
NOTICES_URI = '/notifier_api/v2/notices/'.freeze
|
6
|
+
HTTP_ERRORS = [Timeout::Error,
|
7
|
+
Errno::EINVAL,
|
8
|
+
Errno::ECONNRESET,
|
9
|
+
EOFError,
|
10
|
+
Net::HTTPBadResponse,
|
11
|
+
Net::HTTPHeaderSyntaxError,
|
12
|
+
Net::ProtocolError,
|
13
|
+
Errno::ECONNREFUSED].freeze
|
14
|
+
|
15
|
+
def initialize(options = {})
|
16
|
+
[:proxy_host, :proxy_port, :proxy_user, :proxy_pass, :protocol,
|
17
|
+
:host, :port, :secure, :http_open_timeout, :http_read_timeout].each do |option|
|
18
|
+
instance_variable_set("@#{option}", options[option])
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Sends the notice data off to Validation Tracker for processing.
|
23
|
+
#
|
24
|
+
# @param [String] data The XML notice to be sent off
|
25
|
+
def send_to_hoptoad(data)
|
26
|
+
logger.debug { "Sending request to #{url.to_s}:\n#{data}" } if logger
|
27
|
+
|
28
|
+
http =
|
29
|
+
Net::HTTP::Proxy(proxy_host, proxy_port, proxy_user, proxy_pass).
|
30
|
+
new(url.host, url.port)
|
31
|
+
|
32
|
+
http.read_timeout = http_read_timeout
|
33
|
+
http.open_timeout = http_open_timeout
|
34
|
+
http.use_ssl = secure
|
35
|
+
|
36
|
+
response = begin
|
37
|
+
http.post(url.path, data, HEADERS)
|
38
|
+
rescue *HTTP_ERRORS => e
|
39
|
+
log :error, "Timeout while contacting the Validation Tracker server."
|
40
|
+
nil
|
41
|
+
end
|
42
|
+
|
43
|
+
case response
|
44
|
+
when Net::HTTPSuccess then
|
45
|
+
log :info, "Success: #{response.class}", response
|
46
|
+
else
|
47
|
+
log :error, "Failure: #{response.class}", response
|
48
|
+
end
|
49
|
+
|
50
|
+
if response && response.respond_to?(:body)
|
51
|
+
error_id = response.body.match(%r{<error-id[^>]*>(.*?)</error-id>})
|
52
|
+
error_id[1] if error_id
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
attr_reader :proxy_host, :proxy_port, :proxy_user, :proxy_pass, :protocol,
|
59
|
+
:host, :port, :secure, :http_open_timeout, :http_read_timeout
|
60
|
+
|
61
|
+
def url
|
62
|
+
URI.parse("#{protocol}://#{host}:#{port}").merge(NOTICES_URI)
|
63
|
+
end
|
64
|
+
|
65
|
+
def log(level, message, response = nil)
|
66
|
+
logger.send level, LOG_PREFIX + message if logger
|
67
|
+
ValidationTrackerClient.report_environment_info
|
68
|
+
ValidationTrackerClient.report_response_body(response.body) if response && response.respond_to?(:body)
|
69
|
+
end
|
70
|
+
|
71
|
+
def logger
|
72
|
+
ValidationTrackerClient.logger
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
data/rails/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'validation_tracker_client/rails'
|
data/test.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/validation_tracker_client/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["arun.kumar.arjunan"]
|
6
|
+
gem.email = ["arun@chronus.com"]
|
7
|
+
gem.description = %q{Validation Tracker Client}
|
8
|
+
gem.summary = %q{Validation Tracker Summary}
|
9
|
+
gem.homepage = ""
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "validation_tracker_client"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = ValidationTrackerClient::VERSION
|
17
|
+
end
|
metadata
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: validation_tracker_client
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 2.4.11
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- arun.kumar.arjunan
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-06-08 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: Validation Tracker Client
|
15
|
+
email:
|
16
|
+
- arun@chronus.com
|
17
|
+
executables: []
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- .gitignore
|
22
|
+
- Gemfile
|
23
|
+
- LICENSE
|
24
|
+
- README.md
|
25
|
+
- Rakefile
|
26
|
+
- lib/validation_tracker_client.rb
|
27
|
+
- lib/validation_tracker_client/configuration.rb
|
28
|
+
- lib/validation_tracker_client/notice.rb
|
29
|
+
- lib/validation_tracker_client/rails.rb
|
30
|
+
- lib/validation_tracker_client/rails/controller_methods.rb
|
31
|
+
- lib/validation_tracker_client/railtie.rb
|
32
|
+
- lib/validation_tracker_client/sender.rb
|
33
|
+
- lib/validation_tracker_client/version.rb
|
34
|
+
- rails/init.rb
|
35
|
+
- test.rb
|
36
|
+
- validation_tracker_client.gemspec
|
37
|
+
homepage: ''
|
38
|
+
licenses: []
|
39
|
+
post_install_message:
|
40
|
+
rdoc_options: []
|
41
|
+
require_paths:
|
42
|
+
- lib
|
43
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
44
|
+
none: false
|
45
|
+
requirements:
|
46
|
+
- - ! '>='
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
requirements: []
|
56
|
+
rubyforge_project:
|
57
|
+
rubygems_version: 1.8.10
|
58
|
+
signing_key:
|
59
|
+
specification_version: 3
|
60
|
+
summary: Validation Tracker Summary
|
61
|
+
test_files: []
|