logster 1.2.11 → 1.3.pre

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 (126) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +18 -17
  3. data/.travis.yml +15 -16
  4. data/CHANGELOG.md +130 -130
  5. data/Gemfile +4 -4
  6. data/Guardfile +8 -8
  7. data/LICENSE.txt +22 -22
  8. data/README.md +99 -96
  9. data/Rakefile +24 -23
  10. data/assets/fonts/FontAwesome.otf +0 -0
  11. data/assets/fonts/fontawesome-webfont.eot +0 -0
  12. data/assets/fonts/fontawesome-webfont.svg +639 -639
  13. data/assets/fonts/fontawesome-webfont.ttf +0 -0
  14. data/assets/fonts/fontawesome-webfont.woff +0 -0
  15. data/assets/fonts/fontawesome-webfont.woff2 +0 -0
  16. data/assets/images/Icon-144_rounded.png +0 -0
  17. data/assets/images/Icon-144_square.png +0 -0
  18. data/assets/images/icon_144x144.png +0 -0
  19. data/assets/images/icon_64x64.png +0 -0
  20. data/assets/javascript/client-app.js +81 -0
  21. data/assets/javascript/vendor.js +5302 -0
  22. data/assets/stylesheets/client-app.css +1 -0
  23. data/assets/stylesheets/vendor.css +4 -0
  24. data/build_client_app.sh +12 -0
  25. data/client-app/.editorconfig +20 -0
  26. data/client-app/.ember-cli +9 -0
  27. data/client-app/.eslintignore +19 -0
  28. data/client-app/.eslintrc.js +46 -0
  29. data/client-app/.gitignore +23 -0
  30. data/client-app/.travis.yml +27 -0
  31. data/client-app/.watchmanconfig +3 -0
  32. data/client-app/README.md +57 -0
  33. data/client-app/app/app.js +14 -0
  34. data/client-app/app/components/message-info.js +18 -0
  35. data/client-app/app/components/message-row.js +45 -0
  36. data/client-app/app/components/panel-resizer.js +75 -0
  37. data/client-app/app/components/tab-contents.js +27 -0
  38. data/client-app/app/components/tab-link.js +5 -0
  39. data/client-app/app/components/tabbed-section.js +32 -0
  40. data/client-app/app/components/time-formatter.js +25 -0
  41. data/client-app/app/components/update-time.js +21 -0
  42. data/client-app/app/controllers/index.js +83 -0
  43. data/client-app/app/controllers/show.js +13 -0
  44. data/client-app/app/index.html +29 -0
  45. data/client-app/app/initializers/app-init.js +55 -0
  46. data/client-app/app/lib/preload.js +14 -0
  47. data/client-app/app/lib/utilities.js +140 -0
  48. data/client-app/app/models/message-collection.js +158 -0
  49. data/client-app/app/models/message.js +99 -0
  50. data/client-app/app/resolver.js +3 -0
  51. data/client-app/app/router.js +14 -0
  52. data/client-app/app/routes/index.js +53 -0
  53. data/client-app/app/routes/show.js +14 -0
  54. data/{assets/stylesheets → client-app/app/styles}/app.css +387 -390
  55. data/{assets/javascript → client-app/app}/templates/application.hbs +2 -2
  56. data/client-app/app/templates/components/message-info.hbs +44 -0
  57. data/{assets/javascript → client-app/app/templates}/components/message-row.hbs +17 -17
  58. data/client-app/app/templates/components/tabbed-section.hbs +10 -0
  59. data/client-app/app/templates/components/time-formatter.hbs +1 -0
  60. data/{assets/javascript → client-app/app}/templates/index.hbs +57 -57
  61. data/{assets/javascript → client-app/app}/templates/show.hbs +4 -4
  62. data/client-app/config/environment.js +51 -0
  63. data/client-app/config/optional-features.json +3 -0
  64. data/client-app/config/targets.js +18 -0
  65. data/client-app/ember-cli-build.js +29 -0
  66. data/client-app/package-lock.json +11365 -0
  67. data/client-app/package.json +56 -0
  68. data/client-app/testem.js +25 -0
  69. data/client-app/tests/index.html +34 -0
  70. data/client-app/tests/integration/components/message-info-test.js +26 -0
  71. data/client-app/tests/integration/components/message-row-test.js +26 -0
  72. data/client-app/tests/integration/components/panel-resizer-test.js +26 -0
  73. data/client-app/tests/integration/components/tab-contents-test.js +26 -0
  74. data/client-app/tests/integration/components/tab-link-test.js +26 -0
  75. data/client-app/tests/integration/components/tabbed-section-test.js +26 -0
  76. data/client-app/tests/integration/components/time-formatter-test.js +26 -0
  77. data/client-app/tests/integration/components/update-time-test.js +26 -0
  78. data/client-app/tests/test-helper.js +8 -0
  79. data/client-app/tests/unit/controllers/index-test.js +12 -0
  80. data/client-app/tests/unit/controllers/show-test.js +12 -0
  81. data/client-app/tests/unit/initializers/app-init-test.js +31 -0
  82. data/client-app/tests/unit/routes/index-test.js +11 -0
  83. data/client-app/tests/unit/routes/show-test.js +11 -0
  84. data/lib/examples/sidekiq_logster_reporter.rb +21 -21
  85. data/lib/logster.rb +54 -54
  86. data/lib/logster/base_store.rb +130 -130
  87. data/lib/logster/configuration.rb +25 -25
  88. data/lib/logster/ignore_pattern.rb +65 -65
  89. data/lib/logster/logger.rb +102 -101
  90. data/lib/logster/message.rb +227 -226
  91. data/lib/logster/middleware/debug_exceptions.rb +26 -26
  92. data/lib/logster/middleware/reporter.rb +56 -54
  93. data/lib/logster/middleware/viewer.rb +220 -251
  94. data/lib/logster/rails/railtie.rb +58 -58
  95. data/lib/logster/redis_store.rb +481 -477
  96. data/lib/logster/version.rb +3 -3
  97. data/lib/logster/web.rb +14 -14
  98. data/logster.gemspec +34 -33
  99. data/test/examples/test_sidekiq_reporter_example.rb +46 -46
  100. data/test/fake_data/Gemfile +4 -4
  101. data/test/fake_data/generate.rb +10 -10
  102. data/test/logster/middleware/test_reporter.rb +21 -21
  103. data/test/logster/middleware/test_viewer.rb +96 -70
  104. data/test/logster/test_base_store.rb +147 -147
  105. data/test/logster/test_ignore_pattern.rb +41 -41
  106. data/test/logster/test_logger.rb +74 -74
  107. data/test/logster/test_message.rb +34 -34
  108. data/test/logster/test_redis_rate_limiter.rb +230 -230
  109. data/test/logster/test_redis_store.rb +427 -414
  110. data/test/test_helper.rb +38 -37
  111. data/vendor/assets/javascripts/logster.js.erb +39 -39
  112. metadata +83 -24
  113. data/assets/javascript/app.js +0 -817
  114. data/assets/javascript/components/message-info.hbs +0 -47
  115. data/assets/javascript/components/panel-resizer.hbs +0 -0
  116. data/assets/javascript/components/tab-contents.hbs +0 -1
  117. data/assets/javascript/components/tab-link.hbs +0 -1
  118. data/assets/javascript/components/tabbed-section.hbs +0 -6
  119. data/assets/javascript/external/ember-template-compiler.js +0 -22346
  120. data/assets/javascript/external/ember.js +0 -58500
  121. data/assets/javascript/external/ember.min.js +0 -17
  122. data/assets/javascript/external/jquery.min.js +0 -5
  123. data/assets/javascript/external/lodash.min.js +0 -87
  124. data/assets/javascript/external/moment.min.js +0 -6
  125. data/assets/stylesheets/font-awesome.min.css +0 -4
  126. data/bower.json +0 -25
