onlylogs 0.3.1 → 0.4.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: 46e2bc76a652e2bc255ff847d0516783dace7aedead98ee7e4a2bf6d9cbf7fe1
4
- data.tar.gz: 95cf2efa8b9e94a9a36a5188968e40846e010eedaab5e300275a61028d7a11f0
3
+ metadata.gz: 37909543bef9f932a762a08b53c0dfbebe9094f41e96d0de8740e1e1b4b66614
4
+ data.tar.gz: 1abced159b2385cd445b05196a6ac47801aeeaac96c8062729251aaf778733bd
5
5
  SHA512:
6
- metadata.gz: 614d6037f2142d40ee178cc6b86c100105554b78607642e1e18e5374c15524445ff11119321b5dc79b901c54a472287d37daebfd625e3838216b59077b9d75d4
7
- data.tar.gz: 9762dd06e5fa36068288651de814103a949e4989e10c7dd6352258bea056bb63b1605d4e05d40f549747bd287304210a8f8836de0086b32b9448012279b7ddb5
6
+ metadata.gz: 4def45bcdb6d9c301f3cb2d65de39f2e27247a4ae5fd7835325e8f80781279ce7ed5ac280fea95cf7d61af2d9713fae008485f9e702f4ab747a151712340bf56
7
+ data.tar.gz: 74e0fa68229359024780f850dd2df95ab1d930b6a949ec85b63f20d7e8ff1253e79da81f384bb6057d588b10d67764dbaa7761db1212051c8e69c2841a8dce89
data/README.md CHANGED
@@ -174,7 +174,7 @@ You can configure which files onlylogs is allowed to access by creating a config
174
174
  ```ruby
175
175
  # config/initializers/onlylogs.rb
176
176
  Onlylogs.configure do |config|
177
- config.allowed_files = [
177
+ config.log_file_patterns = [
178
178
  # Default Rails log files
179
179
  Rails.root.join("log/development.log"),
180
180
  Rails.root.join("log/production.log"),
@@ -206,7 +206,7 @@ Onlylogs supports glob patterns to allow multiple files at once:
206
206
  ```ruby
207
207
  # config/initializers/onlylogs.rb
208
208
  Onlylogs.configure do |config|
209
- config.allowed_files = [
209
+ config.log_file_patterns = [
210
210
  # Allow all .log files in the log directory
211
211
  Rails.root.join("log/*.log"),
212
212
 
@@ -18,9 +18,9 @@ module Onlylogs
18
18
  file_path = Onlylogs::SecureFilePath.decrypt(encrypted_file_path)
19
19
 
20
20
  # Verify the decrypted path is still allowed
21
- unless Onlylogs.allowed_file_path?(file_path)
21
+ unless Onlylogs.file_path_permitted?(file_path)
22
22
  Rails.logger.error "Onlylogs: Attempted to access non-allowed file: #{file_path}"
23
- transmit({ action: "error", content: "Access denied" })
23
+ transmit({action: "error", content: "Access denied"})
24
24
  return
25
25
  end
26
26
  else
@@ -29,13 +29,13 @@ module Onlylogs
29
29
  end
30
30
  rescue Onlylogs::SecureFilePath::SecurityError => e
31
31
  Rails.logger.error "Onlylogs: Security violation - #{e.message}"
32
- transmit({ action: "error", content: "Access denied" })
32
+ transmit({action: "error", content: "Access denied"})
33
33
  return
34
34
  end
35
35
 
36
36
  # Check if the file is a text file
37
37
  unless Onlylogs::File.text_file?(file_path)
38
- transmit({ action: "error", content: "Cannot read file: File is not a text file" })
38
+ transmit({action: "error", content: "Cannot read file: File is not a text file"})
39
39
  return
40
40
  end
41
41
 
@@ -57,7 +57,7 @@ module Onlylogs
57
57
 
58
58
  def stop_watcher
59
59
  cleanup_existing_operations
60
- transmit({ action: "finish", content: "Search stopped." })
60
+ transmit({action: "finish", content: "Search stopped."})
61
61
  end
62
62
 
63
63
  def unsubscribed
@@ -82,11 +82,11 @@ module Onlylogs
82
82
  @filter = filter
83
83
  @regexp_mode = regexp_mode
84
84
 
85
- transmit({ action: "message", content: "Reading file. Please wait..." })
85
+ transmit({action: "message", content: "Reading file. Please wait..."})
86
86
 
87
87
  @log_file = Onlylogs::File.new(file_path, last_position: cursor_position)
88
88
 
89
- transmit({ action: "message", content: "" })
89
+ transmit({action: "message", content: ""})
90
90
 
91
91
  @log_watcher_thread = Thread.new do
92
92
  Rails.logger.silence(Logger::ERROR) do
@@ -107,13 +107,13 @@ module Onlylogs
107
107
 
108
108
  if lines_to_send.any?
109
109
  transmit({
110
- action: "append_logs",
111
- lines: lines_to_send
112
- })
110
+ action: "append_logs",
111
+ lines: lines_to_send
112
+ })
113
113
  end
