logviewer 1.5.1 → 1.6.1

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: f8784d7513678b085069d4383c9aaed89a93e3e542bc6a053754ccb0814ef784
4
- data.tar.gz: 9beac9a4fd089a81ea1f5dd7305ab69813b830e136b954b93899965fe9ff500f
3
+ metadata.gz: 1b9106af1e9941238180f211dbbc156e1a0399bf5cca0e3f19923e4c7e6ad5d1
4
+ data.tar.gz: e6af770c419e32950450d7d65d85f43c1f85146d0a76c31615a4a2ed4ddd562b
5
5
  SHA512:
6
- metadata.gz: 84ac955ffd0d95dcc1f2d3f554911500e616a328bcde2398d80ec9d2fe552a78885c588520b2863e9b99bf28ba2547ee1a5c54ddb2736452a109de80a431cdaf
7
- data.tar.gz: ab97e9be8d51a702896c5309422599c55d9ba45b30ee2ffe8e23802817e98779f87220ff48e59ee88f3baec1c9bae1cee16ccf1d75614dbcd1698d31c3926444
6
+ metadata.gz: cc4e7bfb85ab4faa538250ac7eefde469ee1356c62bb320abfbb43416cc34821c7a586dd2ada1d0a4dfda2c034f8eb09702635b98ef2f6a891444154c1feba3c
7
+ data.tar.gz: e40ae9a7947dfa360abea65221a691990d893790ba58e572b7e78ecf7cf62060e524a5f7b92f71058e6767445313bd368b679c8ac9e3ea937927f91d894e7bf2
data/README.md CHANGED
@@ -11,6 +11,7 @@ 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
14
15
  - Responsive design that works well in any browser
15
16
  - Automatically opens the generated HTML file in your default browser
16
17
 
@@ -46,7 +47,7 @@ This will:
46
47
  logviewer --level info example.ndjson
