Skip to main content

dbbasic-logs

Structured logging with TSV storage and compression.

Philosophy: "Log everything. Query anything. Compress the rest."

Part of the DBBasic family of tiny Python modules.

Features

  • Simple API: One-line logging, no setup required
  • Structured: TSV format with JSON context
  • Unix-Native: Plain text files, grep-able, compressible
  • Zero Config: Works out of the box
  • Searchable: Built-in search with regex support
  • Compressed: Automatic gzip compression for old logs
  • Multiple Log Types: Separate files for app, errors, and access logs

Installation

pip install dbbasic-logs

Quick Start

from dbbasic_logs import log

# Basic logging
log.info("User logged in", user_id=42, ip="192.168.1.1")
log.warning("Rate limit approaching", user_id=42, count=95)
log.error("Payment failed", order_id=123, error="Timeout")
log.debug("Cache miss", key="user:42")

# Exception logging with automatic stack traces
try:
    process_payment(order)
except Exception as e:
    log.exception("Payment processing failed", order_id=order.id)
    raise

# HTTP access logging
log.access(
    method="GET",
    path="/api/users",
    status=200,
    duration=0.05,
    ip=request.remote_addr
)

Storage Format

Logs are stored as TSV (tab-separated values) files organized by type and date:

data/logs/
  app/
    2025-10-09.tsv         # Today's application logs
    2025-10-08.tsv.gz      # Yesterday's logs (compressed)
    2025-10-07.tsv.gz      # Older logs (compressed)
  errors/
    2025-10-09.tsv         # Today's error logs with stack traces
    2025-10-08.tsv.gz
  access/
    2025-10-09.tsv         # Today's HTTP access logs
    2025-10-08.tsv.gz

TSV Format

Each log entry is a single line with 4 tab-separated columns:

timestamp   level   message   context

Example:

1696886400  INFO    User logged in  {"user_id":42,"ip":"192.168.1.1"}
1696886401  ERROR   Payment failed  {"order_id":123,"error":"Timeout"}

Querying Logs

Python API

from dbbasic_logs import log

# Search for errors in last 7 days
errors = log.search("ERROR", log_type='errors', days=7)
for error in errors:
    print(f"{error['timestamp']}: {error['message']}")
    print(f"  Context: {error['context']}")

# Find user activity (regex search)
user_logs = log.search(r"user_id.*42", log_type='all', days=30)

# Get recent logs
recent = log.tail('app', lines=100)

# Find slow requests
slow_requests = log.search(r'duration.*[5-9]\.', log_type='access', days=1)

Command Line (Unix Way)

# All errors today
grep ERROR data/logs/app/2025-10-09.tsv

# All errors last 7 days (including compressed)
zgrep ERROR data/logs/app/2025-10-*.tsv*

