log_bench 0.1.4 → 0.1.5
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 +4 -4
- data/exe/log_bench +1 -0
- data/lib/log_bench/app/input_handler.rb +8 -2
- data/lib/log_bench/app/main.rb +8 -2
- data/lib/log_bench/app/mouse_handler.rb +0 -2
- data/lib/log_bench/app/renderer/main.rb +14 -5
- data/lib/log_bench/app/renderer/update_modal.rb +116 -0
- data/lib/log_bench/app/state.rb +17 -1
- data/lib/log_bench/version.rb +1 -1
- data/lib/log_bench/version_checker.rb +100 -0
- metadata +18 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eb8aba2b715d494f771f7bf0b1dda90719ae1a72e36823e86832f6ccbd7966b3
|
4
|
+
data.tar.gz: e7f5a7f4322778e74a4de3f33603c5de448e2e021c78e1506cf97507226ffa80
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 966d732d29bdbeaf30f1428b1f26126733120d2922c4a711a74e629fe78eae088702a51a6d20c311f097e98484bb93334a5eb8387b412b31449934e205013604
|
7
|
+
data.tar.gz: 628a28c650da6ed06b837397e3f79c09fc115ad36c2082ebb8dc9207a87e27034b04696a8d3462b2bb6be278a611ae08909ee4ecac3782509dce908dea5dda45
|
data/exe/log_bench
CHANGED
@@ -72,6 +72,7 @@ rescue => e
|
|
72
72
|
puts " - Log file doesn't exist or is empty"
|
73
73
|
puts " - Lograge not configured (see README.md for setup)"
|
74
74
|
puts " - Log format not supported (LogBench requires lograge JSON format)"
|
75
|
+
puts " Error backtrace: \n #{e.backtrace.join("\n")}"
|
75
76
|
puts
|
76
77
|
puts "For help: log_bench --help"
|
77
78
|
exit 1
|
@@ -17,9 +17,10 @@ module LogBench
|
|
17
17
|
# UI constants
|
18
18
|
DEFAULT_VISIBLE_HEIGHT = 20
|
19
19
|
|
20
|
-
def initialize(state, screen)
|
20
|
+
def initialize(state, screen, renderer = nil)
|
21
21
|
self.state = state
|
22
22
|
self.screen = screen
|
23
|
+
self.renderer = renderer
|
23
24
|
self.mouse_handler = MouseHandler.new(state, screen)
|
24
25
|
end
|
25
26
|
|
@@ -27,6 +28,11 @@ module LogBench
|
|
27
28
|
ch = getch
|
28
29
|
return if ch == -1 || ch.nil?
|
29
30
|
|
31
|
+
# Check if update modal should handle input first
|
32
|
+
if renderer&.handle_modal_input(ch)
|
33
|
+
return
|
34
|
+
end
|
35
|
+
|
30
36
|
if ch == KEY_MOUSE
|
31
37
|
mouse_handler.handle_mouse_input
|
32
38
|
elsif filter_mode_active?
|
@@ -38,7 +44,7 @@ module LogBench
|
|
38
44
|
|
39
45
|
private
|
40
46
|
|
41
|
-
attr_accessor :state, :screen, :mouse_handler
|
47
|
+
attr_accessor :state, :screen, :renderer, :mouse_handler
|
42
48
|
|
43
49
|
def filter_mode_active?
|
44
50
|
state.filter_mode || state.detail_filter_mode
|
data/lib/log_bench/app/main.rb
CHANGED
@@ -11,7 +11,7 @@ module LogBench
|
|
11
11
|
DEFAULT_LOG_PATHS = %w[log/development.log].freeze
|
12
12
|
|
13
13
|
# Timing
|
14
|
-
MAIN_LOOP_SLEEP_INTERVAL = 0
|
14
|
+
MAIN_LOOP_SLEEP_INTERVAL = 1.0 / 1000 # 1ms
|
15
15
|
|
16
16
|
# Error messages
|
17
17
|
LOG_FILE_NOT_FOUND = "Error: No log file found at %s!"
|
@@ -27,6 +27,7 @@ module LogBench
|
|
27
27
|
setup_screen
|
28
28
|
setup_components
|
29
29
|
load_initial_data
|
30
|
+
check_for_updates
|
30
31
|
initial_draw
|
31
32
|
start_monitoring
|
32
33
|
main_loop
|
@@ -55,8 +56,8 @@ module LogBench
|
|
55
56
|
end
|
56
57
|
|
57
58
|
def setup_components
|
58
|
-
self.input_handler = InputHandler.new(state, screen)
|
59
59
|
self.renderer = Renderer::Main.new(screen, state)
|
60
|
+
self.input_handler = InputHandler.new(state, screen, renderer)
|
60
61
|
end
|
61
62
|
|
62
63
|
def load_initial_data
|
@@ -64,6 +65,11 @@ module LogBench
|
|
64
65
|
state.requests = log_file.requests
|
65
66
|
end
|
66
67
|
|
68
|
+
def check_for_updates
|
69
|
+
latest_version = VersionChecker.check_for_update
|
70
|
+
state.set_update_available(latest_version) if latest_version
|
71
|
+
end
|
72
|
+
|
67
73
|
def initial_draw
|
68
74
|
renderer.draw
|
69
75
|
end
|
@@ -40,11 +40,9 @@ module LogBench
|
|
40
40
|
request_index = click_to_request_index(y)
|
41
41
|
return unless request_index
|
42
42
|
|
43
|
-
# Update selection
|
44
43
|
max_index = state.filtered_requests.size - 1
|
45
44
|
state.selected = [request_index, max_index].min
|
46
45
|
state.auto_scroll = false
|
47
|
-
state.adjust_scroll_for_selection(visible_height)
|
48
46
|
elsif click_in_right_pane?(x, y)
|
49
47
|
# Switch to right pane
|
50
48
|
state.switch_to_right_pane unless state.right_pane_focused?
|
@@ -12,18 +12,27 @@ module LogBench
|
|
12
12
|
self.header = Header.new(screen, state)
|
13
13
|
self.request_list = RequestList.new(screen, state, scrollbar)
|
14
14
|
self.details = Details.new(screen, state, scrollbar, ansi_renderer)
|
15
|
+
self.update_modal = UpdateModal.new(screen, state)
|
15
16
|
end
|
16
17
|
|
17
18
|
def draw
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
19
|
+
if update_modal.should_show?
|
20
|
+
update_modal.draw
|
21
|
+
else
|
22
|
+
header.draw
|
23
|
+
request_list.draw
|
24
|
+
details.draw
|
25
|
+
screen.refresh_all
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def handle_modal_input(ch)
|
30
|
+
update_modal.handle_input(ch)
|
22
31
|
end
|
23
32
|
|
24
33
|
private
|
25
34
|
|
26
|
-
attr_accessor :screen, :state, :header, :scrollbar, :request_list, :ansi_renderer, :details
|
35
|
+
attr_accessor :screen, :state, :header, :scrollbar, :request_list, :ansi_renderer, :details, :update_modal
|
27
36
|
end
|
28
37
|
end
|
29
38
|
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LogBench
|
4
|
+
module App
|
5
|
+
module Renderer
|
6
|
+
class UpdateModal
|
7
|
+
include Curses
|
8
|
+
|
9
|
+
# Modal dimensions
|
10
|
+
MODAL_WIDTH = 40
|
11
|
+
MODAL_HEIGHT = 7
|
12
|
+
COUNTDOWN_SECONDS = 5
|
13
|
+
|
14
|
+
# Color constants
|
15
|
+
HEADER_CYAN = 1
|
16
|
+
SUCCESS_GREEN = 3
|
17
|
+
WARNING_YELLOW = 4
|
18
|
+
|
19
|
+
def initialize(screen, state)
|
20
|
+
self.screen = screen
|
21
|
+
self.state = state
|
22
|
+
self.countdown = COUNTDOWN_SECONDS
|
23
|
+
self.modal_win = nil
|
24
|
+
self.last_countdown_update = Time.now
|
25
|
+
self.dismissed = false
|
26
|
+
end
|
27
|
+
|
28
|
+
def should_show?
|
29
|
+
state.update_available? && !dismissed
|
30
|
+
end
|
31
|
+
|
32
|
+
def draw
|
33
|
+
return unless should_show?
|
34
|
+
|
35
|
+
create_modal_window
|
36
|
+
update_countdown_timer
|
37
|
+
draw_content
|
38
|
+
modal_win&.refresh
|
39
|
+
end
|
40
|
+
|
41
|
+
def handle_input(ch)
|
42
|
+
return false unless should_show?
|
43
|
+
|
44
|
+
# Any key dismisses the modal
|
45
|
+
if ch != -1
|
46
|
+
dismiss_modal
|
47
|
+
return true
|
48
|
+
end
|
49
|
+
|
50
|
+
false
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
attr_accessor :screen, :state, :countdown, :modal_win, :last_countdown_update, :dismissed
|
56
|
+
|
57
|
+
def create_modal_window
|
58
|
+
return if modal_win
|
59
|
+
|
60
|
+
# Calculate center position
|
61
|
+
center_y = (screen.height - MODAL_HEIGHT) / 2
|
62
|
+
center_x = (screen.width - MODAL_WIDTH) / 2
|
63
|
+
|
64
|
+
# Create modal window
|
65
|
+
self.modal_win = Window.new(MODAL_HEIGHT, MODAL_WIDTH, center_y, center_x)
|
66
|
+
end
|
67
|
+
|
68
|
+
def draw_content
|
69
|
+
return unless modal_win
|
70
|
+
|
71
|
+
modal_win.erase
|
72
|
+
modal_win.box(0, 0)
|
73
|
+
|
74
|
+
# Header
|
75
|
+
modal_win.setpos(1, 2)
|
76
|
+
modal_win.attron(color_pair(HEADER_CYAN) | A_BOLD) { modal_win.addstr("🚀 LogBench Update Available!") }
|
77
|
+
|
78
|
+
# Version info
|
79
|
+
modal_win.setpos(3, 2)
|
80
|
+
modal_win.addstr("Current: ")
|
81
|
+
modal_win.attron(color_pair(SUCCESS_GREEN)) { modal_win.addstr(LogBench::VERSION) }
|
82
|
+
modal_win.addstr(" → Latest: ")
|
83
|
+
modal_win.attron(color_pair(SUCCESS_GREEN) | A_BOLD) { modal_win.addstr(state.update_version) }
|
84
|
+
|
85
|
+
# Instructions with countdown
|
86
|
+
modal_win.setpos(5, 2)
|
87
|
+
modal_win.addstr("Press any key to continue or wait ")
|
88
|
+
modal_win.attron(color_pair(WARNING_YELLOW) | A_BOLD) { modal_win.addstr("#{countdown}s") }
|
89
|
+
end
|
90
|
+
|
91
|
+
def update_countdown_timer
|
92
|
+
now = Time.now
|
93
|
+
if now - last_countdown_update >= 1.0
|
94
|
+
self.countdown -= 1
|
95
|
+
self.last_countdown_update = now
|
96
|
+
|
97
|
+
if countdown <= 0
|
98
|
+
dismiss_modal
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def dismiss_modal
|
104
|
+
state.dismiss_update_notification
|
105
|
+
modal_win&.close
|
106
|
+
self.modal_win = nil
|
107
|
+
clear
|
108
|
+
end
|
109
|
+
|
110
|
+
def color_pair(n)
|
111
|
+
screen.color_pair(n)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
data/lib/log_bench/app/state.rb
CHANGED
@@ -4,7 +4,7 @@ module LogBench
|
|
4
4
|
module App
|
5
5
|
class State
|
6
6
|
attr_reader :main_filter, :sort, :detail_filter
|
7
|
-
attr_accessor :requests, :auto_scroll, :scroll_offset, :selected, :detail_scroll_offset, :text_selection_mode
|
7
|
+
attr_accessor :requests, :auto_scroll, :scroll_offset, :selected, :detail_scroll_offset, :text_selection_mode, :update_available, :update_version
|
8
8
|
|
9
9
|
def initialize
|
10
10
|
self.requests = []
|
@@ -18,6 +18,8 @@ module LogBench
|
|
18
18
|
self.main_filter = Filter.new
|
19
19
|
self.detail_filter = Filter.new
|
20
20
|
self.sort = Sort.new
|
21
|
+
self.update_available = false
|
22
|
+
self.update_version = nil
|
21
23
|
end
|
22
24
|
|
23
25
|
def running?
|
@@ -40,6 +42,20 @@ module LogBench
|
|
40
42
|
text_selection_mode
|
41
43
|
end
|
42
44
|
|
45
|
+
def set_update_available(version)
|
46
|
+
self.update_available = true
|
47
|
+
self.update_version = version
|
48
|
+
end
|
49
|
+
|
50
|
+
def dismiss_update_notification
|
51
|
+
self.update_available = false
|
52
|
+
self.update_version = nil
|
53
|
+
end
|
54
|
+
|
55
|
+
def update_available?
|
56
|
+
update_available
|
57
|
+
end
|
58
|
+
|
43
59
|
def clear_filter
|
44
60
|
main_filter.clear
|
45
61
|
self.selected = 0
|
data/lib/log_bench/version.rb
CHANGED
@@ -0,0 +1,100 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "net/http"
|
4
|
+
require "json"
|
5
|
+
require "fileutils"
|
6
|
+
|
7
|
+
module LogBench
|
8
|
+
class VersionChecker
|
9
|
+
# Cache file location
|
10
|
+
CACHE_DIR = File.expand_path("~/.cache/log_bench")
|
11
|
+
CACHE_FILE = File.join(CACHE_DIR, "version_check.json")
|
12
|
+
|
13
|
+
# Cache duration (24 hours)
|
14
|
+
CACHE_DURATION = 24 * 60 * 60
|
15
|
+
|
16
|
+
# RubyGems API endpoint
|
17
|
+
RUBYGEMS_API_URL = "https://rubygems.org/api/v1/gems/log_bench.json"
|
18
|
+
|
19
|
+
# Timeout for HTTP requests
|
20
|
+
REQUEST_TIMEOUT = 5
|
21
|
+
|
22
|
+
def self.check_for_update
|
23
|
+
new.check_for_update
|
24
|
+
end
|
25
|
+
|
26
|
+
def check_for_update
|
27
|
+
return nil unless should_check?
|
28
|
+
|
29
|
+
latest_version = fetch_latest_version
|
30
|
+
return nil unless latest_version
|
31
|
+
|
32
|
+
update_cache(latest_version)
|
33
|
+
|
34
|
+
if newer_version_available?(latest_version)
|
35
|
+
latest_version
|
36
|
+
end
|
37
|
+
rescue
|
38
|
+
# Silently fail - don't interrupt the user experience
|
39
|
+
nil
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def should_check?
|
45
|
+
return true unless File.exist?(CACHE_FILE)
|
46
|
+
|
47
|
+
cache_data = read_cache
|
48
|
+
return true unless cache_data
|
49
|
+
|
50
|
+
# Check if cache is expired
|
51
|
+
Time.now - Time.parse(cache_data["checked_at"]) > CACHE_DURATION
|
52
|
+
rescue
|
53
|
+
true
|
54
|
+
end
|
55
|
+
|
56
|
+
def fetch_latest_version
|
57
|
+
uri = URI(RUBYGEMS_API_URL)
|
58
|
+
|
59
|
+
Net::HTTP.start(uri.host, uri.port, use_ssl: true, read_timeout: REQUEST_TIMEOUT) do |http|
|
60
|
+
request = Net::HTTP::Get.new(uri)
|
61
|
+
response = http.request(request)
|
62
|
+
|
63
|
+
return nil unless response.code == "200"
|
64
|
+
|
65
|
+
data = JSON.parse(response.body)
|
66
|
+
data["version"]
|
67
|
+
end
|
68
|
+
rescue
|
69
|
+
nil
|
70
|
+
end
|
71
|
+
|
72
|
+
def read_cache
|
73
|
+
return nil unless File.exist?(CACHE_FILE)
|
74
|
+
|
75
|
+
JSON.parse(File.read(CACHE_FILE))
|
76
|
+
rescue
|
77
|
+
nil
|
78
|
+
end
|
79
|
+
|
80
|
+
def update_cache(latest_version)
|
81
|
+
FileUtils.mkdir_p(CACHE_DIR)
|
82
|
+
|
83
|
+
cache_data = {
|
84
|
+
"latest_version" => latest_version,
|
85
|
+
"checked_at" => Time.now.iso8601
|
86
|
+
}
|
87
|
+
|
88
|
+
File.write(CACHE_FILE, JSON.pretty_generate(cache_data))
|
89
|
+
rescue
|
90
|
+
# Ignore cache write errors
|
91
|
+
nil
|
92
|
+
end
|
93
|
+
|
94
|
+
def newer_version_available?(latest_version)
|
95
|
+
Gem::Version.new(latest_version) > Gem::Version.new(LogBench::VERSION)
|
96
|
+
rescue
|
97
|
+
false
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: log_bench
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Benjamín Silva
|
8
8
|
bindir: exe
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-06-
|
10
|
+
date: 2025-06-09 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: zeitwerk
|
@@ -51,6 +51,20 @@ dependencies:
|
|
51
51
|
- - "~>"
|
52
52
|
- !ruby/object:Gem::Version
|
53
53
|
version: '0.14'
|
54
|
+
- !ruby/object:Gem::Dependency
|
55
|
+
name: net-http
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0.6'
|
61
|
+
type: :runtime
|
62
|
+
prerelease: false
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - "~>"
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '0.6'
|
54
68
|
- !ruby/object:Gem::Dependency
|
55
69
|
name: rake
|
56
70
|
requirement: !ruby/object:Gem::Requirement
|
@@ -121,6 +135,7 @@ files:
|
|
121
135
|
- lib/log_bench/app/renderer/main.rb
|
122
136
|
- lib/log_bench/app/renderer/request_list.rb
|
123
137
|
- lib/log_bench/app/renderer/scrollbar.rb
|
138
|
+
- lib/log_bench/app/renderer/update_modal.rb
|
124
139
|
- lib/log_bench/app/screen.rb
|
125
140
|
- lib/log_bench/app/sort.rb
|
126
141
|
- lib/log_bench/app/state.rb
|
@@ -135,6 +150,7 @@ files:
|
|
135
150
|
- lib/log_bench/log/request.rb
|
136
151
|
- lib/log_bench/railtie.rb
|
137
152
|
- lib/log_bench/version.rb
|
153
|
+
- lib/log_bench/version_checker.rb
|
138
154
|
- lib/tasks/log_bench.rake
|
139
155
|
- logbench-preview.png
|
140
156
|
homepage: https://github.com/silva96/log_bench
|