logster 1.3.0 → 1.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (112) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +18 -18
  3. data/.travis.yml +15 -15
  4. data/CHANGELOG.md +137 -130
  5. data/Gemfile +4 -4
  6. data/Guardfile +8 -8
  7. data/LICENSE.txt +22 -22
  8. data/README.md +99 -99
  9. data/Rakefile +24 -24
  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 -81
  21. data/assets/javascript/vendor.js +5302 -5302
  22. data/assets/stylesheets/client-app.css +0 -0
  23. data/assets/stylesheets/vendor.css +3 -3
  24. data/build_client_app.sh +12 -12
  25. data/client-app/.editorconfig +20 -20
  26. data/client-app/.ember-cli +9 -9
  27. data/client-app/.eslintignore +19 -19
  28. data/client-app/.eslintrc.js +46 -46
  29. data/client-app/.gitignore +23 -23
  30. data/client-app/.travis.yml +27 -27
  31. data/client-app/.watchmanconfig +3 -3
  32. data/client-app/README.md +57 -57
  33. data/client-app/app/app.js +14 -14
  34. data/client-app/app/components/message-info.js +18 -18
  35. data/client-app/app/components/message-row.js +45 -45
  36. data/client-app/app/components/panel-resizer.js +75 -75
  37. data/client-app/app/components/tab-contents.js +27 -27
  38. data/client-app/app/components/tab-link.js +5 -5
  39. data/client-app/app/components/tabbed-section.js +32 -32
  40. data/client-app/app/components/time-formatter.js +25 -25
  41. data/client-app/app/components/update-time.js +21 -21
  42. data/client-app/app/controllers/index.js +83 -83
  43. data/client-app/app/controllers/show.js +13 -13
  44. data/client-app/app/index.html +29 -29
  45. data/client-app/app/initializers/app-init.js +55 -55
  46. data/client-app/app/lib/preload.js +14 -14
  47. data/client-app/app/lib/utilities.js +140 -140
  48. data/client-app/app/models/message-collection.js +158 -158
  49. data/client-app/app/models/message.js +99 -99
  50. data/client-app/app/resolver.js +3 -3
  51. data/client-app/app/router.js +14 -14
  52. data/client-app/app/routes/index.js +53 -53
  53. data/client-app/app/routes/show.js +14 -14
  54. data/client-app/app/styles/app.css +387 -387
  55. data/client-app/app/templates/application.hbs +2 -2
  56. data/client-app/app/templates/components/message-info.hbs +44 -44
  57. data/client-app/app/templates/components/message-row.hbs +17 -17
  58. data/client-app/app/templates/components/tabbed-section.hbs +10 -10
  59. data/client-app/app/templates/components/time-formatter.hbs +1 -1
  60. data/client-app/app/templates/index.hbs +57 -57
  61. data/client-app/app/templates/show.hbs +4 -4
  62. data/client-app/config/environment.js +51 -51
  63. data/client-app/config/optional-features.json +3 -3
  64. data/client-app/config/targets.js +18 -18
  65. data/client-app/ember-cli-build.js +29 -29
  66. data/client-app/package-lock.json +11365 -11365
  67. data/client-app/package.json +56 -56
  68. data/client-app/testem.js +25 -25
  69. data/client-app/tests/index.html +34 -34
  70. data/client-app/tests/integration/components/message-info-test.js +26 -26
  71. data/client-app/tests/integration/components/message-row-test.js +26 -26
  72. data/client-app/tests/integration/components/panel-resizer-test.js +26 -26
  73. data/client-app/tests/integration/components/tab-contents-test.js +26 -26
  74. data/client-app/tests/integration/components/tab-link-test.js +26 -26
  75. data/client-app/tests/integration/components/tabbed-section-test.js +26 -26
  76. data/client-app/tests/integration/components/time-formatter-test.js +26 -26
  77. data/client-app/tests/integration/components/update-time-test.js +26 -26
  78. data/client-app/tests/test-helper.js +8 -8
  79. data/client-app/tests/unit/controllers/index-test.js +12 -12
  80. data/client-app/tests/unit/controllers/show-test.js +12 -12
  81. data/client-app/tests/unit/initializers/app-init-test.js +31 -31
  82. data/client-app/tests/unit/routes/index-test.js +11 -11
  83. data/client-app/tests/unit/routes/show-test.js +11 -11
  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 +108 -102
  90. data/lib/logster/message.rb +227 -227
  91. data/lib/logster/middleware/debug_exceptions.rb +26 -26
  92. data/lib/logster/middleware/reporter.rb +56 -56
  93. data/lib/logster/middleware/viewer.rb +220 -220
  94. data/lib/logster/rails/railtie.rb +58 -58
  95. data/lib/logster/redis_store.rb +481 -481
  96. data/lib/logster/version.rb +3 -3
  97. data/lib/logster/web.rb +14 -14
  98. data/logster.gemspec +34 -34
  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 -96
  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 +80 -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 -427
  110. data/test/test_helper.rb +38 -38
  111. data/vendor/assets/javascripts/logster.js.erb +39 -39
  112. metadata +3 -3
@@ -1,227 +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
- @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
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