# Specific user activity
zgrep 'user_id.*42' data/logs/app/*.tsv*

# Count 500 errors
grep "status.*500" data/logs/access/2025-10-09.tsv | wc -l

# Slow requests (> 1 second)
grep "duration.*[1-9]\." data/logs/access/2025-10-09.tsv

# View logs with the included script
./scripts/view-logs.sh tail app 100
./scripts/view-logs.sh search ERROR app 7
./scripts/view-logs.sh today errors
./scripts/view-logs.sh errors 1

Log Rotation & Compression

The included rotation script automatically:

  • Compresses yesterday's logs (10:1 compression ratio)
  • Deletes old logs based on retention policy
  • Keeps errors longer than access logs

Setup Automatic Rotation

# Install to cron (runs daily)
sudo cp scripts/rotate-logs.sh /etc/cron.daily/dbbasic-logs-rotate
sudo chmod +x /etc/cron.daily/dbbasic-logs-rotate

Manual Rotation

./scripts/rotate-logs.sh

Custom Retention Policies

# Set custom retention (in days)
export APP_RETENTION_DAYS=30      # App logs (default: 30)
export ACCESS_RETENTION_DAYS=7    # Access logs (default: 30)
export ERROR_RETENTION_DAYS=90    # Error logs (default: 90)

./scripts/rotate-logs.sh

Configuration

Custom Log Directory

from dbbasic_logs import DBBasicLogger

# Use custom directory
logger = DBBasicLogger(log_dir='/var/log/myapp')
logger.info("Custom location", app="myapp")

Environment Variable

# Set globally via environment
export LOG_DIR=/var/log/myapp

# Now all logs go to /var/log/myapp
python your_app.py

Integration Examples

Flask Application

from flask import Flask, request
from dbbasic_logs import log
import time

app = Flask(__name__)

@app.before_request
def log_request_start():
    request.start_time = time.time()

@app.after_request
def log_request_end(response):
    duration = time.time() - request.start_time

    log.access(
        method=request.method,
        path=request.path,
        status=response.status_code,
        duration=duration,
        ip=request.remote_addr,
        user_agent=request.user_agent.string
    )

    return response

@app.route('/api/users/<user_id>')
def get_user(user_id):
    log.info("Fetching user", user_id=user_id, ip=request.remote_addr)

    try:
        user = User.get(user_id)
        if not user:
            log.warning("User not found", user_id=user_id)
            return {"error": "Not found"}, 404

        return user.to_dict()
    except Exception as e:
        log.exception("Error fetching user", user_id=user_id)
        return {"error": "Internal error"}, 500

Django Middleware

from dbbasic_logs import log
import time

class LoggingMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        start_time = time.time()

        response = self.get_response(request)

        duration = time.time() - start_time
        log.access(
            method=request.method,
            path=request.path,
            status=response.status_code,
            duration=duration,
            ip=request.META.get('REMOTE_ADDR'),
        )

        return response

Background Job Queue

from dbbasic_logs import log

def process_jobs(handlers):
    jobs = get_pending_jobs()
    log.info("Processing jobs", count=len(jobs))

    for job in jobs:
        try:
            log.info("Starting job", job_id=job['id'], type=job['type'])
            start = time.time()

            result = handlers[job['type']](job['payload'])

            duration = time.time() - start
            log.info("Job completed", job_id=job['id'], duration=duration)
        except Exception as e:
            log.exception("Job failed", job_id=job['id'], type=job['type'])

Performance

Benchmarks

Operation Time Notes
Write log 0.1ms Append to file
Search today 0.5s grep 10MB file
Search compressed 2s zgrep 1MB file
Tail recent 0.01s Read last N lines

Storage

Daily Logs Uncompressed Compressed 30 Days Total
Low traffic 1MB 100KB 3MB
Medium traffic 10MB 1MB 30MB
High traffic 100MB 10MB 300MB

Even high-traffic sites: < 1GB for 30 days of logs

Comparison to Alternatives

vs. Sentry (Error Tracking SaaS)

Sentry:

  • Setup: SDK integration, API keys
  • Cost: $29-$299/month
  • Features: Grouping, alerts, dashboards
  • Privacy: Sends errors to third-party

dbbasic-logs:

  • Setup: Import and use
  • Cost: $0
  • Features: TSV storage, grep search
  • Privacy: All local

vs. Python logging + RotatingFileHandler

Python stdlib:

# 8 lines just for config
import logging
from logging.handlers import RotatingFileHandler

handler = RotatingFileHandler('app.log', maxBytes=10000, backupCount=5)
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
logger = logging.getLogger('app')
logger.addHandler(handler)

logger.info("User logged in", extra={'user_id': 42})  # Awkward

dbbasic-logs:

from dbbasic_logs import log

log.info("User logged in", user_id=42)  # Natural

vs. ELK Stack

ELK:

  • Setup: Docker compose with 3 services
  • Memory: 4GB+ RAM
  • Complexity: High

dbbasic-logs:

  • Setup: Import
  • Memory: 0 (just files)
  • Complexity: Low

Design Principles

  1. Foundational: All other DBBasic modules use this
  2. Simple: One-line logging, no setup
  3. Structured: TSV format, queryable
  4. Unix-Native: Plain text, grep-able, compressible
  5. Zero Config: Works out of the box

Security & Privacy

What NOT to Log

Never log sensitive data:

# BAD - Don't do this
log.info("User logged in", password=password)  # ❌
log.info("Payment", credit_card=card_number)   # ❌

# GOOD - Log safely
log.info("User logged in", user_id=user.id)    # ✓
log.info("Payment", order_id=order.id)         # ✓

Log File Permissions

Protect your logs:

# Restrict access to logs
chmod 700 data/logs
chmod 600 data/logs/*/*.tsv*

Contributing

This module is part of the DBBasic project. Contributions welcome!

License

MIT License - see LICENSE file for details

Credits

Created as part of the DBBasic project - a collection of tiny, composable Python web framework modules.

Philosophy: Keep it simple. Keep it readable. Keep it under 500 lines.

Release files for dbbasic-logs 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for dbbasic-logs 1.0.0
File Size Uploaded
dbbasic_logs-1.0.0.tar.gz 13.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for dbbasic-logs 1.0.0
File Interpreter ABI Platform
dbbasic_logs-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 25.2 kB

Release files / dbbasic_logs-1.0.0.tar.gz

Download URL dbbasic_logs-1.0.0.tar.gz
Size 13.7 kB
Tags Source
SHA-256 checksum
How to use checksums
1d2aee46259b3e39c9d87063570a2465a12b751d17f32daf07207a34ec428ac9
BLAKE2b-256 checksum
How to use checksums
a64a723ce31d87346b5a6f94d7d5be52930b15c6b4709686d282cdfb63ee47e8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.10.1

Release files / dbbasic_logs-1.0.0-py3-none-any.whl

Download URL dbbasic_logs-1.0.0-py3-none-any.whl
Size 11.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1d156d83b47dc05abc33d92442f79f160780342ccd35959a324bf1baac6b31ef
BLAKE2b-256 checksum
How to use checksums
c00ce69762cea592a190a818e128cf0b7e79a855fc325e004c41994aa4777d21
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.10.1

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page