onlylogs 0.8.0 → 0.9.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0e6b4ee2fde339a248ff9e15557c8bb8f0ea525b3807aa09b157e537057c0c7a
4
- data.tar.gz: 208543eb460dc3f7c302fac4d4bd3277c710e402346f759c7e66c1b2dfc7049b
3
+ metadata.gz: f166264d89c5d2273751e3377ef236168da610b1d37d5ddf02d33959f2fe318d
4
+ data.tar.gz: a612d6738ee600171cd21a78b403d1abef06fdf5df893ebcc8c3401b092f6a51
5
5
  SHA512:
6
- metadata.gz: 4b47a580f758cacca9c34b1de0ebe445ff4db5df1e45f6e515cd80b1dd866d3dbbb39d7aea7862b94ee46e5d18cd39797fbadcb202e59745bcb94fb0a62da2b7
7
- data.tar.gz: 8956f328a31a63cbf07a180a51ffa612c516f51ae37523bba49f6a41557a14ae35a83d91bc1bcc05b465bedd6cbc61cbffb8a402822a27b17d534668acd65211
6
+ metadata.gz: 6c2d38d16486ea48cd8e6c695e1b9234dbe8e300f45342afa163adfef2e532cdf1cf0cdecdca411c9a13a80c6c4f32aa5c33a82dfc9137c2da35f72cffa0f2c6
7
+ data.tar.gz: d4b8b016e5c089712e288d6533b613571f5edee524b2784a3aff80b4d8701913aabb169f72cdedb4220c01a86f3be33d0c52eedc644538db1a3fe3e259e947c9
data/README.md CHANGED
@@ -272,6 +272,22 @@ Onlylogs.configure do |config|
272
272
  end
273
273
  ```
274
274
 
275
+ #### Bounding How Long a Viewer Search Can Run
276
+
277
+ Searches started from the log viewer stop after `search_timeout` seconds, keeping whatever they
278
+ found and reporting that they did not reach the end of the file. The default is 120 seconds:
279
+
280
+ ```ruby
281
+ # config/initializers/onlylogs.rb
282
+ Onlylogs.configure do |config|
283
+ config.search_timeout = 300
284
+
285
+ # Or remove the ceiling entirely (a search then holds a CPU until it reaches
286
+ # the end of the file, however large it is)
287
+ config.search_timeout = nil
288
+ end
289
+ ```
290
+
275
291
  ### Filtering Log Lines with a Denylist
276
292
 
277
293
  The `Onlylogs::Formatter` supports a denylist: an array of regular expressions that prevents matching lines from being logged. This is useful for filtering out noisy or irrelevant entries like health checks or asset requests.
@@ -173,7 +173,8 @@ module Onlylogs
173
173
 
174
174
  if filter.present?
175
175
  # Use grep for filtered search
176
- @log_file.grep(filter, regexp_mode: regexp_mode, start_position: start_position, end_position: end_position) do |result|
176
+ @log_file.grep(filter, regexp_mode: regexp_mode, start_position: start_position,
177
+ end_position: end_position, timeout: Onlylogs.search_timeout) do |result|
177
178
  break if @batch_sender.nil? || @log_watcher_running == false
178
179
 
179
180
  # Skip first line if start_position > 0 (line is cut off at byte boundary)
@@ -234,6 +235,11 @@ module Onlylogs
234
235
  else
235
236
  transmit({action: "finish", content: "Search finished."})
236
237
  end
238
+ rescue Onlylogs::Grep::TimeoutError
239
+ @batch_sender&.stop
240
+ transmit({action: "finish",
241
+ content: "Search stopped after #{Onlylogs.search_timeout} seconds and did not reach " \
242
+ "the end of the file. Narrow the range or the filter and search again."})
237
243
  ensure
238
244
  # Always cleanup even if interrupted or error occurs
239
245
  @batch_sender&.stop
@@ -29,7 +29,11 @@ module Onlylogs
29
29
  ->(line) { [nil, line] }
30
30
  end
31
31
 
32
- begin
32
+ matches = 0
33
+
34
+ ActiveSupport::Notifications.instrument("search.onlylogs", file_path: file_path,
35
+ query: pattern, regexp: regexp_mode, start_position: start_position,
36
+ end_position: end_position, max_matches: max_matches) do |payload|
33
37
  each_output_line(command_args, timeout: timeout) do |line|
34
38
  byte_offset, content = parse_line.call(line.chomp)
35
39
 
@@ -37,6 +41,7 @@ module Onlylogs
37
41
  content = String.new(content, encoding: Encoding::UTF_8).scrub
38
42
 
39
43
  result = {byte_offset: byte_offset, content: content}
44
+ matches += 1
40
45
 
41
46
  if block_given?
42
47
  yield result
@@ -44,7 +49,12 @@ module Onlylogs
44
49
  results << result
45
50
  end
46
51
  end
52
+ rescue TimeoutError
53
+ payload[:timed_out] = true
54
+ raise
47
55
  ensure
56
+ payload[:matches] = matches
57
+ payload[:timed_out] ||= false
48
58
  drop_page_cache(file_path)
49
59
  end
50
60
 
@@ -4,7 +4,14 @@ module Onlylogs
4
4
  class Configuration
5
5
  attr_accessor :log_file_patterns, :default_log_file_path, :basic_auth_user, :basic_auth_password,
6
6
  :parent_controller, :disable_basic_authentication, :ripgrep_enabled, :editor,
7
- :max_line_matches
7
+ :max_line_matches, :search_timeout
8
+
9
+ # Seconds a viewer search may run before it is stopped. Bounded by default:
10
+ # a search holds a CPU for as long as it runs, and an unbounded one over a
11
+ # multi-GB file can starve everything else the host is doing. Generous
12
+ # enough for a full scan of a large file - set it to nil to remove the
13
+ # ceiling entirely.
14
+ DEFAULT_SEARCH_TIMEOUT = 120
8
15
 
9
16
  def initialize
10
17
  @log_file_patterns = default_log_file_patterns
@@ -16,6 +23,7 @@ module Onlylogs
16
23
  @ripgrep_enabled = default_ripgrep_enabled
17
24
  @editor = nil
18
25
  @max_line_matches = 100000
26
+ @search_timeout = DEFAULT_SEARCH_TIMEOUT
19
27
  end
20
28
 
21
29
  def configure
@@ -147,6 +155,10 @@ module Onlylogs
147
155
  configuration.max_line_matches
148
156
  end
149
157
 
158
+ def self.search_timeout
159
+ configuration.search_timeout
160
+ end
161
+
150
162
  def self.allowed_file_patterns_for(pattern)
151
163
  absolute_pattern = ::File.expand_path(pattern.to_s)
152
164
  if glob_pattern?(absolute_pattern)
@@ -1,3 +1,3 @@
1
1
  module Onlylogs
2
- VERSION = "0.8.0"
2
+ VERSION = "0.9.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: onlylogs
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alessandro Rodi