Metadata-Version: 2.5
Name: fetchnode
Version: 0.4.3
Summary: Official Django and Python client SDK for FetchNode monitoring
Project-URL: Homepage, https://fetch-node.com
Project-URL: Documentation, https://fetch-node.com/guide/
Project-URL: Repository, https://github.com/remcovanwijk040/fetchnode
Project-URL: Issues, https://github.com/remcovanwijk040/fetchnode/issues
Project-URL: Changelog, https://pypi.org/project/fetchnode/0.4.3/#sdk-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://fetch-node.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

Version 0.4.3 fixes the default ingest endpoint and Django startup discovery for
automatic logging. See the [SDK changelog](#sdk-changelog)
for changes and upgrade instructions.

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
import os

FETCHNODE = {
    "API_KEY": os.environ.get("FETCHNODE_API_KEY", ""),
    "API_URL": "https://fetch-node.com/api/events/ingest/",
    "ENVIRONMENT": "production",  # e.g. "production", "staging"
}
```

Set `FETCHNODE_API_KEY` to your private server key in the deployment environment. Keep it out of source control and browser code. Restart or redeploy Django, then verify a request and test error in FetchNode.

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 private server key from project settings. Never use a public browser key here. |
| `ENDPOINT` / `API_URL` | `FETCHNODE_ENDPOINT` | `https://fetch-node.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={"source": "contact_form"},
            conversion={"display_name": "Lead submitted", "funnel_order": 1, "primary": 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://fetch-node.com)
- **Documentation & Setup Guide:** [fetchnode.com/guide/](https://fetch-node.com/guide/)
- **Changelog:** [fetchnode.com/changelog/](https://fetch-node.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.


# SDK changelog

## 0.4.3 — 2026-09-29

### Fixed

- Use `https://fetch-node.com/api/events/ingest/` as the default ingest endpoint.
- Let Django automatically discover the SDK AppConfig when `fetchnode` is in
  `INSTALLED_APPS`, so startup installs logging and enabled instrumentation.
- Preserve automatic AppConfig discovery for the legacy `fetchnode_client` name.
- Correct the documentation URLs to the active FetchNode website.

### Documentation

- Configure the private server key through `FETCHNODE_API_KEY` and supply an
  explicit ingest URL. Keep private keys out of browser code and source control.
- Show explicit server conversion declarations and non-personal event properties.
- Verify reception after restarting or redeploying Django.

### Release checks

- Test the installed wheel outside the repository, including Django AppConfig and
  automatic logging setup.
- Exercise requests, exceptions, error logs and idempotent conversions against a
  local FetchNode collector, with project isolation checks.
- Check distribution metadata and the release tag before uploading to PyPI.

### Upgrade

```bash
python -m pip install --upgrade fetchnode==0.4.3
```

Update your dependency file or lockfile, restart or redeploy Django, and verify a
request and test error in FetchNode. Existing installations can set `API_URL`
explicitly if they use their own collector.
