onlylogs 0.12.0 → 0.13.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: fae4a8382ece2fa6c8e6c302c0aedda949910921850215d9bcc7f3e86a628fec
4
- data.tar.gz: c94139e2bc001f2a2bbe7488aabd5394858442105159fb790d42c86d688c3a75
3
+ metadata.gz: df2635aae242c5b3d3d1881c3dcb4c9297662200134c403b6f722036ef8f2357
4
+ data.tar.gz: f6faaccddcbd4042a0d6cb4cee8f087ce0ff7e9c75e66f0e403ee5c7de2edbc3
5
5
  SHA512:
6
- metadata.gz: 45f50c071249d629b837bd02f1e785974da7698dcedd6ecd65a55093f853959f24a01290d4b6e1f52d199d09604bf114dcf591daf9ebb8d2d8da34705211a8af
7
- data.tar.gz: cae201c83159e1b5476979c19b98fed07185eb221e600275a780ac4855f4f4cdf76a81805769c151edcf9a5551ce4eb93b62f5adfbfdde5d73f719bbee11b56c
6
+ metadata.gz: e649a51a9841c162ad4c418eea5047462505054a040f5314fec37f171109fb39bf4198e12d107b04f52d77cc19d84ab873e5435ca28bb77c1b4aad17677d02b6
7
+ data.tar.gz: 4e6b8ab9a92d4317c04de55e4f560642e77baa8d8b73c7f583fdb181383eed1965c6e731cbb871ede1aa2ce291a0f3a4dd07759eada1e0d4fc1f5fb069ab479d
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "sqlite_shards"
4
+
3
5
  module Onlylogs
4
6
  class QueriesController < ViewerController
5
7
  before_action :set_log_file
@@ -12,22 +12,27 @@ module Onlylogs
12
12
  # is deliberately not a number, because only the caller knows how long it
13
13
  # can afford to hold the thread it runs on. Anything serving a request
14
14
  # should pass one.
15
+ # +context+ asks for that many lines before and after each match, yielded with
16
+ # <tt>context: true</tt>. It needs ripgrep: plain grep is run without byte
17
+ # offsets, so its context lines could not be told apart from matches, and
18
+ # +context+ is ignored there. Context never reaches outside the byte window.
15
19
  def self.grep(pattern, file_path, start_position: 0, end_position: nil, regexp_mode: false,
16
- case_sensitive: true, max_matches: Onlylogs.max_line_matches, timeout: nil, &block)
20
+ case_sensitive: true, max_matches: Onlylogs.max_line_matches, context: 0, timeout: nil, &block)
21
+ context = 0 unless Onlylogs.ripgrep_enabled?
17
22
  command_args = search_command(pattern, file_path, start_position: start_position,
18
23
  end_position: end_position, regexp_mode: regexp_mode, case_sensitive: case_sensitive,
19
- max_matches: max_matches)
24
+ max_matches: max_matches, context: context)
20
25
 
21
26
  results = []
22
27
 
23
- # Set up parsing logic based on whether ripgrep includes byte offsets
28
+ # ripgrep prints "offset:line" for a match and "offset-line" for context
24
29
  parse_line = if Onlylogs.ripgrep_enabled?
25
30
  ->(line) {
26
- parts = line.split(":", 2)
27
- [parts[0].to_i + start_position, parts[1] || ""]
31
+ offset, separator, content = line.partition(/[:-]/)
32
+ [offset.to_i + start_position, content, separator == "-"]
28
33
  }
29
34
  else
30
- ->(line) { [nil, line] }
35
+ ->(line) { [nil, line, false] }
31
36
  end
32
37
 
33
38
  matches = 0
@@ -36,13 +41,17 @@ module Onlylogs
36
41
  query: pattern, regexp: regexp_mode, case_sensitive: case_sensitive, start_position: start_position,
37
42
  end_position: end_position, max_matches: max_matches) do |payload|
38
43
  each_output_line(command_args, timeout: timeout) do |line|
39
- byte_offset, content = parse_line.call(line.chomp)
44
+ line = line.chomp
45
+ next if context.positive? && line == GROUP_SEPARATOR
46
+
47
+ byte_offset, content, context_line = parse_line.call(line)
40
48
 
41
49
  # Use String.new to create a copy and prevent memory retention from IO buffers
42
50
  content = String.new(content, encoding: Encoding::UTF_8).scrub
43
51
 
44
52
  result = {byte_offset: byte_offset, content: content}
45
- matches += 1
53
+ result[:context] = true if context_line
54
+ matches += 1 unless context_line
46
55
 
47
56
  if block_given?
48
57
  yield result
