logviewer 1.0.0 → 1.5.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: 5af89372bbff4a9d1a87c53c87be966b685532e5734cddaca3d1f338ecca806d
4
- data.tar.gz: 04acdaa2c421345747cdfdaf0445aa139252bac918b74df4d41fa34b0a6451b2
3
+ metadata.gz: b6474de992dc2dea2da7f2dc840c7b8a40ebd00b7bb95d41b5f3c8daf735c825
4
+ data.tar.gz: b77161d3a5ff3ad409d2103fb9244e3e80e04d75f0acea8da23de4d4ca3f8bf4
5
5
  SHA512:
6
- metadata.gz: 7d55746ec6dddde8279deb41c50429acb38f6e3c9bd55350388aa8cda585a33c482b64e6d84acd31b45708e9f84aa239b02a6e6494a82d4f65e992b724e5417b
7
- data.tar.gz: b895f2d31c99001de43836e96c3dacd092b87c1e16fd761baf93321b2fee5a2300228614281266d07dc90926f79031fa7b2547ad647b7efa645aee01bdea8115
6
+ metadata.gz: 543273a8c965e6263d458d9fb728b8f76aacb9d1dc9d70907ae837d7555c7a428aa076d9e35402e25057696edf6f8d56e3947745ed3549bfdd283d8c169fe35b
7
+ data.tar.gz: 15c08fa5c88dd659e0963efe156a8cc02894cc18b07023851391d880f3935e4211ea0d490917f6b38980bf89d853e3dea974f11b71477b5fa4d7a2bf3d614ec6
data/README.md CHANGED
@@ -6,8 +6,11 @@ A Ruby gem that converts NDJSON log files into a readable HTML format for easy v
6
6
 
7
7
  - Converts NDJSON log files to HTML tables
8
8
  - Filters logs by minimum level (trace, debug, info, warning, error, fatal)
9
- - Displays key fields: level, text, file, and method
9
+ - Displays key fields: timestamp, level, tag, text, file, line, and method
10
+ - Human-readable timestamp formatting (MM/DD HH:MM:SS)
11
+ - Simplified file paths (shows only filename, not full path)
10
12
  - Color-coded log levels for easy identification
13
+ - Large, readable fonts throughout the interface (18px base size)
11
14
  - Responsive design that works well in any browser
12
15
  - Automatically opens the generated HTML file in your default browser
13
16
 
@@ -24,11 +27,15 @@ gem install logviewer
24
27
  ### Basic Usage
25
28
 
26
29
  ```bash
30
+ # With a specific file
27
31
  logviewer example.ndjson
32
+
33
+ # Without specifying a file (auto-detects most recent .ndjson file)
34
+ logviewer
28
35
  ```
29
36
 
30
37
  This will:
31
- 1. Parse the NDJSON file
38
+ 1. Parse the NDJSON file (or auto-detect the most recent .ndjson file in current directory)
32
39
  2. Include all log levels (debug and above)
33
40
  3. Generate an HTML file in `/tmp/`
34
41
  4. Open the HTML file in your default browser
@@ -41,6 +48,16 @@ logviewer --level info example.ndjson
41
48
 
42
49
  Only shows log entries with level "info" and above (info, warning, error, fatal).
43
50
 
51
+ ### Auto-Detection of Log Files
52
+
53
+ When no file is specified, LogViewer automatically searches the current directory for `.ndjson` files and uses the one with the most recent modification date:
54
+
55
+ ```bash
56
+ logviewer --level info
57
+ ```
58
+
59
+ This will find the most recent `.ndjson` file in the current directory and apply the specified log level filter.
60
+
44
61
  ### Command Line Options
45
62
 
46
63
  - `-l, --level LEVEL`: Set minimum log level (trace, debug, info, warning, error, fatal)
@@ -50,13 +67,16 @@ Only shows log entries with level "info" and above (info, warning, error, fatal)
50
67
  ### Examples
51
68
 
52
69
  ```bash
53
- # Show all logs
70
+ # Show all logs from a specific file
54
71
  logviewer app.ndjson
55
72
 
56
- # Show only warnings and above
57
- logviewer --level warning app.ndjson
73
+ # Auto-detect most recent .ndjson file and show all logs
74
+ logviewer
75
+
76
+ # Auto-detect most recent .ndjson file and show only warnings and above
77
+ logviewer --level warning
58
78
 
59
- # Show only errors and fatal logs
79
+ # Show only errors and fatal logs from specific file
60
80
  logviewer -l error system.ndjson
61
81
 
62
82
  # Show version
@@ -67,25 +87,33 @@ logviewer --version
67
87
 
68
88
  The tool expects NDJSON (newline-delimited JSON) files where each line contains a JSON object with these fields:
69
89
 
90
+ - `timestamp`: ISO 8601 timestamp (e.g., "2025-06-02T18:22:48.855-07:00")
70
91
  - `level`: Log level (trace, debug, info, warning, error, fatal)
92
+ - `tag`: Category or module tag (e.g., "Play/manager")
71
93
  - `text`: The log message
72
- - `file`: Source file name
94
+ - `file`: Source file path (displayed as filename only)
95
+ - `line`: Line number in the source file
73
96
  - `method`: Function/method name
74
97
 
75
98
  Example log entry:
76
99
  ```json
