Skip to main content
The SDK records inputs, outputs and error details by default, and enables custom-object adapters. Log capture is off. Field-name rules, exception-message capture, log capture and value sampling control different paths; configure each path that handles sensitive data. Use synthetic data when checking capture settings. You need an environment with the SDK installed, a running relay reading the same VEXLO_SPOOL_DIR, and access to the web UI. Run the checks on the test service without an additional policy reduction. A restrictive service policy can suppress the records or logs expected by these checks. Python SDK covers installation and queue configuration.

Verify field, message and log capture

Use a separate test shell and clear capture settings inherited from earlier experiments:
Keep VEXLO_SPOOL_DIR set to the test relay’s queue. The comparisons start from the SDK’s defaults; each run below changes only the setting it names. Do this in the test shell, not the environment running your production service. Save the following as capture_check.py. It passes a synthetic credential under the argument name token, then includes that same value in formatted exception and log text. The script’s --logs option sets the SDK’s capture_logs argument; it is not a Vexlo binary option.
Run the four configurations below. Each prints a unique case_id; use that ID to find the new trace in the UI’s home search. Open the record call, select Input, Error or Logs, and choose fetch full value where available. Inspect full values as well as previews before drawing a conclusion about what was captured.
The settings control separate kinds of data: Every run retains its case_id tag and reports builtins.ValueError on the attempt. With message capture off, the captured stack remains available. Turning off value capture removes that error detail but preserves the error class in the call record. Turning off Vexlo log capture does not suppress the application’s own logging output.

Withhold values by field name

redact_keys matches whole string keys in bound arguments and nested dictionaries. It also applies to declared and runtime tags. Passing a list replaces the defaults; to add a name, use redact_keys=[*vexlo.DEFAULT_REDACT_KEYS, "email"] in init(). Each configured name matches as written, plus its lowercase, uppercase and capitalized spellings. authorization covers Authorization and AUTHORIZATION. api_key does not cover apiKey, Api_Key, Api-Key or X-Api-Key; password does not cover user_password. Add the actual spellings your application receives. The rule examines names, not value contents. It cannot identify a credential returned under an unrelated name, inside an already formatted string, or in an unnamed positional argument. A matched dictionary value is not walked; object adapters can execute conversion code before that dictionary exists. Tags are indexed in clear text. A name cannot appear in both tag_keys and redact_keys: init() rejects that conflict. A runtime tag() pair with a redacted name is dropped and increments diagnostics().redacted_tags.

Control exception messages and logs

capture_error_message=False, or VEXLO_CAPTURE_ERROR_MESSAGE=0, withholds the entire message and avoids calling str(exc) for capture. The exception class and stack remain recorded when value capture is enabled. Stack frames contain the file name, line number and function name; they omit the source line and directory prefix. capture_logs=True installs one handler on the root logger without changing logging levels or the application’s existing handlers. If application logging filters a record or stops its propagation before the root handler, Vexlo does not capture it. Logs belong to the innermost recorded call: a marked child receives its own logs. Captured messages use getMessage(), so formatting can execute application code. Name rules cannot filter the text that formatting produces. Log capture is bounded at 100 entries per attempt, 4 KiB per formatted message and 16 KiB per logs value. See Python API for all bounds.

Control custom-object conversion

Adapters convert dataclass fields, namedtuple _asdict() results and Pydantic-style model_dump() results into captured fields. They are on by default. Those reads and methods are application code: they can perform work or access lazily loaded state. A failed conversion falls back to the type name and increments diagnostics().adapter_errors. Set adapters=False, or VEXLO_ADAPTERS=0, to disable conversions. Unrecognized objects then record their type name instead of fields. Save this as adapter_example.py to compare field capture with type-only capture:
The first run called model_dump() once and captured label. The second made no conversion call and recorded the object’s type. The value-walk deadline does not interrupt a slow conversion. Disabling adapters does not disable exception-message or log formatting.

Disable input, output and error values

capture_values=False, or VEXLO_CAPTURE_VALUES=0, skips their value-capture walk. Relevant slots report not_captured. Function names, call relationships, timing and error classes remain available. Tags and captured logs are separate paths and remain enabled if configured. Without captured input, inferred retry matching has no fingerprint. Use @vexlo.step(retries=True) for declared grouping when value capture is disabled.

Use sampling for volume control

Sampling controls retention of captured value bytes, not the capture work itself. A sampled-out value still carries a preview and capture metadata. Failed attempts retain their captured values at every sample rate, subject to capture controls and delivery limits. Disabling value capture and setting the sample rate to zero therefore have different effects. Using the same check, compare a successful and failed root at a zero sample rate:
The successful run’s output preview contains its synthetic credential even though its capture state is sampled_out. The failed run retains a full error value containing its credential. Neither sampling nor name matching is a filter for arbitrary text. Sampling also leaves the input capture used for inferred retry grouping intact. A capture state describes the capture decision, not a guarantee about readable bytes now. Read the value response before interpreting availability.

Service policy

The SDK combines local configuration with a service policy refreshed by the local writer. Local init() values are ceilings: policy can reduce capture but cannot enable a setting disabled there. The administrative interface and the SDK reader support different fields: The SDK checks for policy changes at most once a second. Missing or unreadable files, invalid JSON, a missing or malformed updated_at, or a policy older than 300 seconds restore the initialization settings. They do not preserve the last remote restriction. A valid policy with enabled: false suppressed recording in the captured check; missing, stale and malformed policies restored local capture. A policy byte limit of 32 did not constrain the captured input to 32 bytes. Put required data-handling restrictions in application configuration. Remote policy is a runtime reduction, not a durable privacy lock. Calls already in progress can finish using the configuration selected at entry. Policy changes also do not remove previously captured data. See Configuration for policy administration and Retention for stored data.