@@ -62,16 +71,19 @@ module Onlylogs
62
71
  block_given? ? nil : results
63
72
  end
64
73
 
74
+ GROUP_SEPARATOR = "--"
75
+
65
76
  # The scripts run under LC_ALL=C. ripgrep folds case over Unicode anyway,
66
77
  # grep then folds ASCII only: "error" finds "ERROR" with both engines, but
67
78
  # "über" finds "Über" with ripgrep only.
68
79
  def self.search_command(pattern, file_path, start_position: 0, end_position: nil, regexp_mode: false,
69
- case_sensitive: true, max_matches: Onlylogs.max_line_matches)
80
+ case_sensitive: true, max_matches: Onlylogs.max_line_matches, context: 0)
70
81
  script_name = Onlylogs.ripgrep_enabled? ? "super_ripgrep" : "super_grep"
71
82
  super_grep_path = ::File.expand_path("../../../bin/#{script_name}", __dir__)
72
83
 
73
84
  command_args = [super_grep_path]
74
85
  command_args += ["--max-matches", max_matches.to_s] if max_matches.present?
86
+ command_args += ["--context", context.to_s] if context.positive?
75
87
  command_args << "--regexp" if regexp_mode
76
88
  command_args << "--case-insensitive" unless case_sensitive
77
89
 
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "sqlite_shards"
4
+
3
5
  module Onlylogs
4
6
  # Saved queries live in a database kept in each log directory, shared by all log files in it:
5
7
  # see File#with_database.
data/bin/super_ripgrep CHANGED
@@ -12,6 +12,10 @@ while [[ $# -gt 0 ]]; do
12
12
  max_matches="$2"
13
13
  shift 2
14
14
  ;;
15
+ --context)
16
+ context="$2"
17
+ shift 2
18
+ ;;
15
19
  --start-position)
16
20
  start_position="$2"
17
21
  shift 2
@@ -67,6 +71,11 @@ query_regex="${query_regex//$placeholder/$actual_color_regex}"
67
71
  rg_cmd="rg --color=never --no-filename --byte-offset --no-mmap"
68
72
  [ -n "$max_matches" ] && rg_cmd="$rg_cmd --max-count=$max_matches"
69
73
  [ "$case_insensitive" = true ] && rg_cmd="$rg_cmd --ignore-case"
74
+ # Context lines come out as "offset-line" instead of "offset:line", with "--" between groups
75
+ case "$context" in
76
+ "" | *[!0-9]*) ;;
77
+ *) rg_cmd="$rg_cmd --context=$context" ;;
78
+ esac
70
79
 
71
80
  # Handle byte range if specified
72
81
  if [ -n "$start_position" ] || [ -n "$end_position" ]; then
@@ -8,7 +8,16 @@ module Onlylogs
8
8
  class Engine < ::Rails::Engine
9
9
  isolate_namespace Onlylogs
10
10
 
11
+ # Load the viewer's code on first use instead of at boot, so apps that only use the
12
+ # loggers don't need the frameworks it builds on (e.g. Action Cable).
13
+ paths.all_paths.select(&:eager_load?).each do |path|
14
+ path.skip_eager_load!
15
+ path.autoload!
16
+ end
17
+
11
18
  initializer "onlylogs.assets" do |app|
19
+ next unless app.config.respond_to?(:assets)
20
+
12
21
  %w[images javascript stylesheets builds fonts].each do |subdir|
13
22
  path = root.join("app/assets", subdir)
14
23
  app.config.assets.paths << path if path.exist?
@@ -1,3 +1,3 @@
1
1
  module Onlylogs
2
- VERSION = "0.12.0"
2
+ VERSION = "0.13.0"
3
3
  end
data/lib/onlylogs.rb CHANGED
@@ -1,4 +1,3 @@
1
- require "sqlite_shards"
2
1
  require "onlylogs/version"
3
2
  require "onlylogs/configuration"
4
3
  require "onlylogs/engine"
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.12.0
4
+ version: 0.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alessandro Rodi
@@ -94,7 +94,6 @@ files:
94
94
  - app/javascript/onlylogs/controllers/queries_controller.js
95
95
  - app/javascript/onlylogs/controllers/range_slider_controller.js
96
96
  - app/javascript/onlylogs/controllers/text_selection_controller.js
97
- - app/jobs/onlylogs/application_job.rb
98
97
  - app/models/onlylogs/ansi_color_parser.rb
99
98
  - app/models/onlylogs/batch_sender.rb
100
99
  - app/models/onlylogs/file.rb
@@ -1,4 +0,0 @@
1
- module Onlylogs
2
- class ApplicationJob < ActiveJob::Base
3
- end
4
- end