Skip to main content

Python tracebacks like structured, analyzable data with rich insights.

Project description

Tattletail

PyPI version Python Support License: AGPL v3 CI codecov Code style: ruff Checked with pyright

Python tracebacks like structured, analyzable data with rich insights.

📌 What is Tattletail?

Don't get me wrong, I love Python's native traceback capabilities, but Tattletail transforms this traceback:

Traceback (most recent call last):
  File "/app/main.py", line 45, in process_data
    result = clean_values(data['values'])
  File "/app/utils.py", line 78, in clean_values
    return [int(v) for v in values]
ValueError: invalid literal for int() with base 10: 'abc'

Into this structured analysis:

{
    "summary": "ValueError in clean_values (utils.py:78): invalid literal for int()",
    "exception": {
        "class": "ValueError",
        "name": "ValueError",
        "message": "invalid literal for int() with base 10: 'abc'",
        "module": None,
        "full_name": "ValueError",
        "hierarchy": ["BaseException", "Exception", "ValueError"],
        "line_number": 78,
        "file_path": "/app/utils.py",
        "function_name": "clean_values",
        "has_cause": False,
        "has_context": False
    },
    "probable_cause": "A function received an argument with the right type but an invalid value.",
    "patterns": {
        "call_depth": 2,
        "is_recursive": False,
        "error_in_stdlib": False
    },
    "metrics": {
        "total_frames": 2,
        "user_frames": 2,
        "unique_files": 2
    }
}

Tattletail is suitable and friendly for debugging, error monitoring, historical log analysis, and building intelligent development tools.

🚀 Quick Start

Installation

uv add tattletail  # or pip install tattletail

Basic Example

import tattletail

# Parse a traceback string
traceback_text = """
Traceback (most recent call last):
  File "example.py", line 10, in main
    result = divide(10, 0)
ZeroDivisionError: division by zero
"""

# Get structured analysis
analysis = tattletail.analyze(traceback_text)
print(analysis['summary'])
# "ZeroDivisionError in main (example.py:10): division by zero"

# Generate a detailed report
report = tattletail.generate_report(traceback_text)
print(report)

Capture Live Exceptions

import tattletail

try:
    # Your risky code here
    result = some_function()
except Exception:
    # Analyze the current exception
    parsed = tattletail.parse_from_exception()
    print(f"Error in {parsed.get_error_location()}")
    print(f"Call chain: {' -> '.join(parsed.get_call_chain())}")

Key Features

🧩 Structured Parsing

  • Rich Data Models: Convert tracebacks into structured ParsedTraceback objects
  • Context Extraction: Automatically pull source code around error locations
  • Chained Exception Support: Handle complex __cause__ and __context__ chains
  • Unicode Friendly: Works with international characters in paths and messages

🧠 Smart Analysis

  • Exception Details: Extract class, hierarchy, location, and metadata information
  • Pattern Detection: Identify recursion, call depth, and code location patterns
  • Probable Cause: Automatic identification of likely error causes
  • Metrics Calculation: Quantitative analysis of stack frames and error characteristics
  • Summary Generation: Concise, human-readable error descriptions

💻 Developer Experience

  • Simple API: Single-function entry points for common tasks
  • Context Aware: Shows relevant source code when files are available
  • Report Generation: Beautiful, formatted reports for debugging
  • Error Monitoring: Perfect for production error tracking

🧞 Why use Tattletail?

Python's built-in traceback module is awesome for basic needs, but Tattletail goes a little bit beyond. Yes, I also know Sentry, Rollbar, Bugsnag, Better Exceptions, Pretty Errors, Structlog and so on. Each one of them are truly great tools. I'm just a guy who faced some situations where none of them fulfilled my needs. Sentry is too powerful for small organizations or projects (somewhat complex to self-host or paid), Structlog asks for some refactoring on already living projects, Better Exceptions is focused on live exceptions, etc.

Tattletail's unique strength: It can extract info from old logs and historical data - something no other tool can do for some reason I don't know. Need to analyze that traceback buried in last week's log files? Tattletail handles it. Want to build custom error analysis tools? Tattletail provides the foundation.

# What you CAN'T do with other tools:
error_from_log = """Traceback (most recent call last):
  File "app.py", line 42, in process_data
    result = parse_json(data)
ValueError: Invalid JSON format"""

analysis = tattletail.analyze(error_from_log)  # This works!
# Sentry/Rollbar: ❌ Can't parse strings from logs
# Better Exceptions: ❌ Only works with live exceptions

Parse tracebacks from ANYWHERE. Ingest everything you have of some existing application.

error_sources = [
    application_logs,           # ✅ Log file entries
    error_monitoring_systems,   # ✅ Sentry, Rollbar exports
    bug_reports,                # ✅ User-submitted errors
    database_error_records,     # ✅ Stored error strings
    CI/CD_failure_logs,         # ✅ Test failure outputs
    email_error_notifications   # ✅ Automated alerts
]

for error_text in error_sources:
    parsed = tattletail.parse(error_text)  # Works with ALL of these!

