A Python decorator that automatically creates GitHub issues when functions encounter errors or log critical messages
Project description
Bug Hunter 🐛🔫
Automatic GitHub issue creation for Python errors using AI-powered descriptions
Bug Hunter is a Python library that provides a decorator-based system for automatically creating GitHub issues when functions encounter errors or log critical messages. It uses Google's Gemini AI to generate intelligent, descriptive issue content that helps developers understand and fix problems faster.
✨ Features
- 🔍 Automatic Error Detection: Captures both exceptions and logger.error calls
- 🤖 AI-Powered Descriptions: Uses Gemini AI to generate detailed, helpful issue descriptions
- 🔄 Smart GitHub Integration: Automatically creates well-formatted GitHub issues
- 🚫 Duplicate Prevention: Automatically detects and prevents duplicate issues using deterministic titles
- ⚡ Thread-Safe: Works correctly in multi-threaded applications
- 🛡️ Robust Error Handling: Includes fallback mechanisms and retry logic
- 🏷️ Configurable: Support for custom labels, assignees, and more
🚀 Quick Start
Installation
pip install exc2issue
Setup
-
Get API Keys:
- GitHub Personal Access Token: Go to GitHub Settings → Developer settings → Personal access tokens
- Gemini API Key: Get one from Google AI Studio
-
Set Environment Variables:
export GITHUB_TOKEN="your_github_token_here" export GEMINI_API_KEY="your_gemini_api_key_here"
Basic Usage
from exc2issue import exc2issue
@exc2issue(
labels=["bug", "auto-generated"],
repository="your-username/your-repo"
)
def risky_function(data):
# This will automatically create a GitHub issue if an error occurs
if not data:
raise ValueError("Data cannot be empty")
return process_data(data)
# If this function fails, a GitHub issue will be created automatically
risky_function(None)
Advanced Configuration
from exc2issue import exc2issue
import logging
# Configure with custom settings
@exc2issue(
labels=["bug", "critical", "production"],
assignees=["maintainer-username", "team-lead"], # Assign to multiple users
repository="your-org/your-repo",
github_token="custom_token", # Optional: override env var
gemini_api_key="custom_key" # Optional: override env var
)
def critical_function():
logger = logging.getLogger(__name__)
try:
# Some critical operation
result = perform_operation()
except Exception as e:
# This will also create an issue
logger.error("Critical operation failed: %s", str(e))
raise
return result
🔧 Configuration Options
Decorator Parameters
|| Parameter | Type | Required | Description |
||-----------|------|----------|-------------|
|| repository | str | ✅ Yes | GitHub repository in format "owner/repo" |
|| labels | List[str] | ❌ No | Labels to apply to created issues |
|| assignees | List[str] | ❌ No | GitHub usernames to assign issues to |
|| assignee | str | ❌ No | Single GitHub username (legacy, use assignees instead) |
|| github_token | str | ❌ No | GitHub token (defaults to GITHUB_TOKEN env var) |
|| gemini_api_key | str | ❌ No | Gemini API key (defaults to GEMINI_API_KEY env var) |
Pydantic Configuration (Advanced)
Bug Hunter uses Pydantic for configuration management, providing strong typing and validation. You can use environment variables with the BUG_HUNTER_ prefix to configure all aspects of the library:
from exc2issue.config import get_settings
# Load settings from environment variables or .env file
settings = get_settings()
@exc2issue(repository="your-org/repo", settings=settings)
def your_function():
# Function implementation
pass
Environment Variable Configuration:
- GitHub Settings:
BUG_HUNTER_GITHUB_TOKEN,BUG_HUNTER_GITHUB_BASE_URL - Gemini Settings:
BUG_HUNTER_GEMINI_API_KEY,BUG_HUNTER_GEMINI_MODEL_NAME,BUG_HUNTER_GEMINI_TEMPERATURE,BUG_HUNTER_GEMINI_MAX_OUTPUT_TOKENS - Global Settings:
BUG_HUNTER_ENABLED,BUG_HUNTER_DRY_RUN - Logging Settings:
BUG_HUNTER_LOGGING_LEVEL,BUG_HUNTER_LOGGING_FORMAT
See .env.example for a complete list of configuration options.
🔍 What Gets Captured
Bug Hunter captures comprehensive error information:
- Exception Details: Type, message, and full stack trace
- Function Context: Name and arguments passed to the function
- Timestamp: When the error occurred
- Log Messages: Critical log messages (logger.error level and above)
🎯 Deterministic Issue Titles
Bug Hunter uses a deterministic title format to prevent duplicate issues for the same error:
Title Format
- Exceptions:
[EXCEPTION]-[function_name]-[ExceptionType] - Log Errors:
[LOG-ERROR]-[function_name]-[MessagePattern]
Examples
[EXCEPTION]-[process_payment]-[ValueError]
[LOG-ERROR]-[database_connect]-[Connection_failed_after_{number}_seconds]
[EXCEPTION]-[send_email]-[SMTPException]
[LOG-ERROR]-[user_lookup]-[User_{email}_not_found]
Benefits
- No Duplicates: Same error type in same function always gets same title
- Highly Readable: Exception type and message patterns are immediately visible
- Informative: Shows actual
ValueError,TypeError, etc. instead of cryptic hashes - Pattern Recognition: Log messages show static patterns with
{placeholders}for variables - Searchable: Easy to find all
ValueErrorissues inprocess_paymentfunction
Pattern Recognition Benefits
- Automatically groups similar errors together
- Makes it easy to identify recurring issues
- Facilitates pattern-based debugging and analysis
Pattern Extraction for Logs
For log messages, variable values are replaced with descriptive placeholders:
- Numbers:
30 seconds→{number} seconds - Emails:
user@example.com→{email} - Times:
14:30:25→{time} - Variables:
user123→{variable} - This ensures messages like "Connection failed after 30 seconds" and "Connection failed after 120 seconds" produce the same title
🚫 Duplicate Prevention
Bug Hunter includes intelligent duplicate detection to prevent creating multiple issues for the same error:
How It Works
- Deterministic Titles: Each error type in each function gets a consistent, deterministic title
- Open Issue Search: Before creating a new issue, Bug Hunter searches for existing open issues with the same title
- Skip Creation: If an open issue already exists, creation is skipped and an informative message is logged
- Closed Issues Ignored: Closed issues are ignored, allowing new issues to be created for recurring problems
Example Behavior
@exc2issue(repository="myorg/myapp", labels=["bug"])
def process_payment(amount):
if amount <= 0:
raise ValueError("Amount must be positive")
# First error creates: [EXCEPTION]-[process_payment]-[ValueError]
process_payment(-10) # Creates new issue
# Second identical error is detected as duplicate
process_payment(-5) # Skips creation, logs: "Skipping duplicate issue creation for '[EXCEPTION]-[process_payment]-[ValueError]'"
Fallback Behavior
- If GitHub search fails, the issue will still be created (fail-safe approach)
- Network errors or API rate limits won't prevent issue creation
- All search failures are logged for debugging
Benefits
- Reduced Noise: Eliminates duplicate issues cluttering your repository
- Better Issue Management: One issue per unique error type and location
- Robust Design: Never prevents issue creation even if duplicate detection fails
- Informative Logging: Clear messages when duplicates are detected
🤖 AI-Generated Issue Content
The Gemini AI generates issue descriptions that include:
- Clear summary of what went wrong
- Technical details from the error
- Function arguments and context
- Stack trace analysis (for exceptions)
- Potential impact assessment
- Properly formatted markdown
🛡️ Error Handling
Bug Hunter is designed to be robust and never interfere with your application:
- Fallback Descriptions: If AI generation fails, creates basic issue descriptions
- Silent Failures: If issue creation fails, logs a warning but doesn't crash your app
- Retry Logic: Automatically retries transient failures
- Input Sanitization: Safely handles sensitive data and special characters
🔧 Developer Reference
Utility Functions
For advanced usage or custom integrations, Bug Hunter provides utility functions:
from exc2issue.utils import (
generate_deterministic_title,
sanitize_function_name,
validate_title_format
)
# Generate deterministic title
title = generate_deterministic_title("my_func", "ValueError", "Invalid input provided")
# Result: "[EXCEPTION]-[my_func]-[ValueError]"
# Generate log pattern title
log_title = generate_deterministic_title("connect_db", "Log", "Connection failed after 30 seconds")
# Result: "[LOG-ERROR]-[connect_db]-[Connection_failed_after_{number}_seconds]"
# Sanitize problematic function names
safe_name = sanitize_function_name("<lambda>")
# Result: "lambda"
# Validate title format
is_valid = validate_title_format("[EXCEPTION]-[my_func]-[ValueError]")
# Result: True
Title Generation Logic
- Function Name Sanitization: Removes problematic characters like
<>, handles special cases like<module> - Exception Handling: Uses actual exception type (ValueError, TypeError) for maximum clarity
- Log Pattern Extraction: Replaces variable values with descriptive placeholders (
{number},{email},{time}) - Format Assembly: Combines category, function name, and exception type or message pattern
📊 Examples
Exception Handling
@exc2issue(labels=["bug"], repository="myorg/myapp")
def divide_numbers(a, b):
return a / b # ZeroDivisionError will create an issue
divide_numbers(10, 0) # Creates: "[EXCEPTION]-[divide_numbers]-[ZeroDivisionError]"
Logger Error Monitoring
import logging
@exc2issue(labels=["error", "database"], repository="myorg/myapp")
def connect_to_database():
logger = logging.getLogger(__name__)
try:
# Database connection logic
db.connect()
except ConnectionError:
logger.error("Failed to connect to database after 3 retries")
# This creates an issue even without raising an exception
🏗️ Development
Local Development Setup
# Clone the repository
git clone https://github.com/your-username/exc2issue.git
cd exc2issue
# Create virtual environment
python -m venv .venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate
# Install development dependencies
uv pip install -e ".[dev]"
# Run tests
pytest
# Run linting
ruff check src/
ruff format src/
mypy src/
Running Tests
# Run all tests
pytest
# Run with coverage
pytest --cov=src/exc2issue --cov-report=html --cov-report=term
# Run specific test file
pytest tests/unit/test_decorator.py -v
🤝 Contributing
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Make your changes and add tests
- Ensure all tests pass:
pytest - Run linting:
ruff check src/ && mypy src/ - Commit your changes:
git commit -m 'Add amazing feature' - Push to the branch:
git push origin feature/amazing-feature - Open a Pull Request
📋 Requirements
- Python 3.12+
- GitHub Personal Access Token
- Google Gemini API Key
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
🙏 Acknowledgments
- Google Gemini AI for intelligent issue descriptions
- GitHub API for seamless issue creation
- The Python community for excellent testing and development tools
Happy Bug Hunting! 🐛🔫
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 exc2issue-0.2.0.tar.gz.
File metadata
- Download URL: exc2issue-0.2.0.tar.gz
- Upload date:
- Size: 39.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
59c44e0e877a9abc344f160068246c143a352445e33fe0cf04f03f789219889e
|
|
| MD5 |
60ed82e409ed55fe463bb6eb88950dcd
|
|
| BLAKE2b-256 |
780eccb4a5a1d3493ecd0b7203e48a1ace515282f78c376b9aeaa8fe6da349b0
|
Provenance
The following attestation bundles were made for exc2issue-0.2.0.tar.gz:
Publisher:
pypi.yaml on DucretJe/exc2issue
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
exc2issue-0.2.0.tar.gz -
Subject digest:
59c44e0e877a9abc344f160068246c143a352445e33fe0cf04f03f789219889e - Sigstore transparency entry: 585125222
- Sigstore integration time:
-
Permalink:
DucretJe/exc2issue@97d366ec3e99d31ad42370e70664c25b2c4e9025 -
Branch / Tag:
refs/tags/0.2.0 - Owner: https://github.com/DucretJe
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi.yaml@97d366ec3e99d31ad42370e70664c25b2c4e9025 -
Trigger Event:
release
-
Statement type:
File details
Details for the file exc2issue-0.2.0-py3-none-any.whl.
File metadata
- Download URL: exc2issue-0.2.0-py3-none-any.whl
- Upload date:
- Size: 54.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f65b7d9f1531c6c15eeecde42886320ecc515d8b40c60e54e2cc341ae6a585c7
|
|
| MD5 |
97ef37d97fbf82e4483882dc4707300c
|
|
| BLAKE2b-256 |
d8fb57a48c9c727a5c55d9e737f2576f4905d5ab9045ebffd63f9af87f27057f
|
Provenance
The following attestation bundles were made for exc2issue-0.2.0-py3-none-any.whl:
Publisher:
pypi.yaml on DucretJe/exc2issue
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
exc2issue-0.2.0-py3-none-any.whl -
Subject digest:
f65b7d9f1531c6c15eeecde42886320ecc515d8b40c60e54e2cc341ae6a585c7 - Sigstore transparency entry: 585125249
- Sigstore integration time:
-
Permalink:
DucretJe/exc2issue@97d366ec3e99d31ad42370e70664c25b2c4e9025 -
Branch / Tag:
refs/tags/0.2.0 - Owner: https://github.com/DucretJe
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi.yaml@97d366ec3e99d31ad42370e70664c25b2c4e9025 -
Trigger Event:
release
-
Statement type: