logviewer 1.5.7 → 1.7.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: 0b2114d40916c4035ec2d6073e0bc07530fccda6d43662e1c0f15e46d2c5b053
4
- data.tar.gz: 9bb090e8c537e956124225447d26d875e77e52f119671a3244db27049595c077
3
+ metadata.gz: c2e1bf52a01e4f5ef4cb8459d5cb0b7951a03b6ac78751b5b0338e132ff28e7f
4
+ data.tar.gz: dbaa77c1b51d5f25169cb23a0d84bc5e0a685494c46f6388ed59d8c142e9e5e2
5
5
  SHA512:
6
- metadata.gz: 16968466a7abbed8986d033d090101f8e56fe9b2e080e6374bc558b469bfd78368a35592af1e2f51d13e8759bedc3dd34b4155344065f94c329e9debbaaac23c
7
- data.tar.gz: 0e97e00b01233e994316d7cbad5343fd60f5e93ae0379b325ca95e8036af79c0046c121cb2db4ae654c1a56b2848ba2b1f1edcce6d75c5b6573bfb4feae04b08
6
+ metadata.gz: 35bed00c8c9b38854f8850156fd0a2a74b3f9e22b08c27fbcce0ccf830e55453a462f04f5eab630624df7aeaec7ab4f67bd3c0421925395f931f710fec3152a4
7
+ data.tar.gz: 8f16831c8b0fdc9bc5d1b927f2ef1d54d96d620e800330a1d9b3fc5192eed47a0a8c3b9b8c4bd5781f4d817d5c517aec8d4112f0f6fabd38cc8b9c3825f4556e
data/README.md CHANGED
@@ -11,6 +11,8 @@ A Ruby gem that converts NDJSON log files into a readable HTML format for easy v
11
11
  - Simplified file paths (shows only filename, not full path)
12
12
  - Color-coded log levels for easy identification
13
13
  - Large, readable fonts throughout the interface (18px base size)
14
+ - Interactive dynamic filtering by log level in the browser
15
+ - Dark mode interface with optimized colors for comfortable viewing
14
16
  - Responsive design that works well in any browser
15
17
  - Automatically opens the generated HTML file in your default browser
16
18
 
@@ -46,7 +48,7 @@ This will:
46
48
  logviewer --level info example.ndjson