114
114
  end
115
115
  end
116
- rescue StandardError => e
116
+ rescue => e
117
117
  Rails.logger.error "Log watcher error: #{e.message}"
118
118
  Rails.logger.error e.backtrace.join("\n")
119
119
  ensure
@@ -147,7 +147,7 @@ module Onlylogs
147
147
  @log_watcher_running = true
148
148
  @log_file = Onlylogs::File.new(file_path, last_position: 0)
149
149
 
150
- transmit({ action: "message", content: "Searching..." })
150
+ transmit({action: "message", content: "Searching..."})
151
151
 
152
152
  @batch_sender = BatchSender.new(self)
153
153
  @batch_sender.start
@@ -157,7 +157,7 @@ module Onlylogs
157
157
  begin
158
158
  Rails.logger.silence(Logger::ERROR) do
159
159
  @log_file.grep(filter, regexp_mode: regexp_mode, start_position: start_position, end_position: end_position) do |log_line|
160
- return if @batch_sender.nil?
160
+ break if @batch_sender.nil?
161
161
 
162
162
  # Add to batch buffer (sender thread will handle sending)
163
163
  @batch_sender.add_line(render_log_line(log_line))
@@ -171,9 +171,9 @@ module Onlylogs
171
171
 
172
172
  # Send completion message
173
173
  if line_count >= Onlylogs.max_line_matches
174
- transmit({ action: "finish", content: "Search finished. Search results limit reached." })
174
+ transmit({action: "finish", content: "Search finished. Search results limit reached."})
175
175
  else
176
- transmit({ action: "finish", content: "Search finished." })
176
+ transmit({action: "finish", content: "Search finished."})
177
177
  end
178
178
  ensure
179
179
  # Always cleanup even if interrupted or error occurs
@@ -1,5 +1,5 @@
1
1
  module Onlylogs
2
- class ApplicationController < (Onlylogs.parent_controller&.constantize || ActionController::Base)
2
+ class ApplicationController < Onlylogs.parent_controller&.constantize || ActionController::Base
3
3
  before_action :authenticate_onlylogs_user!
4
4
 
5
5
  private
@@ -5,8 +5,8 @@ module Onlylogs
5
5
  def index
6
6
  @max_lines = (params[:max_lines] || 100).to_i
7
7
 
8
- # Get the file path from params or use default
9
- @log_file_path = params[:log_file_path] || default_log_file_path
8
+ @available_log_files = Onlylogs.available_log_files
9
+ @log_file_path = selected_log_file_path
10
10
 
11
11
  @filter = params[:filter]
12
12
  @autoscroll = params[:autoscroll] != "false"
@@ -15,9 +15,24 @@ module Onlylogs
15
15
 
16
16
  private