77
- {"level":"info","text":"User logged in successfully","file":"auth.rb","method":"login"}
100
+ {"timestamp":"2025-06-02T18:22:48.855-07:00","level":"info","tag":"Auth/manager","text":"User logged in successfully","file":"auth.rb","line":42,"method":"login"}
78
101
  ```
79
102
 
80
103
  ## Output
81
104
 
82
105
  The generated HTML file will be saved in `/tmp/` with a timestamp and automatically opened in your browser. The HTML includes:
83
106
 
84
- - A responsive table layout
107
+ - A wide, responsive table layout (1800px max width) with timestamp, level, tag, text, file, line, and method columns
108
+ - Human-readable timestamps (MM/DD HH:MM:SS format)
85
109
  - Color-coded log levels
86
110
  - Sticky header for easy navigation
87
111
  - Hover effects for better readability
88
- - File and method names in monospace font
112
+ - Large fonts (18px base size) for excellent readability
113
+ - Simplified file display (filename only, not full paths)
114
+ - Optimized column widths with expanded text area for log messages
115
+ - Timestamp, file, line, and method names in monospace font
116
+ - Color-coded tags for easy categorization
89
117
 
90
118
  ## Development
91
119
 
@@ -1,3 +1,3 @@
1
1
  module LogViewer
2
- VERSION = "1.0.0"
2
+ VERSION = "1.5.0"
3
3
  end
data/lib/logviewer.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'json'
2
2
  require 'optparse'
3
3
  require 'fileutils'
4
+ require 'time'
4
5
  require_relative 'logviewer/version'
5
6
 
6
7
  module LogViewer
@@ -22,7 +23,7 @@ module LogViewer
22
23
 
23
24
  def parse_options
24
25
  OptionParser.new do |opts|
25
- opts.banner = "Usage: logviewer [options] <ndjson_file>"
26
+ opts.banner = "Usage: logviewer [options] [ndjson_file]"
26
27
 
27
28
  opts.on('-l', '--level LEVEL', 'Minimum log level (trace, debug, info, warning, error, fatal)') do |level|
28
29
  level = level.downcase
@@ -47,19 +48,31 @@ module LogViewer
47
48
  end.parse!(@args)
48
49
 
49
50
  if @args.empty?
50
- puts "Error: Please provide an NDJSON file path"
51
- puts "Usage: logviewer [options] <ndjson_file>"
52
- exit 1
51
+ @input_file = find_most_recent_ndjson_file
52
+ if @input_file.nil?
53
+ puts "Error: No .ndjson files found in current directory"
54
+ puts "Usage: logviewer [options] [ndjson_file]"
55
+ exit 1
56
+ end
57
+ puts "No file specified, using most recent .ndjson file: #{@input_file}"
58
+ else
59
+ @input_file = @args[0]
53
60
  end
54
61
 
55
- @input_file = @args[0]
56
-
57
62
  unless File.exist?(@input_file)
58
63
  puts "Error: File not found: #{@input_file}"
59
64
  exit 1
60
65
  end
61
66
  end
62
67
 
68
+ def find_most_recent_ndjson_file
69
+ ndjson_files = Dir.glob('*.ndjson')
70
+ return nil if ndjson_files.empty?
71
+
72
+ # Sort by modification time (most recent first) and return the first one
73
+ ndjson_files.max_by { |file| File.mtime(file) }
74
+ end
75
+
63
76
  def should_include_log?(level)
64
77
  return true unless level
65
78
  LOG_LEVELS[level.downcase] >= LOG_LEVELS[@min_level]
@@ -74,9 +87,12 @@ module LogViewer
74
87
 
75
88
  if should_include_log?(log_entry['level'])
76
89
  logs << {
90
+ timestamp: log_entry['timestamp'] || '',
77
91
  level: log_entry['level'] || 'unknown',
92
+ tag: log_entry['tag'] || '',
78
93
  text: log_entry['text'] || '',
79
94
  file: log_entry['file'] || '',
95
+ line: log_entry['line'],
80
96
  method: log_entry['method'] || ''
81
97
  }
82
98
  end
@@ -107,6 +123,22 @@ module LogViewer
107
123
  end
108
124
  end
109
125
 
126
+ def format_timestamp(timestamp_str)
127
+ return '' if timestamp_str.nil? || timestamp_str.empty?
128
+
129
+ begin
130
+ time = Time.parse(timestamp_str)
131
+ time.strftime('%m/%d %H:%M:%S')
132
+ rescue => e
133
+ timestamp_str # fallback to original if parsing fails
134
+ end
135
+ end
136
+
137
+ def extract_filename(file_path)
138
+ return '' if file_path.nil? || file_path.empty?
139
+ File.basename(file_path)
140
+ end
141
+
110
142
  def generate_html(logs)
111
143
  html = <<~HTML
112
144
  <!DOCTYPE html>
@@ -123,7 +155,7 @@ module LogViewer
123
155
  background-color: #f8f9fa;
124
156
  }
125
157
  .container {
126
- max-width: 1400px;
158
+ max-width: 1800px;
127
159
  margin: 0 auto;
128
160
  background: white;
129
161
  border-radius: 8px;
@@ -150,11 +182,11 @@ module LogViewer
150
182
  table {
151
183
  width: 100%;
152
184
  border-collapse: collapse;
153
- font-size: 14px;
185
+ font-size: 18px;
154
186
  }
155
187
  th {
156
188
  background: #e9ecef;
157
- padding: 12px;
189
+ padding: 18px;
158
190
  text-align: left;
159
191
  font-weight: 600;
160
192
  border-bottom: 2px solid #dee2e6;
@@ -162,7 +194,7 @@ module LogViewer
162
194
  top: 0;
163
195
  }
164
196
  td {
165
- padding: 10px 12px;
197
+ padding: 15px 18px;
166
198
  border-bottom: 1px solid #dee2e6;
167
199
  vertical-align: top;
168
200
  }
@@ -172,27 +204,45 @@ module LogViewer
172
204
  .level {
173
205
  font-weight: bold;
174
206
  text-transform: uppercase;
175
- font-size: 12px;
207
+ font-size: 16px;
176
208
  white-space: nowrap;
177
209
  }
178
210
  .text {
179
- max-width: 600px;
211
+ min-width: 600px;
180
212
  word-wrap: break-word;
181
213
  white-space: pre-wrap;
182
214
  }
183
215
  .file {
184
216
  font-family: 'Monaco', 'Menlo', monospace;
185
- font-size: 12px;
217
+ font-size: 16px;
186
218
  color: #666;
187
219
  max-width: 200px;
188
220
  word-wrap: break-word;
189
221
  }
190
222
  .method {
191
223
  font-family: 'Monaco', 'Menlo', monospace;
192
- font-size: 12px;
224
+ font-size: 16px;
193
225
  color: #333;
194
226
  font-weight: 500;
195
227
  }
228
+ .timestamp {
229
+ font-family: 'Monaco', 'Menlo', monospace;
230
+ font-size: 15px;
231
+ color: #666;
232
+ white-space: nowrap;
233
+ }
234
+ .tag {
235
+ font-family: 'Monaco', 'Menlo', monospace;
236
+ font-size: 16px;
237
+ color: #007acc;
238
+ font-weight: 500;
239
+ }
240
+ .line {
241
+ font-family: 'Monaco', 'Menlo', monospace;
242
+ font-size: 16px;
243
+ color: #999;
244
+ text-align: right;
245
+ }
196
246
  .empty {
197
247
  color: #999;
198
248
  font-style: italic;
@@ -209,10 +259,13 @@ module LogViewer
209
259
  <table>
210
260
  <thead>
211
261
  <tr>
262
+ <th style="width: 120px;">Timestamp</th>
212
263
  <th style="width: 80px;">Level</th>
264
+ <th style="width: 120px;">Tag</th>
213
265
  <th>Text</th>
214
- <th style="width: 200px;">File</th>
215
- <th style="width: 150px;">Method</th>
266
+ <th style="width: 180px;">File</th>
267
+ <th style="width: 50px;">Line</th>
268
+ <th style="width: 100px;">Method</th>
216
269
  </tr>
217
270
  </thead>
218
271
  <tbody>
@@ -220,15 +273,23 @@ module LogViewer
220
273
 
221
274
  logs.each do |log|
222
275
  level_style = "color: #{level_color(log[:level])}"
276
+ formatted_timestamp = format_timestamp(log[:timestamp])
277
+ timestamp_content = formatted_timestamp.empty? ? '<span class="empty">-</span>' : formatted_timestamp
278
+ tag_content = log[:tag].empty? ? '<span class="empty">-</span>' : log[:tag]
223
279
  text_content = log[:text].empty? ? '<span class="empty">-</span>' : log[:text]
224
- file_content = log[:file].empty? ? '<span class="empty">-</span>' : log[:file]
280
+ filename = extract_filename(log[:file])
281
+ file_content = filename.empty? ? '<span class="empty">-</span>' : filename
282
+ line_content = log[:line].nil? ? '<span class="empty">-</span>' : log[:line]
225
283
  method_content = log[:method].empty? ? '<span class="empty">-</span>' : log[:method]
226
284
 
227
285
  html += <<~HTML
228
286
  <tr>
287
+ <td class="timestamp">#{timestamp_content}</td>
229
288
  <td class="level" style="#{level_style}">#{log[:level]}</td>
289
+ <td class="tag">#{tag_content}</td>
230
290
  <td class="text">#{text_content}</td>
231
291
  <td class="file">#{file_content}</td>
292
+ <td class="line">#{line_content}</td>
232
293
  <td class="method">#{method_content}</td>
233
294
  </tr>
234
295
  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.0.0
4
+ version: 1.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Bishop