onlylogs 0.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 (54) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +311 -0
  3. data/Rakefile +8 -0
  4. data/app/assets/config/onlylogs_manifest.js +2 -0
  5. data/app/assets/images/onlylogs/favicon/apple-touch-icon.png +0 -0
  6. data/app/assets/images/onlylogs/favicon/favicon-96x96.png +0 -0
  7. data/app/assets/images/onlylogs/favicon/favicon.ico +0 -0
  8. data/app/assets/images/onlylogs/favicon/favicon.svg +3 -0
  9. data/app/assets/images/onlylogs/favicon/site.webmanifest.erb +21 -0
  10. data/app/assets/images/onlylogs/favicon/web-app-manifest-192x192.png +0 -0
  11. data/app/assets/images/onlylogs/favicon/web-app-manifest-512x512.png +0 -0
  12. data/app/assets/images/onlylogs/logo.png +0 -0
  13. data/app/channels/onlylogs/application_cable/channel.rb +11 -0
  14. data/app/channels/onlylogs/logs_channel.rb +181 -0
  15. data/app/controllers/onlylogs/application_controller.rb +22 -0
  16. data/app/controllers/onlylogs/logs_controller.rb +23 -0
  17. data/app/helpers/onlylogs/application_helper.rb +4 -0
  18. data/app/javascript/onlylogs/application.js +1 -0
  19. data/app/javascript/onlylogs/controllers/application.js +9 -0
  20. data/app/javascript/onlylogs/controllers/index.js +11 -0
  21. data/app/javascript/onlylogs/controllers/keyboard_shortcuts_controller.js +46 -0
  22. data/app/javascript/onlylogs/controllers/log_streamer_controller.js +432 -0
  23. data/app/javascript/onlylogs/controllers/text_selection_controller.js +90 -0
  24. data/app/jobs/onlylogs/application_job.rb +4 -0
  25. data/app/models/onlylogs/ansi_color_parser.rb +78 -0
  26. data/app/models/onlylogs/application_record.rb +5 -0
  27. data/app/models/onlylogs/batch_sender.rb +61 -0
  28. data/app/models/onlylogs/file.rb +151 -0
  29. data/app/models/onlylogs/file_path_parser.rb +118 -0
  30. data/app/models/onlylogs/grep.rb +54 -0
  31. data/app/models/onlylogs/log_line.rb +24 -0
  32. data/app/models/onlylogs/secure_file_path.rb +31 -0
  33. data/app/views/home/show.html.erb +10 -0
  34. data/app/views/layouts/onlylogs/application.html.erb +27 -0
  35. data/app/views/onlylogs/logs/index.html.erb +49 -0
  36. data/app/views/onlylogs/shared/_log_container.html.erb +106 -0
  37. data/app/views/onlylogs/shared/_log_container_styles.html.erb +228 -0
  38. data/config/importmap.rb +6 -0
  39. data/config/puma_plugins/vector.rb +94 -0
  40. data/config/routes.rb +4 -0
  41. data/config/udp_logger.rb +40 -0
  42. data/config/vector.toml +32 -0
  43. data/db/migrate/20250902112548_create_books.rb +9 -0
  44. data/lib/onlylogs/configuration.rb +133 -0
  45. data/lib/onlylogs/engine.rb +39 -0
  46. data/lib/onlylogs/formatter.rb +14 -0
  47. data/lib/onlylogs/log_silencer_middleware.rb +26 -0
  48. data/lib/onlylogs/logger.rb +10 -0
  49. data/lib/onlylogs/socket_logger.rb +71 -0
  50. data/lib/onlylogs/version.rb +3 -0
  51. data/lib/onlylogs.rb +17 -0
  52. data/lib/puma/plugin/onlylogs_sidecar.rb +113 -0
  53. data/lib/tasks/onlylogs_tasks.rake +4 -0
  54. metadata +110 -0