17
17
 
18
+ def selected_log_file_path
19
+ encrypted_path = params[:log_file_path]
20
+ return default_log_file_path if encrypted_path.blank?
21
+
22
+ decrypted_path = Onlylogs::SecureFilePath.decrypt(encrypted_path)
23
+ if Onlylogs.file_path_permitted?(decrypted_path)
24
+ decrypted_path
25
+ else
26
+ raise SecurityError, "File path not allowed"
27
+ end
28
+ end
29
+
18
30
  def default_log_file_path
19
31
  # "/Users/alessandrorodi/RenuoWorkspace/onlylogs/test/fixtures/files/very_big.log"
20
- Onlylogs.default_log_file_path
32
+ configured_default = Onlylogs.default_log_file_path
33
+ return configured_default if Onlylogs.file_path_permitted?(configured_default) && ::File.exist?(configured_default)
34
+
35
+ @available_log_files.first&.to_s || configured_default
21
36
  end
22
37
  end
23
38
  end
@@ -17,25 +17,25 @@ module Onlylogs
17
17
  }.freeze
18
18
 
19
19
  # Pre-compiled regex for better performance
20
- ANSI_REGEX = /\x1b\[(\d+)m/.freeze
20
+ ANSI_REGEX = /\x1b\[(\d+)m/
21
21
 
22
22
  # Pre-built HTML templates to avoid string interpolation (frozen for better performance)
23
23
  HTML_TEMPLATES = {
24
- "1" => '<span class="fw-bold">'.freeze,
25
- "30" => '<span class="log-black">'.freeze,
26
- "31" => '<span class="log-red">'.freeze,
27
- "32" => '<span class="log-green">'.freeze,
28
- "33" => '<span class="log-yellow">'.freeze,
29
- "34" => '<span class="log-blue">'.freeze,
30
- "35" => '<span class="log-magenta">'.freeze,
31
- "36" => '<span class="log-cyan">'.freeze,
32
- "37" => '<span class="log-white">'.freeze,
33
- "39" => '<span class="">'.freeze,
34
- "0" => "".freeze # Reset (no color)
24
+ "1" => '<span class="fw-bold">',
25
+ "30" => '<span class="log-black">',
26
+ "31" => '<span class="log-red">',
27
+ "32" => '<span class="log-green">',
28
+ "33" => '<span class="log-yellow">',
29
+ "34" => '<span class="log-blue">',
30
+ "35" => '<span class="log-magenta">',
31
+ "36" => '<span class="log-cyan">',
32
+ "37" => '<span class="log-white">',
33
+ "39" => '<span class="">',
34
+ "0" => "" # Reset (no color)
35
35
  }.freeze
36
36
 
37
37
  # Pre-built closing span (frozen for better performance)
38
- CLOSING_SPAN = "</span>".freeze
38
+ CLOSING_SPAN = "</span>"
39
39
 
40
40
  def self.parse(string)
41
41
  return string if string.blank?
@@ -6,29 +6,29 @@ require "uri"
6
6
  module Onlylogs
7
7
  class FilePathParser
8
8
  KNOWN_EDITORS = [
9
- { symbols: [ :atom ], sniff: /atom/i, url: "atom://core/open/file?filename=%{file}&line=%{line}" },
10
- { symbols: [ :emacs, :emacsclient ], sniff: /emacs/i, url: "emacs://open?url=file://%{file}&line=%{line}" },
11
- { symbols: [ :idea ], sniff: /idea/i, url: "idea://open?file=%{file}&line=%{line}" },
12
- { symbols: [ :macvim, :mvim, :vim ], sniff: /vim/i, url: "mvim://open?url=file://%{file_unencoded}&line=%{line}" },
13
- { symbols: [ :rubymine, :mine ], sniff: /mine/i, url: "x-mine://open?file=%{file}&line=%{line}" },
14
- { symbols: [ :sublime, :subl, :st ], sniff: /subl/i, url: "subl://open?url=file://%{file}&line=%{line}" },
15
- { symbols: [ :textmate, :txmt, :tm, :mate ], sniff: /mate/i, url: "txmt://open?url=file://%{file}&line=%{line}" },
16
- { symbols: [ :vscode, :code ], sniff: /code/i, url: "vscode://file/%{file}:%{line}" },
17
- { symbols: [ :vscodium, :codium ], sniff: /codium/i, url: "vscodium://file/%{file}:%{line}" }
9
+ {symbols: [:atom], sniff: /atom/i, url: "atom://core/open/file?filename=%{file}&line=%{line}"},
10
+ {symbols: [:emacs, :emacsclient], sniff: /emacs/i, url: "emacs://open?url=file://%{file}&line=%{line}"},
11
+ {symbols: [:idea], sniff: /idea/i, url: "idea://open?file=%{file}&line=%{line}"},
12
+ {symbols: [:macvim, :mvim, :vim], sniff: /vim/i, url: "mvim://open?url=file://%{file_unencoded}&line=%{line}"},
13
+ {symbols: [:rubymine, :mine], sniff: /mine/i, url: "x-mine://open?file=%{file}&line=%{line}"},
14
+ {symbols: [:sublime, :subl, :st], sniff: /subl/i, url: "subl://open?url=file://%{file}&line=%{line}"},
15
+ {symbols: [:textmate, :txmt, :tm, :mate], sniff: /mate/i, url: "txmt://open?url=file://%{file}&line=%{line}"},
16
+ {symbols: [:vscode, :code], sniff: /code/i, url: "vscode://file/%{file}:%{line}"},
17
+ {symbols: [:vscodium, :codium], sniff: /codium/i, url: "vscodium://file/%{file}:%{line}"}
18
18
  ].freeze
19
19
 
20
20
  # Pre-compiled regex for better performance
21
21
  FILE_PATH_PATTERN = %r{
22
22
  (?<![a-zA-Z0-9_/]) # Negative lookbehind - not preceded by word chars or /
23
23
  (?:\./)? # Optional relative path indicator
24
- (?:/[a-zA-Z0-9_\-\.\s]+)+ # File path with allowed characters
24
+ (?:/[a-zA-Z0-9_\-.\s]+)+ # File path with allowed characters
25
25
  (?:\.rb|\.js|\.ts|\.tsx|\.jsx|\.py|\.java|\.go|\.rs|\.php|\.html|\.erb|\.haml|\.slim|\.css|\.scss|\.sass|\.less|\.xml|\.json|\.yml|\.yaml|\.md|\.txt|\.log) # File extensions
26
26
  (?::\d+)? # Optional line number
27
27
  (?![a-zA-Z0-9_/]) # Negative lookahead - not followed by word chars or /
28
- }x.freeze
28
+ }x
29
29
 
30
30
  # Pre-built HTML template to avoid string interpolation
31
- HTML_TEMPLATE = '<a href="%{url}" class="file-link">%{match}</a>'.freeze
31
+ HTML_TEMPLATE = '<a href="%{url}" class="file-link">%{match}</a>'
32
32
 
33
33
  def self.parse(string)
34
34
  return string if string.blank?
@@ -40,7 +40,7 @@ module Onlylogs
40
40
  file_path = extract_file_path(match)
41
41
  line_number = extract_line_number(match)
42
42
  url = cached_editor_instance.url(file_path, line_number)
43
- HTML_TEMPLATE % { url: url, match: match }
43
+ HTML_TEMPLATE % {url: url, match: match}
44
44
  end
45
45
  end
46
46
 
@@ -73,7 +73,6 @@ module Onlylogs
73
73
  end
74
74
  end
75
75
 
76
-
77
76
  def self.editor_from_symbol(symbol)
78
77
  KNOWN_EDITORS.each do |preset|
79
78
  return for_formatting_string(preset[:url]) if preset[:symbols].include?(symbol)
@@ -86,14 +85,14 @@ module Onlylogs
86
85
  end
87
86
 
88
87
  def url(raw_path, line)
89
- if virtual_path && raw_path.start_with?(virtual_path)
88
+ file = if virtual_path && raw_path.start_with?(virtual_path)
90
89
  if host_path
91
- file = raw_path.sub(%r{\A#{virtual_path}}, host_path)
90
+ raw_path.sub(%r{\A#{virtual_path}}, host_path)
92
91
  else
93
- file = raw_path.sub(%r{\A#{virtual_path}/}, "")
92
+ raw_path.sub(%r{\A#{virtual_path}/}, "")
94
93
  end
95
94
  else
96
- file = raw_path
95
+ raw_path
97
96
  end
98
97
 
99
98
  url_proc.call(file, line)
@@ -115,15 +114,19 @@ module Onlylogs
115
114
  @host_path ||= ENV["ONLYLOGS_HOST_PATH"]
116
115
  end
117
116
 
118
- def self.extract_file_path(match)
119
- # Remove line number if present
120
- match.sub(/:\d+$/, "")
121
- end
117
+ class << self
118
+ private
122
119
 
123
- def self.extract_line_number(match)
124
- # Extract line number or default to 1
125
- line_match = match.match(/:(\d+)$/)
126
- line_match ? line_match[1].to_i : 1
120
+ def extract_file_path(match)
121
+ # Remove line number if present
122
+ match.sub(/:\d+$/, "")
123
+ end
124
+
125
+ def extract_line_number(match)
126
+ # Extract line number or default to 1
127
+ line_match = match.match(/:(\d+)$/)
128
+ line_match ? line_match[1].to_i : 1
129
+ end
127
130
  end
128
131
  end
129
132
  end
@@ -5,8 +5,8 @@ module Onlylogs
5
5
  script_name = Onlylogs.ripgrep_enabled? ? "super_ripgrep" : "super_grep"
6
6
  super_grep_path = ::File.expand_path("../../../bin/#{script_name}", __dir__)
7
7
 
8
- command_args = [ super_grep_path ]
9
- command_args += [ "--max-matches", Onlylogs.max_line_matches.to_s ] if Onlylogs.max_line_matches.present?
8
+ command_args = [super_grep_path]
9
+ command_args += ["--max-matches", Onlylogs.max_line_matches.to_s] if Onlylogs.max_line_matches.present?
10
10
  command_args << "--regexp" if regexp_mode
11
11
 
12
12
  # Add byte range parameters if specified
@@ -15,7 +15,7 @@ module Onlylogs
15
15
  command_args << "--end-position" << end_position.to_s if end_position
16
16
  end
17
17
 
18
- command_args += [ pattern, file_path ]
18
+ command_args += [pattern, file_path]
19
19
 
20
20
  results = []
21
21
 
@@ -22,9 +22,7 @@ module Onlylogs
22
22
  raise SecurityError, "Invalid encrypted file path"
23
23
  end
24
24
 
25
- private
26
-
27
- def self.encryption_key
25
+ private_class_method def self.encryption_key
28
26
  Rails.application.secret_key_base[0..31]
29
27
  end
30
28
  end
@@ -1 +1,41 @@
1
- <%= render partial: "onlylogs/shared/log_container", locals: { log_file_path: @log_file_path, tail: @max_lines, filter: @filter, autoscroll: @autoscroll } %>
1
+ <style>
2
+ .grid {
3
+ display: grid;
4
+ grid-template-rows: 32px 1fr;
5
+ height: 100vh;
6
+ }
7
+
8
+ .grid-header {
9
+ display: flex;
10
+ align-items: center;
11
+ border-bottom: 1px solid lightgray;
12
+ }
13
+
14
+ .logo {
15
+ height: 20px;
16
+ margin: 3px;
17
+ }
18
+
19
+ .log-file-dropdown {
20
+ margin-left: 0.5rem;
21
+ }
22
+ </style>
23
+ <div class="grid">
24
+ <div class="grid-header">
25
+ <%= image_tag "onlylogs/logo.png", class: "logo" %>
26
+ <% if @available_log_files.any? %>
27
+ <%= form_with url: root_path, method: :get, local: true, class: "log-file-dropdown" do %>
28
+ <select id="log_file_path" name="log_file_path" onchange="this.form.submit()">
29
+ <% @available_log_files.each do |file| %>
30
+ <% encrypted_path = Onlylogs::SecureFilePath.encrypt(file.to_s) %>
31
+ <% relative_path = Pathname.new(file).relative_path_from(Rails.root).to_s %>
32
+ <option value="<%= encrypted_path %>" <%= "selected" if file.to_s == @log_file_path.to_s %>>
33
+ <%= relative_path %>
34
+ </option>
35
+ <% end %>
36
+ </select>
37
+ <% end %>
38
+ <% end %>
39
+ </div>
40
+ <%= render partial: "onlylogs/shared/log_container", locals: { log_file_path: @log_file_path, tail: @max_lines, filter: @filter, autoscroll: @autoscroll } %>
41
+ </div>
@@ -7,7 +7,7 @@
7
7
  mode = filter.blank? ? "live" : "search"
8
8
  cursor_position = mode == "search" ? 0 : [File.size(log_file_path) - (tail * 100), 0].max
9
9
 
10
- raise SecurityError, "File path not allowed" unless Onlylogs.allowed_file_path?(log_file_path)
10
+ raise SecurityError, "File path not allowed" unless Onlylogs.file_path_permitted?(log_file_path)
11
11
 
12
12
  encrypted_log_file_path = Onlylogs::SecureFilePath.encrypt(log_file_path)
13
13
  %>
data/config/routes.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  Onlylogs::Engine.routes.draw do
2
2
  root "logs#index"
3
- resources :logs, only: [ :index ]
3
+ resources :logs, only: [:index]
4
4
  end
@@ -2,12 +2,12 @@
2
2
 
3
3
  module Onlylogs
4
4
  class Configuration
5
- attr_accessor :allowed_files, :default_log_file_path, :basic_auth_user, :basic_auth_password,
6
- :parent_controller, :disable_basic_authentication, :ripgrep_enabled, :editor,
7
- :max_line_matches
5
+ attr_accessor :log_file_patterns, :default_log_file_path, :basic_auth_user, :basic_auth_password,
6
+ :parent_controller, :disable_basic_authentication, :ripgrep_enabled, :editor,
7
+ :max_line_matches
8
8
 
9
9
  def initialize
10
- @allowed_files = default_allowed_files
10
+ @log_file_patterns = default_log_file_patterns
11
11
  @default_log_file_path = default_log_file_path_value
12
12
  @basic_auth_user = default_basic_auth_user
13
13
  @basic_auth_password = default_basic_auth_password
@@ -44,7 +44,7 @@ module Onlylogs
44
44
  :vscode
45
45
  end
46
46
 
47
- def default_allowed_files
47
+ def default_log_file_patterns
48
48
  # Default to environment-specific log files (without rotation suffixes)
49
49
  [
50
50
  Rails.root.join("log/#{Rails.env}.log")
@@ -76,13 +76,33 @@ module Onlylogs
76
76
  yield configuration
77
77
  end
78
78
 
79
- def self.allowed_file_path?(file_path)
79
+ def self.file_path_permitted?(file_path)
80
80
  path = ::File.expand_path(file_path.to_s)
81
81
 
82
- configuration.allowed_files.any? do |pattern|
83
- pat = ::File.expand_path(pattern.to_s)
84
- ::File.fnmatch?(pat, path, ::File::FNM_PATHNAME | ::File::FNM_DOTMATCH)
82
+ configuration.log_file_patterns.any? do |pattern|
83
+ allowed_file_patterns_for(pattern).any? do |pat|
84
+ ::File.fnmatch?(pat, path, ::File::FNM_PATHNAME | ::File::FNM_DOTMATCH)
85
+ end
86
+ end
87
+ end
88
+
89
+ # Returns all existing files on disk that match the configured allowed_files patterns.
90
+ # Supports direct file paths and glob patterns (e.g., *.log, **/*.log).
91
+ # Returns Pathname objects so callers can access both the basename and the absolute path.
92
+ def self.available_log_files
93
+ patterns = Array(configuration.log_file_patterns)
94
+
95
+ paths = patterns.flat_map do |pattern|
96
+ allowed_file_patterns_for(pattern).flat_map do |expanded_pattern|
97
+ if glob_pattern?(expanded_pattern)
98
+ Dir.glob(expanded_pattern, ::File::FNM_DOTMATCH | ::File::FNM_PATHNAME).select { |p| ::File.file?(p) }
99
+ else
100
+ ::File.file?(expanded_pattern) ? [expanded_pattern] : []
101
+ end
102
+ end
85
103
  end
104
+
105
+ paths.uniq.sort.map { |p| Pathname.new(p) }
86
106
  end
87
107
 
88
108
  def self.default_log_file_path
@@ -126,4 +146,23 @@ module Onlylogs
126
146
  def self.max_line_matches
127
147
  configuration.max_line_matches
128
148
  end
149
+
150
+ def self.allowed_file_patterns_for(pattern)
151
+ absolute_pattern = ::File.expand_path(pattern.to_s)
152
+ if glob_pattern?(absolute_pattern)
153
+ return [absolute_pattern, "#{absolute_pattern}.*"] if absolute_pattern.end_with?(".log")
154
+
155
+ return [absolute_pattern]
156
+ end
157
+
158
+ return [absolute_pattern, "#{absolute_pattern}.*"] if absolute_pattern.end_with?(".log")
159
+
160
+ [absolute_pattern]
161
+ end
162
+
163
+ def self.glob_pattern?(pattern)
164
+ pattern.match?(/[*?\[\]{}]/)
165
+ end
166
+
167
+ private_class_method :allowed_file_patterns_for, :glob_pattern?
129
168
  end
@@ -15,7 +15,7 @@ module Onlylogs
15
15
  end
16
16
 
17
17
  app.config.assets.paths << root.join("app/javascript")
18
- app.config.assets.precompile += %w[ onlylogs_manifest ]
18
+ app.config.assets.precompile += %w[onlylogs_manifest]
19
19
  end
20
20
 
21
21
  if defined?(Importmap)
@@ -12,7 +12,7 @@ module Onlylogs
12
12
  def call(severity, time, progname, msg)
13
13
  return nil if "Onlylogs::LogsChannel".in?(msg)
14
14
  return nil if denylist.any? { |pattern| pattern.match?(msg) }
15
- tags = [ time.iso8601, severity[0].upcase ]
15
+ tags = [time.iso8601, severity[0].upcase]
16
16
  push_tags tags
17
17
  str = super
18
18
  pop_tags tags.size
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "socket"
4
- require "thread"
5
4
 
6
5
  # This logger sends messages to onlylogs.io via a UNIX socket connected to the onlylogs sidecar process.
7
6
  # You need to have the onlylogs sidecar running for this to work.
@@ -29,7 +28,7 @@ module Onlylogs
29
28
 
30
29
  formatted = format_message(format_severity(severity), Time.now, progname, message.to_s)
31
30
  send_to_socket(formatted)
32
- super(severity, message, progname, &block)
31
+ super
33
32
  end
34
33
 
35
34
  private
@@ -40,10 +39,10 @@ module Onlylogs
40
39
  socket = ensure_socket
41
40
  socket&.puts(payload)
42
41
  rescue Errno::EPIPE, Errno::ECONNREFUSED, Errno::ENOENT => e
43
- $stderr.puts "Onlylogs::SocketLogger error: #{e.message}"
42
+ warn "Onlylogs::SocketLogger error: #{e.message}"
44
43
  reconnect_socket
45
44
  rescue => e
46
- $stderr.puts "Onlylogs::SocketLogger unexpected error: #{e.class}: #{e.message}"
45
+ warn "Onlylogs::SocketLogger unexpected error: #{e.class}: #{e.message}"
47
46
  reconnect_socket
48
47
  end
49
48
 
@@ -53,7 +52,7 @@ module Onlylogs
53
52
  @socket_mutex.synchronize do
54
53
  @socket ||= UNIXSocket.new(@socket_path)
55
54
  rescue => e
56
- $stderr.puts "Unable to connect to Onlylogs sidecar (#{@socket_path}): #{e.message}"
55
+ warn "Unable to connect to Onlylogs sidecar (#{@socket_path}): #{e.message}"
57
56
  @socket = nil
58
57
  end
59
58
 
@@ -62,7 +61,11 @@ module Onlylogs
62
61
 
63
62
  def reconnect_socket
64
63
  @socket_mutex.synchronize do
65
- @socket&.close rescue nil
64
+ begin
65
+ @socket&.close
66
+ rescue
67
+ nil
68
+ end
66
69
  @socket = nil
67
70
  end
68
71
  end
@@ -1,3 +1,3 @@
1
1
  module Onlylogs
2
- VERSION = "0.3.1"
2
+ VERSION = "0.4.0"
3
3
  end
@@ -26,12 +26,12 @@ Puma::Plugin.create do
26
26
  FileUtils.mkdir_p(sockets_dir)
27
27
 
28
28
  @socket_path = env_or_option("ONLYLOGS_SIDECAR_SOCKET", :onlylogs_socket,
29
- File.join(sockets_dir, "onlylogs-sidecar.sock"))
29
+ File.join(sockets_dir, "onlylogs-sidecar.sock"))
30
30
  @drain_url = ENV["ONLYLOGS_DRAIN_URL"] || @options[:onlylogs_drain_url]
31
31
  @batch_size = env_or_option("ONLYLOGS_BATCH_SIZE", :onlylogs_batch_size, 100).to_i
32
32
  @flush_interval = env_or_option("ONLYLOGS_FLUSH_INTERVAL", :onlylogs_flush_interval, 0.5).to_f
33
33
  @sidecar_script = env_or_option("ONLYLOGS_SIDECAR_BIN", :onlylogs_sidecar_bin,
34
- File.expand_path("../../../bin/onlylogs_sidecar", __dir__))
34
+ File.expand_path("../../../bin/onlylogs_sidecar", __dir__))
35
35
  end
36
36
 
37
37
  def register_hooks
@@ -63,8 +63,8 @@ Puma::Plugin.create do
63
63
 
64
64
  info "Starting Onlylogs sidecar (socket: #{@socket_path}, drain: #{@drain_url})"
65
65
  @sidecar_pid = Process.spawn(env, RbConfig.ruby, @sidecar_script,
66
- chdir: @app_root,
67
- pgroup: true)
66
+ chdir: @app_root,
67
+ pgroup: true)
68
68
  rescue Errno::ENOENT => e
69
69
  error "Unable to start sidecar: #{e.message}"
70
70
  end
@@ -85,7 +85,11 @@ Puma::Plugin.create do
85
85
  # Already stopped
86
86
  rescue Timeout::Error
87
87
  warn "Sidecar did not stop in time, killing"
88
- Process.kill("KILL", -pgid) rescue nil
88
+ begin
89
+ Process.kill("KILL", -pgid)
90
+ rescue
91
+ nil
92
+ end
89
93
  ensure
90
94
  @sidecar_pid = nil
91
95
  remove_socket_file
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.3.1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alessandro Rodi