-
Notifications
You must be signed in to change notification settings - Fork 423
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(botocore): patch stepfunctions (#7514)
Patch botocore stepfunctions start-execution and start-sync-execution. We want to be able to add trace context to the `input` so the stepfunction logs trace reducer can link stepfunction traces to upstream traces. ## Checklist - [x] Change(s) are motivated and described in the PR description. - [x] Testing strategy is described if automated tests are not included in the PR. - [x] Risk is outlined (performance impact, potential for breakage, maintainability, etc). - [x] Change is maintainable (easy to change, telemetry, documentation). - [x] [Library release note guidelines](https://ddtrace.readthedocs.io/en/stable/releasenotes.html) are followed. If no release note is required, add label `changelog/no-changelog`. - [x] Documentation is included (in-code, generated user docs, [public corp docs](https://github.com/DataDog/documentation/)). - [x] Backport labels are set (if [applicable](https://ddtrace.readthedocs.io/en/latest/contributing.html#backporting)) ## Reviewer Checklist - [x] Title is accurate. - [x] No unnecessary changes are introduced. - [x] Description motivates each change. - [x] Avoids breaking [API](https://ddtrace.readthedocs.io/en/stable/versioning.html#interfaces) changes unless absolutely necessary. - [x] Testing strategy adequately addresses listed risk(s). - [x] Change is maintainable (easy to change, telemetry, documentation). - [x] Release note makes sense to a user of the library. - [x] Reviewer has explicitly acknowledged and discussed the performance implications of this PR as reported in the benchmarks PR comment. - [x] Backport labels are set in a manner that is consistent with the [release branch maintenance policy](https://ddtrace.readthedocs.io/en/latest/contributing.html#backporting) - [x] If this PR touches code that signs or publishes builds or packages, or handles credentials of any kind, I've requested a review from `@DataDog/security-design-and-guidance`. - [x] This PR doesn't touch any of that. --------- Co-authored-by: Tahir H. Butt <[email protected]> Co-authored-by: Zachary Groves <[email protected]> Co-authored-by: Emmett Butler <[email protected]>
- Loading branch information
1 parent
7c75365
commit f7fa041
Showing
4 changed files
with
185 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
import json | ||
from typing import Any # noqa:F401 | ||
from typing import Dict # noqa:F401 | ||
|
||
import botocore.exceptions | ||
|
||
from ddtrace import Span # noqa:F401 | ||
from ddtrace import config | ||
from ddtrace.ext import http | ||
from ddtrace.propagation.http import HTTPPropagator | ||
|
||
from ....ext import SpanTypes | ||
from ....internal.logger import get_logger | ||
from ....internal.schema import SpanDirection | ||
from ....internal.schema import schematize_cloud_messaging_operation | ||
from ....internal.schema import schematize_service_name | ||
from ..utils import set_patched_api_call_span_tags | ||
from ..utils import set_response_metadata_tags | ||
|
||
|
||
log = get_logger(__name__) | ||
|
||
|
||
def inject_trace_to_stepfunction_input(params, span): | ||
# type: (Any, Span) -> None | ||
""" | ||
:params: contains the params for the current botocore action | ||
:span: the span which provides the trace context to be propagated | ||
Inject the trace headers into the StepFunction input if the input is a JSON string | ||
""" | ||
if "input" not in params: | ||
log.warning("Unable to inject context. The StepFunction input had no input.") | ||
return | ||
|
||
if params["input"] is None: | ||
log.warning("Unable to inject context. The StepFunction input was None.") | ||
return | ||
|
||
elif isinstance(params["input"], dict): | ||
if "_datadog" in params["input"]: | ||
log.warning("Input already has trace context.") | ||
return | ||
params["input"]["_datadog"] = {} | ||
HTTPPropagator.inject(span.context, params["input"]["_datadog"]) | ||
return | ||
|
||
elif isinstance(params["input"], str): | ||
try: | ||
input_obj = json.loads(params["input"]) | ||
except ValueError: | ||
log.warning("Input is not a valid JSON string") | ||
return | ||
|
||
if isinstance(input_obj, dict): | ||
input_obj["_datadog"] = {} | ||
HTTPPropagator.inject(span.context, input_obj["_datadog"]) | ||
input_json = json.dumps(input_obj) | ||
|
||
params["input"] = input_json | ||
return | ||
else: | ||
log.warning("Unable to inject context. The StepFunction input was not a dict.") | ||
return | ||
|
||
else: | ||
log.warning("Unable to inject context. The StepFunction input was not a dict or a JSON string.") | ||
|
||
|
||
def patched_stepfunction_api_call(original_func, instance, args, kwargs: Dict, function_vars: Dict): | ||
params = function_vars.get("params") | ||
trace_operation = function_vars.get("trace_operation") | ||
pin = function_vars.get("pin") | ||
endpoint_name = function_vars.get("endpoint_name") | ||
operation = function_vars.get("operation") | ||
|
||
with pin.tracer.trace( | ||
trace_operation, | ||
service=schematize_service_name("{}.{}".format(pin.service, endpoint_name)), | ||
span_type=SpanTypes.HTTP, | ||
) as span: | ||
set_patched_api_call_span_tags(span, instance, args, params, endpoint_name, operation) | ||
|
||
if args: | ||
if config.botocore["distributed_tracing"]: | ||
try: | ||
if endpoint_name == "states" and operation in {"StartExecution", "StartSyncExecution"}: | ||
inject_trace_to_stepfunction_input(params, span) | ||
span.name = schematize_cloud_messaging_operation( | ||
trace_operation, | ||
cloud_provider="aws", | ||
cloud_service="stepfunctions", | ||
direction=SpanDirection.OUTBOUND, | ||
) | ||
except Exception: | ||
log.warning("Unable to inject trace context", exc_info=True) | ||
|
||
try: | ||
return original_func(*args, **kwargs) | ||
except botocore.exceptions.ClientError as e: | ||
set_response_metadata_tags(span, e.response) | ||
|
||
# If we have a status code, and the status code is not an error, | ||
# then ignore the exception being raised | ||
status_code = span.get_tag(http.STATUS_CODE) | ||
if status_code and not config.botocore.operations[span.resource].is_error_code(int(status_code)): | ||
span._ignore_exception(botocore.exceptions.ClientError) | ||
raise |
5 changes: 5 additions & 0 deletions
5
releasenotes/notes/inject-botocore-stepfunction-start_execution-calls-95bed0ca2e1d006e.yaml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
features: | ||
- | | ||
botocore: Add the ability to inject trace context into the input field of botocore stepfunction start_execution and | ||
start_sync_execution calls. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters