Interactive log viewer with charts and visualizations for FastAPI and Flask
Project description
loglensx
loglensx is an interactive log viewer and analysis toolkit for Python applications. It parses standard application log files, summarizes errors and warnings, generates Plotly visualizations, and adds a professional dashboard to FastAPI or Flask apps with a single setup function.
It is designed for teams that want a lightweight operational view of local or server-side logs without deploying a full observability stack.
Highlights
- Framework integrations for FastAPI and Flask
- Responsive dashboard with metric cards, Plotly charts, and searchable tables
- Log explorer with filters for search text, level, logger, source file, time window, and row limits
- JSON APIs for logs, statistics, search results, export, and log file metadata
- Standalone parser and analyzer APIs for scripts, notebooks, and CLI workflows
- JSON-line log parsing, custom regex parsing, and multiline traceback folding
- JSON, CSV, and NDJSON export helpers
- Plotly figure JSON generation for custom dashboards or static viewers
- Support for common Python logging formats and custom regex parsing
Installation
Install the core package:
pip install loglensx
Install with a web framework extra:
pip install "loglensx[flask]"
pip install "loglensx[fastapi]"
Install for local development:
pip install -e ".[dev,flask,fastapi]"
Quick Start
Flask
import logging
import os
from datetime import datetime
from flask import Flask, jsonify
from loglensx import setup_flask_loglensx
app = Flask(__name__)
os.makedirs("logs", exist_ok=True)
log_file = f"logs/log_file_{datetime.now().strftime('%Y-%m-%d')}.log"
logging.basicConfig(
level=logging.INFO,
format="[%(asctime)s] [%(levelname)s] [%(name)s] %(message)s",
handlers=[logging.FileHandler(log_file), logging.StreamHandler()],
)
logger = logging.getLogger(__name__)
setup_flask_loglensx(app, log_dir="logs", prefix="/loglensx")
@app.route("/")
def home():
logger.info("Home page accessed")
return jsonify({"status": "ok", "dashboard": "/loglensx/"})
if __name__ == "__main__":
app.run(port=5000)
Run the app and open:
http://127.0.0.1:5000/loglensx/
FastAPI
import logging
import os
from datetime import datetime
from fastapi import FastAPI
from loglensx import setup_fastapi_loglensx
app = FastAPI()
os.makedirs("logs", exist_ok=True)
log_file = f"logs/log_file_{datetime.now().strftime('%Y-%m-%d')}.log"
logging.basicConfig(
level=logging.INFO,
format="[%(asctime)s] [%(levelname)s] [%(name)s] %(message)s",
handlers=[logging.FileHandler(log_file), logging.StreamHandler()],
)
logger = logging.getLogger(__name__)
setup_fastapi_loglensx(app, log_dir="logs", prefix="/loglensx")
@app.get("/")
def home():
logger.info("Root endpoint accessed")
return {"status": "ok", "dashboard": "/loglensx/"}
Run the app and open:
uvicorn main:app --reload
http://127.0.0.1:8000/loglensx/
Standalone Analysis
from loglensx import LogAnalyzer, LogParser
parser = LogParser(log_dir="logs")
analyzer = LogAnalyzer(parser)
summary = analyzer.get_log_summary()
print(summary["total_logs"], "logs parsed")
print(summary["error_count"], "errors found")
for entry in analyzer.get_recent_errors(limit=5):
print(entry["timestamp"], entry["message"])
Dashboard
The integrated dashboard includes:
- Summary metrics for total logs, errors, warnings, loggers, files, and stability score
- Log level distribution chart
- Error frequency timeline
- Top loggers chart
- Recent errors table with expandable long messages
- Log explorer with server-side filters and client-side table search
- Responsive layout for desktop and mobile screens
Mount path is controlled by the prefix argument:
setup_flask_loglensx(app, log_dir="logs", prefix="/internal/logs")
setup_fastapi_loglensx(app, log_dir="logs", prefix="/internal/logs")
API Reference
When the dashboard is mounted at /loglensx, these routes are available:
| Route | Description |
|---|---|
GET /loglensx/ |
Dashboard UI |
GET /loglensx/logs |
Log explorer UI |
GET /loglensx/api/logs |
Filtered log entries as JSON |
GET /loglensx/api/stats |
Summary statistics, level counts, top loggers, and error frequency |
GET /loglensx/api/search |
Search log entries |
GET /loglensx/api/export |
Export filtered log entries as JSON, CSV, or NDJSON |
GET /loglensx/api/files |
Log file metadata |
Common query parameters for /api/logs and /logs:
| Parameter | Example | Description |
|---|---|---|
search |
database |
Match text in log messages |
level |
ERROR |
Filter by log level |
logger |
app.api |
Match logger names |
file |
app.log |
Match source log file names |
since |
2024-01-15T10:30:00 |
Include entries at or after this timestamp |
until |
2024-01-15T11:00:00 |
Include entries at or before this timestamp |
limit |
100 |
Maximum rows to return |
Examples:
curl "http://127.0.0.1:5000/loglensx/api/logs?level=ERROR&limit=20"
curl "http://127.0.0.1:5000/loglensx/api/logs?file=app.log&since=2024-01-15T10:30:00"
curl "http://127.0.0.1:5000/loglensx/api/stats"
curl "http://127.0.0.1:5000/loglensx/api/search?query=timeout"
curl "http://127.0.0.1:5000/loglensx/api/export?format=csv&level=ERROR"
Log Format
The default parser supports log lines like this:
[2024-01-15 10:30:45] [ERROR] [app.database] Connection timeout
[2024-01-15 10:30:46] [WARNING] [app.cache] Cache miss
[2024-01-15 10:30:47] [INFO] [app.api] GET /users - 200
Recommended Python logging format:
logging.basicConfig(
level=logging.INFO,
format="[%(asctime)s] [%(levelname)s] [%(name)s] %(message)s",
handlers=[logging.FileHandler("logs/app.log"), logging.StreamHandler()],
)
You can also provide a custom regex pattern:
from loglensx import LogParser
pattern = r"(?P<timestamp>.*?)\\|(?P<level>\\w+)\\|(?P<logger>.*?)\\|(?P<message>.*)"
parser = LogParser(log_dir="logs", pattern=pattern)
The pattern should use named groups where possible:
timestamplevelloggermessage
loglensx also understands common JSON-line logs:
{"time":"2024-01-15T10:30:45","severity":"error","name":"app.api","event":"Request failed","request_id":"abc123"}
Continuation lines such as Python tracebacks are folded into the previous parsed log entry, so an exception stays attached to the event that created it.
Visualization JSON
ChartGenerator returns Plotly figure JSON. You can save that JSON and render it in any page that loads Plotly.
from pathlib import Path
from loglensx import LogAnalyzer, LogParser
from loglensx.visualizers import ChartGenerator
parser = LogParser(log_dir="logs")
analyzer = LogAnalyzer(parser)
Path("visualizations").mkdir(exist_ok=True)
Path("visualizations/level_distribution.json").write_text(
ChartGenerator.plotly_level_distribution(analyzer.get_level_statistics())
)
Path("visualizations/error_timeline.json").write_text(
ChartGenerator.plotly_error_timeline(analyzer.get_error_frequency())
)
Path("visualizations/top_loggers.json").write_text(
ChartGenerator.plotly_top_loggers(analyzer.get_top_loggers(limit=10))
)
This repository includes a simple viewer at visualizations/index.html. Serve the project folder and open the viewer:
python -m http.server 8080
http://127.0.0.1:8080/visualizations/
Core API
LogParser
from loglensx import LogParser
parser = LogParser(log_dir="logs")
files = parser.get_log_files(limit=5)
entries = parser.parse_all_logs()
matches = parser.search_logs("timeout", limit=50)
by_level = parser.parse_logs_by_level()
LogAnalyzer
from loglensx import LogAnalyzer
analyzer = LogAnalyzer(parser)
summary = analyzer.get_log_summary()
level_stats = analyzer.get_level_statistics()
top_loggers = analyzer.get_top_loggers(limit=10)
error_frequency = analyzer.get_error_frequency(hours=24)
recent_errors = analyzer.get_recent_errors(limit=10)
filtered = analyzer.filter_logs(
level="ERROR",
logger="database",
source_file="app.log",
search_term="timeout",
since="2024-01-15T10:00:00",
until="2024-01-15T11:00:00",
limit=100,
)
patterns = analyzer.get_error_patterns(limit=10)
files = analyzer.get_file_statistics()
LogExporter
from loglensx import LogExporter
logs = analyzer.filter_logs(level="ERROR", limit=100)
json_payload = LogExporter.to_json(logs)
csv_payload = LogExporter.to_csv(logs)
ndjson_payload = LogExporter.to_ndjson(logs)
LogExporter.export(logs, format="csv", output_path="errors.csv")
TableGenerator
from loglensx.visualizers import TableGenerator
html = TableGenerator.logs_to_html_table(recent_errors, title="Recent Errors")
Examples
Complete examples are available in the examples/ directory:
| File | Purpose |
|---|---|
examples/flask_example.py |
Flask app with dashboard routes |
examples/fastapi_example.py |
FastAPI app with dashboard routes |
examples/standalone_example.py |
Parser, analyzer, and visualization JSON workflow |
Run the Flask example:
python examples/flask_example.py
Run the FastAPI example:
python examples/fastapi_example.py
Run the standalone example:
python examples/standalone_example.py
CLI
After installation, loglensx provides terminal workflows for summaries, filtered log inspection, recurring error patterns, file metadata, and exports:
loglensx
loglensx summary --log-dir logs --format json
loglensx logs --level ERROR --since 2024-01-15T10:00:00 --format csv --output errors.csv
loglensx logs --search timeout --file app.log --limit 20
loglensx patterns --limit 10
loglensx files --format json
Running loglensx without a subcommand keeps the original quick summary behavior.
Project Structure
loglensx/
core/
parser.py
analyzer.py
exporter.py
integrations/
fastapi_integration.py
flask_integration.py
_dashboard.py
visualizers/
charts.py
tables.py
examples/
tests/
visualizations/
Development
Create a local environment and install development dependencies:
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev,flask,fastapi]"
Run tests:
pytest
Run tests with coverage when pytest-cov is installed:
pytest --cov=loglensx --cov-report=html --cov-report=term-missing
Troubleshooting
Dashboard page does not open
- Confirm the Flask or FastAPI server is running.
- Use the correct prefix, for example
/loglensx/. - Check that the framework extra is installed:
loglensx[flask]orloglensx[fastapi].
Logs are not visible
- Confirm
log_dirpoints to the directory where log files are written. - Confirm files have a
.logextension. - Confirm your log format matches the default parser or pass a custom regex pattern.
- Generate a test log entry and refresh the dashboard.
Visualization JSON opens as raw text
The JSON files are data, not standalone charts. Use visualizations/index.html through a local server:
python -m http.server 8080
Then open http://127.0.0.1:8080/visualizations/.
Import fails when running examples directly
Run examples from the repository root:
python examples/flask_example.py
python examples/fastapi_example.py
For installed usage, install the package first:
pip install -e ".[flask,fastapi]"
License
This project is licensed under the MIT License. See LICENSE for details.
Support
Open issues and feature requests on the project issue tracker:
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file loglensx-1.0.4.tar.gz.
File metadata
- Download URL: loglensx-1.0.4.tar.gz
- Upload date:
- Size: 59.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
99f0706295f67bd700c75507aea36eeaf13549fe04ea14a9db496bf1bfd021e3
|
|
| MD5 |
abd1a85b7fd1a4a159c5e9f3e5986937
|
|
| BLAKE2b-256 |
14348873092839bca66f6b7bfdca1bab1838ee68570ecbf9d96f5b75212e06a5
|
File details
Details for the file loglensx-1.0.4-py3-none-any.whl.
File metadata
- Download URL: loglensx-1.0.4-py3-none-any.whl
- Upload date:
- Size: 38.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d8e3b4f5b57f3b8ed82d4e469bd2e136d90a713daac7082a23bda35964775961
|
|
| MD5 |
6a455af448a4cb9afa6d5c42006556f6
|
|
| BLAKE2b-256 |
a88b88aa0f8d8137703b7fe28c869ee8fe5b0b7ea4521996172518154efb618b
|