47
49
  ```
48
50
 
49
- Only shows log entries with level "info" and above (info, warning, error, fatal).
51
+ Only includes log entries with level "info" and above in the HTML file. You can then use the interactive dropdown in the browser to filter further.
50
52
 
51
53
  ### Auto-Detection of Log Files
52
54
 
@@ -104,8 +106,10 @@ Example log entry:
104
106
  The generated HTML file will be saved in `/tmp/` with a timestamp and automatically opened in your browser. The HTML includes:
105
107
 
106
108
  - A wide, responsive table layout (1800px max width) with columns in order: date, level, tag, file, function, text
109
+ - Interactive log level filtering dropdown for dynamic filtering in the browser
110
+ - Dark mode theme with comfortable dark backgrounds and light text
107
111
  - Human-readable timestamps (MM/DD HH:MM:SS format)
108
- - Color-coded log levels
112
+ - Color-coded log levels optimized for dark backgrounds
109
113
  - Sticky header for easy navigation
110
114
  - Hover effects for better readability
111
115
  - Large fonts (18px base size) for excellent readability
@@ -114,6 +118,14 @@ The generated HTML file will be saved in `/tmp/` with a timestamp and automatica
114
118
  - Date, file, and function names in monospace font
115
119
  - Color-coded tags for easy categorization
116
120
 
121
+ ## Interactive Features
122
+
123
+ Once the HTML file opens in your browser, you can:
124
+ - Use the dropdown in the header to dynamically filter log entries by minimum level
125
+ - Filter changes are applied instantly without page reload
126
+ - Entry counts update automatically to show how many entries match the current filter
127
+ - Command line level acts as the initial data set - browser filtering works within those entries
128
+
117
129
  ## Development
118
130
 
119
131
  After checking out the repo, run the following commands to set up development:
@@ -1,3 +1,3 @@
1
1
  module LogViewer
2
- VERSION = "1.5.7"
2
+ VERSION = "1.7.0"
3
3
  end
data/lib/logviewer.rb CHANGED
@@ -106,19 +106,19 @@ module LogViewer
106
106
  def level_color(level)
107
107
  case level.downcase
108
108
  when 'trace'
109
- '#6c757d'
109
+ '#adb5bd'
110
110
  when 'debug'
111
- '#6c757d'
111
+ '#adb5bd'
112
112
  when 'info'
113
- '#0d6efd'
113
+ '#6ea8fe'
114
114
  when 'warning'
115
- '#fd7e14'
115
+ '#fd9843'
116
116
  when 'error'
117
- '#dc3545'
117
+ '#ea868f'
118
118
  when 'fatal'
119
- '#6f42c1'
119
+ '#c29ffa'
120
120
  else
121
- '#000000'
121
+ '#e0e0e0'
122
122
  end
123
123
  end
124
124
 
@@ -151,19 +151,20 @@ module LogViewer
151
151
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
152
152
  margin: 0;
153
153
  padding: 20px;
154
- background-color: #f8f9fa;
154
+ background-color: #1a1a1a;
155
+ color: #e0e0e0;
155
156
  }
156
157
  .container {
157
158
  max-width: 1800px;
158
159
  margin: 0 auto;
159
- background: white;
160
+ background: #2d2d2d;
160
161
  border-radius: 8px;
161
- box-shadow: 0 2px 10px rgba(0,0,0,0.1);
162
+ box-shadow: 0 2px 10px rgba(0,0,0,0.3);
162
163
  overflow: hidden;
163
164
  }
164
165
  .header {
165
- background: #343a40;
166
- color: white;
166
+ background: #1e1e1e;
167
+ color: #f0f0f0;
167
168
  padding: 20px;
168
169
  text-align: center;
169
170
  }
@@ -185,21 +186,23 @@ module LogViewer
185
186
  table-layout: fixed;
186
187
  }
187
188
  th {
188
- background: #e9ecef;
189
+ background: #3a3a3a;
190
+ color: #f0f0f0;
189
191
  padding: 18px;
190
192
  text-align: left;
191
193
  font-weight: 600;
192
- border-bottom: 2px solid #dee2e6;
194
+ border-bottom: 2px solid #555555;
193
195
  position: sticky;
194
196
  top: 0;
195
197
  }
196
198
  td {
197
199
  padding: 15px 18px;
198
- border-bottom: 1px solid #dee2e6;
200
+ border-bottom: 1px solid #404040;
199
201
  vertical-align: top;
202
+ color: #e0e0e0;
200
203
  }
201
204
  tr:hover {
202
- background-color: #f8f9fa;
205
+ background-color: #3a3a3a;
203
206
  }
204
207
  .level {
205
208
  font-weight: bold;
@@ -215,14 +218,14 @@ module LogViewer
215
218
  .file {
216
219
  font-family: 'Monaco', 'Menlo', monospace;
217
220
  font-size: 16px;
218
- color: #666;
221
+ color: #b0b0b0;
219
222
  max-width: 200px;
220
223
  word-wrap: break-word;
221
224
  }
222
225
  .method {
223
226
  font-family: 'Monaco', 'Menlo', monospace;
224
227
  font-size: 16px;
225
- color: #333;
228
+ color: #d0d0d0;
226
229
  font-weight: 500;
227
230
  max-width: 300px;
228
231
  word-wrap: break-word;
@@ -231,18 +234,18 @@ module LogViewer
231
234
  .timestamp {
232
235
  font-family: 'Monaco', 'Menlo', monospace;
233
236
  font-size: 15px;
234
- color: #666;
237
+ color: #b0b0b0;
235
238
  white-space: nowrap;
236
239
  }
237
240
  .tag {
238
241
  font-family: 'Monaco', 'Menlo', monospace;
239
242
  font-size: 16px;
240
- color: #007acc;
243
+ color: #5dade2;
241
244
  font-weight: 500;
242
245
  }
243
246
 
244
247
  .empty {
245
- color: #999;
248
+ color: #777;
246
249
  font-style: italic;
247
250
  }
248
251
  </style>
@@ -252,6 +255,24 @@ module LogViewer
252
255
  <div class="header">
253
256
  <h1>Log Viewer</h1>
254
257
  <p>#{File.basename(@input_file)} • #{logs.length} entries • Level: #{@min_level.upcase}+</p>
258
+ <div style="margin-top: 15px;">
259
+ <label for="levelFilter" style="color: white; margin-right: 10px;">Filter by level:</label>
260
+ <select id="levelFilter" style="padding: 5px; font-size: 14px; border-radius: 4px; border: none; background-color: #3a3a3a; color: #f0f0f0;">
261
+ HTML
262
+
263
+ # Generate dropdown options only for levels >= command line minimum
264
+ min_level_num = LOG_LEVELS[@min_level]
265
+ LOG_LEVELS.each do |level, level_num|
266
+ if level_num >= min_level_num
267
+ html += <<~HTML
268
+ <option value="#{level}">#{level.upcase}+</option>
269
+ HTML
270
+ end
271
+ end
272
+
273
+ html += <<~HTML
274
+ </select>
275
+ </div>
255
276
  </div>
256
277
  <div class="table-container">
257
278
  <table>
@@ -279,7 +300,7 @@ module LogViewer
279
300
  method_content = log[:method].empty? ? '<span class="empty">-</span>' : log[:method]
280
301
 
281
302
  html += <<~HTML
282
- <tr>
303
+ <tr data-level="#{log[:level].downcase}" data-level-num="#{LOG_LEVELS[log[:level].downcase] || 0}">
283
304
  <td class="timestamp">#{timestamp_content}</td>
284
305
  <td class="level" style="#{level_style}">#{log[:level]}</td>
285
306
  <td class="tag">#{tag_content}</td>
@@ -295,6 +316,51 @@ module LogViewer
295
316
  </table>
296
317
  </div>
297
318
  </div>
319
+
320
+ <script>
321
+ const LOG_LEVELS = {
322
+ 'trace': 0,
323
+ 'debug': 1,
324
+ 'info': 2,
325
+ 'warning': 3,
326
+ 'error': 4,
327
+ 'fatal': 5
328
+ };
329
+
330
+ const levelFilter = document.getElementById('levelFilter');
331
+ const tableRows = document.querySelectorAll('tbody tr');
332
+
333
+ // Set initial filter to match command line parameter
334
+ levelFilter.value = '#{@min_level}';
335
+
336
+ function filterByLevel() {
337
+ const selectedLevel = levelFilter.value;
338
+ const selectedLevelNum = LOG_LEVELS[selectedLevel];
339
+ let visibleCount = 0;
340
+
341
+ tableRows.forEach(row => {
342
+ const rowLevelNum = parseInt(row.dataset.levelNum);
343
+ if (rowLevelNum >= selectedLevelNum) {
344
+ row.style.display = '';
345
+ visibleCount++;
346
+ } else {
347
+ row.style.display = 'none';
348
+ }
349
+ });
350
+
351
+ // Update the header count
352
+ const header = document.querySelector('.header p');
353
+ const originalText = header.textContent.split(' • ');
354
+ originalText[1] = visibleCount + ' entries';
355
+ originalText[2] = 'Level: ' + selectedLevel.toUpperCase() + '+';
356
+ header.textContent = originalText.join(' • ');
357
+ }
358
+
359
+ levelFilter.addEventListener('change', filterByLevel);
360
+
361
+ // Apply initial filter
362
+ filterByLevel();
363
+ </script>
298
364
  </body>
299
365
  </html>
300
366
  HTML
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logviewer
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.7
4
+ version: 1.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Bishop