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 +4 -4
- data/README.md +14 -2
- data/lib/logviewer/version.rb +1 -1
- data/lib/logviewer.rb +88 -22
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c2e1bf52a01e4f5ef4cb8459d5cb0b7951a03b6ac78751b5b0338e132ff28e7f
|
4
|
+
data.tar.gz: dbaa77c1b51d5f25169cb23a0d84bc5e0a685494c46f6388ed59d8c142e9e5e2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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:
|
data/lib/logviewer/version.rb
CHANGED
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
|
-
'#
|
109
|
+
'#adb5bd'
|
110
110
|
when 'debug'
|
111
|
-
'#
|
111
|
+
'#adb5bd'
|
112
112
|
when 'info'
|
113
|
-
'#
|
113
|
+
'#6ea8fe'
|
114
114
|
when 'warning'
|
115
|
-
'#
|
115
|
+
'#fd9843'
|
116
116
|
when 'error'
|
117
|
-
'#
|
117
|
+
'#ea868f'
|
118
118
|
when 'fatal'
|
119
|
-
'#
|
119
|
+
'#c29ffa'
|
120
120
|
else
|
121
|
-
'#
|
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: #
|
154
|
+
background-color: #1a1a1a;
|
155
|
+
color: #e0e0e0;
|
155
156
|
}
|
156
157
|
.container {
|
157
158
|
max-width: 1800px;
|
158
159
|
margin: 0 auto;
|
159
|
-
background:
|
160
|
+
background: #2d2d2d;
|
160
161
|
border-radius: 8px;
|
161
|
-
box-shadow: 0 2px 10px rgba(0,0,0,0.
|
162
|
+
box-shadow: 0 2px 10px rgba(0,0,0,0.3);
|
162
163
|
overflow: hidden;
|
163
164
|
}
|
164
165
|
.header {
|
165
|
-
background: #
|
166
|
-
color:
|
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: #
|
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 #
|
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 #
|
200
|
+
border-bottom: 1px solid #404040;
|
199
201
|
vertical-align: top;
|
202
|
+
color: #e0e0e0;
|
200
203
|
}
|
201
204
|
tr:hover {
|
202
|
-
background-color: #
|
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: #
|
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: #
|
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: #
|
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: #
|
243
|
+
color: #5dade2;
|
241
244
|
font-weight: 500;
|
242
245
|
}
|
243
246
|
|
244
247
|
.empty {
|
245
|
-
color: #
|
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
|