Metadata-Version: 2.4
Name: shuuten
Version: 0.2.0
Summary: Last-stop signals for automation failures.
Author-email: Ritvik Nag <me@ritviknag.com>
Maintainer-email: Ritvik Nag <me@ritviknag.com>
License: MIT
Project-URL: Homepage, https://github.com/rnag/shuuten
Project-URL: Documentation, https://shuuten.ritviknag.com
Project-URL: Repository, https://github.com/rnag/shuuten.git
Project-URL: Issues, https://github.com/rnag/shuuten/issues
Project-URL: Changelog, https://github.com/rnag/shuuten/blob/main/CHANGELOG.md
Keywords: automation,notifications,alerts,slack,email,aws,lambda,ecs,observability,ops
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Topic :: System :: Logging
Classifier: Topic :: System :: Monitoring
Classifier: Topic :: Software Development :: Libraries
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
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
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: cli
Requires-Dist: rich; extra == "cli"
Requires-Dist: typer; extra == "cli"
Provides-Extra: docs
Requires-Dist: mkdocs; extra == "docs"
Requires-Dist: mkdocs-material; extra == "docs"
Requires-Dist: mkdocs-github-admonitions-plugin; extra == "docs"
Requires-Dist: mkdocs-markdownextradata-plugin; extra == "docs"
Requires-Dist: mkdocs-macros-plugin; extra == "docs"
Requires-Dist: mkdocs-include-markdown-plugin; extra == "docs"
Provides-Extra: lint
Requires-Dist: ruff; extra == "lint"
Requires-Dist: ty; extra == "lint"
Provides-Extra: test
Requires-Dist: pytest; extra == "test"
Requires-Dist: pytest-cov; extra == "test"
Requires-Dist: coverage; extra == "test"
Provides-Extra: dev
Requires-Dist: bump-my-version==1.2.5; extra == "dev"
Requires-Dist: ipdb; extra == "dev"
Provides-Extra: email
Requires-Dist: boto3; extra == "email"
Dynamic: license-file

<div align="center">
<img alt="logo" width="160" src="https://raw.githubusercontent.com/rnag/shuuten/main/img/logo.png">

**Shuuten Signal — last-stop signals for automation failures**

[![PyPI version](https://img.shields.io/pypi/v/shuuten.svg)](https://pypi.org/project/shuuten)
[![PyPI license](https://img.shields.io/pypi/l/shuuten.svg)](https://pypi.org/project/shuuten)
[![PyPI Python versions](https://img.shields.io/pypi/pyversions/shuuten.svg)](https://pypi.org/project/shuuten)
[![GitHub Actions](https://github.com/rnag/shuuten/actions/workflows/release.yml/badge.svg)](https://github.com/rnag/shuuten/actions/workflows/release.yml)
[![Documentation Status](https://github.com/rnag/shuuten/actions/workflows/gh-pages.yml/badge.svg)](https://shuuten.ritviknag.com)

</div>

<!--intro-start-->

**Shuuten sends structured Slack and email alerts** when your Python automations fail — especially in AWS Lambda and ECS — with minimal setup and zero dependencies.

*終点 (Shūten) means "final stop" in Japanese — the point where a workflow ends and signals that something needs attention.*

📖 [Documentation](https://shuuten.ritviknag.com) · ⭐ [Star on GitHub](https://github.com/rnag/shuuten)

### Quick start (AWS Lambda)

```python
import shuuten

@shuuten.capture
def lambda_handler(event, context):
    shuuten.debug('debug info')      # not sent
    shuuten.error('domain error')    # sent to Slack
    1 / 0                            # sent with stack trace
```

Set one environment variable and you’re done
(see [Slack webhook setup](https://docs.slack.dev/messaging/sending-messages-using-incoming-webhooks/)):

```bash
export SHUUTEN_SLACK_WEBHOOK_URL="https://hooks.slack.com/services/..."
```

## Why Shuuten?

* **Built for failure paths** — only `ERROR+` signals are sent by default
* **Zero dependencies** — no SDKs, agents, or background workers
* **Designed for AWS** — Lambda, ECS tasks, and containers work out of the box
* **Logging-native** — uses familiar `logging` semantics
* **Opinionated but minimal** — small surface area, easy to reason about

## Installation

```bash
pip install shuuten             # no dependencies (Slack, local logging)
pip install "shuuten[email]"    # SES email (boto3) outside AWS Lambda
```

## Usage patterns

### Structured logging (logging-style)

```python
import shuuten

def handler(event, context):
    shuuten.info('hello')        # not sent
    shuuten.error('bad input')   # sent to Slack if configured
```

### Explicit logger + email notifications

> Requires SES env vars (`SHUUTEN_SES_FROM`, `SHUUTEN_SES_TO`). Email is sent via AWS SES if configured.

```python
import shuuten

shuuten.init(shuuten.Config(app='my-app', env='dev'))
log = shuuten.get_logger(__name__)


@shuuten.capture(workflow='my-workflow')
def handler(event, context):
    log.critical('Something went wrong')  # sent to Slack + Email (if configured)
```

### Manual context control (advanced)

```python
import shuuten

def handler(event, context):
    token = shuuten.detect_and_set_context(context)
    try:
        ...
    finally:
        shuuten.reset_runtime_context(token)
```

> The `capture()` decorator works for ECS tasks as well (via ECS metadata v4).

## Configuration

You can configure Shuuten via `Config` in code **or** environment variables.

| Variable                  | Description                                       | Default   |
|---------------------------|---------------------------------------------------|-----------|
| `SHUUTEN_APP`             | Application name (used for grouping/metadata)     | auto      |
| `SHUUTEN_ENV`             | Environment name (`prod`, `dev`, `staging`, etc.) | auto      |
| `SHUUTEN_MIN_LEVEL`       | Minimum level sent to destinations                | `ERROR`   |
| `SHUUTEN_EMIT_LOCAL_LOG`  | Emit local structured log when notifying          | `true`    |
| `SHUUTEN_QUIET_LEVEL`     | Silence noisy third-party logs (e.g. boto)        | `WARNING` |
| `SHUUTEN_DEDUPE_WINDOW_S` | Slack dedupe window (seconds); `0` disables       | `30`      |

### Slack

| Variable                    | Description                |
|-----------------------------|----------------------------|
| `SHUUTEN_SLACK_WEBHOOK_URL` | Slack Incoming Webhook URL |
| `SHUUTEN_SLACK_FORMAT`      | `blocks` or `plain`        |

### Email (SES)

| Variable               | Description                    |
|------------------------|--------------------------------|
| `SHUUTEN_SES_FROM`     | Verified SES sender            |
| `SHUUTEN_SES_TO`       | Comma-separated recipient list |
| `SHUUTEN_SES_REPLY_TO` | Optional reply-to address      |
| `SHUUTEN_SES_REGION`   | Optional SES region            |

## Supported destinations

* **Slack** (Incoming Webhooks)
* **Email** (AWS SES)
  > Note: When running in AWS (e.g. Lambda or ECS), the execution role must be allowed to send email via SES.
  See [AWS docs](https://docs.aws.amazon.com/pinpoint/latest/developerguide/permissions-ses.html).

## Roadmap

* PagerDuty and other alerting destinations
* Context manager for exception capture
* Optional "exceptions-only" alerting mode
* Expanded ECS and EKS support

## Credits

Created with Cookiecutter using
[https://github.com/audreyfeldroy/cookiecutter-pypackage](https://github.com/audreyfeldroy/cookiecutter-pypackage)

<!--intro-end-->
