Skip to main content

wshtlib

Lightweight observability library for AWS Lambda and FastAPI. Zero external dependencies.

A focused alternative to aws-powertools — covers structured logging, CloudWatch metrics (EMF), request context propagation, and Lambda handler boilerplate. Nothing more.

Install

pip install wshtlib

FastAPI/Starlette middleware is optional:

pip install wshtlib[fastapi]

Usage

Lambda handler

Two decorators, one per invocation mode.

@bootstrapsynchronous invocations (API Gateway), where the return value is the response:

from wshtlib import bootstrap, get_logger

logger = get_logger("my-service")

@bootstrap
def handler(event, context):
    logger.info("invoked", path=event.get("path"))
    return {"statusCode": 200}

It handles:

  • Warming events ("source": "lambda-warming") — returns 200 early
  • Context init and structured log enrichment
  • Unhandled exceptions — logs error, returns 500

@workerasynchronous invocations (S3, EventBridge, SQS), where the return value is discarded:

from wshtlib import worker, get_logger

logger = get_logger("my-worker")

@worker
def handler(event, context):
    logger.info("processing", records=len(event["Records"]))

Same context init and structured error logging, but the exception is re-raised rather than swallowed — retries, on_failure destinations, the DLQ, and the Errors metric all depend on Lambda seeing the invocation fail. No warming-event handling.

Structured logging

from wshtlib import get_logger

logger = get_logger("my-service")
logger.info("user signed in", user_id="u_123", plan="pro")

Output is JSON to stdout, enriched with level, timestamp, service, location, runtime fields, and Lambda context on invocation. location names the calling function and line.

Keyword arguments are the preferred spelling, but stdlib's extra={...} works too and lands in the same JSON entry; kwargs win if both supply the same key. Fields are also set as attributes on the LogRecord, so custom filters and %(field)s formatters can read them.

Field names are unrestricted — including msg, args, and level. Only exc_info, extra, stack_info, and stacklevel keep their stdlib meanings and cannot be used as fields. A field whose name collides with one the formatter owns (level, message, timestamp, service, location, trace_id, exception, and the runtime/Lambda fields) is emitted with an extra_ prefix rather than replacing it:

logger.info("subscription renewed", level="premium")
# {"level": "INFO", ..., "message": "subscription renewed", "extra_level": "premium"}

This keeps an enrichment field from falsifying the record it was meant to enrich.

CloudWatch metrics (EMF)

from wshtlib.metrics import metrics

metrics.count("OrderPlaced")
metrics.put("Duration", 142.5, unit="Milliseconds")
metrics.flush()

metrics is a module-level MetricsContext instance. For isolated contexts (e.g. per-request), instantiate MetricsContext() directly.

Namespace defaults to the METRICS_NAMESPACE env var, falling back to "Wholeshoot".

Request context

from wshtlib import get_context, set_user_id

set_user_id(claims["sub"])
ctx = get_context()  # {"trace_id": ..., "correlation_id": ..., "user_id": ...}

Context is stored in a ContextVar — safe for concurrent async handlers.

FastAPI middleware

from fastapi import FastAPI
from wshtlib.middleware import WshtlibMiddleware

app = FastAPI()
app.add_middleware(WshtlibMiddleware)

Initialises request context, logs method, path, status, duration_ms per request, and injects X-Trace-Id into the response.

Utilities

from wshtlib import require_env, require_https_url, require_secret

db_url = require_env("DATABASE_URL")          # raises RuntimeError if missing/empty
endpoint = require_https_url(require_env("API_URL"))  # raises ValueError if not https
api_key = require_secret("api/key")           # raises RuntimeError if missing/empty, cached

Environment variables

Variable Default Description
LOG_LEVEL INFO Logger level
METRICS_NAMESPACE Wholeshoot CloudWatch namespace
ENVIRONMENT Added as a metrics dimension if set

Development

uv sync --group dev
uv run pytest
uv run mypy wshtlib
uv run ruff check wshtlib

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

wshtlib-0.3.0.tar.gz (51.8 kB view details)

Uploaded Source

Built Distribution

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

wshtlib-0.3.0-py3-none-any.whl (12.8 kB view details)

Uploaded Python 3

File details

Details for the file wshtlib-0.3.0.tar.gz.

File metadata

  • Download URL: wshtlib-0.3.0.tar.gz
  • Upload date:
  • Size: 51.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for wshtlib-0.3.0.tar.gz
Algorithm Hash digest
SHA256 1112613c2014cc14abb0fd3469d8872f26fd8e2a51667c8a746d18c6e56eb8d1
MD5 3eb620e100e351c2102015fbe56fa7fa
BLAKE2b-256 74605f39e92583c2a95bb02edb0149b89bea8cd92dc75056ef4e835733697d40

See more details on using hashes here.

Provenance

The following attestation bundles were made for wshtlib-0.3.0.tar.gz:

Publisher: ci.yml on pjosols/wshtlib

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file wshtlib-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: wshtlib-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 12.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for wshtlib-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 cff793c5cce85ad6fcc57c69fecde5a234d3315a2f93b770de4cb4f3165e5869
MD5 a4b3a7f211e97f0ce0be610ad38638ef
BLAKE2b-256 61ca56e04fcc8ca6c85761b958f25d79176a5d0eb67f6f736fdecebb99e38d64

See more details on using hashes here.

Provenance

The following attestation bundles were made for wshtlib-0.3.0-py3-none-any.whl:

Publisher: ci.yml on pjosols/wshtlib

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.5.0

2 files

0.4.0

2 files

This release

0.3.0 This release

2 files

0.2.0

2 files

0.1.2

2 files

0.1.1

2 files

0.1.0

2 files

Supported by

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