logster 2.5.1 → 2.6.0
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.
- checksums.yaml +4 -4
- data/.travis.yml +2 -0
- data/CHANGELOG.md +9 -0
- data/README.md +15 -1
- data/Rakefile +1 -0
- data/assets/javascript/client-app.js +204 -168
- data/assets/javascript/vendor.js +5132 -5833
- data/assets/stylesheets/client-app.css +1 -1
- data/client-app/.eslintrc.js +17 -5
- data/client-app/.travis.yml +4 -3
- data/client-app/app/app.js +5 -7
- data/client-app/app/components/actions-menu.js +24 -17
- data/client-app/app/components/back-trace.js +148 -0
- data/client-app/app/components/env-tab.js +16 -12
- data/client-app/app/components/message-info.js +84 -7
- data/client-app/app/components/message-row.js +13 -15
- data/client-app/app/components/panel-resizer.js +63 -45
- data/client-app/app/components/patterns-list.js +6 -6
- data/client-app/app/components/update-time.js +13 -13
- data/client-app/app/controllers/index.js +4 -2
- data/client-app/app/index.html +1 -1
- data/client-app/app/initializers/app-init.js +1 -1
- data/client-app/app/lib/decorators.js +11 -0
- data/client-app/app/lib/preload.js +14 -3
- data/client-app/app/lib/utilities.js +63 -36
- data/client-app/app/models/group.js +6 -1
- data/client-app/app/models/message-collection.js +9 -7
- data/client-app/app/models/message.js +25 -20
- data/client-app/app/router.js +4 -6
- data/client-app/app/styles/app.css +18 -4
- data/client-app/app/templates/components/actions-menu.hbs +6 -2
- data/client-app/app/templates/components/back-trace.hbs +8 -0
- data/client-app/app/templates/components/message-info.hbs +7 -2
- data/client-app/app/templates/index.hbs +4 -1
- data/client-app/config/environment.js +1 -1
- data/client-app/config/optional-features.json +4 -1
- data/client-app/ember-cli-build.js +2 -3
- data/client-app/package-lock.json +9712 -2884
- data/client-app/package.json +25 -22
- data/client-app/preload-json-manager.rb +62 -0
- data/client-app/testem.js +0 -1
- data/client-app/tests/index.html +1 -1
- data/client-app/tests/integration/components/back-trace-test.js +109 -0
- data/client-app/tests/integration/components/message-info-test.js +4 -3
- data/client-app/tests/integration/components/patterns-list-test.js +7 -2
- data/lib/logster.rb +1 -0
- data/lib/logster/base_store.rb +16 -9
- data/lib/logster/configuration.rb +12 -2
- data/lib/logster/defer_logger.rb +1 -1
- data/lib/logster/logger.rb +12 -0
- data/lib/logster/message.rb +89 -30
- data/lib/logster/middleware/viewer.rb +44 -8
- data/lib/logster/redis_store.rb +69 -51
- data/lib/logster/suppression_pattern.rb +1 -1
- data/lib/logster/version.rb +1 -1
- data/logster.gemspec +1 -1
- data/test/logster/middleware/test_viewer.rb +100 -0
- data/test/logster/test_base_store.rb +16 -0
- data/test/logster/test_defer_logger.rb +1 -1
- data/test/logster/test_message.rb +142 -54
- data/test/logster/test_redis_store.rb +99 -39
- metadata +11 -6
data/client-app/package.json
CHANGED
@@ -18,40 +18,43 @@
|
|
18
18
|
"test": "ember test"
|
19
19
|
},
|
20
20
|
"devDependencies": {
|
21
|
-
"@ember/optional-features": "^
|
22
|
-
"
|
23
|
-
"
|
24
|
-
"
|
21
|
+
"@ember/optional-features": "^1.1.0",
|
22
|
+
"@glimmer/component": "^1.0.0",
|
23
|
+
"babel-eslint": "^10.0.3",
|
24
|
+
"broccoli-asset-rev": "^3.0.0",
|
25
|
+
"ember-auto-import": "^1.5.3",
|
26
|
+
"ember-cli": "^3.15.0",
|
25
27
|
"ember-cli-app-version": "^3.2.0",
|
26
|
-
"ember-cli-babel": "^7.
|
28
|
+
"ember-cli-babel": "^7.13.0",
|
27
29
|
"ember-cli-dependency-checker": "^3.2.0",
|
28
|
-
"ember-cli-eslint": "^
|
29
|
-
"ember-cli-htmlbars": "^
|
30
|
-
"ember-cli-
|
31
|
-
"ember-cli-inject-live-reload": "^1.8.2",
|
30
|
+
"ember-cli-eslint": "^5.1.0",
|
31
|
+
"ember-cli-htmlbars": "^4.2.0",
|
32
|
+
"ember-cli-inject-live-reload": "^2.0.1",
|
32
33
|
"ember-cli-sri": "^2.1.1",
|
33
34
|
"ember-cli-template-lint": "^1.0.0-beta.3",
|
34
|
-
"ember-cli-uglify": "^
|
35
|
-
"ember-data": "~3.
|
36
|
-
"ember-export-application-global": "^2.0.
|
35
|
+
"ember-cli-uglify": "^3.0.0",
|
36
|
+
"ember-data": "~3.15.0",
|
37
|
+
"ember-export-application-global": "^2.0.1",
|
38
|
+
"ember-fetch": "^7.0.0",
|
37
39
|
"ember-font-awesome": "^4.0.0-rc.4",
|
38
|
-
"ember-load-initializers": "^1.1
|
40
|
+
"ember-load-initializers": "^2.1.1",
|
39
41
|
"ember-maybe-import-regenerator": "^0.1.6",
|
40
|
-
"ember-qunit": "^
|
41
|
-
"ember-resolver": "^
|
42
|
-
"ember-source": "^3.
|
43
|
-
"
|
44
|
-
"eslint-plugin-
|
45
|
-
"jquery": "3.4.1",
|
42
|
+
"ember-qunit": "^4.6.0",
|
43
|
+
"ember-resolver": "^7.0.0",
|
44
|
+
"ember-source": "^3.15.0",
|
45
|
+
"eslint-plugin-ember": "^7.7.1",
|
46
|
+
"eslint-plugin-node": "^10.0.0",
|
46
47
|
"loader.js": "^4.7.0",
|
47
48
|
"prettier": "^1.19.1",
|
48
|
-
"qunit-dom": "^0.
|
49
|
+
"qunit-dom": "^0.9.2"
|
49
50
|
},
|
50
51
|
"engines": {
|
51
|
-
"node": "
|
52
|
+
"node": "8.* || >= 10.*"
|
53
|
+
},
|
54
|
+
"ember": {
|
55
|
+
"edition": "octane"
|
52
56
|
},
|
53
57
|
"dependencies": {
|
54
|
-
"lodash": "^4.17.15",
|
55
58
|
"moment": "~2.22.2"
|
56
59
|
}
|
57
60
|
}
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# This script takes care of updating the content of the preloaded json in app/index.html and tests/index.html
|
4
|
+
# All you need to do is update the ruby hash of the corresponding file you want to update and run the script
|
5
|
+
|
6
|
+
require 'bundler/inline'
|
7
|
+
require 'json'
|
8
|
+
require 'cgi'
|
9
|
+
|
10
|
+
gemfile do
|
11
|
+
source 'https://rubygems.org'
|
12
|
+
gem 'nokogiri'
|
13
|
+
end
|
14
|
+
|
15
|
+
tests_index_html = {
|
16
|
+
env_expandable_keys: [],
|
17
|
+
gems_dir: "/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/",
|
18
|
+
backtrace_links_enabled: true,
|
19
|
+
gems_data: [
|
20
|
+
{
|
21
|
+
name: "activerecord",
|
22
|
+
url: "https://github.com/rails/rails/tree/v6.0.1/activerecord"
|
23
|
+
}
|
24
|
+
],
|
25
|
+
directories: [
|
26
|
+
{
|
27
|
+
path: "/var/www/discourse",
|
28
|
+
url: "https://github.com/discourse/discourse",
|
29
|
+
main_app: true
|
30
|
+
},
|
31
|
+
{
|
32
|
+
path: "/var/www/discourse/plugins/discourse-prometheus",
|
33
|
+
url: "https://github.com/discourse/discourse-prometheus"
|
34
|
+
}
|
35
|
+
],
|
36
|
+
application_version: "ce512452b512b909c38e9c63f2a0e1f8c17a2399"
|
37
|
+
}
|
38
|
+
|
39
|
+
app_index_html = {
|
40
|
+
env_expandable_keys: [],
|
41
|
+
patterns_enabled: true,
|
42
|
+
gems_dir: "/home/sam/.rbenv/versions/2.1.2.discourse/lib/ruby/gems/2.1.0/gems/",
|
43
|
+
backtrace_links_enabled: true,
|
44
|
+
gems_data: [],
|
45
|
+
directories: [
|
46
|
+
{
|
47
|
+
path: "/home/sam/Source/discourse",
|
48
|
+
url: "https://github.com/discourse/discourse",
|
49
|
+
main_app: true
|
50
|
+
}
|
51
|
+
],
|
52
|
+
application_version: "b329e23f8511b7248c0e4aee370a9f8a249e1b84"
|
53
|
+
}
|
54
|
+
|
55
|
+
types = { app: app_index_html, tests: tests_index_html }
|
56
|
+
|
57
|
+
%i{app tests}.each do |type|
|
58
|
+
content = File.read("#{type}/index.html")
|
59
|
+
json = CGI.escapeHTML(JSON.generate(types[type]))
|
60
|
+
content.sub!(/data-preloaded=".*">$/, "data-preloaded=\"#{json}\">")
|
61
|
+
File.write("#{type}/index.html", content)
|
62
|
+
end
|
data/client-app/testem.js
CHANGED
data/client-app/tests/index.html
CHANGED
@@ -6,7 +6,7 @@
|
|
6
6
|
<title>ClientApp Tests</title>
|
7
7
|
<meta name="description" content="">
|
8
8
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
9
|
-
<meta id="preloaded-data" data-root-path="/logs" data-preloaded="{"env_expandable_keys":[]}">
|
9
|
+
<meta id="preloaded-data" data-root-path="/logs" data-preloaded="{"env_expandable_keys":[],"gems_dir":"/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/","backtrace_links_enabled":true,"gems_data":[{"name":"activerecord","url":"https://github.com/rails/rails/tree/v6.0.1/activerecord"}],"directories":[{"path":"/var/www/discourse","url":"https://github.com/discourse/discourse","main_app":true},{"path":"/var/www/discourse/plugins/discourse-prometheus","url":"https://github.com/discourse/discourse-prometheus"}],"application_version":"ce512452b512b909c38e9c63f2a0e1f8c17a2399"}">
|
10
10
|
|
11
11
|
{{content-for "head"}}
|
12
12
|
{{content-for "test-head"}}
|
@@ -0,0 +1,109 @@
|
|
1
|
+
import { module, test } from "qunit";
|
2
|
+
import { setupRenderingTest } from "ember-qunit";
|
3
|
+
import { render, find, findAll } from "@ember/test-helpers";
|
4
|
+
import hbs from "htmlbars-inline-precompile";
|
5
|
+
import { uninitialize, mutatePreload } from "client-app/lib/preload";
|
6
|
+
|
7
|
+
module("Integration | Component | back-trace", function(hooks) {
|
8
|
+
setupRenderingTest(hooks);
|
9
|
+
|
10
|
+
hooks.beforeEach(function() {
|
11
|
+
uninitialize();
|
12
|
+
});
|
13
|
+
|
14
|
+
hooks.afterEach(function() {
|
15
|
+
uninitialize();
|
16
|
+
});
|
17
|
+
|
18
|
+
test("backtrace lines display and work correctly", async function(assert) {
|
19
|
+
const backtrace = `/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activerecord-6.0.1/lib/active_record/relation/finder_methods.rb:317:in \`exists?'
|
20
|
+
/var/www/discourse/lib/permalink_constraint.rb:6:in \`matches?'
|
21
|
+
/var/www/discourse/plugins/discourse-prometheus/lib/middleware/metrics.rb:17:in \`call'`;
|
22
|
+
this.set("backtrace", backtrace);
|
23
|
+
await render(hbs`{{back-trace backtrace=backtrace}}`);
|
24
|
+
|
25
|
+
const [gem, app, plugin] = findAll("a");
|
26
|
+
assert.equal(
|
27
|
+
gem.href,
|
28
|
+
"https://github.com/rails/rails/tree/v6.0.1/activerecord/lib/active_record/relation/finder_methods.rb#L317"
|
29
|
+
);
|
30
|
+
|
31
|
+
assert.equal(
|
32
|
+
app.href,
|
33
|
+
"https://github.com/discourse/discourse/blob/ce512452b512b909c38e9c63f2a0e1f8c17a2399/lib/permalink_constraint.rb#L6"
|
34
|
+
);
|
35
|
+
|
36
|
+
assert.equal(
|
37
|
+
plugin.href,
|
38
|
+
"https://github.com/discourse/discourse-prometheus/blob/master/lib/middleware/metrics.rb#L17"
|
39
|
+
);
|
40
|
+
|
41
|
+
let gemLine = find("div.backtrace-line");
|
42
|
+
assert.equal(
|
43
|
+
gemLine.textContent,
|
44
|
+
"activerecord-6.0.1/lib/active_record/relation/finder_methods.rb:317:in `exists?'",
|
45
|
+
"gem lines are truncated"
|
46
|
+
);
|
47
|
+
});
|
48
|
+
|
49
|
+
test("non-ruby backtraces don't break things", async function(assert) {
|
50
|
+
this.set(
|
51
|
+
"backtrace",
|
52
|
+
`m/<@https://discourse-cdn.com/assets/application-f59d2.br.js:1:27448
|
53
|
+
m@https://discourse-cdn.com/assets/application-f59d2.br.js:1:27560
|
54
|
+
string@https://discourse-cdn.com/assets/application-f59d2.br.js:1:27869`
|
55
|
+
);
|
56
|
+
await render(hbs`{{back-trace backtrace=backtrace}}`);
|
57
|
+
const lines = this.backtrace.split("\n");
|
58
|
+
findAll("div.backtrace-line").forEach((node, index) => {
|
59
|
+
assert.equal(node.textContent.trim(), lines[index]);
|
60
|
+
});
|
61
|
+
});
|
62
|
+
|
63
|
+
test("Github links use commit sha", async function(assert) {
|
64
|
+
const backtrace = `/var/www/discourse/lib/permalink_constraint.rb:6:in \`matches?'`;
|
65
|
+
let env = [
|
66
|
+
{ application_version: "123abc" },
|
67
|
+
{ application_version: "abc123" }
|
68
|
+
];
|
69
|
+
this.setProperties({
|
70
|
+
backtrace,
|
71
|
+
env
|
72
|
+
});
|
73
|
+
await render(hbs`{{back-trace backtrace=backtrace env=env}}`);
|
74
|
+
let href = find("a").href;
|
75
|
+
assert.equal(
|
76
|
+
href,
|
77
|
+
"https://github.com/discourse/discourse/blob/123abc/lib/permalink_constraint.rb#L6",
|
78
|
+
"uses the first application_version if there are multiple versions"
|
79
|
+
);
|
80
|
+
|
81
|
+
env = { application_version: "567def" };
|
82
|
+
this.set("env", env);
|
83
|
+
await render(hbs`{{back-trace backtrace=backtrace env=env}}`);
|
84
|
+
href = find("a").href;
|
85
|
+
assert.equal(
|
86
|
+
href,
|
87
|
+
"https://github.com/discourse/discourse/blob/567def/lib/permalink_constraint.rb#L6",
|
88
|
+
"uses application_version when env is only a hash"
|
89
|
+
);
|
90
|
+
|
91
|
+
this.set("env", null);
|
92
|
+
await render(hbs`{{back-trace backtrace=backtrace env=env}}`);
|
93
|
+
href = find("a").href;
|
94
|
+
assert.equal(
|
95
|
+
href,
|
96
|
+
"https://github.com/discourse/discourse/blob/ce512452b512b909c38e9c63f2a0e1f8c17a2399/lib/permalink_constraint.rb#L6",
|
97
|
+
"falls back to preload if env doesn't contain application_version"
|
98
|
+
);
|
99
|
+
|
100
|
+
mutatePreload("application_version", null);
|
101
|
+
await render(hbs`{{back-trace backtrace=backtrace}}`);
|
102
|
+
href = find("a").href;
|
103
|
+
assert.equal(
|
104
|
+
href,
|
105
|
+
"https://github.com/discourse/discourse/blob/master/lib/permalink_constraint.rb#L6",
|
106
|
+
"falls back to master branch when neither preload nor application_version in env are available"
|
107
|
+
);
|
108
|
+
});
|
109
|
+
});
|
@@ -32,11 +32,12 @@ module("Integration | Component | message-info", function(hooks) {
|
|
32
32
|
showTitle=showTitle
|
33
33
|
currentEnvPosition=envPosition
|
34
34
|
envChangedAction=callback
|
35
|
+
showShare=true
|
35
36
|
actionsInMenu=actionsInMenu}}`
|
36
37
|
);
|
37
38
|
let activeTab = find(".message-info .content.active pre");
|
38
39
|
assert.equal(
|
39
|
-
activeTab.textContent,
|
40
|
+
activeTab.textContent.trim(),
|
40
41
|
backtrace,
|
41
42
|
"default active tab is backtrace"
|
42
43
|
);
|
@@ -60,7 +61,7 @@ module("Integration | Component | message-info", function(hooks) {
|
|
60
61
|
await click(find(".message-actions button.expand.no-text"));
|
61
62
|
assert.equal(
|
62
63
|
findAll(".actions-menu button").length,
|
63
|
-
|
64
|
+
3,
|
64
65
|
"extra buttons shown inside a menu"
|
65
66
|
);
|
66
67
|
assert
|
@@ -85,7 +86,7 @@ module("Integration | Component | message-info", function(hooks) {
|
|
85
86
|
.doesNotExist("menu expand button is not shown");
|
86
87
|
assert.equal(
|
87
88
|
findAll(".message-actions button").length,
|
88
|
-
|
89
|
+
4,
|
89
90
|
"all actions buttons are shown inline when `actionsInMenu` is false"
|
90
91
|
);
|
91
92
|
|
@@ -12,7 +12,9 @@ module("Integration | Component | patterns-list", function(hooks) {
|
|
12
12
|
mutable: true,
|
13
13
|
patterns: []
|
14
14
|
});
|
15
|
-
await render(
|
15
|
+
await render(
|
16
|
+
hbs`{{patterns-list patterns=patterns mutable=mutable showCounter=true}}`
|
17
|
+
);
|
16
18
|
assert
|
17
19
|
.dom(".pattern-input")
|
18
20
|
.exists("It shows an input when patterns are emtpy");
|
@@ -33,7 +35,10 @@ module("Integration | Component | patterns-list", function(hooks) {
|
|
33
35
|
.doesNotExist("No save buttons are shown when there is 0 buffer");
|
34
36
|
const counters = findAll("input.count");
|
35
37
|
assert.equal(counters.length, 3, "counters shown for all patterns");
|
36
|
-
assert.ok(
|
38
|
+
assert.ok(
|
39
|
+
counters.every(c => c.disabled),
|
40
|
+
"counters are disabled"
|
41
|
+
);
|
37
42
|
|
38
43
|
pattern1.set("count", 6);
|
39
44
|
this.set("patterns", [pattern1, pattern2]);
|
data/lib/logster.rb
CHANGED
data/lib/logster/base_store.rb
CHANGED
@@ -18,7 +18,7 @@ module Logster
|
|
18
18
|
end
|
19
19
|
|
20
20
|
# Modify the saved message to the given one (identified by message.key) and bump it to the top of the latest list
|
21
|
-
def replace_and_bump(message
|
21
|
+
def replace_and_bump(message)
|
22
22
|
not_implemented
|
23
23
|
end
|
24
24
|
|
@@ -195,26 +195,33 @@ module Logster
|
|
195
195
|
similar = nil
|
196
196
|
|
197
197
|
if Logster.config.allow_grouping
|
198
|
+
message.apply_message_size_limit(
|
199
|
+
Logster.config.maximum_message_size_bytes,
|
200
|
+
gems_dir: Logster.config.gems_dir
|
201
|
+
)
|
198
202
|
key = self.similar_key(message)
|
199
203
|
similar = get(key, load_env: false) if key
|
200
204
|
end
|
201
205
|
|
206
|
+
message.drop_redundant_envs(Logster.config.max_env_count_per_message)
|
207
|
+
message.apply_env_size_limit(Logster.config.max_env_bytes)
|
208
|
+
saved = true
|
202
209
|
if similar
|
203
|
-
|
204
|
-
|
205
|
-
end
|
206
|
-
save_env = similar.merge_similar_message(message)
|
207
|
-
|
208
|
-
replace_and_bump(similar, save_env: save_env)
|
210
|
+
similar.merge_similar_message(message)
|
211
|
+
replace_and_bump(similar)
|
209
212
|
similar
|
210
213
|
else
|
211
|
-
|
214
|
+
message.apply_message_size_limit(
|
215
|
+
Logster.config.maximum_message_size_bytes,
|
216
|
+
gems_dir: Logster.config.gems_dir
|
217
|
+
)
|
218
|
+
saved = save(message)
|
212
219
|
message
|
213
220
|
end
|
214
221
|
|
215
222
|
message = similar || message
|
216
223
|
|
217
|
-
if Logster.config.enable_custom_patterns_via_ui || allow_custom_patterns
|
224
|
+
if (Logster.config.enable_custom_patterns_via_ui || allow_custom_patterns) && saved
|
218
225
|
grouping_patterns = @patterns_cache.fetch(Logster::GroupingPattern::CACHE_KEY) do
|
219
226
|
Logster::GroupingPattern.find_all(store: self)
|
220
227
|
end
|
@@ -12,7 +12,12 @@ module Logster
|
|
12
12
|
:environments,
|
13
13
|
:rate_limit_error_reporting,
|
14
14
|
:web_title,
|
15
|
-
:maximum_message_size_bytes
|
15
|
+
:maximum_message_size_bytes,
|
16
|
+
:project_directories,
|
17
|
+
:enable_backtrace_links,
|
18
|
+
:gems_dir,
|
19
|
+
:max_env_bytes,
|
20
|
+
:max_env_count_per_message
|
16
21
|
)
|
17
22
|
|
18
23
|
attr_writer :subdirectory
|
@@ -26,7 +31,12 @@ module Logster
|
|
26
31
|
@enable_custom_patterns_via_ui = false
|
27
32
|
@rate_limit_error_reporting = true
|
28
33
|
@enable_js_error_reporting = true
|
29
|
-
@maximum_message_size_bytes =
|
34
|
+
@maximum_message_size_bytes = 10_000
|
35
|
+
@max_env_bytes = 1000
|
36
|
+
@max_env_count_per_message = 50
|
37
|
+
@project_directories = []
|
38
|
+
@enable_backtrace_links = true
|
39
|
+
@gems_dir = Gem.dir + "/gems/"
|
30
40
|
|
31
41
|
@allow_grouping = false
|
32
42
|
|
data/lib/logster/defer_logger.rb
CHANGED
data/lib/logster/logger.rb
CHANGED
@@ -70,6 +70,18 @@ module Logster
|
|
70
70
|
message = message.scrub
|
71
71
|
end
|
72
72
|
|
73
|
+
# we want to get the backtrace as early as possible so that logster's
|
74
|
+
# own methods don't show up as the first few frames in the backtrace
|
75
|
+
if !opts || !opts.key?(:backtrace)
|
76
|
+
opts ||= {}
|
77
|
+
backtrace = caller_locations
|
78
|
+
while backtrace.first.path.end_with?("/logger.rb")
|
79
|
+
backtrace.shift
|
80
|
+
end
|
81
|
+
backtrace = backtrace.join("\n")
|
82
|
+
opts[:backtrace] = backtrace
|
83
|
+
end
|
84
|
+
|
73
85
|
if @chained
|
74
86
|
i = 0
|
75
87
|
# micro optimise for logging
|
data/lib/logster/message.rb
CHANGED
@@ -4,8 +4,6 @@ require 'digest/sha1'
|
|
4
4
|
require 'securerandom'
|
5
5
|
|
6
6
|
module Logster
|
7
|
-
|
8
|
-
MAX_GROUPING_LENGTH = 50
|
9
7
|
MAX_MESSAGE_LENGTH = 600
|
10
8
|
|
11
9
|
class Message
|
@@ -22,9 +20,10 @@ module Logster
|
|
22
20
|
hostname
|
23
21
|
process_id
|
24
22
|
application_version
|
23
|
+
time
|
25
24
|
}
|
26
25
|
|
27
|
-
attr_accessor :timestamp, :severity, :progname, :key, :backtrace, :count, :protected, :first_timestamp
|
26
|
+
attr_accessor :timestamp, :severity, :progname, :key, :backtrace, :count, :protected, :first_timestamp, :env_buffer
|
28
27
|
attr_reader :message, :env
|
29
28
|
|
30
29
|
def initialize(severity, progname, message, timestamp = nil, key = nil, count: 1)
|
@@ -37,6 +36,7 @@ module Logster
|
|
37
36
|
@count = count || 1
|
38
37
|
@protected = false
|
39
38
|
@first_timestamp = nil
|
39
|
+
@env_buffer = []
|
40
40
|
end
|
41
41
|
|
42
42
|
def to_h(exclude_env: false)
|
@@ -82,7 +82,6 @@ module Logster
|
|
82
82
|
end
|
83
83
|
|
84
84
|
def env=(env)
|
85
|
-
@env_json = nil
|
86
85
|
@env = self.class.scrub_params(env)
|
87
86
|
end
|
88
87
|
|
@@ -94,12 +93,18 @@ module Logster
|
|
94
93
|
env ||= {}
|
95
94
|
if Array === env
|
96
95
|
env = env.map do |single_env|
|
97
|
-
self.class.default_env.merge(single_env)
|
96
|
+
single_env = self.class.default_env.merge(single_env)
|
97
|
+
if !single_env.key?("time") && !single_env.key?(:time)
|
98
|
+
single_env["time"] = @timestamp || get_timestamp
|
99
|
+
end
|
100
|
+
single_env
|
98
101
|
end
|
99
102
|
else
|
100
103
|
env = self.class.default_env.merge(env)
|
104
|
+
if !env.key?("time") && !env.key?(:time)
|
105
|
+
env["time"] = @timestamp || get_timestamp
|
106
|
+
end
|
101
107
|
end
|
102
|
-
@env_json = nil
|
103
108
|
@env = Message.populate_from_env(env)
|
104
109
|
end
|
105
110
|
|
@@ -127,12 +132,11 @@ module Logster
|
|
127
132
|
if Array === env
|
128
133
|
versions = env.map { |single_env| single_env["application_version"] }
|
129
134
|
else
|
130
|
-
versions = env["application_version"]
|
135
|
+
versions = [env["application_version"]]
|
131
136
|
end
|
137
|
+
versions.compact!
|
132
138
|
|
133
|
-
if
|
134
|
-
versions = [versions] if String === versions
|
135
|
-
|
139
|
+
if backtrace && backtrace.length > 0
|
136
140
|
versions.map do |version|
|
137
141
|
Digest::SHA1.hexdigest "#{version} #{backtrace}"
|
138
142
|
end
|
@@ -146,31 +150,24 @@ module Logster
|
|
146
150
|
def merge_similar_message(other)
|
147
151
|
self.first_timestamp ||= self.timestamp
|
148
152
|
self.timestamp = [self.timestamp, other.timestamp].max
|
149
|
-
|
150
153
|
self.count += other.count || 1
|
151
|
-
return false if self.count > Logster::MAX_GROUPING_LENGTH
|
152
154
|
|
153
|
-
|
154
|
-
|
155
|
-
return false if size + extra_env_size > Logster.config.maximum_message_size_bytes
|
156
|
-
|
157
|
-
other_env = JSON.load JSON.fast_generate other.env
|
158
|
-
if Hash === other_env && !other_env.key?("time")
|
159
|
-
other_env["time"] = other.timestamp
|
160
|
-
end
|
161
|
-
if Hash === self.env && !self.env.key?("time")
|
162
|
-
self.env["time"] = self.first_timestamp
|
155
|
+
if Hash === other.env && !other.env.key?("time") && !other.env.key?(:time)
|
156
|
+
other.env["time"] = other.timestamp
|
163
157
|
end
|
164
158
|
|
165
|
-
if Array ===
|
166
|
-
|
159
|
+
if Array === other.env
|
160
|
+
env_buffer.unshift(*other.env)
|
167
161
|
else
|
168
|
-
|
162
|
+
env_buffer.unshift(other.env)
|
169
163
|
end
|
170
|
-
@env_json = nil
|
171
164
|
true
|
172
165
|
end
|
173
166
|
|
167
|
+
def has_env_buffer?
|
168
|
+
env_buffer.size > 0
|
169
|
+
end
|
170
|
+
|
174
171
|
def self.populate_from_env(env)
|
175
172
|
if Array === env
|
176
173
|
env.map do |single_env|
|
@@ -229,10 +226,6 @@ module Logster
|
|
229
226
|
end
|
230
227
|
end
|
231
228
|
|
232
|
-
def env_json
|
233
|
-
@env_json ||= (self.env || {}).to_json
|
234
|
-
end
|
235
|
-
|
236
229
|
def self.scrub_params(params)
|
237
230
|
if Array === params
|
238
231
|
params.map! { |p| scrub_params(p) }
|
@@ -250,8 +243,74 @@ module Logster
|
|
250
243
|
end
|
251
244
|
end
|
252
245
|
|
246
|
+
def drop_redundant_envs(limit)
|
247
|
+
if Array === env
|
248
|
+
env.slice!(limit..-1)
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
def apply_env_size_limit(size_limit)
|
253
|
+
if Array === env
|
254
|
+
env.each { |e| truncate_env(e, size_limit) }
|
255
|
+
elsif Hash === env
|
256
|
+
truncate_env(env, size_limit)
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
def apply_message_size_limit(limit, gems_dir: nil)
|
261
|
+
size = self.to_json(exclude_env: true).bytesize
|
262
|
+
if size > limit && @backtrace
|
263
|
+
@backtrace.gsub!(gems_dir, "") if gems_dir
|
264
|
+
@backtrace.strip!
|
265
|
+
size = self.to_json(exclude_env: true).bytesize
|
266
|
+
backtrace_limit = limit - (size - @backtrace.bytesize)
|
267
|
+
return if backtrace_limit <= 0 || size <= limit
|
268
|
+
truncate_backtrace(backtrace_limit)
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
def truncate_backtrace(bytes_limit)
|
273
|
+
@backtrace = @backtrace.byteslice(0...bytes_limit)
|
274
|
+
while !@backtrace[-1].valid_encoding? && @backtrace.size > 1
|
275
|
+
@backtrace.slice!(-1)
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
253
279
|
protected
|
254
280
|
|
281
|
+
def truncate_env(env, limit)
|
282
|
+
if JSON.fast_generate(env).bytesize > limit
|
283
|
+
sizes = {}
|
284
|
+
braces = '{}'.bytesize
|
285
|
+
env.each do |k, v|
|
286
|
+
sizes[k] = JSON.fast_generate(k => v).bytesize - braces
|
287
|
+
end
|
288
|
+
sorted = env.keys.sort { |a, b| sizes[a] <=> sizes[b] }
|
289
|
+
|
290
|
+
kept_keys = []
|
291
|
+
if env.key?(:time)
|
292
|
+
kept_keys << :time
|
293
|
+
elsif env.key?("time")
|
294
|
+
kept_keys << "time"
|
295
|
+
end
|
296
|
+
|
297
|
+
sum = braces
|
298
|
+
if time_key = kept_keys.first
|
299
|
+
sum += sizes[time_key]
|
300
|
+
sorted.delete(time_key)
|
301
|
+
end
|
302
|
+
comma = ','.bytesize
|
303
|
+
|
304
|
+
sorted.each do |k|
|
305
|
+
extra = kept_keys.size == 0 ? 0 : comma
|
306
|
+
break if sum + sizes[k] + extra > limit
|
307
|
+
kept_keys << k
|
308
|
+
sum += sizes[k] + extra
|
309
|
+
end
|
310
|
+
env.select! { |k| kept_keys.include?(k) }
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
255
314
|
def truncate_message(msg)
|
256
315
|
return msg unless msg
|
257
316
|
msg = msg.inspect unless String === msg
|