log4lab 0.0.2__tar.gz

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.
log4lab-0.0.2/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Thibaut Lamadon
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
log4lab-0.0.2/PKG-INFO ADDED
@@ -0,0 +1,222 @@
1
+ Metadata-Version: 2.4
2
+ Name: log4lab
3
+ Version: 0.0.2
4
+ Summary: A lightweight structured log viewer with live streaming and filters.
5
+ Author: Thibaut Lamadon
6
+ License: MIT License
7
+
8
+ Copyright (c) 2025 Thibaut Lamadon
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Project-URL: Homepage, https://github.com/tlamadon/log4lab
29
+ Project-URL: Repository, https://github.com/tlamadon/log4lab
30
+ Project-URL: Issues, https://github.com/tlamadon/log4lab/issues
31
+ Keywords: logging,log-viewer,structured-logs,jsonl,monitoring,dashboard,live-streaming
32
+ Classifier: Development Status :: 4 - Beta
33
+ Classifier: Intended Audience :: Developers
34
+ Classifier: Programming Language :: Python :: 3
35
+ Classifier: Programming Language :: Python :: 3.8
36
+ Classifier: Programming Language :: Python :: 3.9
37
+ Classifier: Programming Language :: Python :: 3.10
38
+ Classifier: Programming Language :: Python :: 3.11
39
+ Classifier: Programming Language :: Python :: 3.12
40
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
41
+ Classifier: Topic :: System :: Logging
42
+ Classifier: Topic :: System :: Monitoring
43
+ Requires-Python: >=3.8
44
+ Description-Content-Type: text/markdown
45
+ License-File: LICENSE
46
+ Requires-Dist: fastapi
47
+ Requires-Dist: uvicorn
48
+ Requires-Dist: jinja2
49
+ Requires-Dist: typer
50
+ Requires-Dist: rich>=13.0.0
51
+ Provides-Extra: test
52
+ Requires-Dist: pytest>=7.0; extra == "test"
53
+ Requires-Dist: pytest-asyncio>=0.21; extra == "test"
54
+ Requires-Dist: pytest-cov>=4.0; extra == "test"
55
+ Requires-Dist: httpx>=0.24; extra == "test"
56
+ Provides-Extra: images
57
+ Requires-Dist: term-image>=0.7.0; extra == "images"
58
+ Dynamic: license-file
59
+
60
+ # Log4Lab
61
+
62
+ A lightweight structured log viewer with live streaming, filtering, and rich content rendering.
63
+
64
+ Log4Lab is a web-based dashboard for viewing and analyzing structured JSON logs in real-time. It provides a clean interface for monitoring application logs with live updates, making it easy to track experiments and debug issues.
65
+
66
+ ## Installation
67
+
68
+ ### Using pipx (Recommended)
69
+
70
+ Install log4lab as an isolated application:
71
+
72
+ ```bash
73
+ pipx install log4lab
74
+ ```
75
+
76
+ ### Using pip
77
+
78
+ ```bash
79
+ pip install log4lab
80
+ ```
81
+
82
+ ### From source
83
+
84
+ ```bash
85
+ git clone https://github.com/tlamadon/log4lab.git
86
+ cd log4lab
87
+ pip install -e .
88
+ ```
89
+
90
+ ## Quick Start
91
+
92
+ 1. **Start the web interface:**
93
+ ```bash
94
+ log4lab serve logs/app.log
95
+ ```
96
+ Then open http://localhost:8000
97
+
98
+ 2. **View logs in terminal:**
99
+ ```bash
100
+ log4lab tail logs/app.log
101
+ ```
102
+
103
+ 3. **Export to HTML:**
104
+ ```bash
105
+ log4lab export logs/app.log -o report.html
106
+ ```
107
+
108
+ ## Log Format
109
+
110
+ Log4Lab expects JSONL format (one JSON object per line):
111
+
112
+ ```json
113
+ {"time": "2025-02-03T10:30:00Z", "level": "INFO", "section": "train", "message": "Training started"}
114
+ {"time": "2025-02-03T10:30:05Z", "level": "WARN", "section": "data", "message": "Missing data point"}
115
+ {"time": "2025-02-03T10:30:10Z", "level": "ERROR", "section": "model", "message": "Model failed to converge"}
116
+ ```
117
+
118
+ ### With Rich Content
119
+
120
+ Log4Lab can display various file types when you include a `cache_path` field:
121
+
122
+ ```json
123
+ {
124
+ "time": "2025-02-03T10:30:00Z",
125
+ "level": "INFO",
126
+ "section": "train",
127
+ "message": "Training complete",
128
+ "cache_path": "artifacts/results.png",
129
+ "run_name": "experiment_1",
130
+ "accuracy": 0.95
131
+ }
132
+ ```
133
+
134
+ **Supported content types:**
135
+ - **Images**: PNG, JPG, SVG, etc. (displayed inline)
136
+ - **Code files**: Python, JavaScript, JSON, YAML, etc. (syntax highlighted, collapsible)
137
+ - **Markdown**: .md files (rendered as HTML, collapsible)
138
+ - **PDFs**: Embedded viewer
139
+ - **Other files**: Download links
140
+
141
+ ### Core Fields
142
+
143
+ - `time`: Timestamp in ISO 8601 format
144
+ - `level`: Log level (INFO, WARN, ERROR, DEBUG)
145
+ - `section`: Component or module name
146
+ - `message` or `msg`: Main log message
147
+ - `cache_path`: Path to artifact file
148
+ - `run_name`: Name of the run collection
149
+ - `run_id`: Unique run identifier
150
+
151
+ Any additional fields are shown in the expandable JSON view.
152
+
153
+ ## Commands
154
+
155
+ ### Serve (Web Interface)
156
+
157
+ ```bash
158
+ log4lab serve [LOGFILE]
159
+
160
+ # Options:
161
+ --host 0.0.0.0 # Bind to all interfaces (default: 127.0.0.1)
162
+ --port 3000 # Custom port (default: 8000)
163
+ --reload # Auto-reload for development
164
+ ```
165
+
166
+ ### Tail (Terminal)
167
+
168
+ ```bash
169
+ log4lab tail [LOGFILE]
170
+
171
+ # Options:
172
+ --level ERROR # Filter by log level
173
+ --open-images # Open images automatically
174
+ ```
175
+
176
+ ### Export
177
+
178
+ ```bash
179
+ log4lab export [LOGFILE] -o output.html
180
+
181
+ # Options:
182
+ -o, --output FILE # Output file path
183
+ -t, --title TEXT # Custom page title
184
+ --no-embed-images # Don't embed images (smaller file)
185
+ ```
186
+
187
+ ## Filtering
188
+
189
+ The web interface supports:
190
+ - **Level filtering**: Dropdown with all levels found in logs
191
+ - **Text filters**: Section, run name, run ID (partial matching)
192
+ - **Time range**: Last 1m, 5m, 30m, 1h, 6h, 24h
193
+ - **URL filters**: Bookmark and share filtered views
194
+
195
+ ```
196
+ # Filter by error logs from last hour
197
+ http://localhost:8000/?level=error&time=3600
198
+
199
+ # View specific run
200
+ http://localhost:8000/?run_name=experiment_1
201
+ ```
202
+
203
+ ## Use Cases
204
+
205
+ **Machine Learning**: Track training runs with metrics and plots
206
+ ```json
207
+ {"run_name": "resnet_training", "epoch": 10, "loss": 0.23, "cache_path": "plots/loss.png"}
208
+ ```
209
+
210
+ **Debugging**: Monitor distributed systems across components
211
+ ```json
212
+ {"section": "api", "level": "ERROR", "message": "Connection timeout", "duration_ms": 5000}
213
+ ```
214
+
215
+ **Research**: Document experiments with artifacts
216
+ ```json
217
+ {"run_name": "param_sweep", "message": "Testing lr=0.001", "cache_path": "results.pdf"}
218
+ ```
219
+
220
+ ## License
221
+
222
+ MIT
@@ -0,0 +1,163 @@
1
+ # Log4Lab
2
+
3
+ A lightweight structured log viewer with live streaming, filtering, and rich content rendering.
4
+
5
+ Log4Lab is a web-based dashboard for viewing and analyzing structured JSON logs in real-time. It provides a clean interface for monitoring application logs with live updates, making it easy to track experiments and debug issues.
6
+
7
+ ## Installation
8
+
9
+ ### Using pipx (Recommended)
10
+
11
+ Install log4lab as an isolated application:
12
+
13
+ ```bash
14
+ pipx install log4lab
15
+ ```
16
+
17
+ ### Using pip
18
+
19
+ ```bash
20
+ pip install log4lab
21
+ ```
22
+
23
+ ### From source
24
+
25
+ ```bash
26
+ git clone https://github.com/tlamadon/log4lab.git
27
+ cd log4lab
28
+ pip install -e .
29
+ ```
30
+
31
+ ## Quick Start
32
+
33
+ 1. **Start the web interface:**
34
+ ```bash
35
+ log4lab serve logs/app.log
36
+ ```
37
+ Then open http://localhost:8000
38
+
39
+ 2. **View logs in terminal:**
40
+ ```bash
41
+ log4lab tail logs/app.log
42
+ ```
43
+
44
+ 3. **Export to HTML:**
45
+ ```bash
46
+ log4lab export logs/app.log -o report.html
47
+ ```
48
+
49
+ ## Log Format
50
+
51
+ Log4Lab expects JSONL format (one JSON object per line):
52
+
53
+ ```json
54
+ {"time": "2025-02-03T10:30:00Z", "level": "INFO", "section": "train", "message": "Training started"}
55
+ {"time": "2025-02-03T10:30:05Z", "level": "WARN", "section": "data", "message": "Missing data point"}
56
+ {"time": "2025-02-03T10:30:10Z", "level": "ERROR", "section": "model", "message": "Model failed to converge"}
57
+ ```
58
+
59
+ ### With Rich Content
60
+
61
+ Log4Lab can display various file types when you include a `cache_path` field:
62
+
63
+ ```json
64
+ {
65
+ "time": "2025-02-03T10:30:00Z",
66
+ "level": "INFO",
67
+ "section": "train",
68
+ "message": "Training complete",
69
+ "cache_path": "artifacts/results.png",
70
+ "run_name": "experiment_1",
71
+ "accuracy": 0.95
72
+ }
73
+ ```
74
+
75
+ **Supported content types:**
76
+ - **Images**: PNG, JPG, SVG, etc. (displayed inline)
77
+ - **Code files**: Python, JavaScript, JSON, YAML, etc. (syntax highlighted, collapsible)
78
+ - **Markdown**: .md files (rendered as HTML, collapsible)
79
+ - **PDFs**: Embedded viewer
80
+ - **Other files**: Download links
81
+
82
+ ### Core Fields
83
+
84
+ - `time`: Timestamp in ISO 8601 format
85
+ - `level`: Log level (INFO, WARN, ERROR, DEBUG)
86
+ - `section`: Component or module name
87
+ - `message` or `msg`: Main log message
88
+ - `cache_path`: Path to artifact file
89
+ - `run_name`: Name of the run collection
90
+ - `run_id`: Unique run identifier
91
+
92
+ Any additional fields are shown in the expandable JSON view.
93
+
94
+ ## Commands
95
+
96
+ ### Serve (Web Interface)
97
+
98
+ ```bash
99
+ log4lab serve [LOGFILE]
100
+
101
+ # Options:
102
+ --host 0.0.0.0 # Bind to all interfaces (default: 127.0.0.1)
103
+ --port 3000 # Custom port (default: 8000)
104
+ --reload # Auto-reload for development
105
+ ```
106
+
107
+ ### Tail (Terminal)
108
+
109
+ ```bash
110
+ log4lab tail [LOGFILE]
111
+
112
+ # Options:
113
+ --level ERROR # Filter by log level
114
+ --open-images # Open images automatically
115
+ ```
116
+
117
+ ### Export
118
+
119
+ ```bash
120
+ log4lab export [LOGFILE] -o output.html
121
+
122
+ # Options:
123
+ -o, --output FILE # Output file path
124
+ -t, --title TEXT # Custom page title
125
+ --no-embed-images # Don't embed images (smaller file)
126
+ ```
127
+
128
+ ## Filtering
129
+
130
+ The web interface supports:
131
+ - **Level filtering**: Dropdown with all levels found in logs
132
+ - **Text filters**: Section, run name, run ID (partial matching)
133
+ - **Time range**: Last 1m, 5m, 30m, 1h, 6h, 24h
134
+ - **URL filters**: Bookmark and share filtered views
135
+
136
+ ```
137
+ # Filter by error logs from last hour
138
+ http://localhost:8000/?level=error&time=3600
139
+
140
+ # View specific run
141
+ http://localhost:8000/?run_name=experiment_1
142
+ ```
143
+
144
+ ## Use Cases
145
+
146
+ **Machine Learning**: Track training runs with metrics and plots
147
+ ```json
148
+ {"run_name": "resnet_training", "epoch": 10, "loss": 0.23, "cache_path": "plots/loss.png"}
149
+ ```
150
+
151
+ **Debugging**: Monitor distributed systems across components
152
+ ```json
153
+ {"section": "api", "level": "ERROR", "message": "Connection timeout", "duration_ms": 5000}
154
+ ```
155
+
156
+ **Research**: Document experiments with artifacts
157
+ ```json
158
+ {"run_name": "param_sweep", "message": "Testing lr=0.001", "cache_path": "results.pdf"}
159
+ ```
160
+
161
+ ## License
162
+
163
+ MIT
@@ -0,0 +1 @@
1
+ __version__ = "0.1.0"
@@ -0,0 +1,123 @@
1
+ import typer
2
+ import uvicorn
3
+ from pathlib import Path
4
+ from typing import Optional
5
+ from . import server
6
+ from .tail import LogTailer
7
+ from .export import export_logs_to_html
8
+
9
+ app = typer.Typer(help="Log4Lab — a lightweight structured log dashboard")
10
+
11
+
12
+ @app.command()
13
+ def serve(
14
+ logfile: Path = typer.Argument(
15
+ "logs/app.log",
16
+ exists=False,
17
+ help="Path to the JSONL log file to stream (default: logs/app.log)"
18
+ ),
19
+ host: str = typer.Option("127.0.0.1", help="Host to bind to"),
20
+ port: int = typer.Option(8000, help="Port to listen on"),
21
+ reload: bool = typer.Option(False, help="Enable auto-reload"),
22
+ ):
23
+ """Start the Log4Lab web server."""
24
+ server.set_log_path(logfile)
25
+ try:
26
+ uvicorn.run(
27
+ "log4lab.server:app",
28
+ host=host,
29
+ port=port,
30
+ reload=reload,
31
+ timeout_graceful_shutdown=0 # Exit immediately on CTRL-C
32
+ )
33
+ except KeyboardInterrupt:
34
+ pass # Exit immediately without waiting
35
+
36
+
37
+ @app.command()
38
+ def tail(
39
+ logfile: Path = typer.Argument(
40
+ "logs/app.log",
41
+ help="Path to the JSONL log file to tail"
42
+ ),
43
+ level: Optional[str] = typer.Option(None, "--level", "-l", help="Filter by log level (e.g., INFO, ERROR)"),
44
+ section: Optional[str] = typer.Option(None, "--section", "-s", help="Filter by section name"),
45
+ run_name: Optional[str] = typer.Option(None, "--run-name", "-r", help="Filter by run name"),
46
+ run_id: Optional[str] = typer.Option(None, "--run-id", help="Filter by run ID"),
47
+ group: Optional[str] = typer.Option(None, "--group", "-g", help="Filter by group name"),
48
+ time_range: Optional[int] = typer.Option(None, "--time-range", "-t", help="Only show logs from last N seconds"),
49
+ follow: bool = typer.Option(True, "--follow/--no-follow", "-f", help="Follow log file for new entries"),
50
+ show_images: bool = typer.Option(True, "--images/--no-images", help="Try to show images inline in terminal"),
51
+ open_images: bool = typer.Option(False, "--open-images", help="Open images in system default viewer (Preview, etc.)"),
52
+ ):
53
+ """Tail logs to the terminal with rich formatting and filters."""
54
+ tailer = LogTailer(
55
+ log_path=logfile,
56
+ level=level,
57
+ section=section,
58
+ run_name=run_name,
59
+ run_id=run_id,
60
+ group=group,
61
+ time_range=time_range,
62
+ follow=follow,
63
+ show_images=show_images,
64
+ open_images=open_images,
65
+ )
66
+ try:
67
+ tailer.tail()
68
+ except KeyboardInterrupt:
69
+ pass # Clean exit on Ctrl+C
70
+
71
+
72
+ @app.command()
73
+ def export(
74
+ logfile: Path = typer.Argument(
75
+ "logs/app.log",
76
+ help="Path to the JSONL log file to export"
77
+ ),
78
+ output: Path = typer.Option(
79
+ "logs-export.html",
80
+ "--output", "-o",
81
+ help="Output HTML file path"
82
+ ),
83
+ title: str = typer.Option(
84
+ "Log4Lab Export",
85
+ "--title", "-t",
86
+ help="Title for the HTML page"
87
+ ),
88
+ no_embed_images: bool = typer.Option(
89
+ False,
90
+ "--no-embed-images",
91
+ help="Don't embed images as base64 (reduces file size but images won't be included)"
92
+ ),
93
+ ):
94
+ """Export logs to a self-contained HTML file with embedded images and working filters."""
95
+ if not logfile.exists():
96
+ typer.echo(f"Error: Log file '{logfile}' does not exist.", err=True)
97
+ raise typer.Exit(1)
98
+
99
+ typer.echo(f"Exporting logs from '{logfile}' to '{output}'...")
100
+
101
+ try:
102
+ export_logs_to_html(
103
+ log_path=logfile,
104
+ output_path=output,
105
+ title=title,
106
+ embed_images=not no_embed_images
107
+ )
108
+
109
+ file_size = output.stat().st_size
110
+ size_mb = file_size / (1024 * 1024)
111
+
112
+ typer.echo(f"✓ Export complete! File size: {size_mb:.2f} MB")
113
+ typer.echo(f"✓ Saved to: {output.absolute()}")
114
+ typer.echo(f"\nOpen the file in your browser to view the logs with working filters.")
115
+
116
+ except Exception as e:
117
+ typer.echo(f"Error during export: {e}", err=True)
118
+ raise typer.Exit(1)
119
+
120
+
121
+ if __name__ == "__main__":
122
+ app()
123
+