@@ -0,0 +1,14 @@
1
+ module Onlylogs
2
+ class Formatter < ActiveSupport::Logger::SimpleFormatter
3
+ include ActiveSupport::TaggedLogging::Formatter
4
+
5
+ def call(severity, time, progname, msg)
6
+ return nil if "Onlylogs::LogsChannel".in?(msg)
7
+ tags = [ time.iso8601, severity[0].upcase ]
8
+ push_tags tags
9
+ str = super
10
+ pop_tags tags.size
11
+ str
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,26 @@
1
+ module Onlylogs
2
+ class LogSilencerMiddleware
3
+ def initialize(app, paths_to_silence:)
4
+ @app = app
5
+ # Ensure paths are an array for flexibility
6
+ @paths_to_silence = Array(paths_to_silence)
7
+ end
8
+
9
+ def call(env)
10
+ if silence_request?(env)
11
+ Rails.logger.silence do
12
+ @app.call(env)
13
+ end
14
+ else
15
+ @app.call(env)
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def silence_request?(env)
22
+ request_path = env['PATH_INFO']
23
+ @paths_to_silence.any? { |path| request_path.start_with?(path) }
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,10 @@
1
+ module Onlylogs
2
+ class Logger < ActiveSupport::Logger
3
+ include ActiveSupport::TaggedLogging
4
+
5
+ def initialize(*args)
6
+ super
7
+ self.formatter = Onlylogs::Formatter.new
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "socket"
4
+ require "thread"
5
+
6
+ # This logger sends messages to onlylogs.io via a UNIX socket connected to the onlylogs sidecar process.
7
+ # You need to have the onlylogs sidecar running for this to work.
8
+
9
+ module Onlylogs
10
+ class SocketLogger < Onlylogs::Logger
11
+ DEFAULT_SOCKET = "tmp/sockets/onlylogs-sidecar.sock"
12
+
13
+ def initialize(local_fallback: $stdout, socket_path: ENV.fetch("ONLYLOGS_SIDECAR_SOCKET", DEFAULT_SOCKET))
14
+ super(local_fallback)
15
+ @socket_path = socket_path
16
+ @socket_mutex = Mutex.new
17
+ @socket = nil
18
+ end
19
+
20
+ def add(severity, message = nil, progname = nil, &block)
21
+
22
+ if message.nil?
23
+ if block_given?
24
+ message = block.call
25
+ else
26
+ message = progname
27
+ progname = nil
28
+ end
29
+ end
30
+
31
+ formatted = format_message(format_severity(severity), Time.now, progname, message.to_s)
32
+ send_to_socket(formatted)
33
+ super(severity, message, progname, &block)
34
+ end
35
+
36
+ private
37
+
38
+ def send_to_socket(payload)
39
+ return if payload.nil? || payload.empty?
40
+
41
+ socket = ensure_socket
42
+ socket&.puts(payload)
43
+ rescue Errno::EPIPE, Errno::ECONNREFUSED, Errno::ENOENT => e
44
+ puts "Onlylogs::SocketLogger error: #{e.message}"
45
+ reconnect_socket
46
+ rescue => e
47
+ puts"Onlylogs::SocketLogger unexpected error: #{e.class}: #{e.message}"
48
+ reconnect_socket
49
+ end
50
+
51
+ def ensure_socket
52
+ return @socket if @socket
53
+
54
+ @socket_mutex.synchronize do
55
+ @socket ||= UNIXSocket.new(@socket_path)
56
+ rescue => e
57
+ warn "Unable to connect to Onlylogs sidecar (#{@socket_path}): #{e.message}"
58
+ @socket = nil
59
+ end
60
+
61
+ @socket
62
+ end
63
+
64
+ def reconnect_socket
65
+ @socket_mutex.synchronize do
66
+ @socket&.close rescue nil
67
+ @socket = nil
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,3 @@
1
+ module Onlylogs
2
+ VERSION = "0.1.2"
3
+ end
data/lib/onlylogs.rb ADDED
@@ -0,0 +1,17 @@
1
+ require "onlylogs/version"
2
+ require "onlylogs/configuration"
3
+ require "onlylogs/engine"
4
+ require "onlylogs/formatter"
5
+ require "onlylogs/logger"
6
+ require "onlylogs/socket_logger"
7
+
8
+ # require "zeitwerk"
9
+ #
10
+ # loader = Zeitwerk::Loader.new
11
+ # loader.inflector = Zeitwerk::GemInflector.new(__FILE__)
12
+ # loader.push_dir(File.expand_path("..", __dir__))
13
+ # loader.setup
14
+
15
+ module Onlylogs
16
+ mattr_accessor :importmap, default: Importmap::Map.new
17
+ end
@@ -0,0 +1,113 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "puma/plugin"
4
+ require "rbconfig"
5
+ require "fileutils"
6
+ require "timeout"
7
+
8
+ Puma::Plugin.create do
9
+ def start(launcher)
10
+ @launcher = launcher
11
+ @events = launcher.events
12
+ @log_writer = launcher.log_writer
13
+ @options = launcher.config.options
14
+ @sidecar_pid = nil
15
+
16
+ setup_paths
17
+ start_sidecar
18
+ register_hooks
19
+ end
20
+
21
+ private
22
+
23
+ def setup_paths
24
+ @app_root = @options[:directory] || Dir.pwd
25
+ sockets_dir = File.expand_path("tmp/sockets", @app_root)
26
+ FileUtils.mkdir_p(sockets_dir)
27
+
28
+ @socket_path = env_or_option("ONLYLOGS_SIDECAR_SOCKET", :onlylogs_socket,
29
+ File.join(sockets_dir, "onlylogs-sidecar.sock"))
30
+ @drain_url = ENV["ONLYLOGS_DRAIN_URL"] || @options[:onlylogs_drain_url]
31
+ @batch_size = env_or_option("ONLYLOGS_BATCH_SIZE", :onlylogs_batch_size, 100).to_i
32
+ @flush_interval = env_or_option("ONLYLOGS_FLUSH_INTERVAL", :onlylogs_flush_interval, 0.5).to_f
33
+ @sidecar_script = env_or_option("ONLYLOGS_SIDECAR_BIN", :onlylogs_sidecar_bin,
34
+ File.expand_path("../../../bin/onlylogs_sidecar", __dir__))
35
+ end
36
+
37
+ def register_hooks
38
+ events = @launcher.events
39
+
40
+ events.register(:on_restart) { restart_sidecar }
41
+ at_exit { stop_sidecar }
42
+ end
43
+
44
+ def env_or_option(env_key, option_key, default)
45
+ ENV.fetch(env_key, @options.fetch(option_key, default))
46
+ end
47
+
48
+ def start_sidecar
49
+ if @drain_url.to_s.strip.empty?
50
+ warn "ONLYLOGS_DRAIN_URL not set; skipping Onlylogs sidecar start"
51
+ return
52
+ end
53
+
54
+ stop_sidecar if @sidecar_pid
55
+ remove_socket_file
56
+
57
+ env = {
58
+ "ONLYLOGS_SIDECAR_SOCKET" => @socket_path,
59
+ "ONLYLOGS_DRAIN_URL" => @drain_url,
60
+ "ONLYLOGS_BATCH_SIZE" => @batch_size.to_s,
61
+ "ONLYLOGS_FLUSH_INTERVAL" => @flush_interval.to_s
62
+ }
63
+
64
+ info "Starting Onlylogs sidecar (socket: #{@socket_path}, drain: #{@drain_url})"
65
+ @sidecar_pid = Process.spawn(env, RbConfig.ruby, @sidecar_script,
66
+ chdir: @app_root,
67
+ pgroup: true)
68
+ rescue Errno::ENOENT => e
69
+ error "Unable to start sidecar: #{e.message}"
70
+ end
71
+
72
+ def restart_sidecar
73
+ info "Restarting Onlylogs sidecar"
74
+ start_sidecar
75
+ end
76
+
77
+ def stop_sidecar
78
+ return unless @sidecar_pid
79
+
80
+ info "Stopping Onlylogs sidecar"
81
+ pgid = Process.getpgid(@sidecar_pid)
82
+ Process.kill("TERM", -pgid)
83
+ Timeout.timeout(5) { Process.wait(@sidecar_pid) }
84
+ rescue Errno::ESRCH, Errno::ECHILD
85
+ # Already stopped
86
+ rescue Timeout::Error
87
+ warn "Sidecar did not stop in time, killing"
88
+ Process.kill("KILL", -pgid) rescue nil
89
+ ensure
90
+ @sidecar_pid = nil
91
+ remove_socket_file
92
+ end
93
+
94
+ def remove_socket_file
95
+ FileUtils.rm_f(@socket_path)
96
+ end
97
+
98
+ def log(message)
99
+ @log_writer.log(message)
100
+ end
101
+
102
+ def info(message)
103
+ log("[OnlylogsSidecar] #{message}")
104
+ end
105
+
106
+ def warn(message)
107
+ log("[OnlylogsSidecar][WARN] #{message}")
108
+ end
109
+
110
+ def error(message)
111
+ log("[OnlylogsSidecar][ERROR] #{message}")
112
+ end
113
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :onlylogs do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,110 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: onlylogs
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.2
5
+ platform: ruby
6
+ authors:
7
+ - Alessandro Rodi
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: rails
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '8.0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '8.0'
26
+ description: This gem includes all the tools needed to view and stream you log files
27
+ directly on a web interface.
28
+ email:
29
+ - alessandro.rodi@renuo.ch
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - README.md
35
+ - Rakefile
36
+ - app/assets/config/onlylogs_manifest.js
37
+ - app/assets/images/onlylogs/favicon/apple-touch-icon.png
38
+ - app/assets/images/onlylogs/favicon/favicon-96x96.png
39
+ - app/assets/images/onlylogs/favicon/favicon.ico
40
+ - app/assets/images/onlylogs/favicon/favicon.svg
41
+ - app/assets/images/onlylogs/favicon/site.webmanifest.erb
42
+ - app/assets/images/onlylogs/favicon/web-app-manifest-192x192.png
43
+ - app/assets/images/onlylogs/favicon/web-app-manifest-512x512.png
44
+ - app/assets/images/onlylogs/logo.png
45
+ - app/channels/onlylogs/application_cable/channel.rb
46
+ - app/channels/onlylogs/logs_channel.rb
47
+ - app/controllers/onlylogs/application_controller.rb
48
+ - app/controllers/onlylogs/logs_controller.rb
49
+ - app/helpers/onlylogs/application_helper.rb
50
+ - app/javascript/onlylogs/application.js
51
+ - app/javascript/onlylogs/controllers/application.js
52
+ - app/javascript/onlylogs/controllers/index.js
53
+ - app/javascript/onlylogs/controllers/keyboard_shortcuts_controller.js
54
+ - app/javascript/onlylogs/controllers/log_streamer_controller.js
55
+ - app/javascript/onlylogs/controllers/text_selection_controller.js
56
+ - app/jobs/onlylogs/application_job.rb
57
+ - app/models/onlylogs/ansi_color_parser.rb
58
+ - app/models/onlylogs/application_record.rb
59
+ - app/models/onlylogs/batch_sender.rb
60
+ - app/models/onlylogs/file.rb
61
+ - app/models/onlylogs/file_path_parser.rb
62
+ - app/models/onlylogs/grep.rb
63
+ - app/models/onlylogs/log_line.rb
64
+ - app/models/onlylogs/secure_file_path.rb
65
+ - app/views/home/show.html.erb
66
+ - app/views/layouts/onlylogs/application.html.erb
67
+ - app/views/onlylogs/logs/index.html.erb
68
+ - app/views/onlylogs/shared/_log_container.html.erb
69
+ - app/views/onlylogs/shared/_log_container_styles.html.erb
70
+ - config/importmap.rb
71
+ - config/puma_plugins/vector.rb
72
+ - config/routes.rb
73
+ - config/udp_logger.rb
74
+ - config/vector.toml
75
+ - db/migrate/20250902112548_create_books.rb
76
+ - lib/onlylogs.rb
77
+ - lib/onlylogs/configuration.rb
78
+ - lib/onlylogs/engine.rb
79
+ - lib/onlylogs/formatter.rb
80
+ - lib/onlylogs/log_silencer_middleware.rb
81
+ - lib/onlylogs/logger.rb
82
+ - lib/onlylogs/socket_logger.rb
83
+ - lib/onlylogs/version.rb
84
+ - lib/puma/plugin/onlylogs_sidecar.rb
85
+ - lib/tasks/onlylogs_tasks.rake
86
+ homepage: https://onlylogs.io
87
+ licenses:
88
+ - MIT
89
+ metadata:
90
+ homepage_uri: https://onlylogs.io
91
+ source_code_uri: https://github.com/renuo/onlylogs
92
+ changelog_uri: https://github.com/renuo/onlylogs/CHANGELOG.md
93
+ rdoc_options: []
94
+ require_paths:
95
+ - lib
96
+ required_ruby_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ required_rubygems_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ requirements: []
107
+ rubygems_version: 3.6.9
108
+ specification_version: 4
109
+ summary: A Rails engine to view, stream, grep log files in real-time.
110
+ test_files: []