@@ -1,101 +1,102 @@
1
- require 'logger'
2
-
3
- module Logster
4
- class Logger < ::Logger
5
- LOGSTER_ENV = "logster_env".freeze
6
-
7
- attr_accessor :store, :skip_store
8
- attr_reader :chained
9
-
10
- def initialize(store)
11
- super(nil)
12
- @store = store
13
- @override_levels = nil
14
- end
15
-
16
- def override_level=(val)
17
- tid = Thread.current.object_id
18
-
19
- ol = @override_levels
20
- if val.nil? && ol && ol.key?(tid)
21
- ol.delete(tid)
22
- @override_levels = nil if ol.length == 0
23
- elsif val
24
- (@override_levels ||= {})[tid] = val
25
- end
26
- end
27
-
28
- def chain(logger)
29
- @chained ||= []
30
- @chained << logger
31
- end
32
-
33
- def add_to_chained(logger, severity, message, progname, opts=nil, &block)
34
- if logger.respond_to? :skip_store
35
- old = logger.skip_store
36
- logger.skip_store = @skip_store
37
- end
38
-
39
- if logger.is_a?(self.class)
40
- logger.add(severity, message, progname, opts, &block)
41
- else
42
- logger.add(severity, message, progname, &block)
43
- end
44
- ensure
45
- if logger.respond_to? :skip_store
46
- logger.skip_store = old
47
- end
48
- end
49
-
50
- def add(*args, &block)
51
- add_with_opts(*args,&block)
52
- end
53
-
54
- def level
55
- ol = @override_levels
56
- (ol && ol[Thread.current.object_id]) || @level
57
- end
58
-
59
- def add_with_opts(severity, message, progname, opts=nil, &block)
60
- if severity < level
61
- return true
62
- end
63
-
64
- if @chained
65
- i = 0
66
- # micro optimise for logging
67
- while i < @chained.length
68
- # TODO double yielding blocks
69
- begin
70
- add_to_chained(@chained[i], severity, message, progname, opts, &block)
71
- rescue => e
72
- # don't blow up if STDERR is somehow closed
73
- STDERR.puts "Failed to report message to chained logger #{e}" rescue nil
74
- end
75
- i += 1
76
- end
77
- end
78
-
79
- progname ||= @progname
80
- if message.nil?
81
- if block_given?
82
- message = yield
83
- else
84
- message = progname
85
- progname = @progname
86
- end
87
- end
88
-
89
- return if @skip_store
90
-
91
- opts ||= {}
92
- opts[:env] ||= Thread.current[LOGSTER_ENV]
93
-
94
- @store.report(severity, progname, message, opts)
95
-
96
- rescue => e
97
- # don't blow up if STDERR is somehow closed
98
- STDERR.puts "Failed to report error: #{e} #{severity} #{message} #{progname}" rescue nil
99
- end
100
- end
101
- end
1
+ require 'logger'
2
+
3
+ module Logster
4
+ class Logger < ::Logger
5
+ LOGSTER_ENV = "logster_env".freeze
6
+
7
+ attr_accessor :store, :skip_store
8
+ attr_reader :chained
9
+
10
+ def initialize(store)
11
+ super(nil)
12
+ @store = store
13
+ @override_levels = nil
14
+ @chained = []
15
+ @skip_store = false
16
+ end
17
+
18
+ def override_level=(val)
19
+ tid = Thread.current.object_id
20
+
21
+ ol = @override_levels
22
+ if val.nil? && ol && ol.key?(tid)
23
+ ol.delete(tid)
24
+ @override_levels = nil if ol.length == 0
25
+ elsif val
26
+ (@override_levels ||= {})[tid] = val
27
+ end
28
+ end
29
+
30
+ def chain(logger)
31
+ @chained << logger
32
+ end
33
+
34
+ def add_to_chained(logger, severity, message, progname, opts=nil, &block)
35
+ if logger.respond_to? :skip_store
36
+ old = logger.skip_store
37
+ logger.skip_store = @skip_store
38
+ end
39
+
40
+ if logger.is_a?(self.class)
41
+ logger.add(severity, message, progname, opts, &block)
42
+ else
43
+ logger.add(severity, message, progname, &block)
44
+ end
45
+ ensure
46
+ if logger.respond_to? :skip_store
47
+ logger.skip_store = old
48
+ end
49
+ end
50
+
51
+ def add(*args, &block)
52
+ add_with_opts(*args,&block)
53
+ end
54
+
55
+ def level
56
+ ol = @override_levels
57
+ (ol && ol[Thread.current.object_id]) || @level
58
+ end
59
+
60
+ def add_with_opts(severity, message, progname, opts=nil, &block)
61
+ if severity < level
62
+ return true
63
+ end
64
+
65
+ if @chained
66
+ i = 0
67
+ # micro optimise for logging
68
+ while i < @chained.length
69
+ # TODO double yielding blocks
70
+ begin
71
+ add_to_chained(@chained[i], severity, message, progname, opts, &block)
72
+ rescue => e
73
+ # don't blow up if STDERR is somehow closed
74
+ STDERR.puts "Failed to report message to chained logger #{e}" rescue nil
75
+ end
76
+ i += 1
77
+ end
78
+ end
79
+
80
+ progname ||= @progname
81
+ if message.nil?
82
+ if block_given?
83
+ message = yield
84
+ else
85
+ message = progname
86
+ progname = @progname
87
+ end
88
+ end
89
+
90
+ return if @skip_store
91
+
92
+ opts ||= {}
93
+ opts[:env] ||= Thread.current[LOGSTER_ENV]
94
+
95
+ @store.report(severity, progname, message, opts)
96
+
97
+ rescue => e
98
+ # don't blow up if STDERR is somehow closed
99
+ STDERR.puts "Failed to report error: #{e} #{severity} #{message} #{progname}" rescue nil
100
+ end
101
+ end
102
+ end
@@ -1,226 +1,227 @@
1
- require 'digest/sha1'
2
- require 'securerandom'
3
-
4
- module Logster
5
-
6
- MAX_GROUPING_LENGTH = 50
7
-
8
- class Message
9
- LOGSTER_ENV = "_logster_env".freeze
10
- ALLOWED_ENV = %w{
11
- HTTP_HOST
12
- REQUEST_URI
13
- REQUEST_METHOD
14
- HTTP_USER_AGENT
15
- HTTP_ACCEPT
16
- HTTP_REFERER
17
- HTTP_X_FORWARDED_FOR
18
- HTTP_X_REAL_IP
19
- hostname
20
- process_id
21
- application_version
22
- }
23
-
24
- attr_accessor :timestamp, :severity, :progname, :message, :key, :backtrace, :count, :env, :protected, :first_timestamp
25
-
26
- def initialize(severity, progname, message, timestamp = nil, key = nil)
27
- @timestamp = timestamp || get_timestamp
28
- @severity = severity
29
- @progname = progname
30
- @message = message
31
- @key = key || SecureRandom.hex
32
- @backtrace = nil
33
- @count = 1
34
- @protected = false
35
- end
36
-
37
- def to_h
38
- h = {
39
- message: @message,
40
- progname: @progname,
41
- severity: @severity,
42
- timestamp: @timestamp,
43
- key: @key,
44
- backtrace: @backtrace,
45
- count: @count,
46
- env: @env,
47
- protected: @protected
48
- }
49
-
50
- if @first_timestamp
51
- h[:first_timestamp] = @first_timestamp
52
- end
53
-
54
- h
55
- end
56
-
57
- def to_json(opts = nil)
58
- JSON.fast_generate(to_h, opts)
59
- end
60
-
61
- def self.from_json(json)
62
- parsed = ::JSON.parse(json)
63
- msg = new( parsed["severity"],
64
- parsed["progname"],
65
- parsed["message"],
66
- parsed["timestamp"],
67
- parsed["key"] )
68
- msg.backtrace = parsed["backtrace"]
69
- msg.env = parsed["env"]
70
- msg.count = parsed["count"]
71
- msg.protected = parsed["protected"]
72
- msg.first_timestamp = parsed["first_timestamp"]
73
- msg
74
- end
75
-
76
- def self.hostname
77
- @hostname ||= `hostname`.strip! rescue "<unknown>"
78
- end
79
-
80
- def populate_from_env(env)
81
- env ||= {}
82
- @env = Message.populate_from_env(self.class.default_env.merge env)
83
- end
84
-
85
- def self.default_env
86
- env = {
87
- "hostname" => hostname,
88
- "process_id" => Process.pid
89
- }
90
- env["application_version"] = Logster.config.application_version if Logster.config.application_version
91
- env
92
- end
93
-
94
- # in its own method so it can be overridden
95
- def grouping_hash
96
- return { message: self.message, severity: self.severity, backtrace: self.backtrace }
97
- end
98
-
99
- # todo - memoize?
100
- def grouping_key
101
- Digest::SHA1.hexdigest JSON.fast_generate grouping_hash
102
- end
103
-
104
- # todo - memoize?
105
- def solved_keys
106
- if (versions=env["application_version"]) &&
107
- (backtrace && backtrace.length > 0)
108
- versions = [versions] if String === versions
109
-
110
- versions.map do |version|
111
- Digest::SHA1.hexdigest "#{version} #{backtrace}"
112
- end
113
- end
114
- end
115
-
116
- def is_similar?(other)
117
- self.grouping_key == other.grouping_key
118
- end
119
-
120
- def merge_similar_message(other)
121
- self.first_timestamp ||= self.timestamp
122
- self.timestamp = [self.timestamp,other.timestamp].max
123
- other_env = JSON.load JSON.fast_generate other.env
124
- other_env.keys.each do |env_key|
125
- self.env[env_key] = Message.env_merge_helper(self.env[env_key], other_env[env_key])
126
- end
127
- end
128
-
129
- def self.populate_from_env(env)
130
- env[LOGSTER_ENV] ||= begin
131
- unless env.include? "rack.input"
132
- # Not a web request
133
- return env
134
- end
135
- scrubbed = default_env
136
- request = Rack::Request.new(env)
137
- params = {}
138
- request.params.each do |k,v|
139
- if k.include? "password"
140
- params[k] = "[redacted]"
141
- elsif Array === v
142
- params[k] = v[0..20]
143
- else
144
- params[k] = v && v[0..100]
145
- end
146
- end
147
- scrubbed["params"] = params if params.length > 0
148
- ALLOWED_ENV.map{ |k|
149
- scrubbed[k] = env[k] if env[k]
150
- }
151
- scrubbed
152
- end
153
- end
154
-
155
- def <=>(other)
156
- time = self.timestamp <=> other.timestamp
157
- return time if time && time != 0
158
-
159
- self.key <=> other.key
160
- end
161
-
162
- def =~(pattern)
163
- case pattern
164
- when Hash
165
- IgnorePattern.new(nil, pattern).matches? self
166
- when String
167
- IgnorePattern.new(pattern, nil).matches? self
168
- when Regexp
169
- IgnorePattern.new(pattern, nil).matches? self
170
- when IgnorePattern
171
- pattern.matches? self
172
- else
173
- nil
174
- end
175
- end
176
-
177
- protected
178
-
179
- def get_timestamp
180
- (Time.new.to_f * 1000).to_i
181
- end
182
-
183
- private
184
-
185
- def self.env_merge_helper(self_value, other_value)
186
- other_value = other_value.to_s if Symbol === other_value
187
-
188
- if (Hash === self_value || self_value.nil?) && (Hash === other_value || other_value.nil?) && (!self_value.nil? || !other_value.nil?)
189
- # one or both is a hash but not neither -> recurse on the keys
190
- self_value = {} unless self_value
191
- other_value = {} unless other_value
192
- shared_keys = self_value.keys | (other_value.keys rescue [])
193
- shared_keys.each do |key|
194
- self_value[key] = env_merge_helper(self_value[key], other_value[key])
195
- end
196
- self_value
197
- elsif self_value.is_a?(Array) && !other_value.is_a?(Array)
198
- # Already have grouped data, so append to array (it's actually a set)
199
- self_value << other_value unless self_value.include?(other_value) || self_value.length >= Logster::MAX_GROUPING_LENGTH
200
- self_value
201
- elsif !self_value.is_a?(Array)
202
- if self_value == other_value
203
- self_value
204
- else
205
- [self_value, other_value]
206
- end
207
- else
208
- # They're both arrays.
209
- # Three cases:
210
- # self = [1,2,3] and other = [1,2,4] -> make into array of array
211
- # self = [] and other = [1,2,4] -> make into array of array
212
- # self = [[1,2,3], [1,2,5]] and other = [1,2,4] -> append to array
213
- if self_value.length > 0 && self_value[0].is_a?(Array)
214
- self_value << other_value unless self_value.include?(other_value) || self_value.length >= Logster::MAX_GROUPING_LENGTH
215
- self_value
216
- else
217
- if self_value == other_value
218
- self_value
219
- else
220
- [self_value, other_value]
221
- end
222
- end
223
- end
224
- end
225
- end
226
- end
1
+ require 'digest/sha1'
2
+ require 'securerandom'
3
+
4
+ module Logster
5
+
6
+ MAX_GROUPING_LENGTH = 50
7
+
8
+ class Message
9
+ LOGSTER_ENV = "_logster_env".freeze
10
+ ALLOWED_ENV = %w{
11
+ HTTP_HOST
12
+ REQUEST_URI
13
+ REQUEST_METHOD
14
+ HTTP_USER_AGENT
15
+ HTTP_ACCEPT
16
+ HTTP_REFERER
17
+ HTTP_X_FORWARDED_FOR
18
+ HTTP_X_REAL_IP
19
+ hostname
20
+ process_id
21
+ application_version
22
+ }
23
+
24
+ attr_accessor :timestamp, :severity, :progname, :message, :key, :backtrace, :count, :env, :protected, :first_timestamp
25
+
26
+ def initialize(severity, progname, message, timestamp = nil, key = nil)
27
+ @timestamp = timestamp || get_timestamp
28
+ @severity = severity
29
+ @progname = progname
30
+ @message = message
31
+ @key = key || SecureRandom.hex
32
+ @backtrace = nil
33
+ @count = 1
34
+ @protected = false
35
+ @first_timestamp = nil
36
+ end
37
+
38
+ def to_h
39
+ h = {
40
+ message: @message,
41
+ progname: @progname,
42
+ severity: @severity,
43
+ timestamp: @timestamp,
44
+ key: @key,
45
+ backtrace: @backtrace,
46
+ count: @count,
47
+ env: @env,
48
+ protected: @protected
49
+ }
50
+
51
+ if @first_timestamp
52
+ h[:first_timestamp] = @first_timestamp
53
+ end
54
+
55
+ h
56
+ end
57
+
58
+ def to_json(opts = nil)
59
+ JSON.fast_generate(to_h, opts)
60
+ end
61
+
62
+ def self.from_json(json)
63
+ parsed = ::JSON.parse(json)
64
+ msg = new( parsed["severity"],
65
+ parsed["progname"],
66
+ parsed["message"],
67
+ parsed["timestamp"],
68
+ parsed["key"] )
69
+ msg.backtrace = parsed["backtrace"]
70
+ msg.env = parsed["env"]
71
+ msg.count = parsed["count"]
72
+ msg.protected = parsed["protected"]
73
+ msg.first_timestamp = parsed["first_timestamp"]
74
+ msg
75
+ end
76
+
77
+ def self.hostname
78
+ @hostname ||= `hostname`.strip! rescue "<unknown>"
79
+ end
80
+
81
+ def populate_from_env(env)
82
+ env ||= {}
83
+ @env = Message.populate_from_env(self.class.default_env.merge env)
84
+ end
85
+
86
+ def self.default_env
87
+ env = {
88
+ "hostname" => hostname,
89
+ "process_id" => Process.pid
90
+ }
91
+ env["application_version"] = Logster.config.application_version if Logster.config.application_version
92
+ env
93
+ end
94
+
95
+ # in its own method so it can be overridden
96
+ def grouping_hash
97
+ return { message: self.message, severity: self.severity, backtrace: self.backtrace }
98
+ end
99
+
100
+ # todo - memoize?
101
+ def grouping_key
102
+ Digest::SHA1.hexdigest JSON.fast_generate grouping_hash
103
+ end
104
+
105
+ # todo - memoize?
106
+ def solved_keys
107
+ if (versions=env["application_version"]) &&
108
+ (backtrace && backtrace.length > 0)
109
+ versions = [versions] if String === versions
110
+
111
+ versions.map do |version|
112
+ Digest::SHA1.hexdigest "#{version} #{backtrace}"
113
+ end
114
+ end
115
+ end
116
+
117
+ def is_similar?(other)
118
+ self.grouping_key == other.grouping_key
119
+ end
120
+
121
+ def merge_similar_message(other)
122
+ self.first_timestamp ||= self.timestamp
123
+ self.timestamp = [self.timestamp,other.timestamp].max
124
+ other_env = JSON.load JSON.fast_generate other.env
125
+ other_env.keys.each do |env_key|
126
+ self.env[env_key] = Message.env_merge_helper(self.env[env_key], other_env[env_key])
127
+ end
128
+ end
129
+
130
+ def self.populate_from_env(env)
131
+ env[LOGSTER_ENV] ||= begin
132
+ unless env.include? "rack.input"
133
+ # Not a web request
134
+ return env
135
+ end
136
+ scrubbed = default_env
137
+ request = Rack::Request.new(env)
138
+ params = {}
139
+ request.params.each do |k,v|
140
+ if k.include? "password"
141
+ params[k] = "[redacted]"
142
+ elsif Array === v
143
+ params[k] = v[0..20]
144
+ else
145
+ params[k] = v && v[0..100]
146
+ end
147
+ end
148
+ scrubbed["params"] = params if params.length > 0
149
+ ALLOWED_ENV.map{ |k|
150
+ scrubbed[k] = env[k] if env[k]
151
+ }
152
+ scrubbed
153
+ end
154
+ end
155
+
156
+ def <=>(other)
157
+ time = self.timestamp <=> other.timestamp
158
+ return time if time && time != 0
159
+
160
+ self.key <=> other.key
161
+ end
162
+
163
+ def =~(pattern)
164
+ case pattern
165
+ when Hash
166
+ IgnorePattern.new(nil, pattern).matches? self
167
+ when String
168
+ IgnorePattern.new(pattern, nil).matches? self
169
+ when Regexp
170
+ IgnorePattern.new(pattern, nil).matches? self
171
+ when IgnorePattern
172
+ pattern.matches? self
173
+ else
174
+ nil
175
+ end
176
+ end
177
+
178
+ protected
179
+
180
+ def get_timestamp
181
+ (Time.new.to_f * 1000).to_i
182
+ end
183
+
184
+ private
185
+
186
+ def self.env_merge_helper(self_value, other_value)
187
+ other_value = other_value.to_s if Symbol === other_value
188
+
189
+ if (Hash === self_value || self_value.nil?) && (Hash === other_value || other_value.nil?) && (!self_value.nil? || !other_value.nil?)
190
+ # one or both is a hash but not neither -> recurse on the keys
191
+ self_value = {} unless self_value
192
+ other_value = {} unless other_value
193
+ shared_keys = self_value.keys | (other_value.keys rescue [])
194
+ shared_keys.each do |key|
195
+ self_value[key] = env_merge_helper(self_value[key], other_value[key])
196
+ end
197
+ self_value
198
+ elsif self_value.is_a?(Array) && !other_value.is_a?(Array)
199
+ # Already have grouped data, so append to array (it's actually a set)
200
+ self_value << other_value unless self_value.include?(other_value) || self_value.length >= Logster::MAX_GROUPING_LENGTH
201
+ self_value
202
+ elsif !self_value.is_a?(Array)
203
+ if self_value == other_value
204
+ self_value
205
+ else
206
+ [self_value, other_value]
207
+ end
208
+ else
209
+ # They're both arrays.
210
+ # Three cases:
211
+ # self = [1,2,3] and other = [1,2,4] -> make into array of array
212
+ # self = [] and other = [1,2,4] -> make into array of array
213
+ # self = [[1,2,3], [1,2,5]] and other = [1,2,4] -> append to array
214
+ if self_value.length > 0 && self_value[0].is_a?(Array)
215
+ self_value << other_value unless self_value.include?(other_value) || self_value.length >= Logster::MAX_GROUPING_LENGTH
216
+ self_value
217
+ else
218
+ if self_value == other_value
219
+ self_value
220
+ else
221
+ [self_value, other_value]
222
+ end
223
+ end
224
+ end
225
+ end
226
+ end
227
+ end