aws-durable-execution-sdk-python-telemetry-exporter 0.0.1__tar.gz → 0.0.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {aws_durable_execution_sdk_python_telemetry_exporter-0.0.1 → aws_durable_execution_sdk_python_telemetry_exporter-0.0.2}/.gitignore +1 -0
- aws_durable_execution_sdk_python_telemetry_exporter-0.0.2/PKG-INFO +401 -0
- aws_durable_execution_sdk_python_telemetry_exporter-0.0.2/README.md +378 -0
- {aws_durable_execution_sdk_python_telemetry_exporter-0.0.1 → aws_durable_execution_sdk_python_telemetry_exporter-0.0.2}/pyproject.toml +8 -2
- {aws_durable_execution_sdk_python_telemetry_exporter-0.0.1 → aws_durable_execution_sdk_python_telemetry_exporter-0.0.2}/src/aws_durable_execution_sdk_python_telemetry_exporter/__about__.py +1 -1
- {aws_durable_execution_sdk_python_telemetry_exporter-0.0.1 → aws_durable_execution_sdk_python_telemetry_exporter-0.0.2}/src/aws_durable_execution_sdk_python_telemetry_exporter/__init__.py +3 -4
- aws_durable_execution_sdk_python_telemetry_exporter-0.0.2/src/aws_durable_execution_sdk_python_telemetry_exporter/_export_scheduler.py +656 -0
- {aws_durable_execution_sdk_python_telemetry_exporter-0.0.1 → aws_durable_execution_sdk_python_telemetry_exporter-0.0.2}/src/aws_durable_execution_sdk_python_telemetry_exporter/exporters/dynamodb_exporter.py +40 -4
- aws_durable_execution_sdk_python_telemetry_exporter-0.0.2/src/aws_durable_execution_sdk_python_telemetry_exporter/exporters/lambda_log_exporter.py +90 -0
- {aws_durable_execution_sdk_python_telemetry_exporter-0.0.1 → aws_durable_execution_sdk_python_telemetry_exporter-0.0.2}/src/aws_durable_execution_sdk_python_telemetry_exporter/exporters/otel_exporter.py +2 -1
- aws_durable_execution_sdk_python_telemetry_exporter-0.0.2/src/aws_durable_execution_sdk_python_telemetry_exporter/plugin.py +936 -0
- {aws_durable_execution_sdk_python_telemetry_exporter-0.0.1 → aws_durable_execution_sdk_python_telemetry_exporter-0.0.2}/src/aws_durable_execution_sdk_python_telemetry_exporter/truncation.py +53 -11
- {aws_durable_execution_sdk_python_telemetry_exporter-0.0.1 → aws_durable_execution_sdk_python_telemetry_exporter-0.0.2}/src/aws_durable_execution_sdk_python_telemetry_exporter/types.py +42 -1
- {aws_durable_execution_sdk_python_telemetry_exporter-0.0.1 → aws_durable_execution_sdk_python_telemetry_exporter-0.0.2}/tests/e2e/wait_suspend_resume_int_test.py +8 -5
- aws_durable_execution_sdk_python_telemetry_exporter-0.0.2/tests/test_error_and_result_format.py +415 -0
- aws_durable_execution_sdk_python_telemetry_exporter-0.0.2/tests/test_export_scheduler.py +1218 -0
- {aws_durable_execution_sdk_python_telemetry_exporter-0.0.1 → aws_durable_execution_sdk_python_telemetry_exporter-0.0.2}/tests/test_exporters.py +37 -9
- aws_durable_execution_sdk_python_telemetry_exporter-0.0.2/tests/test_package_metadata.py +122 -0
- aws_durable_execution_sdk_python_telemetry_exporter-0.0.2/tests/test_plugin.py +1948 -0
- aws_durable_execution_sdk_python_telemetry_exporter-0.0.2/tests/test_public_path_limits.py +468 -0
- {aws_durable_execution_sdk_python_telemetry_exporter-0.0.1 → aws_durable_execution_sdk_python_telemetry_exporter-0.0.2}/tests/test_shaping.py +64 -0
- aws_durable_execution_sdk_python_telemetry_exporter-0.0.2/tests/test_timestamp_format.py +301 -0
- aws_durable_execution_sdk_python_telemetry_exporter-0.0.1/PKG-INFO +0 -256
- aws_durable_execution_sdk_python_telemetry_exporter-0.0.1/README.md +0 -233
- aws_durable_execution_sdk_python_telemetry_exporter-0.0.1/src/aws_durable_execution_sdk_python_telemetry_exporter/_export_scheduler.py +0 -178
- aws_durable_execution_sdk_python_telemetry_exporter-0.0.1/src/aws_durable_execution_sdk_python_telemetry_exporter/exporters/lambda_log_exporter.py +0 -41
- aws_durable_execution_sdk_python_telemetry_exporter-0.0.1/src/aws_durable_execution_sdk_python_telemetry_exporter/plugin.py +0 -452
- aws_durable_execution_sdk_python_telemetry_exporter-0.0.1/tests/test_export_scheduler.py +0 -255
- aws_durable_execution_sdk_python_telemetry_exporter-0.0.1/tests/test_plugin.py +0 -663
- {aws_durable_execution_sdk_python_telemetry_exporter-0.0.1 → aws_durable_execution_sdk_python_telemetry_exporter-0.0.2}/LICENSE +0 -0
- {aws_durable_execution_sdk_python_telemetry_exporter-0.0.1 → aws_durable_execution_sdk_python_telemetry_exporter-0.0.2}/NOTICE +0 -0
- {aws_durable_execution_sdk_python_telemetry_exporter-0.0.1 → aws_durable_execution_sdk_python_telemetry_exporter-0.0.2}/src/aws_durable_execution_sdk_python_telemetry_exporter/exporters/__init__.py +0 -0
- {aws_durable_execution_sdk_python_telemetry_exporter-0.0.1 → aws_durable_execution_sdk_python_telemetry_exporter-0.0.2}/src/aws_durable_execution_sdk_python_telemetry_exporter/exporters/_common.py +0 -0
- {aws_durable_execution_sdk_python_telemetry_exporter-0.0.1 → aws_durable_execution_sdk_python_telemetry_exporter-0.0.2}/src/aws_durable_execution_sdk_python_telemetry_exporter/exporters/aurora_exporter.py +0 -0
- {aws_durable_execution_sdk_python_telemetry_exporter-0.0.1 → aws_durable_execution_sdk_python_telemetry_exporter-0.0.2}/src/aws_durable_execution_sdk_python_telemetry_exporter/exporters/cloudwatch_logs_exporter.py +0 -0
- {aws_durable_execution_sdk_python_telemetry_exporter-0.0.1 → aws_durable_execution_sdk_python_telemetry_exporter-0.0.2}/src/aws_durable_execution_sdk_python_telemetry_exporter/exporters/eventbridge_exporter.py +0 -0
- {aws_durable_execution_sdk_python_telemetry_exporter-0.0.1 → aws_durable_execution_sdk_python_telemetry_exporter-0.0.2}/src/aws_durable_execution_sdk_python_telemetry_exporter/exporters/file_exporter.py +0 -0
- {aws_durable_execution_sdk_python_telemetry_exporter-0.0.1 → aws_durable_execution_sdk_python_telemetry_exporter-0.0.2}/src/aws_durable_execution_sdk_python_telemetry_exporter/exporters/firehose_exporter.py +0 -0
- {aws_durable_execution_sdk_python_telemetry_exporter-0.0.1 → aws_durable_execution_sdk_python_telemetry_exporter-0.0.2}/src/aws_durable_execution_sdk_python_telemetry_exporter/exporters/http_exporter.py +0 -0
- {aws_durable_execution_sdk_python_telemetry_exporter-0.0.1 → aws_durable_execution_sdk_python_telemetry_exporter-0.0.2}/src/aws_durable_execution_sdk_python_telemetry_exporter/exporters/opensearch_exporter.py +0 -0
- {aws_durable_execution_sdk_python_telemetry_exporter-0.0.1 → aws_durable_execution_sdk_python_telemetry_exporter-0.0.2}/src/aws_durable_execution_sdk_python_telemetry_exporter/exporters/redshift_exporter.py +0 -0
- {aws_durable_execution_sdk_python_telemetry_exporter-0.0.1 → aws_durable_execution_sdk_python_telemetry_exporter-0.0.2}/src/aws_durable_execution_sdk_python_telemetry_exporter/exporters/s3_exporter.py +0 -0
- {aws_durable_execution_sdk_python_telemetry_exporter-0.0.1 → aws_durable_execution_sdk_python_telemetry_exporter-0.0.2}/src/aws_durable_execution_sdk_python_telemetry_exporter/exporters/sqs_exporter.py +0 -0
- {aws_durable_execution_sdk_python_telemetry_exporter-0.0.1 → aws_durable_execution_sdk_python_telemetry_exporter-0.0.2}/src/aws_durable_execution_sdk_python_telemetry_exporter/operations_index.py +0 -0
- {aws_durable_execution_sdk_python_telemetry_exporter-0.0.1 → aws_durable_execution_sdk_python_telemetry_exporter-0.0.2}/src/aws_durable_execution_sdk_python_telemetry_exporter/py.typed +0 -0
- {aws_durable_execution_sdk_python_telemetry_exporter-0.0.1 → aws_durable_execution_sdk_python_telemetry_exporter-0.0.2}/tests/__init__.py +0 -0
- {aws_durable_execution_sdk_python_telemetry_exporter-0.0.1 → aws_durable_execution_sdk_python_telemetry_exporter-0.0.2}/tests/e2e/__init__.py +0 -0
- {aws_durable_execution_sdk_python_telemetry_exporter-0.0.1 → aws_durable_execution_sdk_python_telemetry_exporter-0.0.2}/tests/e2e/exporters_lifecycle_int_test.py +0 -0
- {aws_durable_execution_sdk_python_telemetry_exporter-0.0.1 → aws_durable_execution_sdk_python_telemetry_exporter-0.0.2}/tests/test_aurora_exporter.py +0 -0
- {aws_durable_execution_sdk_python_telemetry_exporter-0.0.1 → aws_durable_execution_sdk_python_telemetry_exporter-0.0.2}/tests/test_cloudwatch_logs_exporter.py +0 -0
- {aws_durable_execution_sdk_python_telemetry_exporter-0.0.1 → aws_durable_execution_sdk_python_telemetry_exporter-0.0.2}/tests/test_config.py +0 -0
- {aws_durable_execution_sdk_python_telemetry_exporter-0.0.1 → aws_durable_execution_sdk_python_telemetry_exporter-0.0.2}/tests/test_dynamodb_exporter.py +0 -0
- {aws_durable_execution_sdk_python_telemetry_exporter-0.0.1 → aws_durable_execution_sdk_python_telemetry_exporter-0.0.2}/tests/test_eventbridge_exporter.py +0 -0
- {aws_durable_execution_sdk_python_telemetry_exporter-0.0.1 → aws_durable_execution_sdk_python_telemetry_exporter-0.0.2}/tests/test_file_exporter.py +0 -0
- {aws_durable_execution_sdk_python_telemetry_exporter-0.0.1 → aws_durable_execution_sdk_python_telemetry_exporter-0.0.2}/tests/test_firehose_exporter.py +0 -0
- {aws_durable_execution_sdk_python_telemetry_exporter-0.0.1 → aws_durable_execution_sdk_python_telemetry_exporter-0.0.2}/tests/test_http_exporter.py +0 -0
- {aws_durable_execution_sdk_python_telemetry_exporter-0.0.1 → aws_durable_execution_sdk_python_telemetry_exporter-0.0.2}/tests/test_opensearch_exporter.py +0 -0
- {aws_durable_execution_sdk_python_telemetry_exporter-0.0.1 → aws_durable_execution_sdk_python_telemetry_exporter-0.0.2}/tests/test_otel_exporter.py +0 -0
- {aws_durable_execution_sdk_python_telemetry_exporter-0.0.1 → aws_durable_execution_sdk_python_telemetry_exporter-0.0.2}/tests/test_redshift_exporter.py +0 -0
- {aws_durable_execution_sdk_python_telemetry_exporter-0.0.1 → aws_durable_execution_sdk_python_telemetry_exporter-0.0.2}/tests/test_sqs_exporter.py +0 -0
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: aws-durable-execution-sdk-python-telemetry-exporter
|
|
3
|
+
Version: 0.0.2
|
|
4
|
+
Summary: Durable Execution Telemetry instrumentation plugin for the AWS Durable Execution SDK for Python
|
|
5
|
+
Project-URL: Documentation, https://github.com/aws/aws-durable-execution-sdk-python#readme
|
|
6
|
+
Project-URL: Issues, https://github.com/aws/aws-durable-execution-sdk-python/issues
|
|
7
|
+
Project-URL: Source, https://github.com/aws/aws-durable-execution-sdk-python
|
|
8
|
+
Author-email: AWS durable-execution-dev <durable-execution-dev@amazon.com>
|
|
9
|
+
License-Expression: Apache-2.0
|
|
10
|
+
Keywords: durable-execution,durable-execution-telemetry,observability
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Programming Language :: Python
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
17
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
18
|
+
Requires-Python: >=3.11
|
|
19
|
+
Requires-Dist: aws-durable-execution-sdk-python<4,>=3.0.0
|
|
20
|
+
Provides-Extra: s3
|
|
21
|
+
Requires-Dist: boto3>=1.26.0; extra == 's3'
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
|
|
24
|
+
# AWS Durable Execution SDK for Python — Durable Execution Telemetry plugin
|
|
25
|
+
|
|
26
|
+
Durable Execution Telemetry instrumentation plugin for the AWS Durable Execution SDK for
|
|
27
|
+
Python. A port of the JavaScript SDK's `durableExecutionTelemetry()` plugin: it listens to
|
|
28
|
+
the SDK's instrumentation hooks and emits one curated `DurableExecutionTelemetry` record
|
|
29
|
+
per execution to the configured exporters. The wire record keeps the JS
|
|
30
|
+
camelCase field names so records read identically across SDKs.
|
|
31
|
+
|
|
32
|
+
> **Experimental.** Like its JS counterpart, this plugin is experimental and may
|
|
33
|
+
> change or be removed in future releases.
|
|
34
|
+
|
|
35
|
+
## Install
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pip install aws-durable-execution-sdk-python-telemetry-exporter
|
|
39
|
+
# with the S3 exporter's local-dev dependency:
|
|
40
|
+
pip install "aws-durable-execution-sdk-python-telemetry-exporter[s3]"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Usage
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
from aws_durable_execution_sdk_python import durable_execution
|
|
47
|
+
from aws_durable_execution_sdk_python_telemetry_exporter import (
|
|
48
|
+
DurableExecutionTelemetryConfig,
|
|
49
|
+
durable_execution_telemetry,
|
|
50
|
+
)
|
|
51
|
+
from aws_durable_execution_sdk_python_telemetry_exporter.exporters import S3Exporter
|
|
52
|
+
|
|
53
|
+
@durable_execution(
|
|
54
|
+
plugins=[
|
|
55
|
+
durable_execution_telemetry(
|
|
56
|
+
DurableExecutionTelemetryConfig(
|
|
57
|
+
exporters=[
|
|
58
|
+
S3Exporter(bucket="my-bucket", prefix="durable-execution-telemetry/")
|
|
59
|
+
],
|
|
60
|
+
)
|
|
61
|
+
)
|
|
62
|
+
]
|
|
63
|
+
)
|
|
64
|
+
def handler(event, context):
|
|
65
|
+
...
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
`durable_execution_telemetry()` returns a plugin *factory*, which is what the SDK's
|
|
69
|
+
`plugins` argument takes: the SDK calls its `create_plugin` once per invocation to
|
|
70
|
+
build that invocation's plugin instance. The factory holds the resolved
|
|
71
|
+
configuration and the exporters, so configuration is per handler while record
|
|
72
|
+
state is per invocation. Its type is `DurableExecutionTelemetryPluginFactory`, exported from
|
|
73
|
+
the package root for annotating a value you hold.
|
|
74
|
+
|
|
75
|
+
With no exporter configured, records are written to the function's own
|
|
76
|
+
CloudWatch log group as single JSON lines (the `LambdaLogExporter` default, see
|
|
77
|
+
below), carrying the name-keyed `operationsByName` summary. The `S3Exporter` writes the
|
|
78
|
+
lossless per-occurrence `operations` array, one object per execution
|
|
79
|
+
(upsert-by-execution-name, so re-emission overwrites rather than appends).
|
|
80
|
+
|
|
81
|
+
## Exporters
|
|
82
|
+
|
|
83
|
+
All exporters live in `aws_durable_execution_sdk_python_telemetry_exporter.exporters` and
|
|
84
|
+
are re-exported from the package root. Each serializes the record as compact
|
|
85
|
+
JSON. Exporters that call AWS accept an injected `client=` for tests and use
|
|
86
|
+
the Lambda runtime's boto3 otherwise; none adds a required dependency.
|
|
87
|
+
|
|
88
|
+
| Exporter | Destination | Upsert | Operations shape | Default size limit |
|
|
89
|
+
| --- | --- | --- | --- | --- |
|
|
90
|
+
| `LambdaLogExporter` | Function's own log group | No | `operationsByName` | 256 KB |
|
|
91
|
+
| `CloudWatchLogsExporter` | Any log group, one stream per day | No | `operationsByName` | 256 KB |
|
|
92
|
+
| `S3Exporter` | S3 object per execution | Yes (key) | `operations` | 5 MB |
|
|
93
|
+
| `DynamoDBExporter` | DynamoDB item | Configurable | `operationsByName` | 400 KB |
|
|
94
|
+
| `AuroraExporter` | Aurora MySQL/PostgreSQL row (Data API) | Yes (upsert) | full record as JSON column | 1 MB |
|
|
95
|
+
| `RedshiftExporter` | Redshift row (Data API) | Yes (MERGE) | full record as SUPER column | 1 MB |
|
|
96
|
+
| `OpenSearchExporter` | OpenSearch document | Yes (`_id`) | `operations` | 10 MB |
|
|
97
|
+
| `FirehoseExporter` | Firehose delivery stream | N/A | `operations_format` | 1 MB |
|
|
98
|
+
| `EventBridgeExporter` | EventBridge event | N/A | `operations_format` | 256 KB |
|
|
99
|
+
| `SQSExporter` | SQS message | N/A | `operations_format` | 256 KB |
|
|
100
|
+
| `OTelExporter` | OTLP/HTTP logs endpoint | N/A | `operations_format` | 1 MB |
|
|
101
|
+
| `HttpExporter` | Any HTTP endpoint | N/A | `operations_format` | none |
|
|
102
|
+
| `FileExporter` | Directory (EFS, mount, `/tmp`) | Configurable | `operations_format` | none |
|
|
103
|
+
|
|
104
|
+
`operations_format` is `"array"` (default), `"by-name"`, or `"both"`
|
|
105
|
+
(`OperationsFormat`). `max_record_size_bytes` raises or lowers an exporter's
|
|
106
|
+
size limit; omitting it keeps the default. `HttpExporter` and `FileExporter`
|
|
107
|
+
have no default and do not truncate unless a limit is set.
|
|
108
|
+
|
|
109
|
+
### LambdaLogExporter
|
|
110
|
+
|
|
111
|
+
Prints one line per record to stdout, which Lambda sends to the function's own
|
|
112
|
+
log group. The line is the Lambda JSON log envelope, with keys in this order:
|
|
113
|
+
|
|
114
|
+
```json
|
|
115
|
+
{"timestamp":"2026-01-01T00:00:01.234Z","level":"INFO","message":"<compact record JSON>"}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
`timestamp` is UTC with millisecond precision and a `Z` suffix. `message` is
|
|
119
|
+
the compact record JSON as a string; parse it to get the record. The exporter
|
|
120
|
+
writes the envelope itself because Lambda captures Python `print` output as
|
|
121
|
+
plain text, in both the plain text and the JSON log format, and Lambda does not
|
|
122
|
+
double-encode output that is already JSON (see
|
|
123
|
+
[Log and monitor Python Lambda functions](https://docs.aws.amazon.com/lambda/latest/dg/python-logging.html)
|
|
124
|
+
and [Lambda log formats](https://docs.aws.amazon.com/lambda/latest/dg/monitoring-cloudwatchlogs-logformat.html)).
|
|
125
|
+
|
|
126
|
+
`max_record_size_bytes` (default 256,000 bytes) limits the printed line: the
|
|
127
|
+
envelope, including the JSON escaping of `message`, in UTF-8 bytes without the
|
|
128
|
+
trailing newline. Truncation measures that line in one pass. A CloudWatch Logs
|
|
129
|
+
event can be up to 1 MB
|
|
130
|
+
([PutLogEvents](https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_PutLogEvents.html)).
|
|
131
|
+
U+2028 and U+2029 are written as `\u2028` and `\u2029`, so a tool that treats
|
|
132
|
+
them as line breaks still sees one line per record. A lone surrogate (a string
|
|
133
|
+
character with no UTF-8 encoding) is written as its `\uXXXX` escape, so
|
|
134
|
+
printing it never fails. The limit counts these escapes; other exporters'
|
|
135
|
+
limits count the characters as they write them.
|
|
136
|
+
|
|
137
|
+
The lines have `level` `INFO`. With the JSON log format and an application log
|
|
138
|
+
level of `WARN` or above, Lambda drops them. With the Text log format, Lambda
|
|
139
|
+
does not filter them.
|
|
140
|
+
|
|
141
|
+
### CloudWatchLogsExporter
|
|
142
|
+
|
|
143
|
+
Writes one `PutLogEvents` event per record to `log_group_name`, in a stream
|
|
144
|
+
named `{log_stream_prefix}{YYYY}/{MM}/{DD}` (default prefix `durable-execution-telemetry/`).
|
|
145
|
+
IAM: `logs:CreateLogStream`, `logs:PutLogEvents` on the log group.
|
|
146
|
+
|
|
147
|
+
```python
|
|
148
|
+
CloudWatchLogsExporter(log_group_name="/custom/durable-execution-telemetry")
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### DynamoDBExporter
|
|
152
|
+
|
|
153
|
+
`PutItem` keyed by `partition_key` (default `pk`) = `executionArn`. With the
|
|
154
|
+
default `sort_key="sk"` (= `emittedAt`) every export adds an item; pass
|
|
155
|
+
`sort_key=None` for a key-only table that upserts. IAM: `dynamodb:PutItem`.
|
|
156
|
+
A number DynamoDB cannot store (more than 38 significant digits, a magnitude
|
|
157
|
+
outside 1E-130 to 9.99...E+125, NaN or Infinity) is written as a string
|
|
158
|
+
attribute holding its JSON text, so it never drops the item. The same field can
|
|
159
|
+
therefore be a number (`N`) in one item and a string (`S`) in another; readers
|
|
160
|
+
that filter or compare on the attribute type should allow for both. An integer
|
|
161
|
+
with more than 38 digits but at most 38 significant digits, such as `10**38`,
|
|
162
|
+
is stored as a number.
|
|
163
|
+
|
|
164
|
+
```python
|
|
165
|
+
DynamoDBExporter(table_name="durable-execution-telemetry")
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### AuroraExporter
|
|
169
|
+
|
|
170
|
+
Upserts a row by `execution_arn` through the RDS Data API; `engine` is
|
|
171
|
+
`"postgresql"` or `"mysql"` and selects the dialect. Columns: `execution_arn,
|
|
172
|
+
execution_name, function_name, status, start_time, end_time, duration_ms,
|
|
173
|
+
record_json, emitted_at`. IAM: `rds-data:ExecuteStatement`,
|
|
174
|
+
`secretsmanager:GetSecretValue`.
|
|
175
|
+
|
|
176
|
+
```python
|
|
177
|
+
AuroraExporter(
|
|
178
|
+
resource_arn="arn:aws:rds:us-east-1:123456789012:cluster:my-cluster",
|
|
179
|
+
secret_arn="arn:aws:secretsmanager:us-east-1:123456789012:secret:my-db-creds",
|
|
180
|
+
database="telemetry",
|
|
181
|
+
engine="postgresql",
|
|
182
|
+
)
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### RedshiftExporter
|
|
186
|
+
|
|
187
|
+
`MERGE` by `execution_arn` through the Redshift Data API into
|
|
188
|
+
`{schema}.{table}` (default `public.durable_execution_telemetry`, same columns as Aurora,
|
|
189
|
+
`record_json` as `SUPER`). Provide `workgroup_name` (Serverless) or
|
|
190
|
+
`cluster_identifier` (provisioned, with `db_user` or `secret_arn`). IAM:
|
|
191
|
+
`redshift-data:ExecuteStatement` plus `redshift-serverless:GetCredentials` or
|
|
192
|
+
`secretsmanager:GetSecretValue`. The statement is submitted and not awaited, so
|
|
193
|
+
statement failures are not reported and `on-change` records may land out of
|
|
194
|
+
order; prefer the default `on-complete` emit mode with this exporter.
|
|
195
|
+
|
|
196
|
+
```python
|
|
197
|
+
RedshiftExporter(database="telemetry", workgroup_name="telemetry-wg")
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### OpenSearchExporter
|
|
201
|
+
|
|
202
|
+
`PUT {endpoint}/{index_name}/_doc/{executionArn}` (default index
|
|
203
|
+
`durable-execution-telemetry`). `auth="sigv4"` (default) signs with the runtime's
|
|
204
|
+
credentials via botocore; `auth="basic"` uses `username`/`password`. IAM:
|
|
205
|
+
`es:ESHttpPut` on the domain.
|
|
206
|
+
|
|
207
|
+
```python
|
|
208
|
+
OpenSearchExporter(endpoint="https://my-domain.us-east-1.es.amazonaws.com", region="us-east-1")
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### FirehoseExporter
|
|
212
|
+
|
|
213
|
+
`PutRecord` of one JSON line (trailing newline) per record. IAM:
|
|
214
|
+
`firehose:PutRecord`.
|
|
215
|
+
|
|
216
|
+
```python
|
|
217
|
+
FirehoseExporter(delivery_stream_name="durable-execution-telemetry-stream")
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### EventBridgeExporter
|
|
221
|
+
|
|
222
|
+
`PutEvents` with `Source` (default `software.amazon.lambda.durable.telemetry`),
|
|
223
|
+
`DetailType` = record status, `Detail` = record. All arguments optional. IAM:
|
|
224
|
+
`events:PutEvents`.
|
|
225
|
+
|
|
226
|
+
```python
|
|
227
|
+
EventBridgeExporter(event_bus_name="default")
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### SQSExporter
|
|
231
|
+
|
|
232
|
+
`SendMessage` with the record as body and `status`/`functionName` message
|
|
233
|
+
attributes. A `.fifo` queue URL enables `MessageGroupId` (default
|
|
234
|
+
`executionArn`, or `message_group_id`) and a deduplication id of
|
|
235
|
+
`executionArn:emittedAt`. IAM: `sqs:SendMessage`.
|
|
236
|
+
|
|
237
|
+
```python
|
|
238
|
+
SQSExporter(queue_url="https://sqs.us-east-1.amazonaws.com/123456789012/telemetry")
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### OTelExporter
|
|
242
|
+
|
|
243
|
+
POSTs one OTLP `ExportLogsServiceRequest` (`http/json` only) per record to
|
|
244
|
+
`endpoint`; identity fields become attributes and the record is the log body.
|
|
245
|
+
Pass vendor auth in `headers`. No IAM.
|
|
246
|
+
|
|
247
|
+
```python
|
|
248
|
+
OTelExporter(endpoint="https://otlp.vendor.com/v1/logs", headers={"x-api-key": "..."})
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### HttpExporter
|
|
252
|
+
|
|
253
|
+
`POST` (or `method="PUT"`) the record as JSON to `url` with
|
|
254
|
+
`Content-Type: application/json` plus `headers`; a non-2xx status raises.
|
|
255
|
+
`timeout_ms` defaults to 10000 and currently applies to each socket operation
|
|
256
|
+
(the connect, each write of the request, and each read of the status line,
|
|
257
|
+
headers, and a non-2xx error body; a 2xx body is never read) rather than to the
|
|
258
|
+
whole request, so an endpoint that consumes or responds slowly can hold the
|
|
259
|
+
export open longer than `timeout_ms`; a future release may enforce it as a
|
|
260
|
+
whole-request deadline. No IAM.
|
|
261
|
+
|
|
262
|
+
```python
|
|
263
|
+
HttpExporter(url="https://hooks.example.com/telemetry", headers={"Authorization": "Bearer ..."})
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### FileExporter
|
|
267
|
+
|
|
268
|
+
`mode="ndjson"` (default) appends to `{directory}/{YYYY-MM-DD}.ndjson`;
|
|
269
|
+
`mode="json"` writes `{directory}/{executionName}.json`, overwriting on update.
|
|
270
|
+
For Lambda use an EFS mount (IAM: `elasticfilesystem:ClientMount`,
|
|
271
|
+
`elasticfilesystem:ClientWrite`) or `/tmp` for testing. Appends from many
|
|
272
|
+
concurrent environments to one NDJSON file on a network file system can
|
|
273
|
+
interleave; use `mode="json"` when several environments share a directory.
|
|
274
|
+
|
|
275
|
+
```python
|
|
276
|
+
FileExporter(directory="/mnt/efs/durable-execution-telemetry")
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
Emission behavior, record schema (`recordType: DurableExecutionTelemetry`,
|
|
280
|
+
`schemaVersion: "1.0"`), sampling, content configuration (input/output
|
|
281
|
+
omission, `include_errors`, per-operation result opt-in), truncation phases,
|
|
282
|
+
and `top-level` vs `full-tree` operation detail all mirror the JS plugin.
|
|
283
|
+
Behavior is validated cross-SDK by the `telemetry` conformance suite
|
|
284
|
+
(`aws-durable-execution-conformance-tests-telemetry`).
|
|
285
|
+
|
|
286
|
+
Record timestamps (`emittedAt`, `startTime`, `endTime`, and each operation's
|
|
287
|
+
`startTime` and `endTime`) use one fixed-width UTC format:
|
|
288
|
+
`YYYY-MM-DDTHH:MM:SS.sssZ`, for example `2026-10-23T18:42:40.784Z`. The
|
|
289
|
+
fraction always has exactly 3 digits, and the suffix is always `Z`. The plugin
|
|
290
|
+
converts each time to UTC and truncates it to milliseconds. JavaScript's
|
|
291
|
+
`Date.prototype.toISOString()` writes the same format. Stores such as DynamoDB
|
|
292
|
+
compare these values as text. Text order equals time order only when every
|
|
293
|
+
value has the same width. So a text comparison of two record timestamps orders
|
|
294
|
+
them by time.
|
|
295
|
+
|
|
296
|
+
`emittedAt` strictly increases within one invocation. In `on-change` mode, one
|
|
297
|
+
invocation can build two records in the same millisecond. The SQS FIFO
|
|
298
|
+
deduplication id and the default DynamoDB sort key both use `emittedAt`. So
|
|
299
|
+
equal values would drop or overwrite a record. So when the clock has not
|
|
300
|
+
passed the previous `emittedAt`, the plugin writes the previous value plus 1
|
|
301
|
+
millisecond.
|
|
302
|
+
|
|
303
|
+
> **Note (asynchronous export).** Export rendering, truncation, `export()`, and
|
|
304
|
+
> `flush()` run on one lazy background worker per registered factory. Checkpoint
|
|
305
|
+
> hooks only replace the latest pending snapshot and wake the worker. Consecutive
|
|
306
|
+
> `on-change` snapshots may coalesce while an export is in flight. Every
|
|
307
|
+
> sampled-in invocation end waits for a covering flush to complete after its
|
|
308
|
+
> drain starts, including an end that emitted no record. Overlapping ends may
|
|
309
|
+
> share a flush when it covers both entry snapshots. Only a sampled-out execution
|
|
310
|
+
> neither exports nor flushes. Exporter failures are logged and isolated; this is
|
|
311
|
+
> best-effort telemetry, not a guarantee of delivery to the destination.
|
|
312
|
+
|
|
313
|
+
> **Note (invocation-end latency under concurrency).** The drain an invocation
|
|
314
|
+
> end performs captures a finite snapshot of work already scheduled across the
|
|
315
|
+
> factory's executions. It waits until those records have been offered to the
|
|
316
|
+
> exporters and a covering flush completes. If a pending record is coalesced, its
|
|
317
|
+
> replacement satisfies the earlier obligation. Once the worker takes that
|
|
318
|
+
> replacement, later records for the same execution belong to a new queue slot.
|
|
319
|
+
> Later drains cannot extend an earlier flush target: they share a covering
|
|
320
|
+
> target or queue a subsequent one. Thus continuing arrivals do not move an
|
|
321
|
+
> earlier drain's finish line. One worker serializes exports and flushes, so
|
|
322
|
+
> invocation-end latency still includes other executions' work present at entry
|
|
323
|
+
> and any earlier flushes. Budget for that finite backlog, especially when an
|
|
324
|
+
> exporter makes a network call per record.
|
|
325
|
+
|
|
326
|
+
## Error names and causes
|
|
327
|
+
|
|
328
|
+
Every error in a record (the execution `error`, each `operations[].error`, and
|
|
329
|
+
each `operationsByName.<name>.error`) has the shape
|
|
330
|
+
`{"name": ..., "message": ..., "cause": ...}`, with keys in that order. `name`
|
|
331
|
+
is the SDK's error type, unchanged, and `message` is the error message. `cause`
|
|
332
|
+
has the same shape, recursively, and is present only when the SDK provides a
|
|
333
|
+
cause.
|
|
334
|
+
|
|
335
|
+
In Python, the plugin hooks carry only an `ErrorObject` (type, message, data,
|
|
336
|
+
stack trace) with no cause, so no error in a Python record has a `cause`: not
|
|
337
|
+
the execution `error`, not an operation error. The exporter does not build a
|
|
338
|
+
cause from other operations or from `ErrorData`. `include_errors=False`
|
|
339
|
+
removes operation errors.
|
|
340
|
+
|
|
341
|
+
Every `name` and `message` is capped at 8,192 characters, counted as Unicode
|
|
342
|
+
code points (a Python `str` is a sequence of code points, so a cut never splits
|
|
343
|
+
a character). A longer value keeps its first 8,192 code points followed by `…`.
|
|
344
|
+
|
|
345
|
+
When a record is over its exporter's size limit, truncation first removes every
|
|
346
|
+
`cause` and sets `droppedCauses: true`, then runs its usual steps (operation
|
|
347
|
+
results, then whole operations, then input, then output). Python records have
|
|
348
|
+
no cause, so the first step never changes them. With the name and message
|
|
349
|
+
caps, a record whose operations, input and output are dropped fits any limit of
|
|
350
|
+
64 KB or more, assuming ARN fields of normal length (a few hundred bytes, as in
|
|
351
|
+
real Lambda ARNs) and an error `name` of normal length (a type name such as
|
|
352
|
+
`module.QualName`). Without the `name` assumption, the worst case (a name and
|
|
353
|
+
message of 8,192 control characters, each escaped as `\u00XX`) fits any limit
|
|
354
|
+
of 128 KB (131,072 bytes) or more.
|
|
355
|
+
|
|
356
|
+
Names are each language's own and differ across SDKs. For example, a step that
|
|
357
|
+
throws `PaymentError` can be reported as `StepError` in JS,
|
|
358
|
+
`aws_durable_execution_sdk_python.exceptions.StepError` or `PaymentError` in
|
|
359
|
+
Python, and `StepFailedException` or `PaymentError` in Java. Query error names
|
|
360
|
+
per SDK, or query on `message` and the `cause` chain.
|
|
361
|
+
|
|
362
|
+
## Operation results
|
|
363
|
+
|
|
364
|
+
An opted-in operation `result` (`OperationOverride(result=...)`) is passed to
|
|
365
|
+
the transform as a plain JSON value. When the checkpointed string is the
|
|
366
|
+
default serializer's (`ExtendedTypeSerDes`) envelope, a JSON object whose keys
|
|
367
|
+
are exactly `t` and `v` with a string `t`, it is decoded with that serializer
|
|
368
|
+
and converted to plain JSON:
|
|
369
|
+
|
|
370
|
+
- `int`: unchanged when its absolute value is at most `2**53 - 1`
|
|
371
|
+
(9007199254740991), the largest integer a JavaScript reader parses exactly.
|
|
372
|
+
Otherwise `str(value)`, for example `"12345678901234567"`.
|
|
373
|
+
- `Decimal`: an integer when it is integral and its absolute value is at most
|
|
374
|
+
`2**53 - 1`. Otherwise a float when the float round-trips exactly and is
|
|
375
|
+
within DynamoDB's number range (magnitude 1E-130 to 9.99...E+125). Otherwise `str(value)`, for example `"9007199254740993"`,
|
|
376
|
+
`"12345678901234567.89"` or `"1E+299"`. NaN and Infinity become `null`.
|
|
377
|
+
Every zero, of any sign or exponent (`Decimal("-0")`, `Decimal("-0E+20")`),
|
|
378
|
+
becomes `0` and loses its sign.
|
|
379
|
+
- `datetime` and `date`: `isoformat()`. `UUID`: string. `bytes`: base64.
|
|
380
|
+
`tuple`: list. `BatchResult`: `to_dict()`.
|
|
381
|
+
|
|
382
|
+
Any other result is parsed as JSON, or kept as the raw string when it is not
|
|
383
|
+
JSON. In parsed JSON, NaN and Infinity become `null`, and an integer whose
|
|
384
|
+
absolute value is greater than `2**53 - 1` becomes its decimal string, as
|
|
385
|
+
above; nothing else changes. A
|
|
386
|
+
result that fails to decode keeps its parsed or raw value, and the rest of the
|
|
387
|
+
record is still emitted.
|
|
388
|
+
|
|
389
|
+
The hooks do not say which serializer wrote a result, so the envelope is
|
|
390
|
+
recognized by shape alone. A result written by `JsonSerDes` or a custom
|
|
391
|
+
`SerDes` that has this exact shape is decoded too: `{"t": "s", "v": "x"}` is
|
|
392
|
+
reported as `"x"`. Only the core serializer's known tags are decoded, and the
|
|
393
|
+
core may coerce `v` while decoding: `{"t": "b", "v": "yes"}` is reported as
|
|
394
|
+
`true`. An unknown tag, such as `{"t": "temperature", "v": 21.5}`, fails to
|
|
395
|
+
decode and passes through unchanged.
|
|
396
|
+
|
|
397
|
+
## Requirements
|
|
398
|
+
|
|
399
|
+
- `aws-durable-execution-sdk-python` with the plugin invocation hooks that
|
|
400
|
+
surface `execution_input` / `execution_result` (included since the version
|
|
401
|
+
this package declares as its minimum).
|