logster 2.1.1 → 2.1.2

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 (121) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +19 -19
  3. data/.rubocop.yml +1 -1
  4. data/.travis.yml +16 -16
  5. data/CHANGELOG.md +172 -169
  6. data/Gemfile +4 -4
  7. data/Guardfile +8 -8
  8. data/LICENSE.txt +22 -22
  9. data/README.md +99 -99
  10. data/Rakefile +21 -21
  11. data/assets/fonts/FontAwesome.otf +0 -0
  12. data/assets/fonts/fontawesome-webfont.eot +0 -0
  13. data/assets/fonts/fontawesome-webfont.svg +639 -639
  14. data/assets/fonts/fontawesome-webfont.ttf +0 -0
  15. data/assets/fonts/fontawesome-webfont.woff +0 -0
  16. data/assets/fonts/fontawesome-webfont.woff2 +0 -0
  17. data/assets/images/Icon-144_rounded.png +0 -0
  18. data/assets/images/Icon-144_square.png +0 -0
  19. data/assets/images/icon_144x144.png +0 -0
  20. data/assets/images/icon_64x64.png +0 -0
  21. data/assets/javascript/client-app.js +106 -100
  22. data/assets/stylesheets/client-app.css +1 -1
  23. data/build_client_app.sh +0 -0
  24. data/client-app/.editorconfig +20 -20
  25. data/client-app/.ember-cli +9 -9
  26. data/client-app/.eslintignore +19 -19
  27. data/client-app/.eslintrc.js +46 -46
  28. data/client-app/.gitignore +23 -23
  29. data/client-app/.travis.yml +27 -27
  30. data/client-app/.watchmanconfig +3 -3
  31. data/client-app/README.md +57 -57
  32. data/client-app/app/app.js +0 -0
  33. data/client-app/app/components/actions-menu.js +43 -37
  34. data/client-app/app/components/env-tab.js +80 -44
  35. data/client-app/app/components/message-info.js +0 -0
  36. data/client-app/app/components/message-row.js +0 -0
  37. data/client-app/app/components/panel-resizer.js +0 -0
  38. data/client-app/app/components/tab-contents.js +27 -27
  39. data/client-app/app/components/tabbed-section.js +0 -0
  40. data/client-app/app/components/time-formatter.js +0 -0
  41. data/client-app/app/components/update-time.js +0 -0
  42. data/client-app/app/controllers/index.js +0 -0
  43. data/client-app/app/controllers/show.js +0 -0
  44. data/client-app/app/index.html +29 -29
  45. data/client-app/app/initializers/app-init.js +67 -72
  46. data/client-app/app/lib/preload.js +20 -14
  47. data/client-app/app/lib/utilities.js +149 -140
  48. data/client-app/app/models/message-collection.js +0 -0
  49. data/client-app/app/models/message.js +100 -100
  50. data/client-app/app/resolver.js +0 -0
  51. data/client-app/app/router.js +0 -0
  52. data/client-app/app/routes/index.js +0 -0
  53. data/client-app/app/routes/show.js +0 -0
  54. data/client-app/app/styles/app.css +527 -521
  55. data/client-app/app/templates/application.hbs +2 -2
  56. data/client-app/app/templates/components/actions-menu.hbs +12 -12
  57. data/client-app/app/templates/components/env-tab.hbs +10 -10
  58. data/client-app/app/templates/components/message-info.hbs +41 -41
  59. data/client-app/app/templates/components/message-row.hbs +15 -15
  60. data/client-app/app/templates/components/panel-resizer.hbs +3 -3
  61. data/client-app/app/templates/components/tabbed-section.hbs +10 -10
  62. data/client-app/app/templates/components/time-formatter.hbs +1 -1
  63. data/client-app/app/templates/index.hbs +58 -58
  64. data/client-app/app/templates/show.hbs +7 -7
  65. data/client-app/config/environment.js +51 -51
  66. data/client-app/config/optional-features.json +3 -3
  67. data/client-app/config/targets.js +18 -18
  68. data/client-app/ember-cli-build.js +29 -29
  69. data/client-app/package-lock.json +11365 -11365
  70. data/client-app/package.json +56 -56
  71. data/client-app/testem.js +25 -25
  72. data/client-app/tests/index.html +34 -34
  73. data/client-app/tests/integration/components/env-tab-test.js +123 -73
  74. data/client-app/tests/integration/components/message-info-test.js +111 -26
  75. data/client-app/tests/test-helper.js +8 -8
  76. data/client-app/tests/unit/controllers/index-test.js +12 -12
  77. data/client-app/tests/unit/controllers/show-test.js +12 -12
  78. data/client-app/tests/unit/initializers/app-init-test.js +31 -31
  79. data/client-app/tests/unit/routes/index-test.js +11 -11
  80. data/client-app/tests/unit/routes/show-test.js +11 -11
  81. data/lib/examples/sidekiq_logster_reporter.rb +21 -21
  82. data/lib/logster.rb +54 -54
  83. data/lib/logster/base_store.rb +141 -141
  84. data/lib/logster/configuration.rb +26 -25
  85. data/lib/logster/defer_logger.rb +14 -14
  86. data/lib/logster/ignore_pattern.rb +65 -65
  87. data/lib/logster/logger.rb +113 -113
  88. data/lib/logster/message.rb +212 -212
  89. data/lib/logster/middleware/debug_exceptions.rb +26 -26
  90. data/lib/logster/middleware/reporter.rb +55 -55
  91. data/lib/logster/middleware/viewer.rb +222 -221
  92. data/lib/logster/rails/railtie.rb +63 -63
  93. data/lib/logster/redis_store.rb +566 -566
  94. data/lib/logster/scheduler.rb +54 -54
  95. data/lib/logster/version.rb +3 -3
  96. data/lib/logster/web.rb +14 -14
  97. data/logster.gemspec +35 -35
  98. data/test/examples/test_sidekiq_reporter_example.rb +46 -46
  99. data/test/fake_data/Gemfile +4 -4
  100. data/test/fake_data/generate.rb +10 -10
  101. data/test/logster/middleware/test_reporter.rb +19 -19
  102. data/test/logster/middleware/test_viewer.rb +96 -96
  103. data/test/logster/test_base_store.rb +147 -147
  104. data/test/logster/test_defer_logger.rb +34 -34
  105. data/test/logster/test_ignore_pattern.rb +41 -41
  106. data/test/logster/test_logger.rb +86 -86
  107. data/test/logster/test_message.rb +119 -119
  108. data/test/logster/test_redis_rate_limiter.rb +230 -230
  109. data/test/logster/test_redis_store.rb +720 -720
  110. data/test/test_helper.rb +38 -38
  111. data/vendor/assets/javascripts/logster.js.erb +39 -39
  112. metadata +1 -10
  113. data/client-app/app/components/tab-link.js +0 -5
  114. data/client-app/tests/integration/components/actions-menu-test.js +0 -26
  115. data/client-app/tests/integration/components/message-row-test.js +0 -26
  116. data/client-app/tests/integration/components/panel-resizer-test.js +0 -26
  117. data/client-app/tests/integration/components/tab-contents-test.js +0 -26
  118. data/client-app/tests/integration/components/tab-link-test.js +0 -26
  119. data/client-app/tests/integration/components/tabbed-section-test.js +0 -26
  120. data/client-app/tests/integration/components/time-formatter-test.js +0 -26
  121. data/client-app/tests/integration/components/update-time-test.js +0 -26
