Metadata-Version: 2.5
Name: fetchnode
Version: 0.4.1
Summary: Official Django and Python client SDK for FetchNode monitoring
Project-URL: Homepage, https://fetchnode.com
Project-URL: Documentation, https://fetchnode.com/guide/
Project-URL: Repository, https://github.com/remcovanwijk040/fetchnode
Project-URL: Issues, https://github.com/remcovanwijk040/fetchnode/issues
Project-URL: Changelog, https://fetchnode.com/changelog/
Author-email: Remco van Wijk <remcovanwijk040@users.noreply.github.com>
License-Expression: MIT
License-File: LICENSE
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Web Environment
Classifier: Framework :: Django
Classifier: Framework :: Django :: 4.2
Classifier: Framework :: Django :: 5.0
Classifier: Framework :: Django :: 5.1
Classifier: Framework :: Django :: 5.2
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: System :: Monitoring
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: django>=4.2
Provides-Extra: celery
Requires-Dist: celery>=5.0; extra == 'celery'
Description-Content-Type: text/markdown

# FetchNode Python & Django SDK

[![PyPI version](https://img.shields.io/pypi/v/fetchnode.svg)](https://pypi.org/project/fetchnode/)
[![Python Versions](https://img.shields.io/pypi/pyversions/fetchnode.svg)](https://pypi.org/project/fetchnode/)
[![Django Versions](https://img.shields.io/badge/django-4.2%20%7C%205.0%20%7C%205.1%20%7C%205.2-blue.svg)](https://www.djangoproject.com/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Typing: Typed](https://img.shields.io/badge/typing-typed-green.svg)](https://peps.python.org/pep-0561/)

Official Python and Django client SDK for [FetchNode](https://fetchnode.com) — the focused operations workspace for developers and teams managing multiple production Django websites.

FetchNode captures unhandled exceptions, error logs, slow database queries, N+1 query patterns, Celery background tasks, and authoritative business conversions with zero bloat and privacy-safe defaults.

---

## Table of Contents

- [Installation](#installation)
- [Quickstart (Django)](#quickstart-django)
- [Configuration Options](#configuration-options)
- [Telemetry & Usage](#telemetry--usage)
  - [Conversion & Lead Tracking](#conversion--lead-tracking)
  - [Automatic Error Monitoring](#automatic-error-monitoring)
  - [Manual Exception Capture](#manual-exception-capture)
  - [Celery Job Monitoring](#celery-job-monitoring)
  - [Logging Handler](#logging-handler)
- [Privacy & Security Defaults](#privacy--security-defaults)
- [Testing in Development](#testing-in-development)
- [Compatibility](#compatibility)
- [Links & Resources](#links--resources)
- [License](#license)

---

## Installation

Install via `pip`:

```bash
pip install fetchnode
```

Or using `uv`:

```bash
uv add fetchnode
```

*(For Celery support, you can optionally install `fetchnode[celery]`)*

---

## Quickstart (Django)

### 1. Add to `INSTALLED_APPS`

In your Django `settings.py`:

```python
INSTALLED_APPS = [
    # ...
    "fetchnode",
]
```

### 2. Add the Middleware

Add `FetchNodeMiddleware` near the top of your `MIDDLEWARE` list for comprehensive request, query, and exception coverage:

```python
MIDDLEWARE = [
    "fetchnode.middleware.FetchNodeMiddleware",
    "django.middleware.security.SecurityMiddleware",
    # ...
]
```

### 3. Configure `settings.FETCHNODE`

```python
FETCHNODE = {
    "API_KEY": "fn_live_your_project_key_here",
    "ENVIRONMENT": "production",  # e.g. "production", "staging"
}
```

That's it! Django will automatically initialize FetchNode upon startup and capture unhandled exceptions, slow queries, and request telemetry.

---

## Configuration Options

Configure via `settings.FETCHNODE` or environment variables:

| Setting Key | Environment Variable | Default | Description |
| :--- | :--- | :--- | :--- |
| `API_KEY` | `FETCHNODE_API_KEY` | `""` | **Required.** Your FetchNode project key (starts with `fn_live_` or `fn_test_`). |
| `ENDPOINT` / `API_URL` | `FETCHNODE_ENDPOINT` | `https://monitor.fetchnode.com/api/events/ingest/` | Processing server URL. Point to your self-hosted instance if applicable. |
| `ENVIRONMENT` | `FETCHNODE_ENVIRONMENT` | `"development"` | Active environment name (`"production"`, `"staging"`). |
| `RELEASE` | `FETCHNODE_RELEASE` | `""` | Release tag or git commit hash (e.g. `git rev-parse HEAD`). |
| `ENABLED` | `FETCHNODE_ENABLED` | `True` if API_KEY present | Master toggle for event sending. |
| `CAPTURE_TRANSACTIONS` | — | `True` | Track request duration and database query counts. |
| `CAPTURE_BODY` | — | `False` | Privacy safeguard: request bodies are excluded by default. |
| `CAPTURE_HEADERS` | — | `False` | Privacy safeguard: request headers are excluded by default. |
| `QUERY_SLOW_THRESHOLD_MS` | — | `100` | Minimum execution time (ms) to flag an ORM query as slow. |
| `N_PLUS_ONE_THRESHOLD` | — | `5` | Identical SELECT query repetition threshold to flag N+1 issues. |
| `SENSITIVE_KEYS` | — | *(built-in list)* | Extra field names to scrub from payloads (additive). |

---

## Telemetry & Usage

### Conversion & Lead Tracking

Track authoritative business events server-side (form submissions, payments, lead captures) with automatic session and visitor cookie attribution:

```python
import fetchnode

def contact_view(request):
    form = ContactForm(request.POST)
    if form.is_valid():
        lead = form.save()

        # Track authoritative conversion
        fetchnode.track(
            "lead_submitted",
            request=request,
            idempotency_key=f"lead:{lead.id}",
            properties={"email": lead.email},
            conversion=True,
        )
        return redirect("thank_you")
```

**Why `idempotency_key` matters:** Providing an `idempotency_key` (such as the database record ID or payment provider ID) ensures that retried requests, webhook replays, or browser reloads do not inflate your conversion metrics. FetchNode securely hashes the key client-side to produce a deterministic event ID.

### Automatic Error Monitoring

Unhandled exceptions in Django views are caught by `FetchNodeMiddleware`, decorated with:
* The exact failing line of code and stack trace.
* In-app vs. framework/library frame classification.
* Database query count and execution time during the failing request.
* Correlated request ID and trace ID.

### Manual Exception Capture

Capture handled exceptions or background exceptions:

```python
import fetchnode

try:
    external_service_call()
except ThirdPartyAPIError as exc:
    fetchnode.capture_exception(exc, tags={"provider": "stripe"})
```

### Celery Job Monitoring

FetchNode automatically instruments Celery when installed. You can also explicitly decorate tasks:

```python
from fetchnode import capture_job

@capture_job(name="sync_external_inventory")
def sync_inventory():
    ...
```

### Logging Handler

Send standard `logging.ERROR` and `logging.CRITICAL` records to FetchNode:

```python
LOGGING = {
    "version": 1,
    "disable_existing_loggers": False,
    "handlers": {
        "fetchnode": {
            "level": "ERROR",
            "class": "fetchnode.handlers.FetchNodeHandler",
        },
    },
    "loggers": {
        "django": {
            "handlers": ["fetchnode"],
            "level": "ERROR",
            "propagate": True,
        },
    },
}
```

---

## Privacy & Security Defaults

FetchNode is engineered with a strict **privacy-first architecture**:
1. **Client-side Scrubbing:** Sensitive keys (`password`, `token`, `secret`, `api_key`, `authorization`, `cookie`, `csrfmiddlewaretoken`) and any compound keys like `user_password` or `client_secret` are scrubbed before payload transmission.
2. **Safe SQL Normalization:** Raw SQL text is stripped of literals and parameters (`SELECT * FROM user WHERE id = 123` becomes `SELECT * FROM user WHERE id = ?`).
3. **No Unintentional PII:** Request bodies, query strings, and raw IP addresses are excluded by default.
4. **Inspectable & Lightweight:** The entire client is open-source Python with zero compiled binaries and zero unnecessary dependencies.

---

## Testing in Development

In your local test suite (e.g. `pytest` or `python manage.py test`), FetchNode can be disabled by omitting the API key or explicitly setting:

```python
# settings_test.py
FETCHNODE = {
    "ENABLED": False,
}
```

To test that event transmission works in your staging environment, run:

```python
import fetchnode
fetchnode.capture_message("FetchNode verification ping", level="info")
fetchnode.flush()
```

---

## Compatibility

- **Python:** 3.10, 3.11, 3.12, 3.13, 3.14
- **Django:** 4.2 LTS, 5.0, 5.1, 5.2
- **Operating Systems:** Linux, macOS, Windows

---

## Links & Resources

- **Website & Cloud App:** [fetchnode.com](https://fetchnode.com)
- **Documentation & Setup Guide:** [fetchnode.com/guide/](https://fetchnode.com/guide/)
- **Changelog:** [fetchnode.com/changelog/](https://fetchnode.com/changelog/)
- **GitHub Repository:** [github.com/remcovanwijk040/fetchnode](https://github.com/remcovanwijk040/fetchnode)
- **Issue Tracker:** [github.com/remcovanwijk040/fetchnode/issues](https://github.com/remcovanwijk040/fetchnode/issues)

---

## License

MIT License. See [LICENSE](LICENSE) for details.
