log_bench 0.1.3 → 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/README.md +1 -3
- data/exe/log_bench +1 -0
- data/lib/log_bench/app/input_handler.rb +22 -9
- data/lib/log_bench/app/main.rb +8 -2
- data/lib/log_bench/app/mouse_handler.rb +102 -0
- data/lib/log_bench/app/renderer/header.rb +3 -1
- 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/screen.rb +5 -0
- data/lib/log_bench/app/state.rb +26 -1
- data/lib/log_bench/version.rb +1 -1
- data/lib/log_bench/version_checker.rb +100 -0
- metadata +19 -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/README.md
CHANGED
@@ -107,7 +107,7 @@ log_bench log/development.log
|
|
107
107
|
|
108
108
|
### Filtering
|
109
109
|
|
110
|
-
Press `f` to open the filter dialog.
|
110
|
+
Press `f` to open the filter dialog.
|
111
111
|
|
112
112
|
In the left pane you can filter by:
|
113
113
|
|
@@ -233,5 +233,3 @@ This gem is available as open source under the terms of the [MIT License](LICENS
|
|
233
233
|
## Support
|
234
234
|
|
235
235
|
- 🐛 **Bug reports**: [GitHub Issues](https://github.com/silva96/log_bench/issues)
|
236
|
-
- 💡 **Feature requests**: [GitHub Discussions](https://github.com/silva96/log_bench/discussions)
|
237
|
-
- 📖 **Documentation**: [GitHub Wiki](https://github.com/silva96/log_bench/wiki)
|
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,15 +17,25 @@ module LogBench
|
|
17
17
|
# UI constants
|
18
18
|
DEFAULT_VISIBLE_HEIGHT = 20
|
19
19
|
|
20
|
-
def initialize(state)
|
20
|
+
def initialize(state, screen, renderer = nil)
|
21
21
|
self.state = state
|
22
|
+
self.screen = screen
|
23
|
+
self.renderer = renderer
|
24
|
+
self.mouse_handler = MouseHandler.new(state, screen)
|
22
25
|
end
|
23
26
|
|
24
27
|
def handle_input
|
25
28
|
ch = getch
|
26
29
|
return if ch == -1 || ch.nil?
|
27
30
|
|
28
|
-
if
|
31
|
+
# Check if update modal should handle input first
|
32
|
+
if renderer&.handle_modal_input(ch)
|
33
|
+
return
|
34
|
+
end
|
35
|
+
|
36
|
+
if ch == KEY_MOUSE
|
37
|
+
mouse_handler.handle_mouse_input
|
38
|
+
elsif filter_mode_active?
|
29
39
|
handle_filter_input(ch)
|
30
40
|
else
|
31
41
|
handle_navigation_input(ch)
|
@@ -34,7 +44,7 @@ module LogBench
|
|
34
44
|
|
35
45
|
private
|
36
46
|
|
37
|
-
attr_accessor :state
|
47
|
+
attr_accessor :state, :screen, :renderer, :mouse_handler
|
38
48
|
|
39
49
|
def filter_mode_active?
|
40
50
|
state.filter_mode || state.detail_filter_mode
|
@@ -44,10 +54,10 @@ module LogBench
|
|
44
54
|
case ch
|
45
55
|
when 10, 13, 27
|
46
56
|
state.exit_filter_mode
|
47
|
-
when
|
57
|
+
when KEY_UP, "k", "K"
|
48
58
|
state.exit_filter_mode
|
49
59
|
state.navigate_up
|
50
|
-
when
|
60
|
+
when KEY_DOWN, "j", "J"
|
51
61
|
state.exit_filter_mode
|
52
62
|
state.navigate_down
|
53
63
|
when 127, 8 # Backspace
|
@@ -89,15 +99,15 @@ module LogBench
|
|
89
99
|
|
90
100
|
def handle_navigation_input(ch)
|
91
101
|
case ch
|
92
|
-
when
|
102
|
+
when KEY_LEFT, "h", "H"
|
93
103
|
state.switch_to_left_pane
|
94
|
-
when
|
104
|
+
when KEY_RIGHT, "l", "L"
|
95
105
|
state.switch_to_right_pane
|
96
106
|
when TAB
|
97
107
|
toggle_pane_focus
|
98
|
-
when
|
108
|
+
when KEY_UP, "k", "K"
|
99
109
|
handle_up_navigation
|
100
|
-
when
|
110
|
+
when KEY_DOWN, "j", "J"
|
101
111
|
handle_down_navigation
|
102
112
|
when CTRL_F
|
103
113
|
handle_page_down
|
@@ -125,6 +135,9 @@ module LogBench
|
|
125
135
|
state.cycle_sort_mode
|
126
136
|
when "q", "Q", CTRL_C
|
127
137
|
state.stop!
|
138
|
+
when "t", "T"
|
139
|
+
state.toggle_text_selection_mode
|
140
|
+
screen.turn_text_selection_mode(state.text_selection_mode?)
|
128
141
|
when ESC
|
129
142
|
handle_escape
|
130
143
|
end
|
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)
|
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
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LogBench
|
4
|
+
module App
|
5
|
+
class MouseHandler
|
6
|
+
include Curses
|
7
|
+
|
8
|
+
# UI constants
|
9
|
+
DEFAULT_VISIBLE_HEIGHT = 20
|
10
|
+
|
11
|
+
def initialize(state, screen)
|
12
|
+
self.state = state
|
13
|
+
self.screen = screen
|
14
|
+
end
|
15
|
+
|
16
|
+
def handle_mouse_input
|
17
|
+
with_warnings_suppressed do
|
18
|
+
mouse_event = getmouse
|
19
|
+
|
20
|
+
return unless mouse_event
|
21
|
+
|
22
|
+
if mouse_event.bstate & BUTTON1_CLICKED != 0
|
23
|
+
handle_mouse_click(mouse_event.x, mouse_event.y)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
rescue
|
27
|
+
nil
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
attr_accessor :state, :screen
|
33
|
+
|
34
|
+
def handle_mouse_click(x, y)
|
35
|
+
if click_in_left_pane?(x, y)
|
36
|
+
# Switch to left pane if not already focused
|
37
|
+
state.switch_to_left_pane unless state.left_pane_focused?
|
38
|
+
|
39
|
+
# Convert click coordinates to request index
|
40
|
+
request_index = click_to_request_index(y)
|
41
|
+
return unless request_index
|
42
|
+
|
43
|
+
max_index = state.filtered_requests.size - 1
|
44
|
+
state.selected = [request_index, max_index].min
|
45
|
+
state.auto_scroll = false
|
46
|
+
elsif click_in_right_pane?(x, y)
|
47
|
+
# Switch to right pane
|
48
|
+
state.switch_to_right_pane unless state.right_pane_focused?
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def click_in_left_pane?(x, y)
|
53
|
+
# Left pane spans from x=0 to panel_width
|
54
|
+
# Header takes up first HEADER_HEIGHT lines
|
55
|
+
# Request list starts at HEADER_HEIGHT + 1 (accounting for border)
|
56
|
+
panel_width = screen.panel_width
|
57
|
+
header_height = 5 # Screen::HEADER_HEIGHT
|
58
|
+
|
59
|
+
x >= 0 && x < panel_width && y > header_height
|
60
|
+
end
|
61
|
+
|
62
|
+
def click_in_right_pane?(x, y)
|
63
|
+
# Right pane starts after left panel + border width
|
64
|
+
# From Screen: panel_width + PANEL_BORDER_WIDTH
|
65
|
+
panel_width = screen.panel_width
|
66
|
+
border_width = 3 # Screen::PANEL_BORDER_WIDTH
|
67
|
+
header_height = 5 # Screen::HEADER_HEIGHT
|
68
|
+
|
69
|
+
right_pane_start = panel_width + border_width
|
70
|
+
|
71
|
+
x >= right_pane_start && y > header_height
|
72
|
+
end
|
73
|
+
|
74
|
+
def click_to_request_index(y)
|
75
|
+
# Header takes up first 5 lines
|
76
|
+
# Request list has 1 line border at top, then 1 line for column headers
|
77
|
+
# So actual request rows start at y = 7 (5 header + 1 border + 1 column header)
|
78
|
+
header_height = 5
|
79
|
+
list_header_offset = 2 # border + column header
|
80
|
+
|
81
|
+
row_in_list = y - header_height - list_header_offset
|
82
|
+
return nil if row_in_list < 0
|
83
|
+
|
84
|
+
# Convert to actual request index accounting for scroll
|
85
|
+
state.scroll_offset + row_in_list
|
86
|
+
end
|
87
|
+
|
88
|
+
def visible_height
|
89
|
+
# Approximate visible height for calculations
|
90
|
+
DEFAULT_VISIBLE_HEIGHT
|
91
|
+
end
|
92
|
+
|
93
|
+
def with_warnings_suppressed
|
94
|
+
old_verbose = $VERBOSE
|
95
|
+
$VERBOSE = nil
|
96
|
+
yield
|
97
|
+
ensure
|
98
|
+
$VERBOSE = old_verbose
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -77,12 +77,14 @@ module LogBench
|
|
77
77
|
header_win.attron(color_pair(3)) { header_win.addstr(state.auto_scroll ? "ON" : "OFF") }
|
78
78
|
header_win.addstr(") | f:Filter | c:Clear filter | s:Sort(")
|
79
79
|
header_win.attron(color_pair(3)) { header_win.addstr(state.sort.display_name) }
|
80
|
+
header_win.addstr(") | t:Text selection(")
|
81
|
+
header_win.attron(color_pair(3)) { header_win.addstr(state.text_selection_mode? ? "ON" : "OFF") }
|
80
82
|
header_win.addstr(") | q:Quit")
|
81
83
|
end
|
82
84
|
|
83
85
|
header_win.setpos(3, 2)
|
84
86
|
header_win.attron(A_DIM) do
|
85
|
-
header_win.addstr("←→/hl:Switch Pane | ↑↓/jk:Navigate | g/G:Top/End")
|
87
|
+
header_win.addstr("←→/hl:Switch Pane | ↑↓/jk/Click:Navigate | g/G:Top/End")
|
86
88
|
end
|
87
89
|
end
|
88
90
|
|
@@ -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/screen.rb
CHANGED
@@ -29,6 +29,7 @@ module LogBench
|
|
29
29
|
setup_colors
|
30
30
|
clear_screen_immediately
|
31
31
|
setup_windows
|
32
|
+
turn_text_selection_mode(false)
|
32
33
|
end
|
33
34
|
|
34
35
|
def cleanup
|
@@ -54,6 +55,10 @@ module LogBench
|
|
54
55
|
Curses.color_pair(n)
|
55
56
|
end
|
56
57
|
|
58
|
+
def turn_text_selection_mode(enabled)
|
59
|
+
enabled ? mousemask(0) : mousemask(BUTTON1_CLICKED)
|
60
|
+
end
|
61
|
+
|
57
62
|
private
|
58
63
|
|
59
64
|
attr_writer :header_win, :log_win, :panel_width, :detail_win
|
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
|
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 = []
|
@@ -14,9 +14,12 @@ module LogBench
|
|
14
14
|
self.running = true
|
15
15
|
self.focused_pane = :left
|
16
16
|
self.detail_scroll_offset = 0
|
17
|
+
self.text_selection_mode = false
|
17
18
|
self.main_filter = Filter.new
|
18
19
|
self.detail_filter = Filter.new
|
19
20
|
self.sort = Sort.new
|
21
|
+
self.update_available = false
|
22
|
+
self.update_version = nil
|
20
23
|
end
|
21
24
|
|
22
25
|
def running?
|
@@ -31,6 +34,28 @@ module LogBench
|
|
31
34
|
self.auto_scroll = !auto_scroll
|
32
35
|
end
|
33
36
|
|
37
|
+
def toggle_text_selection_mode
|
38
|
+
self.text_selection_mode = !text_selection_mode
|
39
|
+
end
|
40
|
+
|
41
|
+
def text_selection_mode?
|
42
|
+
text_selection_mode
|
43
|
+
end
|
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
|
+
|
34
59
|
def clear_filter
|
35
60
|
main_filter.clear
|
36
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
|
@@ -114,12 +128,14 @@ files:
|
|
114
128
|
- lib/log_bench/app/input_handler.rb
|
115
129
|
- lib/log_bench/app/main.rb
|
116
130
|
- lib/log_bench/app/monitor.rb
|
131
|
+
- lib/log_bench/app/mouse_handler.rb
|
117
132
|
- lib/log_bench/app/renderer/ansi.rb
|
118
133
|
- lib/log_bench/app/renderer/details.rb
|
119
134
|
- lib/log_bench/app/renderer/header.rb
|
120
135
|
- lib/log_bench/app/renderer/main.rb
|
121
136
|
- lib/log_bench/app/renderer/request_list.rb
|
122
137
|
- lib/log_bench/app/renderer/scrollbar.rb
|
138
|
+
- lib/log_bench/app/renderer/update_modal.rb
|
123
139
|
- lib/log_bench/app/screen.rb
|
124
140
|
- lib/log_bench/app/sort.rb
|
125
141
|
- lib/log_bench/app/state.rb
|
@@ -134,6 +150,7 @@ files:
|
|
134
150
|
- lib/log_bench/log/request.rb
|
135
151
|
- lib/log_bench/railtie.rb
|
136
152
|
- lib/log_bench/version.rb
|
153
|
+
- lib/log_bench/version_checker.rb
|
137
154
|
- lib/tasks/log_bench.rake
|
138
155
|
- logbench-preview.png
|
139
156
|
homepage: https://github.com/silva96/log_bench
|