@@ -1,8 +1,8 @@
1
- import Application from '../app';
2
- import config from '../config/environment';
3
- import { setApplication } from '@ember/test-helpers';
4
- import { start } from 'ember-qunit';
5
-
6
- setApplication(Application.create(config.APP));
7
-
8
- start();
1
+ import Application from '../app';
2
+ import config from '../config/environment';
3
+ import { setApplication } from '@ember/test-helpers';
4
+ import { start } from 'ember-qunit';
5
+
6
+ setApplication(Application.create(config.APP));
7
+
8
+ start();
@@ -1,12 +1,12 @@
1
- import { module, test } from 'qunit';
2
- import { setupTest } from 'ember-qunit';
3
-
4
- module('Unit | Controller | index', function(hooks) {
5
- setupTest(hooks);
6
-
7
- // Replace this with your real tests.
8
- test('it exists', function(assert) {
9
- let controller = this.owner.lookup('controller:index');
10
- assert.ok(controller);
11
- });
12
- });
1
+ import { module, test } from 'qunit';
2
+ import { setupTest } from 'ember-qunit';
3
+
4
+ module('Unit | Controller | index', function(hooks) {
5
+ setupTest(hooks);
6
+
7
+ // Replace this with your real tests.
8
+ test('it exists', function(assert) {
9
+ let controller = this.owner.lookup('controller:index');
10
+ assert.ok(controller);
11
+ });
12
+ });
@@ -1,12 +1,12 @@
1
- import { module, test } from 'qunit';
2
- import { setupTest } from 'ember-qunit';
3
-
4
- module('Unit | Controller | show', function(hooks) {
5
- setupTest(hooks);
6
-
7
- // Replace this with your real tests.
8
- test('it exists', function(assert) {
9
- let controller = this.owner.lookup('controller:show');
10
- assert.ok(controller);
11
- });
12
- });
1
+ import { module, test } from 'qunit';
2
+ import { setupTest } from 'ember-qunit';
3
+
4
+ module('Unit | Controller | show', function(hooks) {
5
+ setupTest(hooks);
6
+
7
+ // Replace this with your real tests.
8
+ test('it exists', function(assert) {
9
+ let controller = this.owner.lookup('controller:show');
10
+ assert.ok(controller);
11
+ });
12
+ });
@@ -1,31 +1,31 @@
1
- import Application from '@ember/application';
2
-
3
- import { initialize } from 'client-app/initializers/app-init';
4
- import { module, test } from 'qunit';
5
- import { setupTest } from 'ember-qunit';
6
- import { run } from '@ember/runloop';
7
-
8
- module('Unit | Initializer | app-init', function(hooks) {
9
- setupTest(hooks);
10
-
11
- hooks.beforeEach(function() {
12
- this.TestApplication = Application.extend();
13
- this.TestApplication.initializer({
14
- name: 'initializer under test',
15
- initialize
16
- });
17
-
18
- this.application = this.TestApplication.create({ autoboot: false });
19
- });
20
-
21
- hooks.afterEach(function() {
22
- run(this.application, 'destroy');
23
- });
24
-
25
- // Replace this with your real tests.
26
- test('it works', async function(assert) {
27
- await this.application.boot();
28
-
29
- assert.ok(true);
30
- });
31
- });
1
+ import Application from '@ember/application';
2
+
3
+ import { initialize } from 'client-app/initializers/app-init';
4
+ import { module, test } from 'qunit';
5
+ import { setupTest } from 'ember-qunit';
6
+ import { run } from '@ember/runloop';
7
+
8
+ module('Unit | Initializer | app-init', function(hooks) {
9
+ setupTest(hooks);
10
+
11
+ hooks.beforeEach(function() {
12
+ this.TestApplication = Application.extend();
13
+ this.TestApplication.initializer({
14
+ name: 'initializer under test',
15
+ initialize
16
+ });
17
+
18
+ this.application = this.TestApplication.create({ autoboot: false });
19
+ });
20
+
21
+ hooks.afterEach(function() {
22
+ run(this.application, 'destroy');
23
+ });
24
+
25
+ // Replace this with your real tests.
26
+ test('it works', async function(assert) {
27
+ await this.application.boot();
28
+
29
+ assert.ok(true);
30
+ });
31
+ });
@@ -1,11 +1,11 @@
1
- import { module, test } from 'qunit';
2
- import { setupTest } from 'ember-qunit';
3
-
4
- module('Unit | Route | index', function(hooks) {
5
- setupTest(hooks);
6
-
7
- test('it exists', function(assert) {
8
- let route = this.owner.lookup('route:index');
9
- assert.ok(route);
10
- });
11
- });
1
+ import { module, test } from 'qunit';
2
+ import { setupTest } from 'ember-qunit';
3
+
4
+ module('Unit | Route | index', function(hooks) {
5
+ setupTest(hooks);
6
+
7
+ test('it exists', function(assert) {
8
+ let route = this.owner.lookup('route:index');
9
+ assert.ok(route);
10
+ });
11
+ });
@@ -1,11 +1,11 @@
1
- import { module, test } from 'qunit';
2
- import { setupTest } from 'ember-qunit';
3
-
4
- module('Unit | Route | show', function(hooks) {
5
- setupTest(hooks);
6
-
7
- test('it exists', function(assert) {
8
- let route = this.owner.lookup('route:show');
9
- assert.ok(route);
10
- });
11
- });
1
+ import { module, test } from 'qunit';
2
+ import { setupTest } from 'ember-qunit';
3
+
4
+ module('Unit | Route | show', function(hooks) {
5
+ setupTest(hooks);
6
+
7
+ test('it exists', function(assert) {
8
+ let route = this.owner.lookup('route:show');
9
+ assert.ok(route);
10
+ });
11
+ });
@@ -1,21 +1,21 @@
1
- class SidekiqLogsterReporter
2
- def call(ex, context = {})
3
- # Pass context to Logster
4
- fake_env = {}
5
- context.each do |key, value|
6
- Logster.add_to_env(fake_env, key, value)
7
- end
8
-
9
- text = "Job exception: #{ex}\n"
10
- if ex.backtrace
11
- Logster.add_to_env(fake_env, :backtrace, ex.backtrace)
12
- end
13
-
14
- Thread.current[Logster::Logger::LOGSTER_ENV] = fake_env
15
- Logster.logger.error(text)
16
- rescue => e
17
- Logster.logger.fatal("Failed to log exception #{ex} #{hash}\nReason: #{e.class} #{e}\n#{e.backtrace.join("\n")}")
18
- ensure
19
- Thread.current[Logster::Logger::LOGSTER_ENV] = nil
20
- end
21
- end
1
+ class SidekiqLogsterReporter
2
+ def call(ex, context = {})
3
+ # Pass context to Logster
4
+ fake_env = {}
5
+ context.each do |key, value|
6
+ Logster.add_to_env(fake_env, key, value)
7
+ end
8
+
9
+ text = "Job exception: #{ex}\n"
10
+ if ex.backtrace
11
+ Logster.add_to_env(fake_env, :backtrace, ex.backtrace)
12
+ end
13
+
14
+ Thread.current[Logster::Logger::LOGSTER_ENV] = fake_env
15
+ Logster.logger.error(text)
16
+ rescue => e
17
+ Logster.logger.fatal("Failed to log exception #{ex} #{hash}\nReason: #{e.class} #{e}\n#{e.backtrace.join("\n")}")
18
+ ensure
19
+ Thread.current[Logster::Logger::LOGSTER_ENV] = nil
20
+ end
21
+ end
@@ -1,54 +1,54 @@
1
- require 'logster/logger'
2
- require 'logster/message'
3
- require 'logster/configuration'
4
- require 'logster/web'
5
- require 'logster/ignore_pattern'
6
-
7
- if defined? Redis
8
- require 'logster/redis_store'
9
- else
10
- STDERR.puts "ERROR: Redis is not loaded, ensure redis gem is required before logster"
11
- exit
12
- end
13
-
14
- module Logster
15
- def self.logger=(logger)
16
- @logger = logger
17
- end
18
-
19
- def self.logger
20
- @logger
21
- end
22
-
23
- def self.store=(store)
24
- @store = store
25
- end
26
-
27
- def self.store
28
- @store
29
- end
30
-
31
- def self.config=(config)
32
- @config = config
33
- end
34
-
35
- def self.config
36
- @config ||= Configuration.new
37
- end
38
-
39
- def self.add_to_env(env, key, value)
40
- logster_env = Logster::Message.populate_from_env(env)
41
- logster_env[key] = value
42
- end
43
-
44
- def self.set_environments(envs)
45
- config.environments = envs
46
- end
47
- end
48
-
49
- # check logster/configuration.rb for config options
50
- # Logster.config.environments << :staging
51
-
52
- if defined?(::Rails) && ::Rails::VERSION::MAJOR.to_i >= 3
53
- require 'logster/rails/railtie'
54
- end
1
+ require 'logster/logger'
2
+ require 'logster/message'
3
+ require 'logster/configuration'
4
+ require 'logster/web'
5
+ require 'logster/ignore_pattern'
6
+
7
+ if defined? Redis
8
+ require 'logster/redis_store'
9
+ else
10
+ STDERR.puts "ERROR: Redis is not loaded, ensure redis gem is required before logster"
11
+ exit
12
+ end
13
+
14
+ module Logster
15
+ def self.logger=(logger)
16
+ @logger = logger
17
+ end
18
+
19
+ def self.logger
20
+ @logger
21
+ end
22
+
23
+ def self.store=(store)
24
+ @store = store
25
+ end
26
+
27
+ def self.store
28
+ @store
29
+ end
30
+
31
+ def self.config=(config)
32
+ @config = config
33
+ end
34
+
35
+ def self.config
36
+ @config ||= Configuration.new
37
+ end
38
+
39
+ def self.add_to_env(env, key, value)
40
+ logster_env = Logster::Message.populate_from_env(env)
41
+ logster_env[key] = value
42
+ end
43
+
44
+ def self.set_environments(envs)
45
+ config.environments = envs
46
+ end
47
+ end
48
+
49
+ # check logster/configuration.rb for config options
50
+ # Logster.config.environments << :staging
51
+
52
+ if defined?(::Rails) && ::Rails::VERSION::MAJOR.to_i >= 3
53
+ require 'logster/rails/railtie'
54
+ end
@@ -1,141 +1,141 @@
1
- module Logster
2
- class BaseStore
3
-
4
- attr_accessor :level, :max_retention, :skip_empty, :ignore
5
-
6
- def initialize
7
- @max_retention = 60 * 60 * 24 * 7
8
- @skip_empty = true
9
- end
10
-
11
- # Save a new message at the front of the latest list.
12
- def save(message)
13
- not_implemented
14
- end
15
-
16
- # Modify the saved message to the given one (identified by message.key) and bump it to the top of the latest list
17
- def replace_and_bump(message, save_env: true)
18
- not_implemented
19
- end
20
-
21
- # Check if another message with the same grouping_key is already stored.
22
- # Returns the similar message's message.key
23
- def similar_key(message)
24
- not_implemented
25
- end
26
-
27
- # The number of messages currently stored.
28
- def count
29
- not_implemented
30
- end
31
-
32
- # Delete all unprotected messages in the store.
33
- def clear
34
- not_implemented
35
- end
36
-
37
- # Delete all messages, including protected messages.
38
- def clear_all
39
- not_implemented
40
- end
41
-
42
- # Get a message by its message_key
43
- def get(message_key, load_env: true)
44
- not_implemented
45
- end
46
-
47
- # Get a group of messages by their message_keys
48
- def bulk_get(message_keys)
49
- not_implemented
50
- end
51
-
52
- # Get a message's env by its message_key
53
- def get_env(message_key)
54
- not_implemented
55
- end
56
-
57
- # Mark a message as protected; i.e. it is not deleted by the #clear method
58
- def protect(message_key)
59
- not_implemented
60
- end
61
-
62
- def delete(message_key)
63
- not_implemented
64
- end
65
-
66
- # Clear the protected mark for a message.
67
- def unprotect(message_key)
68
- not_implemented
69
- end
70
-
71
- # Solve a particular message, causing all old messages with matching version and backtrace
72
- # to be deleted (report should delete any solved messages when called)
73
- def solve(message_key)
74
- not_implemented
75
- end
76
-
77
- # Registers a rate limit on the given severities of logs
78
- def register_rate_limit(severities, limit, duration, &block)
79
- not_implemented
80
- end
81
-
82
- # Checks all the existing rate limiters to check if any has been exceeded
83
- def check_rate_limits(severity)
84
- not_implemented
85
- end
86
-
87
- def report(severity, progname, msg, opts = {})
88
- return if (!msg || (String === msg && msg.empty?)) && skip_empty
89
- return if level && severity < level
90
-
91
- message = Logster::Message.new(severity, progname, msg, opts[:timestamp], count: opts[:count])
92
-
93
- env = opts[:env] || {}
94
- backtrace = opts[:backtrace]
95
- if Hash === env && env[:backtrace]
96
- # Special - passing backtrace through env
97
- backtrace = env.delete(:backtrace)
98
- end
99
-
100
- message.populate_from_env(env)
101
-
102
- if backtrace
103
- if backtrace.respond_to? :join
104
- backtrace = backtrace.join("\n")
105
- end
106
- message.backtrace = backtrace
107
- else
108
- message.backtrace = caller.join("\n")
109
- end
110
-
111
- return if ignore && ignore.any? { |pattern| message =~ pattern }
112
-
113
- similar = nil
114
-
115
- if Logster.config.allow_grouping
116
- key = self.similar_key(message)
117
- similar = get(key, load_env: false) if key
118
- end
119
-
120
- if similar
121
- has_env = !similar.env.nil? && !similar.env.empty?
122
- if similar.count < Logster::MAX_GROUPING_LENGTH && !has_env
123
- similar.env = get_env(similar.key) || {}
124
- end
125
- save_env = similar.merge_similar_message(message)
126
-
127
- replace_and_bump(similar, save_env: save_env || has_env)
128
- similar
129
- else
130
- save message
131
- message
132
- end
133
- end
134
-
135
- private
136
-
137
- def not_implemented
138
- raise "Not Implemented"
139
- end
140
- end
141
- end
1
+ module Logster
2
+ class BaseStore
3
+
4
+ attr_accessor :level, :max_retention, :skip_empty, :ignore
5
+
6
+ def initialize
7
+ @max_retention = 60 * 60 * 24 * 7
8
+ @skip_empty = true
9
+ end
10
+
11
+ # Save a new message at the front of the latest list.
12
+ def save(message)
13
+ not_implemented
14
+ end
15
+
16
+ # Modify the saved message to the given one (identified by message.key) and bump it to the top of the latest list
17
+ def replace_and_bump(message, save_env: true)
18
+ not_implemented
19
+ end
20
+
21
+ # Check if another message with the same grouping_key is already stored.
22
+ # Returns the similar message's message.key
23
+ def similar_key(message)
24
+ not_implemented
25
+ end
26
+
27
+ # The number of messages currently stored.
28
+ def count
29
+ not_implemented
30
+ end
31
+
32
+ # Delete all unprotected messages in the store.
33
+ def clear
34
+ not_implemented
35
+ end
36
+
37
+ # Delete all messages, including protected messages.
38
+ def clear_all
39
+ not_implemented
40
+ end
41
+
42
+ # Get a message by its message_key
43
+ def get(message_key, load_env: true)
44
+ not_implemented
45
+ end
46
+
47
+ # Get a group of messages by their message_keys
48
+ def bulk_get(message_keys)
49
+ not_implemented
50
+ end
51
+
52
+ # Get a message's env by its message_key
53
+ def get_env(message_key)
54
+ not_implemented
55
+ end
56
+
57
+ # Mark a message as protected; i.e. it is not deleted by the #clear method
58
+ def protect(message_key)
59
+ not_implemented
60
+ end
61
+
62
+ def delete(message_key)
63
+ not_implemented
64
+ end
65
+
66
+ # Clear the protected mark for a message.
67
+ def unprotect(message_key)
68
+ not_implemented
69
+ end
70
+
71
+ # Solve a particular message, causing all old messages with matching version and backtrace
72
+ # to be deleted (report should delete any solved messages when called)
73
+ def solve(message_key)
74
+ not_implemented
75
+ end
76
+
77
+ # Registers a rate limit on the given severities of logs
78
+ def register_rate_limit(severities, limit, duration, &block)
79
+ not_implemented
80
+ end
81
+
82
+ # Checks all the existing rate limiters to check if any has been exceeded
83
+ def check_rate_limits(severity)
84
+ not_implemented
85
+ end
86
+
87
+ def report(severity, progname, msg, opts = {})
88
+ return if (!msg || (String === msg && msg.empty?)) && skip_empty
89
+ return if level && severity < level
90
+
91
+ message = Logster::Message.new(severity, progname, msg, opts[:timestamp], count: opts[:count])
92
+
93
+ env = opts[:env] || {}
94
+ backtrace = opts[:backtrace]
95
+ if Hash === env && env[:backtrace]
96
+ # Special - passing backtrace through env
97
+ backtrace = env.delete(:backtrace)
98
+ end
99
+
100
+ message.populate_from_env(env)
101
+
102
+ if backtrace
103
+ if backtrace.respond_to? :join
104
+ backtrace = backtrace.join("\n")
105
+ end
106
+ message.backtrace = backtrace
107
+ else
108
+ message.backtrace = caller.join("\n")
109
+ end
110
+
111
+ return if ignore && ignore.any? { |pattern| message =~ pattern }
112
+
113
+ similar = nil
114
+
115
+ if Logster.config.allow_grouping
116
+ key = self.similar_key(message)
117
+ similar = get(key, load_env: false) if key
118
+ end
119
+
120
+ if similar
121
+ has_env = !similar.env.nil? && !similar.env.empty?
122
+ if similar.count < Logster::MAX_GROUPING_LENGTH && !has_env
123
+ similar.env = get_env(similar.key) || {}
124
+ end
125
+ save_env = similar.merge_similar_message(message)
126
+
127
+ replace_and_bump(similar, save_env: save_env || has_env)
128
+ similar
129
+ else
130
+ save message
131
+ message
132
+ end
133
+ end
134
+
135
+ private
136
+
137
+ def not_implemented
138
+ raise "Not Implemented"
139
+ end
140
+ end
141
+ end