It's deadly simple with zero third-party dependencies. I'm not aiming to compete with anyone. I just wrote Tattletail for personal use and... it's done. Why shouldn't I publish it if it maybe can be of use to someone?

🎯 Common Use Cases

Interactive Debugging

import tattletail

# Quick analysis during development
try:
    complex_operation()
except Exception:
    parsed = tattletail.parse_from_exception(extract_context=True)

    # See the error location with source code context
    for frame in parsed.stack_frames:
        if frame.context_lines:
            print(f"Error in {frame.file_path}:{frame.line_number}")
            for ctx in frame.context_lines:
                marker = ">>>" if ctx.is_error_line else "   "
                print(f"{marker} {ctx.line_number:3d}: {ctx.code}")

Production Monitoring

import tattletail
import logging

def log_error(exception_text, user_context=None):
    analysis = tattletail.analyze(exception_text)

    logger.info(f"Error: {analysis['summary']}")
    logger.info(f"Cause: {analysis['probable_cause']}")

    if analysis['patterns']['is_recursive']:
        logger.warning("Recursive pattern detected!")

    if analysis['patterns']['call_depth'] > 10:
        logger.warning(f"Deep call stack: {analysis['patterns']['call_depth']} frames")

Tool Integration

import tattletail

# Build debugging tools with rich traceback data
def analyze_test_failure(traceback_text):
    parsed = tattletail.parse(traceback_text)
    analysis = tattletail.analyze(traceback_text)

    return {
        'test_file': parsed.get_error_location().file_path,
        'error_line': parsed.get_error_location().line_number,
        'error_type': parsed.exception.exception_type,
        'complexity': analysis['patterns']['call_depth'],
        'user_code_ratio': analysis['metrics']['user_frames'] / analysis['metrics']['total_frames']
    }

🔬 Advanced Features

Context Extraction

Automatically show source code around errors when files are available:

# Enable context extraction
parsed = tattletail.parse(traceback_text, extract_context=True)

# Access source code context
error_frame = parsed.get_error_location()
if error_frame.context_lines:
    for line in error_frame.context_lines:
        print(f"{line.line_number}: {line.code}")

Pattern Analysis

Detect common patterns in your tracebacks:

analysis = tattletail.analyze(traceback_text)
patterns = analysis['patterns']

if patterns['is_recursive']:
    print(f"Recursion detected! Functions: {patterns['repeated_functions']}")

if patterns['error_in_stdlib']:
    print("Error originated in Python standard library")

print(f"Call stack depth: {patterns['call_depth']} frames")

Exception Details

Access focused exception information with comprehensive details:

analysis = tattletail.analyze(traceback_text)
exception = analysis['exception']

print(f"Exception type: {exception['class']}")
print(f"Error message: {exception['message']}")
print(f"Inheritance chain: {' -> '.join(exception['hierarchy'])}")
print(f"Error location: {exception['file_path']}:{exception['line_number']}")
print(f"In function: {exception['function_name']}")
print(f"Has chained exceptions: {exception['has_cause'] or exception['has_context']}")

Detailed Metrics

Get quantitative insights about your errors:

metrics = analysis['metrics']
print(f"Total frames: {metrics['total_frames']}")
print(f"User code frames: {metrics['user_frames']}")
print(f"Third-party frames: {metrics['site_packages_frames']}")
print(f"Files involved: {metrics['unique_files']}")
print(f"Has chained exceptions: {metrics['has_chained_exceptions']}")

📚 Examples

Check out the examples/ directory for detailed usage patterns:

🙌 Contributing

I would love contributions! Here's how to get started:

  1. Fork the repository
  2. Create a feature branch: git checkout -b my-feature
  3. Write tests for your changes
  4. Run the test suite: make test
  5. Submit a pull request

Development Setup

# Clone the repository
git clone https://github.com/yourusername/tattletail.git
cd tattletail

# Install dependencies
uv sync

# Run tests
make test

# Run linting
make lint

Happy debugging! 🚀

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

tattletail-0.1.0.tar.gz (65.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tattletail-0.1.0-py3-none-any.whl (30.9 kB view details)

Uploaded Python 3

File details

Details for the file tattletail-0.1.0.tar.gz.

File metadata

  • Download URL: tattletail-0.1.0.tar.gz
  • Upload date:
  • Size: 65.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.6.3

File hashes

Hashes for tattletail-0.1.0.tar.gz
Algorithm Hash digest
SHA256 6d49ffab6c60b32193cbb6afa6785245097b3fd6d27c4bb08850caab7a013d0f
MD5 b1e42ee8630469670c97e93146a0518f
BLAKE2b-256 01ead34579a480d01ef366e98e895e222285b3c464cd7ca3137262086abcb6f6

See more details on using hashes here.

File details

Details for the file tattletail-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: tattletail-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 30.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.6.3

File hashes

Hashes for tattletail-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1d621f4687db5244925f7a0c7bf68bd3ec381efde20c64e21d6a6be9af15427b
MD5 8a4703875f78dac8ebad4daa1048d00e
BLAKE2b-256 dd74984dfa110de05c3d844bfe80ad89ae0ab45f668d694f4e73175a1c67b2a5

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page