Skip to main content
When request logging is enabled, the Apitally SDK captures details about each request and response handled by your application. To protect sensitive data and reduce noise, the SDK provides mechanisms for masking data and filtering out requests you don’t want to log.

Default masking and exclusion

The SDK automatically masks common sensitive query parameters, headers, and request/response body fields based on built-in patterns. For example, fields named password, token, secret, or headers like Authorization are masked by default. To reduce noise, the SDK also automatically excludes common static assets and health check endpoints, such as /robots.txt or /healthz. See the data privacy page for complete lists of default masking and exclusion patterns.

Mask sensitive data

You can extend the default masking rules by providing additional regular expressions via the mask_query_params, mask_headers, and mask_body_fields parameters. Patterns are case-insensitive and match anywhere within the name. Use ^ and $ anchors for exact matches. For more control over request and response body masking, you can provide callback functions via the mask_request_body_callback and mask_response_body_callback parameters. The functions receive the captured request and response data as arguments (see callback arguments below) and should return the masked body as bytes, or None to mask the entire body.
from fastapi import FastAPI
from apitally.fastapi import ApitallyMiddleware

app = FastAPI()
app.add_middleware(
    ApitallyMiddleware,
    client_id="your-client-id",
    env="dev",
    enable_request_logging=True,
    log_request_headers=True,
    log_request_body=True,
    log_response_body=True,
    # Mask specific query parameters, headers and body fields
    mask_query_params=[r"^card_number$", r"^account_id$"],
    mask_headers=[r"^X-Custom-Key$", r"^X-Internal-"],
    mask_body_fields=[r"^credit_card$", r"social_security"],
    # Mask request and response body using custom logic (see examples below)
    mask_request_body_callback=mask_request_body,
    mask_response_body_callback=mask_response_body,
)
Callback function examples
import json

def mask_request_body(request: dict) -> bytes | None:
    # Mask entire request body for admin endpoints
    if request["path"] and request["path"].startswith("/admin/"):
        return None
    # Otherwise, return the original request body
    return request["body"]

def mask_response_body(request: dict, response: dict) -> bytes | None:
    # Mask entire response body for admin endpoints
    if request["path"] and request["path"].startswith("/admin/"):
        return None
    # Mask specific fields in user profile responses
    if request["path"] and request["path"].startswith("/users/") and response["body"]:
        try:
            data = json.loads(response["body"])
            if isinstance(data, dict):
                if "email" in data:
                    data["email"] = "******"
                if "phone" in data:
                    data["phone"] = "******"
                return json.dumps(data).encode()
        except (json.JSONDecodeError, UnicodeDecodeError):
            pass
    # Otherwise, return the original response body
    return response["body"]
Callbacks are applied before pattern-based field masking. The returned body is still masked using the default and custom mask_body_fields patterns.

Exclude requests

You can exclude requests from logging using path patterns (regular expressions) via the exclude_paths parameter. Like the masking patterns, these are case-insensitive and match anywhere within the request path. Use ^ and $ anchors for exact matches. Alternatively, you can provide a callback function with custom exclusion logic via the exclude_callback parameter. The function receives the captured request and response data as arguments (see callback arguments below) and should return True to exclude the request from logging, or False to include it.
from fastapi import FastAPI
from apitally.fastapi import ApitallyMiddleware

app = FastAPI()
app.add_middleware(
    ApitallyMiddleware,
    client_id="your-client-id",
    env="dev",
    enable_request_logging=True,
    # Exclude paths matching certain patterns
    exclude_paths=[r"/admin/", r"/internal/"],
    # Exclude requests using custom logic (see example below)
    exclude_callback=exclude_request,
)
Callback function example
def exclude_request(request: dict, response: dict) -> bool:
    # Exclude requests from a specific consumer
    if request["consumer"] == "internal-service":
        return True
    # Exclude successful requests (only log failures)
    if response["status_code"] < 400:
        return True
    return False
Excluded requests won’t be logged, but are still counted in metrics. To exclude endpoints from metrics, you can mark them as excluded in the dashboard.

Callback arguments

The request dict passed to callback functions has the following keys:
KeyDescriptionType
timestampUnix timestamp of the request.float
methodHTTP method of the request.str
pathPath of the matched endpoint, if applicable.str | None
urlFull URL of the request.str
headersList of key-value pairs representing the request headers.list[tuple[str, str]]
sizeSize of the request body in bytes.int | None
consumerIdentifier of the consumer making the request.str | None
bodyRaw request body.bytes | None
The response dict passed to mask_response_body_callback and exclude_callback has the following keys:
KeyDescriptionType
status_codeHTTP status code of the response.int
response_timeTime taken to respond to the request in seconds.float
headersList of key-value pairs representing the response headers.list[tuple[str, str]]
sizeSize of the response body in bytes.int | None
bodyRaw response body.bytes | None