47
48
  ```
48
49
 
49
- Only shows log entries with level "info" and above (info, warning, error, fatal).
50
+ 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
51
 
51
52
  ### Auto-Detection of Log Files
52
53
 
@@ -104,6 +105,7 @@ Example log entry:
104
105
  The generated HTML file will be saved in `/tmp/` with a timestamp and automatically opened in your browser. The HTML includes:
105
106
 
106
107
  - A wide, responsive table layout (1800px max width) with columns in order: date, level, tag, file, function, text
108
+ - Interactive log level filtering dropdown for dynamic filtering in the browser
107
109
  - Human-readable timestamps (MM/DD HH:MM:SS format)
108
110
  - Color-coded log levels
109
111
  - Sticky header for easy navigation
@@ -114,6 +116,14 @@ The generated HTML file will be saved in `/tmp/` with a timestamp and automatica
114
116
  - Date, file, and function names in monospace font
115
117
  - Color-coded tags for easy categorization
116
118
 
119
+ ## Interactive Features
120
+
121
+ Once the HTML file opens in your browser, you can:
122
+ - Use the dropdown in the header to dynamically filter log entries by minimum level
123
+ - Filter changes are applied instantly without page reload
124
+ - Entry counts update automatically to show how many entries match the current filter
125
+ - Command line level acts as the initial data set - browser filtering works within those entries
126
+
117
127
  ## Development
118
128
 
119
129
  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.1"
2
+ VERSION = "1.6.1"
3
3
  end
data/lib/logviewer.rb CHANGED
@@ -182,6 +182,7 @@ module LogViewer
182
182
  width: 100%;
183
183
  border-collapse: collapse;
184
184
  font-size: 18px;
185
+ table-layout: fixed;
185
186
  }
186
187
  th {
187
188
  background: #e9ecef;
@@ -207,9 +208,9 @@ module LogViewer
207
208
  white-space: nowrap;
208
209
  }
209
210
  .text {
210
- min-width: 600px;
211
211
  word-wrap: break-word;
212
212
  white-space: pre-wrap;
213
+ width: auto;
213
214
  }
214
215
  .file {
215
216
  font-family: 'Monaco', 'Menlo', monospace;
@@ -223,6 +224,9 @@ module LogViewer
223
224
  font-size: 16px;
224
225
  color: #333;
225
226
  font-weight: 500;
227
+ max-width: 300px;
228
+ word-wrap: break-word;
229
+ overflow-wrap: break-word;
226
230
  }
227
231
  .timestamp {
228
232
  font-family: 'Monaco', 'Menlo', monospace;
@@ -248,6 +252,24 @@ module LogViewer
248
252
  <div class="header">
249
253
  <h1>Log Viewer</h1>
250
254
  <p>#{File.basename(@input_file)} • #{logs.length} entries • Level: #{@min_level.upcase}+</p>
255
+ <div style="margin-top: 15px;">
256
+ <label for="levelFilter" style="color: white; margin-right: 10px;">Filter by level:</label>
257
+ <select id="levelFilter" style="padding: 5px; font-size: 14px; border-radius: 4px; border: none;">
258
+ HTML
259
+
260
+ # Generate dropdown options only for levels >= command line minimum
261
+ min_level_num = LOG_LEVELS[@min_level]
262
+ LOG_LEVELS.each do |level, level_num|
263
+ if level_num >= min_level_num
264
+ html += <<~HTML
265
+ <option value="#{level}">#{level.upcase}+</option>
266
+ HTML
267
+ end
268
+ end
269
+
270
+ html += <<~HTML
271
+ </select>
272
+ </div>
251
273
  </div>
252
274
  <div class="table-container">
253
275
  <table>
@@ -257,8 +279,8 @@ module LogViewer
257
279
  <th style="width: 80px;">Level</th>
258
280
  <th style="width: 120px;">Tag</th>
259
281
  <th style="width: 180px;">File</th>
260
- <th style="width: 100px;">Function</th>
261
- <th>Text</th>
282
+ <th style="width: 300px;">Function</th>
283
+ <th style="width: auto;">Text</th>
262
284
  </tr>
263
285
  </thead>
264
286
  <tbody>
@@ -275,7 +297,7 @@ module LogViewer
275
297
  method_content = log[:method].empty? ? '<span class="empty">-</span>' : log[:method]
276
298
 
277
299
  html += <<~HTML
278
- <tr>
300
+ <tr data-level="#{log[:level].downcase}" data-level-num="#{LOG_LEVELS[log[:level].downcase] || 0}">
279
301
  <td class="timestamp">#{timestamp_content}</td>
280
302
  <td class="level" style="#{level_style}">#{log[:level]}</td>
281
303
  <td class="tag">#{tag_content}</td>
@@ -291,6 +313,51 @@ module LogViewer
291
313
  </table>
292
314
  </div>
293
315
  </div>
316
+
317
+ <script>
318
+ const LOG_LEVELS = {
319
+ 'trace': 0,
320
+ 'debug': 1,
321
+ 'info': 2,
322
+ 'warning': 3,
323
+ 'error': 4,
324
+ 'fatal': 5
325
+ };
326
+
327
+ const levelFilter = document.getElementById('levelFilter');
328
+ const tableRows = document.querySelectorAll('tbody tr');
329
+
330
+ // Set initial filter to match command line parameter
331
+ levelFilter.value = '#{@min_level}';
332
+
333
+ function filterByLevel() {
334
+ const selectedLevel = levelFilter.value;
335
+ const selectedLevelNum = LOG_LEVELS[selectedLevel];
336
+ let visibleCount = 0;
337
+
338
+ tableRows.forEach(row => {
339
+ const rowLevelNum = parseInt(row.dataset.levelNum);
340
+ if (rowLevelNum >= selectedLevelNum) {
341
+ row.style.display = '';
342
+ visibleCount++;
343
+ } else {
344
+ row.style.display = 'none';
345
+ }
346
+ });
347
+
348
+ // Update the header count
349
+ const header = document.querySelector('.header p');
350
+ const originalText = header.textContent.split(' • ');
351
+ originalText[1] = visibleCount + ' entries';
352
+ originalText[2] = 'Level: ' + selectedLevel.toUpperCase() + '+';
353
+ header.textContent = originalText.join(' • ');
354
+ }
355
+
356
+ levelFilter.addEventListener('change', filterByLevel);
357
+
358
+ // Apply initial filter
359
+ filterByLevel();
360
+ </script>
294
361
  </body>
295
362
  </html>
296
363
  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.1
4
+ version: 1.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Bishop