diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 000000000..a7f48dfeb --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @DataDog/serverless-aws @DataDog/apm-serverless diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 97a4fbbe4..050624478 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -5,6 +5,8 @@ on: branches: - "main" pull_request: + schedule: + - cron: '0 0,12 * * *' # Runs every day at midnight and noon utc jobs: lint: @@ -41,7 +43,7 @@ jobs: strategy: max-parallel: 4 matrix: - python-version: ['3.7', '3.8', '3.9', '3.10', '3.11'] + python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13'] steps: - name: Checkout @@ -62,75 +64,4 @@ jobs: - name: Run tests run: | source venv/bin/activate - nose2 -v - - integration-test: - runs-on: ubuntu-latest - strategy: - matrix: - runtime-param: ['3.7', '3.8', '3.9', '3.10', '3.11'] - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Set up Node 14 - uses: actions/setup-node@v3 - with: - node-version: 14 - - - name: Cache Node modules - id: cache-node-modules - uses: actions/cache@v3 - with: - path: "**/node_modules" - key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }} - - - name: Set up Python - uses: actions/setup-python@v4 - with: - python-version: 3.9 - - - name: Install Python dependencies - run: | - pip install virtualenv - virtualenv venv - source venv/bin/activate - pip install .[dev] - - - name: Install Serverless Framework - run: sudo yarn global add serverless@^3.7.0 --prefix /usr/local - - name: Install Crossbuild Deps - run: | - sudo apt-get update --allow-releaseinfo-change --fix-missing - sudo apt install -y qemu-user-static binfmt-support - - - name: Install dependencies - if: steps.cache-node-modules.outputs.cache-hit != 'true' - working-directory: tests/integration - run: yarn install - - - name: Run tests - env: - BUILD_LAYERS: true - DD_API_KEY: ${{ secrets.DD_API_KEY }} - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - RUNTIME_PARAM: ${{ matrix.runtime-param }} - run: ./scripts/run_integration_tests.sh - - - name: Send success metric - env: - DD_API_KEY: ${{ secrets.DD_API_KEY }} - run: ./scripts/send_status_metric.sh 0 $DD_API_KEY - - integration-test-failure: - runs-on: ubuntu-latest - needs: [integration-test] - if: always() && (needs.integration-test.result == 'failure') - steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Send a failure metric - env: - DD_API_KEY: ${{ secrets.DD_API_KEY }} - run: ./scripts/send_status_metric.sh 1 $DD_API_KEY + pytest -vv diff --git a/.github/workflows/build_layer.yml b/.github/workflows/build_layer.yml new file mode 100644 index 000000000..789868ed0 --- /dev/null +++ b/.github/workflows/build_layer.yml @@ -0,0 +1,35 @@ +name: Build Layers for system-Tests + +on: + push: + branches: + - "main" + +jobs: + build: + runs-on: ${{ matrix.arch == 'arm64' && 'ubuntu-24.04-arm' || 'ubuntu-latest' }} + + strategy: + matrix: + arch: [arm64, amd64] + python_version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"] + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Patch pyproject.toml + run: | + echo "Patching pyproject.toml to use main branch of dd-trace-py" + sed -i 's|^ddtrace =.*$|ddtrace = { git = "https://github.com/DataDog/dd-trace-py.git" }|' pyproject.toml + + - name: Build layer for Python ${{ matrix.python_version }} on ${{ matrix.arch }} + run: | + echo "Building layer for Python ${{ matrix.python_version }} on ${{ matrix.arch }}" + ARCH=${{ matrix.arch }} PYTHON_VERSION=${{ matrix.python_version }} ./scripts/build_layers.sh + + - name: Upload layer artifact + uses: actions/upload-artifact@v4 + with: + path: .layers/datadog_lambda_py-${{ matrix.arch }}-${{ matrix.python_version }}.zip + name: datadog-lambda-python-${{ matrix.python_version }}-${{ matrix.arch }} diff --git a/.github/workflows/check-size.yml b/.github/workflows/check-size.yml deleted file mode 100644 index c056d09bc..000000000 --- a/.github/workflows/check-size.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: check-size - -on: pull_request - -jobs: - check-size: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Set up Python - uses: actions/setup-python@v4 - with: - python-version: 3.7 - - - name: Install Crossbuild Deps - run: | - sudo apt-get update --allow-releaseinfo-change --fix-missing - sudo apt install -y qemu-user-static binfmt-support - - - name: Install dependencies - run: | - pip install virtualenv - virtualenv venv - source venv/bin/activate - pip install .[dev] - - - name: Build Layers - run: ./scripts/build_layers.sh - - - name: Check Size - run: ./scripts/check_layer_size.sh diff --git a/.github/workflows/system_tests.yml b/.github/workflows/system_tests.yml new file mode 100644 index 000000000..b61725b1a --- /dev/null +++ b/.github/workflows/system_tests.yml @@ -0,0 +1,38 @@ +name: System Tests + +on: + push: + branches: + - main + pull_request: + branches: + - "**" + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Build layer + run: | + ARCH=amd64 PYTHON_VERSION=3.13 ./scripts/build_layers.sh + + - uses: actions/upload-artifact@v4 + with: + path: .layers/datadog_lambda_py-amd64-3.13.zip + name: binaries + + system-tests: + needs: + - build + uses: DataDog/system-tests/.github/workflows/system-tests.yml@main + secrets: inherit + permissions: + contents: read + packages: write + with: + library: python_lambda + binaries_artifact: binaries + scenarios_groups: appsec + skip_empty_scenarios: true diff --git a/.github/workflows/update_deps.yml b/.github/workflows/update_deps.yml index 31025402f..15a3ac665 100644 --- a/.github/workflows/update_deps.yml +++ b/.github/workflows/update_deps.yml @@ -3,30 +3,39 @@ name: update-deps on: schedule: - cron: "0 10 * * *" # Run at 10 am every day + workflow_dispatch: jobs: check: runs-on: ubuntu-latest + environment: + name: protected-main-env steps: + - name: Generate token + id: generate_token + uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6 + with: + app-id: ${{ secrets.GH_APP_ID }} + private-key: ${{ secrets.GH_APP_PRIVATE_KEY }} + - uses: actions/checkout@v3 with: - ssh-key: ${{ secrets.SSH_PRIVATE_KEY }} + token: ${{ steps.generate_token.outputs.token }} - name: Set up Python uses: actions/setup-python@v4 with: - python-version: 3.7 + python-version: 3.13 - name: Update Dependencies run: | - curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python - - source $HOME/.poetry/env - poetry build + pip install poetry poetry update - name: Create Pull Request uses: peter-evans/create-pull-request@v3 with: + token: ${{ steps.generate_token.outputs.token }} commit-message: update dependencies title: Update Dependencies body: | diff --git a/.gitignore b/.gitignore index d6b01dbff..ff0272ba6 100644 --- a/.gitignore +++ b/.gitignore @@ -28,7 +28,6 @@ pip-log.txt # Unit test / coverage reports .coverage .tox -nosetests.xml #Misc .cache/ @@ -42,3 +41,5 @@ nosetests.xml node_modules yarn-lock.json + +.benchmarks diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 000000000..0f36a781d --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,29 @@ +stages: + - pre + - build + +.go-cache: &go-cache + key: datadog-lambda-python-go-cache + policy: pull + +generator: + stage: pre + image: registry.ddbuild.io/images/mirror/golang:alpine + tags: ["arch:amd64"] + cache: *go-cache + script: + - apk add --no-cache gomplate + - gomplate --config ci/config.yaml + artifacts: + paths: + - ci/*-pipeline.yaml + +build-layers: + stage: build + trigger: + include: + - artifact: ci/build-pipeline.yaml + job: generator + strategy: depend + rules: + - when: on_success diff --git a/CODEOWNERS b/CODEOWNERS deleted file mode 100644 index e340f1ed6..000000000 --- a/CODEOWNERS +++ /dev/null @@ -1 +0,0 @@ -* @DataDog/serverless \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index befae3ca1..d632d1513 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -24,7 +24,7 @@ We love pull requests. For new features, consider opening an issue to discuss th ./scripts/build_layers.sh # Publish the a testing layer to your own AWS account, and the ARN will be returned - # Example: VERSION=1 REGIONS=us-east-1 LAYERS=Datadog-Python37 ./scripts/publish_layers.sh + # Example: VERSION=1 REGIONS=us-east-1 LAYERS=Datadog-Python313 ./scripts/publish_layers.sh VERSION= REGIONS= LAYERS= ./scripts/publish_layers.sh ``` diff --git a/Dockerfile b/Dockerfile index 2cf569a7f..8da968fb2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ ARG image -FROM $image +FROM $image as builder ARG runtime @@ -7,19 +7,77 @@ ARG runtime RUN mkdir -p /build/python/lib/$runtime/site-packages WORKDIR /build -# Install datadog_lambda and dependencies from local -COPY . . -RUN pip install . -t ./python/lib/$runtime/site-packages +# Install newer version of GCC on AL2 +RUN set -eux; \ + if command -v yum >/dev/null 2>&1; then \ + yum -y install git gcc10 gcc10-c++; \ + cd /usr/bin; \ + rm gcc && ln -s gcc10-gcc gcc; \ + rm g++ && ln -s gcc10-g++ g++; \ + rm cc && ln -s gcc10-cc cc; \ + fi -# Remove *.pyc files -RUN find ./python/lib/$runtime/site-packages -name \*.pyc -delete +# Add Rust compiler which is needed to build dd-trace-py from source +RUN curl https://sh.rustup.rs -sSf | \ + sh -s -- --default-toolchain stable -y +ENV PATH=/root/.cargo/bin:$PATH -# Strip symbols from ddtrace's binaries. -# TODO (AJ): remove when ddtrace fixes this upstream -RUN find . -name '*.so' -exec strip -g {} \; +# Install datadog_lambda and dependencies from local +COPY . . +RUN pip install --no-cache-dir . -t ./python/lib/$runtime/site-packages # Remove botocore (40MB) to reduce package size. aws-xray-sdk # installs it, while it's already provided by the Lambda Runtime. RUN rm -rf ./python/lib/$runtime/site-packages/botocore* RUN rm -rf ./python/lib/$runtime/site-packages/setuptools RUN rm -rf ./python/lib/$runtime/site-packages/jsonschema/tests +RUN rm -f ./python/lib/$runtime/site-packages/ddtrace/appsec/_iast/_ast/iastpatch*.so +RUN rm -f ./python/lib/$runtime/site-packages/ddtrace/appsec/_iast/_taint_tracking/*.so +RUN rm -f ./python/lib/$runtime/site-packages/ddtrace/appsec/_iast/_stacktrace*.so +# _stack_v2 may not exist for some versions of ddtrace (e.g. under python 3.13) +RUN rm -f ./python/lib/$runtime/site-packages/ddtrace/internal/datadog/profiling/stack_v2/_stack_v2.*.so +# remove *.dist-info directories except any entry_points.txt files and METADATA files required for Appsec Software Composition Analysis +RUN find ./python/lib/$runtime/site-packages/*.dist-info \ + -type f \ + ! \( -name 'entry_points.txt' -o -name 'METADATA' \) \ + -delete +RUN find ./python/lib/$runtime/site-packages -type d -empty -delete + +# Remove requests and dependencies +RUN rm -rf \ + ./python/lib/$runtime/site-packages/requests* \ + ./python/lib/$runtime/site-packages/urllib3* \ + ./python/lib/$runtime/site-packages/certifi* \ + ./python/lib/$runtime/site-packages/idna* \ + ./python/lib/$runtime/site-packages/charset_normalizer* + +# Precompile all .pyc files and remove .py files. This speeds up load time. +# Compile with optimization level 2 (-OO) and PYTHONNODEBUGRANGES=1 to redtce +# size of .pyc files. +# See https://docs.python.org/3/tutorial/modules.html#compiled-python-files +# https://docs.python.org/3.11/using/cmdline.html#cmdoption-O +# https://docs.python.org/3/using/cmdline.html#envvar-PYTHONNODEBUGRANGES +RUN PYTHONNODEBUGRANGES=1 python -OO -m compileall -b ./python/lib/$runtime/site-packages +# remove all .py files except ddtrace/contrib/*/patch.py which are necessary +# for ddtrace.patch to discover instrumationation packages. +RUN find ./python/lib/$runtime/site-packages -name \*.py | grep -v ddtrace/contrib | xargs rm -rf +RUN find ./python/lib/$runtime/site-packages/ddtrace/contrib -name \*.py | grep -v patch.py | xargs rm -rf +RUN find ./python/lib/$runtime/site-packages -name __pycache__ -type d -exec rm -r {} \+ + +# When building ddtrace from branch, remove extra source files. These are +# removed by the ddtrace build process before publishing a wheel to PyPI. +RUN find ./python/lib/$runtime/site-packages/ddtrace -name \*.c -delete +RUN find ./python/lib/$runtime/site-packages/ddtrace -name \*.cpp -delete +RUN find ./python/lib/$runtime/site-packages/ddtrace -name \*.cc -delete +RUN find ./python/lib/$runtime/site-packages/ddtrace -name \*.h -delete +RUN find ./python/lib/$runtime/site-packages/ddtrace -name \*.hpp -delete +RUN find ./python/lib/$runtime/site-packages/ddtrace -name \*.pyx -delete + +# Strip debug symbols using strip -g for all .so files in ddtrace. This is to +# reduce the size when ddtrace is built from sources. The release wheels are +# already stripped of debug symbols. We should revisit this when serverless +# benchmark uses pre-built wheels instead of building from sources. +RUN find ./python/lib/$runtime/site-packages/ddtrace -name "*.so" -exec strip -g {} \; + +FROM scratch +COPY --from=builder /build/python / diff --git a/LICENSE-3rdparty.csv b/LICENSE-3rdparty.csv index e15ac6e59..1cfacb703 100644 --- a/LICENSE-3rdparty.csv +++ b/LICENSE-3rdparty.csv @@ -1,4 +1,13 @@ Component,Origin,License,Copyright +datadog,github.com/DataDog/datadogpy,BSD-3-Clause,"Copyright (c) 2015-Present Datadog, Inc " +wrapt,github.com/GrahamDumpleton/wrapt,BSD-2-Clause,"Copyright (c) 2013-2019, Graham Dumpleton" +ddtrace,github.com/DataDog/dd-trace-py,BSD-3-Clause,"Copyright (c) 2016, Datadog " +urllib3,github.com/urllib3/urllib3,MIT,Copyright (c) 2008-2020 Andrey Petrov and contributors. +ujson,github.com/ultrajson/ultrajson,BSD-3-Clause,"Copyright (c) 2014, Electronic Arts Inc" +importlib_metadata,github.com/python/importlib_metadata,Apache-2.0,Copyright © Jason R. Coombs +boto3,github.com/boto/boto3,Apache-2.0,"Copyright 2013-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved." +typing_extensions,github.com/python/typing_extensions,PSF-2.0,"Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam, The Netherlands. All rights reserved" +requests,github.com/psf/requests,Apache-2.0,"Copyright 2018 Kenneth Reitz" +pytest,github.com/pytest-dev/pytest,MIT,Copyright (c) 2004 Holger Krekel and others +pytest-benchmark,github.com/ionelmc/pytest-benchmark,BSD-2-Clause,"Copyright (c) 2014-2023, Ionel Cristian Mărieș. All rights reserved." flake8,gitlab.com/pycqa/flake8,MIT,"Copyright (C) 2011-2013 Tarek Ziade . Copyright (C) 2012-2016 Ian Cordasco ." -nose2,github.com/nose-devs/nose2,BSD-2-Clause,"Copyright (c) 2012, Jason Pellerin. All rights reserved." -wrapt,github.com/GrahamDumpleton/wrapt,BSD-2-Clause,"Copyright (c) 2013-2019, Graham Dumpleton" \ No newline at end of file diff --git a/README.md b/README.md index e3702b1ba..658babc28 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ [![Slack](https://chat.datadoghq.com/badge.svg?bg=632CA6)](https://chat.datadoghq.com/) [![License](https://img.shields.io/badge/license-Apache--2.0-blue)](https://github.com/DataDog/datadog-lambda-python/blob/main/LICENSE) -Datadog Lambda Library for Python (3.7, 3.8, 3.9, 3.10, and 3.11) enables [enhanced Lambda metrics](https://docs.datadoghq.com/serverless/enhanced_lambda_metrics), [distributed tracing](https://docs.datadoghq.com/serverless/distributed_tracing), and [custom metric submission](https://docs.datadoghq.com/serverless/custom_metrics) from AWS Lambda functions. +Datadog Lambda Library for Python (3.8, 3.9, 3.10, 3.11, 3.12, and 3.13) enables [enhanced Lambda metrics](https://docs.datadoghq.com/serverless/enhanced_lambda_metrics), [distributed tracing](https://docs.datadoghq.com/serverless/distributed_tracing), and [custom metric submission](https://docs.datadoghq.com/serverless/custom_metrics) from AWS Lambda functions. ## Installation @@ -24,11 +24,12 @@ Besides the environment variables supported by dd-trace-py, the datadog-lambda-p | -------------------- | ------------ | ------------- | | DD_ENCODE_AUTHORIZER_CONTEXT | When set to `true` for Lambda authorizers, the tracing context will be encoded into the response for propagation. Supported for NodeJS and Python. | `true` | | DD_DECODE_AUTHORIZER_CONTEXT | When set to `true` for Lambdas that are authorized via Lambda authorizers, it will parse and use the encoded tracing context (if found). Supported for NodeJS and Python. | `true` | -| DD_COLD_START_TRACING | Set to `false` to disable Cold Start Tracing. Used in NodeJS and Python. | `true` | +| DD_COLD_START_TRACING | When true (default), tracing occurs during cold start which creates many child spans. When false, only one cold start span is created. Used in NodeJS and Python. | `true` | | DD_MIN_COLD_START_DURATION | Sets the minimum duration (in milliseconds) for a module load event to be traced via Cold Start Tracing. Number. | `3` | | DD_COLD_START_TRACE_SKIP_LIB | optionally skip creating Cold Start Spans for a comma-separated list of libraries. Useful to limit depth or skip known libraries. | `ddtrace.internal.compat,ddtrace.filters` | | DD_CAPTURE_LAMBDA_PAYLOAD | [Captures incoming and outgoing AWS Lambda payloads][1] in the Datadog APM spans for Lambda invocations. | `false` | | DD_CAPTURE_LAMBDA_PAYLOAD_MAX_DEPTH | Determines the level of detail captured from AWS Lambda payloads, which are then assigned as tags for the `aws.lambda` span. It specifies the nesting depth of the JSON payload structure to process. Once the specified maximum depth is reached, the tag's value is set to the stringified value of any nested elements beyond this level.
For example, given the input payload:
{
"lv1" : {
"lv2": {
"lv3": "val"
}
}
}
If the depth is set to `2`, the resulting tag's key is set to `function.request.lv1.lv2` and the value is `{\"lv3\": \"val\"}`.
If the depth is set to `0`, the resulting tag's key is set to `function.request` and value is `{\"lv1\":{\"lv2\":{\"lv3\": \"val\"}}}` | `10` | +| DD_EXCEPTION_REPLAY_ENABLED | When set to `true`, the Lambda will run with Error Tracking Exception Replay enabled, capturing local variables. | `false` | ## Opening Issues @@ -47,6 +48,12 @@ The Continuous Profiler works by spawning a thread which periodically wakes up a ## Major Version Notes +### 6.x / Layer version 95+ +- The release changed how Lambda's traceID is hashed if the incoming payload contains Step Functions context object. This change only affects those who uses inject Step Functions context object into Lambda payload. + +### 5.x / Layer version 86+ +- Python3.7 support has been [deprecated](https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html) by AWS, and support removed from this library. + ### 4.x / Layer version 61+ - Python3.6 support has been [deprecated](https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html) by AWS, and support removed from this library. diff --git a/ci/config.yaml b/ci/config.yaml new file mode 100644 index 000000000..d37a0f316 --- /dev/null +++ b/ci/config.yaml @@ -0,0 +1,13 @@ +inputFiles: + - ci/input_files/build.yaml.tpl + +outputFiles: + - ci/build-pipeline.yaml + +datasources: + runtimes: + url: ci/datasources/runtimes.yaml + regions: + url: ci/datasources/regions.yaml + environments: + url: ci/datasources/environments.yaml diff --git a/ci/datasources/environments.yaml b/ci/datasources/environments.yaml new file mode 100644 index 000000000..1ae2b4d71 --- /dev/null +++ b/ci/datasources/environments.yaml @@ -0,0 +1,9 @@ +environments: + sandbox: + external_id: sandbox-publish-externalid + role_to_assume: sandbox-layer-deployer + account: 425362996713 + prod: + external_id: prod-publish-externalid + role_to_assume: dd-serverless-layer-deployer-role + account: 464622532012 diff --git a/ci/datasources/regions.yaml b/ci/datasources/regions.yaml new file mode 100644 index 000000000..d41bade3a --- /dev/null +++ b/ci/datasources/regions.yaml @@ -0,0 +1,33 @@ +regions: + - code: "us-east-1" + - code: "us-east-2" + - code: "us-west-1" + - code: "us-west-2" + - code: "af-south-1" + - code: "ap-east-1" + - code: "ap-south-1" + - code: "ap-south-2" + - code: "ap-southeast-1" + - code: "ap-southeast-2" + - code: "ap-southeast-3" + - code: "ap-southeast-4" + - code: "ap-southeast-5" + - code: "ap-southeast-7" + - code: "ap-northeast-1" + - code: "ap-northeast-2" + - code: "ap-northeast-3" + - code: "ca-central-1" + - code: "ca-west-1" + - code: "eu-central-1" + - code: "eu-central-2" + - code: "eu-north-1" + - code: "eu-west-1" + - code: "eu-west-2" + - code: "eu-west-3" + - code: "eu-south-1" + - code: "eu-south-2" + - code: "il-central-1" + - code: "me-south-1" + - code: "me-central-1" + - code: "mx-central-1" + - code: "sa-east-1" diff --git a/ci/datasources/runtimes.yaml b/ci/datasources/runtimes.yaml new file mode 100644 index 000000000..f9456d396 --- /dev/null +++ b/ci/datasources/runtimes.yaml @@ -0,0 +1,49 @@ +runtimes: + - name: "python38" + python_version: "3.8" + arch: "amd64" + image: "3.8" + - name: "python38" + python_version: "3.8" + arch: "arm64" + image: "3.8" + - name: "python39" + python_version: "3.9" + arch: "amd64" + image: "3.9" + - name: "python39" + python_version: "3.9" + arch: "arm64" + image: "3.9" + - name: "python310" + python_version: "3.10" + arch: "amd64" + image: "3.10" + - name: "python310" + python_version: "3.10" + arch: "arm64" + image: "3.10" + - name: "python311" + python_version: "3.11" + arch: "amd64" + image: "3.11.6" + - name: "python311" + python_version: "3.11" + arch: "arm64" + image: "3.11.6" + - name: "python312" + python_version: "3.12" + arch: "amd64" + image: "3.12.0" + - name: "python312" + python_version: "3.12" + arch: "arm64" + image: "3.12.0" + - name: "python313" + python_version: "3.13" + arch: "amd64" + image: "3.13.0" + - name: "python313" + python_version: "3.13" + arch: "arm64" + image: "3.13.0" diff --git a/ci/get_secrets.sh b/ci/get_secrets.sh new file mode 100755 index 000000000..9d9c957c0 --- /dev/null +++ b/ci/get_secrets.sh @@ -0,0 +1,48 @@ +#!/bin/bash + +# Unless explicitly stated otherwise all files in this repository are licensed +# under the Apache License Version 2.0. +# This product includes software developed at Datadog (https://www.datadoghq.com/). +# Copyright 2023 Datadog, Inc. + +set -e + +if [ -z "$EXTERNAL_ID_NAME" ]; then + printf "[Error] No EXTERNAL_ID_NAME found.\n" + printf "Exiting script...\n" + exit 1 +fi + +if [ -z "$ROLE_TO_ASSUME" ]; then + printf "[Error] No ROLE_TO_ASSUME found.\n" + printf "Exiting script...\n" + exit 1 +fi + +printf "Getting AWS External ID...\n" + +EXTERNAL_ID=$(aws ssm get-parameter \ + --region us-east-1 \ + --name "ci.datadog-lambda-python.$EXTERNAL_ID_NAME" \ + --with-decryption \ + --query "Parameter.Value" \ + --out text) + +printf "Getting DD API KEY...\n" + +export DD_API_KEY=$(aws ssm get-parameter \ + --region us-east-1 \ + --name ci.datadog-lambda-python.dd-api-key \ + --with-decryption \ + --query "Parameter.Value" \ + --out text) + +printf "Assuming role...\n" + +export $(printf "AWS_ACCESS_KEY_ID=%s AWS_SECRET_ACCESS_KEY=%s AWS_SESSION_TOKEN=%s" \ + $(aws sts assume-role \ + --role-arn "arn:aws:iam::$AWS_ACCOUNT:role/$ROLE_TO_ASSUME" \ + --role-session-name "ci.datadog-lambda-python-$CI_JOB_ID-$CI_JOB_STAGE" \ + --query "Credentials.[AccessKeyId,SecretAccessKey,SessionToken]" \ + --external-id $EXTERNAL_ID \ + --output text)) diff --git a/ci/input_files/build.yaml.tpl b/ci/input_files/build.yaml.tpl new file mode 100644 index 000000000..599160fbf --- /dev/null +++ b/ci/input_files/build.yaml.tpl @@ -0,0 +1,296 @@ +{{- $e2e_region := "us-west-2" -}} + +stages: + - build + - test + - sign + - publish + - e2e + +.python-before-script: &python-before-script + - pip install virtualenv + - virtualenv venv + - source venv/bin/activate + - pip install .[dev] + - pip install poetry + +default: + retry: + max: 1 + when: + # Retry when the runner fails to start + - runner_system_failure + +# This is for serverless framework +.install-node: &install-node + - apt-get update + - apt-get install -y ca-certificates curl gnupg xxd + - mkdir -p /etc/apt/keyrings + - curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg + # We are explicitly setting the node_20.x version for the installation + - echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_20.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list + - apt-get update + - apt-get install nodejs -y + - npm install --global yarn + +{{ range $runtime := (ds "runtimes").runtimes }} + +# TODO(astuyve) - figure out python build cache +.{{ $runtime.name }}-{{ $runtime.arch }}-cache: &{{ $runtime.name }}-{{ $runtime.arch }}-cache + key: "$CI_JOB_STAGE-$CI_COMMIT_REF_SLUG" + paths: + - $CI_PROJECT_DIR/.yarn-cache + policy: pull + +build-layer ({{ $runtime.name }}-{{ $runtime.arch }}): + stage: build + tags: ["arch:amd64"] + image: registry.ddbuild.io/images/docker:20.10 + artifacts: + expire_in: 1 hr # Unsigned zips expire in 1 hour + paths: + - .layers/datadog_lambda_py-{{ $runtime.arch }}-{{ $runtime.python_version }}.zip + variables: + CI_ENABLE_CONTAINER_IMAGE_BUILDS: "true" + script: + - PYTHON_VERSION={{ $runtime.python_version }} ARCH={{ $runtime.arch }} ./scripts/build_layers.sh + +check-layer-size ({{ $runtime.name }}-{{ $runtime.arch }}): + stage: test + tags: ["arch:amd64"] + image: registry.ddbuild.io/images/docker:20.10 + needs: + - build-layer ({{ $runtime.name }}-{{ $runtime.arch }}) + dependencies: + - build-layer ({{ $runtime.name }}-{{ $runtime.arch }}) + script: + - PYTHON_VERSION={{ $runtime.python_version }} ARCH={{ $runtime.arch }} ./scripts/check_layer_size.sh + +lint python: + stage: test + tags: ["arch:amd64"] + image: registry.ddbuild.io/images/mirror/python:{{ $runtime.image }} + cache: &{{ $runtime.name }}-{{ $runtime.arch }}-cache + before_script: *python-before-script + script: + - source venv/bin/activate + - ./scripts/check_format.sh + +unit-test ({{ $runtime.name }}-{{ $runtime.arch }}): + stage: test + tags: ["arch:amd64"] + image: registry.ddbuild.io/images/mirror/python:{{ $runtime.image }} + cache: &{{ $runtime.name }}-{{ $runtime.arch }}-cache + before_script: *python-before-script + script: + - source venv/bin/activate + - pytest -vv + +integration-test ({{ $runtime.name }}-{{ $runtime.arch }}): + stage: test + tags: ["arch:amd64"] + image: registry.ddbuild.io/images/docker:20.10-py3 + needs: + - build-layer ({{ $runtime.name }}-{{ $runtime.arch }}) + dependencies: + - build-layer ({{ $runtime.name }}-{{ $runtime.arch }}) + cache: &{{ $runtime.name }}-{{ $runtime.arch }}-cache + variables: + CI_ENABLE_CONTAINER_IMAGE_BUILDS: "true" + before_script: + - *install-node + - EXTERNAL_ID_NAME=integration-test-externalid ROLE_TO_ASSUME=sandbox-integration-test-deployer AWS_ACCOUNT=425362996713 source ./ci/get_secrets.sh + - yarn global add serverless@^3.38.0 --prefix /usr/local + - yarn global add serverless-python-requirements@^6.1.1 --prefix /usr/local + - cd integration_tests && yarn install && cd .. + script: + - RUNTIME_PARAM={{ $runtime.python_version }} ARCH={{ $runtime.arch }} ./scripts/run_integration_tests.sh + +sign-layer ({{ $runtime.name }}-{{ $runtime.arch }}): + stage: sign + tags: ["arch:amd64"] + image: registry.ddbuild.io/images/docker:20.10-py3 + rules: + - if: '$CI_COMMIT_TAG =~ /^v.*/' + when: manual + needs: + - build-layer ({{ $runtime.name }}-{{ $runtime.arch }}) + - check-layer-size ({{ $runtime.name }}-{{ $runtime.arch }}) + - lint python + - unit-test ({{ $runtime.name }}-{{ $runtime.arch }}) + - integration-test ({{ $runtime.name }}-{{ $runtime.arch }}) + dependencies: + - build-layer ({{ $runtime.name }}-{{ $runtime.arch }}) + artifacts: # Re specify artifacts so the modified signed file is passed + expire_in: 1 day # Signed layers should expire after 1 day + paths: + - .layers/datadog_lambda_py-{{ $runtime.arch }}-{{ $runtime.python_version }}.zip + before_script: + - apt-get update + - apt-get install -y uuid-runtime + {{ with $environment := (ds "environments").environments.prod }} + - EXTERNAL_ID_NAME={{ $environment.external_id }} ROLE_TO_ASSUME={{ $environment.role_to_assume }} AWS_ACCOUNT={{ $environment.account }} source ./ci/get_secrets.sh + {{ end }} + script: + - LAYER_FILE=datadog_lambda_py-{{ $runtime.arch}}-{{ $runtime.python_version }}.zip ./scripts/sign_layers.sh prod + +{{ range $environment_name, $environment := (ds "environments").environments }} +{{ $dotenv := print $runtime.name "_" $runtime.arch "_" $environment_name ".env" }} + +publish-layer-{{ $environment_name }} ({{ $runtime.name }}-{{ $runtime.arch }}): + stage: publish + tags: ["arch:amd64"] + image: registry.ddbuild.io/images/docker:20.10-py3 + rules: + - if: '"{{ $environment_name }}" == "sandbox" && $REGION == "{{ $e2e_region }}" && "{{ $runtime.arch }}" == "amd64"' + when: on_success + - if: '"{{ $environment_name }}" == "sandbox"' + when: manual + allow_failure: true + - if: '$CI_COMMIT_TAG =~ /^v.*/' + artifacts: + reports: + dotenv: {{ $dotenv }} + needs: +{{ if or (eq $environment_name "prod") }} + - sign-layer ({{ $runtime.name }}-{{ $runtime.arch}}) +{{ else }} + - build-layer ({{ $runtime.name }}-{{ $runtime.arch }}) + - check-layer-size ({{ $runtime.name }}-{{ $runtime.arch }}) + - lint python + - unit-test ({{ $runtime.name }}-{{ $runtime.arch }}) + - integration-test ({{ $runtime.name }}-{{ $runtime.arch }}) +{{ end }} + dependencies: +{{ if or (eq $environment_name "prod") }} + - sign-layer ({{ $runtime.name }}-{{ $runtime.arch}}) +{{ else }} + - build-layer ({{ $runtime.name }}-{{ $runtime.arch }}) +{{ end }} + parallel: + matrix: + - REGION: {{ range (ds "regions").regions }} + - {{ .code }} + {{- end}} + before_script: + - EXTERNAL_ID_NAME={{ $environment.external_id }} ROLE_TO_ASSUME={{ $environment.role_to_assume }} AWS_ACCOUNT={{ $environment.account }} source ./ci/get_secrets.sh + script: + - STAGE={{ $environment_name }} PYTHON_VERSION={{ $runtime.python_version }} ARCH={{ $runtime.arch }} DOTENV={{ $dotenv }} ./ci/publish_layers.sh + +{{- end }} + +{{- end }} + +publish-pypi-package: + stage: publish + tags: ["arch:amd64"] + image: registry.ddbuild.io/images/docker:20.10-py3 + before_script: *python-before-script + cache: [] + rules: + - if: '$CI_COMMIT_TAG =~ /^v.*/' + when: manual + needs: {{ range $runtime := (ds "runtimes").runtimes }} + - sign-layer ({{ $runtime.name }}-{{ $runtime.arch}}) + {{- end }} + script: + - ./ci/publish_pypi.sh + +layer bundle: + stage: build + tags: ["arch:amd64"] + image: registry.ddbuild.io/images/docker:20.10 + needs: + {{ range (ds "runtimes").runtimes }} + - build-layer ({{ .name }}-{{ .arch }}) + {{ end }} + dependencies: + {{ range (ds "runtimes").runtimes }} + - build-layer ({{ .name }}-{{ .arch }}) + {{ end }} + artifacts: + expire_in: 1 hr + paths: + - datadog_lambda_py-bundle-${CI_JOB_ID}/ + name: datadog_lambda_py-bundle-${CI_JOB_ID} + script: + - rm -rf datadog_lambda_py-bundle-${CI_JOB_ID} + - mkdir -p datadog_lambda_py-bundle-${CI_JOB_ID} + - cp .layers/datadog_lambda_py-*.zip datadog_lambda_py-bundle-${CI_JOB_ID} + +signed layer bundle: + stage: sign + image: registry.ddbuild.io/images/docker:20.10-py3 + tags: ["arch:amd64"] + rules: + - if: '$CI_COMMIT_TAG =~ /^v.*/' + needs: + {{ range (ds "runtimes").runtimes }} + - sign-layer ({{ .name }}-{{ .arch }}) + {{ end }} + dependencies: + {{ range (ds "runtimes").runtimes }} + - sign-layer ({{ .name }}-{{ .arch }}) + {{ end }} + artifacts: + expire_in: 1 day + paths: + - datadog_lambda_py-signed-bundle-${CI_JOB_ID}/ + name: datadog_lambda_py-signed-bundle-${CI_JOB_ID} + script: + - rm -rf datadog_lambda_py-signed-bundle-${CI_JOB_ID} + - mkdir -p datadog_lambda_py-signed-bundle-${CI_JOB_ID} + - cp .layers/datadog_lambda_py-*.zip datadog_lambda_py-signed-bundle-${CI_JOB_ID} + +e2e-test: + stage: e2e + trigger: + project: DataDog/serverless-e2e-tests + strategy: depend + variables: + LANGUAGES_SUBSET: python + # These env vars are inherited from the dotenv reports of the publish-layer jobs + {{- range (ds "runtimes").runtimes }} + {{- if eq .arch "amd64" }} + {{- $version := print (.name | strings.Trim "python") }} + PYTHON_{{ $version }}_VERSION: $PYTHON_{{ $version }}_VERSION + {{- end }} + {{- end }} + needs: {{ range (ds "runtimes").runtimes }} + {{- if eq .arch "amd64" }} + - "publish-layer-sandbox ({{ .name }}-{{ .arch }}): [{{ $e2e_region }}]" + {{- end }} + {{- end }} + +e2e-test-status: + stage: e2e + image: registry.ddbuild.io/images/docker:20.10-py3 + tags: ["arch:amd64"] + timeout: 3h + script: | + GITLAB_API_TOKEN=$(aws ssm get-parameter --region us-east-1 --name "ci.${CI_PROJECT_NAME}.serverless-e2e-gitlab-token" --with-decryption --query "Parameter.Value" --out text) + URL="${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/pipelines/${CI_PIPELINE_ID}/bridges" + echo "Fetching E2E job status from: $URL" + while true; do + RESPONSE=$(curl -s --header "PRIVATE-TOKEN: ${GITLAB_API_TOKEN}" "$URL") + E2E_JOB_STATUS=$(echo "$RESPONSE" | jq -r '.[] | select(.name=="e2e-test") | .downstream_pipeline.status') + echo -n "E2E job status: $E2E_JOB_STATUS, " + if [ "$E2E_JOB_STATUS" == "success" ]; then + echo "✅ E2E tests completed successfully" + exit 0 + elif [ "$E2E_JOB_STATUS" == "failed" ]; then + echo "❌ E2E tests failed" + exit 1 + elif [ "$E2E_JOB_STATUS" == "running" ]; then + echo "⏳ E2E tests are still running, retrying in 1 minute..." + elif [ "$E2E_JOB_STATUS" == "canceled" ]; then + echo "🚫 E2E tests were canceled" + exit 1 + elif [ "$E2E_JOB_STATUS" == "skipped" ]; then + echo "⏭️ E2E tests were skipped" + exit 0 + else + echo "❓ Unknown E2E test status: $E2E_JOB_STATUS, retrying in 1 minute..." + fi + sleep 60 + done diff --git a/ci/publish_layers.sh b/ci/publish_layers.sh new file mode 100755 index 000000000..9654582a2 --- /dev/null +++ b/ci/publish_layers.sh @@ -0,0 +1,220 @@ +#!/bin/bash + +# Unless explicitly stated otherwise all files in this repository are licensed +# under the Apache License Version 2.0. +# This product includes software developed at Datadog (https://www.datadoghq.com/). +# Copyright 2023 Datadog, Inc. + +# PYTHON_VERSION=20.9 REGION=us-east-1 + +set -e + +# Available runtimes: https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html +AWS_CLI_PYTHON_VERSIONS=( + "python3.8" + "python3.8" + "python3.9" + "python3.9" + "python3.10" + "python3.10" + "python3.11" + "python3.11" + "python3.12" + "python3.12" + "python3.13" + "python3.13" +) +PYTHON_VERSIONS=( + "3.8-amd64" + "3.8-arm64" + "3.9-amd64" + "3.9-arm64" + "3.10-amd64" + "3.10-arm64" + "3.11-amd64" + "3.11-arm64" + "3.12-amd64" + "3.12-arm64" + "3.13-amd64" + "3.13-arm64" +) +LAYER_PATHS=( + ".layers/datadog_lambda_py-amd64-3.8.zip" + ".layers/datadog_lambda_py-arm64-3.8.zip" + ".layers/datadog_lambda_py-amd64-3.9.zip" + ".layers/datadog_lambda_py-arm64-3.9.zip" + ".layers/datadog_lambda_py-amd64-3.10.zip" + ".layers/datadog_lambda_py-arm64-3.10.zip" + ".layers/datadog_lambda_py-amd64-3.11.zip" + ".layers/datadog_lambda_py-arm64-3.11.zip" + ".layers/datadog_lambda_py-amd64-3.12.zip" + ".layers/datadog_lambda_py-arm64-3.12.zip" + ".layers/datadog_lambda_py-amd64-3.13.zip" + ".layers/datadog_lambda_py-arm64-3.13.zip" +) +LAYERS=( + "Datadog-Python38" + "Datadog-Python38-ARM" + "Datadog-Python39" + "Datadog-Python39-ARM" + "Datadog-Python310" + "Datadog-Python310-ARM" + "Datadog-Python311" + "Datadog-Python311-ARM" + "Datadog-Python312" + "Datadog-Python312-ARM" + "Datadog-Python313" + "Datadog-Python313-ARM" +) +STAGES=('prod', 'sandbox', 'staging', 'gov-staging', 'gov-prod') + +printf "Starting script...\n\n" + +if [ -z "$SKIP_PIP_INSTALL" ]; then + echo "Installing dependencies" + pip install awscli +else + echo "Skipping pip install" +fi + +publish_layer() { + region=$1 + layer_name=$2 + compatible_runtimes=$3 + layer_path=$4 + + version_nbr=$(aws lambda publish-layer-version --layer-name $layer_name \ + --description "Datadog Lambda Layer for Python" \ + --zip-file "fileb://$layer_path" \ + --region $region \ + --compatible-runtimes $compatible_runtimes \ + | jq -r '.Version') + + permission=$(aws lambda add-layer-version-permission --layer-name $layer_name \ + --version-number $version_nbr \ + --statement-id "release-$version_nbr" \ + --action lambda:GetLayerVersion --principal "*" \ + --region $region) + + echo $version_nbr +} + +# Target Python version +if [ -z $PYTHON_VERSION ]; then + printf "[Error] PYTHON_VERSION version not specified.\n" + exit 1 +fi + +printf "Python version specified: $PYTHON_VERSION\n" +if [[ ! ${PYTHON_VERSIONS[@]} =~ $PYTHON_VERSION ]]; then + printf "[Error] Unsupported PYTHON_VERSION found: $PYTHON_VERSION.\n" + exit 1 +fi + +if [ -z $ARCH ]; then + printf "[Error] ARCH architecture not specified.\n" + exit 1 +fi + +index=0 +for i in "${!PYTHON_VERSIONS[@]}"; do + if [[ "${PYTHON_VERSIONS[$i]}" = "${PYTHON_VERSION}-${ARCH}" ]]; then + index=$i + fi +done + +REGIONS=$(aws ec2 describe-regions | jq -r '.[] | .[] | .RegionName') + +# Target region +if [ -z "$REGION" ]; then + printf "REGION not specified.\n" + exit 1 +fi + +printf "Region specified, region is: $REGION\n" +if [[ ! "$REGIONS" == *"$REGION"* ]]; then + printf "[Error] Could not find $REGION in AWS available regions: \n${REGIONS[@]}\n" + exit 1 +fi + +# Deploy stage +if [ -z "$STAGE" ]; then + printf "[Error] STAGE not specified.\n" + printf "Exiting script...\n" + exit 1 +fi + +printf "Stage specified: $STAGE\n" +if [[ ! ${STAGES[@]} =~ $STAGE ]]; then + printf "[Error] Unsupported STAGE found.\n" + exit 1 +fi + +layer="${LAYERS[$index]}" +if [ -z "$LAYER_NAME_SUFFIX" ]; then + echo "No layer name suffix" +else + layer="${layer}-${LAYER_NAME_SUFFIX}" +fi +echo "layer name: $layer" + +if [[ "$STAGE" =~ ^(staging|sandbox|gov-staging)$ ]]; then + # Deploy latest version + latest_version=$(aws lambda list-layer-versions --region $REGION --layer-name $layer --query 'LayerVersions[0].Version || `0`') + VERSION=$(($latest_version + 1)) +else + # Running on prod + if [ -z "$CI_COMMIT_TAG" ]; then + printf "[Error] No CI_COMMIT_TAG found.\n" + printf "Exiting script...\n" + exit 1 + else + printf "Tag found in environment: $CI_COMMIT_TAG\n" + fi + + VERSION=$(echo "${CI_COMMIT_TAG##*v}" | cut -d. -f2) +fi + +# Target layer version +if [ -z "$VERSION" ]; then + printf "[Error] VERSION for layer version not specified.\n" + printf "Exiting script...\n" + exit 1 +else + printf "Layer version parsed: $VERSION\n" +fi + +printf "[$REGION] Starting publishing layers...\n" +aws_cli_python_version_key="${AWS_CLI_PYTHON_VERSIONS[$index]}" +layer_path="${LAYER_PATHS[$index]}" + +latest_version=$(aws lambda list-layer-versions --region $REGION --layer-name $layer --query 'LayerVersions[0].Version || `0`') +if [ $latest_version -ge $VERSION ]; then + printf "[$REGION] Layer $layer version $VERSION already exists in region $REGION, skipping...\n" + exit 0 +elif [ $latest_version -lt $((VERSION-1)) ]; then + printf "[$REGION][WARNING] The latest version of layer $layer in region $REGION is $latest_version, this will publish all the missing versions including $VERSION\n" +fi + +while [ $latest_version -lt $VERSION ]; do + latest_version=$(publish_layer $REGION $layer $aws_cli_python_version_key $layer_path) + printf "[$REGION] Published version $latest_version for layer $layer in region $REGION\n" + latest_arn=$(aws lambda get-layer-version --layer-name $layer --version-number $latest_version --region $REGION --query 'LayerVersionArn' --output text) + printf "[$REGION] Published arn $latest_arn\n" + + # This shouldn't happen unless someone manually deleted the latest version, say 28, and + # then tries to republish 28 again. The published version would actually be 29, because + # Lambda layers are immutable and AWS will skip deleted version and use the next number. + if [ $latest_version -gt $VERSION ]; then + printf "[$REGION] Published version $latest_version is greater than the desired version $VERSION!" + exit 1 + fi +done + +if [ -n "$DOTENV" ]; then + printf "[$REGION] Exporting layer version to $DOTENV file...\n" + echo "PYTHON_${PYTHON_VERSION/./}_VERSION=$latest_arn" >> "$DOTENV" + cat "$DOTENV" +fi + +printf "[$REGION] Finished publishing layers...\n\n" diff --git a/ci/publish_pypi.sh b/ci/publish_pypi.sh new file mode 100755 index 000000000..c01df7ef7 --- /dev/null +++ b/ci/publish_pypi.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +# Unless explicitly stated otherwise all files in this repository are licensed +# under the Apache License Version 2.0. +# This product includes software developed at Datadog (https://www.datadoghq.com/). +# Copyright 2023 Datadog, Inc. +set -e +PYPI_TOKEN=$(aws ssm get-parameter \ + --region us-east-1 \ + --name "ci.datadog-lambda-python.pypi-token" \ + --with-decryption \ + --query "Parameter.Value" \ + --out text) +# Builds the lambda layer and upload to Pypi + +if [ -z "$CI_COMMIT_TAG" ]; then + printf "[Error] No CI_COMMIT_TAG found.\n" + printf "Exiting script...\n" + exit 1 +else + printf "Tag found in environment: $CI_COMMIT_TAG\n" +fi + +# Clear previously built distributions +if [ -d "dist" ]; then + echo "Removing folder 'dist' to clear previously built distributions" + rm -rf dist; +fi + +# Publish to pypi +poetry publish --build --username __token__ --password $PYPI_TOKEN diff --git a/datadog_lambda/__init__.py b/datadog_lambda/__init__.py index 20b424432..2034d3cbf 100644 --- a/datadog_lambda/__init__.py +++ b/datadog_lambda/__init__.py @@ -1,17 +1,27 @@ -import os -import logging from datadog_lambda.cold_start import initialize_cold_start_tracing +import os + + +if os.environ.get("DD_INSTRUMENTATION_TELEMETRY_ENABLED") is None: + # Telemetry is required for Appsec Software Composition Analysis + os.environ["DD_INSTRUMENTATION_TELEMETRY_ENABLED"] = os.environ.get( + "DD_APPSEC_ENABLED", "false" + ) + initialize_cold_start_tracing() # The minor version corresponds to the Lambda layer version. # E.g.,, version 0.5.0 gets packaged into layer version 5. -try: - import importlib.metadata as importlib_metadata -except ModuleNotFoundError: - import importlib_metadata +from datadog_lambda.version import __version__ # noqa: E402 F401 +from datadog_lambda.logger import initialize_logging # noqa: E402 + + +initialize_logging(__name__) + -__version__ = importlib_metadata.version(__name__) +from datadog_lambda.patch import patch_all # noqa: E402 -logger = logging.getLogger(__name__) -logger.setLevel(logging.getLevelName(os.environ.get("DD_LOG_LEVEL", "INFO").upper())) +# Patch third-party libraries for tracing, must be done before importing any +# handler code. +patch_all() diff --git a/datadog_lambda/api.py b/datadog_lambda/api.py index 079f69dab..4921dae90 100644 --- a/datadog_lambda/api.py +++ b/datadog_lambda/api.py @@ -1,13 +1,16 @@ -import os import logging -import base64 -from datadog_lambda.extension import should_use_extension +import os + +from datadog_lambda.config import config logger = logging.getLogger(__name__) KMS_ENCRYPTION_CONTEXT_KEY = "LambdaFunctionName" +api_key = None def decrypt_kms_api_key(kms_client, ciphertext): + import base64 + from botocore.exceptions import ClientError """ @@ -26,7 +29,6 @@ def decrypt_kms_api_key(kms_client, ciphertext): is added. We need to try decrypting the API key both with and without the encryption context. """ # Try without encryption context, in case API key was encrypted using the AWS CLI - function_name = os.environ.get("AWS_LAMBDA_FUNCTION_NAME") try: plaintext = kms_client.decrypt(CiphertextBlob=decoded_bytes)[ "Plaintext" @@ -40,46 +42,89 @@ def decrypt_kms_api_key(kms_client, ciphertext): plaintext = kms_client.decrypt( CiphertextBlob=decoded_bytes, EncryptionContext={ - KMS_ENCRYPTION_CONTEXT_KEY: function_name, + KMS_ENCRYPTION_CONTEXT_KEY: config.function_name, }, )["Plaintext"].decode("utf-8") return plaintext +def get_api_key() -> str: + """ + Gets the Datadog API key from the environment variables or secrets manager. + Extracts the result to a global value to avoid repeated calls to the + secrets manager from different products. + """ + global api_key + if api_key: + return api_key + + DD_API_KEY_SECRET_ARN = os.environ.get("DD_API_KEY_SECRET_ARN", "") + DD_API_KEY_SSM_NAME = os.environ.get("DD_API_KEY_SSM_NAME", "") + DD_KMS_API_KEY = os.environ.get("DD_KMS_API_KEY", "") + DD_API_KEY = os.environ.get("DD_API_KEY", os.environ.get("DATADOG_API_KEY", "")) + + LAMBDA_REGION = os.environ.get("AWS_REGION", "") + if config.fips_mode_enabled: + logger.debug( + "FIPS mode is enabled, using FIPS endpoints for secrets management." + ) + + if DD_API_KEY_SECRET_ARN: + # Secrets manager endpoints: https://docs.aws.amazon.com/general/latest/gr/asm.html + try: + secrets_region = DD_API_KEY_SECRET_ARN.split(":")[3] + except Exception: + logger.debug( + "Invalid secret arn in DD_API_KEY_SECRET_ARN. Unable to get API key." + ) + return "" + endpoint_url = ( + f"https://secretsmanager-fips.{secrets_region}.amazonaws.com/" + if config.fips_mode_enabled + else None + ) + secrets_manager_client = _boto3_client( + "secretsmanager", endpoint_url=endpoint_url, region_name=secrets_region + ) + api_key = secrets_manager_client.get_secret_value( + SecretId=DD_API_KEY_SECRET_ARN + )["SecretString"] + elif DD_API_KEY_SSM_NAME: + # SSM endpoints: https://docs.aws.amazon.com/general/latest/gr/ssm.html + fips_endpoint = ( + f"https://ssm-fips.{lambda_region}.amazonaws.com/" + if config.fips_mode_enabled + else None + ) + ssm_client = _boto3_client("ssm", endpoint_url=fips_endpoint) + api_key = ssm_client.get_parameter( + Name=DD_API_KEY_SSM_NAME, WithDecryption=True + )["Parameter"]["Value"] + elif DD_KMS_API_KEY: + # KMS endpoints: https://docs.aws.amazon.com/general/latest/gr/kms.html + fips_endpoint = ( + f"https://kms-fips.{lambda_region}.amazonaws.com/" + if config.fips_mode_enabled + else None + ) + kms_client = _boto3_client("kms", endpoint_url=fips_endpoint) + api_key = decrypt_kms_api_key(kms_client, DD_KMS_API_KEY) + else: + api_key = DD_API_KEY + + return api_key + + def init_api(): - if ( - not should_use_extension - and not os.environ.get("DD_FLUSH_TO_LOG", "").lower() == "true" - ): + if not config.flush_to_log: # Make sure that this package would always be lazy-loaded/outside from the critical path # since underlying packages are quite heavy to load - # and useless when the extension is present + # and useless with the extension unless sending metrics with timestamps from datadog import api if not api._api_key: - import boto3 - - DD_API_KEY_SECRET_ARN = os.environ.get("DD_API_KEY_SECRET_ARN", "") - DD_API_KEY_SSM_NAME = os.environ.get("DD_API_KEY_SSM_NAME", "") - DD_KMS_API_KEY = os.environ.get("DD_KMS_API_KEY", "") - DD_API_KEY = os.environ.get( - "DD_API_KEY", os.environ.get("DATADOG_API_KEY", "") - ) - - if DD_API_KEY_SECRET_ARN: - api._api_key = boto3.client("secretsmanager").get_secret_value( - SecretId=DD_API_KEY_SECRET_ARN - )["SecretString"] - elif DD_API_KEY_SSM_NAME: - api._api_key = boto3.client("ssm").get_parameter( - Name=DD_API_KEY_SSM_NAME, WithDecryption=True - )["Parameter"]["Value"] - elif DD_KMS_API_KEY: - kms_client = boto3.client("kms") - api._api_key = decrypt_kms_api_key(kms_client, DD_KMS_API_KEY) - else: - api._api_key = DD_API_KEY + api._api_key = get_api_key() logger.debug("Setting DATADOG_API_KEY of length %d", len(api._api_key)) @@ -91,3 +136,9 @@ def init_api(): # Unmute exceptions from datadog api client, so we can catch and handle them api._mute = False + + +def _boto3_client(*args, **kwargs): + import botocore.session + + return botocore.session.get_session().create_client(*args, **kwargs) diff --git a/datadog_lambda/asm.py b/datadog_lambda/asm.py new file mode 100644 index 000000000..6c65a9465 --- /dev/null +++ b/datadog_lambda/asm.py @@ -0,0 +1,251 @@ +import logging +import urllib.parse +from copy import deepcopy +from typing import Any, Dict, List, Optional, Union + +from ddtrace.contrib.internal.trace_utils import _get_request_header_client_ip +from ddtrace.internal import core +from ddtrace.internal.utils import get_blocked +from ddtrace.internal.utils import http as http_utils +from ddtrace.trace import Span + +from datadog_lambda.trigger import ( + EventSubtypes, + EventTypes, + _EventSource, + _http_event_types, +) + +logger = logging.getLogger(__name__) + + +def _to_single_value_headers(headers: Dict[str, List[str]]) -> Dict[str, str]: + """ + Convert multi-value headers to single-value headers. + If a header has multiple values, join them with commas. + """ + single_value_headers = {} + for key, values in headers.items(): + single_value_headers[key] = ", ".join(values) + return single_value_headers + + +def _merge_single_and_multi_value_headers( + single_value_headers: Dict[str, str], + multi_value_headers: Dict[str, List[str]], +): + """ + Merge single-value headers with multi-value headers. + If a header exists in both, we merge them removing duplicates + """ + merged_headers = deepcopy(multi_value_headers) + for key, value in single_value_headers.items(): + if key not in merged_headers: + merged_headers[key] = [value] + elif value not in merged_headers[key]: + merged_headers[key].append(value) + return _to_single_value_headers(merged_headers) + + +def asm_set_context(event_source: _EventSource): + """Add asm specific items to the ExecutionContext. + + This allows the AppSecSpanProcessor to know information about the event + at the moment the span is created and skip it when not relevant. + """ + + if event_source.event_type not in _http_event_types: + core.set_item("appsec_skip_next_lambda_event", True) + + +def asm_start_request( + span: Span, + event: Dict[str, Any], + event_source: _EventSource, + trigger_tags: Dict[str, str], +): + if event_source.event_type not in _http_event_types: + return + + request_headers: Dict[str, str] = {} + peer_ip: Optional[str] = None + request_path_parameters: Optional[Dict[str, Any]] = None + route: Optional[str] = None + + if event_source.event_type == EventTypes.ALB: + raw_uri = event.get("path") + + if event_source.subtype == EventSubtypes.ALB: + request_headers = event.get("headers", {}) + parsed_query = event.get("queryStringParameters") + if event_source.subtype == EventSubtypes.ALB_MULTI_VALUE_HEADERS: + request_headers = _to_single_value_headers( + event.get("multiValueHeaders", {}) + ) + parsed_query = event.get("multiValueQueryStringParameters") + + elif event_source.event_type == EventTypes.LAMBDA_FUNCTION_URL: + request_headers = event.get("headers", {}) + peer_ip = event.get("requestContext", {}).get("http", {}).get("sourceIp") + raw_uri = event.get("rawPath") + parsed_query = event.get("queryStringParameters") + + elif event_source.event_type == EventTypes.API_GATEWAY: + request_context = event.get("requestContext", {}) + request_path_parameters = event.get("pathParameters") + route = trigger_tags.get("http.route") + + if event_source.subtype == EventSubtypes.API_GATEWAY: + request_headers = event.get("headers", {}) + peer_ip = request_context.get("identity", {}).get("sourceIp") + raw_uri = event.get("path") + parsed_query = event.get("multiValueQueryStringParameters") + + elif event_source.subtype == EventSubtypes.HTTP_API: + request_headers = event.get("headers", {}) + peer_ip = request_context.get("http", {}).get("sourceIp") + raw_uri = event.get("rawPath") + parsed_query = event.get("queryStringParameters") + + elif event_source.subtype == EventSubtypes.WEBSOCKET: + request_headers = _to_single_value_headers( + event.get("multiValueHeaders", {}) + ) + peer_ip = request_context.get("identity", {}).get("sourceIp") + raw_uri = event.get("path") + parsed_query = event.get("multiValueQueryStringParameters") + + else: + return + + else: + return + + body = event.get("body") + is_base64_encoded = event.get("isBase64Encoded", False) + + request_ip = _get_request_header_client_ip(request_headers, peer_ip, True) + if request_ip is not None: + span.set_tag("http.client_ip", request_ip) + span.set_tag("network.client.ip", request_ip) + + # Encode the parsed query and append it to reconstruct the original raw URI expected by AppSec. + if parsed_query: + try: + encoded_query = urllib.parse.urlencode(parsed_query, doseq=True) + raw_uri += "?" + encoded_query # type: ignore + except Exception: + pass + + core.dispatch( + # The matching listener is registered in ddtrace.appsec._handlers + "aws_lambda.start_request", + ( + span, + request_headers, + request_ip, + body, + is_base64_encoded, + raw_uri, + route, + trigger_tags.get("http.method"), + parsed_query, + request_path_parameters, + ), + ) + + +def asm_start_response( + span: Span, + status_code: str, + event_source: _EventSource, + response: Union[Dict[str, Any], str, None], +): + if event_source.event_type not in _http_event_types: + return + + if isinstance(response, dict) and ( + "headers" in response or "multiValueHeaders" in response + ): + headers = response.get("headers", {}) + multi_value_request_headers = response.get("multiValueHeaders") + if isinstance(multi_value_request_headers, dict) and isinstance(headers, dict): + response_headers = _merge_single_and_multi_value_headers( + headers, multi_value_request_headers + ) + elif isinstance(headers, dict): + response_headers = headers + else: + response_headers = { + "content-type": "application/json", + } + else: + response_headers = { + "content-type": "application/json", + } + + core.dispatch( + # The matching listener is registered in ddtrace.appsec._handlers + "aws_lambda.start_response", + ( + span, + status_code, + response_headers, + ), + ) + + if isinstance(response, dict) and "statusCode" in response: + body = response.get("body") + else: + body = response + + core.dispatch( + # The matching listener is registered in ddtrace.appsec._handlers + "aws_lambda.parse_body", + (body,), + ) + + +def get_asm_blocked_response( + event_source: _EventSource, +) -> Optional[Dict[str, Any]]: + """Get the blocked response for the given event source.""" + if event_source.event_type not in _http_event_types: + return None + + blocked = get_blocked() + if not blocked: + return None + + desired_type = blocked.get("type", "auto") + if desired_type == "none": + content_type = "text/plain; charset=utf-8" + content = "" + else: + content_type = blocked.get("content-type", "application/json") + content = http_utils._get_blocked_template(content_type) + + response = { + "statusCode": blocked.get("status_code", 403), + "body": content, + "isBase64Encoded": False, + } + + needs_multi_value_headers = event_source.equals( + EventTypes.ALB, EventSubtypes.ALB_MULTI_VALUE_HEADERS + ) + + if needs_multi_value_headers: + response["multiValueHeaders"] = { + "content-type": [content_type], + } + if "location" in blocked: + response["multiValueHeaders"]["location"] = [blocked["location"]] + else: + response["headers"] = { + "content-type": content_type, + } + if "location" in blocked: + response["headers"]["location"] = blocked["location"] + + return response diff --git a/datadog_lambda/cold_start.py b/datadog_lambda/cold_start.py index 0a3ba34d1..a40e2fcb3 100644 --- a/datadog_lambda/cold_start.py +++ b/datadog_lambda/cold_start.py @@ -1,13 +1,15 @@ import time -import os from typing import List, Hashable import logging +from datadog_lambda.config import config + logger = logging.getLogger(__name__) _cold_start = True _proactive_initialization = False _lambda_container_initialized = False +_tracer = None def set_cold_start(init_timestamp_ns): @@ -18,6 +20,7 @@ def set_cold_start(init_timestamp_ns): global _cold_start global _lambda_container_initialized global _proactive_initialization + global _tracer if not _lambda_container_initialized: now = time.time_ns() if (now - init_timestamp_ns) // 1_000_000_000 > 10: @@ -29,6 +32,7 @@ def set_cold_start(init_timestamp_ns): _cold_start = False _proactive_initialization = False _lambda_container_initialized = True + from ddtrace.trace import tracer as _tracer def is_cold_start(): @@ -47,12 +51,16 @@ def is_new_sandbox(): def get_cold_start_tag(): """Returns the cold start tag to be used in metrics""" - return "cold_start:{}".format(str(is_cold_start()).lower()) + return "cold_start:true" if _cold_start else "cold_start:false" def get_proactive_init_tag(): """Returns the proactive init tag to be used in metrics""" - return "proactive_initialization:{}".format(str(is_proactive_init()).lower()) + return ( + "proactive_initialization:true" + if _proactive_initialization + else "proactive_initialization:false" + ) class ImportNode(object): @@ -62,6 +70,9 @@ def __init__(self, module_name, full_file_path, start_time_ns, end_time_ns=None) self.start_time_ns = start_time_ns self.end_time_ns = end_time_ns self.children = [] + self.context = None + if _lambda_container_initialized: + self.context = _tracer.context_provider.active() root_nodes: List[ImportNode] = [] @@ -70,22 +81,18 @@ def __init__(self, module_name, full_file_path, start_time_ns, end_time_ns=None) def reset_node_stacks(): - global root_nodes - root_nodes = [] - global import_stack - import_stack = [] + root_nodes.clear() + import_stack.clear() def push_node(module_name, file_path): node = ImportNode(module_name, file_path, time.time_ns()) - global import_stack if import_stack: import_stack[-1].children.append(node) import_stack.append(node) def pop_node(module_name): - global import_stack if not import_stack: return node = import_stack.pop() @@ -94,7 +101,6 @@ def pop_node(module_name): end_time_ns = time.time_ns() node.end_time_ns = end_time_ns if not import_stack: # import_stack empty, a root node has been found - global root_nodes root_nodes.append(node) @@ -139,19 +145,14 @@ def wrapped_find_spec(*args, **kwargs): def initialize_cold_start_tracing(): - if ( - is_new_sandbox() - and os.environ.get("DD_TRACE_ENABLED", "true").lower() == "true" - and os.environ.get("DD_COLD_START_TRACING", "true").lower() == "true" - ): - from sys import version_info, meta_path + if is_new_sandbox() and config.cold_start_tracing: + from sys import meta_path - if version_info >= (3, 7): # current implementation only support version > 3.7 - for importer in meta_path: - try: - importer.find_spec = wrap_find_spec(importer.find_spec) - except Exception: - pass + for importer in meta_path: + try: + importer.find_spec = wrap_find_spec(importer.find_spec) + except Exception: + pass class ColdStartTracer(object): @@ -184,12 +185,14 @@ def trace(self, root_nodes: List[ImportNode] = root_nodes): cold_start_span = self.create_cold_start_span(cold_start_span_start_time_ns) while root_nodes: root_node = root_nodes.pop() - self.trace_tree(root_node, cold_start_span) + parent = root_node.context or cold_start_span + self.trace_tree(root_node, parent) self.finish_span(cold_start_span, cold_start_span_end_time_ns) def trace_tree(self, import_node: ImportNode, parent_span): if ( - import_node.end_time_ns - import_node.start_time_ns + not self.trace_ctx + or import_node.end_time_ns - import_node.start_time_ns < self.min_duration_ms * 1e6 or import_node.module_name in self.ignored_libs ): diff --git a/datadog_lambda/config.py b/datadog_lambda/config.py new file mode 100644 index 000000000..aaa1af5e8 --- /dev/null +++ b/datadog_lambda/config.py @@ -0,0 +1,146 @@ +# Unless explicitly stated otherwise all files in this repository are licensed +# under the Apache License Version 2.0. +# This product includes software developed at Datadog (https://www.datadoghq.com/). +# Copyright 2019 Datadog, Inc. + +import logging +import os + +logger = logging.getLogger(__name__) + + +def _get_env(key, default=None, cast=None, depends_on_tracing=False): + @property + def _getter(self): + if not hasattr(self, prop_key): + val = self._resolve_env(key, default, cast, depends_on_tracing) + setattr(self, prop_key, val) + return getattr(self, prop_key) + + prop_key = f"_config_{key}" + return _getter + + +def as_bool(val): + return val.lower() == "true" or val == "1" + + +def as_list(val): + return [val.strip() for val in val.split(",") if val.strip()] + + +class Config: + def _resolve_env(self, key, default=None, cast=None, depends_on_tracing=False): + if depends_on_tracing and not self.trace_enabled: + return False + val = os.environ.get(key, default) + if cast is not None: + try: + val = cast(val) + except (ValueError, TypeError): + msg = ( + "Failed to cast environment variable '%s' with " + "value '%s' to type %s. Using default value '%s'." + ) + logger.warning(msg, key, val, cast.__name__, default) + val = default + return val + + service = _get_env("DD_SERVICE") + env = _get_env("DD_ENV") + + cold_start_tracing = _get_env( + "DD_COLD_START_TRACING", "true", as_bool, depends_on_tracing=True + ) + min_cold_start_trace_duration = _get_env("DD_MIN_COLD_START_DURATION", 3, int) + cold_start_trace_skip_lib = _get_env( + "DD_COLD_START_TRACE_SKIP_LIB", + "ddtrace.internal.compat,ddtrace.filters", + as_list, + ) + + capture_payload_max_depth = _get_env("DD_CAPTURE_LAMBDA_PAYLOAD_MAX_DEPTH", 10, int) + capture_payload_enabled = _get_env("DD_CAPTURE_LAMBDA_PAYLOAD", "false", as_bool) + + trace_enabled = _get_env("DD_TRACE_ENABLED", "true", as_bool) + make_inferred_span = _get_env( + "DD_TRACE_MANAGED_SERVICES", "true", as_bool, depends_on_tracing=True + ) + encode_authorizer_context = _get_env( + "DD_ENCODE_AUTHORIZER_CONTEXT", "true", as_bool, depends_on_tracing=True + ) + decode_authorizer_context = _get_env( + "DD_DECODE_AUTHORIZER_CONTEXT", "true", as_bool, depends_on_tracing=True + ) + add_span_pointers = _get_env("DD_BOTOCORE_ADD_SPAN_POINTERS", "true", as_bool) + trace_extractor = _get_env("DD_TRACE_EXTRACTOR") + + enhanced_metrics_enabled = _get_env("DD_ENHANCED_METRICS", "true", as_bool) + + flush_in_thread = _get_env("DD_FLUSH_IN_THREAD", "false", as_bool) + flush_to_log = _get_env("DD_FLUSH_TO_LOG", "false", as_bool) + logs_injection = _get_env("DD_LOGS_INJECTION", "true", as_bool) + merge_xray_traces = _get_env("DD_MERGE_XRAY_TRACES", "false", as_bool) + + telemetry_enabled = _get_env( + "DD_INSTRUMENTATION_TELEMETRY_ENABLED", + "false", + as_bool, + depends_on_tracing=True, + ) + otel_enabled = _get_env("DD_TRACE_OTEL_ENABLED", "false", as_bool) + profiling_enabled = _get_env("DD_PROFILING_ENABLED", "false", as_bool) + llmobs_enabled = _get_env("DD_LLMOBS_ENABLED", "false", as_bool) + exception_replay_enabled = _get_env("DD_EXCEPTION_REPLAY_ENABLED", "false", as_bool) + data_streams_enabled = _get_env( + "DD_DATA_STREAMS_ENABLED", "false", as_bool, depends_on_tracing=True + ) + appsec_enabled = _get_env("DD_APPSEC_ENABLED", "false", as_bool) + + is_gov_region = _get_env("AWS_REGION", "", lambda x: x.startswith("us-gov-")) + + local_test = _get_env("DD_LOCAL_TEST", "false", as_bool) + integration_test = _get_env("DD_INTEGRATION_TEST", "false", as_bool) + + aws_lambda_function_name = _get_env("AWS_LAMBDA_FUNCTION_NAME") + + @property + def function_name(self): + if not hasattr(self, "_config_function_name"): + if self.aws_lambda_function_name is None: + self._config_function_name = "function" + else: + self._config_function_name = self.aws_lambda_function_name + return self._config_function_name + + @property + def is_lambda_context(self): + if not hasattr(self, "_config_is_lambda_context"): + self._config_is_lambda_context = bool(self.aws_lambda_function_name) + return self._config_is_lambda_context + + @property + def fips_mode_enabled(self): + if not hasattr(self, "_config_fips_mode_enabled"): + self._config_fips_mode_enabled = ( + os.environ.get( + "DD_LAMBDA_FIPS_MODE", + "true" if self.is_gov_region else "false", + ).lower() + == "true" + ) + return self._config_fips_mode_enabled + + def _reset(self): + for attr in dir(self): + if attr.startswith("_config_"): + delattr(self, attr) + + +config = Config() + +if config.is_gov_region or config.fips_mode_enabled: + logger.debug( + "Python Lambda Layer FIPS mode is %s.", + "enabled" if config.fips_mode_enabled else "not enabled", + ) diff --git a/datadog_lambda/constants.py b/datadog_lambda/constants.py index fd8afb3ed..6ab627384 100644 --- a/datadog_lambda/constants.py +++ b/datadog_lambda/constants.py @@ -3,9 +3,8 @@ # This product includes software developed at Datadog (https://www.datadoghq.com/). # Copyright 2019 Datadog, Inc. -# Datadog trace sampling priority - +# Datadog trace sampling priority class SamplingPriority(object): USER_REJECT = -1 AUTO_REJECT = 0 @@ -18,6 +17,7 @@ class TraceHeader(object): TRACE_ID = "x-datadog-trace-id" PARENT_ID = "x-datadog-parent-id" SAMPLING_PRIORITY = "x-datadog-sampling-priority" + TAGS = "x-datadog-tags" # X-Ray subsegment to save Datadog trace metadata diff --git a/datadog_lambda/dogstatsd.py b/datadog_lambda/dogstatsd.py index a627492dc..a08e25926 100644 --- a/datadog_lambda/dogstatsd.py +++ b/datadog_lambda/dogstatsd.py @@ -1,11 +1,10 @@ +import errno import logging import os -import socket -import errno import re +import socket from threading import Lock - MIN_SEND_BUFFER_SIZE = 32 * 1024 log = logging.getLogger("datadog_lambda.dogstatsd") @@ -55,14 +54,21 @@ def _get_udp_socket(cls, host, port): return sock - def distribution(self, metric, value, tags=None): + def distribution(self, metric, value, tags=None, timestamp=None): """ - Send a global distribution value, optionally setting tags. + Send a global distribution value, optionally setting tags. The optional + timestamp should be an integer representing seconds since the epoch + (January 1, 1970, 00:00:00 UTC). >>> statsd.distribution("uploaded.file.size", 1445) >>> statsd.distribution("album.photo.count", 26, tags=["gender:female"]) + >>> statsd.distribution( + >>> "historic.file.count", + >>> 5, + >>> timestamp=int(datetime(2020, 2, 14, 12, 0, 0).timestamp()), + >>> ) """ - self._report(metric, "d", value, tags) + self._report(metric, "d", value, tags, timestamp) def close_socket(self): """ @@ -84,20 +90,21 @@ def normalize_tags(self, tag_list): for tag in tag_list ] - def _serialize_metric(self, metric, metric_type, value, tags): + def _serialize_metric(self, metric, metric_type, value, tags, timestamp): # Create/format the metric packet - return "%s:%s|%s%s" % ( + return "%s:%s|%s%s%s" % ( metric, value, metric_type, ("|#" + ",".join(self.normalize_tags(tags))) if tags else "", + ("|T" + str(int(timestamp))) if timestamp is not None else "", ) - def _report(self, metric, metric_type, value, tags): + def _report(self, metric, metric_type, value, tags, timestamp): if value is None: return - payload = self._serialize_metric(metric, metric_type, value, tags) + payload = self._serialize_metric(metric, metric_type, value, tags, timestamp) # Send it self._send_to_server(payload) diff --git a/datadog_lambda/extension.py b/datadog_lambda/extension.py index d66848ff0..79c0031aa 100644 --- a/datadog_lambda/extension.py +++ b/datadog_lambda/extension.py @@ -1,36 +1,21 @@ import logging -from os import path - -try: - # only available in python 3 - # not an issue since the extension is not compatible with python 2.x runtime - # https://docs.aws.amazon.com/lambda/latest/dg/using-extensions.html - import urllib.request -except ImportError: - # safe since both calls to urllib are protected with try/expect and will return false - urllib = None +import os AGENT_URL = "http://127.0.0.1:8124/" -HELLO_PATH = "/lambda/hello" FLUSH_PATH = "/lambda/flush" EXTENSION_PATH = "/opt/extensions/datadog-agent" logger = logging.getLogger(__name__) -def is_extension_running(): - if not path.exists(EXTENSION_PATH): - return False - try: - urllib.request.urlopen(AGENT_URL + HELLO_PATH) - except Exception as e: - logger.debug("Extension is not running, returned with error %s", e) - return False - return True +def is_extension_present(): + return os.path.exists(EXTENSION_PATH) def flush_extension(): try: + import urllib.request + req = urllib.request.Request(AGENT_URL + FLUSH_PATH, "".encode("ascii")) urllib.request.urlopen(req) except Exception as e: @@ -39,4 +24,4 @@ def flush_extension(): return True -should_use_extension = is_extension_running() +should_use_extension = is_extension_present() diff --git a/datadog_lambda/handler.py b/datadog_lambda/handler.py index 09cc5e7d7..4f12b1ad8 100644 --- a/datadog_lambda/handler.py +++ b/datadog_lambda/handler.py @@ -3,10 +3,12 @@ # This product includes software developed at Datadog (https://www.datadoghq.com/). # Copyright 2020 Datadog, Inc. -from __future__ import absolute_import from importlib import import_module import os +from time import time_ns + +from datadog_lambda.tracing import emit_telemetry_on_exception_outside_of_handler from datadog_lambda.wrapper import datadog_lambda_wrapper from datadog_lambda.module_name import modify_module_name @@ -22,10 +24,22 @@ class HandlerError(Exception): ) parts = path.rsplit(".", 1) if len(parts) != 2: - raise HandlerError("Value %s for DD_LAMBDA_HANDLER has invalid format." % path) + raise HandlerError(f"Value {path} for DD_LAMBDA_HANDLER has invalid format.") (mod_name, handler_name) = parts modified_mod_name = modify_module_name(mod_name) -handler_module = import_module(modified_mod_name) -handler = datadog_lambda_wrapper(getattr(handler_module, handler_name)) + +try: + handler_load_start_time_ns = time_ns() + handler_module = import_module(modified_mod_name) + handler_func = getattr(handler_module, handler_name) +except Exception as e: + emit_telemetry_on_exception_outside_of_handler( + e, + modified_mod_name, + handler_load_start_time_ns, + ) + raise + +handler = datadog_lambda_wrapper(handler_func) diff --git a/datadog_lambda/logger.py b/datadog_lambda/logger.py new file mode 100644 index 000000000..ae2b5d6d9 --- /dev/null +++ b/datadog_lambda/logger.py @@ -0,0 +1,27 @@ +import logging +import os + +try: + _level_mappping = logging.getLevelNamesMapping() +except AttributeError: + # python 3.8 + _level_mappping = {name: num for num, name in logging._levelToName.items()} +# https://docs.datadoghq.com/agent/troubleshooting/debug_mode/?tab=agentv6v7#agent-log-level +_level_mappping.update( + { + "TRACE": 5, + "WARN": logging.WARNING, + "OFF": 100, + } +) + + +def initialize_logging(name): + logger = logging.getLogger(name) + str_level = (os.environ.get("DD_LOG_LEVEL") or "INFO").upper() + level = _level_mappping.get(str_level) + if level is None: + logger.setLevel(logging.INFO) + logger.warning("Invalid log level: %s Defaulting to INFO", str_level) + else: + logger.setLevel(level) diff --git a/datadog_lambda/metric.py b/datadog_lambda/metric.py index ca23ed963..5df0812f1 100644 --- a/datadog_lambda/metric.py +++ b/datadog_lambda/metric.py @@ -3,34 +3,62 @@ # This product includes software developed at Datadog (https://www.datadoghq.com/). # Copyright 2019 Datadog, Inc. -import os -import json -import time +import enum import logging +import time +from datetime import datetime, timedelta +import ujson as json + +from datadog_lambda.config import config from datadog_lambda.extension import should_use_extension -from datadog_lambda.tags import get_enhanced_metrics_tags, tag_dd_lambda_layer -from datadog_lambda.api import init_api +from datadog_lambda.tags import dd_lambda_layer_tag, get_enhanced_metrics_tags logger = logging.getLogger(__name__) -lambda_stats = None -init_api() +class MetricsHandler(enum.Enum): + EXTENSION = "extension" + FORWARDER = "forwarder" + DATADOG_API = "datadog_api" + NO_METRICS = "no_metrics" + + +def _select_metrics_handler(): + if should_use_extension: + return MetricsHandler.EXTENSION + if config.flush_to_log: + return MetricsHandler.FORWARDER + + if config.fips_mode_enabled: + logger.debug( + "With FIPS mode enabled, the Datadog API metrics handler is unavailable." + ) + return MetricsHandler.NO_METRICS + + return MetricsHandler.DATADOG_API + + +metrics_handler = _select_metrics_handler() +logger.debug("identified primary metrics handler as %s", metrics_handler) + -if should_use_extension: +lambda_stats = None +if metrics_handler == MetricsHandler.EXTENSION: from datadog_lambda.statsd_writer import StatsDWriter lambda_stats = StatsDWriter() -else: + +elif metrics_handler == MetricsHandler.DATADOG_API: # Periodical flushing in a background thread is NOT guaranteed to succeed # and leads to data loss. When disabled, metrics are only flushed at the # end of invocation. To make metrics submitted from a long-running Lambda # function available sooner, consider using the Datadog Lambda extension. + from datadog_lambda.api import init_api from datadog_lambda.thread_stats_writer import ThreadStatsWriter - flush_in_thread = os.environ.get("DD_FLUSH_IN_THREAD", "").lower() == "true" - lambda_stats = ThreadStatsWriter(flush_in_thread) + init_api() + lambda_stats = ThreadStatsWriter(config.flush_in_thread) def lambda_metric(metric_name, value, timestamp=None, tags=None, force_async=False): @@ -38,38 +66,96 @@ def lambda_metric(metric_name, value, timestamp=None, tags=None, force_async=Fal Submit a data point to Datadog distribution metrics. https://docs.datadoghq.com/graphing/metrics/distributions/ - When DD_FLUSH_TO_LOG is True, write metric to log, and - wait for the Datadog Log Forwarder Lambda function to submit - the metrics asynchronously. + If the Datadog Lambda Extension is present, metrics are submitted to its + dogstatsd endpoint. + + When DD_FLUSH_TO_LOG is True or force_async is True, write metric to log, + and wait for the Datadog Log Forwarder Lambda function to submit the + metrics asynchronously. Otherwise, the metrics will be submitted to the Datadog API periodically and at the end of the function execution in a background thread. - Note that if the extension is present, it will override the DD_FLUSH_TO_LOG value - and always use the layer to send metrics to the extension + Note that if the extension is present, it will override the DD_FLUSH_TO_LOG + value and always use the layer to send metrics to the extension """ - flush_to_logs = os.environ.get("DD_FLUSH_TO_LOG", "").lower() == "true" - tags = tag_dd_lambda_layer(tags) + if not metric_name or not isinstance(metric_name, str): + logger.warning( + "Ignoring metric submission. Invalid metric name: %s", metric_name + ) + return + + try: + float(value) + except (ValueError, TypeError): + logger.warning( + "Ignoring metric submission for metric '%s' because the value is not numeric: %r", + metric_name, + value, + ) + return + + tags = [] if tags is None else list(tags) + tags.append(dd_lambda_layer_tag) + + if metrics_handler == MetricsHandler.EXTENSION: + if timestamp is not None: + if isinstance(timestamp, datetime): + timestamp = int(timestamp.timestamp()) + + else: + try: + timestamp = int(timestamp) + except Exception: + logger.debug( + "Ignoring metric submission for metric '%s' because the timestamp cannot " + "be turned into an integer: %r", + metric_name, + timestamp, + ) + return + + timestamp_floor = int((datetime.now() - timedelta(hours=4)).timestamp()) + if timestamp < timestamp_floor: + logger.warning( + "Timestamp %s is older than 4 hours, not submitting metric %s", + timestamp, + metric_name, + ) + return - if should_use_extension: logger.debug( "Sending metric %s value %s to Datadog via extension", metric_name, value ) lambda_stats.distribution(metric_name, value, tags=tags, timestamp=timestamp) + + elif force_async or (metrics_handler == MetricsHandler.FORWARDER): + write_metric_point_to_stdout(metric_name, value, timestamp=timestamp, tags=tags) + + elif metrics_handler == MetricsHandler.DATADOG_API: + lambda_stats.distribution(metric_name, value, tags=tags, timestamp=timestamp) + + elif metrics_handler == MetricsHandler.NO_METRICS: + logger.debug( + "Metric %s cannot be submitted because the metrics handler is disabled", + metric_name, + ), + else: - if flush_to_logs or force_async: - write_metric_point_to_stdout( - metric_name, value, timestamp=timestamp, tags=tags - ) - else: - lambda_stats.distribution( - metric_name, value, tags=tags, timestamp=timestamp - ) + # This should be qutie impossible, but let's at least log a message if + # it somehow happens. + logger.debug( + "Metric %s cannot be submitted because the metrics handler is not configured: %s", + metric_name, + metrics_handler, + ) -def write_metric_point_to_stdout(metric_name, value, timestamp=None, tags=[]): +def write_metric_point_to_stdout(metric_name, value, timestamp=None, tags=None): """Writes the specified metric point to standard output""" + tags = tags or [] + logger.debug( "Sending metric %s value %s to Datadog via log forwarder", metric_name, value ) @@ -80,23 +166,15 @@ def write_metric_point_to_stdout(metric_name, value, timestamp=None, tags=[]): "v": value, "e": timestamp or int(time.time()), "t": tags, - } + }, + escape_forward_slashes=False, ) ) -def flush_stats(): - lambda_stats.flush() - - -def are_enhanced_metrics_enabled(): - """Check env var to find if enhanced metrics should be submitted - - Returns: - boolean for whether enhanced metrics are enabled - """ - # DD_ENHANCED_METRICS defaults to true - return os.environ.get("DD_ENHANCED_METRICS", "true").lower() == "true" +def flush_stats(lambda_context=None): + if lambda_stats is not None: + lambda_stats.flush() def submit_enhanced_metric(metric_name, lambda_context): @@ -104,9 +182,9 @@ def submit_enhanced_metric(metric_name, lambda_context): Args: metric_name (str): metric name w/o enhanced prefix i.e. "invocations" or "errors" - lambda_context (dict): Lambda context dict passed to the function by AWS + lambda_context (object): Lambda context dict passed to the function by AWS """ - if not are_enhanced_metrics_enabled(): + if not config.enhanced_metrics_enabled: logger.debug( "Not submitting enhanced metric %s because enhanced metrics are disabled", metric_name, @@ -122,7 +200,7 @@ def submit_invocations_metric(lambda_context): """Increment aws.lambda.enhanced.invocations by 1, applying runtime, layer, and cold_start tags Args: - lambda_context (dict): Lambda context dict passed to the function by AWS + lambda_context (object): Lambda context dict passed to the function by AWS """ submit_enhanced_metric("invocations", lambda_context) @@ -131,6 +209,47 @@ def submit_errors_metric(lambda_context): """Increment aws.lambda.enhanced.errors by 1, applying runtime, layer, and cold_start tags Args: - lambda_context (dict): Lambda context dict passed to the function by AWS + lambda_context (object): Lambda context dict passed to the function by AWS """ submit_enhanced_metric("errors", lambda_context) + + +def submit_batch_item_failures_metric(response, lambda_context): + """Submit aws.lambda.enhanced.batch_item_failures metric with the count of batch item failures + + Args: + response (dict): Lambda function response object + lambda_context (object): Lambda context dict passed to the function by AWS + """ + if not config.enhanced_metrics_enabled: + logger.debug( + "Not submitting batch_item_failures metric because enhanced metrics are disabled" + ) + return + + if not isinstance(response, dict): + return + + batch_item_failures = response.get("batchItemFailures") + if batch_item_failures is not None and isinstance(batch_item_failures, list): + lambda_metric( + "aws.lambda.enhanced.batch_item_failures", + len(batch_item_failures), + timestamp=None, + tags=get_enhanced_metrics_tags(lambda_context), + force_async=True, + ) + + +def submit_dynamodb_stream_type_metric(event): + stream_view_type = ( + event.get("Records", [{}])[0].get("dynamodb", {}).get("StreamViewType") + ) + if stream_view_type: + lambda_metric( + "datadog.serverless.dynamodb.stream.type", + 1, + timestamp=None, + tags=[f"streamtype:{stream_view_type}"], + force_async=True, + ) diff --git a/datadog_lambda/patch.py b/datadog_lambda/patch.py index 0f6d28e96..6d2af0dcf 100644 --- a/datadog_lambda/patch.py +++ b/datadog_lambda/patch.py @@ -3,20 +3,17 @@ # This product includes software developed at Datadog (https://www.datadoghq.com/). # Copyright 2019 Datadog, Inc. -import json -import os import sys import logging import zlib +import ujson as json from wrapt import wrap_function_wrapper as wrap from wrapt.importer import when_imported from ddtrace import patch_all as patch_all_dd -from datadog_lambda.tracing import ( - get_dd_trace_context, - dd_tracing_enabled, -) +from datadog_lambda.config import config +from datadog_lambda.tracing import get_dd_trace_context from collections.abc import MutableMapping logger = logging.getLogger(__name__) @@ -32,7 +29,7 @@ def patch_all(): """ _patch_for_integration_tests() - if dd_tracing_enabled: + if config.trace_enabled: patch_all_dd() else: _patch_http() @@ -44,8 +41,7 @@ def _patch_for_integration_tests(): Patch `requests` to log the outgoing requests for integration tests. """ global _integration_tests_patched - is_in_tests = os.environ.get("DD_INTEGRATION_TEST", "false").lower() == "true" - if not _integration_tests_patched and is_in_tests: + if not _integration_tests_patched and config.integration_test: wrap("requests", "Session.send", _log_request) _integration_tests_patched = True @@ -144,14 +140,14 @@ def _print_request_string(request): data = zlib.decompress(data) data_dict = json.loads(data) data_dict.get("series", []).sort(key=lambda series: series.get("metric")) - sorted_data = json.dumps(data_dict) + sorted_data = json.dumps(data_dict, escape_forward_slashes=False) # Sort headers to prevent any differences in ordering headers = request.headers or {} sorted_headers = sorted( "{}:{}".format(key, value) for key, value in headers.items() ) - sorted_header_str = json.dumps(sorted_headers) + sorted_header_str = json.dumps(sorted_headers, escape_forward_slashes=False) print( "HTTP {} {} Headers: {} Data: {}".format( method, url, sorted_header_str, sorted_data diff --git a/datadog_lambda/span_pointers.py b/datadog_lambda/span_pointers.py new file mode 100644 index 000000000..45925d929 --- /dev/null +++ b/datadog_lambda/span_pointers.py @@ -0,0 +1,200 @@ +from itertools import chain +import logging +from typing import List +from typing import Optional + +from ddtrace._trace._span_pointer import _SpanPointerDirection +from ddtrace._trace._span_pointer import _SpanPointerDescription + +from datadog_lambda.config import config +from datadog_lambda.metric import submit_dynamodb_stream_type_metric +from datadog_lambda.trigger import EventTypes + + +logger = logging.getLogger(__name__) + + +def calculate_span_pointers( + event_source, + event, + botocore_add_span_pointers=config.add_span_pointers, +) -> List[_SpanPointerDescription]: + try: + if botocore_add_span_pointers: + if event_source.equals(EventTypes.S3): + return _calculate_s3_span_pointers_for_event(event) + + elif event_source.equals(EventTypes.DYNAMODB): + # Temporary metric. TODO eventually remove(@nhulston) + submit_dynamodb_stream_type_metric(event) + return _calculate_dynamodb_span_pointers_for_event(event) + + except Exception as e: + logger.debug( + "failed to calculate span pointers for event: %s", + e, + ) + + return [] + + +def _calculate_s3_span_pointers_for_event(event) -> List[_SpanPointerDescription]: + # Example event: + # https://docs.aws.amazon.com/lambda/latest/dg/with-s3.html + + return list( + chain.from_iterable( + _calculate_s3_span_pointers_for_event_record(record) + for record in event.get("Records", []) + ) + ) + + +def _calculate_s3_span_pointers_for_event_record( + record, +) -> List[_SpanPointerDescription]: + # Event types: + # https://docs.aws.amazon.com/AmazonS3/latest/userguide/notification-how-to-event-types-and-destinations.html + + if record.get("eventName").startswith("ObjectCreated:"): + s3_information = record.get("s3", None) + if s3_information is not None: + return _calculate_s3_span_pointers_for_object_created_s3_information( + s3_information + ) + + return [] + + +def _calculate_s3_span_pointers_for_object_created_s3_information( + s3_information, +) -> List[_SpanPointerDescription]: + try: + bucket = s3_information["bucket"]["name"] + key = s3_information["object"]["key"] + etag = s3_information["object"]["eTag"] + + except KeyError as e: + logger.debug( + "missing s3 information required to make a span pointer: %s", + e, + ) + return [] + + try: + from ddtrace._trace.utils_botocore.span_pointers.s3 import ( + _aws_s3_object_span_pointer_description, + ) + + try: + span_pointer_description = _aws_s3_object_span_pointer_description( + operation="S3.LambdaEvent", + pointer_direction=_SpanPointerDirection.UPSTREAM, + bucket=bucket, + key=key, + etag=etag, + ) + except TypeError: + # The older version of this function did not have an operation + # parameter. + span_pointer_description = _aws_s3_object_span_pointer_description( + pointer_direction=_SpanPointerDirection.UPSTREAM, + bucket=bucket, + key=key, + etag=etag, + ) + + if span_pointer_description is None: + return [] + + return [span_pointer_description] + + except Exception as e: + logger.debug( + "failed to generate S3 span pointer: %s", + e, + ) + return [] + + +def _calculate_dynamodb_span_pointers_for_event(event) -> List[_SpanPointerDescription]: + # Example event: + # https://docs.aws.amazon.com/lambda/latest/dg/with-ddb.html + + return list( + chain.from_iterable( + _calculate_dynamodb_span_pointers_for_event_record(record) + for record in event.get("Records", []) + ) + ) + + +def _calculate_dynamodb_span_pointers_for_event_record( + record, +) -> List[_SpanPointerDescription]: + try: + table_name = _extract_table_name_from_dynamodb_stream_record(record) + if table_name is None: + return [] + + primary_key = record["dynamodb"]["Keys"] + + except Exception as e: + logger.debug( + "missing DynamoDB information required to make a span pointer: %s", + e, + ) + return [] + + try: + from ddtrace._trace.utils_botocore.span_pointers.dynamodb import ( + _aws_dynamodb_item_span_pointer_description, + ) + + try: + span_pointer_description = _aws_dynamodb_item_span_pointer_description( + operation="DynamoDB.LambdaEvent", + pointer_direction=_SpanPointerDirection.UPSTREAM, + table_name=table_name, + primary_key=primary_key, + ) + except TypeError: + # The older version of this function did not have an operation + # parameter. + span_pointer_description = _aws_dynamodb_item_span_pointer_description( + pointer_direction=_SpanPointerDirection.UPSTREAM, + table_name=table_name, + primary_key=primary_key, + ) + + if span_pointer_description is None: + return [] + + return [span_pointer_description] + + except Exception as e: + logger.debug( + "failed to generate DynamoDB span pointer: %s", + e, + ) + return [] + + +def _extract_table_name_from_dynamodb_stream_record(record) -> Optional[str]: + # Example eventSourceARN: + # arn:aws:dynamodb:us-east-2:123456789012:table/my-table/stream/2024-06-10T19:26:16.525 + event_source_arn = record["eventSourceARN"] + + [_arn, _aws, _dynamodb, _region, _account, dynamodb_info] = event_source_arn.split( + ":", maxsplit=5 + ) + if _arn != "arn" or _aws != "aws" or _dynamodb != "dynamodb": + logger.debug("unexpected eventSourceARN format: %s", event_source_arn) + return None + + [_table, table_name, _stream, _timestamp] = dynamodb_info.split("/") + if _table != "table" or _stream != "stream": + logger.debug("unexpected eventSourceARN format: %s", event_source_arn) + return None + + return table_name diff --git a/datadog_lambda/stats_writer.py b/datadog_lambda/stats_writer.py index d3919c30f..563b1ae98 100644 --- a/datadog_lambda/stats_writer.py +++ b/datadog_lambda/stats_writer.py @@ -1,5 +1,5 @@ class StatsWriter: - def distribution(self, metric_name, value, tags=[], timestamp=None): + def distribution(self, metric_name, value, tags=None, timestamp=None): raise NotImplementedError() def flush(self): diff --git a/datadog_lambda/statsd_writer.py b/datadog_lambda/statsd_writer.py index 33843dc6a..4aaab8d53 100644 --- a/datadog_lambda/statsd_writer.py +++ b/datadog_lambda/statsd_writer.py @@ -1,5 +1,5 @@ -from datadog_lambda.stats_writer import StatsWriter from datadog_lambda.dogstatsd import statsd +from datadog_lambda.stats_writer import StatsWriter class StatsDWriter(StatsWriter): @@ -7,8 +7,8 @@ class StatsDWriter(StatsWriter): Writes distribution metrics using StatsD protocol """ - def distribution(self, metric_name, value, tags=[], timestamp=None): - statsd.distribution(metric_name, value, tags=tags) + def distribution(self, metric_name, value, tags=None, timestamp=None): + statsd.distribution(metric_name, value, tags=tags, timestamp=timestamp) def flush(self): pass diff --git a/datadog_lambda/tag_object.py b/datadog_lambda/tag_object.py index ec1c5a669..744e48933 100644 --- a/datadog_lambda/tag_object.py +++ b/datadog_lambda/tag_object.py @@ -4,18 +4,17 @@ # Copyright 2021 Datadog, Inc. from decimal import Decimal -import json -import logging +import ujson as json + +from datadog_lambda.config import config redactable_keys = ["authorization", "x-authorization", "password", "token"] -max_depth = 10 -logger = logging.getLogger(__name__) def tag_object(span, key, obj, depth=0): if obj is None: return span.set_tag(key, obj) - if depth >= max_depth: + if depth >= config.capture_payload_max_depth: return span.set_tag(key, _redact_val(key, str(obj)[0:5000])) depth += 1 if _should_try_string(obj): @@ -30,17 +29,17 @@ def tag_object(span, key, obj, depth=0): return span.set_tag(key, str(obj)) if isinstance(obj, list): for k, v in enumerate(obj): - formatted_key = "{}.{}".format(key, k) + formatted_key = f"{key}.{k}" tag_object(span, formatted_key, v, depth) return if hasattr(obj, "items"): for k, v in obj.items(): - formatted_key = "{}.{}".format(key, k) + formatted_key = f"{key}.{k}" tag_object(span, formatted_key, v, depth) return if hasattr(obj, "to_dict"): for k, v in obj.to_dict().items(): - formatted_key = "{}.{}".format(key, k) + formatted_key = f"{key}.{k}" tag_object(span, formatted_key, v, depth) return try: diff --git a/datadog_lambda/tags.py b/datadog_lambda/tags.py index cdaeb4eda..5b3fe43e6 100644 --- a/datadog_lambda/tags.py +++ b/datadog_lambda/tags.py @@ -1,28 +1,13 @@ import sys -from platform import python_version_tuple - from datadog_lambda import __version__ from datadog_lambda.cold_start import get_cold_start_tag -def _format_dd_lambda_layer_tag(): - """ - Formats the dd_lambda_layer tag, e.g., 'dd_lambda_layer:datadog-python39_1' - """ - runtime = "python{}{}".format(sys.version_info[0], sys.version_info[1]) - return "dd_lambda_layer:datadog-{}_{}".format(runtime, __version__) - - -def tag_dd_lambda_layer(tags): - """ - Used by lambda_metric to insert the dd_lambda_layer tag - """ - dd_lambda_layer_tag = _format_dd_lambda_layer_tag() - if tags: - return tags + [dd_lambda_layer_tag] - else: - return [dd_lambda_layer_tag] +_major, _minor = sys.version_info[0], sys.version_info[1] +dd_lambda_layer_tag = f"dd_lambda_layer:datadog-python{_major}{_minor}_{__version__}" +runtime_tag = f"runtime:python{_major}.{_minor}" +library_version_tag = f"datadog_lambda:v{__version__}" def parse_lambda_tags_from_arn(lambda_context): @@ -32,64 +17,52 @@ def parse_lambda_tags_from_arn(lambda_context): ex: lambda_context.arn = arn:aws:lambda:us-east-1:123597598159:function:my-lambda:1 """ # Set up flag for extra testing to distinguish between a version or alias - hasAlias = False + has_alias = False # Cap the number of times to spli split_arn = lambda_context.invoked_function_arn.split(":") if len(split_arn) > 7: - hasAlias = True + has_alias = True _, _, _, region, account_id, _, function_name, alias = split_arn else: _, _, _, region, account_id, _, function_name = split_arn # Add the standard tags to a list tags = [ - "region:{}".format(region), - "account_id:{}".format(account_id), - "functionname:{}".format(function_name), + f"region:{region}", + f"account_id:{account_id}", + f"functionname:{function_name}", ] # Check if we have a version or alias - if hasAlias: + if has_alias: # If $Latest, drop the $ for datadog tag convention. A lambda alias can't start with $ if alias.startswith("$"): alias = alias[1:] # Versions are numeric. Aliases need the executed version tag elif not check_if_number(alias): - tags.append("executedversion:{}".format(lambda_context.function_version)) + tags.append(f"executedversion:{lambda_context.function_version}") # create resource tag with function name and alias/version - resource = "resource:{}:{}".format(function_name, alias) + resource = f"resource:{function_name}:{alias}" else: # Resource is only the function name otherwise - resource = "resource:{}".format(function_name) + resource = f"resource:{function_name}" tags.append(resource) return tags -def get_runtime_tag(): - """Get the runtime tag from the current Python version""" - major_version, minor_version, _ = python_version_tuple() - - return "runtime:python{major}.{minor}".format( - major=major_version, minor=minor_version - ) - - -def get_library_version_tag(): - """Get datadog lambda library tag""" - return "datadog_lambda:v{}".format(__version__) - - def get_enhanced_metrics_tags(lambda_context): """Get the list of tags to apply to enhanced metrics""" - return parse_lambda_tags_from_arn(lambda_context) + [ - get_cold_start_tag(), - "memorysize:{}".format(lambda_context.memory_limit_in_mb), - get_runtime_tag(), - get_library_version_tag(), - ] + tags = [] + if lambda_context: + tags = parse_lambda_tags_from_arn(lambda_context) + tags.append(f"memorysize:{lambda_context.memory_limit_in_mb}") + tags.append(get_cold_start_tag()) + tags.append(runtime_tag) + tags.append(library_version_tag) + return tags def check_if_number(alias): diff --git a/datadog_lambda/thread_stats_writer.py b/datadog_lambda/thread_stats_writer.py index bfcf3c992..f21ee31f9 100644 --- a/datadog_lambda/thread_stats_writer.py +++ b/datadog_lambda/thread_stats_writer.py @@ -3,6 +3,7 @@ # Make sure that this package would always be lazy-loaded/outside from the critical path # since underlying packages are quite heavy to load and useless when the extension is present from datadog.threadstats import ThreadStats + from datadog_lambda.stats_writer import StatsWriter logger = logging.getLogger(__name__) @@ -17,16 +18,21 @@ def __init__(self, flush_in_thread): self.thread_stats = ThreadStats(compress_payload=True) self.thread_stats.start(flush_in_thread=flush_in_thread) - def distribution(self, metric_name, value, tags=[], timestamp=None): + def distribution(self, metric_name, value, tags=None, timestamp=None): self.thread_stats.distribution( metric_name, value, tags=tags, timestamp=timestamp ) - def flush(self): + def flush(self, tags=None): """ "Flush distributions from ThreadStats to Datadog. Modified based on `datadog.threadstats.base.ThreadStats.flush()`, to gain better control over exception handling. """ + original_constant_tags = self.thread_stats.constant_tags.copy() + if tags: + # Temporarily add tags for this flush + self.thread_stats.constant_tags = original_constant_tags + tags + _, dists = self.thread_stats._get_aggregate_metrics_and_dists(float("inf")) count_dists = len(dists) if not count_dists: @@ -60,6 +66,9 @@ def flush(self): logger.debug( "Flush #%s failed", self.thread_stats.flush_count, exc_info=True ) + finally: + # Reset constant_tags to its original state + self.thread_stats.constant_tags = original_constant_tags def stop(self): self.thread_stats.stop() diff --git a/datadog_lambda/tracing.py b/datadog_lambda/tracing.py index 6adf5d002..4faaed2df 100644 --- a/datadog_lambda/tracing.py +++ b/datadog_lambda/tracing.py @@ -2,11 +2,11 @@ # under the Apache License Version 2.0. # This product includes software developed at Datadog (https://www.datadoghq.com/). # Copyright 2019 Datadog, Inc. -import hashlib import logging import os -import json -import base64 +import re +import traceback +import ujson as json from datetime import datetime, timezone from typing import Optional, Dict @@ -28,23 +28,24 @@ send_segment, parse_xray_header, ) -from ddtrace import tracer, patch, Span + +from ddtrace import patch from ddtrace import __version__ as ddtrace_version from ddtrace.propagation.http import HTTPPropagator -from ddtrace.context import Context +from ddtrace.trace import Context, Span, tracer + +from datadog_lambda.config import config from datadog_lambda import __version__ as datadog_lambda_version from datadog_lambda.trigger import ( _EventSource, parse_event_source, get_first_record, + is_step_function_event, EventTypes, EventSubtypes, ) -dd_trace_otel_enabled = ( - os.environ.get("DD_TRACE_OTEL_ENABLED", "false").lower() == "true" -) -if dd_trace_otel_enabled: +if config.otel_enabled: from opentelemetry.trace import set_tracer_provider from ddtrace.opentelemetry import TracerProvider @@ -54,19 +55,36 @@ logger = logging.getLogger(__name__) dd_trace_context = None -dd_tracing_enabled = os.environ.get("DD_TRACE_ENABLED", "false").lower() == "true" -if dd_tracing_enabled: +if config.telemetry_enabled: # Enable the telemetry client if the user has opted in - if ( - os.environ.get("DD_INSTRUMENTATION_TELEMETRY_ENABLED", "false").lower() - == "true" - ): - from ddtrace.internal.telemetry import telemetry_writer + from ddtrace.internal.telemetry import telemetry_writer - telemetry_writer.enable() + telemetry_writer.enable() propagator = HTTPPropagator() +DD_TRACE_JAVA_TRACE_ID_PADDING = "00000000" +HIGHER_64_BITS = "HIGHER_64_BITS" +LOWER_64_BITS = "LOWER_64_BITS" + + +def _dsm_set_checkpoint(context_json, event_type, arn): + if not config.data_streams_enabled: + return + + if not arn: + return + + try: + from ddtrace.data_streams import set_consume_checkpoint + + carrier_get = lambda k: context_json and context_json.get(k) # noqa: E731 + set_consume_checkpoint(event_type, arn, carrier_get, manual_checkpoint=False) + except Exception as e: + logger.debug( + f"DSM:Failed to set consume checkpoint for {event_type} {arn}: {e}" + ) + def _convert_xray_trace_id(xray_trace_id): """ @@ -90,7 +108,7 @@ def _convert_xray_sampling(xray_sampled): def _get_xray_trace_context(): - if not is_lambda_context(): + if not config.is_lambda_context: return None xray_trace_entity = parse_xray_header( @@ -106,11 +124,7 @@ def _get_xray_trace_context(): logger.debug( "Converted trace context %s from X-Ray segment %s", trace_context, - ( - xray_trace_entity["trace_id"], - xray_trace_entity["parent_id"], - xray_trace_entity["sampled"], - ), + xray_trace_entity, ) return trace_context @@ -121,7 +135,9 @@ def _get_dd_trace_py_context(): return None logger.debug( - "found dd trace context: %s", (span.context.trace_id, span.context.span_id) + "found dd trace context: trace_id=%s span_id=%s", + span.context.trace_id, + span.context.span_id, ) return span.context @@ -193,6 +209,20 @@ def extract_context_from_http_event_or_context( return context +def extract_context_from_request_header_or_context(event, lambda_context, event_source): + request = event.get("request") + if isinstance(request, (set, dict)) and "headers" in request: + context = extract_context_from_http_event_or_context( + request, + lambda_context, + event_source, + decode_authorizer_context=False, + ) + else: + context = extract_context_from_lambda_context(lambda_context) + return context + + def create_sns_event(message): return { "Records": [ @@ -205,7 +235,9 @@ def create_sns_event(message): } -def extract_context_from_sqs_or_sns_event_or_context(event, lambda_context): +def extract_context_from_sqs_or_sns_event_or_context( + event, lambda_context, event_source +): """ Extract Datadog trace context from an SQS event. @@ -217,7 +249,10 @@ def extract_context_from_sqs_or_sns_event_or_context(event, lambda_context): Lambda Context. Falls back to lambda context if no trace data is found in the SQS message attributes. + Set a DSM checkpoint if DSM is enabled and the method for context propagation is supported. """ + source_arn = "" + event_type = "sqs" if event_source.equals(EventTypes.SQS) else "sns" # EventBridge => SQS try: @@ -229,48 +264,88 @@ def extract_context_from_sqs_or_sns_event_or_context(event, lambda_context): try: first_record = event.get("Records")[0] + source_arn = first_record.get("eventSourceARN", "") # logic to deal with SNS => SQS event if "body" in first_record: - body_str = first_record.get("body", {}) + body_str = first_record.get("body") try: body = json.loads(body_str) if body.get("Type", "") == "Notification" and "TopicArn" in body: logger.debug("Found SNS message inside SQS event") first_record = get_first_record(create_sns_event(body)) except Exception: - first_record = event.get("Records")[0] pass - msg_attributes = first_record.get( - "messageAttributes", - first_record.get("Sns", {}).get("MessageAttributes", {}), - ) - dd_payload = msg_attributes.get("_datadog", {}) - # SQS uses dataType and binaryValue/stringValue - # SNS uses Type and Value - dd_json_data_type = dd_payload.get("Type", dd_payload.get("dataType", "")) - if dd_json_data_type == "Binary": - dd_json_data = dd_payload.get( - "binaryValue", - dd_payload.get("Value", r"{}"), - ) - dd_json_data = base64.b64decode(dd_json_data) - elif dd_json_data_type == "String": - dd_json_data = dd_payload.get( - "stringValue", - dd_payload.get("Value", r"{}"), - ) + msg_attributes = first_record.get("messageAttributes") + if msg_attributes is None: + sns_record = first_record.get("Sns") or {} + # SNS->SQS event would extract SNS arn without this check + if event_source.equals(EventTypes.SNS): + source_arn = sns_record.get("TopicArn", "") + msg_attributes = sns_record.get("MessageAttributes") or {} + dd_payload = msg_attributes.get("_datadog") + if dd_payload: + # SQS uses dataType and binaryValue/stringValue + # SNS uses Type and Value + dd_json_data = None + dd_json_data_type = dd_payload.get("Type") or dd_payload.get("dataType") + if dd_json_data_type == "Binary": + import base64 + + dd_json_data = dd_payload.get("binaryValue") or dd_payload.get("Value") + if dd_json_data: + dd_json_data = base64.b64decode(dd_json_data) + elif dd_json_data_type == "String": + dd_json_data = dd_payload.get("stringValue") or dd_payload.get("Value") + else: + logger.debug( + "Datadog Lambda Python only supports extracting trace" + "context from String or Binary SQS/SNS message attributes" + ) + + if dd_json_data: + dd_data = json.loads(dd_json_data) + + if is_step_function_event(dd_data): + try: + return extract_context_from_step_functions(dd_data, None) + except Exception: + logger.debug( + "Failed to extract Step Functions context from SQS/SNS event." + ) + context = propagator.extract(dd_data) + _dsm_set_checkpoint(dd_data, event_type, source_arn) + return context else: - logger.debug( - "Datadog Lambda Python only supports extracting trace" - "context from String or Binary SQS/SNS message attributes" - ) - return extract_context_from_lambda_context(lambda_context) - dd_data = json.loads(dd_json_data) - return propagator.extract(dd_data) + # Handle case where trace context is injected into attributes.AWSTraceHeader + # example: Root=1-654321ab-000000001234567890abcdef;Parent=0123456789abcdef;Sampled=1 + attrs = event.get("Records")[0].get("attributes") + if attrs: + x_ray_header = attrs.get("AWSTraceHeader") + if x_ray_header: + x_ray_context = parse_xray_header(x_ray_header) + trace_id_parts = x_ray_context.get("trace_id", "").split("-") + if len(trace_id_parts) > 2 and trace_id_parts[2].startswith( + DD_TRACE_JAVA_TRACE_ID_PADDING + ): + # If it starts with eight 0's padding, + # then this AWSTraceHeader contains Datadog injected trace context + logger.debug( + "Found dd-trace injected trace context from AWSTraceHeader" + ) + return Context( + trace_id=int(trace_id_parts[2][8:], 16), + span_id=int(x_ray_context["parent_id"], 16), + sampling_priority=float(x_ray_context["sampled"]), + ) + # Still want to set a DSM checkpoint even if DSM context not propagated + _dsm_set_checkpoint(None, event_type, source_arn) + return extract_context_from_lambda_context(lambda_context) except Exception as e: logger.debug("The trace extractor returned with error %s", e) + # Still want to set a DSM checkpoint even if DSM context not propagated + _dsm_set_checkpoint(None, event_type, source_arn) return extract_context_from_lambda_context(lambda_context) @@ -287,6 +362,15 @@ def _extract_context_from_eventbridge_sqs_event(event): body = json.loads(body_str) detail = body.get("detail") dd_context = detail.get("_datadog") + + if is_step_function_event(dd_context): + try: + return extract_context_from_step_functions(dd_context, None) + except Exception: + logger.debug( + "Failed to extract Step Functions context from EventBridge to SQS event." + ) + return propagator.extract(dd_context) @@ -294,12 +378,23 @@ def extract_context_from_eventbridge_event(event, lambda_context): """ Extract datadog trace context from an EventBridge message's Details. This is only possible if Details is a JSON string. + + If we find a Step Function context, try to extract the trace context from + that header. """ try: detail = event.get("detail") dd_context = detail.get("_datadog") if not dd_context: return extract_context_from_lambda_context(lambda_context) + + try: + return extract_context_from_step_functions(dd_context, None) + except Exception: + logger.debug( + "Failed to extract Step Functions context from EventBridge event." + ) + return propagator.extract(dd_context) except Exception as e: logger.debug("The trace extractor returned with error %s", e) @@ -309,55 +404,147 @@ def extract_context_from_eventbridge_event(event, lambda_context): def extract_context_from_kinesis_event(event, lambda_context): """ Extract datadog trace context from a Kinesis Stream's base64 encoded data string + Set a DSM checkpoint if DSM is enabled and the method for context propagation is supported. """ + source_arn = "" try: record = get_first_record(event) - data = record.get("kinesis", {}).get("data", None) + source_arn = record.get("eventSourceARN", "") + kinesis = record.get("kinesis") + if not kinesis: + return extract_context_from_lambda_context(lambda_context) + data = kinesis.get("data") if data: + import base64 + b64_bytes = data.encode("ascii") str_bytes = base64.b64decode(b64_bytes) data_str = str_bytes.decode("ascii") data_obj = json.loads(data_str) dd_ctx = data_obj.get("_datadog") - - if not dd_ctx: - return extract_context_from_lambda_context(lambda_context) - - return propagator.extract(dd_ctx) + if dd_ctx: + context = propagator.extract(dd_ctx) + _dsm_set_checkpoint(dd_ctx, "kinesis", source_arn) + return context except Exception as e: logger.debug("The trace extractor returned with error %s", e) - return extract_context_from_lambda_context(lambda_context) + # Still want to set a DSM checkpoint even if DSM context not propagated + _dsm_set_checkpoint(None, "kinesis", source_arn) + return extract_context_from_lambda_context(lambda_context) -def _deterministic_md5_hash(s: str) -> int: - """MD5 here is to generate trace_id, not for any encryption.""" - hex_number = hashlib.md5(s.encode("ascii")).hexdigest() - binary = bin(int(hex_number, 16)) - binary_str = str(binary) - binary_str_remove_0b = binary_str[2:].rjust(128, "0") - most_significant_64_bits_without_leading_1 = "0" + binary_str_remove_0b[1:-64] - result = int(most_significant_64_bits_without_leading_1, 2) +def _deterministic_sha256_hash(s: str, part: str) -> int: + import hashlib + + sha256_hash = hashlib.sha256(s.encode()).hexdigest() + # First two chars is '0b'. zfill to ensure 256 bits, but we only care about the first 128 bits + binary_hash = bin(int(sha256_hash, 16))[2:].zfill(256) + if part == HIGHER_64_BITS: + updated_binary_hash = "0" + binary_hash[1:64] + else: + updated_binary_hash = "0" + binary_hash[65:128] + result = int(updated_binary_hash, 2) if result == 0: return 1 return result +def _parse_high_64_bits(trace_tags: str) -> str: + """ + Parse a list of trace tags such as [_dd.p.tid=66bcb5eb00000000,_dd.p.dm=-0] and return the + value of the _dd.p.tid tag or an empty string if not found. + """ + if trace_tags: + for tag in trace_tags.split(","): + if "_dd.p.tid=" in tag: + return tag.split("=")[1] + + return "" + + +def _generate_sfn_parent_id(context: dict) -> int: + """ + Generates a stable parent span ID for a downstream Lambda invoked by a Step Function. The + upstream Step Function execution context is used to infer the parent's span ID, ensuring trace + continuity. + + `RetryCount` and `RedriveCount` are appended only when both are nonzero to maintain + compatibility with older Lambda layers that did not include these fields. + """ + execution_id = context.get("Execution").get("Id") + redrive_count = context.get("Execution").get("RedriveCount", 0) + state_name = context.get("State").get("Name") + state_entered_time = context.get("State").get("EnteredTime") + retry_count = context.get("State").get("RetryCount", 0) + + include_counts = not (retry_count == 0 and redrive_count == 0) + counts_suffix = f"#{retry_count}#{redrive_count}" if include_counts else "" + + return _deterministic_sha256_hash( + f"{execution_id}#{state_name}#{state_entered_time}{counts_suffix}", + HIGHER_64_BITS, + ) + + +def _generate_sfn_trace_id(execution_id: str, part: str): + """ + Take the SHA-256 hash of the execution_id to calculate the trace ID. If the high 64 bits are + specified, we take those bits and use hex to encode it. We also remove the first two characters + as they will be '0x in the hex string. + + We care about full 128 bits because they will break up into traditional traceID and + _dd.p.tid tag. + """ + if part == HIGHER_64_BITS: + return hex(_deterministic_sha256_hash(execution_id, part))[2:] + return _deterministic_sha256_hash(execution_id, part) + + def extract_context_from_step_functions(event, lambda_context): """ Only extract datadog trace context when Step Functions Context Object is injected - into lambda's event dict. + into lambda's event dict. Unwrap "Payload" if it exists to handle Legacy Lambda cases. + + If '_datadog' header is present, we have two cases: + 1. Root is a Lambda and we use its traceID + 2. Root is a SFN, and we use its executionARN to calculate the traceID + We calculate the parentID the same in both cases by using the parent SFN's context object. + + Otherwise, we're dealing with the legacy case where we only have the parent SFN's context + object. """ try: - execution_id = event.get("Execution").get("Id") - state_name = event.get("State").get("Name") - state_entered_time = event.get("State").get("EnteredTime") - trace_id = _deterministic_md5_hash(execution_id) - parent_id = _deterministic_md5_hash( - execution_id + "#" + state_name + "#" + state_entered_time - ) + event = event.get("Payload", event) + event = event.get("_datadog", event) + + meta = {} + + if event.get("serverless-version") == "v1": + if "x-datadog-trace-id" in event: # lambda root + trace_id = int(event.get("x-datadog-trace-id")) + high_64_bit_trace_id = _parse_high_64_bits(event.get("x-datadog-tags")) + if high_64_bit_trace_id: + meta["_dd.p.tid"] = high_64_bit_trace_id + else: # sfn root + root_execution_id = event.get("RootExecutionId") + trace_id = _generate_sfn_trace_id(root_execution_id, LOWER_64_BITS) + meta["_dd.p.tid"] = _generate_sfn_trace_id( + root_execution_id, HIGHER_64_BITS + ) + + parent_id = _generate_sfn_parent_id(event) + else: + execution_id = event.get("Execution").get("Id") + trace_id = _generate_sfn_trace_id(execution_id, LOWER_64_BITS) + meta["_dd.p.tid"] = _generate_sfn_trace_id(execution_id, HIGHER_64_BITS) + parent_id = _generate_sfn_parent_id(event) + sampling_priority = SamplingPriority.AUTO_KEEP return Context( - trace_id=trace_id, span_id=parent_id, sampling_priority=sampling_priority + trace_id=trace_id, + span_id=parent_id, + sampling_priority=sampling_priority, + meta=meta, ) except Exception as e: logger.debug("The Step Functions trace extractor returned with error %s", e) @@ -369,11 +556,7 @@ def extract_context_custom_extractor(extractor, event, lambda_context): Extract Datadog trace context using a custom trace extractor function """ try: - ( - trace_id, - parent_id, - sampling_priority, - ) = extractor(event, lambda_context) + trace_id, parent_id, sampling_priority = extractor(event, lambda_context) return Context( trace_id=int(trace_id), span_id=int(parent_id), @@ -399,19 +582,26 @@ def is_authorizer_response(response) -> bool: def get_injected_authorizer_data(event, is_http_api) -> dict: try: - authorizer_headers = event.get("requestContext", {}).get("authorizer") + req_ctx = event.get("requestContext") + if not req_ctx: + return None + authorizer_headers = req_ctx.get("authorizer") if not authorizer_headers: return None - dd_data_raw = ( - authorizer_headers.get("lambda", {}).get("_datadog") - if is_http_api - else authorizer_headers.get("_datadog") - ) + if is_http_api: + lambda_hdr = authorizer_headers.get("lambda") + if not lambda_hdr: + return None + dd_data_raw = lambda_hdr.get("_datadog") + else: + dd_data_raw = authorizer_headers.get("_datadog") if not dd_data_raw: return None + import base64 + injected_data = json.loads(base64.b64decode(dd_data_raw)) # Lambda authorizer's results can be cached. But the payload will still have the injected @@ -421,16 +611,19 @@ def get_injected_authorizer_data(event, is_http_api) -> dict: # that case, we use the injected Authorizing_Request_Id to tell if it's cached. But token # authorizers don't pass on the requestId. The Authorizing_Request_Id can't work for all # cases neither. As a result, we combine both methods as shown below. - if authorizer_headers.get("integrationLatency", 0) > 0 or event.get( - "requestContext", {} - ).get("requestId") == injected_data.get(Headers.Authorizing_Request_Id): + if authorizer_headers.get("integrationLatency", 0) > 0: return injected_data - else: + req_ctx = event.get("requestContext") + if not req_ctx: return None + if req_ctx.get("requestId") == injected_data.get( + Headers.Authorizing_Request_Id + ): + return injected_data + return None except Exception as e: logger.debug("Failed to check if invocated by an authorizer. error %s", e) - return None def extract_dd_trace_context( @@ -448,13 +641,17 @@ def extract_dd_trace_context( if extractor is not None: context = extract_context_custom_extractor(extractor, event, lambda_context) + elif isinstance(event, (set, dict)) and "request" in event: + context = extract_context_from_request_header_or_context( + event, lambda_context, event_source + ) elif isinstance(event, (set, dict)) and "headers" in event: context = extract_context_from_http_event_or_context( event, lambda_context, event_source, decode_authorizer_context ) elif event_source.equals(EventTypes.SNS) or event_source.equals(EventTypes.SQS): context = extract_context_from_sqs_or_sns_event_or_context( - event, lambda_context + event, lambda_context, event_source ) elif event_source.equals(EventTypes.EVENTBRIDGE): context = extract_context_from_eventbridge_event(event, lambda_context) @@ -491,19 +688,17 @@ def get_dd_trace_context_obj(): automatically, but this function can be used to manually inject the trace context to an outgoing request. """ - if dd_tracing_enabled: + if config.trace_enabled: dd_trace_py_context = _get_dd_trace_py_context() if _is_context_complete(dd_trace_py_context): return dd_trace_py_context - global dd_trace_context - try: xray_context = _get_xray_trace_context() # xray (sub)segment except Exception as e: logger.debug( - "get_dd_trace_context couldn't read from segment from x-ray, with error %s" - % e + "get_dd_trace_context couldn't read from segment from x-ray, with error %s", + e, ) if not xray_context: return None @@ -542,10 +737,10 @@ def set_correlation_ids(): TODO: Remove me when Datadog tracer is natively supported in Lambda. """ - if not is_lambda_context(): + if not config.is_lambda_context: logger.debug("set_correlation_ids is only supported in LambdaContext") return - if dd_tracing_enabled: + if config.trace_enabled: logger.debug("using ddtrace implementation for spans") return @@ -569,9 +764,8 @@ def inject_correlation_ids(): # Override the log format of the AWS provided LambdaLoggerHandler root_logger = logging.getLogger() for handler in root_logger.handlers: - if ( - handler.__class__.__name__ == "LambdaLoggerHandler" - and type(handler.formatter) == logging.Formatter + if handler.__class__.__name__ == "LambdaLoggerHandler" and isinstance( + handler.formatter, logging.Formatter ): handler.setFormatter( logging.Formatter( @@ -587,15 +781,9 @@ def inject_correlation_ids(): logger.debug("logs injection configured") -def is_lambda_context(): - """ - Return True if the X-Ray context is `LambdaContext`, rather than the - regular `Context` (e.g., when testing lambda functions locally). - """ - return os.environ.get(XrayDaemon.FUNCTION_NAME_HEADER_NAME, "") != "" - - def set_dd_trace_py_root(trace_context_source, merge_xray_traces): + if not _is_context_complete(dd_trace_context): + return if trace_context_source == TraceContextSource.EVENT or merge_xray_traces: context = Context( trace_id=dd_trace_context.trace_id, @@ -609,8 +797,9 @@ def set_dd_trace_py_root(trace_context_source, merge_xray_traces): tracer.context_provider.activate(context) logger.debug( - "Set dd trace root context to: %s", - (context.trace_id, context.span_id), + "Set dd trace root context to: trace_id=%s span_id=%s", + context.trace_id, + context.span_id, ) @@ -671,9 +860,7 @@ def create_inferred_span( event_source.to_string(), e, ) - return None logger.debug("Unable to infer a span: unknown event type") - return None def create_service_mapping(val): @@ -688,55 +875,72 @@ def create_service_mapping(val): return new_service_mapping -def determine_service_name(service_mapping, specific_key, generic_key, default_value): - service_name = service_mapping.get(specific_key) - if service_name is None: - service_name = service_mapping.get(generic_key, default_value) - return service_name +def determine_service_name( + service_mapping, specific_key, generic_key, extracted_key, fallback=None +): + # Check for mapped service (specific key first, then generic key) + mapped_service = service_mapping.get(specific_key) or service_mapping.get( + generic_key + ) + if mapped_service: + return mapped_service + + # Check if AWS service representation is disabled + aws_service_representation = os.environ.get( + "DD_TRACE_AWS_SERVICE_REPRESENTATION_ENABLED", "" + ).lower() + if aws_service_representation in ("false", "0"): + return fallback + + # Use extracted_key if it exists and is not empty, otherwise use fallback + return ( + extracted_key.strip() if extracted_key and extracted_key.strip() else fallback + ) -service_mapping = {} # Initialization code -service_mapping_str = os.getenv("DD_SERVICE_MAPPING", "") +service_mapping_str = os.environ.get("DD_SERVICE_MAPPING", "") service_mapping = create_service_mapping(service_mapping_str) +_dd_origin = {"_dd.origin": "lambda"} + def create_inferred_span_from_lambda_function_url_event(event, context): request_context = event.get("requestContext") api_id = request_context.get("apiId") domain = request_context.get("domainName") service_name = determine_service_name(service_mapping, api_id, "lambda_url", domain) - method = request_context.get("http", {}).get("method") - path = request_context.get("http", {}).get("path") - resource = "{0} {1}".format(method, path) + http = request_context.get("http") + method = http.get("method") if http else None + path = http.get("path") if http else None + http_url = f"https://{domain}{path}/" + resource = f"{method} {path}" tags = { "operation_name": "aws.lambda.url", - "http.url": domain + path, + "http.url": http_url, "endpoint": path, "http.method": method, - "resource_names": domain + path, + "resource_names": resource, "request_id": context.aws_request_id, } request_time_epoch = request_context.get("timeEpoch") - args = { - "service": service_name, - "resource": resource, - "span_type": "http", - } - tracer.set_tags( - {"_dd.origin": "lambda"} - ) # function urls don't count as lambda_inferred, + tracer.set_tags(_dd_origin) # function urls don't count as lambda_inferred, # because they're in the same service as the inferring lambda function - span = tracer.trace("aws.lambda.url", **args) + span = tracer.trace( + "aws.lambda.url", service=service_name, resource=resource, span_type="http" + ) InferredSpanInfo.set_tags(tags, tag_source="self", synchronicity="sync") if span: span.set_tags(tags) - span.start = request_time_epoch / 1000 + span.start_ns = int(request_time_epoch * 1e6) return span def is_api_gateway_invocation_async(event): - return event.get("headers", {}).get("X-Amz-Invocation-Type") == "Event" + hdrs = event.get("headers") + if not hdrs: + return False + return hdrs.get("X-Amz-Invocation-Type") == "Event" def insert_upstream_authorizer_span( @@ -808,6 +1012,7 @@ def create_inferred_span_from_api_gateway_websocket_event( request_context = event.get("requestContext") domain = request_context.get("domainName") endpoint = request_context.get("routeKey") + http_url = f"https://{domain}{endpoint}/" api_id = request_context.get("apiId") service_name = determine_service_name( @@ -815,9 +1020,10 @@ def create_inferred_span_from_api_gateway_websocket_event( ) tags = { "operation_name": "aws.apigateway.websocket", - "http.url": domain + endpoint, + "http.url": http_url, "endpoint": endpoint, "resource_names": endpoint, + "span.kind": "server", "apiid": api_id, "apiname": api_id, "stage": request_context.get("stage"), @@ -836,7 +1042,7 @@ def create_inferred_span_from_api_gateway_websocket_event( "resource": endpoint, "span_type": "web", } - tracer.set_tags({"_dd.origin": "lambda"}) + tracer.set_tags(_dd_origin) upstream_authorizer_span = None finish_time_ns = None if decode_authorizer_context: @@ -867,13 +1073,16 @@ def create_inferred_span_from_api_gateway_event( ) method = event.get("httpMethod") path = event.get("path") - resource = "{0} {1}".format(method, path) + http_url = f"https://{domain}{path}/" + resource_path = _get_resource_path(event, request_context) + resource = f"{method} {resource_path}" tags = { "operation_name": "aws.apigateway.rest", - "http.url": domain + path, + "http.url": http_url, "endpoint": path, "http.method": method, "resource_names": resource, + "span.kind": "server", "apiid": api_id, "apiname": api_id, "stage": request_context.get("stage"), @@ -889,7 +1098,7 @@ def create_inferred_span_from_api_gateway_event( "resource": resource, "span_type": "http", } - tracer.set_tags({"_dd.origin": "lambda"}) + tracer.set_tags(_dd_origin) upstream_authorizer_span = None finish_time_ns = None if decode_authorizer_context: @@ -910,6 +1119,16 @@ def create_inferred_span_from_api_gateway_event( return span +def _get_resource_path(event, request_context): + route_key = request_context.get("routeKey") or "" + if "{" in route_key: + try: + return route_key.split(" ")[1] + except Exception as e: + logger.debug("Error parsing routeKey: %s", e) + return event.get("rawPath") or request_context.get("resourcePath") or route_key + + def create_inferred_span_from_http_api_event( event, context, decode_authorizer_context: bool = True ): @@ -919,17 +1138,20 @@ def create_inferred_span_from_http_api_event( service_name = determine_service_name( service_mapping, api_id, "lambda_api_gateway", domain ) - method = request_context.get("http", {}).get("method") + http = request_context.get("http") or {} + method = http.get("method") path = event.get("rawPath") - resource = "{0} {1}".format(method, path) + http_url = f"https://{domain}{path}/" + resource_path = _get_resource_path(event, request_context) + resource = f"{method} {resource_path}" tags = { "operation_name": "aws.httpapi", "endpoint": path, - "http.url": domain + path, - "http.method": request_context.get("http", {}).get("method"), - "http.protocol": request_context.get("http", {}).get("protocol"), - "http.source_ip": request_context.get("http", {}).get("sourceIp"), - "http.user_agent": request_context.get("http", {}).get("userAgent"), + "http.url": http_url, + "http.method": http.get("method"), + "http.protocol": http.get("protocol"), + "http.source_ip": http.get("sourceIp"), + "http.user_agent": http.get("userAgent"), "resource_names": resource, "request_id": context.aws_request_id, "apiid": api_id, @@ -941,12 +1163,7 @@ def create_inferred_span_from_http_api_event( InferredSpanInfo.set_tags(tags, tag_source="self", synchronicity="async") else: InferredSpanInfo.set_tags(tags, tag_source="self", synchronicity="sync") - args = { - "service": service_name, - "resource": resource, - "span_type": "http", - } - tracer.set_tags({"_dd.origin": "lambda"}) + tracer.set_tags(_dd_origin) inferred_span_start_ns = request_time_epoch_ms * 1e6 if decode_authorizer_context: injected_authorizer_data = get_injected_authorizer_data(event, True) @@ -954,7 +1171,9 @@ def create_inferred_span_from_http_api_event( inferred_span_start_ns = injected_authorizer_data.get( Headers.Parent_Span_Finish_Time ) - span = tracer.trace("aws.httpapi", **args) + span = tracer.trace( + "aws.httpapi", service=service_name, resource=resource, span_type="http" + ) if span: span.set_tags(tags) span.start_ns = int(inferred_span_start_ns) @@ -968,23 +1187,20 @@ def create_inferred_span_from_sqs_event(event, context): event_source_arn = event_record.get("eventSourceARN") queue_name = event_source_arn.split(":")[-1] service_name = determine_service_name( - service_mapping, queue_name, "lambda_sqs", "sqs" + service_mapping, queue_name, "lambda_sqs", queue_name, "sqs" ) + attrs = event_record.get("attributes") or {} tags = { "operation_name": "aws.sqs", "resource_names": queue_name, + "span.kind": "server", "queuename": queue_name, "event_source_arn": event_source_arn, "receipt_handle": event_record.get("receiptHandle"), - "sender_id": event_record.get("attributes", {}).get("SenderId"), + "sender_id": attrs.get("SenderId"), } InferredSpanInfo.set_tags(tags, tag_source="self", synchronicity="async") - request_time_epoch = event_record.get("attributes", {}).get("SentTimestamp") - args = { - "service": service_name, - "resource": queue_name, - "span_type": "web", - } + request_time_epoch = attrs.get("SentTimestamp") start_time = int(request_time_epoch) / 1000 upstream_span = None @@ -1013,15 +1229,17 @@ def create_inferred_span_from_sqs_event(event, context): except Exception as e: logger.debug( - "Unable to create upstream span from SQS message, with error %s" % e + "Unable to create upstream span from SQS message, with error %s", e ) pass # trace context needs to be set again as it is reset # when sns_span.finish executes tracer.context_provider.activate(trace_ctx) - tracer.set_tags({"_dd.origin": "lambda"}) - span = tracer.trace("aws.sqs", **args) + tracer.set_tags(_dd_origin) + span = tracer.trace( + "aws.sqs", service=service_name, resource=queue_name, span_type="web" + ) if span: span.set_tags(tags) span.start = start_time @@ -1033,15 +1251,16 @@ def create_inferred_span_from_sqs_event(event, context): def create_inferred_span_from_sns_event(event, context): event_record = get_first_record(event) - sns_message = event_record.get("Sns") - topic_arn = event_record.get("Sns", {}).get("TopicArn") + sns_message = event_record.get("Sns") or {} + topic_arn = sns_message.get("TopicArn") topic_name = topic_arn.split(":")[-1] service_name = determine_service_name( - service_mapping, topic_name, "lambda_sns", "sns" + service_mapping, topic_name, "lambda_sns", topic_name, "sns" ) tags = { "operation_name": "aws.sns", "resource_names": topic_name, + "span.kind": "server", "topicname": topic_name, "topic_arn": topic_arn, "message_id": sns_message.get("MessageId"), @@ -1049,21 +1268,19 @@ def create_inferred_span_from_sns_event(event, context): } # Subject not available in SNS => SQS scenario - if "Subject" in sns_message and sns_message["Subject"]: - tags["subject"] = sns_message.get("Subject") + subject = sns_message.get("Subject") + if subject: + tags["subject"] = subject InferredSpanInfo.set_tags(tags, tag_source="self", synchronicity="async") sns_dt_format = "%Y-%m-%dT%H:%M:%S.%fZ" - timestamp = event_record.get("Sns", {}).get("Timestamp") + timestamp = sns_message.get("Timestamp") dt = datetime.strptime(timestamp, sns_dt_format) - args = { - "service": service_name, - "resource": topic_name, - "span_type": "web", - } - tracer.set_tags({"_dd.origin": "lambda"}) - span = tracer.trace("aws.sns", **args) + tracer.set_tags(_dd_origin) + span = tracer.trace( + "aws.sns", service=service_name, resource=topic_name, span_type="web" + ) if span: span.set_tags(tags) span.start = dt.replace(tzinfo=timezone.utc).timestamp() @@ -1074,34 +1291,31 @@ def create_inferred_span_from_kinesis_event(event, context): event_record = get_first_record(event) event_source_arn = event_record.get("eventSourceARN") event_id = event_record.get("eventID") - stream_name = event_source_arn.split(":")[-1] + stream_name = re.sub(r"^stream/", "", (event_source_arn or "").split(":")[-1]) shard_id = event_id.split(":")[0] service_name = determine_service_name( - service_mapping, stream_name, "lambda_kinesis", "kinesis" + service_mapping, stream_name, "lambda_kinesis", stream_name, "kinesis" ) + kinesis = event_record.get("kinesis") or {} tags = { "operation_name": "aws.kinesis", "resource_names": stream_name, + "span.kind": "server", "streamname": stream_name, "shardid": shard_id, "event_source_arn": event_source_arn, "event_id": event_id, "event_name": event_record.get("eventName"), "event_version": event_record.get("eventVersion"), - "partition_key": event_record.get("kinesis", {}).get("partitionKey"), + "partition_key": kinesis.get("partitionKey"), } InferredSpanInfo.set_tags(tags, tag_source="self", synchronicity="async") - request_time_epoch = event_record.get("kinesis", {}).get( - "approximateArrivalTimestamp" - ) + request_time_epoch = kinesis.get("approximateArrivalTimestamp") - args = { - "service": service_name, - "resource": stream_name, - "span_type": "web", - } - tracer.set_tags({"_dd.origin": "lambda"}) - span = tracer.trace("aws.kinesis", **args) + tracer.set_tags(_dd_origin) + span = tracer.trace( + "aws.kinesis", service=service_name, resource=stream_name, span_type="web" + ) if span: span.set_tags(tags) span.start = request_time_epoch @@ -1113,12 +1327,13 @@ def create_inferred_span_from_dynamodb_event(event, context): event_source_arn = event_record.get("eventSourceARN") table_name = event_source_arn.split("/")[1] service_name = determine_service_name( - service_mapping, table_name, "lambda_dynamodb", "dynamodb" + service_mapping, table_name, "lambda_dynamodb", table_name, "dynamodb" ) - dynamodb_message = event_record.get("dynamodb") + dynamodb_message = event_record.get("dynamodb") or {} tags = { "operation_name": "aws.dynamodb", "resource_names": table_name, + "span.kind": "server", "tablename": table_name, "event_source_arn": event_source_arn, "event_id": event_record.get("eventID"), @@ -1128,16 +1343,11 @@ def create_inferred_span_from_dynamodb_event(event, context): "size_bytes": str(dynamodb_message.get("SizeBytes")), } InferredSpanInfo.set_tags(tags, synchronicity="async", tag_source="self") - request_time_epoch = event_record.get("dynamodb", {}).get( - "ApproximateCreationDateTime" + request_time_epoch = dynamodb_message.get("ApproximateCreationDateTime") + tracer.set_tags(_dd_origin) + span = tracer.trace( + "aws.dynamodb", service=service_name, resource=table_name, span_type="web" ) - args = { - "service": service_name, - "resource": table_name, - "span_type": "web", - } - tracer.set_tags({"_dd.origin": "lambda"}) - span = tracer.trace("aws.dynamodb", **args) if span: span.set_tags(tags) @@ -1147,32 +1357,33 @@ def create_inferred_span_from_dynamodb_event(event, context): def create_inferred_span_from_s3_event(event, context): event_record = get_first_record(event) - bucket_name = event_record.get("s3", {}).get("bucket", {}).get("name") + s3 = event_record.get("s3") or {} + bucket = s3.get("bucket") or {} + obj = s3.get("object") or {} + bucket_name = bucket.get("name") service_name = determine_service_name( - service_mapping, bucket_name, "lambda_s3", "s3" + service_mapping, bucket_name, "lambda_s3", bucket_name, "s3" ) tags = { "operation_name": "aws.s3", "resource_names": bucket_name, + "span.kind": "server", "event_name": event_record.get("eventName"), "bucketname": bucket_name, - "bucket_arn": event_record.get("s3", {}).get("bucket", {}).get("arn"), - "object_key": event_record.get("s3", {}).get("object", {}).get("key"), - "object_size": str(event_record.get("s3", {}).get("object", {}).get("size")), - "object_etag": event_record.get("s3", {}).get("object", {}).get("eTag"), + "bucket_arn": bucket.get("arn"), + "object_key": obj.get("key"), + "object_size": str(obj.get("size")), + "object_etag": obj.get("eTag"), } InferredSpanInfo.set_tags(tags, synchronicity="async", tag_source="self") dt_format = "%Y-%m-%dT%H:%M:%S.%fZ" timestamp = event_record.get("eventTime") dt = datetime.strptime(timestamp, dt_format) - args = { - "service": service_name, - "resource": bucket_name, - "span_type": "web", - } - tracer.set_tags({"_dd.origin": "lambda"}) - span = tracer.trace("aws.s3", **args) + tracer.set_tags(_dd_origin) + span = tracer.trace( + "aws.s3", service=service_name, resource=bucket_name, span_type="web" + ) if span: span.set_tags(tags) span.start = dt.replace(tzinfo=timezone.utc).timestamp() @@ -1182,11 +1393,12 @@ def create_inferred_span_from_s3_event(event, context): def create_inferred_span_from_eventbridge_event(event, context): source = event.get("source") service_name = determine_service_name( - service_mapping, source, "lambda_eventbridge", "eventbridge" + service_mapping, source, "lambda_eventbridge", source, "eventbridge" ) tags = { "operation_name": "aws.eventbridge", "resource_names": source, + "span.kind": "server", "detail_type": event.get("detail-type"), } InferredSpanInfo.set_tags( @@ -1194,20 +1406,32 @@ def create_inferred_span_from_eventbridge_event(event, context): synchronicity="async", tag_source="self", ) - dt_format = "%Y-%m-%dT%H:%M:%SZ" + timestamp = event.get("time") + dt_format = "%Y-%m-%dT%H:%M:%SZ" + + # Use more granular timestamp from upstream Step Function if possible + try: + if is_step_function_event(event.get("detail")): + timestamp = event["detail"]["_datadog"]["State"]["EnteredTime"] + dt_format = "%Y-%m-%dT%H:%M:%S.%fZ" + except (TypeError, KeyError, AttributeError): + logger.debug("Error parsing timestamp from Step Functions event") + dt = datetime.strptime(timestamp, dt_format) - args = { - "service": service_name, - "resource": source, - "span_type": "web", - } - tracer.set_tags({"_dd.origin": "lambda"}) - span = tracer.trace("aws.eventbridge", **args) + tracer.set_tags(_dd_origin) + span = tracer.trace( + "aws.eventbridge", service=service_name, resource=source, span_type="web" + ) if span: span.set_tags(tags) span.start = dt.replace(tzinfo=timezone.utc).timestamp() + + # Since inferred span will later parent Lambda, preserve Lambda's current parent + if dd_trace_context.span_id: + span.parent_id = dd_trace_context.span_id + return span @@ -1220,8 +1444,9 @@ def create_function_execution_span( merge_xray_traces, trigger_tags, parent_span=None, + span_pointers=None, ): - tags = {} + tags = None if context: function_arn = (context.invoked_function_arn or "").lower() tk = function_arn.split(":") @@ -1233,29 +1458,51 @@ def create_function_execution_span( "function_version": function_version, "request_id": context.aws_request_id, "resource_names": context.function_name, - "functionname": context.function_name.lower() - if context.function_name - else None, + "functionname": ( + context.function_name.lower() if context.function_name else None + ), "datadog_lambda": datadog_lambda_version, "dd_trace": ddtrace_version, "span.name": "aws.lambda", } + tags = tags or {} if is_proactive_init: tags["proactive_initialization"] = str(is_proactive_init).lower() if trace_context_source == TraceContextSource.XRAY and merge_xray_traces: tags["_dd.parent_source"] = trace_context_source tags.update(trigger_tags) - args = { - "service": "aws.lambda", - "resource": function_name, - "span_type": "serverless", - } - tracer.set_tags({"_dd.origin": "lambda"}) - span = tracer.trace("aws.lambda", **args) + tracer.set_tags(_dd_origin) + # Determine service name based on config and env var + if config.service: + service_name = config.service + else: + aws_service_representation = os.environ.get( + "DD_TRACE_AWS_SERVICE_REPRESENTATION_ENABLED", "" + ).lower() + if aws_service_representation in ("false", "0"): + service_name = "aws.lambda" + else: + service_name = function_name if function_name else "aws.lambda" + + span = tracer.trace( + "aws.lambda", + service=service_name, + resource=function_name, + span_type="serverless", + ) if span: span.set_tags(tags) if parent_span: span.parent_id = parent_span.span_id + if span_pointers: + root_span = parent_span if parent_span else span + for span_pointer_description in span_pointers: + root_span._add_span_pointer( + pointer_kind=span_pointer_description.pointer_kind, + pointer_direction=span_pointer_description.pointer_direction, + pointer_hash=span_pointer_description.pointer_hash, + extra_attributes=span_pointer_description.extra_attributes, + ) return span @@ -1307,3 +1554,34 @@ def is_async(span: Span) -> bool: e, ) return False + + +def emit_telemetry_on_exception_outside_of_handler( + exception, resource_name, handler_load_start_time_ns +): + """ + Emit an enhanced error metric and create a span for exceptions occurring outside the handler + """ + submit_errors_metric(None) + if config.trace_enabled: + span = tracer.trace( + "aws.lambda", + service="aws.lambda", + resource=resource_name, + span_type="serverless", + ) + span.start_ns = handler_load_start_time_ns + + tags = { + "error.status": 500, + "error.type": type(exception).__name__, + "error.message": exception, + "error.stack": traceback.format_exc(), + "resource_names": resource_name, + "resource.name": resource_name, + "operation_name": "aws.lambda", + "status": "error", + } + span.set_tags(tags) + span.error = 1 + span.finish() diff --git a/datadog_lambda/trigger.py b/datadog_lambda/trigger.py index bbb44b30e..e60de8f0c 100644 --- a/datadog_lambda/trigger.py +++ b/datadog_lambda/trigger.py @@ -3,9 +3,8 @@ # This product includes software developed at Datadog (https://www.datadoghq.com/). # Copyright 2019 Datadog, Inc. -import base64 import gzip -import json +import ujson as json from io import BytesIO, BufferedReader from enum import Enum from typing import Any @@ -55,6 +54,10 @@ class EventSubtypes(_stringTypedEnum): WEBSOCKET = "websocket" HTTP_API = "http-api" + ALB = "alb" # regular alb + # ALB with the multi-value headers option checked on the target group + ALB_MULTI_VALUE_HEADERS = "alb-multi-value-headers" + class _EventSource: """ @@ -110,15 +113,19 @@ def get_first_record(event): def parse_event_source(event: dict) -> _EventSource: """Determines the source of the trigger event""" - if type(event) is not dict: + if not isinstance(event, dict): return _EventSource(EventTypes.UNKNOWN) - event_source = _EventSource(EventTypes.UNKNOWN) + event_source = None + # Get requestContext safely and ensure it's a dictionary request_context = event.get("requestContext") + if not isinstance(request_context, dict): + request_context = None + if request_context and request_context.get("stage"): if "domainName" in request_context and detect_lambda_function_url_domain( - request_context.get("domainName") + request_context.get("domainName", "") ): return _EventSource(EventTypes.LAMBDA_FUNCTION_URL) event_source = _EventSource(EventTypes.API_GATEWAY) @@ -126,11 +133,16 @@ def parse_event_source(event: dict) -> _EventSource: event_source.subtype = EventSubtypes.API_GATEWAY if "routeKey" in event: event_source.subtype = EventSubtypes.HTTP_API - if event.get("requestContext", {}).get("messageDirection"): + if request_context.get("messageDirection"): event_source.subtype = EventSubtypes.WEBSOCKET if request_context and request_context.get("elb"): - event_source = _EventSource(EventTypes.ALB) + if "multiValueHeaders" in event: + event_source = _EventSource( + EventTypes.ALB, EventSubtypes.ALB_MULTI_VALUE_HEADERS + ) + else: + event_source = _EventSource(EventTypes.ALB, EventSubtypes.ALB) if event.get("awslogs"): event_source = _EventSource(EventTypes.CLOUDWATCH_LOGS) @@ -146,15 +158,14 @@ def parse_event_source(event: dict) -> _EventSource: if event.get("source") == "aws.events" or has_event_categories: event_source = _EventSource(EventTypes.CLOUDWATCH_EVENTS) - if "Execution" in event and "StateMachine" in event and "State" in event: + if is_step_function_event(event): event_source = _EventSource(EventTypes.STEPFUNCTIONS) event_record = get_first_record(event) - if event_record: - aws_event_source = event_record.get( - "eventSource", event_record.get("EventSource") + if event_record and isinstance(event_record, dict): + aws_event_source = event_record.get("eventSource") or event_record.get( + "EventSource" ) - if aws_event_source == "aws:dynamodb": event_source = _EventSource(EventTypes.DYNAMODB) if aws_event_source == "aws:kinesis": @@ -165,15 +176,16 @@ def parse_event_source(event: dict) -> _EventSource: event_source = _EventSource(EventTypes.SNS) if aws_event_source == "aws:sqs": event_source = _EventSource(EventTypes.SQS) - if event_record.get("cf"): event_source = _EventSource(EventTypes.CLOUDFRONT) - return event_source + return event_source or _EventSource(EventTypes.UNKNOWN) def detect_lambda_function_url_domain(domain: str) -> bool: # e.g. "etsn5fibjr.lambda-url.eu-south-1.amazonaws.com" + if not isinstance(domain, str): + return False domain_parts = domain.split(".") if len(domain_parts) < 2: return False @@ -193,20 +205,26 @@ def parse_event_source_arn(source: _EventSource, event: dict, context: Any) -> s event_record = get_first_record(event) # e.g. arn:aws:s3:::lambda-xyz123-abc890 if source.to_string() == "s3": - return event_record.get("s3", {}).get("bucket", {}).get("arn") + s3 = event_record.get("s3") + if s3: + bucket = s3.get("bucket") + if bucket: + return bucket.get("arn") + return None # e.g. arn:aws:sns:us-east-1:123456789012:sns-lambda if source.to_string() == "sns": - return event_record.get("Sns", {}).get("TopicArn") + sns = event_record.get("Sns") + if sns: + return sns.get("TopicArn") + return None # e.g. arn:aws:cloudfront::123456789012:distribution/ABC123XYZ if source.event_type == EventTypes.CLOUDFRONT: distribution_id = ( event_record.get("cf", {}).get("config", {}).get("distributionId") ) - return "arn:{}:cloudfront::{}:distribution/{}".format( - aws_arn, account_id, distribution_id - ) + return f"arn:{aws_arn}:cloudfront::{account_id}:distribution/{distribution_id}" # e.g. arn:aws:lambda:::url:: if source.equals(EventTypes.LAMBDA_FUNCTION_URL): @@ -223,31 +241,42 @@ def parse_event_source_arn(source: _EventSource, event: dict, context: Any) -> s # e.g. arn:aws:apigateway:us-east-1::/restapis/xyz123/stages/default if source.event_type == EventTypes.API_GATEWAY: request_context = event.get("requestContext") - return "arn:{}:apigateway:{}::/restapis/{}/stages/{}".format( - aws_arn, region, request_context.get("apiId"), request_context.get("stage") - ) + api_id = request_context.get("apiId") + stage = request_context.get("stage") + return f"arn:{aws_arn}:apigateway:{region}::/restapis/{api_id}/stages/{stage}" # e.g. arn:aws:elasticloadbalancing:us-east-1:123456789012:targetgroup/lambda-xyz/123 if source.event_type == EventTypes.ALB: request_context = event.get("requestContext") - return request_context.get("elb", {}).get("targetGroupArn") + if request_context: + elb = request_context.get("elb") + if elb: + return elb.get("targetGroupArn") + return None # e.g. arn:aws:logs:us-west-1:123456789012:log-group:/my-log-group-xyz if source.event_type == EventTypes.CLOUDWATCH_LOGS: + import base64 + with gzip.GzipFile( fileobj=BytesIO(base64.b64decode(event.get("awslogs", {}).get("data"))) ) as decompress_stream: data = b"".join(BufferedReader(decompress_stream)) logs = json.loads(data) log_group = logs.get("logGroup", "cloudwatch") - return "arn:{}:logs:{}:{}:log-group:{}".format( - aws_arn, region, account_id, log_group - ) + return f"arn:{aws_arn}:logs:{region}:{account_id}:log-group:{log_group}" # e.g. arn:aws:events:us-east-1:123456789012:rule/my-schedule if source.event_type == EventTypes.CLOUDWATCH_EVENTS and event.get("resources"): return event.get("resources")[0] + # Returning state machine arn as event source arn. + if source.event_type == EventTypes.STEPFUNCTIONS: + context = event + if "_datadog" in event: + context = event.get("_datadog") + return context.get("StateMachine").get("Id") + def get_event_source_arn(source: _EventSource, event: dict, context: Any) -> str: event_source_arn = event.get("eventSourceARN") or event.get("eventSourceArn") @@ -268,34 +297,67 @@ def extract_http_tags(event): """ Extracts HTTP facet tags from the triggering event """ - http_tags = {} + http_tags = {"span.kind": "server"} + + # Safely get request_context and ensure it's a dictionary request_context = event.get("requestContext") + if not isinstance(request_context, dict): + request_context = None + path = event.get("path") method = event.get("httpMethod") + if request_context and request_context.get("stage"): - if request_context.get("domainName"): - http_tags["http.url"] = request_context.get("domainName") + domain_name = request_context.get("domainName") + if domain_name: + http_tags["http.url"] = f"https://{domain_name}/" path = request_context.get("path") method = request_context.get("httpMethod") + # Version 2.0 HTTP API Gateway - apigateway_v2_http = request_context.get("http") + apigateway_v2_http = request_context.get("http", {}) + if not isinstance(apigateway_v2_http, dict): + apigateway_v2_http = {} + if event.get("version") == "2.0" and apigateway_v2_http: path = apigateway_v2_http.get("path") method = apigateway_v2_http.get("method") if path: - http_tags["http.url_details.path"] = path + if http_tags.get("http.url"): + http_tags["http.url"] += path if method: http_tags["http.method"] = method - headers = event.get("headers") + # Safely get headers + headers = event.get("headers", {}) + if not isinstance(headers, dict): + headers = {} + if headers and headers.get("Referer"): http_tags["http.referer"] = headers.get("Referer") + # Try to get `routeKey` from API GW v2; otherwise try to get `resource` from API GW v1 + route = event.get("routeKey") or event.get("resource") + if route and isinstance(route, str): + try: + # "GET /my/endpoint" = > "/my/endpoint" + http_tags["http.route"] = route.split(" ")[-1] + except Exception: + # If splitting fails, use the route as is + http_tags["http.route"] = route + return http_tags +_http_event_types = ( + EventTypes.API_GATEWAY, + EventTypes.ALB, + EventTypes.LAMBDA_FUNCTION_URL, +) + + def extract_trigger_tags(event: dict, context: Any) -> dict: """ Parses the trigger event object to get tags to be added to the span metadata @@ -309,16 +371,15 @@ def extract_trigger_tags(event: dict, context: Any) -> dict: if event_source_arn: trigger_tags["function_trigger.event_source_arn"] = event_source_arn - if event_source.event_type in [ - EventTypes.API_GATEWAY, - EventTypes.ALB, - EventTypes.LAMBDA_FUNCTION_URL, - ]: + if event_source.event_type in _http_event_types: trigger_tags.update(extract_http_tags(event)) return trigger_tags +_str_http_triggers = [et.value for et in _http_event_types] + + def extract_http_status_code_tag(trigger_tags, response): """ If the Lambda was triggered by API Gateway, Lambda Function URL, or ALB, @@ -329,15 +390,7 @@ def extract_http_status_code_tag(trigger_tags, response): str_event_source = trigger_tags.get("function_trigger.event_source") # it would be cleaner if each event type was a constant object that # knew some properties about itself like this. - str_http_triggers = [ - et.value - for et in [ - EventTypes.API_GATEWAY, - EventTypes.LAMBDA_FUNCTION_URL, - EventTypes.ALB, - ] - ] - if str_event_source not in str_http_triggers: + if str_event_source not in _str_http_triggers: return status_code = "200" @@ -350,3 +403,29 @@ def extract_http_status_code_tag(trigger_tags, response): status_code = response.status_code return str(status_code) + + +def is_step_function_event(event): + """ + Check if the event is a step function that invoked the current lambda. + + The whole event can be wrapped in "Payload" in Legacy Lambda cases. There may also be a + "_datadog" for JSONata style context propagation. + + The actual event must contain "Execution", "StateMachine", and "State" fields. + """ + event = event.get("Payload", event) + + # JSONPath style + if "Execution" in event and "StateMachine" in event and "State" in event: + return True + + # JSONata style + dd_context = event.get("_datadog") + return ( + dd_context + and "Execution" in dd_context + and "StateMachine" in dd_context + and "State" in dd_context + and "serverless-version" in dd_context + ) diff --git a/datadog_lambda/version.py b/datadog_lambda/version.py new file mode 100644 index 000000000..373eef7d0 --- /dev/null +++ b/datadog_lambda/version.py @@ -0,0 +1 @@ +__version__ = "8.117.0.dev0" diff --git a/datadog_lambda/wrapper.py b/datadog_lambda/wrapper.py index 811188486..8dbd7e359 100644 --- a/datadog_lambda/wrapper.py +++ b/datadog_lambda/wrapper.py @@ -2,14 +2,14 @@ # under the Apache License Version 2.0. # This product includes software developed at Datadog (https://www.datadoghq.com/). # Copyright 2019 Datadog, Inc. -import base64 import os import logging import traceback +import ujson as json from importlib import import_module -import json from time import time_ns +from ddtrace.internal._exceptions import BlockingException from datadog_lambda.extension import should_use_extension, flush_extension from datadog_lambda.cold_start import ( set_cold_start, @@ -18,24 +18,19 @@ is_new_sandbox, ColdStartTracer, ) +from datadog_lambda.config import config from datadog_lambda.constants import ( TraceContextSource, XraySubsegment, Headers, - TraceHeader, -) -from datadog_lambda.metric import ( - flush_stats, - submit_invocations_metric, - submit_errors_metric, ) from datadog_lambda.module_name import modify_module_name -from datadog_lambda.patch import patch_all +from datadog_lambda.span_pointers import calculate_span_pointers +from datadog_lambda.tag_object import tag_object from datadog_lambda.tracing import ( extract_dd_trace_context, create_dd_dummy_metadata_subsegment, inject_correlation_ids, - dd_tracing_enabled, mark_trace_as_error_for_5xx_responses, set_correlation_ids, set_dd_trace_py_root, @@ -44,58 +39,46 @@ InferredSpanInfo, is_authorizer_response, tracer, + propagator, ) from datadog_lambda.trigger import ( extract_trigger_tags, extract_http_status_code_tag, ) -profiling_env_var = os.environ.get("DD_PROFILING_ENABLED", "false").lower() == "true" -if profiling_env_var: - from ddtrace.profiling import profiler - -logger = logging.getLogger(__name__) +# ddtrace imports are also tested in +# dd-trace-py/tests/internal/test_serverless.py please update those tests when +# making changes to any ddtrace import. -DD_FLUSH_TO_LOG = "DD_FLUSH_TO_LOG" -DD_LOGS_INJECTION = "DD_LOGS_INJECTION" -DD_MERGE_XRAY_TRACES = "DD_MERGE_XRAY_TRACES" -AWS_LAMBDA_FUNCTION_NAME = "AWS_LAMBDA_FUNCTION_NAME" -DD_TRACE_EXTRACTOR = "DD_TRACE_EXTRACTOR" -DD_TRACE_MANAGED_SERVICES = "DD_TRACE_MANAGED_SERVICES" -DD_ENCODE_AUTHORIZER_CONTEXT = "DD_ENCODE_AUTHORIZER_CONTEXT" -DD_DECODE_AUTHORIZER_CONTEXT = "DD_DECODE_AUTHORIZER_CONTEXT" -DD_COLD_START_TRACING = "DD_COLD_START_TRACING" -DD_MIN_COLD_START_DURATION = "DD_MIN_COLD_START_DURATION" -DD_COLD_START_TRACE_SKIP_LIB = "DD_COLD_START_TRACE_SKIP_LIB" -DD_CAPTURE_LAMBDA_PAYLOAD = "DD_CAPTURE_LAMBDA_PAYLOAD" -DD_CAPTURE_LAMBDA_PAYLOAD_MAX_DEPTH = "DD_CAPTURE_LAMBDA_PAYLOAD_MAX_DEPTH" -DD_REQUESTS_SERVICE_NAME = "DD_REQUESTS_SERVICE_NAME" -DD_SERVICE = "DD_SERVICE" -DD_ENV = "DD_ENV" +if config.appsec_enabled: + from datadog_lambda.asm import ( + asm_set_context, + asm_start_response, + asm_start_request, + get_asm_blocked_response, + ) + from ddtrace.internal.appsec.product import start + start() -def get_env_as_int(env_key, default_value: int) -> int: - try: - return int(os.environ.get(env_key, default_value)) - except Exception as e: - logger.warn( - f"Failed to parse {env_key} as int. Using default value: {default_value}. Error: {e}" - ) - return default_value +if config.profiling_enabled: + from ddtrace.profiling import profiler +if config.llmobs_enabled: + from ddtrace.llmobs import LLMObs -dd_capture_lambda_payload_enabled = ( - os.environ.get(DD_CAPTURE_LAMBDA_PAYLOAD, "false").lower() == "true" -) +if config.exception_replay_enabled: + from ddtrace.debugging._exception.replay import SpanExceptionHandler -if dd_capture_lambda_payload_enabled: - import datadog_lambda.tag_object as tag_object + try: + from ddtrace.debugging._uploader import SignalUploader + except ImportError: + from ddtrace.debugging._uploader import LogsIntakeUploaderV1 as SignalUploader - tag_object.max_depth = get_env_as_int( - DD_CAPTURE_LAMBDA_PAYLOAD_MAX_DEPTH, tag_object.max_depth - ) +logger = logging.getLogger(__name__) -env_env_var = os.environ.get(DD_ENV, None) +DD_REQUESTS_SERVICE_NAME = "DD_REQUESTS_SERVICE_NAME" +DD_SERVICE = "DD_SERVICE" init_timestamp_ns = time_ns() @@ -152,53 +135,17 @@ def __init__(self, func): """Executes when the wrapped function gets wrapped""" try: self.func = func - self.flush_to_log = os.environ.get(DD_FLUSH_TO_LOG, "").lower() == "true" - self.logs_injection = ( - os.environ.get(DD_LOGS_INJECTION, "true").lower() == "true" - ) - self.merge_xray_traces = ( - os.environ.get(DD_MERGE_XRAY_TRACES, "false").lower() == "true" - ) - self.function_name = os.environ.get(AWS_LAMBDA_FUNCTION_NAME, "function") - self.service = os.environ.get(DD_SERVICE, None) - self.extractor_env = os.environ.get(DD_TRACE_EXTRACTOR, None) self.trace_extractor = None self.span = None self.inferred_span = None - depends_on_dd_tracing_enabled = ( - lambda original_boolean: dd_tracing_enabled and original_boolean - ) - self.make_inferred_span = depends_on_dd_tracing_enabled( - os.environ.get(DD_TRACE_MANAGED_SERVICES, "true").lower() == "true" - ) - self.encode_authorizer_context = depends_on_dd_tracing_enabled( - os.environ.get(DD_ENCODE_AUTHORIZER_CONTEXT, "true").lower() == "true" - ) - self.decode_authorizer_context = depends_on_dd_tracing_enabled( - os.environ.get(DD_DECODE_AUTHORIZER_CONTEXT, "true").lower() == "true" - ) - self.cold_start_tracing = depends_on_dd_tracing_enabled( - os.environ.get(DD_COLD_START_TRACING, "true").lower() == "true" - ) - self.min_cold_start_trace_duration = get_env_as_int( - DD_MIN_COLD_START_DURATION, 3 - ) - self.cold_start_trace_skip_lib = [ - "ddtrace.internal.compat", - "ddtrace.filters", - ] - if DD_COLD_START_TRACE_SKIP_LIB in os.environ: - try: - self.cold_start_trace_skip_lib = os.environ[ - DD_COLD_START_TRACE_SKIP_LIB - ].split(",") - except Exception: - logger.debug(f"Malformatted for env {DD_COLD_START_TRACE_SKIP_LIB}") self.response = None - if profiling_env_var: - self.prof = profiler.Profiler(env=env_env_var, service=self.service) - if self.extractor_env: - extractor_parts = self.extractor_env.rsplit(".", 1) + self.blocking_response = None + + if config.profiling_enabled: + self.prof = profiler.Profiler(env=config.env, service=config.service) + + if config.trace_extractor: + extractor_parts = config.trace_extractor.rsplit(".", 1) if len(extractor_parts) == 2: (mod_name, extractor_name) = extractor_parts modified_extractor_name = modify_module_name(mod_name) @@ -206,7 +153,7 @@ def __init__(self, func): self.trace_extractor = getattr(extractor_module, extractor_name) # Inject trace correlation ids to logs - if self.logs_injection: + if config.logs_injection: inject_correlation_ids() # This prevents a breaking change in ddtrace v0.49 regarding the service name @@ -214,8 +161,15 @@ def __init__(self, func): os.environ[DD_REQUESTS_SERVICE_NAME] = os.environ.get( DD_SERVICE, "aws.lambda" ) - # Patch third-party libraries for tracing - patch_all() + + # Enable LLM Observability + if config.llmobs_enabled: + LLMObs.enable() + + # Enable Exception Replay + if config.exception_replay_enabled: + logger.debug("Enabling exception replay") + SpanExceptionHandler.enable() logger.debug("datadog_lambda_wrapper initialized") except Exception as e: @@ -225,15 +179,24 @@ def __call__(self, event, context, **kwargs): """Executes when the wrapped function gets called""" self._before(event, context) try: + if self.blocking_response: + return self.blocking_response self.response = self.func(event, context, **kwargs) return self.response + except BlockingException: + self.blocking_response = get_asm_blocked_response(self.event_source) except Exception: + from datadog_lambda.metric import submit_errors_metric + submit_errors_metric(context) + if self.span: self.span.set_traceback() raise finally: self._after(event, context) + if self.blocking_response: + return self.blocking_response def _inject_authorizer_span_headers(self, request_id): reference_span = self.inferred_span if self.inferred_span else self.span @@ -250,59 +213,77 @@ def _inject_authorizer_span_headers(self, request_id): injected_headers = {} source_span = self.inferred_span if self.inferred_span else self.span span_context = source_span.context - injected_headers[TraceHeader.TRACE_ID] = str(span_context.trace_id) - injected_headers[TraceHeader.PARENT_ID] = str(span_context.span_id) - sampling_priority = span_context.sampling_priority - if sampling_priority is not None: - injected_headers[TraceHeader.SAMPLING_PRIORITY] = str( - span_context.sampling_priority - ) + propagator.inject(span_context, injected_headers) injected_headers[Headers.Parent_Span_Finish_Time] = finish_time_ns if request_id is not None: injected_headers[Headers.Authorizing_Request_Id] = request_id - datadog_data = base64.b64encode(json.dumps(injected_headers).encode()).decode() + + import base64 + + datadog_data = base64.b64encode( + json.dumps(injected_headers, escape_forward_slashes=False).encode() + ).decode() self.response.setdefault("context", {}) self.response["context"]["_datadog"] = datadog_data def _before(self, event, context): try: self.response = None + self.blocking_response = None set_cold_start(init_timestamp_ns) - submit_invocations_metric(context) + + if not should_use_extension: + from datadog_lambda.metric import submit_invocations_metric + + submit_invocations_metric(context) + self.trigger_tags = extract_trigger_tags(event, context) # Extract Datadog trace context and source from incoming requests dd_context, trace_context_source, event_source = extract_dd_trace_context( event, context, extractor=self.trace_extractor, - decode_authorizer_context=self.decode_authorizer_context, + decode_authorizer_context=config.decode_authorizer_context, ) self.event_source = event_source # Create a Datadog X-Ray subsegment with the trace context if dd_context and trace_context_source == TraceContextSource.EVENT: create_dd_dummy_metadata_subsegment( - dd_context, XraySubsegment.TRACE_KEY + { + "trace-id": str(dd_context.trace_id), + "parent-id": str(dd_context.span_id), + "sampling-priority": str(dd_context.sampling_priority), + }, + XraySubsegment.TRACE_KEY, ) - if dd_tracing_enabled: - set_dd_trace_py_root(trace_context_source, self.merge_xray_traces) - if self.make_inferred_span: + if config.trace_enabled: + set_dd_trace_py_root(trace_context_source, config.merge_xray_traces) + if config.make_inferred_span: self.inferred_span = create_inferred_span( - event, context, event_source, self.decode_authorizer_context + event, context, event_source, config.decode_authorizer_context ) + + if config.appsec_enabled: + asm_set_context(event_source) + self.span = create_function_execution_span( - context, - self.function_name, - is_cold_start(), - is_proactive_init(), - trace_context_source, - self.merge_xray_traces, - self.trigger_tags, + context=context, + function_name=config.function_name, + is_cold_start=is_cold_start(), + is_proactive_init=is_proactive_init(), + trace_context_source=trace_context_source, + merge_xray_traces=config.merge_xray_traces, + trigger_tags=self.trigger_tags, parent_span=self.inferred_span, + span_pointers=calculate_span_pointers(event_source, event), ) + if config.appsec_enabled: + asm_start_request(self.span, event, event_source, self.trigger_tags) + self.blocking_response = get_asm_blocked_response(self.event_source) else: set_correlation_ids() - if profiling_env_var and is_new_sandbox(): + if config.profiling_enabled and is_new_sandbox(): self.prof.start(stop_on_exit=False, profile_children=True) logger.debug("datadog_lambda_wrapper _before() done") except Exception as e: @@ -310,7 +291,39 @@ def _before(self, event, context): def _after(self, event, context): try: + from datadog_lambda.metric import submit_batch_item_failures_metric + + submit_batch_item_failures_metric(self.response, context) + status_code = extract_http_status_code_tag(self.trigger_tags, self.response) + + if self.span: + if config.appsec_enabled and not self.blocking_response: + asm_start_response( + self.span, + status_code, + self.event_source, + response=self.response, + ) + self.blocking_response = get_asm_blocked_response(self.event_source) + + if self.blocking_response: + status_code = str(self.blocking_response.get("statusCode")) + if config.capture_payload_enabled and self.response: + tag_object( + self.span, "function.blocked_response", self.response + ) + self.response = self.blocking_response + + if config.capture_payload_enabled: + tag_object(self.span, "function.request", event) + tag_object(self.span, "function.response", self.response) + + if status_code: + self.span.set_tag("http.status_code", status_code) + + self.span.finish() + if status_code: self.trigger_tags["http.status_code"] = status_code mark_trace_as_error_for_5xx_responses(context, status_code, self.span) @@ -321,25 +334,19 @@ def _after(self, event, context): create_dd_dummy_metadata_subsegment( self.trigger_tags, XraySubsegment.LAMBDA_FUNCTION_TAGS_KEY ) - should_trace_cold_start = self.cold_start_tracing and is_new_sandbox() + should_trace_cold_start = config.cold_start_tracing and is_new_sandbox() if should_trace_cold_start: trace_ctx = tracer.current_trace_context() - if self.span: - if dd_capture_lambda_payload_enabled: - tag_object.tag_object(self.span, "function.request", event) - tag_object.tag_object(self.span, "function.response", self.response) - - if status_code: - self.span.set_tag("http.status_code", status_code) - self.span.finish() - if self.inferred_span: if status_code: self.inferred_span.set_tag("http.status_code", status_code) - if self.service: - self.inferred_span.set_tag("peer.service", self.service) + if self.trigger_tags and (route := self.trigger_tags.get("http.route")): + self.inferred_span.set_tag("http.route", route) + + if config.service: + self.inferred_span.set_tag("peer.service", config.service) if InferredSpanInfo.is_async(self.inferred_span) and self.span: self.inferred_span.finish(finish_time=self.span.start) @@ -351,21 +358,35 @@ def _after(self, event, context): following_span = self.span or self.inferred_span ColdStartTracer( tracer, - self.function_name, + config.function_name, following_span.start_ns, trace_ctx, - self.min_cold_start_trace_duration, - self.cold_start_trace_skip_lib, + config.min_cold_start_trace_duration, + config.cold_start_trace_skip_lib, ).trace() except Exception as e: logger.debug("Failed to create cold start spans. %s", e) - if not self.flush_to_log or should_use_extension: - flush_stats() - if should_use_extension: + if not config.flush_to_log or should_use_extension: + from datadog_lambda.metric import flush_stats + + flush_stats(context) + if should_use_extension and config.local_test: + # when testing locally, the extension does not know when an + # invocation completes because it does not have access to the + # logs api flush_extension() - if self.encode_authorizer_context and is_authorizer_response(self.response): + if config.llmobs_enabled: + LLMObs.flush() + + # Flush exception replay + if config.exception_replay_enabled: + SignalUploader._instance.periodic() + + if config.encode_authorizer_context and is_authorizer_response( + self.response + ): self._inject_authorizer_span_headers( event.get("requestContext", {}).get("requestId") ) @@ -375,9 +396,8 @@ def _after(self, event, context): def format_err_with_traceback(e): - return "Error {}. Traceback: {}".format( - e, traceback.format_exc().replace("\n", "\r") - ) + tb = traceback.format_exc().replace("\n", "\r") + return f"Error {e}. Traceback: {tb}" datadog_lambda_wrapper = _LambdaDecorator diff --git a/datadog_lambda/xray.py b/datadog_lambda/xray.py index 88d108f56..002d13b19 100644 --- a/datadog_lambda/xray.py +++ b/datadog_lambda/xray.py @@ -1,47 +1,60 @@ import os import logging -import json import binascii import time import socket +import ujson as json from datadog_lambda.constants import XrayDaemon, XraySubsegment, TraceContextSource logger = logging.getLogger(__name__) -def get_xray_host_port(address): - if address == "": - logger.debug("X-Ray daemon env var not set, not sending sub-segment") - return None - parts = address.split(":") - if len(parts) <= 1: - logger.debug("X-Ray daemon env var not set, not sending sub-segment") - return None - port = int(parts[1]) - host = parts[0] - return (host, port) - - -def send(host_port_tuple, payload): - sock = None - try: - sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - sock.setblocking(0) - sock.connect(host_port_tuple) - sock.send(payload.encode("utf-8")) - except Exception as e_send: - logger.error("Error occurred submitting to xray daemon: %s", str(e_send)) - try: - sock.close() - except Exception as e_close: - logger.error("Error while closing the socket: %s", str(e_close)) +class Socket(object): + def __init__(self): + self.sock = None + + @property + def host_port_tuple(self): + if not hasattr(self, "_host_port_tuple"): + self._host_port_tuple = self._get_xray_host_port( + os.environ.get(XrayDaemon.XRAY_DAEMON_ADDRESS, "") + ) + return self._host_port_tuple + + def send(self, payload): + if not self.sock: + self._connect() + try: + self.sock.send(payload.encode("utf-8")) + except Exception as e_send: + logger.error("Error occurred submitting to xray daemon: %s", e_send) + + def _connect(self): + self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + self.sock.setblocking(0) + self.sock.connect(self.host_port_tuple) + + def _get_xray_host_port(self, address): + if address == "": + logger.debug("X-Ray daemon env var not set, not sending sub-segment") + return None + parts = address.split(":") + if len(parts) <= 1: + logger.debug("X-Ray daemon env var not set, not sending sub-segment") + return None + port = int(parts[1]) + host = parts[0] + return (host, port) + + +sock = Socket() def build_segment_payload(payload): if payload is None: return None - return '{"format": "json", "version": 1}' + "\n" + payload + return '{"format": "json", "version": 1}\n' + payload def parse_xray_header(raw_trace_id): @@ -89,16 +102,14 @@ def build_segment(context, key, metadata): key: metadata, } }, - } + }, + escape_forward_slashes=False, ) return segment def send_segment(key, metadata): - host_port_tuple = get_xray_host_port( - os.environ.get(XrayDaemon.XRAY_DAEMON_ADDRESS, "") - ) - if host_port_tuple is None: + if sock.host_port_tuple is None: return None context = parse_xray_header( os.environ.get(XrayDaemon.XRAY_TRACE_ID_HEADER_NAME, "") @@ -115,4 +126,4 @@ def send_segment(key, metadata): return None segment = build_segment(context, key, metadata) segment_payload = build_segment_payload(segment) - send(host_port_tuple, segment_payload) + sock.send(segment_payload) diff --git a/poetry.lock b/poetry.lock index c32c4c691..4c37bf871 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,54 +1,16 @@ -# This file is automatically @generated by Poetry 1.5.0 and should not be changed by hand. - -[[package]] -name = "attrs" -version = "23.1.0" -description = "Classes Without Boilerplate" -optional = false -python-versions = ">=3.7" -files = [ - {file = "attrs-23.1.0-py3-none-any.whl", hash = "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04"}, - {file = "attrs-23.1.0.tar.gz", hash = "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"}, -] - -[package.dependencies] -importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} - -[package.extras] -cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] -dev = ["attrs[docs,tests]", "pre-commit"] -docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] -tests = ["attrs[tests-no-zope]", "zope-interface"] -tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] - -[[package]] -name = "boto3" -version = "1.29.5" -description = "The AWS SDK for Python" -optional = true -python-versions = ">= 3.7" -files = [ - {file = "boto3-1.29.5-py3-none-any.whl", hash = "sha256:030b0f0faf8d44f97e67a5411644243482f33ebf1c45338bb40662239a16dda4"}, - {file = "boto3-1.29.5.tar.gz", hash = "sha256:76fc6a17781c27558c526e899579ccf530df10eb279261fe7800540f0043917e"}, -] - -[package.dependencies] -botocore = ">=1.32.5,<1.33.0" -jmespath = ">=0.7.1,<2.0.0" -s3transfer = ">=0.7.0,<0.8.0" - -[package.extras] -crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] +# This file is automatically @generated by Poetry 2.1.1 and should not be changed by hand. [[package]] name = "botocore" -version = "1.32.5" +version = "1.36.8" description = "Low-level, data-driven core of boto 3." optional = true -python-versions = ">= 3.7" +python-versions = ">=3.8" +groups = ["main"] +markers = "extra == \"dev\"" files = [ - {file = "botocore-1.32.5-py3-none-any.whl", hash = "sha256:b8960c955ba275915bf022c54c896c2dac1038289d8a5ace92d1431257c0a439"}, - {file = "botocore-1.32.5.tar.gz", hash = "sha256:75a68f942cd87baff83b3a20dfda11b3aeda48aad32e4dcd6fe8992c0cb0e7db"}, + {file = "botocore-1.36.8-py3-none-any.whl", hash = "sha256:59d3fdfbae6d916b046e973bebcbeb70a102f9e570ca86d5ba512f1854b78fc2"}, + {file = "botocore-1.36.8.tar.gz", hash = "sha256:81c88e5566cf018e1411a68304dc1fb9e4156ca2b50a3a0f0befc274299e67fa"}, ] [package.dependencies] @@ -56,388 +18,294 @@ jmespath = ">=0.7.1,<2.0.0" python-dateutil = ">=2.1,<3.0.0" urllib3 = [ {version = ">=1.25.4,<1.27", markers = "python_version < \"3.10\""}, - {version = ">=1.25.4,<2.1", markers = "python_version >= \"3.10\""}, + {version = ">=1.25.4,<2.2.0 || >2.2.0,<3", markers = "python_version >= \"3.10\""}, ] [package.extras] -crt = ["awscrt (==0.19.12)"] +crt = ["awscrt (==0.23.4)"] [[package]] name = "bytecode" -version = "0.13.0" -description = "Python module to generate and modify bytecode" -optional = false -python-versions = ">=3.6" -files = [ - {file = "bytecode-0.13.0-py3-none-any.whl", hash = "sha256:e69f92e7d27f99d5d7d76e6a824bd3d9ff857c72b59927aaf87e1a620f67fe50"}, - {file = "bytecode-0.13.0.tar.gz", hash = "sha256:6af3c2f0a31ce05dce41f7eea5cc380e33f5e8fbb7dcee3b52467a00acd52fcd"}, -] - -[[package]] -name = "bytecode" -version = "0.15.1" +version = "0.16.1" description = "Python module to generate and modify bytecode" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ - {file = "bytecode-0.15.1-py3-none-any.whl", hash = "sha256:0a1dc340cac823cff605609b8b214f7f9bf80418c6b9e0fc8c6db1793c27137d"}, - {file = "bytecode-0.15.1.tar.gz", hash = "sha256:7263239a8d3f70fc7c303862b20cd2c6788052e37ce0a26e67309d280e985984"}, + {file = "bytecode-0.16.1-py3-none-any.whl", hash = "sha256:1d4b61ed6bade4bff44127c8283bef8131a664ce4dbe09d64a88caf329939f35"}, + {file = "bytecode-0.16.1.tar.gz", hash = "sha256:8fbbb637c880f339e564858bc6c7984ede67ae97bc71343379a535a9a4baf398"}, ] [package.dependencies] -typing-extensions = {version = "*", markers = "python_version < \"3.10\""} - -[[package]] -name = "cattrs" -version = "23.1.2" -description = "Composable complex class support for attrs and dataclasses." -optional = false -python-versions = ">=3.7" -files = [ - {file = "cattrs-23.1.2-py3-none-any.whl", hash = "sha256:b2bb14311ac17bed0d58785e5a60f022e5431aca3932e3fc5cc8ed8639de50a4"}, - {file = "cattrs-23.1.2.tar.gz", hash = "sha256:db1c821b8c537382b2c7c66678c3790091ca0275ac486c76f3c8f3920e83c657"}, -] - -[package.dependencies] -attrs = ">=20" -exceptiongroup = {version = "*", markers = "python_version < \"3.11\""} -typing_extensions = {version = ">=4.1.0", markers = "python_version < \"3.11\""} - -[package.extras] -bson = ["pymongo (>=4.2.0,<5.0.0)"] -cbor2 = ["cbor2 (>=5.4.6,<6.0.0)"] -msgpack = ["msgpack (>=1.0.2,<2.0.0)"] -orjson = ["orjson (>=3.5.2,<4.0.0)"] -pyyaml = ["PyYAML (>=6.0,<7.0)"] -tomlkit = ["tomlkit (>=0.11.4,<0.12.0)"] -ujson = ["ujson (>=5.4.0,<6.0.0)"] +typing_extensions = {version = "*", markers = "python_version < \"3.10\""} [[package]] name = "certifi" -version = "2023.11.17" +version = "2024.12.14" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" +groups = ["main"] files = [ - {file = "certifi-2023.11.17-py3-none-any.whl", hash = "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474"}, - {file = "certifi-2023.11.17.tar.gz", hash = "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1"}, + {file = "certifi-2024.12.14-py3-none-any.whl", hash = "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56"}, + {file = "certifi-2024.12.14.tar.gz", hash = "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db"}, ] [[package]] name = "charset-normalizer" -version = "3.3.2" +version = "3.4.1" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false -python-versions = ">=3.7.0" -files = [ - {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, - {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, -] - -[[package]] -name = "coverage" -version = "7.2.7" -description = "Code coverage measurement for Python" -optional = true python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "charset_normalizer-3.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e218488cd232553829be0664c2292d3af2eeeb94b32bea483cf79ac6a694e037"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:80ed5e856eb7f30115aaf94e4a08114ccc8813e6ed1b5efa74f9f82e8509858f"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b010a7a4fd316c3c484d482922d13044979e78d1861f0e0650423144c616a46a"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4532bff1b8421fd0a320463030c7520f56a79c9024a4e88f01c537316019005a"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d973f03c0cb71c5ed99037b870f2be986c3c05e63622c017ea9816881d2dd247"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3a3bd0dcd373514dcec91c411ddb9632c0d7d92aed7093b8c3bbb6d69ca74408"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:d9c3cdf5390dcd29aa8056d13e8e99526cda0305acc038b96b30352aff5ff2bb"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2bdfe3ac2e1bbe5b59a1a63721eb3b95fc9b6817ae4a46debbb4e11f6232428d"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:eab677309cdb30d047996b36d34caeda1dc91149e4fdca0b1a039b3f79d9a807"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-win32.whl", hash = "sha256:c0429126cf75e16c4f0ad00ee0eae4242dc652290f940152ca8c75c3a4b6ee8f"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:9f0b8b1c6d84c8034a44893aba5e767bf9c7a211e313a9605d9c617d7083829f"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-win32.whl", hash = "sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-win32.whl", hash = "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-win32.whl", hash = "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f30bf9fd9be89ecb2360c7d94a711f00c09b976258846efe40db3d05828e8089"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:97f68b8d6831127e4787ad15e6757232e14e12060bec17091b85eb1486b91d8d"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7974a0b5ecd505609e3b19742b60cee7aa2aa2fb3151bc917e6e2646d7667dcf"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc54db6c8593ef7d4b2a331b58653356cf04f67c960f584edb7c3d8c97e8f39e"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:311f30128d7d333eebd7896965bfcfbd0065f1716ec92bd5638d7748eb6f936a"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:7d053096f67cd1241601111b698f5cad775f97ab25d81567d3f59219b5f1adbd"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:807f52c1f798eef6cf26beb819eeb8819b1622ddfeef9d0977a8502d4db6d534"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:dccbe65bd2f7f7ec22c4ff99ed56faa1e9f785482b9bbd7c717e26fd723a1d1e"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:2fb9bd477fdea8684f78791a6de97a953c51831ee2981f8e4f583ff3b9d9687e"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:01732659ba9b5b873fc117534143e4feefecf3b2078b0a6a2e925271bb6f4cfa"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-win32.whl", hash = "sha256:7a4f97a081603d2050bfaffdefa5b02a9ec823f8348a572e39032caa8404a487"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:7b1bef6280950ee6c177b326508f86cad7ad4dff12454483b51d8b7d673a2c5d"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ecddf25bee22fe4fe3737a399d0d177d72bc22be6913acfab364b40bce1ba83c"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c60ca7339acd497a55b0ea5d506b2a2612afb2826560416f6894e8b5770d4a9"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b7b2d86dd06bfc2ade3312a83a5c364c7ec2e3498f8734282c6c3d4b07b346b8"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dd78cfcda14a1ef52584dbb008f7ac81c1328c0f58184bf9a84c49c605002da6"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e27f48bcd0957c6d4cb9d6fa6b61d192d0b13d5ef563e5f2ae35feafc0d179c"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01ad647cdd609225c5350561d084b42ddf732f4eeefe6e678765636791e78b9a"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:619a609aa74ae43d90ed2e89bdd784765de0a25ca761b93e196d938b8fd1dbbd"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:89149166622f4db9b4b6a449256291dc87a99ee53151c74cbd82a53c8c2f6ccd"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:7709f51f5f7c853f0fb938bcd3bc59cdfdc5203635ffd18bf354f6967ea0f824"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:345b0426edd4e18138d6528aed636de7a9ed169b4aaf9d61a8c19e39d26838ca"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0907f11d019260cdc3f94fbdb23ff9125f6b5d1039b76003b5b0ac9d6a6c9d5b"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-win32.whl", hash = "sha256:ea0d8d539afa5eb2728aa1932a988a9a7af94f18582ffae4bc10b3fbdad0626e"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:329ce159e82018d646c7ac45b01a430369d526569ec08516081727a20e9e4af4"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b97e690a2118911e39b4042088092771b4ae3fc3aa86518f84b8cf6888dbdb41"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78baa6d91634dfb69ec52a463534bc0df05dbd546209b79a3880a34487f4b84f"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1a2bc9f351a75ef49d664206d51f8e5ede9da246602dc2d2726837620ea034b2"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75832c08354f595c760a804588b9357d34ec00ba1c940c15e31e96d902093770"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0af291f4fe114be0280cdd29d533696a77b5b49cfde5467176ecab32353395c4"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0167ddc8ab6508fe81860a57dd472b2ef4060e8d378f0cc555707126830f2537"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2a75d49014d118e4198bcee5ee0a6f25856b29b12dbf7cd012791f8a6cc5c496"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:363e2f92b0f0174b2f8238240a1a30142e3db7b957a5dd5689b0e75fb717cc78"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ab36c8eb7e454e34e60eb55ca5d241a5d18b2c6244f6827a30e451c42410b5f7"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:4c0907b1928a36d5a998d72d64d8eaa7244989f7aaaf947500d3a800c83a3fd6"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:04432ad9479fa40ec0f387795ddad4437a2b50417c69fa275e212933519ff294"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-win32.whl", hash = "sha256:3bed14e9c89dcb10e8f3a29f9ccac4955aebe93c71ae803af79265c9ca5644c5"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:49402233c892a461407c512a19435d1ce275543138294f7ef013f0b63d5d3765"}, + {file = "charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85"}, + {file = "charset_normalizer-3.4.1.tar.gz", hash = "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3"}, +] + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = true +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["main"] +markers = "extra == \"dev\" and sys_platform == \"win32\"" files = [ - {file = "coverage-7.2.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d39b5b4f2a66ccae8b7263ac3c8170994b65266797fb96cbbfd3fb5b23921db8"}, - {file = "coverage-7.2.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6d040ef7c9859bb11dfeb056ff5b3872436e3b5e401817d87a31e1750b9ae2fb"}, - {file = "coverage-7.2.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba90a9563ba44a72fda2e85302c3abc71c5589cea608ca16c22b9804262aaeb6"}, - {file = "coverage-7.2.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7d9405291c6928619403db1d10bd07888888ec1abcbd9748fdaa971d7d661b2"}, - {file = "coverage-7.2.7-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31563e97dae5598556600466ad9beea39fb04e0229e61c12eaa206e0aa202063"}, - {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ebba1cd308ef115925421d3e6a586e655ca5a77b5bf41e02eb0e4562a111f2d1"}, - {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:cb017fd1b2603ef59e374ba2063f593abe0fc45f2ad9abdde5b4d83bd922a353"}, - {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d62a5c7dad11015c66fbb9d881bc4caa5b12f16292f857842d9d1871595f4495"}, - {file = "coverage-7.2.7-cp310-cp310-win32.whl", hash = "sha256:ee57190f24fba796e36bb6d3aa8a8783c643d8fa9760c89f7a98ab5455fbf818"}, - {file = "coverage-7.2.7-cp310-cp310-win_amd64.whl", hash = "sha256:f75f7168ab25dd93110c8a8117a22450c19976afbc44234cbf71481094c1b850"}, - {file = "coverage-7.2.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:06a9a2be0b5b576c3f18f1a241f0473575c4a26021b52b2a85263a00f034d51f"}, - {file = "coverage-7.2.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5baa06420f837184130752b7c5ea0808762083bf3487b5038d68b012e5937dbe"}, - {file = "coverage-7.2.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdec9e8cbf13a5bf63290fc6013d216a4c7232efb51548594ca3631a7f13c3a3"}, - {file = "coverage-7.2.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:52edc1a60c0d34afa421c9c37078817b2e67a392cab17d97283b64c5833f427f"}, - {file = "coverage-7.2.7-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63426706118b7f5cf6bb6c895dc215d8a418d5952544042c8a2d9fe87fcf09cb"}, - {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:afb17f84d56068a7c29f5fa37bfd38d5aba69e3304af08ee94da8ed5b0865833"}, - {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:48c19d2159d433ccc99e729ceae7d5293fbffa0bdb94952d3579983d1c8c9d97"}, - {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0e1f928eaf5469c11e886fe0885ad2bf1ec606434e79842a879277895a50942a"}, - {file = "coverage-7.2.7-cp311-cp311-win32.whl", hash = "sha256:33d6d3ea29d5b3a1a632b3c4e4f4ecae24ef170b0b9ee493883f2df10039959a"}, - {file = "coverage-7.2.7-cp311-cp311-win_amd64.whl", hash = "sha256:5b7540161790b2f28143191f5f8ec02fb132660ff175b7747b95dcb77ac26562"}, - {file = "coverage-7.2.7-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f2f67fe12b22cd130d34d0ef79206061bfb5eda52feb6ce0dba0644e20a03cf4"}, - {file = "coverage-7.2.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a342242fe22407f3c17f4b499276a02b01e80f861f1682ad1d95b04018e0c0d4"}, - {file = "coverage-7.2.7-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:171717c7cb6b453aebac9a2ef603699da237f341b38eebfee9be75d27dc38e01"}, - {file = "coverage-7.2.7-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49969a9f7ffa086d973d91cec8d2e31080436ef0fb4a359cae927e742abfaaa6"}, - {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b46517c02ccd08092f4fa99f24c3b83d8f92f739b4657b0f146246a0ca6a831d"}, - {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:a3d33a6b3eae87ceaefa91ffdc130b5e8536182cd6dfdbfc1aa56b46ff8c86de"}, - {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:976b9c42fb2a43ebf304fa7d4a310e5f16cc99992f33eced91ef6f908bd8f33d"}, - {file = "coverage-7.2.7-cp312-cp312-win32.whl", hash = "sha256:8de8bb0e5ad103888d65abef8bca41ab93721647590a3f740100cd65c3b00511"}, - {file = "coverage-7.2.7-cp312-cp312-win_amd64.whl", hash = "sha256:9e31cb64d7de6b6f09702bb27c02d1904b3aebfca610c12772452c4e6c21a0d3"}, - {file = "coverage-7.2.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:58c2ccc2f00ecb51253cbe5d8d7122a34590fac9646a960d1430d5b15321d95f"}, - {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d22656368f0e6189e24722214ed8d66b8022db19d182927b9a248a2a8a2f67eb"}, - {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a895fcc7b15c3fc72beb43cdcbdf0ddb7d2ebc959edac9cef390b0d14f39f8a9"}, - {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e84606b74eb7de6ff581a7915e2dab7a28a0517fbe1c9239eb227e1354064dcd"}, - {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:0a5f9e1dbd7fbe30196578ca36f3fba75376fb99888c395c5880b355e2875f8a"}, - {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:419bfd2caae268623dd469eff96d510a920c90928b60f2073d79f8fe2bbc5959"}, - {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2aee274c46590717f38ae5e4650988d1af340fe06167546cc32fe2f58ed05b02"}, - {file = "coverage-7.2.7-cp37-cp37m-win32.whl", hash = "sha256:61b9a528fb348373c433e8966535074b802c7a5d7f23c4f421e6c6e2f1697a6f"}, - {file = "coverage-7.2.7-cp37-cp37m-win_amd64.whl", hash = "sha256:b1c546aca0ca4d028901d825015dc8e4d56aac4b541877690eb76490f1dc8ed0"}, - {file = "coverage-7.2.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:54b896376ab563bd38453cecb813c295cf347cf5906e8b41d340b0321a5433e5"}, - {file = "coverage-7.2.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3d376df58cc111dc8e21e3b6e24606b5bb5dee6024f46a5abca99124b2229ef5"}, - {file = "coverage-7.2.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e330fc79bd7207e46c7d7fd2bb4af2963f5f635703925543a70b99574b0fea9"}, - {file = "coverage-7.2.7-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e9d683426464e4a252bf70c3498756055016f99ddaec3774bf368e76bbe02b6"}, - {file = "coverage-7.2.7-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d13c64ee2d33eccf7437961b6ea7ad8673e2be040b4f7fd4fd4d4d28d9ccb1e"}, - {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b7aa5f8a41217360e600da646004f878250a0d6738bcdc11a0a39928d7dc2050"}, - {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8fa03bce9bfbeeef9f3b160a8bed39a221d82308b4152b27d82d8daa7041fee5"}, - {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:245167dd26180ab4c91d5e1496a30be4cd721a5cf2abf52974f965f10f11419f"}, - {file = "coverage-7.2.7-cp38-cp38-win32.whl", hash = "sha256:d2c2db7fd82e9b72937969bceac4d6ca89660db0a0967614ce2481e81a0b771e"}, - {file = "coverage-7.2.7-cp38-cp38-win_amd64.whl", hash = "sha256:2e07b54284e381531c87f785f613b833569c14ecacdcb85d56b25c4622c16c3c"}, - {file = "coverage-7.2.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:537891ae8ce59ef63d0123f7ac9e2ae0fc8b72c7ccbe5296fec45fd68967b6c9"}, - {file = "coverage-7.2.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:06fb182e69f33f6cd1d39a6c597294cff3143554b64b9825d1dc69d18cc2fff2"}, - {file = "coverage-7.2.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:201e7389591af40950a6480bd9edfa8ed04346ff80002cec1a66cac4549c1ad7"}, - {file = "coverage-7.2.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f6951407391b639504e3b3be51b7ba5f3528adbf1a8ac3302b687ecababf929e"}, - {file = "coverage-7.2.7-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f48351d66575f535669306aa7d6d6f71bc43372473b54a832222803eb956fd1"}, - {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b29019c76039dc3c0fd815c41392a044ce555d9bcdd38b0fb60fb4cd8e475ba9"}, - {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:81c13a1fc7468c40f13420732805a4c38a105d89848b7c10af65a90beff25250"}, - {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:975d70ab7e3c80a3fe86001d8751f6778905ec723f5b110aed1e450da9d4b7f2"}, - {file = "coverage-7.2.7-cp39-cp39-win32.whl", hash = "sha256:7ee7d9d4822c8acc74a5e26c50604dff824710bc8de424904c0982e25c39c6cb"}, - {file = "coverage-7.2.7-cp39-cp39-win_amd64.whl", hash = "sha256:eb393e5ebc85245347950143969b241d08b52b88a3dc39479822e073a1a8eb27"}, - {file = "coverage-7.2.7-pp37.pp38.pp39-none-any.whl", hash = "sha256:b7b4c971f05e6ae490fef852c218b0e79d4e52f79ef0c8475566584a8fb3e01d"}, - {file = "coverage-7.2.7.tar.gz", hash = "sha256:924d94291ca674905fe9481f12294eb11f2d3d3fd1adb20314ba89e94f44ed59"}, + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] -[package.extras] -toml = ["tomli"] - [[package]] name = "datadog" -version = "0.47.0" +version = "0.51.0" description = "The Datadog Python library" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["main"] files = [ - {file = "datadog-0.47.0-py2.py3-none-any.whl", hash = "sha256:a45ec997ab554208837e8c44d81d0e1456539dc14da5743687250e028bc809b7"}, - {file = "datadog-0.47.0.tar.gz", hash = "sha256:47be3b2c3d709a7f5b709eb126ed4fe6cc7977d618fe5c158dd89c2a9f7d9916"}, + {file = "datadog-0.51.0-py2.py3-none-any.whl", hash = "sha256:a9764f091c96af4e0996d4400b168fc5fba380f911d6d672c9dcd4773e29ea3f"}, + {file = "datadog-0.51.0.tar.gz", hash = "sha256:3279534f831ae0b4ae2d8ce42ef038b4ab38e667d7ed6ff7437982d7a0cf5250"}, ] [package.dependencies] requests = ">=2.6.0" -[[package]] -name = "ddsketch" -version = "2.0.4" -description = "Distributed quantile sketches" -optional = false -python-versions = ">=2.7" -files = [ - {file = "ddsketch-2.0.4-py3-none-any.whl", hash = "sha256:3227a270fd686a29d3a7128f9352ccf852314410380fc11384356f1ae2a75938"}, - {file = "ddsketch-2.0.4.tar.gz", hash = "sha256:32f7314077fec8747d4faebaec2c854b5ffc399c5f552f73fa94024f48d74d64"}, -] - -[package.dependencies] -protobuf = {version = ">=3.0.0", markers = "python_version >= \"3.7\""} -six = "*" - [[package]] name = "ddtrace" -version = "2.3.1" +version = "2.20.0" description = "Datadog APM client library" optional = false python-versions = ">=3.7" -files = [ - {file = "ddtrace-2.3.1-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:556a046413024cf53ebb0256bbf957692a5e417599e04dac5793e659d08c398c"}, - {file = "ddtrace-2.3.1-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:6066f1deddb454b8e098e5a0eb53ab36d81344209fdf6bec94767358da190294"}, - {file = "ddtrace-2.3.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb2b950901845b966a7805ff49a9ad58dcd5e9c27b5b804079977a1309c5b4fb"}, - {file = "ddtrace-2.3.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:05b0da47bc98a9802faa2557e83c096868c4ef249c3d9a43f8e5daf91d1c8e4f"}, - {file = "ddtrace-2.3.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0183c5178112604eb012653fd17d0947e6e2f17325f93b1e32cc6af05ceffd0"}, - {file = "ddtrace-2.3.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:462eb671cd78780af6e42b43f2bc451537a0d283db054c175348e9b3a1fcaff4"}, - {file = "ddtrace-2.3.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:9b5284786a0912a9739665a33760f561423524e2d250c0b0bb2dedf6edba2da5"}, - {file = "ddtrace-2.3.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:dbfb1ade5725a63f21945ab8234e64e46645e98a7deb4342eddf6e86d0f9145c"}, - {file = "ddtrace-2.3.1-cp310-cp310-win32.whl", hash = "sha256:1f51732c4181e5b671a5ae3c6c786ce3b9fd2abacad2d4249d53a55564906902"}, - {file = "ddtrace-2.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f0ae5814fbb51b4aba4d4f4b5c1fd2110790b04d4141cf4a03291566d1d5b0f"}, - {file = "ddtrace-2.3.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:24f4df55fd952182efe6815748db4675540f6fb674d9838dfa680dec1fdd176f"}, - {file = "ddtrace-2.3.1-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:04b4e476f78389021b50b3ae5c4d494bbbd033a300e93253fe1f873a67611436"}, - {file = "ddtrace-2.3.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:711978dd14c0aca7eaf90587b8608c891b82e1767fc6f2be7d82b67d56c8d580"}, - {file = "ddtrace-2.3.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bfa6b1b2698029b7b1f8cc351869397c33bff996159660a00ca254d9fcc5b78d"}, - {file = "ddtrace-2.3.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0dd7295921009ccc61f5325cc3d30fc6182396fc8e598975b372bdf94fd16077"}, - {file = "ddtrace-2.3.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:94aa6a2e16d05cbb2d7a9a7553ca9b638e5b200e0d80fd027179e6af0faf59a2"}, - {file = "ddtrace-2.3.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:62f67040ef16149a46c8506d92a2824d7ded39427a51947a3651d572bb7a379f"}, - {file = "ddtrace-2.3.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:02622c4b8d5497f6367d9ccad38ac8c59d46fc3373034be114474fb01b1a28e6"}, - {file = "ddtrace-2.3.1-cp311-cp311-win32.whl", hash = "sha256:1d13ec5393802a619f922fb37a9f534911f44554bd0434dfd2d8db4e8897649e"}, - {file = "ddtrace-2.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:36b3427136f61d499f3fd307f97ae168a4d2728887e1922204e509a5aa72a4a3"}, - {file = "ddtrace-2.3.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:ac47d141e03c8bea3953fc5f51ac284de9ff4e6325faf2554b003ac906bc4da8"}, - {file = "ddtrace-2.3.1-cp312-cp312-macosx_11_0_x86_64.whl", hash = "sha256:dd23e10b4cac1cf26e64d4d1ec1d6e173e609a207f5520469326f5cff6c7e462"}, - {file = "ddtrace-2.3.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a31cddf750d7a28c886c194624c6be5a4475de064489002df898731f27f3d16"}, - {file = "ddtrace-2.3.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3dedd8097e58519f47f8908fe684f37c8f9722ce4b0614de78d9f39b83621dc7"}, - {file = "ddtrace-2.3.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:367aed800b78fb4d2af332c44d07d7126b1dbf758af422299f9a177811ec723d"}, - {file = "ddtrace-2.3.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ca4dea67facdeba44040d9af8eeff96fb9a35a2b1cff93255e33a4d7250881b9"}, - {file = "ddtrace-2.3.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:a661e133d451416741c6c2ad96baa417a1267204975bfb0d247cab748ecc3ed1"}, - {file = "ddtrace-2.3.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:556f60d6c9bbfc2da6d7f6751625fa3ae597c26bb8bbe74953db0d2d74f93b04"}, - {file = "ddtrace-2.3.1-cp312-cp312-win32.whl", hash = "sha256:261e20b9e9a363ec2dc728f8a009a2b1d3c9de4fbe07438b5600902a285bb179"}, - {file = "ddtrace-2.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:119be400024efff2f0eb66216b2aa3d2a700cd9b4a07605f7f9c94eb5e4b4cb5"}, - {file = "ddtrace-2.3.1-cp37-cp37m-macosx_11_0_x86_64.whl", hash = "sha256:a66d0e0cccfa2fb207fc9a4d9ca6ab235a768f130129d6bb1dd256b7b3d34305"}, - {file = "ddtrace-2.3.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c465e43b96380f09e1e8f2d0f9cb3b78b4ef2bb211f25b57c925bb79f53cb00c"}, - {file = "ddtrace-2.3.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c3eaaf8c5b63e07533822425b3402552c75adf091a1f0a6bf949725fa610c779"}, - {file = "ddtrace-2.3.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:600551ecd232df060203714dc1acba4809e9194fc91a7c638b68c548e92af171"}, - {file = "ddtrace-2.3.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:837232d708956a5d595a3618641c188a5844d663e0f77b1461f20c83f74a21c0"}, - {file = "ddtrace-2.3.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:ddf3043581e2424fc3d4271ee00a038651a4ec9d2610eeaa2d6645095c9f4960"}, - {file = "ddtrace-2.3.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:63c6b28096e273431da923a8dfc0f54f7d472c3c78f0a5c4c99ed7e210b9c855"}, - {file = "ddtrace-2.3.1-cp37-cp37m-win32.whl", hash = "sha256:8b09a42cc975f798bfda9b8d8bf5c8c813022bfcf48b9e0e5e90caf4cf33ee8f"}, - {file = "ddtrace-2.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:66b49153c85423d5e99b1f364cc3b4a3ffedf35be0f3eb840f3bacd7c58100e8"}, - {file = "ddtrace-2.3.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:81f0bd1d50c8fc7d8a96e38f746ca4421fa3b52991f0df44e5e9faeb5a934c2b"}, - {file = "ddtrace-2.3.1-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:37d600d582a5046f82cf77ae9247cf15cf62cf23c15739c5f23c30db2aa092c9"}, - {file = "ddtrace-2.3.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:60a62cfa22695cb1392c617910fb389c7240fa9dae0b5792bd87ff3ae82d2c45"}, - {file = "ddtrace-2.3.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1bdf55fa4a842f9786ca30434b31bf6f877e95af86b6fb7a5a540ce592f566b7"}, - {file = "ddtrace-2.3.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63032c6a76173cab03c021e65c1997a12c0c571263caf00ec18b82c2293c49be"}, - {file = "ddtrace-2.3.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:516b830e52bc8ac2988f11a06a6c6a5296f73b119e99e8ee55a34e531389acea"}, - {file = "ddtrace-2.3.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:86e7764759043439c3f672f998f60bb9118fc4a6d7f603c762b125471b17f549"}, - {file = "ddtrace-2.3.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:87ae203dd8fa3e04f8855786ae4b2f103bc66c9f2368ee2b4e620bccdde9b34d"}, - {file = "ddtrace-2.3.1-cp38-cp38-win32.whl", hash = "sha256:f42fa2fa6f2cd9e3673a3bd7469439f5bea0ee86456706db1b50dc20b10682a6"}, - {file = "ddtrace-2.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:2a3ad8e53c45c3329f939fe921714dfe76f5737e48f5b37a5422b1573a20ce44"}, - {file = "ddtrace-2.3.1-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:5adff6a5d60239e64062ad5efb72631c47c7fb8310ebea6d817f0208a7585074"}, - {file = "ddtrace-2.3.1-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:84012bc7d27dd3c4cd591bbaf0a0cc0413ebc6c838637ca5a76bacb354e2518f"}, - {file = "ddtrace-2.3.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cc2596b26701c9e3a362195f79ddcf54b491a8ea13277ed16697da9ad943646"}, - {file = "ddtrace-2.3.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:986113f7eb4d8a8e87216b55e6cc40b578f84a5730241822af3f34cc61e42710"}, - {file = "ddtrace-2.3.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd0cdbc6d81e556b6af0875b0bb2ac77d3cf0a0c5da8faa014da1936e1e0adc2"}, - {file = "ddtrace-2.3.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9e8eb17ef8ca2fc9464216290969cff3bbf8df00860ebb219328804125b43bd1"}, - {file = "ddtrace-2.3.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:fc21e46c5e9d077022b7634ae247d15d2318cbb347f6756607dfd64ff5941797"}, - {file = "ddtrace-2.3.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:51bf7e3e5c80ef0daadd22c26e7c24c90fc4b4a7662dec1a3d9d8e0db68f3c09"}, - {file = "ddtrace-2.3.1-cp39-cp39-win32.whl", hash = "sha256:2a5f040c0eb101f82a9cd8b8b0279e8583bb0a62fd39b879197d53b71a5d6dbe"}, - {file = "ddtrace-2.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:ff708683becb18771cb31ae5fb5d1430ac5031a082106e0dabac46a1fd6f832e"}, - {file = "ddtrace-2.3.1.tar.gz", hash = "sha256:273a0e98f93e7231708b30067768d80df9bc93a505de93500f30c6da24b70a7b"}, +groups = ["main"] +files = [ + {file = "ddtrace-2.20.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:e1dee099099b95acf7d0e552179925cfec58a52315cc914d153506367b195bc4"}, + {file = "ddtrace-2.20.0-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:9d209bef14caafcd53be8c14e04741d86c08f76496c1bf755e2eaa38605ce3e0"}, + {file = "ddtrace-2.20.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f37966012078151713d61382de2a7ed710a8f375820e0db41930436b813b651"}, + {file = "ddtrace-2.20.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:879b963baf0b97d5ddd26185ab496b79efd25bbfdc2c25dbb1113ec19dc5abf9"}, + {file = "ddtrace-2.20.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13e9b9a87c9df8a029fd3583ac660538dfa9d53207fee82b7f04749148bf8a3b"}, + {file = "ddtrace-2.20.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:eb76547a4bbf285d03ffc6e065bbad61761954741da2df0e4683d68d46ef2159"}, + {file = "ddtrace-2.20.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:194973afa1e357c68b6a6eceaabbddcef01130d167775126c2a15b3c1827f683"}, + {file = "ddtrace-2.20.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:a71d2fc753b8fa2c3435b6f4d5f820d8deb51f49df59a4886b4da68b67f923d3"}, + {file = "ddtrace-2.20.0-cp310-cp310-win32.whl", hash = "sha256:567054d0c01dc552a8a24c4c9eeb98d778be720d2c4c9536acf1b86d6969a5e4"}, + {file = "ddtrace-2.20.0-cp310-cp310-win_amd64.whl", hash = "sha256:d39f96e2fdfdf7ab43ee89a20d914f5ab12f8f361c390663eacb0e5da6e6e7fb"}, + {file = "ddtrace-2.20.0-cp311-cp311-macosx_12_0_universal2.whl", hash = "sha256:0a1d7eaf6c9a5e0eabb8396f7d19faffc8f76a1ae37f34814c3432a9ca6f31da"}, + {file = "ddtrace-2.20.0-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:301a7787a34113b56cc9067a593c4717f6e158f2393883c30b59d0a37ebc06fa"}, + {file = "ddtrace-2.20.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d76ce49eb42588766db6756240d746441a66f03932547bfca9c62a8aecdbb38"}, + {file = "ddtrace-2.20.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a84d2e2411496c1b4ca3ce0cfb407d186cb3d13f1769c321fec30e677d815cd8"}, + {file = "ddtrace-2.20.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da47746a24242d805a800bca0a10b1354353e18b0bc4b6caf9c9c1724ba286b0"}, + {file = "ddtrace-2.20.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6f89e6003a738800beeb9948c847366976c73de2e24cc469b644a125f418c0a8"}, + {file = "ddtrace-2.20.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4fca20220bf668ebcac7051d28648b62aa95d2afeb5036ecad167cb454c7dcf1"}, + {file = "ddtrace-2.20.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1197e89fcaaca4ce419e3c812d04c73b8d16973202472cf3f674b4698b967697"}, + {file = "ddtrace-2.20.0-cp311-cp311-win32.whl", hash = "sha256:44bcd604a1d9095f4eb6813db6a677a208bd47884aff9ddc5aa46f596765f38e"}, + {file = "ddtrace-2.20.0-cp311-cp311-win_amd64.whl", hash = "sha256:0a5f092df1ee4d0afe96502866ff0fb446a07c6a23d445ed616f1302c883e1d3"}, + {file = "ddtrace-2.20.0-cp312-cp312-macosx_12_0_universal2.whl", hash = "sha256:f77103d36e6ab52cb45781766620d3874d0a728565afa7fd57f8ce2d5087e8e7"}, + {file = "ddtrace-2.20.0-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:d1cec952ce2ca9efbb34c8a9ee522e1cc588fe454b9115120b30fd5d0f821512"}, + {file = "ddtrace-2.20.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a4a1da150e92b6d43047f2a91a7d3b7133207f94b82613625abf82662359b30e"}, + {file = "ddtrace-2.20.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91ab68c1facc6cf04085fdeea53210ed9928e95116809fd9bfe2dea54e83375d"}, + {file = "ddtrace-2.20.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4fd7ec6410225e64ca875d1bc9bd6bd8489f52dd8558462fbb52447fb8f66ad3"}, + {file = "ddtrace-2.20.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:57864590ddb84da4eb99332fe4b521e6fd747992178e3eabcf4f87406e908bb1"}, + {file = "ddtrace-2.20.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:37693555704a0cbd4a925e4ffe9c6df696146c85557c5f66ce3a7a88406772d9"}, + {file = "ddtrace-2.20.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ae5e802aaefc0cd3b63e3fd46e051a39e9f960a02e89f44a5bb820f445b736f9"}, + {file = "ddtrace-2.20.0-cp312-cp312-win32.whl", hash = "sha256:14fe4f583bec105c40e233c74fcbaea185658651c626ce1609750d83d93a00ae"}, + {file = "ddtrace-2.20.0-cp312-cp312-win_amd64.whl", hash = "sha256:cfbc926ddfeece0312e82f9e00a68001647666d11ceb050a5bbe66ca8931e3d2"}, + {file = "ddtrace-2.20.0-cp313-cp313-macosx_12_0_universal2.whl", hash = "sha256:eeca6b6bd48794d48de438981dccbc96a06366edde798c12b2b3348ca5e03717"}, + {file = "ddtrace-2.20.0-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:3f526e75d1b61019db2cd715e8c7298325e21c3584f8677a7decf37aa81e7284"}, + {file = "ddtrace-2.20.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:96441189ccc772ef4871e23a35cec58a748c16ebfb2293eccaaa719dcbc368fd"}, + {file = "ddtrace-2.20.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4d31d769f222c9a5bde1d4a594da1341014bf02db1a7194f5a41ed7e5c4c9fa8"}, + {file = "ddtrace-2.20.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:54068dbf034e1f607ef5d58a9fa1b26bd78b4f3db0618ce0a3e9c4b04fff7209"}, + {file = "ddtrace-2.20.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:62e86d9b00277fe2b9bdfbc51ca1bc34aa5c1200aa6bc5084c7eaaab28b022de"}, + {file = "ddtrace-2.20.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:c83c2458de1cf1bbac48689c6541a85d54ad94ae6608961e1089cc2959a8c77a"}, + {file = "ddtrace-2.20.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:569d7a92a88ba9b2a203addea688b0585901534c92c2d148ef9f971b6d7b3805"}, + {file = "ddtrace-2.20.0-cp37-cp37m-macosx_12_0_x86_64.whl", hash = "sha256:df413d646fc14b4be51a15ed8e484bcdf3b21e370e2644a586283bcc7e0b2355"}, + {file = "ddtrace-2.20.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:33e4406a436278722df193c93d49e662a8891e8a440fddb273dca9a56fa27947"}, + {file = "ddtrace-2.20.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b9d358bc7b4b1daa2d6e6bc697244b39db653ddd5ae139045941d3db28950bfe"}, + {file = "ddtrace-2.20.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a523924382d2f8f87731e4ad86bbf4721fba9eb807ed3b0c862db6d768e1e81c"}, + {file = "ddtrace-2.20.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:0af78a424e9d87250a8648a35b7de5653f27b3f6f6803c1b33780816a07e6d26"}, + {file = "ddtrace-2.20.0-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:2723378e670d27927f7d1ab878c8668fc392a5656a66453b9808e7c4025431fd"}, + {file = "ddtrace-2.20.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:01f76fc9bf1413a188ddd59851eb3b668d3de936afed73a5914a817f36e11005"}, + {file = "ddtrace-2.20.0-cp37-cp37m-win32.whl", hash = "sha256:3a615ae95ef8f889304b2958655ac8cda23cf2f2c8faf5d8ff88bd14bdcf3fb4"}, + {file = "ddtrace-2.20.0-cp37-cp37m-win_amd64.whl", hash = "sha256:b90333661ffd3460bae6dbbd7a5f35d8467cff36bd7a689a47b014edb19c0fe6"}, + {file = "ddtrace-2.20.0-cp38-cp38-macosx_12_0_universal2.whl", hash = "sha256:ab27596e82bdfe9c0c5580f6886ec943ae2fe615a446c22470f6a1f9742dec62"}, + {file = "ddtrace-2.20.0-cp38-cp38-macosx_12_0_x86_64.whl", hash = "sha256:e2de7371291283cba1afdd7e919a577637099da0d6872d33b4008e1cad6e1b8b"}, + {file = "ddtrace-2.20.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fa4f90f472768aef8ce023a924505c9d1d09428fc9d6ab81bc0e3ab183e3ff48"}, + {file = "ddtrace-2.20.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:05b68ba6fe4da5317396100669edf91b3d54b95ae979a2a22ca880cfcc6c249d"}, + {file = "ddtrace-2.20.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1512d07e6c7cde13ae251906d57d31613fe5ee99fab2894e90679053b4256953"}, + {file = "ddtrace-2.20.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:dcadc60aa60e11f2db56065a834aaa5e52a9be02e8edc8d14aa7015fb54092ce"}, + {file = "ddtrace-2.20.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:698207d88941ea3e4e5f3add6071e6651caa12fcffe079359507391382251759"}, + {file = "ddtrace-2.20.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:9f95a251f84725df055202d933b4a8fb39cefd51341e10cad17d2a8b4d64700e"}, + {file = "ddtrace-2.20.0-cp38-cp38-win32.whl", hash = "sha256:0b121285459693ae9f3c9ce54cc4be981a2e73d4c52b8a5eb038cf41df9974dd"}, + {file = "ddtrace-2.20.0-cp38-cp38-win_amd64.whl", hash = "sha256:4c840dc91c622138a4a6abdbcbee56897d4c55d9e7bf16b1902ee676f20b22f2"}, + {file = "ddtrace-2.20.0-cp39-cp39-macosx_12_0_universal2.whl", hash = "sha256:c74d69e6a4cbd91f6fe411519d753f34893d6d40a68829b43485690df8a7f30f"}, + {file = "ddtrace-2.20.0-cp39-cp39-macosx_12_0_x86_64.whl", hash = "sha256:4902b64ba89a8e4008228e7a5007e20b2bb8071c6c7689abd47dddc159e2baf1"}, + {file = "ddtrace-2.20.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:758ba828eddd144a4804af692869e7278376efa740932a7453e8fdc0ed6ef6a7"}, + {file = "ddtrace-2.20.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:37995326df811236c9d92d1b5713378a7f11270bf1e21c64914653a3e12d7d01"}, + {file = "ddtrace-2.20.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab7f1babd7a8e73edf70c957a5b3bbeb4c615b232a078a0fe4da566e1663d1aa"}, + {file = "ddtrace-2.20.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1cd1b240f465c98e226ab896b1b1c3696752d5eb1051a0aafb8a3db701d2ddc1"}, + {file = "ddtrace-2.20.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3a300515c3327af4fd5c6c83e6ca63cd0a20e4243381d4b712e3f406d9ddf201"}, + {file = "ddtrace-2.20.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:f1ce886b112e0e8aa66ba8cf3593f00f7f6ae6b48dd09bd8ce90c59adad59d66"}, + {file = "ddtrace-2.20.0-cp39-cp39-win32.whl", hash = "sha256:bb77464849b092f93839d5c257df9eaeb018521ddea2deef97dfc6e3501a2516"}, + {file = "ddtrace-2.20.0-cp39-cp39-win_amd64.whl", hash = "sha256:b95f14f0634fe3f02dcebb7b8a124207b3d44168fd0dfc6bfff1e4db93978089"}, + {file = "ddtrace-2.20.0.tar.gz", hash = "sha256:f185c6dd88cd04884f0ad27b37f14d837274e8fc4dc43407781334d92d41c3bc"}, ] [package.dependencies] -attrs = ">=20" bytecode = [ - {version = ">=0.13.0,<0.14.0", markers = "python_version == \"3.7\""}, - {version = "*", markers = "python_version >= \"3.8\""}, + {version = ">=0.13.0", markers = "python_version < \"3.11\""}, + {version = ">=0.16.0", markers = "python_version >= \"3.13.0\""}, + {version = ">=0.15.0", markers = "python_version ~= \"3.12.0\""}, + {version = ">=0.14.0", markers = "python_version ~= \"3.11.0\""}, ] -cattrs = "*" -ddsketch = ">=2.0.1" -envier = "*" -importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} +envier = ">=0.5,<1.0" +legacy-cgi = {version = ">=2.0.0", markers = "python_version >= \"3.13.0\""} opentelemetry-api = ">=1" protobuf = ">=3" -setuptools = {version = "*", markers = "python_version >= \"3.12\""} -six = ">=1.12.0" -typing-extensions = "*" +typing_extensions = "*" +wrapt = ">=1" xmltodict = ">=0.12" [package.extras] +openai = ["tiktoken"] opentracing = ["opentracing (>=2.0.0)"] [[package]] name = "deprecated" -version = "1.2.14" +version = "1.2.18" description = "Python @deprecated decorator to deprecate old python classes, functions or methods." optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" +groups = ["main"] files = [ - {file = "Deprecated-1.2.14-py2.py3-none-any.whl", hash = "sha256:6fac8b097794a90302bdbb17b9b815e732d3c4720583ff1b198499d78470466c"}, - {file = "Deprecated-1.2.14.tar.gz", hash = "sha256:e5323eb936458dccc2582dc6f9c322c852a775a27065ff2b0c4970b9d53d01b3"}, + {file = "Deprecated-1.2.18-py2.py3-none-any.whl", hash = "sha256:bd5011788200372a32418f888e326a09ff80d0214bd961147cfed01b5c018eec"}, + {file = "deprecated-1.2.18.tar.gz", hash = "sha256:422b6f6d859da6f2ef57857761bfb392480502a64c3028ca9bbe86085d72115d"}, ] [package.dependencies] wrapt = ">=1.10,<2" [package.extras] -dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "sphinx (<2)", "tox"] +dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "setuptools ; python_version >= \"3.12\"", "tox"] [[package]] name = "envier" -version = "0.4.0" +version = "0.6.1" description = "Python application configuration via the environment" optional = false -python-versions = ">=2.7" +python-versions = ">=3.7" +groups = ["main"] files = [ - {file = "envier-0.4.0-py3-none-any.whl", hash = "sha256:7b91af0f16ea3e56d91ec082f038987e81b441fc19c657a8b8afe0909740a706"}, - {file = "envier-0.4.0.tar.gz", hash = "sha256:e68dcd1ed67d8b6313883e27dff3e701b7fba944d2ed4b7f53d0cc2e12364a82"}, + {file = "envier-0.6.1-py3-none-any.whl", hash = "sha256:73609040a76be48bbcb97074d9969666484aa0de706183a6e9ef773156a8a6a9"}, + {file = "envier-0.6.1.tar.gz", hash = "sha256:3309a01bb3d8850c9e7a31a5166d5a836846db2faecb79b9cb32654dd50ca9f9"}, ] [package.extras] @@ -445,13 +313,15 @@ mypy = ["mypy"] [[package]] name = "exceptiongroup" -version = "1.2.0" +version = "1.2.2" description = "Backport of PEP 654 (exception groups)" -optional = false +optional = true python-versions = ">=3.7" +groups = ["main"] +markers = "extra == \"dev\" and python_version <= \"3.10\"" files = [ - {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"}, - {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"}, + {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, + {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, ] [package.extras] @@ -459,64 +329,73 @@ test = ["pytest (>=6)"] [[package]] name = "flake8" -version = "3.9.2" +version = "5.0.4" description = "the modular source code checker: pep8 pyflakes and co" optional = true -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" +python-versions = ">=3.6.1" +groups = ["main"] +markers = "extra == \"dev\"" files = [ - {file = "flake8-3.9.2-py2.py3-none-any.whl", hash = "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907"}, - {file = "flake8-3.9.2.tar.gz", hash = "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b"}, + {file = "flake8-5.0.4-py2.py3-none-any.whl", hash = "sha256:7a1cf6b73744f5806ab95e526f6f0d8c01c66d7bbe349562d22dfca20610b248"}, + {file = "flake8-5.0.4.tar.gz", hash = "sha256:6fbe320aad8d6b95cec8b8e47bc933004678dc63095be98528b7bdd2a9f510db"}, ] [package.dependencies] -importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} -mccabe = ">=0.6.0,<0.7.0" -pycodestyle = ">=2.7.0,<2.8.0" -pyflakes = ">=2.3.0,<2.4.0" - -[[package]] -name = "httpretty" -version = "0.9.7" -description = "HTTP client mock for Python" -optional = true -python-versions = "*" -files = [ - {file = "httpretty-0.9.7.tar.gz", hash = "sha256:66216f26b9d2c52e81808f3e674a6fb65d4bf719721394a1a9be926177e55fbe"}, -] - -[package.dependencies] -six = "*" +mccabe = ">=0.7.0,<0.8.0" +pycodestyle = ">=2.9.0,<2.10.0" +pyflakes = ">=2.5.0,<2.6.0" [[package]] name = "idna" -version = "3.4" +version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" optional = false -python-versions = ">=3.5" +python-versions = ">=3.6" +groups = ["main"] files = [ - {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, - {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, + {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, + {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, ] +[package.extras] +all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] + [[package]] name = "importlib-metadata" -version = "6.7.0" +version = "8.5.0" description = "Read metadata from Python packages" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" +groups = ["main"] files = [ - {file = "importlib_metadata-6.7.0-py3-none-any.whl", hash = "sha256:cb52082e659e97afc5dac71e79de97d8681de3aa07ff18578330904a9d18e5b5"}, - {file = "importlib_metadata-6.7.0.tar.gz", hash = "sha256:1aaf550d4f73e5d6783e7acb77aec43d49da8017410afae93822cc9cca98c4d4"}, + {file = "importlib_metadata-8.5.0-py3-none-any.whl", hash = "sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b"}, + {file = "importlib_metadata-8.5.0.tar.gz", hash = "sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7"}, ] [package.dependencies] -typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} -zipp = ">=0.5" +zipp = ">=3.20" [package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] perf = ["ipython"] -testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"] +test = ["flufl.flake8", "importlib-resources (>=1.3) ; python_version < \"3.9\"", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"] +type = ["pytest-mypy"] + +[[package]] +name = "iniconfig" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" +optional = true +python-versions = ">=3.7" +groups = ["main"] +markers = "extra == \"dev\"" +files = [ + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +] [[package]] name = "jmespath" @@ -524,109 +403,202 @@ version = "1.0.1" description = "JSON Matching Expressions" optional = true python-versions = ">=3.7" +groups = ["main"] +markers = "extra == \"dev\"" files = [ {file = "jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980"}, {file = "jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe"}, ] [[package]] -name = "mccabe" -version = "0.6.1" -description = "McCabe checker, plugin for flake8" -optional = true -python-versions = "*" +name = "legacy-cgi" +version = "2.6.2" +description = "Fork of the standard library cgi and cgitb modules, being deprecated in PEP-594" +optional = false +python-versions = ">=3.10" +groups = ["main"] +markers = "python_version >= \"3.13.0\"" files = [ - {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, - {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, + {file = "legacy_cgi-2.6.2-py3-none-any.whl", hash = "sha256:a7b83afb1baf6ebeb56522537c5943ef9813cf933f6715e88a803f7edbce0bff"}, + {file = "legacy_cgi-2.6.2.tar.gz", hash = "sha256:9952471ceb304043b104c22d00b4f333cac27a6abe446d8a528fc437cf13c85f"}, ] [[package]] -name = "nose2" -version = "0.9.2" -description = "unittest2 with plugins, the succesor to nose" +name = "mccabe" +version = "0.7.0" +description = "McCabe checker, plugin for flake8" optional = true -python-versions = "*" +python-versions = ">=3.6" +groups = ["main"] +markers = "extra == \"dev\"" files = [ - {file = "nose2-0.9.2-py2.py3-none-any.whl", hash = "sha256:fd4b84c65ecea869080a23bdb8916716f5363df3b899933991c861ada8aa3f48"}, - {file = "nose2-0.9.2.tar.gz", hash = "sha256:8762f77925bbafcdf38331e0e2ee718756fb75ff74b1f9097cd08731ad59ab5e"}, + {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, + {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, ] -[package.dependencies] -coverage = ">=4.4.1" -six = ">=1.7" - -[package.extras] -coverage-plugin = ["coverage (>=4.4.1)"] -doc = ["Sphinx (>=1.6.5)", "mock", "sphinx-rtd-theme"] - [[package]] name = "opentelemetry-api" -version = "1.21.0" +version = "1.29.0" description = "OpenTelemetry Python API" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" +groups = ["main"] files = [ - {file = "opentelemetry_api-1.21.0-py3-none-any.whl", hash = "sha256:4bb86b28627b7e41098f0e93280fe4892a1abed1b79a19aec6f928f39b17dffb"}, - {file = "opentelemetry_api-1.21.0.tar.gz", hash = "sha256:d6185fd5043e000075d921822fd2d26b953eba8ca21b1e2fa360dd46a7686316"}, + {file = "opentelemetry_api-1.29.0-py3-none-any.whl", hash = "sha256:5fcd94c4141cc49c736271f3e1efb777bebe9cc535759c54c936cca4f1b312b8"}, + {file = "opentelemetry_api-1.29.0.tar.gz", hash = "sha256:d04a6cf78aad09614f52964ecb38021e248f5714dc32c2e0d8fd99517b4d69cf"}, ] [package.dependencies] deprecated = ">=1.2.6" -importlib-metadata = ">=6.0,<7.0" +importlib-metadata = ">=6.0,<=8.5.0" + +[[package]] +name = "packaging" +version = "24.2" +description = "Core utilities for Python packages" +optional = true +python-versions = ">=3.8" +groups = ["main"] +markers = "extra == \"dev\"" +files = [ + {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, + {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, +] + +[[package]] +name = "pluggy" +version = "1.5.0" +description = "plugin and hook calling mechanisms for python" +optional = true +python-versions = ">=3.8" +groups = ["main"] +markers = "extra == \"dev\"" +files = [ + {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, + {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] [[package]] name = "protobuf" -version = "4.24.4" +version = "5.29.5" description = "" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" +groups = ["main"] files = [ - {file = "protobuf-4.24.4-cp310-abi3-win32.whl", hash = "sha256:ec9912d5cb6714a5710e28e592ee1093d68c5ebfeda61983b3f40331da0b1ebb"}, - {file = "protobuf-4.24.4-cp310-abi3-win_amd64.whl", hash = "sha256:1badab72aa8a3a2b812eacfede5020472e16c6b2212d737cefd685884c191085"}, - {file = "protobuf-4.24.4-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:8e61a27f362369c2f33248a0ff6896c20dcd47b5d48239cb9720134bef6082e4"}, - {file = "protobuf-4.24.4-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:bffa46ad9612e6779d0e51ae586fde768339b791a50610d85eb162daeb23661e"}, - {file = "protobuf-4.24.4-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:b493cb590960ff863743b9ff1452c413c2ee12b782f48beca77c8da3e2ffe9d9"}, - {file = "protobuf-4.24.4-cp37-cp37m-win32.whl", hash = "sha256:dbbed8a56e56cee8d9d522ce844a1379a72a70f453bde6243e3c86c30c2a3d46"}, - {file = "protobuf-4.24.4-cp37-cp37m-win_amd64.whl", hash = "sha256:6b7d2e1c753715dcfe9d284a25a52d67818dd43c4932574307daf836f0071e37"}, - {file = "protobuf-4.24.4-cp38-cp38-win32.whl", hash = "sha256:02212557a76cd99574775a81fefeba8738d0f668d6abd0c6b1d3adcc75503dbe"}, - {file = "protobuf-4.24.4-cp38-cp38-win_amd64.whl", hash = "sha256:2fa3886dfaae6b4c5ed2730d3bf47c7a38a72b3a1f0acb4d4caf68e6874b947b"}, - {file = "protobuf-4.24.4-cp39-cp39-win32.whl", hash = "sha256:b77272f3e28bb416e2071186cb39efd4abbf696d682cbb5dc731308ad37fa6dd"}, - {file = "protobuf-4.24.4-cp39-cp39-win_amd64.whl", hash = "sha256:9fee5e8aa20ef1b84123bb9232b3f4a5114d9897ed89b4b8142d81924e05d79b"}, - {file = "protobuf-4.24.4-py3-none-any.whl", hash = "sha256:80797ce7424f8c8d2f2547e2d42bfbb6c08230ce5832d6c099a37335c9c90a92"}, - {file = "protobuf-4.24.4.tar.gz", hash = "sha256:5a70731910cd9104762161719c3d883c960151eea077134458503723b60e3667"}, + {file = "protobuf-5.29.5-cp310-abi3-win32.whl", hash = "sha256:3f1c6468a2cfd102ff4703976138844f78ebd1fb45f49011afc5139e9e283079"}, + {file = "protobuf-5.29.5-cp310-abi3-win_amd64.whl", hash = "sha256:3f76e3a3675b4a4d867b52e4a5f5b78a2ef9565549d4037e06cf7b0942b1d3fc"}, + {file = "protobuf-5.29.5-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e38c5add5a311f2a6eb0340716ef9b039c1dfa428b28f25a7838ac329204a671"}, + {file = "protobuf-5.29.5-cp38-abi3-manylinux2014_aarch64.whl", hash = "sha256:fa18533a299d7ab6c55a238bf8629311439995f2e7eca5caaff08663606e9015"}, + {file = "protobuf-5.29.5-cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:63848923da3325e1bf7e9003d680ce6e14b07e55d0473253a690c3a8b8fd6e61"}, + {file = "protobuf-5.29.5-cp38-cp38-win32.whl", hash = "sha256:ef91363ad4faba7b25d844ef1ada59ff1604184c0bcd8b39b8a6bef15e1af238"}, + {file = "protobuf-5.29.5-cp38-cp38-win_amd64.whl", hash = "sha256:7318608d56b6402d2ea7704ff1e1e4597bee46d760e7e4dd42a3d45e24b87f2e"}, + {file = "protobuf-5.29.5-cp39-cp39-win32.whl", hash = "sha256:6f642dc9a61782fa72b90878af134c5afe1917c89a568cd3476d758d3c3a0736"}, + {file = "protobuf-5.29.5-cp39-cp39-win_amd64.whl", hash = "sha256:470f3af547ef17847a28e1f47200a1cbf0ba3ff57b7de50d22776607cd2ea353"}, + {file = "protobuf-5.29.5-py3-none-any.whl", hash = "sha256:6cf42630262c59b2d8de33954443d94b746c952b01434fc58a417fdbd2e84bd5"}, + {file = "protobuf-5.29.5.tar.gz", hash = "sha256:bc1463bafd4b0929216c35f437a8e28731a2b7fe3d98bb77a600efced5a15c84"}, +] + +[[package]] +name = "py-cpuinfo" +version = "9.0.0" +description = "Get CPU info with pure Python" +optional = true +python-versions = "*" +groups = ["main"] +markers = "extra == \"dev\"" +files = [ + {file = "py-cpuinfo-9.0.0.tar.gz", hash = "sha256:3cdbbf3fac90dc6f118bfd64384f309edeadd902d7c8fb17f02ffa1fc3f49690"}, + {file = "py_cpuinfo-9.0.0-py3-none-any.whl", hash = "sha256:859625bc251f64e21f077d099d4162689c762b5d6a4c3c97553d56241c9674d5"}, ] [[package]] name = "pycodestyle" -version = "2.7.0" +version = "2.9.1" description = "Python style guide checker" optional = true -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.6" +groups = ["main"] +markers = "extra == \"dev\"" files = [ - {file = "pycodestyle-2.7.0-py2.py3-none-any.whl", hash = "sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068"}, - {file = "pycodestyle-2.7.0.tar.gz", hash = "sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef"}, + {file = "pycodestyle-2.9.1-py2.py3-none-any.whl", hash = "sha256:d1735fc58b418fd7c5f658d28d943854f8a849b01a5d0a1e6f3f3fdd0166804b"}, + {file = "pycodestyle-2.9.1.tar.gz", hash = "sha256:2c9607871d58c76354b697b42f5d57e1ada7d261c261efac224b664affdc5785"}, ] [[package]] name = "pyflakes" -version = "2.3.1" +version = "2.5.0" description = "passive checker of Python programs" optional = true -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.6" +groups = ["main"] +markers = "extra == \"dev\"" files = [ - {file = "pyflakes-2.3.1-py2.py3-none-any.whl", hash = "sha256:7893783d01b8a89811dd72d7dfd4d84ff098e5eed95cfa8905b22bbffe52efc3"}, - {file = "pyflakes-2.3.1.tar.gz", hash = "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"}, + {file = "pyflakes-2.5.0-py2.py3-none-any.whl", hash = "sha256:4579f67d887f804e67edb544428f264b7b24f435b263c4614f384135cea553d2"}, + {file = "pyflakes-2.5.0.tar.gz", hash = "sha256:491feb020dca48ccc562a8c0cbe8df07ee13078df59813b83959cbdada312ea3"}, ] +[[package]] +name = "pytest" +version = "8.3.4" +description = "pytest: simple powerful testing with Python" +optional = true +python-versions = ">=3.8" +groups = ["main"] +markers = "extra == \"dev\"" +files = [ + {file = "pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6"}, + {file = "pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=1.5,<2" +tomli = {version = ">=1", markers = "python_version < \"3.11\""} + +[package.extras] +dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] + +[[package]] +name = "pytest-benchmark" +version = "4.0.0" +description = "A ``pytest`` fixture for benchmarking code. It will group the tests into rounds that are calibrated to the chosen timer." +optional = true +python-versions = ">=3.7" +groups = ["main"] +markers = "extra == \"dev\"" +files = [ + {file = "pytest-benchmark-4.0.0.tar.gz", hash = "sha256:fb0785b83efe599a6a956361c0691ae1dbb5318018561af10f3e915caa0048d1"}, + {file = "pytest_benchmark-4.0.0-py3-none-any.whl", hash = "sha256:fdb7db64e31c8b277dff9850d2a2556d8b60bcb0ea6524e36e28ffd7c87f71d6"}, +] + +[package.dependencies] +py-cpuinfo = "*" +pytest = ">=3.8" + +[package.extras] +aspect = ["aspectlib"] +elasticsearch = ["elasticsearch"] +histogram = ["pygal", "pygaljs"] + [[package]] name = "python-dateutil" -version = "2.8.2" +version = "2.9.0.post0" description = "Extensions to the standard Python datetime module" optional = true python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +groups = ["main"] +markers = "extra == \"dev\"" files = [ - {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, - {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, + {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, + {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, ] [package.dependencies] @@ -634,18 +606,19 @@ six = ">=1.5" [[package]] name = "requests" -version = "2.31.0" +version = "2.32.4" description = "Python HTTP for Humans." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" +groups = ["main"] files = [ - {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, - {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, + {file = "requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c"}, + {file = "requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422"}, ] [package.dependencies] certifi = ">=2017.4.17" -charset-normalizer = ">=2,<4" +charset_normalizer = ">=2,<4" idna = ">=2.5,<4" urllib3 = ">=1.21.1,<3" @@ -654,202 +627,323 @@ socks = ["PySocks (>=1.5.6,!=1.5.7)"] use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] -name = "s3transfer" -version = "0.7.0" -description = "An Amazon S3 Transfer Manager" +name = "six" +version = "1.17.0" +description = "Python 2 and 3 compatibility utilities" optional = true -python-versions = ">= 3.7" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +groups = ["main"] +markers = "extra == \"dev\"" files = [ - {file = "s3transfer-0.7.0-py3-none-any.whl", hash = "sha256:10d6923c6359175f264811ef4bf6161a3156ce8e350e705396a7557d6293c33a"}, - {file = "s3transfer-0.7.0.tar.gz", hash = "sha256:fd3889a66f5fe17299fe75b82eae6cf722554edca744ca5d5fe308b104883d2e"}, + {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, + {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, ] -[package.dependencies] -botocore = ">=1.12.36,<2.0a.0" - -[package.extras] -crt = ["botocore[crt] (>=1.20.29,<2.0a.0)"] - [[package]] -name = "setuptools" -version = "69.0.2" -description = "Easily download, build, install, upgrade, and uninstall Python packages" -optional = false +name = "tomli" +version = "2.2.1" +description = "A lil' TOML parser" +optional = true python-versions = ">=3.8" -files = [ - {file = "setuptools-69.0.2-py3-none-any.whl", hash = "sha256:1e8fdff6797d3865f37397be788a4e3cba233608e9b509382a2777d25ebde7f2"}, - {file = "setuptools-69.0.2.tar.gz", hash = "sha256:735896e78a4742605974de002ac60562d286fa8051a7e2299445e8e8fbb01aa6"}, +groups = ["main"] +markers = "extra == \"dev\" and python_version <= \"3.10\"" +files = [ + {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"}, + {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"}, + {file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"}, + {file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"}, + {file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"}, + {file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"}, + {file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"}, + {file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"}, + {file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"}, + {file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"}, ] -[package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] - [[package]] -name = "six" -version = "1.16.0" -description = "Python 2 and 3 compatibility utilities" +name = "typing-extensions" +version = "4.12.2" +description = "Backported and Experimental Type Hints for Python 3.8+" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +python-versions = ">=3.8" +groups = ["main"] files = [ - {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, - {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, ] [[package]] -name = "typing-extensions" -version = "4.7.1" -description = "Backported and Experimental Type Hints for Python 3.7+" +name = "ujson" +version = "5.10.0" +description = "Ultra fast JSON encoder and decoder for Python" optional = false -python-versions = ">=3.7" -files = [ - {file = "typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36"}, - {file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"}, +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "ujson-5.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2601aa9ecdbee1118a1c2065323bda35e2c5a2cf0797ef4522d485f9d3ef65bd"}, + {file = "ujson-5.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:348898dd702fc1c4f1051bc3aacbf894caa0927fe2c53e68679c073375f732cf"}, + {file = "ujson-5.10.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22cffecf73391e8abd65ef5f4e4dd523162a3399d5e84faa6aebbf9583df86d6"}, + {file = "ujson-5.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26b0e2d2366543c1bb4fbd457446f00b0187a2bddf93148ac2da07a53fe51569"}, + {file = "ujson-5.10.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:caf270c6dba1be7a41125cd1e4fc7ba384bf564650beef0df2dd21a00b7f5770"}, + {file = "ujson-5.10.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a245d59f2ffe750446292b0094244df163c3dc96b3ce152a2c837a44e7cda9d1"}, + {file = "ujson-5.10.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:94a87f6e151c5f483d7d54ceef83b45d3a9cca7a9cb453dbdbb3f5a6f64033f5"}, + {file = "ujson-5.10.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:29b443c4c0a113bcbb792c88bea67b675c7ca3ca80c3474784e08bba01c18d51"}, + {file = "ujson-5.10.0-cp310-cp310-win32.whl", hash = "sha256:c18610b9ccd2874950faf474692deee4223a994251bc0a083c114671b64e6518"}, + {file = "ujson-5.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:924f7318c31874d6bb44d9ee1900167ca32aa9b69389b98ecbde34c1698a250f"}, + {file = "ujson-5.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a5b366812c90e69d0f379a53648be10a5db38f9d4ad212b60af00bd4048d0f00"}, + {file = "ujson-5.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:502bf475781e8167f0f9d0e41cd32879d120a524b22358e7f205294224c71126"}, + {file = "ujson-5.10.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b91b5d0d9d283e085e821651184a647699430705b15bf274c7896f23fe9c9d8"}, + {file = "ujson-5.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:129e39af3a6d85b9c26d5577169c21d53821d8cf68e079060602e861c6e5da1b"}, + {file = "ujson-5.10.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f77b74475c462cb8b88680471193064d3e715c7c6074b1c8c412cb526466efe9"}, + {file = "ujson-5.10.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7ec0ca8c415e81aa4123501fee7f761abf4b7f386aad348501a26940beb1860f"}, + {file = "ujson-5.10.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ab13a2a9e0b2865a6c6db9271f4b46af1c7476bfd51af1f64585e919b7c07fd4"}, + {file = "ujson-5.10.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:57aaf98b92d72fc70886b5a0e1a1ca52c2320377360341715dd3933a18e827b1"}, + {file = "ujson-5.10.0-cp311-cp311-win32.whl", hash = "sha256:2987713a490ceb27edff77fb184ed09acdc565db700ee852823c3dc3cffe455f"}, + {file = "ujson-5.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:f00ea7e00447918ee0eff2422c4add4c5752b1b60e88fcb3c067d4a21049a720"}, + {file = "ujson-5.10.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:98ba15d8cbc481ce55695beee9f063189dce91a4b08bc1d03e7f0152cd4bbdd5"}, + {file = "ujson-5.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a9d2edbf1556e4f56e50fab7d8ff993dbad7f54bac68eacdd27a8f55f433578e"}, + {file = "ujson-5.10.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6627029ae4f52d0e1a2451768c2c37c0c814ffc04f796eb36244cf16b8e57043"}, + {file = "ujson-5.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8ccb77b3e40b151e20519c6ae6d89bfe3f4c14e8e210d910287f778368bb3d1"}, + {file = "ujson-5.10.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3caf9cd64abfeb11a3b661329085c5e167abbe15256b3b68cb5d914ba7396f3"}, + {file = "ujson-5.10.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6e32abdce572e3a8c3d02c886c704a38a1b015a1fb858004e03d20ca7cecbb21"}, + {file = "ujson-5.10.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a65b6af4d903103ee7b6f4f5b85f1bfd0c90ba4eeac6421aae436c9988aa64a2"}, + {file = "ujson-5.10.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:604a046d966457b6cdcacc5aa2ec5314f0e8c42bae52842c1e6fa02ea4bda42e"}, + {file = "ujson-5.10.0-cp312-cp312-win32.whl", hash = "sha256:6dea1c8b4fc921bf78a8ff00bbd2bfe166345f5536c510671bccececb187c80e"}, + {file = "ujson-5.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:38665e7d8290188b1e0d57d584eb8110951a9591363316dd41cf8686ab1d0abc"}, + {file = "ujson-5.10.0-cp313-cp313-macosx_10_9_x86_64.whl", hash = "sha256:618efd84dc1acbd6bff8eaa736bb6c074bfa8b8a98f55b61c38d4ca2c1f7f287"}, + {file = "ujson-5.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:38d5d36b4aedfe81dfe251f76c0467399d575d1395a1755de391e58985ab1c2e"}, + {file = "ujson-5.10.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67079b1f9fb29ed9a2914acf4ef6c02844b3153913eb735d4bf287ee1db6e557"}, + {file = "ujson-5.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7d0e0ceeb8fe2468c70ec0c37b439dd554e2aa539a8a56365fd761edb418988"}, + {file = "ujson-5.10.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:59e02cd37bc7c44d587a0ba45347cc815fb7a5fe48de16bf05caa5f7d0d2e816"}, + {file = "ujson-5.10.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2a890b706b64e0065f02577bf6d8ca3b66c11a5e81fb75d757233a38c07a1f20"}, + {file = "ujson-5.10.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:621e34b4632c740ecb491efc7f1fcb4f74b48ddb55e65221995e74e2d00bbff0"}, + {file = "ujson-5.10.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b9500e61fce0cfc86168b248104e954fead61f9be213087153d272e817ec7b4f"}, + {file = "ujson-5.10.0-cp313-cp313-win32.whl", hash = "sha256:4c4fc16f11ac1612f05b6f5781b384716719547e142cfd67b65d035bd85af165"}, + {file = "ujson-5.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:4573fd1695932d4f619928fd09d5d03d917274381649ade4328091ceca175539"}, + {file = "ujson-5.10.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a984a3131da7f07563057db1c3020b1350a3e27a8ec46ccbfbf21e5928a43050"}, + {file = "ujson-5.10.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:73814cd1b9db6fc3270e9d8fe3b19f9f89e78ee9d71e8bd6c9a626aeaeaf16bd"}, + {file = "ujson-5.10.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:61e1591ed9376e5eddda202ec229eddc56c612b61ac6ad07f96b91460bb6c2fb"}, + {file = "ujson-5.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2c75269f8205b2690db4572a4a36fe47cd1338e4368bc73a7a0e48789e2e35a"}, + {file = "ujson-5.10.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7223f41e5bf1f919cd8d073e35b229295aa8e0f7b5de07ed1c8fddac63a6bc5d"}, + {file = "ujson-5.10.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d4dc2fd6b3067c0782e7002ac3b38cf48608ee6366ff176bbd02cf969c9c20fe"}, + {file = "ujson-5.10.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:232cc85f8ee3c454c115455195a205074a56ff42608fd6b942aa4c378ac14dd7"}, + {file = "ujson-5.10.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:cc6139531f13148055d691e442e4bc6601f6dba1e6d521b1585d4788ab0bfad4"}, + {file = "ujson-5.10.0-cp38-cp38-win32.whl", hash = "sha256:e7ce306a42b6b93ca47ac4a3b96683ca554f6d35dd8adc5acfcd55096c8dfcb8"}, + {file = "ujson-5.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:e82d4bb2138ab05e18f089a83b6564fee28048771eb63cdecf4b9b549de8a2cc"}, + {file = "ujson-5.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dfef2814c6b3291c3c5f10065f745a1307d86019dbd7ea50e83504950136ed5b"}, + {file = "ujson-5.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4734ee0745d5928d0ba3a213647f1c4a74a2a28edc6d27b2d6d5bd9fa4319e27"}, + {file = "ujson-5.10.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d47ebb01bd865fdea43da56254a3930a413f0c5590372a1241514abae8aa7c76"}, + {file = "ujson-5.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dee5e97c2496874acbf1d3e37b521dd1f307349ed955e62d1d2f05382bc36dd5"}, + {file = "ujson-5.10.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7490655a2272a2d0b072ef16b0b58ee462f4973a8f6bbe64917ce5e0a256f9c0"}, + {file = "ujson-5.10.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:ba17799fcddaddf5c1f75a4ba3fd6441f6a4f1e9173f8a786b42450851bd74f1"}, + {file = "ujson-5.10.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:2aff2985cef314f21d0fecc56027505804bc78802c0121343874741650a4d3d1"}, + {file = "ujson-5.10.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:ad88ac75c432674d05b61184178635d44901eb749786c8eb08c102330e6e8996"}, + {file = "ujson-5.10.0-cp39-cp39-win32.whl", hash = "sha256:2544912a71da4ff8c4f7ab5606f947d7299971bdd25a45e008e467ca638d13c9"}, + {file = "ujson-5.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:3ff201d62b1b177a46f113bb43ad300b424b7847f9c5d38b1b4ad8f75d4a282a"}, + {file = "ujson-5.10.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5b6fee72fa77dc172a28f21693f64d93166534c263adb3f96c413ccc85ef6e64"}, + {file = "ujson-5.10.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:61d0af13a9af01d9f26d2331ce49bb5ac1fb9c814964018ac8df605b5422dcb3"}, + {file = "ujson-5.10.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ecb24f0bdd899d368b715c9e6664166cf694d1e57be73f17759573a6986dd95a"}, + {file = "ujson-5.10.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fbd8fd427f57a03cff3ad6574b5e299131585d9727c8c366da4624a9069ed746"}, + {file = "ujson-5.10.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:beeaf1c48e32f07d8820c705ff8e645f8afa690cca1544adba4ebfa067efdc88"}, + {file = "ujson-5.10.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:baed37ea46d756aca2955e99525cc02d9181de67f25515c468856c38d52b5f3b"}, + {file = "ujson-5.10.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7663960f08cd5a2bb152f5ee3992e1af7690a64c0e26d31ba7b3ff5b2ee66337"}, + {file = "ujson-5.10.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:d8640fb4072d36b08e95a3a380ba65779d356b2fee8696afeb7794cf0902d0a1"}, + {file = "ujson-5.10.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78778a3aa7aafb11e7ddca4e29f46bc5139131037ad628cc10936764282d6753"}, + {file = "ujson-5.10.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0111b27f2d5c820e7f2dbad7d48e3338c824e7ac4d2a12da3dc6061cc39c8e6"}, + {file = "ujson-5.10.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:c66962ca7565605b355a9ed478292da628b8f18c0f2793021ca4425abf8b01e5"}, + {file = "ujson-5.10.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ba43cc34cce49cf2d4bc76401a754a81202d8aa926d0e2b79f0ee258cb15d3a4"}, + {file = "ujson-5.10.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:ac56eb983edce27e7f51d05bc8dd820586c6e6be1c5216a6809b0c668bb312b8"}, + {file = "ujson-5.10.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f44bd4b23a0e723bf8b10628288c2c7c335161d6840013d4d5de20e48551773b"}, + {file = "ujson-5.10.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c10f4654e5326ec14a46bcdeb2b685d4ada6911050aa8baaf3501e57024b804"}, + {file = "ujson-5.10.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0de4971a89a762398006e844ae394bd46991f7c385d7a6a3b93ba229e6dac17e"}, + {file = "ujson-5.10.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:e1402f0564a97d2a52310ae10a64d25bcef94f8dd643fcf5d310219d915484f7"}, + {file = "ujson-5.10.0.tar.gz", hash = "sha256:b3cd8f3c5d8c7738257f1018880444f7b7d9b66232c64649f562d7ba86ad4bc1"}, ] [[package]] name = "urllib3" -version = "1.26.18" +version = "1.26.20" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +groups = ["main"] +markers = "python_version < \"3.10\"" files = [ - {file = "urllib3-1.26.18-py2.py3-none-any.whl", hash = "sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07"}, - {file = "urllib3-1.26.18.tar.gz", hash = "sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0"}, + {file = "urllib3-1.26.20-py2.py3-none-any.whl", hash = "sha256:0ed14ccfbf1c30a9072c7ca157e4319b70d65f623e91e7b32fadb2853431016e"}, + {file = "urllib3-1.26.20.tar.gz", hash = "sha256:40c2dc0c681e47eb8f90e7e27bf6ff7df2e677421fd46756da1161c39ca70d32"}, ] [package.extras] -brotli = ["brotli (==1.0.9)", "brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] -secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] +brotli = ["brotli (==1.0.9) ; os_name != \"nt\" and python_version < \"3\" and platform_python_implementation == \"CPython\"", "brotli (>=1.0.9) ; python_version >= \"3\" and platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; (os_name != \"nt\" or python_version >= \"3\") and platform_python_implementation != \"CPython\"", "brotlipy (>=0.6.0) ; os_name == \"nt\" and python_version < \"3\""] +secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress ; python_version == \"2.7\"", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [[package]] name = "urllib3" -version = "2.0.7" +version = "2.3.0" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" +groups = ["main"] +markers = "python_version >= \"3.10\"" files = [ - {file = "urllib3-2.0.7-py3-none-any.whl", hash = "sha256:fdb6d215c776278489906c2f8916e6e7d4f5a9b602ccbcfdf7f016fc8da0596e"}, - {file = "urllib3-2.0.7.tar.gz", hash = "sha256:c97dfde1f7bd43a71c8d2a58e369e9b2bf692d1334ea9f9cae55add7d0dd0f84"}, + {file = "urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df"}, + {file = "urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d"}, ] [package.extras] -brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] -secure = ["certifi", "cryptography (>=1.9)", "idna (>=2.0.0)", "pyopenssl (>=17.1.0)", "urllib3-secure-extra"] +brotli = ["brotli (>=1.0.9) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\""] +h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] [[package]] name = "wrapt" -version = "1.16.0" +version = "1.17.2" description = "Module for decorators, wrappers and monkey patching." optional = false -python-versions = ">=3.6" -files = [ - {file = "wrapt-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4"}, - {file = "wrapt-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e4fdb9275308292e880dcbeb12546df7f3e0f96c6b41197e0cf37d2826359020"}, - {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb2dee3874a500de01c93d5c71415fcaef1d858370d405824783e7a8ef5db440"}, - {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a88e6010048489cda82b1326889ec075a8c856c2e6a256072b28eaee3ccf487"}, - {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac83a914ebaf589b69f7d0a1277602ff494e21f4c2f743313414378f8f50a4cf"}, - {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:73aa7d98215d39b8455f103de64391cb79dfcad601701a3aa0dddacf74911d72"}, - {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:807cc8543a477ab7422f1120a217054f958a66ef7314f76dd9e77d3f02cdccd0"}, - {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bf5703fdeb350e36885f2875d853ce13172ae281c56e509f4e6eca049bdfb136"}, - {file = "wrapt-1.16.0-cp310-cp310-win32.whl", hash = "sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d"}, - {file = "wrapt-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:decbfa2f618fa8ed81c95ee18a387ff973143c656ef800c9f24fb7e9c16054e2"}, - {file = "wrapt-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1a5db485fe2de4403f13fafdc231b0dbae5eca4359232d2efc79025527375b09"}, - {file = "wrapt-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:75ea7d0ee2a15733684badb16de6794894ed9c55aa5e9903260922f0482e687d"}, - {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a452f9ca3e3267cd4d0fcf2edd0d035b1934ac2bd7e0e57ac91ad6b95c0c6389"}, - {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:43aa59eadec7890d9958748db829df269f0368521ba6dc68cc172d5d03ed8060"}, - {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72554a23c78a8e7aa02abbd699d129eead8b147a23c56e08d08dfc29cfdddca1"}, - {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d2efee35b4b0a347e0d99d28e884dfd82797852d62fcd7ebdeee26f3ceb72cf3"}, - {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6dcfcffe73710be01d90cae08c3e548d90932d37b39ef83969ae135d36ef3956"}, - {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:eb6e651000a19c96f452c85132811d25e9264d836951022d6e81df2fff38337d"}, - {file = "wrapt-1.16.0-cp311-cp311-win32.whl", hash = "sha256:66027d667efe95cc4fa945af59f92c5a02c6f5bb6012bff9e60542c74c75c362"}, - {file = "wrapt-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:aefbc4cb0a54f91af643660a0a150ce2c090d3652cf4052a5397fb2de549cd89"}, - {file = "wrapt-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5eb404d89131ec9b4f748fa5cfb5346802e5ee8836f57d516576e61f304f3b7b"}, - {file = "wrapt-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9090c9e676d5236a6948330e83cb89969f433b1943a558968f659ead07cb3b36"}, - {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94265b00870aa407bd0cbcfd536f17ecde43b94fb8d228560a1e9d3041462d73"}, - {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2058f813d4f2b5e3a9eb2eb3faf8f1d99b81c3e51aeda4b168406443e8ba809"}, - {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98b5e1f498a8ca1858a1cdbffb023bfd954da4e3fa2c0cb5853d40014557248b"}, - {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:14d7dc606219cdd7405133c713f2c218d4252f2a469003f8c46bb92d5d095d81"}, - {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:49aac49dc4782cb04f58986e81ea0b4768e4ff197b57324dcbd7699c5dfb40b9"}, - {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:418abb18146475c310d7a6dc71143d6f7adec5b004ac9ce08dc7a34e2babdc5c"}, - {file = "wrapt-1.16.0-cp312-cp312-win32.whl", hash = "sha256:685f568fa5e627e93f3b52fda002c7ed2fa1800b50ce51f6ed1d572d8ab3e7fc"}, - {file = "wrapt-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:dcdba5c86e368442528f7060039eda390cc4091bfd1dca41e8046af7c910dda8"}, - {file = "wrapt-1.16.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d462f28826f4657968ae51d2181a074dfe03c200d6131690b7d65d55b0f360f8"}, - {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a33a747400b94b6d6b8a165e4480264a64a78c8a4c734b62136062e9a248dd39"}, - {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3646eefa23daeba62643a58aac816945cadc0afaf21800a1421eeba5f6cfb9c"}, - {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ebf019be5c09d400cf7b024aa52b1f3aeebeff51550d007e92c3c1c4afc2a40"}, - {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:0d2691979e93d06a95a26257adb7bfd0c93818e89b1406f5a28f36e0d8c1e1fc"}, - {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:1acd723ee2a8826f3d53910255643e33673e1d11db84ce5880675954183ec47e"}, - {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:bc57efac2da352a51cc4658878a68d2b1b67dbe9d33c36cb826ca449d80a8465"}, - {file = "wrapt-1.16.0-cp36-cp36m-win32.whl", hash = "sha256:da4813f751142436b075ed7aa012a8778aa43a99f7b36afe9b742d3ed8bdc95e"}, - {file = "wrapt-1.16.0-cp36-cp36m-win_amd64.whl", hash = "sha256:6f6eac2360f2d543cc875a0e5efd413b6cbd483cb3ad7ebf888884a6e0d2e966"}, - {file = "wrapt-1.16.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a0ea261ce52b5952bf669684a251a66df239ec6d441ccb59ec7afa882265d593"}, - {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bd2d7ff69a2cac767fbf7a2b206add2e9a210e57947dd7ce03e25d03d2de292"}, - {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9159485323798c8dc530a224bd3ffcf76659319ccc7bbd52e01e73bd0241a0c5"}, - {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a86373cf37cd7764f2201b76496aba58a52e76dedfaa698ef9e9688bfd9e41cf"}, - {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:73870c364c11f03ed072dda68ff7aea6d2a3a5c3fe250d917a429c7432e15228"}, - {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b935ae30c6e7400022b50f8d359c03ed233d45b725cfdd299462f41ee5ffba6f"}, - {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:db98ad84a55eb09b3c32a96c576476777e87c520a34e2519d3e59c44710c002c"}, - {file = "wrapt-1.16.0-cp37-cp37m-win32.whl", hash = "sha256:9153ed35fc5e4fa3b2fe97bddaa7cbec0ed22412b85bcdaf54aeba92ea37428c"}, - {file = "wrapt-1.16.0-cp37-cp37m-win_amd64.whl", hash = "sha256:66dfbaa7cfa3eb707bbfcd46dab2bc6207b005cbc9caa2199bcbc81d95071a00"}, - {file = "wrapt-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1dd50a2696ff89f57bd8847647a1c363b687d3d796dc30d4dd4a9d1689a706f0"}, - {file = "wrapt-1.16.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:44a2754372e32ab315734c6c73b24351d06e77ffff6ae27d2ecf14cf3d229202"}, - {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e9723528b9f787dc59168369e42ae1c3b0d3fadb2f1a71de14531d321ee05b0"}, - {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbed418ba5c3dce92619656802cc5355cb679e58d0d89b50f116e4a9d5a9603e"}, - {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:941988b89b4fd6b41c3f0bfb20e92bd23746579736b7343283297c4c8cbae68f"}, - {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6a42cd0cfa8ffc1915aef79cb4284f6383d8a3e9dcca70c445dcfdd639d51267"}, - {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1ca9b6085e4f866bd584fb135a041bfc32cab916e69f714a7d1d397f8c4891ca"}, - {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5e49454f19ef621089e204f862388d29e6e8d8b162efce05208913dde5b9ad6"}, - {file = "wrapt-1.16.0-cp38-cp38-win32.whl", hash = "sha256:c31f72b1b6624c9d863fc095da460802f43a7c6868c5dda140f51da24fd47d7b"}, - {file = "wrapt-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:490b0ee15c1a55be9c1bd8609b8cecd60e325f0575fc98f50058eae366e01f41"}, - {file = "wrapt-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9b201ae332c3637a42f02d1045e1d0cccfdc41f1f2f801dafbaa7e9b4797bfc2"}, - {file = "wrapt-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2076fad65c6736184e77d7d4729b63a6d1ae0b70da4868adeec40989858eb3fb"}, - {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5cd603b575ebceca7da5a3a251e69561bec509e0b46e4993e1cac402b7247b8"}, - {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b47cfad9e9bbbed2339081f4e346c93ecd7ab504299403320bf85f7f85c7d46c"}, - {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a"}, - {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5f15814a33e42b04e3de432e573aa557f9f0f56458745c2074952f564c50e664"}, - {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db2e408d983b0e61e238cf579c09ef7020560441906ca990fe8412153e3b291f"}, - {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:edfad1d29c73f9b863ebe7082ae9321374ccb10879eeabc84ba3b69f2579d537"}, - {file = "wrapt-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed867c42c268f876097248e05b6117a65bcd1e63b779e916fe2e33cd6fd0d3c3"}, - {file = "wrapt-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:eb1b046be06b0fce7249f1d025cd359b4b80fc1c3e24ad9eca33e0dcdb2e4a35"}, - {file = "wrapt-1.16.0-py3-none-any.whl", hash = "sha256:6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1"}, - {file = "wrapt-1.16.0.tar.gz", hash = "sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d"}, +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "wrapt-1.17.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3d57c572081fed831ad2d26fd430d565b76aa277ed1d30ff4d40670b1c0dd984"}, + {file = "wrapt-1.17.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b5e251054542ae57ac7f3fba5d10bfff615b6c2fb09abeb37d2f1463f841ae22"}, + {file = "wrapt-1.17.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:80dd7db6a7cb57ffbc279c4394246414ec99537ae81ffd702443335a61dbf3a7"}, + {file = "wrapt-1.17.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a6e821770cf99cc586d33833b2ff32faebdbe886bd6322395606cf55153246c"}, + {file = "wrapt-1.17.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b60fb58b90c6d63779cb0c0c54eeb38941bae3ecf7a73c764c52c88c2dcb9d72"}, + {file = "wrapt-1.17.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b870b5df5b71d8c3359d21be8f0d6c485fa0ebdb6477dda51a1ea54a9b558061"}, + {file = "wrapt-1.17.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4011d137b9955791f9084749cba9a367c68d50ab8d11d64c50ba1688c9b457f2"}, + {file = "wrapt-1.17.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:1473400e5b2733e58b396a04eb7f35f541e1fb976d0c0724d0223dd607e0f74c"}, + {file = "wrapt-1.17.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3cedbfa9c940fdad3e6e941db7138e26ce8aad38ab5fe9dcfadfed9db7a54e62"}, + {file = "wrapt-1.17.2-cp310-cp310-win32.whl", hash = "sha256:582530701bff1dec6779efa00c516496968edd851fba224fbd86e46cc6b73563"}, + {file = "wrapt-1.17.2-cp310-cp310-win_amd64.whl", hash = "sha256:58705da316756681ad3c9c73fd15499aa4d8c69f9fd38dc8a35e06c12468582f"}, + {file = "wrapt-1.17.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ff04ef6eec3eee8a5efef2401495967a916feaa353643defcc03fc74fe213b58"}, + {file = "wrapt-1.17.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4db983e7bca53819efdbd64590ee96c9213894272c776966ca6306b73e4affda"}, + {file = "wrapt-1.17.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9abc77a4ce4c6f2a3168ff34b1da9b0f311a8f1cfd694ec96b0603dff1c79438"}, + {file = "wrapt-1.17.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b929ac182f5ace000d459c59c2c9c33047e20e935f8e39371fa6e3b85d56f4a"}, + {file = "wrapt-1.17.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f09b286faeff3c750a879d336fb6d8713206fc97af3adc14def0cdd349df6000"}, + {file = "wrapt-1.17.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a7ed2d9d039bd41e889f6fb9364554052ca21ce823580f6a07c4ec245c1f5d6"}, + {file = "wrapt-1.17.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:129a150f5c445165ff941fc02ee27df65940fcb8a22a61828b1853c98763a64b"}, + {file = "wrapt-1.17.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1fb5699e4464afe5c7e65fa51d4f99e0b2eadcc176e4aa33600a3df7801d6662"}, + {file = "wrapt-1.17.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9a2bce789a5ea90e51a02dfcc39e31b7f1e662bc3317979aa7e5538e3a034f72"}, + {file = "wrapt-1.17.2-cp311-cp311-win32.whl", hash = "sha256:4afd5814270fdf6380616b321fd31435a462019d834f83c8611a0ce7484c7317"}, + {file = "wrapt-1.17.2-cp311-cp311-win_amd64.whl", hash = "sha256:acc130bc0375999da18e3d19e5a86403667ac0c4042a094fefb7eec8ebac7cf3"}, + {file = "wrapt-1.17.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d5e2439eecc762cd85e7bd37161d4714aa03a33c5ba884e26c81559817ca0925"}, + {file = "wrapt-1.17.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3fc7cb4c1c744f8c05cd5f9438a3caa6ab94ce8344e952d7c45a8ed59dd88392"}, + {file = "wrapt-1.17.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8fdbdb757d5390f7c675e558fd3186d590973244fab0c5fe63d373ade3e99d40"}, + {file = "wrapt-1.17.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5bb1d0dbf99411f3d871deb6faa9aabb9d4e744d67dcaaa05399af89d847a91d"}, + {file = "wrapt-1.17.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d18a4865f46b8579d44e4fe1e2bcbc6472ad83d98e22a26c963d46e4c125ef0b"}, + {file = "wrapt-1.17.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc570b5f14a79734437cb7b0500376b6b791153314986074486e0b0fa8d71d98"}, + {file = "wrapt-1.17.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6d9187b01bebc3875bac9b087948a2bccefe464a7d8f627cf6e48b1bbae30f82"}, + {file = "wrapt-1.17.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:9e8659775f1adf02eb1e6f109751268e493c73716ca5761f8acb695e52a756ae"}, + {file = "wrapt-1.17.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e8b2816ebef96d83657b56306152a93909a83f23994f4b30ad4573b00bd11bb9"}, + {file = "wrapt-1.17.2-cp312-cp312-win32.whl", hash = "sha256:468090021f391fe0056ad3e807e3d9034e0fd01adcd3bdfba977b6fdf4213ea9"}, + {file = "wrapt-1.17.2-cp312-cp312-win_amd64.whl", hash = "sha256:ec89ed91f2fa8e3f52ae53cd3cf640d6feff92ba90d62236a81e4e563ac0e991"}, + {file = "wrapt-1.17.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6ed6ffac43aecfe6d86ec5b74b06a5be33d5bb9243d055141e8cabb12aa08125"}, + {file = "wrapt-1.17.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:35621ae4c00e056adb0009f8e86e28eb4a41a4bfa8f9bfa9fca7d343fe94f998"}, + {file = "wrapt-1.17.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a604bf7a053f8362d27eb9fefd2097f82600b856d5abe996d623babd067b1ab5"}, + {file = "wrapt-1.17.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5cbabee4f083b6b4cd282f5b817a867cf0b1028c54d445b7ec7cfe6505057cf8"}, + {file = "wrapt-1.17.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49703ce2ddc220df165bd2962f8e03b84c89fee2d65e1c24a7defff6f988f4d6"}, + {file = "wrapt-1.17.2-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8112e52c5822fc4253f3901b676c55ddf288614dc7011634e2719718eaa187dc"}, + {file = "wrapt-1.17.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9fee687dce376205d9a494e9c121e27183b2a3df18037f89d69bd7b35bcf59e2"}, + {file = "wrapt-1.17.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:18983c537e04d11cf027fbb60a1e8dfd5190e2b60cc27bc0808e653e7b218d1b"}, + {file = "wrapt-1.17.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:703919b1633412ab54bcf920ab388735832fdcb9f9a00ae49387f0fe67dad504"}, + {file = "wrapt-1.17.2-cp313-cp313-win32.whl", hash = "sha256:abbb9e76177c35d4e8568e58650aa6926040d6a9f6f03435b7a522bf1c487f9a"}, + {file = "wrapt-1.17.2-cp313-cp313-win_amd64.whl", hash = "sha256:69606d7bb691b50a4240ce6b22ebb319c1cfb164e5f6569835058196e0f3a845"}, + {file = "wrapt-1.17.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:4a721d3c943dae44f8e243b380cb645a709ba5bd35d3ad27bc2ed947e9c68192"}, + {file = "wrapt-1.17.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:766d8bbefcb9e00c3ac3b000d9acc51f1b399513f44d77dfe0eb026ad7c9a19b"}, + {file = "wrapt-1.17.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e496a8ce2c256da1eb98bd15803a79bee00fc351f5dfb9ea82594a3f058309e0"}, + {file = "wrapt-1.17.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d615e4fe22f4ad3528448c193b218e077656ca9ccb22ce2cb20db730f8d306"}, + {file = "wrapt-1.17.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a5aaeff38654462bc4b09023918b7f21790efb807f54c000a39d41d69cf552cb"}, + {file = "wrapt-1.17.2-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a7d15bbd2bc99e92e39f49a04653062ee6085c0e18b3b7512a4f2fe91f2d681"}, + {file = "wrapt-1.17.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:e3890b508a23299083e065f435a492b5435eba6e304a7114d2f919d400888cc6"}, + {file = "wrapt-1.17.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:8c8b293cd65ad716d13d8dd3624e42e5a19cc2a2f1acc74b30c2c13f15cb61a6"}, + {file = "wrapt-1.17.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4c82b8785d98cdd9fed4cac84d765d234ed3251bd6afe34cb7ac523cb93e8b4f"}, + {file = "wrapt-1.17.2-cp313-cp313t-win32.whl", hash = "sha256:13e6afb7fe71fe7485a4550a8844cc9ffbe263c0f1a1eea569bc7091d4898555"}, + {file = "wrapt-1.17.2-cp313-cp313t-win_amd64.whl", hash = "sha256:eaf675418ed6b3b31c7a989fd007fa7c3be66ce14e5c3b27336383604c9da85c"}, + {file = "wrapt-1.17.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5c803c401ea1c1c18de70a06a6f79fcc9c5acfc79133e9869e730ad7f8ad8ef9"}, + {file = "wrapt-1.17.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f917c1180fdb8623c2b75a99192f4025e412597c50b2ac870f156de8fb101119"}, + {file = "wrapt-1.17.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ecc840861360ba9d176d413a5489b9a0aff6d6303d7e733e2c4623cfa26904a6"}, + {file = "wrapt-1.17.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb87745b2e6dc56361bfde481d5a378dc314b252a98d7dd19a651a3fa58f24a9"}, + {file = "wrapt-1.17.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58455b79ec2661c3600e65c0a716955adc2410f7383755d537584b0de41b1d8a"}, + {file = "wrapt-1.17.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b4e42a40a5e164cbfdb7b386c966a588b1047558a990981ace551ed7e12ca9c2"}, + {file = "wrapt-1.17.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:91bd7d1773e64019f9288b7a5101f3ae50d3d8e6b1de7edee9c2ccc1d32f0c0a"}, + {file = "wrapt-1.17.2-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:bb90fb8bda722a1b9d48ac1e6c38f923ea757b3baf8ebd0c82e09c5c1a0e7a04"}, + {file = "wrapt-1.17.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:08e7ce672e35efa54c5024936e559469436f8b8096253404faeb54d2a878416f"}, + {file = "wrapt-1.17.2-cp38-cp38-win32.whl", hash = "sha256:410a92fefd2e0e10d26210e1dfb4a876ddaf8439ef60d6434f21ef8d87efc5b7"}, + {file = "wrapt-1.17.2-cp38-cp38-win_amd64.whl", hash = "sha256:95c658736ec15602da0ed73f312d410117723914a5c91a14ee4cdd72f1d790b3"}, + {file = "wrapt-1.17.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:99039fa9e6306880572915728d7f6c24a86ec57b0a83f6b2491e1d8ab0235b9a"}, + {file = "wrapt-1.17.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2696993ee1eebd20b8e4ee4356483c4cb696066ddc24bd70bcbb80fa56ff9061"}, + {file = "wrapt-1.17.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:612dff5db80beef9e649c6d803a8d50c409082f1fedc9dbcdfde2983b2025b82"}, + {file = "wrapt-1.17.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62c2caa1585c82b3f7a7ab56afef7b3602021d6da34fbc1cf234ff139fed3cd9"}, + {file = "wrapt-1.17.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c958bcfd59bacc2d0249dcfe575e71da54f9dcf4a8bdf89c4cb9a68a1170d73f"}, + {file = "wrapt-1.17.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc78a84e2dfbc27afe4b2bd7c80c8db9bca75cc5b85df52bfe634596a1da846b"}, + {file = "wrapt-1.17.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:ba0f0eb61ef00ea10e00eb53a9129501f52385c44853dbd6c4ad3f403603083f"}, + {file = "wrapt-1.17.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1e1fe0e6ab7775fd842bc39e86f6dcfc4507ab0ffe206093e76d61cde37225c8"}, + {file = "wrapt-1.17.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c86563182421896d73858e08e1db93afdd2b947a70064b813d515d66549e15f9"}, + {file = "wrapt-1.17.2-cp39-cp39-win32.whl", hash = "sha256:f393cda562f79828f38a819f4788641ac7c4085f30f1ce1a68672baa686482bb"}, + {file = "wrapt-1.17.2-cp39-cp39-win_amd64.whl", hash = "sha256:36ccae62f64235cf8ddb682073a60519426fdd4725524ae38874adf72b5f2aeb"}, + {file = "wrapt-1.17.2-py3-none-any.whl", hash = "sha256:b18f2d1533a71f069c7f82d524a52599053d4c7166e9dd374ae2136b7f40f7c8"}, + {file = "wrapt-1.17.2.tar.gz", hash = "sha256:41388e9d4d1522446fe79d3213196bd9e3b301a336965b9e27ca2788ebd122f3"}, ] [[package]] name = "xmltodict" -version = "0.13.0" +version = "0.14.2" description = "Makes working with XML feel like you are working with JSON" optional = false -python-versions = ">=3.4" +python-versions = ">=3.6" +groups = ["main"] files = [ - {file = "xmltodict-0.13.0-py2.py3-none-any.whl", hash = "sha256:aa89e8fd76320154a40d19a0df04a4695fb9dc5ba977cbb68ab3e4eb225e7852"}, - {file = "xmltodict-0.13.0.tar.gz", hash = "sha256:341595a488e3e01a85a9d8911d8912fd922ede5fecc4dce437eb4b6c8d037e56"}, + {file = "xmltodict-0.14.2-py2.py3-none-any.whl", hash = "sha256:20cc7d723ed729276e808f26fb6b3599f786cbc37e06c65e192ba77c40f20aac"}, + {file = "xmltodict-0.14.2.tar.gz", hash = "sha256:201e7c28bb210e374999d1dde6382923ab0ed1a8a5faeece48ab525b7810a553"}, ] [[package]] name = "zipp" -version = "3.15.0" +version = "3.20.2" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" +groups = ["main"] files = [ - {file = "zipp-3.15.0-py3-none-any.whl", hash = "sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556"}, - {file = "zipp-3.15.0.tar.gz", hash = "sha256:112929ad649da941c23de50f356a2b5570c954b65150642bccdd66bf194d224b"}, + {file = "zipp-3.20.2-py3-none-any.whl", hash = "sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350"}, + {file = "zipp-3.20.2.tar.gz", hash = "sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["big-O", "importlib-resources ; python_version < \"3.9\"", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"] +type = ["pytest-mypy"] [extras] -dev = ["boto3", "flake8", "httpretty", "nose2", "requests"] +dev = ["botocore", "flake8", "pytest", "pytest-benchmark", "requests"] [metadata] -lock-version = "2.0" -python-versions = ">=3.7.0,<4" -content-hash = "6687f40495eae4686955981f339f7eb3bcfbc71c7cfba272620b7aca4c45ad1b" +lock-version = "2.1" +python-versions = ">=3.8.0,<4" +content-hash = "f6a2f7355200da107aa5b027d6fe4fb6bdb5a898ce8298a56e6ac39fe8d8e34d" diff --git a/pyproject.toml b/pyproject.toml index 3829ffc73..d135e085b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "datadog_lambda" -version = "5.84.0" +version = "8.117.0.dev0" description = "The Datadog AWS Lambda Library" authors = ["Datadog, Inc. "] license = "Apache-2.0" @@ -16,40 +16,38 @@ packages = [ { include = "datadog_lambda" } ] classifiers = [ - "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", ] [tool.poetry.dependencies] -python = ">=3.7.0,<4" -datadog = ">=0.41.0,<1.0.0" +python = ">=3.8.0,<4" +datadog = ">=0.51.0,<1.0.0" wrapt = "^1.11.2" -ddtrace = ">=2.3.1" -urllib3 = [ - {version = "<2.0.0", python = "<3.11", optional = true}, - {version = "<2.1.0", python = ">=3.11", optional = true}, -] -importlib_metadata = {version = "*", python = "<3.8"} -boto3 = { version = "^1.28.0", optional = true } -typing_extensions = {version = "^4.0", python = "<3.8"} +ddtrace = ">=3.16.2,<4" +ujson = ">=5.9.0" +botocore = { version = "^1.34.0", optional = true } requests = { version ="^2.22.0", optional = true } -nose2 = { version= "^0.9.1", optional = true } -flake8 = { version = "^3.7.9", optional = true } -httpretty = {version = "^0.9.7", optional = true } - +pytest = { version= "^8.0.0", optional = true } +pytest-benchmark = { version = "^4.0", optional = true } +flake8 = { version = "^5.0.4", optional = true } [tool.poetry.extras] dev = [ - "boto3", - "requests", - "nose2", + "botocore", "flake8", - "httpretty", + "pytest", + "pytest-benchmark", + "requests", ] [build-system] requires = ["poetry-core>=1.0.0"] build-backend = "poetry.core.masonry.api" + +[tool.pytest.ini_options] +addopts = "--benchmark-disable --benchmark-autosave" diff --git a/scripts/add_new_region.sh b/scripts/add_new_region.sh index 1b1753cfd..576d13e7f 100755 --- a/scripts/add_new_region.sh +++ b/scripts/add_new_region.sh @@ -12,8 +12,34 @@ set -e OLD_REGION='us-east-1' -LAYER_NAMES=("Datadog-Python37" "Datadog-Python38" "Datadog-Python38-ARM" "Datadog-Python39" "Datadog-Python39-ARM" "Datadog-Python310" "Datadog-Python310-ARM" "Datadog-Python311" "Datadog-Python311-ARM") -PYTHON_VERSIONS_FOR_AWS_CLI=("python3.7" "python3.8" "python3.8" "python3.9" "python3.9" "python3.10" "python3.10" "python3.11" "python3.11") +LAYER_NAMES=( + "Datadog-Python38" + "Datadog-Python38-ARM" + "Datadog-Python39" + "Datadog-Python39-ARM" + "Datadog-Python310" + "Datadog-Python310-ARM" + "Datadog-Python311" + "Datadog-Python311-ARM" + "Datadog-Python312" + "Datadog-Python312-ARM" + "Datadog-Python313" + "Datadog-Python313-ARM" +) +PYTHON_VERSIONS_FOR_AWS_CLI=( + "python3.8" + "python3.8" + "python3.9" + "python3.9" + "python3.10" + "python3.10" + "python3.11" + "python3.11" + "python3.12" + "python3.12" + "python3.13" + "python3.13" +) NEW_REGION=$1 publish_layer() { diff --git a/scripts/build_layers.sh b/scripts/build_layers.sh index 976ba5d1e..23941b7a0 100755 --- a/scripts/build_layers.sh +++ b/scripts/build_layers.sh @@ -7,14 +7,29 @@ # Builds datadog-lambda-python layers for Lambda functions -# Usage: PYTHON_VERSION=3.7 ./build_layers.sh +# Usage: PYTHON_VERSION=3.11 ./build_layers.sh # If PYTHON_VERSION is not specified, all versions will be built. set -e LAYER_DIR=".layers" LAYER_FILES_PREFIX="datadog_lambda_py" -AVAILABLE_PYTHON_VERSIONS=("3.7" "3.8" "3.9" "3.10" "3.11") +AVAILABLE_PYTHON_VERSIONS=("3.8" "3.9" "3.10" "3.11" "3.12" "3.13") +AVAILABLE_ARCHS=("arm64" "amd64") + +if [ -z "$ARCH" ]; then + echo "No architectures specified, building layers for all architectures." + ARCHS=("${AVAILABLE_ARCHS[@]}") +else + echo "Architecture specified: $ARCH" + if [[ ! " ${AVAILABLE_ARCHS[@]} " =~ " ${ARCH} " ]]; then + echo "Architecture $ARCH is not a valid option. Choose from: ${AVAILABLE_ARCHS[@]}" + echo "" + echo "EXITING SCRIPT." + exit 1 + fi + ARCHS=$ARCH +fi # Determine which Python versions to build layers for if [ -z "$PYTHON_VERSION" ]; then @@ -46,15 +61,11 @@ function docker_build_zip { # between different python runtimes. temp_dir=$(mktemp -d) docker buildx build -t datadog-lambda-python-${arch}:$1 . --no-cache \ - --build-arg image=python:$1 \ + --build-arg image=public.ecr.aws/sam/build-python$1:1 \ --build-arg runtime=python$1 \ --platform linux/${arch} \ - --load - - # Run the image by runtime tag and copy the output /build/python to the temp dir - dockerId=$(docker create datadog-lambda-python-${arch}:$1) - docker cp $dockerId:/build/python $temp_dir/python - + --progress=plain \ + -o $temp_dir/python # Zip to destination, and keep directory structure as based in $temp_dir (cd $temp_dir && zip -q -r $destination ./) @@ -68,12 +79,11 @@ mkdir $LAYER_DIR for python_version in "${PYTHON_VERSIONS[@]}" do - if [ "$python_version" != "3.7" ]; then - echo "Building layer for Python ${python_version} arch=arm64" - docker_build_zip ${python_version} $LAYER_DIR/${LAYER_FILES_PREFIX}-arm64-${python_version}.zip arm64 - fi - echo "Building layer for Python ${python_version} arch=amd64" - docker_build_zip ${python_version} $LAYER_DIR/${LAYER_FILES_PREFIX}-amd64-${python_version}.zip amd64 + for architecture in "${ARCHS[@]}" + do + echo "Building layer for Python ${python_version} arch=${architecture}" + docker_build_zip ${python_version} $LAYER_DIR/${LAYER_FILES_PREFIX}-${architecture}-${python_version}.zip ${architecture} + done done echo "Done creating layers:" diff --git a/scripts/check_layer_size.sh b/scripts/check_layer_size.sh index 5d8399087..ce67d92d9 100755 --- a/scripts/check_layer_size.sh +++ b/scripts/check_layer_size.sh @@ -7,33 +7,29 @@ # Compares layer size to threshold, and fails if below that threshold -# 7 mb size limit -MAX_LAYER_COMPRESSED_SIZE_KB=$(expr 7 \* 1024) -MAX_LAYER_UNCOMPRESSED_SIZE_KB=$(expr 24 \* 1024) +set -e +MAX_LAYER_COMPRESSED_SIZE_KB=$(expr 9 \* 1024) # 9216 KB +MAX_LAYER_UNCOMPRESSED_SIZE_KB=$(expr 25 \* 1024) # 25600 KB LAYER_FILES_PREFIX="datadog_lambda_py" LAYER_DIR=".layers" -VERSIONS=("3.7" "3.8" "3.9" "3.10" "3.11") -for version in "${VERSIONS[@]}" -do - FILE=$LAYER_DIR/${LAYER_FILES_PREFIX}-amd64-${version}.zip - FILE_SIZE=$(stat --printf="%s" $FILE) - FILE_SIZE_KB="$(( ${FILE_SIZE%% *} / 1024))" - echo "Layer file ${FILE} has zipped size ${FILE_SIZE_KB} kb" - if [ "$FILE_SIZE_KB" -gt "$MAX_LAYER_COMPRESSED_SIZE_KB" ]; then - echo "Zipped size exceeded limit $MAX_LAYER_COMPRESSED_SIZE_KB kb" - exit 1 - fi - mkdir tmp - unzip -q $FILE -d tmp - UNZIPPED_FILE_SIZE=$(du -shb tmp/ | cut -f1) - UNZIPPED_FILE_SIZE_KB="$(( ${UNZIPPED_FILE_SIZE%% *} / 1024))" - rm -rf tmp - echo "Layer file ${FILE} has unzipped size ${UNZIPPED_FILE_SIZE_KB} kb" - if [ "$UNZIPPED_FILE_SIZE_KB" -gt "$MAX_LAYER_UNCOMPRESSED_SIZE_KB" ]; then - echo "Unzipped size exceeded limit $MAX_LAYER_UNCOMPRESSED_SIZE_KB kb" - exit 1 - fi -done +FILE=$LAYER_DIR/${LAYER_FILES_PREFIX}-${ARCH}-${PYTHON_VERSION}.zip +FILE_SIZE=$(stat --printf="%s" $FILE) +FILE_SIZE_KB="$(( ${FILE_SIZE%% *} / 1024))" +echo "Layer file ${FILE} has zipped size ${FILE_SIZE_KB} kb" +if [ "$FILE_SIZE_KB" -gt "$MAX_LAYER_COMPRESSED_SIZE_KB" ]; then + echo "Zipped size exceeded limit $MAX_LAYER_COMPRESSED_SIZE_KB kb" + exit 1 +fi +mkdir tmp +unzip -q $FILE -d tmp +UNZIPPED_FILE_SIZE=$(du -shb tmp/ | cut -f1) +UNZIPPED_FILE_SIZE_KB="$(( ${UNZIPPED_FILE_SIZE%% *} / 1024))" +rm -rf tmp +echo "Layer file ${FILE} has unzipped size ${UNZIPPED_FILE_SIZE_KB} kb" +if [ "$UNZIPPED_FILE_SIZE_KB" -gt "$MAX_LAYER_UNCOMPRESSED_SIZE_KB" ]; then + echo "Unzipped size exceeded limit $MAX_LAYER_UNCOMPRESSED_SIZE_KB kb" + exit 1 +fi diff --git a/scripts/list_layers.sh b/scripts/list_layers.sh index c0b541afc..6449e5115 100755 --- a/scripts/list_layers.sh +++ b/scripts/list_layers.sh @@ -10,7 +10,20 @@ set -e -LAYER_NAMES=("Datadog-Python37" "Datadog-Python38" "Datadog-Python38-ARM" "Datadog-Python39" "Datadog-Python39-ARM" "Datadog-Python310" "Datadog-Python310-ARM" "Datadog-Python311" "Datadog-Python311-ARM") +LAYER_NAMES=( + "Datadog-Python38" + "Datadog-Python38-ARM" + "Datadog-Python39" + "Datadog-Python39-ARM" + "Datadog-Python310" + "Datadog-Python310-ARM" + "Datadog-Python311" + "Datadog-Python311-ARM" + "Datadog-Python312" + "Datadog-Python312-ARM" + "Datadog-Python313" + "Datadog-Python313-ARM" +) AVAILABLE_REGIONS=$(aws ec2 describe-regions | jq -r '.[] | .[] | .RegionName') LAYERS_MISSING_REGIONS=() diff --git a/scripts/publish_govcloud.sh b/scripts/publish_govcloud.sh new file mode 100755 index 000000000..5fd107b0e --- /dev/null +++ b/scripts/publish_govcloud.sh @@ -0,0 +1,105 @@ +#! /usr/bin/env bash + +# Unless explicitly stated otherwise all files in this repository are licensed +# under the Apache License Version 2.0. +# This product includes software developed at Datadog (https://www.datadoghq.com/). +# Copyright 2025 Datadog, Inc. +# +# USAGE: download the layer bundle from the build pipeline in gitlab. Use the +# Download button on the `layer bundle` job. This will be a zip file containing +# all of the required layers. Run this script as follows: +# +# ENVIRONMENT=[us1-staging-fed or us1-fed] [LAYER_NAME_SUFFIX=optional-layer-suffix] [REGIONS=us-gov-west-1] ./scripts/publish_govcloud.sh +# +# protip: you can drag the zip file from finder into your terminal to insert +# its path. + +set -e + +LAYER_PACKAGE=$1 + +if [ -z "$LAYER_PACKAGE" ]; then + printf "[ERROR]: layer package not provided\n" + exit 1 +fi + +PACKAGE_NAME=$(basename "$LAYER_PACKAGE" .zip) + +if [ -z "$ENVIRONMENT" ]; then + printf "[ERROR]: ENVIRONMENT not specified\n" + exit 1 +fi + +if [ "$ENVIRONMENT" = "us1-staging-fed" ]; then + AWS_VAULT_ROLE=sso-govcloud-us1-staging-fed-power-user + + export STAGE=gov-staging + + if [[ ! "$PACKAGE_NAME" =~ ^datadog_lambda_py-(signed-)?bundle-[0-9]+$ ]]; then + echo "[ERROR]: Unexpected package name: $PACKAGE_NAME" + exit 1 + fi + +elif [ $ENVIRONMENT = "us1-fed" ]; then + AWS_VAULT_ROLE=sso-govcloud-us1-fed-engineering + + export STAGE=gov-prod + + if [[ ! "$PACKAGE_NAME" =~ ^datadog_lambda_py-signed-bundle-[0-9]+$ ]]; then + echo "[ERROR]: Unexpected package name: $PACKAGE_NAME" + exit 1 + fi + +else + printf "[ERROR]: ENVIRONMENT not supported, must be us1-staging-fed or us1-fed.\n" + exit 1 +fi + +TEMP_DIR=$(mktemp -d) +unzip $LAYER_PACKAGE -d $TEMP_DIR +cp -v $TEMP_DIR/$PACKAGE_NAME/*.zip .layers/ + + +AWS_VAULT_PREFIX="aws-vault exec $AWS_VAULT_ROLE --" + +echo "Checking that you have access to the GovCloud AWS account" +$AWS_VAULT_PREFIX aws sts get-caller-identity + + +AVAILABLE_REGIONS=$($AWS_VAULT_PREFIX aws ec2 describe-regions | jq -r '.[] | .[] | .RegionName') + +# Determine the target regions +if [ -z "$REGIONS" ]; then + echo "Region not specified, running for all available regions." + REGIONS=$AVAILABLE_REGIONS +else + echo "Region specified: $REGIONS" + if [[ ! "$AVAILABLE_REGIONS" == *"$REGIONS"* ]]; then + echo "Could not find $REGIONS in available regions: $AVAILABLE_REGIONS" + echo "" + echo "EXITING SCRIPT." + exit 1 + fi +fi + +for region in $REGIONS +do + echo "Starting publishing layers for region $region..." + + export REGION=$region + + for python_version in "3.8" "3.9" "3.10" "3.11" "3.12" "3.13"; do + for arch in "amd64" "arm64"; do + export PYTHON_VERSION=$python_version + export ARCH=$arch + + export SKIP_PIP_INSTALL=true + + echo "Publishing layer for $PYTHON_VERSION and $ARCH" + + $AWS_VAULT_PREFIX ./ci/publish_layers.sh + done + done +done + +echo "Done !" diff --git a/scripts/publish_layers.sh b/scripts/publish_layers.sh index bd8d3a7e8..8c78093f8 100755 --- a/scripts/publish_layers.sh +++ b/scripts/publish_layers.sh @@ -13,10 +13,48 @@ set -e # Makes sure any subprocesses will be terminated with this process trap "pkill -P $$; exit 1;" INT -PYTHON_VERSIONS_FOR_AWS_CLI=("python3.7" "python3.8" "python3.8" "python3.9" "python3.9" "python3.10" "python3.10" "python3.11" "python3.11") -LAYER_PATHS=(".layers/datadog_lambda_py-amd64-3.7.zip" ".layers/datadog_lambda_py-amd64-3.8.zip" ".layers/datadog_lambda_py-arm64-3.8.zip" ".layers/datadog_lambda_py-amd64-3.9.zip" ".layers/datadog_lambda_py-arm64-3.9.zip" ".layers/datadog_lambda_py-amd64-3.10.zip" ".layers/datadog_lambda_py-arm64-3.10.zip" ".layers/datadog_lambda_py-amd64-3.11.zip" ".layers/datadog_lambda_py-arm64-3.11.zip") -AVAILABLE_LAYERS=("Datadog-Python37" "Datadog-Python38" "Datadog-Python38-ARM" "Datadog-Python39" "Datadog-Python39-ARM" "Datadog-Python310" "Datadog-Python310-ARM" "Datadog-Python311" "Datadog-Python311-ARM") -ARCHS=("amd64" "amd64" "amd64""amd64" "amd64" "arm64" "amd64" "arm64" "amd64" "arm64") +PYTHON_VERSIONS_FOR_AWS_CLI=( + "python3.8" + "python3.8" + "python3.9" + "python3.9" + "python3.10" + "python3.10" + "python3.11" + "python3.11" + "python3.12" + "python3.12" + "python3.13" + "python3.13" +) +LAYER_PATHS=( + ".layers/datadog_lambda_py-amd64-3.8.zip" + ".layers/datadog_lambda_py-arm64-3.8.zip" + ".layers/datadog_lambda_py-amd64-3.9.zip" + ".layers/datadog_lambda_py-arm64-3.9.zip" + ".layers/datadog_lambda_py-amd64-3.10.zip" + ".layers/datadog_lambda_py-arm64-3.10.zip" + ".layers/datadog_lambda_py-amd64-3.11.zip" + ".layers/datadog_lambda_py-arm64-3.11.zip" + ".layers/datadog_lambda_py-amd64-3.12.zip" + ".layers/datadog_lambda_py-arm64-3.12.zip" + ".layers/datadog_lambda_py-amd64-3.13.zip" + ".layers/datadog_lambda_py-arm64-3.13.zip" +) +AVAILABLE_LAYERS=( + "Datadog-Python38" + "Datadog-Python38-ARM" + "Datadog-Python39" + "Datadog-Python39-ARM" + "Datadog-Python310" + "Datadog-Python310-ARM" + "Datadog-Python311" + "Datadog-Python311-ARM" + "Datadog-Python312" + "Datadog-Python312-ARM" + "Datadog-Python313" + "Datadog-Python313-ARM" +) AVAILABLE_REGIONS=$(aws ec2 describe-regions | jq -r '.[] | .[] | .RegionName') BATCH_SIZE=60 diff --git a/scripts/publish_prod.sh b/scripts/publish_prod.sh index e8838c5a1..d2918c544 100755 --- a/scripts/publish_prod.sh +++ b/scripts/publish_prod.sh @@ -4,6 +4,13 @@ set -e +read -p "Are we only doing the simplified GovCloud release? ONLY IF THE NORMAL RELEASE IS DONE AND YOU HAVE DOWNLOADED THE LAYERS (y/n)? " GOVCLOUD_ONLY + +if [ $GOVCLOUD_ONLY != "n" ]; then + echo "GovCloud publishing is now supported only in publich_govcloud.sh" + exit 1 +fi + # Ensure on main, and pull the latest BRANCH=$(git rev-parse --abbrev-ref HEAD) if [ $BRANCH != "main" ]; then @@ -31,11 +38,6 @@ else NEW_VERSION=$1 fi -# Ensure AWS access before proceeding -ddsaml2aws login -a govcloud-us1-fed-human-engineering -AWS_PROFILE=govcloud-us1-fed-human-engineering aws sts get-caller-identity -aws-vault exec sso-prod-engineering -- aws sts get-caller-identity - # Ensure pypi registry access read -p "Do you have access to PyPI (y/n)?" CONT if [ "$CONT" != "y" ]; then @@ -52,11 +54,18 @@ if [ "$CONT" != "y" ]; then exit 1 fi -echo -echo "Replacing version in pyproject.toml" -echo +echo "Answer 'n' if already done in a PR" +read -p "Update pyproject.toml version? (y/n)?" CONT +if [ "$CONT" != "y" ]; then + echo "Skipping updating package.json version" +else + echo + echo "Replacing version in pyproject.toml and datadog_lambda/version.py" + echo -poetry version ${NEW_VERSION} + poetry version ${NEW_VERSION} + echo "__version__ = \"${NEW_VERSION}\"" > datadog_lambda/version.py +fi echo echo "Building layers..." @@ -66,33 +75,46 @@ echo echo "Signing layers for commercial AWS regions" aws-vault exec sso-prod-engineering -- ./scripts/sign_layers.sh prod -echo -echo "Publishing layers to commercial AWS regions" -VERSION=$LAYER_VERSION aws-vault exec sso-prod-engineering -- ./scripts/publish_layers.sh +echo "Answer 'n' if GitLab already did this" +read -p "Deploy layers to commercial AWS (y/n)?" CONT +if [ "$CONT" != "y" ]; then + echo "Skipping deployment to commercial AWS" +else + echo "Ensuring you have access to the production AWS account" + aws-vault exec sso-prod-engineering -- aws sts get-caller-identity -echo "Publishing layers to GovCloud AWS regions" -ddsaml2aws login -a govcloud-us1-fed-human-engineering -VERSION=$LAYER_VERSION AWS_PROFILE=govcloud-us1-fed-human-engineering ./scripts/publish_layers.sh + echo + echo "Publishing layers to commercial AWS regions" + VERSION=$LAYER_VERSION aws-vault exec sso-prod-engineering --no-session -- ./scripts/publish_layers.sh +fi +echo "Answer 'n' if GitLab already did this" read -p "Ready to publish $NEW_VERSION to PyPI (y/n)?" CONT if [ "$CONT" != "y" ]; then - echo "Exiting" - exit 1 + echo "Skipping publishing to PyPI" +else + echo + echo "Publishing to https://pypi.org/project/datadog-lambda/" + ./scripts/pypi.sh fi -echo -echo "Publishing to https://pypi.org/project/datadog-lambda/" -./scripts/pypi.sh -echo -echo 'Publishing updates to github' -git commit pyproject.toml -m "Bump version to ${NEW_VERSION}" -git push origin main -git tag "v$LAYER_VERSION" -git push origin "refs/tags/v$LAYER_VERSION" +echo "Answer 'n' if you already released in GitHub" +read -p "Do you want to bump the version in GitHub? (y/n)" CONT +if [ "$CONT" != "y" ]; then + echo "Skipping publishing updates to GitHub" +else + echo + echo 'Publishing updates to github' + git commit pyproject.toml datadog_lambda/version.py -m "Bump version to ${NEW_VERSION}" + git push origin main + git tag "v$LAYER_VERSION" + git push origin "refs/tags/v$LAYER_VERSION" +fi echo -echo "Now create a new release with the tag v${LAYER_VERSION} created" +echo "Now create a new release with the tag v${LAYER_VERSION} created unless you have done this already" echo "https://github.com/DataDog/datadog-lambda-python/releases/new?tag=v$LAYER_VERSION&title=v$LAYER_VERSION" + # Open a PR to the documentation repo to automatically bump layer version VERSION=$LAYER_VERSION LAYER=datadog-lambda-python ./scripts/create_documentation_pr.sh diff --git a/scripts/run_integration_tests.sh b/scripts/run_integration_tests.sh index ebda6fded..f6e4f537c 100755 --- a/scripts/run_integration_tests.sh +++ b/scripts/run_integration_tests.sh @@ -2,16 +2,15 @@ # Usage - run commands from repo root: # To check if new changes to the layer cause changes to any snapshots: -# BUILD_LAYERS=true DD_API_KEY=XXXX aws-vault exec sso-serverless-sandbox-account-admin -- ./scripts/run_integration_tests +# BUILD_LAYERS=true DD_API_KEY=XXXX aws-vault exec sso-serverless-sandbox-account-admin -- ./scripts/run_integration_tests.sh # To regenerate snapshots: -# UPDATE_SNAPSHOTS=true DD_API_KEY=XXXX aws-vault exec sso-serverless-sandbox-account-admin -- ./scripts/run_integration_tests +# UPDATE_SNAPSHOTS=true DD_API_KEY=XXXX aws-vault exec sso-serverless-sandbox-account-admin -- ./scripts/run_integration_tests.sh set -e # These values need to be in sync with serverless.yml, where there needs to be a function # defined for every handler_runtime combination LAMBDA_HANDLERS=("async-metrics" "sync-metrics") -RUNTIMES=("python37" "python38" "python39" "python310" "python311") LOGS_WAIT_SECONDS=20 @@ -28,13 +27,14 @@ mismatch_found=false # [0]: serverless runtime name # [1]: python version # [2]: random 8-character ID to avoid collisions with other runs -python37=("python3.7" "3.7" $(xxd -l 4 -c 4 -p < /dev/random)) python38=("python3.8" "3.8" $(xxd -l 4 -c 4 -p < /dev/random)) python39=("python3.9" "3.9" $(xxd -l 4 -c 4 -p < /dev/random)) python310=("python3.10" "3.10" $(xxd -l 4 -c 4 -p < /dev/random)) python311=("python3.11" "3.11" $(xxd -l 4 -c 4 -p < /dev/random)) +python312=("python3.12" "3.12" $(xxd -l 4 -c 4 -p < /dev/random)) +python313=("python3.13" "3.13" $(xxd -l 4 -c 4 -p < /dev/random)) -PARAMETERS_SETS=("python37" "python38" "python39" "python310" "python311") +PARAMETERS_SETS=("python38" "python39" "python310" "python311" "python312" "python313") if [ -z "$RUNTIME_PARAM" ]; then echo "Python version not specified, running for all python versions." @@ -57,6 +57,11 @@ if [ -z "$DD_API_KEY" ]; then exit 1 fi +if [ -z "$ARCH" ]; then + echo "No ARCH env var set, exiting" + exit 1 +fi + if [ -n "$UPDATE_SNAPSHOTS" ]; then echo "Overwriting snapshots in this execution" fi @@ -72,6 +77,12 @@ else echo "Not building layers, ensure they've already been built or re-run with 'BUILD_LAYERS=true DD_API_KEY=XXXX ./scripts/run_integration_tests.sh'" fi +SERVERLESS_FRAMEWORK_ARCH="" +if [ "$ARCH" = "amd64" ]; then + SERVERLESS_FRAMEWORK_ARCH="x86_64" +else + SERVERLESS_FRAMEWORK_ARCH="arm64" +fi cd $integration_tests_dir input_event_files=$(ls ./input_events) @@ -85,13 +96,11 @@ function remove_stack() { python_version=$parameters_set[1] run_id=$parameters_set[2] echo "Removing stack for stage : ${!run_id}" - PYTHON_VERSION=${!python_version} RUNTIME=$parameters_set SERVERLESS_RUNTIME=${!serverless_runtime} \ + PYTHON_VERSION=${!python_version} RUNTIME=$parameters_set SERVERLESS_RUNTIME=${!serverless_runtime} SLS_ARCH=${SERVERLESS_FRAMEWORK_ARCH} \ serverless remove --stage ${!run_id} done } - - trap remove_stack EXIT for parameters_set in "${PARAMETERS_SETS[@]}"; do serverless_runtime=$parameters_set[0] @@ -101,7 +110,7 @@ for parameters_set in "${PARAMETERS_SETS[@]}"; do echo "Deploying functions for runtime : $parameters_set, serverless runtime : ${!serverless_runtime}, \ python version : ${!python_version} and run id : ${!run_id}" - PYTHON_VERSION=${!python_version} RUNTIME=$parameters_set SERVERLESS_RUNTIME=${!serverless_runtime} \ + PYTHON_VERSION=${!python_version} RUNTIME=$parameters_set SERVERLESS_RUNTIME=${!serverless_runtime} ARCH=${ARCH} SLS_ARCH=${SERVERLESS_FRAMEWORK_ARCH} \ serverless deploy --stage ${!run_id} echo "Invoking functions for runtime $parameters_set" @@ -115,7 +124,7 @@ python version : ${!python_version} and run id : ${!run_id}" input_event_name=$(echo "$input_event_file" | sed "s/.json//") snapshot_path="./snapshots/return_values/${handler_name}_${input_event_name}.json" - return_value=$(PYTHON_VERSION=${!python_version} RUNTIME=$parameters_set SERVERLESS_RUNTIME=${!serverless_runtime} \ + return_value=$(PYTHON_VERSION=${!python_version} RUNTIME=$parameters_set SERVERLESS_RUNTIME=${!serverless_runtime} SLS_ARCH=${SERVERLESS_FRAMEWORK_ARCH} \ serverless invoke --stage ${!run_id} -f "$function_name" --path "./input_events/$input_event_file") if [ ! -f $snapshot_path ]; then @@ -157,7 +166,7 @@ for handler_name in "${LAMBDA_HANDLERS[@]}"; do # Fetch logs with serverless cli, retrying to avoid AWS account-wide rate limit error retry_counter=0 while [ $retry_counter -lt 10 ]; do - raw_logs=$(PYTHON_VERSION=${!python_version} RUNTIME=$parameters_set SERVERLESS_RUNTIME=${!serverless_runtime} \ + raw_logs=$(PYTHON_VERSION=${!python_version} RUNTIME=$parameters_set SERVERLESS_RUNTIME=${!serverless_runtime} ARCH=${ARCH} SLS_ARCH=${SERVERLESS_FRAMEWORK_ARCH} \ serverless logs --stage ${!run_id} -f $function_name --startTime $script_utc_start_time) fetch_logs_exit_code=$? if [ $fetch_logs_exit_code -eq 1 ]; then @@ -203,6 +212,8 @@ for handler_name in "${LAMBDA_HANDLERS[@]}"; do sed -E "s/(datadog_lambda:v)([0-9]+\.[0-9]+\.[0-9]+)/\1XX/g" | sed -E "s/(datadogpy\/)([0-9]+\.[0-9]+\.[0-9]+)/\1XX/g" | sed -E "s/(python )([0-9]\.[0-9]+\.[0-9]+)/\1XX/g" | + # Remove .devN versioning from logs + sed -E "s/\.dev[0-9]+//g" | # Strip out run ID (from function name, resource, etc.) sed -E "s/${!run_id}/XXXX/g" | # Normalize python-requests version @@ -239,6 +250,7 @@ for handler_name in "${LAMBDA_HANDLERS[@]}"; do sed -E "s/(tracestate\:)([A-Za-z0-9\-\=\:\;].+)/\1XXX/g" | sed -E "s/(\"_dd.p.tid\"\: \")[a-z0-9\.\-]+/\1XXXX/g" | sed -E "s/(_dd.p.tid=)[a-z0-9\.\-]+/\1XXXX/g" | + sed -E 's/arch (aarch64|x86_64)/arch XXXX/g' | # Parse out account ID in ARN sed -E "s/([a-zA-Z0-9]+):([a-zA-Z0-9]+):([a-zA-Z0-9]+):([a-zA-Z0-9\-]+):([a-zA-Z0-9\-\:]+)/\1:\2:\3:\4:XXXX:\4/g" | sed -E "/init complete at epoch/d" | diff --git a/scripts/run_tests.sh b/scripts/run_tests.sh index 193a6d001..26f4e2156 100755 --- a/scripts/run_tests.sh +++ b/scripts/run_tests.sh @@ -8,7 +8,7 @@ # Run unit tests in Docker set -e -PYTHON_VERSIONS=("3.7" "3.8" "3.9" "3.10" "3.11") +PYTHON_VERSIONS=("3.8" "3.9" "3.10" "3.11" "3.12" "3.13") for python_version in "${PYTHON_VERSIONS[@]}" do @@ -18,7 +18,7 @@ do --build-arg python_version=$python_version docker run -w /test \ datadog-lambda-python-test:$python_version \ - nose2 -v + pytest -vv docker run -w /test \ datadog-lambda-python-test:$python_version \ flake8 datadog_lambda/ diff --git a/scripts/sign_layers.sh b/scripts/sign_layers.sh index 3c9aa6628..eb40062f0 100755 --- a/scripts/sign_layers.sh +++ b/scripts/sign_layers.sh @@ -9,7 +9,6 @@ set -e LAYER_DIR=".layers" LAYER_FILES=( - "datadog_lambda_py-amd64-3.7.zip" "datadog_lambda_py-amd64-3.8.zip" "datadog_lambda_py-arm64-3.8.zip" "datadog_lambda_py-amd64-3.9.zip" @@ -18,6 +17,10 @@ LAYER_FILES=( "datadog_lambda_py-arm64-3.10.zip" "datadog_lambda_py-amd64-3.11.zip" "datadog_lambda_py-arm64-3.11.zip" + "datadog_lambda_py-amd64-3.12.zip" + "datadog_lambda_py-arm64-3.12.zip" + "datadog_lambda_py-amd64-3.13.zip" + "datadog_lambda_py-arm64-3.13.zip" ) SIGNING_PROFILE_NAME="DatadogLambdaSigningProfile" @@ -40,6 +43,18 @@ if [ "$1" = "prod" ]; then S3_BUCKET_NAME="dd-lambda-signing-bucket" fi +if [ -z "$LAYER_FILE" ]; then + echo "Layer file not specified, running for all layer files." +else + echo "Layer file is specified: $LAYER_FILE" + if (printf '%s\n' "${LAYER_FILES[@]}" | grep -xq $LAYER_FILE); then + LAYER_FILES=($LAYER_FILE) + else + echo "Unsupported layer found, valid options are : ${LAYER_FILES[@]}" + exit 1 + fi +fi + for LAYER_FILE in "${LAYER_FILES[@]}" do echo diff --git a/tests/Dockerfile b/tests/Dockerfile index 948de1bcd..585c0fbe0 100644 --- a/tests/Dockerfile +++ b/tests/Dockerfile @@ -1,8 +1,13 @@ ARG python_version -FROM python:$python_version +FROM public.ecr.aws/docker/library/python:$python_version ENV PYTHONDONTWRITEBYTECODE True +# Add Rust compiler which is needed to build dd-trace-py from source +RUN curl https://sh.rustup.rs -sSf | \ + sh -s -- --default-toolchain stable -y +ENV PATH=/root/.cargo/bin:$PATH + RUN mkdir -p /test/datadog_lambda WORKDIR /test diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 000000000..338698025 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,8 @@ +import pytest + +from datadog_lambda.config import config + + +@pytest.fixture(autouse=True) +def reset_config(): + config._reset() diff --git a/tests/event_samples/api-gateway-v1-parametrized.json b/tests/event_samples/api-gateway-v1-parametrized.json new file mode 100644 index 000000000..65527ccb6 --- /dev/null +++ b/tests/event_samples/api-gateway-v1-parametrized.json @@ -0,0 +1,111 @@ +{ + "resource": "/user/{id}", + "path": "/user/42", + "httpMethod": "GET", + "headers": { + "Accept": "*/*", + "CloudFront-Forwarded-Proto": "https", + "CloudFront-Is-Desktop-Viewer": "true", + "CloudFront-Is-Mobile-Viewer": "false", + "CloudFront-Is-SmartTV-Viewer": "false", + "CloudFront-Is-Tablet-Viewer": "false", + "CloudFront-Viewer-ASN": "7922", + "CloudFront-Viewer-Country": "US", + "Host": "mcwkra0ya4.execute-api.sa-east-1.amazonaws.com", + "User-Agent": "curl/8.1.2", + "Via": "2.0 xxx.cloudfront.net (CloudFront)", + "X-Amz-Cf-Id": "Tz3yUVcJkwOhQGqZgKTzrEHqAoOd8ZprYAHpg2S6BNxdd-Ym79pb6g==", + "X-Amzn-Trace-Id": "Root=1-65f49d20-7ba106216238dd0078a5db31", + "X-Forwarded-For": "76.115.124.192, 15.158.54.119", + "X-Forwarded-Port": "443", + "X-Forwarded-Proto": "https" + }, + "multiValueHeaders": { + "Accept": [ + "*/*" + ], + "CloudFront-Forwarded-Proto": [ + "https" + ], + "CloudFront-Is-Desktop-Viewer": [ + "true" + ], + "CloudFront-Is-Mobile-Viewer": [ + "false" + ], + "CloudFront-Is-SmartTV-Viewer": [ + "false" + ], + "CloudFront-Is-Tablet-Viewer": [ + "false" + ], + "CloudFront-Viewer-ASN": [ + "7922" + ], + "CloudFront-Viewer-Country": [ + "US" + ], + "Host": [ + "mcwkra0ya4.execute-api.sa-east-1.amazonaws.com" + ], + "User-Agent": [ + "curl/8.1.2" + ], + "Via": [ + "2.0 xxx.cloudfront.net (CloudFront)" + ], + "X-Amz-Cf-Id": [ + "Tz3yUVcJkwOhQGqZgKTzrEHqAoOd8ZprYAHpg2S6BNxdd-Ym79pb6g==" + ], + "X-Amzn-Trace-Id": [ + "Root=1-65f49d20-7ba106216238dd0078a5db31" + ], + "X-Forwarded-For": [ + "76.115.124.192, 15.158.54.119" + ], + "X-Forwarded-Port": [ + "443" + ], + "X-Forwarded-Proto": [ + "https" + ] + }, + "queryStringParameters": null, + "multiValueQueryStringParameters": null, + "pathParameters": { + "id": "42" + }, + "stageVariables": null, + "requestContext": { + "resourceId": "ojg3nk", + "resourcePath": "/user/{id}", + "httpMethod": "GET", + "extendedRequestId": "Ur19IHYDmjQEU5A=", + "requestTime": "15/Mar/2024:19:10:24 +0000", + "path": "/dev/user/42", + "accountId": "425362996713", + "protocol": "HTTP/1.1", + "stage": "dev", + "domainPrefix": "mcwkra0ya4", + "requestTimeEpoch": 1710529824520, + "requestId": "e16399f7-e984-463a-9931-745ba021a27f", + "identity": { + "cognitoIdentityPoolId": null, + "accountId": null, + "cognitoIdentityId": null, + "caller": null, + "sourceIp": "76.115.124.192", + "principalOrgId": null, + "accessKey": null, + "cognitoAuthenticationType": null, + "cognitoAuthenticationProvider": null, + "userArn": null, + "userAgent": "curl/8.1.2", + "user": null + }, + "domainName": "mcwkra0ya4.execute-api.sa-east-1.amazonaws.com", + "apiId": "mcwkra0ya4" + }, + "body": null, + "isBase64Encoded": false +} diff --git a/tests/event_samples/api-gateway-v2-parametrized.json b/tests/event_samples/api-gateway-v2-parametrized.json new file mode 100644 index 000000000..89ff72b9c --- /dev/null +++ b/tests/event_samples/api-gateway-v2-parametrized.json @@ -0,0 +1,38 @@ +{ + "version": "2.0", + "routeKey": "GET /user/{id}", + "rawPath": "/user/42", + "rawQueryString": "", + "headers": { + "accept": "*/*", + "content-length": "0", + "host": "9vj54we5ih.execute-api.sa-east-1.amazonaws.com", + "user-agent": "curl/8.1.2", + "x-amzn-trace-id": "Root=1-65f49d71-505edb3b69b8abd513cfa08b", + "x-forwarded-for": "76.115.124.192", + "x-forwarded-port": "443", + "x-forwarded-proto": "https" + }, + "requestContext": { + "accountId": "425362996713", + "apiId": "9vj54we5ih", + "domainName": "9vj54we5ih.execute-api.sa-east-1.amazonaws.com", + "domainPrefix": "9vj54we5ih", + "http": { + "method": "GET", + "path": "/user/42", + "protocol": "HTTP/1.1", + "sourceIp": "76.115.124.192", + "userAgent": "curl/8.1.2" + }, + "requestId": "Ur2JtjEfGjQEPOg=", + "routeKey": "GET /user/{id}", + "stage": "$default", + "time": "15/Mar/2024:19:11:45 +0000", + "timeEpoch": 1710529905066 + }, + "pathParameters": { + "id": "42" + }, + "isBase64Encoded": false +} diff --git a/tests/event_samples/application-load-balancer-multivalue-headers.json b/tests/event_samples/application-load-balancer-multivalue-headers.json new file mode 100644 index 000000000..a35ca5023 --- /dev/null +++ b/tests/event_samples/application-load-balancer-multivalue-headers.json @@ -0,0 +1,31 @@ +{ + "requestContext": { + "elb": { + "targetGroupArn": "arn:aws:elasticloadbalancing:us-east-2:123456789012:targetgroup/lambda-xyz/123abc" + } + }, + "httpMethod": "GET", + "path": "/lambda", + "multiValueQueryStringParameters": { + "query": "1234ABCD" + }, + "multiValueHeaders": { + "accept": ["text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8"], + "accept-encoding": ["gzip"], + "accept-language": ["en-US,en;q=0.9"], + "connection": ["keep-alive"], + "host": ["lambda-alb-123578498.us-east-2.elb.amazonaws.com"], + "upgrade-insecure-requests": ["1"], + "user-agent": ["Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36"], + "x-amzn-trace-id": ["Root=1-5c536348-3d683b8b04734faae651f476"], + "x-forwarded-for": ["72.12.164.125"], + "x-forwarded-port": ["80"], + "x-forwarded-proto": ["http"], + "x-imforwards": ["20"], + "x-datadog-trace-id": ["12345"], + "x-datadog-parent-id": ["67890"], + "x-datadog-sampling-priority": ["2"] + }, + "body": "", + "isBase64Encoded": false +} diff --git a/tests/event_samples/kinesisStream.json b/tests/event_samples/kinesisStream.json new file mode 100644 index 000000000..a320fc44f --- /dev/null +++ b/tests/event_samples/kinesisStream.json @@ -0,0 +1,20 @@ +{ + "Records": [ + { + "kinesis": { + "kinesisSchemaVersion": "1.0", + "partitionKey": "partitionkey", + "sequenceNumber": "49624230154685806402418173680709770494154422022871973922", + "data": "eyJmb28iOiAiYmFyIiwgIl9kYXRhZG9nIjogeyJ4LWRhdGFkb2ctdHJhY2UtaWQiOiAiNDk0ODM3NzMxNjM1NzI5MTQyMSIsICJ4LWRhdGFkb2ctcGFyZW50LWlkIjogIjI4NzYyNTMzODAwMTg2ODEwMjYiLCAieC1kYXRhZG9nLXNhbXBsaW5nLXByaW9yaXR5IjogIjEifX0=", + "approximateArrivalTimestamp": 1643638425.163 + }, + "eventSource": "aws:kinesis", + "eventVersion": "1.0", + "eventID": "shardId-000000000002:49624230154685806402418173680709770494154422022871973922", + "eventName": "aws:kinesis:record", + "invokeIdentityArn": "arn:aws:iam::601427279990:role/inferred-spans-python-dev-eu-west-1-lambdaRole", + "awsRegion": "eu-west-1", + "eventSourceARN": "arn:aws:kinesis:eu-west-1:601427279990:stream/kinesisStream" + } + ] +} diff --git a/tests/event_samples/rum-appsync-no-headers.json b/tests/event_samples/rum-appsync-no-headers.json new file mode 100644 index 000000000..ce42c9722 --- /dev/null +++ b/tests/event_samples/rum-appsync-no-headers.json @@ -0,0 +1,14 @@ +{ + "identity": "None", + "info": { + "fieldName": "getItems", + "parentTypeName": "Query", + "selectionSetGraphQL": "{\n id\n}", + "selectionSetList":["id"] + }, + "prev": "None", + "request": { + "domainName": "None" + }, + "source": "None" +} \ No newline at end of file diff --git a/tests/event_samples/rum-appsync-request-not-dict.json b/tests/event_samples/rum-appsync-request-not-dict.json new file mode 100644 index 000000000..1ab6dba82 --- /dev/null +++ b/tests/event_samples/rum-appsync-request-not-dict.json @@ -0,0 +1,12 @@ +{ + "identity": "None", + "info": { + "fieldName": "getItems", + "parentTypeName": "Query", + "selectionSetGraphQL": "{\n id\n}", + "selectionSetList":["id"] + }, + "prev": "None", + "request": "hello", + "source": "None" +} \ No newline at end of file diff --git a/tests/event_samples/rum-appsync.json b/tests/event_samples/rum-appsync.json new file mode 100644 index 000000000..ae085359f --- /dev/null +++ b/tests/event_samples/rum-appsync.json @@ -0,0 +1,53 @@ +{ + "identity": "None", + "info": { + "fieldName": "getItems", + "parentTypeName": "Query", + "selectionSetGraphQL": "{\n id\n}", + "selectionSetList":["id"] + }, + "prev": "None", + "request": { + "domainName": "None", + "headers": { + "accept": "*/*", + "accept-encoding": "gzip, deflate, br, zstd", + "accept-language": "en-US,en;q=0.9", + "cloudfront-forwarded-proto": "https", + "cloudfront-is-desktop-viewer": "True", + "cloudfront-is-mobile-viewer": "False", + "cloudfront-is-smarttv-viewer":"False", + "cloudfront-is-tablet-viewer":" False", + "cloudfront-viewer-asn": "6461", + "cloudfront-viewer-country": "US", + "content-length": "47", + "content-type": "application/graphql", + "host": "4aowrg2uhvbw5mn7osu6searqi.appsync-api.us-east-1.amazonaws.com", + "origin": "http://localhost:5173/", + "priority": "u=1, i", + "referer": "http://localhost:5173/", + "sec-ch-ua": "\"Chromium\";v=\"140\", \"Not=A?Brand\";v=\"24\", \"Google Chrome\";v=\"140\"", + "sec-ch-ua-mobile": "?0", + "sec-ch-ua-platform": "macOS", + "sec-fetch-dest": "empty", + "sec-fetch-mode": "cors", + "sec-fetch-site": "cross-site", + "traceparent": "00-0000000000000000d9f454c80b9a529a-73ac6ca3427073a3-01", + "tracestate": "dd=s:1;o:rum", + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36","via":"2.0 62f9f3967e93a923f21c8acb20cf10b6.cloudfront.net (CloudFront)", + "x-amz-cf-id": "Femhicb_Vbva-J8qWjdI4hKMmqusCeQSp207UGyY3u8VOUrdE8BBvg==", + "x-amzn-appsync-is-vpce-request": "False", + "x-amzn-remote-ip": "64.124.12.19", + "x-amzn-requestid": "1ee1669a-eda3-4d4f-911c-35f74ebef31d", + "x-amzn-trace-id": "Root=1-68cdb7e9-438bf88259d7ce3535723bdd", + "x-datadog-origin": "rum", + "x-datadog-parent-id": "67890", + "x-datadog-sampling-priority": "1", + "x-datadog-trace-id": "12345", + "x-forwarded-for": "64.124.12.19,15.158.225.229", + "x-forwarded-port": "443", + "x-forwarded-proto": "https" + } + }, + "source": "None" +} \ No newline at end of file diff --git a/tests/event_samples/sns-sqs-java-upstream.json b/tests/event_samples/sns-sqs-java-upstream.json new file mode 100644 index 000000000..bef072c3c --- /dev/null +++ b/tests/event_samples/sns-sqs-java-upstream.json @@ -0,0 +1,32 @@ +{ + "Records": [ + { + "messageId": "892f0033-3a4e-4d61-9e26-70d6f7901cd5", + "receiptHandle": "AQEBa1vYusKmlcrFsXDOh8/il3nFWZt+cGeLSU7cjEEpF+N4dPfHzkFpVXKEZebtXbUGyJ18lpBpRtXMpbL7gNukCv3z3Uj61NQbwTTabhsX0Y0iAbh2TSTNgaC/egNVbl3mwDjtXhmIvQIA8Zzzl4AqIlS7a76QiTeTVAjLb1c2FtJYq+znDb52GNPzZ62fSJtDpjfhFEkHwL+w23NQo/Yx4rCmaygR/F7/5hOFtsOwERpTFBei7fDM0z87HVT0nLkqvtg9wyM1kKSsMX8ltjdI3cwFSMs9aTMGFA3uAee6JKswkMp0HCXxNZZ8lp3T9wdQTBUwS8y01vMxl9e0qtYwUpakBYfdlmGHDIbZGEsf59ZpLYlUek0iFl0pdW+5LquNvlA2hA/J9ENpxJYHN4eguTNwRxxpEyzSwmfNXgukgRqDmcZT84UY9GkeaGJ2f2jfyCE525sqB2CAPcK7zx9MZ2Jt/UxsbX5APdX4skXDgck=", + "body": { + "Type": "Notification", + "MessageId": "6dacdb4e-f8dd-5752-9f49-858ee02bcd55", + "TopicArn": "arn:aws:sns:us-west-2:425362996713:DdTraceXLambda-snssqschecksNestedStacksnssqschecksNestedStackResource58F786C6-11NORKTA1JFML-snsProducerJavaForPythonNonRawsnssqsproducerjavaforpythonnonrawtopicDDBAB6EA-ZBb8uCZzkS0S", + "Message": "hello from DdTraceXLambda-snssqschec-snssqsproducerjavaforpyt-z0t7yDk3zWt1", + "Timestamp": "2024-05-16T14:22:46.902Z", + "SignatureVersion": "1", + "Signature": "HBf+KLJg/1Crvg3T5a8jJwVwIjmiNe1jEZ1QXOw11x8At/nqXUrevdm/j8KR33w4gmW/MG6WPpafH8K5k+M+tmn8Mr4sWfJhzsfV4in8s6qbbesBCVL5TsGkfauBfSeOkvrH+2/MAnexUx1m28m+qLJyeTzozelT9IdEhm1ATg5bASeVQS3mFTWYvnO4DoJdMSS9O15ZUQSitjhB8Lv5/DRLKGIYYwhAqOVBVKBfbEbz/BbaI47dqu+uarxL4+m5wAUQIACncg/mxCIsB+oGdBVvFCd0YS7NahSpIKkL08tC78mvKZGiITPOzXw0VlmryWruNYyIXPPnTDhE31Pw6Q==", + "SigningCertURL": "https://sns.us-west-2.amazonaws.com/SimpleNotificationService-60eadc530605d63b8e62a523676ef735.pem", + "UnsubscribeURL": "https://sns.us-west-2.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:us-west-2:425362996713:DdTraceXLambda-snssqschecksNestedStacksnssqschecksNestedStackResource58F786C6-11NORKTA1JFML-snsProducerJavaForPythonNonRawsnssqsproducerjavaforpythonnonrawtopicDDBAB6EA-ZBb8uCZzkS0S:d44c53e8-538c-472f-89e1-89c131d9cd26", + "MessageAttributes": {} + }, + "attributes": { + "ApproximateReceiveCount": "1", + "AWSTraceHeader": "Root=1-664616b6-00000000425c5f4f8367f57e;Parent=6b971d513e9f9847;Sampled=1", + "SentTimestamp": "1715869366931", + "SenderId": "AIDAIYLAVTDLUXBIEIX46", + "ApproximateFirstReceiveTimestamp": "1715869366945" + }, + "messageAttributes": {}, + "md5OfBody": "e4f9d1cfee42abb22f764d004e88e7f2", + "eventSource": "aws:sqs", + "eventSourceARN": "arn:aws:sqs:us-west-2:425362996713:DdTraceXLambda-snssqschecksNested-snsProducerJavaForPythonNonRawsns-1vws7QPqW8e6", + "awsRegion": "us-west-2" + } + ] +} diff --git a/tests/event_samples/sqs-java-upstream.json b/tests/event_samples/sqs-java-upstream.json new file mode 100644 index 000000000..23ab68811 --- /dev/null +++ b/tests/event_samples/sqs-java-upstream.json @@ -0,0 +1,22 @@ +{ + "Records": [ + { + "messageId": "f7e888aa-1368-484c-8e15-fc3f0f7c6fea", + "receiptHandle": "AQEBN1aYTQ1c5huZh9bkhBYqcMMnqTUMRh8MfUPyGXkEolcn23rvM9saGEg3wTK/7JnJ1s3Uk107uLjaP6yV6+zS3oQRU0vMG2LfyTgHovWhYQ8TnrpC7XpYL+Uf+oc9KoILQopiYi4wsFnOWQqy82yQmlOA3W+CZ3Rvq8N6rNcmyaZEXVdozHG+FyMCMQ8QdTcCHhzR9YKnkZ87Y40+LhysUR57VNPVtRwENI8H1uMEfmxaCkW+CAkdCGoXeX+KioT7pHJDZaEutXM3VRmGXDDzCXvfUJQ9JQIlP5xe66JO8/cpCyl5sDoHsCjLy6X/XCmfG2+XclPObGHBzcMSjG1RQtHsEGTOAJrLREucqf/oj0Ab4svpxz6lR4UXrICygZ2x0NZcNFXcZx3GV2QL9nHmJxzrO2lnNTEOMuYB4SnqtIhsaDTcmkYHumaAJdRHl5BksFcU5qpS7BQrnRvXn5Sz3hYdR2KuYKN5Oq6W1vuT16o=", + "body": "{\"hello\":\"world\"}", + "attributes": { + "ApproximateReceiveCount": "1", + "AWSTraceHeader": "Root=1-65eb7350-000000006dfd06bf489aa4e5;Parent=48cc02b6aafae897;Sampled=1", + "SentTimestamp": "1709929297382", + "SenderId": "AROAWGCM4HXUTHYJKOM7M:DdTraceXLambda-sqsjavache-sqsjavaproducerforPython-moi7s7Hu7Ppy", + "ApproximateFirstReceiveTimestamp": "1709929297387" + }, + "messageAttributes": {}, + "md5OfMessageAttributes": "", + "md5OfBody": "fbc24bcc7a1794758fc1327fcfebdaf6", + "eventSource": "aws:sqs", + "eventSourceARN": "arn:aws:sqs:us-west-2:444442222111:DdTraceXLambda-sqsjavachecksNeste-sqsJavaProducer2sqsjavaproducerfo-dwpHQF6fcZT4", + "awsRegion": "us-west-2" + } + ] +} diff --git a/tests/event_samples/states.json b/tests/event_samples/states.json new file mode 100644 index 000000000..778fe4376 --- /dev/null +++ b/tests/event_samples/states.json @@ -0,0 +1,22 @@ +{ + "_datadog": { + "Execution": { + "Id": "arn:aws:states:ca-central-1:425362996713:execution:MyStateMachine-wsx8chv4d:1356a963-42a5-48b0-ba3f-73bde559a50c", + "StartTime": "2024-11-13T16:46:47.715Z", + "Name": "1356a963-42a5-48b0-ba3f-73bde559a50c", + "RoleArn": "arn:aws:iam::425362996713:role/service-role/StepFunctions-MyStateMachine-wsx8chv4d-role-1su0fkfd3", + "RedriveCount": 0 + }, + "StateMachine": { + "Id": "arn:aws:states:ca-central-1:425362996713:stateMachine:MyStateMachine-wsx8chv4d", + "Name": "MyStateMachine-wsx8chv4d" + }, + "State": { + "Name": "Lambda Invoke", + "EnteredTime": "2024-11-13T16:46:47.740Z", + "RetryCount": 0 + }, + "RootExecutionId": "arn:aws:states:ca-central-1:425362996713:execution:MyStateMachine-wsx8chv4d:1356a963-42a5-48b0-ba3f-73bde559a50c", + "serverless-version": "v1" + } +} diff --git a/tests/integration/input_events/appsync.json b/tests/integration/input_events/appsync.json new file mode 100644 index 000000000..dacf24e7e --- /dev/null +++ b/tests/integration/input_events/appsync.json @@ -0,0 +1,49 @@ +{ + "identity": "None", + "info": { + "fieldName": "getItems", + "parentTypeName": "Query", + "selectionSetGraphQL": "{\n id\n}", + "selectionSetList":["id"] + }, + "prev": "None", + "request": { + "domainName": "None", + "headers": { + "accept": "*/*", + "accept-encoding": "gzip, deflate, br, zstd", + "accept-language": "en-US,en;q=0.9", + "cloudfront-forwarded-proto": "https", + "cloudfront-is-desktop-viewer": "True", + "cloudfront-is-mobile-viewer": "False", + "cloudfront-is-smarttv-viewer":"False", + "cloudfront-is-tablet-viewer":" False", + "cloudfront-viewer-asn": "6461", + "cloudfront-viewer-country": "US", + "content-length": "47", + "content-type": "application/graphql", + "host": "4aowrg2uhvbw5mn7osu6searqi.appsync-api.us-east-1.amazonaws.com", + "origin": "http://localhost:5173/", + "priority": "u=1, i", + "referer": "http://localhost:5173/", + "sec-ch-ua": "\"Chromium\";v=\"140\", \"Not=A?Brand\";v=\"24\", \"Google Chrome\";v=\"140\"", + "sec-ch-ua-mobile": "?0", + "sec-ch-ua-platform": "macOS", + "sec-fetch-dest": "empty", + "sec-fetch-mode": "cors", + "sec-fetch-site": "cross-site", + "traceparent": "00-0000000000000000d9f454c80b9a529a-73ac6ca3427073a3-01", + "tracestate": "dd=s:1;o:rum", + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36","via":"2.0 62f9f3967e93a923f21c8acb20cf10b6.cloudfront.net (CloudFront)", + "x-amz-cf-id": "Femhicb_Vbva-J8qWjdI4hKMmqusCeQSp207UGyY3u8VOUrdE8BBvg==", + "x-amzn-appsync-is-vpce-request": "False", + "x-amzn-remote-ip": "64.124.12.19", + "x-amzn-requestid": "1ee1669a-eda3-4d4f-911c-35f74ebef31d", + "x-amzn-trace-id": "Root=1-68cdb7e9-438bf88259d7ce3535723bdd", + "x-forwarded-for": "64.124.12.19,15.158.225.229", + "x-forwarded-port": "443", + "x-forwarded-proto": "https" + } + }, + "source": "None" +} \ No newline at end of file diff --git a/tests/integration/package-lock.json b/tests/integration/package-lock.json new file mode 100644 index 000000000..5990cc8db --- /dev/null +++ b/tests/integration/package-lock.json @@ -0,0 +1,1119 @@ +{ + "name": "integration", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "devDependencies": { + "serverless-plugin-datadog": "^2.18.0", + "serverless-python-requirements": "^6.1.2" + } + }, + "node_modules/@iarna/toml": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz", + "integrity": "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==", + "dev": true, + "license": "ISC" + }, + "node_modules/2-thenable": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/2-thenable/-/2-thenable-1.0.0.tgz", + "integrity": "sha512-HqiDzaLDFCXkcCO/SwoyhRwqYtINFHF7t9BDRq4x90TOKNAJpiqUt9X5lQ08bwxYzc067HUywDjGySpebHcUpw==", + "dev": true, + "license": "ISC", + "dependencies": { + "d": "1", + "es5-ext": "^0.10.47" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/appdirectory": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/appdirectory/-/appdirectory-0.1.0.tgz", + "integrity": "sha512-DJ5DV8vZXBbusyiyPlH28xppwS8eAMRuuyMo88xeEcf4bV64lbLtbxRxqixZuJBXsZzLtXFmA13GwVjJc7vdQw==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "dev": true, + "license": "MIT" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/child-process-ext": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/child-process-ext/-/child-process-ext-2.1.1.tgz", + "integrity": "sha512-0UQ55f51JBkOFa+fvR76ywRzxiPwQS3Xe8oe5bZRphpv+dIMeerW5Zn5e4cUy4COJwVtJyU0R79RMnw+aCqmGA==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^6.0.5", + "es5-ext": "^0.10.53", + "log": "^6.0.0", + "split2": "^3.1.1", + "stream-promise": "^3.2.0" + } + }, + "node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz", + "integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/cross-spawn/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/d": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.2.tgz", + "integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==", + "dev": true, + "license": "ISC", + "dependencies": { + "es5-ext": "^0.10.64", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/duration": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/duration/-/duration-0.2.2.tgz", + "integrity": "sha512-06kgtea+bGreF5eKYgI/36A6pLXggY7oR4p1pq4SmdFBn1ReOL5D8RhG64VrqfTTKNucqqtBAwEj8aB88mcqrg==", + "dev": true, + "license": "ISC", + "dependencies": { + "d": "1", + "es5-ext": "~0.10.46" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/es5-ext": { + "version": "0.10.64", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", + "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", + "dev": true, + "hasInstallScript": true, + "license": "ISC", + "dependencies": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "esniff": "^2.0.1", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "dev": true, + "license": "MIT", + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/es6-symbol": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz", + "integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==", + "dev": true, + "license": "ISC", + "dependencies": { + "d": "^1.0.2", + "ext": "^1.7.0" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/esniff": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", + "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", + "dev": true, + "license": "ISC", + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "event-emitter": "^0.3.5", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "node_modules/ext": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", + "dev": true, + "license": "ISC", + "dependencies": { + "type": "^2.7.2" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-all": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/glob-all/-/glob-all-3.3.1.tgz", + "integrity": "sha512-Y+ESjdI7ZgMwfzanHZYQ87C59jOO0i+Hd+QYtVt9PhLi6d8wlOpzQnfBxWUlaTuAoR3TkybLqqbIoWveU4Ji7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "glob": "^7.2.3", + "yargs": "^15.3.1" + }, + "bin": { + "glob-all": "bin/glob-all" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-primitive": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-3.0.1.tgz", + "integrity": "sha512-GljRxhWvlCNRfZyORiH77FwdFwGcMO620o37EOYC0ORWdq+WYNVqW0w2Juzew4M+L81l6/QS3t5gkkihyRqv9w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "dev": true, + "license": "(MIT OR GPL-3.0-or-later)", + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "immediate": "~3.0.5" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", + "deprecated": "This package is deprecated. Use the optional chaining (?.) operator instead.", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.uniqby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz", + "integrity": "sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.values": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.values/-/lodash.values-4.3.0.tgz", + "integrity": "sha512-r0RwvdCv8id9TUblb/O7rYPwVy6lerCbcawrfdo9iC/1t1wsNMJknO79WNBgwkH0hIeJ08jmvvESbFpNb4jH0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/log": { + "version": "6.3.2", + "resolved": "https://registry.npmjs.org/log/-/log-6.3.2.tgz", + "integrity": "sha512-ek8NRg/OPvS9ISOJNWNAz5vZcpYacWNFDWNJjj5OXsc6YuKacfey6wF04cXz/tOJIVrZ2nGSkHpAY5qKtF6ISg==", + "dev": true, + "license": "ISC", + "dependencies": { + "d": "^1.0.2", + "duration": "^0.2.2", + "es5-ext": "^0.10.64", + "event-emitter": "^0.3.5", + "sprintf-kit": "^2.0.2", + "type": "^2.7.3", + "uni-global": "^1.0.0" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true, + "license": "(MIT AND Zlib)" + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true, + "license": "ISC" + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/serverless-plugin-datadog": { + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/serverless-plugin-datadog/-/serverless-plugin-datadog-2.18.0.tgz", + "integrity": "sha512-RUdCNjUk+uUKQYgQBjK0WNeYJ7lM2/RScqg/LjVSfv5EACeJ3iIUPz1c4bS2jtiH05al8qXudNb6QDkv9zxG7w==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/serverless-python-requirements": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/serverless-python-requirements/-/serverless-python-requirements-6.1.2.tgz", + "integrity": "sha512-pas27CBxxaLTU5XMYnCVPJc+LVdm65Ys5olNvRWRqfUaZwTfD/7KSSt2XPSRme8BeJubroslaiOtWPP+IrxTVA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@iarna/toml": "^2.2.5", + "appdirectory": "^0.1.0", + "bluebird": "^3.7.2", + "child-process-ext": "^2.1.1", + "fs-extra": "^10.1.0", + "glob-all": "^3.3.1", + "is-wsl": "^2.2.0", + "jszip": "^3.10.1", + "lodash.get": "^4.4.2", + "lodash.uniqby": "^4.7.0", + "lodash.values": "^4.3.0", + "rimraf": "^3.0.2", + "semver": "^7.6.0", + "set-value": "^4.1.0", + "sha256-file": "1.0.0", + "shell-quote": "^1.8.1" + }, + "engines": { + "node": ">=12.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true, + "license": "ISC" + }, + "node_modules/set-value": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-4.1.0.tgz", + "integrity": "sha512-zTEg4HL0RwVrqcWs3ztF+x1vkxfm0lP+MQQFPiMJTKVceBwEV0A569Ou8l9IYQG8jOZdMVI1hGsc0tmeD2o/Lw==", + "dev": true, + "funding": [ + "https://github.com/sponsors/jonschlinkert", + "https://paypal.me/jonathanschlinkert", + "https://jonschlinkert.dev/sponsor" + ], + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4", + "is-primitive": "^3.0.1" + }, + "engines": { + "node": ">=11.0" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "dev": true, + "license": "MIT" + }, + "node_modules/sha256-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/sha256-file/-/sha256-file-1.0.0.tgz", + "integrity": "sha512-nqf+g0veqgQAkDx0U2y2Tn2KWyADuuludZTw9A7J3D+61rKlIIl9V5TS4mfnwKuXZOH9B7fQyjYJ9pKRHIsAyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shell-quote": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz", + "integrity": "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/split2": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", + "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", + "dev": true, + "license": "ISC", + "dependencies": { + "readable-stream": "^3.0.0" + } + }, + "node_modules/split2/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/sprintf-kit": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/sprintf-kit/-/sprintf-kit-2.0.2.tgz", + "integrity": "sha512-lnapdj6W4LflHZGKvl9eVkz5YF0xaTrqpRWVA4cNVOTedwqifIP8ooGImldzT/4IAN5KXFQAyXTdLidYVQdyag==", + "dev": true, + "license": "ISC", + "dependencies": { + "es5-ext": "^0.10.64" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/stream-promise": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/stream-promise/-/stream-promise-3.2.0.tgz", + "integrity": "sha512-P+7muTGs2C8yRcgJw/PPt61q7O517tDHiwYEzMWo1GSBCcZedUMT/clz7vUNsSxFphIlJ6QUL4GexQKlfJoVtA==", + "dev": true, + "license": "ISC", + "dependencies": { + "2-thenable": "^1.0.0", + "es5-ext": "^0.10.49", + "is-stream": "^1.1.0" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/type": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.3.tgz", + "integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/uni-global": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/uni-global/-/uni-global-1.0.0.tgz", + "integrity": "sha512-WWM3HP+siTxzIWPNUg7hZ4XO8clKi6NoCAJJWnuRL+BAqyFXF8gC03WNyTefGoUXYc47uYgXxpKLIEvo65PEHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "type": "^2.5.0" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/which-module": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + } + } +} diff --git a/tests/integration/package.json b/tests/integration/package.json index 9dcad1b4c..8dae6acaa 100644 --- a/tests/integration/package.json +++ b/tests/integration/package.json @@ -1,5 +1,6 @@ { "devDependencies": { - "serverless-plugin-datadog": "^2.18.0" + "serverless-plugin-datadog": "^2.18.0", + "serverless-python-requirements": "^6.1.2" } } diff --git a/tests/integration/requirements.txt b/tests/integration/requirements.txt new file mode 100644 index 000000000..343ea0257 --- /dev/null +++ b/tests/integration/requirements.txt @@ -0,0 +1,4 @@ +certifi==2024.12.14 +charset-normalizer==3.4.1 +idna==3.10 +requests==2.32.4 diff --git a/tests/integration/serverless.yml b/tests/integration/serverless.yml index bb64c3972..8c7e62f08 100644 --- a/tests/integration/serverless.yml +++ b/tests/integration/serverless.yml @@ -6,6 +6,7 @@ provider: region: eu-west-1 tracing: lambda: "PassThrough" + architecture: ${env:SLS_ARCH} environment: DD_INTEGRATION_TEST: true DD_TRACE_ENABLED: true @@ -19,11 +20,26 @@ provider: iam: # IAM permissions require that all functions are deployed with this role role: "arn:aws:iam::425362996713:role/serverless-integration-test-lambda-role" + layers: + - { Ref: PythonLambdaLayer } + - { Ref: PythonRequirementsLambdaLayer } + +plugins: + - serverless-python-requirements + +custom: + pythonRequirements: + pythonBin: python3 + pipCmdExtraArgs: + - --no-deps # install just requests + layer: + compatibleRuntimes: + - ${env:SERVERLESS_RUNTIME} layers: python: package: - artifact: ../../.layers/datadog_lambda_py-amd64-${env:PYTHON_VERSION}.zip + artifact: ../../.layers/datadog_lambda_py-${env:ARCH}-${env:PYTHON_VERSION}.zip functions: # async-metrics (flushed to logs) @@ -31,8 +47,6 @@ functions: name: integration-tests-python-${sls:stage}-async-metrics_${env:RUNTIME} handler: handle.handle runtime: ${env:SERVERLESS_RUNTIME} - layers: - - { Ref: PythonLambdaLayer } environment: DD_FLUSH_TO_LOG: true @@ -41,5 +55,3 @@ functions: name: integration-tests-python-${sls:stage}-sync-metrics_${env:RUNTIME} handler: handle.handle runtime: ${env:SERVERLESS_RUNTIME} - layers: - - { Ref: PythonLambdaLayer } diff --git a/tests/integration/snapshots/logs/async-metrics_python310.log b/tests/integration/snapshots/logs/async-metrics_python310.log index 81d2351ec..6779d7ddb 100644 --- a/tests/integration/snapshots/logs/async-metrics_python310.log +++ b/tests/integration/snapshots/logs/async-metrics_python310.log @@ -9,8 +9,8 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-async-metrics_python310", "resource:integration-tests-python-XXXX-async-metrics_python310", - "cold_start:true", "memorysize:1024", + "cold_start:true", "runtime:python3.10", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python310_X.X.X" @@ -36,8 +36,8 @@ START "dd_lambda_layer:datadog-python310_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -55,10 +55,11 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "runtime-id": "XXXX", "_dd.origin": "lambda", "operation_name": "aws.apigateway.rest", - "http.url": "XXXX.execute-api.us-east-2.amazonaws.com/", + "http.url": "https://xxxx.execute-api.us-east-2.amazonaws.com/", "endpoint": "/", "http.method": "GET", "resource_names": "GET /", + "span.kind": "server", "apiid": "XXXX", "apiname": "XXXX", "stage": "Prod", @@ -66,12 +67,12 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "sync", "_inferred_span.tag_source": "self", "http.status_code": "200", + "http.route": "/", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -84,7 +85,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-async-metrics_python310", "name": "aws.lambda", "error": 0, @@ -103,11 +104,11 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "span.name": "aws.lambda", "function_trigger.event_source": "api-gateway", "function_trigger.event_source_arn": "XXXX", - "http.url": "XXXX.execute-api.us-east-2.amazonaws.com", - "http.url_details.path": "/Prod/", + "span.kind": "server", + "http.url": "https://xxxx.execute-api.us-east-2.amazonaws.com/Prod/", "http.method": "GET", - "http.status_code": "200", - "_dd.base_service": "integration-tests-python" + "http.route": "/", + "http.status_code": "200" }, "metrics": { "_dd.top_level": 1 @@ -118,8 +119,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -144,8 +145,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -180,13 +181,150 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-async-metrics_python310", "resource:integration-tests-python-XXXX-async-metrics_python310", + "memorysize:1024", "cold_start:false", + "runtime:python3.10", + "datadog_lambda:vXX", + "dd_lambda_layer:datadog-python310_X.X.X" + ] +} +{ + "m": "hello.dog", + "v": 1, + "e": XXXX, + "t": [ + "team:serverless", + "role:hello", + "dd_lambda_layer:datadog-python310_X.X.X" + ] +} +{ + "m": "tests.integration.count", + "v": 21, + "e": XXXX, + "t": [ + "test:integration", + "role:hello", + "dd_lambda_layer:datadog-python310_X.X.X" + ] +} +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +{ + "traces": [ + [ + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "integration-tests-python", + "resource": "integration-tests-python-XXXX-async-metrics_python310", + "name": "aws.lambda", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "runtime-id": "XXXX", + "_dd.origin": "lambda", + "cold_start": "false", + "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-async-metrics_python310", + "function_version": "$LATEST", + "request_id": "XXXX", + "resource_names": "integration-tests-python-XXXX-async-metrics_python310", + "functionname": "integration-tests-python-XXXX-async-metrics_python310", + "datadog_lambda": "X.X.X", + "dd_trace": "X.X.X", + "span.name": "aws.lambda", + "language": "python" + }, + "metrics": { + "process_id": XXXX, + "_dd.top_level": 1, + "_sampling_priority_v1": 1 + }, + "type": "serverless" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://datadoghq.com/", + "out.host": "datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1 + }, + "type": "http" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://www.datadoghq.com/", + "out.host": "www.datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1 + }, + "type": "http" + } + ] + ] +} +END Duration: XXXX ms Memory Used: XXXX MB +START +{ + "m": "aws.lambda.enhanced.invocations", + "v": 1, + "e": XXXX, + "t": [ + "region:eu-west-1", + "account_id:XXXX", + "functionname:integration-tests-python-XXXX-async-metrics_python310", + "resource:integration-tests-python-XXXX-async-metrics_python310", "memorysize:1024", + "cold_start:false", "runtime:python3.10", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python310_X.X.X" ] } +{ + "m": "datadog.serverless.dynamodb.stream.type", + "v": 1, + "e": XXXX, + "t": [ + "streamtype:NEW_AND_OLD_IMAGES", + "dd_lambda_layer:datadog-python310_X.X.X" + ] +} { "m": "hello.dog", "v": 1, @@ -207,8 +345,8 @@ START "dd_lambda_layer:datadog-python310_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -216,7 +354,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "dynamodb", + "service": "ExampleTableWithStream", "resource": "ExampleTableWithStream", "name": "aws.dynamodb", "error": 0, @@ -227,6 +365,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.dynamodb", "resource_names": "ExampleTableWithStream", + "span.kind": "server", "tablename": "ExampleTableWithStream", "event_source_arn": "arn:aws:dynamodb:us-east-1:XXXX:us-east-1/ExampleTableWithStream/stream/2015-06-27T00:48:05.899", "event_id": "XXXX", @@ -237,24 +376,55 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, - "type": "web" + "type": "web", + "span_links": [ + { + "trace_id": "XXXX", + "span_id": "XXXX", + "attributes": { + "ptr.kind": "aws.dynamodb.item", + "ptr.dir": "u", + "ptr.hash": "e2af34d333891f765c7f02d2da80895e", + "link.kind": "span-pointer" + } + }, + { + "trace_id": "XXXX", + "span_id": "XXXX", + "attributes": { + "ptr.kind": "aws.dynamodb.item", + "ptr.dir": "u", + "ptr.hash": "e2af34d333891f765c7f02d2da80895e", + "link.kind": "span-pointer" + } + }, + { + "trace_id": "XXXX", + "span_id": "XXXX", + "attributes": { + "ptr.kind": "aws.dynamodb.item", + "ptr.dir": "u", + "ptr.hash": "e2af34d333891f765c7f02d2da80895e", + "link.kind": "span-pointer" + } + } + ] }, { "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-async-metrics_python310", "name": "aws.lambda", "error": 0, @@ -272,8 +442,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "dynamodb", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -284,8 +453,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -310,8 +479,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -346,8 +515,8 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-async-metrics_python310", "resource:integration-tests-python-XXXX-async-metrics_python310", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.10", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python310_X.X.X" @@ -373,8 +542,8 @@ START "dd_lambda_layer:datadog-python310_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -382,7 +551,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "eventbridge", + "service": "eventbridge.custom.event.sender", "resource": "eventbridge.custom.event.sender", "name": "aws.eventbridge", "error": 0, @@ -393,15 +562,15 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.eventbridge", "resource_names": "eventbridge.custom.event.sender", + "span.kind": "server", "detail_type": "testdetail", "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -414,7 +583,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-async-metrics_python310", "name": "aws.lambda", "error": 0, @@ -431,8 +600,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "datadog_lambda": "X.X.X", "dd_trace": "X.X.X", "span.name": "aws.lambda", - "function_trigger.event_source": "eventbridge", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source": "eventbridge" }, "metrics": { "_dd.top_level": 1 @@ -443,8 +611,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -469,8 +637,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -505,8 +673,8 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-async-metrics_python310", "resource:integration-tests-python-XXXX-async-metrics_python310", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.10", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python310_X.X.X" @@ -532,8 +700,8 @@ START "dd_lambda_layer:datadog-python310_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -552,7 +720,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.httpapi", "endpoint": "/httpapi/get", - "http.url": "XXXX.execute-api.eu-west-1.amazonaws.com/httpapi/get", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com/httpapi/get", "http.method": "GET", "http.protocol": "HTTP/1.1", "http.source_ip": "XXXX", @@ -565,12 +733,12 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "sync", "_inferred_span.tag_source": "self", "http.status_code": "200", + "http.route": "/httpapi/get", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -583,7 +751,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-async-metrics_python310", "name": "aws.lambda", "error": 0, @@ -602,11 +770,11 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "span.name": "aws.lambda", "function_trigger.event_source": "api-gateway", "function_trigger.event_source_arn": "XXXX$default", - "http.url": "XXXX.execute-api.eu-west-1.amazonaws.com", - "http.url_details.path": "/httpapi/get", + "span.kind": "server", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com/httpapi/get", "http.method": "GET", - "http.status_code": "200", - "_dd.base_service": "integration-tests-python" + "http.route": "/httpapi/get", + "http.status_code": "200" }, "metrics": { "_dd.top_level": 1 @@ -617,8 +785,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -643,8 +811,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -679,8 +847,8 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-async-metrics_python310", "resource:integration-tests-python-XXXX-async-metrics_python310", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.10", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python310_X.X.X" @@ -706,8 +874,8 @@ START "dd_lambda_layer:datadog-python310_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -715,7 +883,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "kinesis", + "service": "EXAMPLE", "resource": "EXAMPLE", "name": "aws.kinesis", "error": 0, @@ -726,6 +894,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.kinesis", "resource_names": "EXAMPLE", + "span.kind": "server", "streamname": "EXAMPLE", "shardid": "shardId-XXXX", "event_source_arn": "arn:aws:kinesis:EXAMPLE", @@ -736,11 +905,10 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -753,7 +921,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-async-metrics_python310", "name": "aws.lambda", "error": 0, @@ -771,8 +939,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "kinesis", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -783,8 +950,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -809,8 +976,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -845,8 +1012,8 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-async-metrics_python310", "resource:integration-tests-python-XXXX-async-metrics_python310", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.10", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python310_X.X.X" @@ -872,8 +1039,8 @@ START "dd_lambda_layer:datadog-python310_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -881,7 +1048,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "s3", + "service": "example-bucket", "resource": "example-bucket", "name": "aws.s3", "error": 0, @@ -890,6 +1057,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.s3", "resource_names": "example-bucket", + "span.kind": "server", "event_name": "ObjectCreated:Put", "bucketname": "example-bucket", "bucket_arn": "arn:aws:s3:::example-bucket", @@ -899,24 +1067,35 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, - "type": "web" + "type": "web", + "span_links": [ + { + "trace_id": "XXXX", + "span_id": "XXXX", + "attributes": { + "ptr.kind": "aws.s3.object", + "ptr.dir": "u", + "ptr.hash": "1dc3e5d00dae48c1f07d95371a747788", + "link.kind": "span-pointer" + } + } + ] }, { "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-async-metrics_python310", "name": "aws.lambda", "error": 0, @@ -934,8 +1113,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "s3", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -946,8 +1124,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -972,8 +1150,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1008,8 +1186,8 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-async-metrics_python310", "resource:integration-tests-python-XXXX-async-metrics_python310", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.10", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python310_X.X.X" @@ -1035,8 +1213,8 @@ START "dd_lambda_layer:datadog-python310_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1044,7 +1222,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "sns", + "service": "sns-lambda", "resource": "sns-lambda", "name": "aws.sns", "error": 0, @@ -1055,6 +1233,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.sns", "resource_names": "sns-lambda", + "span.kind": "server", "topicname": "sns-lambda", "topic_arn": "arn:aws:sns:us-east-2:XXXX:us-east-2-lambda", "message_id": "XXXX", @@ -1063,11 +1242,10 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -1080,7 +1258,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-async-metrics_python310", "name": "aws.lambda", "error": 0, @@ -1098,8 +1276,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "sns", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -1110,8 +1287,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1136,8 +1313,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1172,8 +1349,8 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-async-metrics_python310", "resource:integration-tests-python-XXXX-async-metrics_python310", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.10", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python310_X.X.X" @@ -1199,8 +1376,8 @@ START "dd_lambda_layer:datadog-python310_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1208,7 +1385,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "sqs", + "service": "my-queue", "resource": "my-queue", "name": "aws.sqs", "error": 0, @@ -1219,6 +1396,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.sqs", "resource_names": "my-queue", + "span.kind": "server", "queuename": "my-queue", "event_source_arn": "arn:aws:sqs:us-east-2:XXXX:us-east-2-queue", "receipt_handle": "AQEBwJnKyrHigUMZj6rYigCgxlaS3SLy0a...", @@ -1226,11 +1404,10 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -1243,7 +1420,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-async-metrics_python310", "name": "aws.lambda", "error": 0, @@ -1261,8 +1438,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "sqs", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -1273,8 +1449,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1299,8 +1475,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1335,8 +1511,8 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-async-metrics_python310", "resource:integration-tests-python-XXXX-async-metrics_python310", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.10", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python310_X.X.X" @@ -1362,8 +1538,8 @@ START "dd_lambda_layer:datadog-python310_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1381,9 +1557,10 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "runtime-id": "XXXX", "_dd.origin": "lambda", "operation_name": "aws.apigateway.websocket", - "http.url": "XXXX.execute-api.eu-west-1.amazonaws.com$default", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com$default/", "endpoint": "$default", "resource_names": "$default", + "span.kind": "server", "apiid": "XXXX", "apiname": "XXXX", "stage": "dev", @@ -1395,11 +1572,10 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.tag_source": "self", "http.status_code": "200", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -1412,7 +1588,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-async-metrics_python310", "name": "aws.lambda", "error": 0, @@ -1431,9 +1607,9 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "span.name": "aws.lambda", "function_trigger.event_source": "api-gateway", "function_trigger.event_source_arn": "XXXX", - "http.url": "XXXX.execute-api.eu-west-1.amazonaws.com", - "http.status_code": "200", - "_dd.base_service": "integration-tests-python" + "span.kind": "server", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com/", + "http.status_code": "200" }, "metrics": { "_dd.top_level": 1 @@ -1444,8 +1620,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1470,8 +1646,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", diff --git a/tests/integration/snapshots/logs/async-metrics_python311.log b/tests/integration/snapshots/logs/async-metrics_python311.log index ebecb1392..9f14ff15c 100644 --- a/tests/integration/snapshots/logs/async-metrics_python311.log +++ b/tests/integration/snapshots/logs/async-metrics_python311.log @@ -9,8 +9,8 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-async-metrics_python311", "resource:integration-tests-python-XXXX-async-metrics_python311", - "cold_start:true", "memorysize:1024", + "cold_start:true", "runtime:python3.11", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python311_X.X.X" @@ -36,8 +36,8 @@ START "dd_lambda_layer:datadog-python311_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -55,10 +55,11 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "runtime-id": "XXXX", "_dd.origin": "lambda", "operation_name": "aws.apigateway.rest", - "http.url": "XXXX.execute-api.us-east-2.amazonaws.com/", + "http.url": "https://xxxx.execute-api.us-east-2.amazonaws.com/", "endpoint": "/", "http.method": "GET", "resource_names": "GET /", + "span.kind": "server", "apiid": "XXXX", "apiname": "XXXX", "stage": "Prod", @@ -66,12 +67,12 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "sync", "_inferred_span.tag_source": "self", "http.status_code": "200", + "http.route": "/", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -84,7 +85,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-async-metrics_python311", "name": "aws.lambda", "error": 0, @@ -103,11 +104,11 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "span.name": "aws.lambda", "function_trigger.event_source": "api-gateway", "function_trigger.event_source_arn": "XXXX", - "http.url": "XXXX.execute-api.us-east-2.amazonaws.com", - "http.url_details.path": "/Prod/", + "span.kind": "server", + "http.url": "https://xxxx.execute-api.us-east-2.amazonaws.com/Prod/", "http.method": "GET", - "http.status_code": "200", - "_dd.base_service": "integration-tests-python" + "http.route": "/", + "http.status_code": "200" }, "metrics": { "_dd.top_level": 1 @@ -118,8 +119,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -144,8 +145,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -180,13 +181,150 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-async-metrics_python311", "resource:integration-tests-python-XXXX-async-metrics_python311", + "memorysize:1024", "cold_start:false", + "runtime:python3.11", + "datadog_lambda:vXX", + "dd_lambda_layer:datadog-python311_X.X.X" + ] +} +{ + "m": "hello.dog", + "v": 1, + "e": XXXX, + "t": [ + "team:serverless", + "role:hello", + "dd_lambda_layer:datadog-python311_X.X.X" + ] +} +{ + "m": "tests.integration.count", + "v": 21, + "e": XXXX, + "t": [ + "test:integration", + "role:hello", + "dd_lambda_layer:datadog-python311_X.X.X" + ] +} +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +{ + "traces": [ + [ + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "integration-tests-python", + "resource": "integration-tests-python-XXXX-async-metrics_python311", + "name": "aws.lambda", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "runtime-id": "XXXX", + "_dd.origin": "lambda", + "cold_start": "false", + "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-async-metrics_python311", + "function_version": "$LATEST", + "request_id": "XXXX", + "resource_names": "integration-tests-python-XXXX-async-metrics_python311", + "functionname": "integration-tests-python-XXXX-async-metrics_python311", + "datadog_lambda": "X.X.X", + "dd_trace": "X.X.X", + "span.name": "aws.lambda", + "language": "python" + }, + "metrics": { + "process_id": XXXX, + "_dd.top_level": 1, + "_sampling_priority_v1": 1 + }, + "type": "serverless" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://datadoghq.com/", + "out.host": "datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1 + }, + "type": "http" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://www.datadoghq.com/", + "out.host": "www.datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1 + }, + "type": "http" + } + ] + ] +} +END Duration: XXXX ms Memory Used: XXXX MB +START +{ + "m": "aws.lambda.enhanced.invocations", + "v": 1, + "e": XXXX, + "t": [ + "region:eu-west-1", + "account_id:XXXX", + "functionname:integration-tests-python-XXXX-async-metrics_python311", + "resource:integration-tests-python-XXXX-async-metrics_python311", "memorysize:1024", + "cold_start:false", "runtime:python3.11", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python311_X.X.X" ] } +{ + "m": "datadog.serverless.dynamodb.stream.type", + "v": 1, + "e": XXXX, + "t": [ + "streamtype:NEW_AND_OLD_IMAGES", + "dd_lambda_layer:datadog-python311_X.X.X" + ] +} { "m": "hello.dog", "v": 1, @@ -207,8 +345,8 @@ START "dd_lambda_layer:datadog-python311_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -216,7 +354,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "dynamodb", + "service": "ExampleTableWithStream", "resource": "ExampleTableWithStream", "name": "aws.dynamodb", "error": 0, @@ -227,6 +365,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.dynamodb", "resource_names": "ExampleTableWithStream", + "span.kind": "server", "tablename": "ExampleTableWithStream", "event_source_arn": "arn:aws:dynamodb:us-east-1:XXXX:us-east-1/ExampleTableWithStream/stream/2015-06-27T00:48:05.899", "event_id": "XXXX", @@ -237,24 +376,55 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, - "type": "web" + "type": "web", + "span_links": [ + { + "trace_id": "XXXX", + "span_id": "XXXX", + "attributes": { + "ptr.kind": "aws.dynamodb.item", + "ptr.dir": "u", + "ptr.hash": "e2af34d333891f765c7f02d2da80895e", + "link.kind": "span-pointer" + } + }, + { + "trace_id": "XXXX", + "span_id": "XXXX", + "attributes": { + "ptr.kind": "aws.dynamodb.item", + "ptr.dir": "u", + "ptr.hash": "e2af34d333891f765c7f02d2da80895e", + "link.kind": "span-pointer" + } + }, + { + "trace_id": "XXXX", + "span_id": "XXXX", + "attributes": { + "ptr.kind": "aws.dynamodb.item", + "ptr.dir": "u", + "ptr.hash": "e2af34d333891f765c7f02d2da80895e", + "link.kind": "span-pointer" + } + } + ] }, { "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-async-metrics_python311", "name": "aws.lambda", "error": 0, @@ -272,8 +442,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "dynamodb", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -284,8 +453,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -310,8 +479,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -346,8 +515,8 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-async-metrics_python311", "resource:integration-tests-python-XXXX-async-metrics_python311", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.11", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python311_X.X.X" @@ -373,8 +542,8 @@ START "dd_lambda_layer:datadog-python311_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -382,7 +551,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "eventbridge", + "service": "eventbridge.custom.event.sender", "resource": "eventbridge.custom.event.sender", "name": "aws.eventbridge", "error": 0, @@ -393,15 +562,15 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.eventbridge", "resource_names": "eventbridge.custom.event.sender", + "span.kind": "server", "detail_type": "testdetail", "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -414,7 +583,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-async-metrics_python311", "name": "aws.lambda", "error": 0, @@ -431,8 +600,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "datadog_lambda": "X.X.X", "dd_trace": "X.X.X", "span.name": "aws.lambda", - "function_trigger.event_source": "eventbridge", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source": "eventbridge" }, "metrics": { "_dd.top_level": 1 @@ -443,8 +611,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -469,8 +637,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -505,8 +673,8 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-async-metrics_python311", "resource:integration-tests-python-XXXX-async-metrics_python311", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.11", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python311_X.X.X" @@ -532,8 +700,8 @@ START "dd_lambda_layer:datadog-python311_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -552,7 +720,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.httpapi", "endpoint": "/httpapi/get", - "http.url": "XXXX.execute-api.eu-west-1.amazonaws.com/httpapi/get", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com/httpapi/get", "http.method": "GET", "http.protocol": "HTTP/1.1", "http.source_ip": "XXXX", @@ -565,12 +733,12 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "sync", "_inferred_span.tag_source": "self", "http.status_code": "200", + "http.route": "/httpapi/get", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -583,7 +751,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-async-metrics_python311", "name": "aws.lambda", "error": 0, @@ -602,11 +770,11 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "span.name": "aws.lambda", "function_trigger.event_source": "api-gateway", "function_trigger.event_source_arn": "XXXX$default", - "http.url": "XXXX.execute-api.eu-west-1.amazonaws.com", - "http.url_details.path": "/httpapi/get", + "span.kind": "server", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com/httpapi/get", "http.method": "GET", - "http.status_code": "200", - "_dd.base_service": "integration-tests-python" + "http.route": "/httpapi/get", + "http.status_code": "200" }, "metrics": { "_dd.top_level": 1 @@ -617,8 +785,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -643,8 +811,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -679,8 +847,8 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-async-metrics_python311", "resource:integration-tests-python-XXXX-async-metrics_python311", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.11", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python311_X.X.X" @@ -706,8 +874,8 @@ START "dd_lambda_layer:datadog-python311_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -715,7 +883,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "kinesis", + "service": "EXAMPLE", "resource": "EXAMPLE", "name": "aws.kinesis", "error": 0, @@ -726,6 +894,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.kinesis", "resource_names": "EXAMPLE", + "span.kind": "server", "streamname": "EXAMPLE", "shardid": "shardId-XXXX", "event_source_arn": "arn:aws:kinesis:EXAMPLE", @@ -736,11 +905,10 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -753,7 +921,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-async-metrics_python311", "name": "aws.lambda", "error": 0, @@ -771,8 +939,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "kinesis", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -783,8 +950,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -809,8 +976,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -845,8 +1012,8 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-async-metrics_python311", "resource:integration-tests-python-XXXX-async-metrics_python311", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.11", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python311_X.X.X" @@ -872,8 +1039,8 @@ START "dd_lambda_layer:datadog-python311_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -881,7 +1048,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "s3", + "service": "example-bucket", "resource": "example-bucket", "name": "aws.s3", "error": 0, @@ -890,6 +1057,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.s3", "resource_names": "example-bucket", + "span.kind": "server", "event_name": "ObjectCreated:Put", "bucketname": "example-bucket", "bucket_arn": "arn:aws:s3:::example-bucket", @@ -899,24 +1067,35 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, - "type": "web" + "type": "web", + "span_links": [ + { + "trace_id": "XXXX", + "span_id": "XXXX", + "attributes": { + "ptr.kind": "aws.s3.object", + "ptr.dir": "u", + "ptr.hash": "1dc3e5d00dae48c1f07d95371a747788", + "link.kind": "span-pointer" + } + } + ] }, { "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-async-metrics_python311", "name": "aws.lambda", "error": 0, @@ -934,8 +1113,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "s3", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -946,8 +1124,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -972,8 +1150,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1008,8 +1186,8 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-async-metrics_python311", "resource:integration-tests-python-XXXX-async-metrics_python311", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.11", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python311_X.X.X" @@ -1035,8 +1213,8 @@ START "dd_lambda_layer:datadog-python311_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1044,7 +1222,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "sns", + "service": "sns-lambda", "resource": "sns-lambda", "name": "aws.sns", "error": 0, @@ -1055,6 +1233,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.sns", "resource_names": "sns-lambda", + "span.kind": "server", "topicname": "sns-lambda", "topic_arn": "arn:aws:sns:us-east-2:XXXX:us-east-2-lambda", "message_id": "XXXX", @@ -1063,11 +1242,10 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -1080,7 +1258,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-async-metrics_python311", "name": "aws.lambda", "error": 0, @@ -1098,8 +1276,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "sns", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -1110,8 +1287,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1136,8 +1313,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1172,8 +1349,8 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-async-metrics_python311", "resource:integration-tests-python-XXXX-async-metrics_python311", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.11", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python311_X.X.X" @@ -1199,8 +1376,8 @@ START "dd_lambda_layer:datadog-python311_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1208,7 +1385,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "sqs", + "service": "my-queue", "resource": "my-queue", "name": "aws.sqs", "error": 0, @@ -1219,6 +1396,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.sqs", "resource_names": "my-queue", + "span.kind": "server", "queuename": "my-queue", "event_source_arn": "arn:aws:sqs:us-east-2:XXXX:us-east-2-queue", "receipt_handle": "AQEBwJnKyrHigUMZj6rYigCgxlaS3SLy0a...", @@ -1226,11 +1404,10 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -1243,7 +1420,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-async-metrics_python311", "name": "aws.lambda", "error": 0, @@ -1261,8 +1438,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "sqs", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -1273,8 +1449,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1299,8 +1475,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1335,8 +1511,8 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-async-metrics_python311", "resource:integration-tests-python-XXXX-async-metrics_python311", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.11", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python311_X.X.X" @@ -1362,8 +1538,8 @@ START "dd_lambda_layer:datadog-python311_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1381,9 +1557,10 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "runtime-id": "XXXX", "_dd.origin": "lambda", "operation_name": "aws.apigateway.websocket", - "http.url": "XXXX.execute-api.eu-west-1.amazonaws.com$default", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com$default/", "endpoint": "$default", "resource_names": "$default", + "span.kind": "server", "apiid": "XXXX", "apiname": "XXXX", "stage": "dev", @@ -1395,11 +1572,10 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.tag_source": "self", "http.status_code": "200", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -1412,7 +1588,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-async-metrics_python311", "name": "aws.lambda", "error": 0, @@ -1431,9 +1607,9 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "span.name": "aws.lambda", "function_trigger.event_source": "api-gateway", "function_trigger.event_source_arn": "XXXX", - "http.url": "XXXX.execute-api.eu-west-1.amazonaws.com", - "http.status_code": "200", - "_dd.base_service": "integration-tests-python" + "span.kind": "server", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com/", + "http.status_code": "200" }, "metrics": { "_dd.top_level": 1 @@ -1444,8 +1620,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1470,8 +1646,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", diff --git a/tests/integration/snapshots/logs/async-metrics_python37.log b/tests/integration/snapshots/logs/async-metrics_python312.log similarity index 74% rename from tests/integration/snapshots/logs/async-metrics_python37.log rename to tests/integration/snapshots/logs/async-metrics_python312.log index bdde3f9ef..789a39551 100644 --- a/tests/integration/snapshots/logs/async-metrics_python37.log +++ b/tests/integration/snapshots/logs/async-metrics_python312.log @@ -1,4 +1,4 @@ -INIT_START Runtime Version: python:3.7.vX Runtime Version ARN: arn:aws:lambda:eu-west-1:XXXX:eu-west-1 +INIT_START Runtime Version: python:3.12.vX Runtime Version ARN: arn:aws:lambda:eu-west-1:XXXX:eu-west-1 START { "m": "aws.lambda.enhanced.invocations", @@ -7,13 +7,13 @@ START "t": [ "region:eu-west-1", "account_id:XXXX", - "functionname:integration-tests-python-XXXX-async-metrics_python37", - "resource:integration-tests-python-XXXX-async-metrics_python37", - "cold_start:true", + "functionname:integration-tests-python-XXXX-async-metrics_python312", + "resource:integration-tests-python-XXXX-async-metrics_python312", "memorysize:1024", - "runtime:python3.7", + "cold_start:true", + "runtime:python3.12", "datadog_lambda:vXX", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python312_X.X.X" ] } { @@ -23,7 +23,7 @@ START "t": [ "team:serverless", "role:hello", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python312_X.X.X" ] } { @@ -33,11 +33,11 @@ START "t": [ "test:integration", "role:hello", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python312_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -55,10 +55,11 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "runtime-id": "XXXX", "_dd.origin": "lambda", "operation_name": "aws.apigateway.rest", - "http.url": "XXXX.execute-api.us-east-2.amazonaws.com/", + "http.url": "https://xxxx.execute-api.us-east-2.amazonaws.com/", "endpoint": "/", "http.method": "GET", "resource_names": "GET /", + "span.kind": "server", "apiid": "XXXX", "apiname": "XXXX", "stage": "Prod", @@ -66,12 +67,12 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "sync", "_inferred_span.tag_source": "self", "http.status_code": "200", + "http.route": "/", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -84,8 +85,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "integration-tests-python-XXXX-async-metrics_python37", + "service": "integration-tests-python", + "resource": "integration-tests-python-XXXX-async-metrics_python312", "name": "aws.lambda", "error": 0, "start": "XXXX", @@ -93,21 +94,21 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "meta": { "_dd.origin": "lambda", "cold_start": "true", - "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-async-metrics_python37", + "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-async-metrics_python312", "function_version": "$LATEST", "request_id": "XXXX", - "resource_names": "integration-tests-python-XXXX-async-metrics_python37", - "functionname": "integration-tests-python-XXXX-async-metrics_python37", + "resource_names": "integration-tests-python-XXXX-async-metrics_python312", + "functionname": "integration-tests-python-XXXX-async-metrics_python312", "datadog_lambda": "X.X.X", "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "api-gateway", "function_trigger.event_source_arn": "XXXX", - "http.url": "XXXX.execute-api.us-east-2.amazonaws.com", - "http.url_details.path": "/Prod/", + "span.kind": "server", + "http.url": "https://xxxx.execute-api.us-east-2.amazonaws.com/Prod/", "http.method": "GET", - "http.status_code": "200", - "_dd.base_service": "integration-tests-python" + "http.route": "/", + "http.status_code": "200" }, "metrics": { "_dd.top_level": 1 @@ -118,8 +119,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -144,8 +145,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -178,13 +179,150 @@ START "t": [ "region:eu-west-1", "account_id:XXXX", - "functionname:integration-tests-python-XXXX-async-metrics_python37", - "resource:integration-tests-python-XXXX-async-metrics_python37", + "functionname:integration-tests-python-XXXX-async-metrics_python312", + "resource:integration-tests-python-XXXX-async-metrics_python312", + "memorysize:1024", "cold_start:false", + "runtime:python3.12", + "datadog_lambda:vXX", + "dd_lambda_layer:datadog-python312_X.X.X" + ] +} +{ + "m": "hello.dog", + "v": 1, + "e": XXXX, + "t": [ + "team:serverless", + "role:hello", + "dd_lambda_layer:datadog-python312_X.X.X" + ] +} +{ + "m": "tests.integration.count", + "v": 21, + "e": XXXX, + "t": [ + "test:integration", + "role:hello", + "dd_lambda_layer:datadog-python312_X.X.X" + ] +} +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +{ + "traces": [ + [ + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "integration-tests-python", + "resource": "integration-tests-python-XXXX-async-metrics_python312", + "name": "aws.lambda", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "runtime-id": "XXXX", + "_dd.origin": "lambda", + "cold_start": "false", + "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-async-metrics_python312", + "function_version": "$LATEST", + "request_id": "XXXX", + "resource_names": "integration-tests-python-XXXX-async-metrics_python312", + "functionname": "integration-tests-python-XXXX-async-metrics_python312", + "datadog_lambda": "X.X.X", + "dd_trace": "X.X.X", + "span.name": "aws.lambda", + "language": "python" + }, + "metrics": { + "process_id": XXXX, + "_dd.top_level": 1, + "_sampling_priority_v1": 1 + }, + "type": "serverless" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://datadoghq.com/", + "out.host": "datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1 + }, + "type": "http" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://www.datadoghq.com/", + "out.host": "www.datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1 + }, + "type": "http" + } + ] + ] +} +END Duration: XXXX ms Memory Used: XXXX MB +START +{ + "m": "aws.lambda.enhanced.invocations", + "v": 1, + "e": XXXX, + "t": [ + "region:eu-west-1", + "account_id:XXXX", + "functionname:integration-tests-python-XXXX-async-metrics_python312", + "resource:integration-tests-python-XXXX-async-metrics_python312", "memorysize:1024", - "runtime:python3.7", + "cold_start:false", + "runtime:python3.12", "datadog_lambda:vXX", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python312_X.X.X" + ] +} +{ + "m": "datadog.serverless.dynamodb.stream.type", + "v": 1, + "e": XXXX, + "t": [ + "streamtype:NEW_AND_OLD_IMAGES", + "dd_lambda_layer:datadog-python312_X.X.X" ] } { @@ -194,7 +332,7 @@ START "t": [ "team:serverless", "role:hello", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python312_X.X.X" ] } { @@ -204,11 +342,11 @@ START "t": [ "test:integration", "role:hello", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python312_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -216,7 +354,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "dynamodb", + "service": "ExampleTableWithStream", "resource": "ExampleTableWithStream", "name": "aws.dynamodb", "error": 0, @@ -227,6 +365,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.dynamodb", "resource_names": "ExampleTableWithStream", + "span.kind": "server", "tablename": "ExampleTableWithStream", "event_source_arn": "arn:aws:dynamodb:us-east-1:XXXX:us-east-1/ExampleTableWithStream/stream/2015-06-27T00:48:05.899", "event_id": "XXXX", @@ -237,25 +376,56 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, - "type": "web" + "type": "web", + "span_links": [ + { + "trace_id": "XXXX", + "span_id": "XXXX", + "attributes": { + "ptr.kind": "aws.dynamodb.item", + "ptr.dir": "u", + "ptr.hash": "e2af34d333891f765c7f02d2da80895e", + "link.kind": "span-pointer" + } + }, + { + "trace_id": "XXXX", + "span_id": "XXXX", + "attributes": { + "ptr.kind": "aws.dynamodb.item", + "ptr.dir": "u", + "ptr.hash": "e2af34d333891f765c7f02d2da80895e", + "link.kind": "span-pointer" + } + }, + { + "trace_id": "XXXX", + "span_id": "XXXX", + "attributes": { + "ptr.kind": "aws.dynamodb.item", + "ptr.dir": "u", + "ptr.hash": "e2af34d333891f765c7f02d2da80895e", + "link.kind": "span-pointer" + } + } + ] }, { "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "integration-tests-python-XXXX-async-metrics_python37", + "service": "integration-tests-python", + "resource": "integration-tests-python-XXXX-async-metrics_python312", "name": "aws.lambda", "error": 0, "start": "XXXX", @@ -263,17 +433,16 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "meta": { "_dd.origin": "lambda", "cold_start": "false", - "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-async-metrics_python37", + "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-async-metrics_python312", "function_version": "$LATEST", "request_id": "XXXX", - "resource_names": "integration-tests-python-XXXX-async-metrics_python37", - "functionname": "integration-tests-python-XXXX-async-metrics_python37", + "resource_names": "integration-tests-python-XXXX-async-metrics_python312", + "functionname": "integration-tests-python-XXXX-async-metrics_python312", "datadog_lambda": "X.X.X", "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "dynamodb", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -284,8 +453,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -310,8 +479,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -344,13 +513,13 @@ START "t": [ "region:eu-west-1", "account_id:XXXX", - "functionname:integration-tests-python-XXXX-async-metrics_python37", - "resource:integration-tests-python-XXXX-async-metrics_python37", - "cold_start:false", + "functionname:integration-tests-python-XXXX-async-metrics_python312", + "resource:integration-tests-python-XXXX-async-metrics_python312", "memorysize:1024", - "runtime:python3.7", + "cold_start:false", + "runtime:python3.12", "datadog_lambda:vXX", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python312_X.X.X" ] } { @@ -360,7 +529,7 @@ START "t": [ "team:serverless", "role:hello", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python312_X.X.X" ] } { @@ -370,11 +539,11 @@ START "t": [ "test:integration", "role:hello", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python312_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -382,7 +551,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "eventbridge", + "service": "eventbridge.custom.event.sender", "resource": "eventbridge.custom.event.sender", "name": "aws.eventbridge", "error": 0, @@ -393,15 +562,15 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.eventbridge", "resource_names": "eventbridge.custom.event.sender", + "span.kind": "server", "detail_type": "testdetail", "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -414,8 +583,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "integration-tests-python-XXXX-async-metrics_python37", + "service": "integration-tests-python", + "resource": "integration-tests-python-XXXX-async-metrics_python312", "name": "aws.lambda", "error": 0, "start": "XXXX", @@ -423,16 +592,15 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "meta": { "_dd.origin": "lambda", "cold_start": "false", - "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-async-metrics_python37", + "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-async-metrics_python312", "function_version": "$LATEST", "request_id": "XXXX", - "resource_names": "integration-tests-python-XXXX-async-metrics_python37", - "functionname": "integration-tests-python-XXXX-async-metrics_python37", + "resource_names": "integration-tests-python-XXXX-async-metrics_python312", + "functionname": "integration-tests-python-XXXX-async-metrics_python312", "datadog_lambda": "X.X.X", "dd_trace": "X.X.X", "span.name": "aws.lambda", - "function_trigger.event_source": "eventbridge", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source": "eventbridge" }, "metrics": { "_dd.top_level": 1 @@ -443,8 +611,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -469,8 +637,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -503,13 +671,13 @@ START "t": [ "region:eu-west-1", "account_id:XXXX", - "functionname:integration-tests-python-XXXX-async-metrics_python37", - "resource:integration-tests-python-XXXX-async-metrics_python37", - "cold_start:false", + "functionname:integration-tests-python-XXXX-async-metrics_python312", + "resource:integration-tests-python-XXXX-async-metrics_python312", "memorysize:1024", - "runtime:python3.7", + "cold_start:false", + "runtime:python3.12", "datadog_lambda:vXX", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python312_X.X.X" ] } { @@ -519,7 +687,7 @@ START "t": [ "team:serverless", "role:hello", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python312_X.X.X" ] } { @@ -529,11 +697,11 @@ START "t": [ "test:integration", "role:hello", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python312_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -552,7 +720,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.httpapi", "endpoint": "/httpapi/get", - "http.url": "XXXX.execute-api.eu-west-1.amazonaws.com/httpapi/get", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com/httpapi/get", "http.method": "GET", "http.protocol": "HTTP/1.1", "http.source_ip": "XXXX", @@ -565,12 +733,12 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "sync", "_inferred_span.tag_source": "self", "http.status_code": "200", + "http.route": "/httpapi/get", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -583,8 +751,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "integration-tests-python-XXXX-async-metrics_python37", + "service": "integration-tests-python", + "resource": "integration-tests-python-XXXX-async-metrics_python312", "name": "aws.lambda", "error": 0, "start": "XXXX", @@ -592,21 +760,21 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "meta": { "_dd.origin": "lambda", "cold_start": "false", - "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-async-metrics_python37", + "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-async-metrics_python312", "function_version": "$LATEST", "request_id": "XXXX", - "resource_names": "integration-tests-python-XXXX-async-metrics_python37", - "functionname": "integration-tests-python-XXXX-async-metrics_python37", + "resource_names": "integration-tests-python-XXXX-async-metrics_python312", + "functionname": "integration-tests-python-XXXX-async-metrics_python312", "datadog_lambda": "X.X.X", "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "api-gateway", "function_trigger.event_source_arn": "XXXX$default", - "http.url": "XXXX.execute-api.eu-west-1.amazonaws.com", - "http.url_details.path": "/httpapi/get", + "span.kind": "server", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com/httpapi/get", "http.method": "GET", - "http.status_code": "200", - "_dd.base_service": "integration-tests-python" + "http.route": "/httpapi/get", + "http.status_code": "200" }, "metrics": { "_dd.top_level": 1 @@ -617,8 +785,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -643,8 +811,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -677,13 +845,13 @@ START "t": [ "region:eu-west-1", "account_id:XXXX", - "functionname:integration-tests-python-XXXX-async-metrics_python37", - "resource:integration-tests-python-XXXX-async-metrics_python37", - "cold_start:false", + "functionname:integration-tests-python-XXXX-async-metrics_python312", + "resource:integration-tests-python-XXXX-async-metrics_python312", "memorysize:1024", - "runtime:python3.7", + "cold_start:false", + "runtime:python3.12", "datadog_lambda:vXX", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python312_X.X.X" ] } { @@ -693,7 +861,7 @@ START "t": [ "team:serverless", "role:hello", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python312_X.X.X" ] } { @@ -703,11 +871,11 @@ START "t": [ "test:integration", "role:hello", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python312_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -715,7 +883,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "kinesis", + "service": "EXAMPLE", "resource": "EXAMPLE", "name": "aws.kinesis", "error": 0, @@ -726,6 +894,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.kinesis", "resource_names": "EXAMPLE", + "span.kind": "server", "streamname": "EXAMPLE", "shardid": "shardId-XXXX", "event_source_arn": "arn:aws:kinesis:EXAMPLE", @@ -736,11 +905,10 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -753,8 +921,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "integration-tests-python-XXXX-async-metrics_python37", + "service": "integration-tests-python", + "resource": "integration-tests-python-XXXX-async-metrics_python312", "name": "aws.lambda", "error": 0, "start": "XXXX", @@ -762,17 +930,16 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "meta": { "_dd.origin": "lambda", "cold_start": "false", - "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-async-metrics_python37", + "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-async-metrics_python312", "function_version": "$LATEST", "request_id": "XXXX", - "resource_names": "integration-tests-python-XXXX-async-metrics_python37", - "functionname": "integration-tests-python-XXXX-async-metrics_python37", + "resource_names": "integration-tests-python-XXXX-async-metrics_python312", + "functionname": "integration-tests-python-XXXX-async-metrics_python312", "datadog_lambda": "X.X.X", "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "kinesis", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -783,8 +950,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -809,8 +976,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -843,13 +1010,13 @@ START "t": [ "region:eu-west-1", "account_id:XXXX", - "functionname:integration-tests-python-XXXX-async-metrics_python37", - "resource:integration-tests-python-XXXX-async-metrics_python37", - "cold_start:false", + "functionname:integration-tests-python-XXXX-async-metrics_python312", + "resource:integration-tests-python-XXXX-async-metrics_python312", "memorysize:1024", - "runtime:python3.7", + "cold_start:false", + "runtime:python3.12", "datadog_lambda:vXX", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python312_X.X.X" ] } { @@ -859,7 +1026,7 @@ START "t": [ "team:serverless", "role:hello", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python312_X.X.X" ] } { @@ -869,11 +1036,11 @@ START "t": [ "test:integration", "role:hello", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python312_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -881,7 +1048,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "s3", + "service": "example-bucket", "resource": "example-bucket", "name": "aws.s3", "error": 0, @@ -890,6 +1057,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.s3", "resource_names": "example-bucket", + "span.kind": "server", "event_name": "ObjectCreated:Put", "bucketname": "example-bucket", "bucket_arn": "arn:aws:s3:::example-bucket", @@ -899,25 +1067,36 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, - "type": "web" + "type": "web", + "span_links": [ + { + "trace_id": "XXXX", + "span_id": "XXXX", + "attributes": { + "ptr.kind": "aws.s3.object", + "ptr.dir": "u", + "ptr.hash": "1dc3e5d00dae48c1f07d95371a747788", + "link.kind": "span-pointer" + } + } + ] }, { "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "integration-tests-python-XXXX-async-metrics_python37", + "service": "integration-tests-python", + "resource": "integration-tests-python-XXXX-async-metrics_python312", "name": "aws.lambda", "error": 0, "start": "XXXX", @@ -925,17 +1104,16 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "meta": { "_dd.origin": "lambda", "cold_start": "false", - "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-async-metrics_python37", + "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-async-metrics_python312", "function_version": "$LATEST", "request_id": "XXXX", - "resource_names": "integration-tests-python-XXXX-async-metrics_python37", - "functionname": "integration-tests-python-XXXX-async-metrics_python37", + "resource_names": "integration-tests-python-XXXX-async-metrics_python312", + "functionname": "integration-tests-python-XXXX-async-metrics_python312", "datadog_lambda": "X.X.X", "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "s3", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -946,8 +1124,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -972,8 +1150,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1006,13 +1184,13 @@ START "t": [ "region:eu-west-1", "account_id:XXXX", - "functionname:integration-tests-python-XXXX-async-metrics_python37", - "resource:integration-tests-python-XXXX-async-metrics_python37", - "cold_start:false", + "functionname:integration-tests-python-XXXX-async-metrics_python312", + "resource:integration-tests-python-XXXX-async-metrics_python312", "memorysize:1024", - "runtime:python3.7", + "cold_start:false", + "runtime:python3.12", "datadog_lambda:vXX", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python312_X.X.X" ] } { @@ -1022,7 +1200,7 @@ START "t": [ "team:serverless", "role:hello", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python312_X.X.X" ] } { @@ -1032,11 +1210,11 @@ START "t": [ "test:integration", "role:hello", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python312_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1044,7 +1222,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "sns", + "service": "sns-lambda", "resource": "sns-lambda", "name": "aws.sns", "error": 0, @@ -1055,6 +1233,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.sns", "resource_names": "sns-lambda", + "span.kind": "server", "topicname": "sns-lambda", "topic_arn": "arn:aws:sns:us-east-2:XXXX:us-east-2-lambda", "message_id": "XXXX", @@ -1063,11 +1242,10 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -1080,8 +1258,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "integration-tests-python-XXXX-async-metrics_python37", + "service": "integration-tests-python", + "resource": "integration-tests-python-XXXX-async-metrics_python312", "name": "aws.lambda", "error": 0, "start": "XXXX", @@ -1089,17 +1267,16 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "meta": { "_dd.origin": "lambda", "cold_start": "false", - "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-async-metrics_python37", + "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-async-metrics_python312", "function_version": "$LATEST", "request_id": "XXXX", - "resource_names": "integration-tests-python-XXXX-async-metrics_python37", - "functionname": "integration-tests-python-XXXX-async-metrics_python37", + "resource_names": "integration-tests-python-XXXX-async-metrics_python312", + "functionname": "integration-tests-python-XXXX-async-metrics_python312", "datadog_lambda": "X.X.X", "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "sns", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -1110,8 +1287,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1136,8 +1313,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1170,13 +1347,13 @@ START "t": [ "region:eu-west-1", "account_id:XXXX", - "functionname:integration-tests-python-XXXX-async-metrics_python37", - "resource:integration-tests-python-XXXX-async-metrics_python37", - "cold_start:false", + "functionname:integration-tests-python-XXXX-async-metrics_python312", + "resource:integration-tests-python-XXXX-async-metrics_python312", "memorysize:1024", - "runtime:python3.7", + "cold_start:false", + "runtime:python3.12", "datadog_lambda:vXX", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python312_X.X.X" ] } { @@ -1186,7 +1363,7 @@ START "t": [ "team:serverless", "role:hello", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python312_X.X.X" ] } { @@ -1196,11 +1373,11 @@ START "t": [ "test:integration", "role:hello", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python312_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1208,7 +1385,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "sqs", + "service": "my-queue", "resource": "my-queue", "name": "aws.sqs", "error": 0, @@ -1219,6 +1396,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.sqs", "resource_names": "my-queue", + "span.kind": "server", "queuename": "my-queue", "event_source_arn": "arn:aws:sqs:us-east-2:XXXX:us-east-2-queue", "receipt_handle": "AQEBwJnKyrHigUMZj6rYigCgxlaS3SLy0a...", @@ -1226,11 +1404,10 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -1243,8 +1420,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "integration-tests-python-XXXX-async-metrics_python37", + "service": "integration-tests-python", + "resource": "integration-tests-python-XXXX-async-metrics_python312", "name": "aws.lambda", "error": 0, "start": "XXXX", @@ -1252,17 +1429,16 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "meta": { "_dd.origin": "lambda", "cold_start": "false", - "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-async-metrics_python37", + "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-async-metrics_python312", "function_version": "$LATEST", "request_id": "XXXX", - "resource_names": "integration-tests-python-XXXX-async-metrics_python37", - "functionname": "integration-tests-python-XXXX-async-metrics_python37", + "resource_names": "integration-tests-python-XXXX-async-metrics_python312", + "functionname": "integration-tests-python-XXXX-async-metrics_python312", "datadog_lambda": "X.X.X", "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "sqs", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -1273,8 +1449,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1299,8 +1475,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1333,13 +1509,13 @@ START "t": [ "region:eu-west-1", "account_id:XXXX", - "functionname:integration-tests-python-XXXX-async-metrics_python37", - "resource:integration-tests-python-XXXX-async-metrics_python37", - "cold_start:false", + "functionname:integration-tests-python-XXXX-async-metrics_python312", + "resource:integration-tests-python-XXXX-async-metrics_python312", "memorysize:1024", - "runtime:python3.7", + "cold_start:false", + "runtime:python3.12", "datadog_lambda:vXX", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python312_X.X.X" ] } { @@ -1349,7 +1525,7 @@ START "t": [ "team:serverless", "role:hello", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python312_X.X.X" ] } { @@ -1359,11 +1535,11 @@ START "t": [ "test:integration", "role:hello", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python312_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1381,9 +1557,10 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "runtime-id": "XXXX", "_dd.origin": "lambda", "operation_name": "aws.apigateway.websocket", - "http.url": "XXXX.execute-api.eu-west-1.amazonaws.com$default", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com$default/", "endpoint": "$default", "resource_names": "$default", + "span.kind": "server", "apiid": "XXXX", "apiname": "XXXX", "stage": "dev", @@ -1395,11 +1572,10 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.tag_source": "self", "http.status_code": "200", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -1412,8 +1588,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "integration-tests-python-XXXX-async-metrics_python37", + "service": "integration-tests-python", + "resource": "integration-tests-python-XXXX-async-metrics_python312", "name": "aws.lambda", "error": 0, "start": "XXXX", @@ -1421,19 +1597,19 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "meta": { "_dd.origin": "lambda", "cold_start": "false", - "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-async-metrics_python37", + "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-async-metrics_python312", "function_version": "$LATEST", "request_id": "XXXX", - "resource_names": "integration-tests-python-XXXX-async-metrics_python37", - "functionname": "integration-tests-python-XXXX-async-metrics_python37", + "resource_names": "integration-tests-python-XXXX-async-metrics_python312", + "functionname": "integration-tests-python-XXXX-async-metrics_python312", "datadog_lambda": "X.X.X", "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "api-gateway", "function_trigger.event_source_arn": "XXXX", - "http.url": "XXXX.execute-api.eu-west-1.amazonaws.com", - "http.status_code": "200", - "_dd.base_service": "integration-tests-python" + "span.kind": "server", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com/", + "http.status_code": "200" }, "metrics": { "_dd.top_level": 1 @@ -1444,8 +1620,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1470,8 +1646,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", diff --git a/tests/integration/snapshots/logs/async-metrics_python313.log b/tests/integration/snapshots/logs/async-metrics_python313.log new file mode 100644 index 000000000..78ade6a7a --- /dev/null +++ b/tests/integration/snapshots/logs/async-metrics_python313.log @@ -0,0 +1,1674 @@ +INIT_START Runtime Version: python:3.13.vX Runtime Version ARN: arn:aws:lambda:eu-west-1:XXXX:eu-west-1 +START +{ + "m": "aws.lambda.enhanced.invocations", + "v": 1, + "e": XXXX, + "t": [ + "region:eu-west-1", + "account_id:XXXX", + "functionname:integration-tests-python-XXXX-async-metrics_python313", + "resource:integration-tests-python-XXXX-async-metrics_python313", + "memorysize:1024", + "cold_start:true", + "runtime:python3.13", + "datadog_lambda:vXX", + "dd_lambda_layer:datadog-python313_X.X.X" + ] +} +{ + "m": "hello.dog", + "v": 1, + "e": XXXX, + "t": [ + "team:serverless", + "role:hello", + "dd_lambda_layer:datadog-python313_X.X.X" + ] +} +{ + "m": "tests.integration.count", + "v": 21, + "e": XXXX, + "t": [ + "test:integration", + "role:hello", + "dd_lambda_layer:datadog-python313_X.X.X" + ] +} +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +{ + "traces": [ + [ + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "XXXX.execute-api.us-east-2.amazonaws.com", + "resource": "GET /", + "name": "aws.apigateway", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "runtime-id": "XXXX", + "_dd.origin": "lambda", + "operation_name": "aws.apigateway.rest", + "http.url": "https://xxxx.execute-api.us-east-2.amazonaws.com/", + "endpoint": "/", + "http.method": "GET", + "resource_names": "GET /", + "span.kind": "server", + "apiid": "XXXX", + "apiname": "XXXX", + "stage": "Prod", + "request_id": "XXXX", + "_inferred_span.synchronicity": "sync", + "_inferred_span.tag_source": "self", + "http.status_code": "200", + "http.route": "/", + "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", + "_dd.p.dm": "-0", + "_dd.p.tid": "XXXX", + "language": "python" + }, + "metrics": { + "process_id": XXXX, + "_dd.top_level": 1, + "_sampling_priority_v1": 1 + }, + "type": "http" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "integration-tests-python", + "resource": "integration-tests-python-XXXX-async-metrics_python313", + "name": "aws.lambda", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "cold_start": "true", + "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-async-metrics_python313", + "function_version": "$LATEST", + "request_id": "XXXX", + "resource_names": "integration-tests-python-XXXX-async-metrics_python313", + "functionname": "integration-tests-python-XXXX-async-metrics_python313", + "datadog_lambda": "X.X.X", + "dd_trace": "X.X.X", + "span.name": "aws.lambda", + "function_trigger.event_source": "api-gateway", + "function_trigger.event_source_arn": "XXXX", + "span.kind": "server", + "http.url": "https://xxxx.execute-api.us-east-2.amazonaws.com/Prod/", + "http.method": "GET", + "http.route": "/", + "http.status_code": "200" + }, + "metrics": { + "_dd.top_level": 1 + }, + "type": "serverless" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://datadoghq.com/", + "out.host": "datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1 + }, + "type": "http" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.p.tid": "XXXX", + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://www.datadoghq.com/", + "out.host": "www.datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1 + }, + "type": "http" + } + ] + ] +} +END Duration: XXXX ms (init: XXXX ms) Memory Used: XXXX MB +START +{ + "m": "aws.lambda.enhanced.invocations", + "v": 1, + "e": XXXX, + "t": [ + "region:eu-west-1", + "account_id:XXXX", + "functionname:integration-tests-python-XXXX-async-metrics_python313", + "resource:integration-tests-python-XXXX-async-metrics_python313", + "memorysize:1024", + "cold_start:false", + "runtime:python3.13", + "datadog_lambda:vXX", + "dd_lambda_layer:datadog-python313_X.X.X" + ] +} +{ + "m": "hello.dog", + "v": 1, + "e": XXXX, + "t": [ + "team:serverless", + "role:hello", + "dd_lambda_layer:datadog-python313_X.X.X" + ] +} +{ + "m": "tests.integration.count", + "v": 21, + "e": XXXX, + "t": [ + "test:integration", + "role:hello", + "dd_lambda_layer:datadog-python313_X.X.X" + ] +} +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +{ + "traces": [ + [ + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "integration-tests-python", + "resource": "integration-tests-python-XXXX-async-metrics_python313", + "name": "aws.lambda", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "runtime-id": "XXXX", + "_dd.origin": "lambda", + "cold_start": "false", + "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-async-metrics_python313", + "function_version": "$LATEST", + "request_id": "XXXX", + "resource_names": "integration-tests-python-XXXX-async-metrics_python313", + "functionname": "integration-tests-python-XXXX-async-metrics_python313", + "datadog_lambda": "X.X.X", + "dd_trace": "X.X.X", + "span.name": "aws.lambda", + "language": "python" + }, + "metrics": { + "process_id": XXXX, + "_dd.top_level": 1, + "_sampling_priority_v1": 1 + }, + "type": "serverless" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://datadoghq.com/", + "out.host": "datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1 + }, + "type": "http" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://www.datadoghq.com/", + "out.host": "www.datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1 + }, + "type": "http" + } + ] + ] +} +END Duration: XXXX ms Memory Used: XXXX MB +START +{ + "m": "aws.lambda.enhanced.invocations", + "v": 1, + "e": XXXX, + "t": [ + "region:eu-west-1", + "account_id:XXXX", + "functionname:integration-tests-python-XXXX-async-metrics_python313", + "resource:integration-tests-python-XXXX-async-metrics_python313", + "memorysize:1024", + "cold_start:false", + "runtime:python3.13", + "datadog_lambda:vXX", + "dd_lambda_layer:datadog-python313_X.X.X" + ] +} +{ + "m": "datadog.serverless.dynamodb.stream.type", + "v": 1, + "e": XXXX, + "t": [ + "streamtype:NEW_AND_OLD_IMAGES", + "dd_lambda_layer:datadog-python313_X.X.X" + ] +} +{ + "m": "hello.dog", + "v": 1, + "e": XXXX, + "t": [ + "team:serverless", + "role:hello", + "dd_lambda_layer:datadog-python313_X.X.X" + ] +} +{ + "m": "tests.integration.count", + "v": 21, + "e": XXXX, + "t": [ + "test:integration", + "role:hello", + "dd_lambda_layer:datadog-python313_X.X.X" + ] +} +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +{ + "traces": [ + [ + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "ExampleTableWithStream", + "resource": "ExampleTableWithStream", + "name": "aws.dynamodb", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "runtime-id": "XXXX", + "_dd.origin": "lambda", + "operation_name": "aws.dynamodb", + "resource_names": "ExampleTableWithStream", + "span.kind": "server", + "tablename": "ExampleTableWithStream", + "event_source_arn": "arn:aws:dynamodb:us-east-1:XXXX:us-east-1/ExampleTableWithStream/stream/2015-06-27T00:48:05.899", + "event_id": "XXXX", + "event_name": "INSERT", + "event_version": "1.1", + "stream_view_type": "NEW_AND_OLD_IMAGES", + "size_bytes": "26", + "_inferred_span.synchronicity": "async", + "_inferred_span.tag_source": "self", + "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", + "_dd.p.dm": "-0", + "_dd.p.tid": "XXXX", + "language": "python" + }, + "metrics": { + "process_id": XXXX, + "_dd.top_level": 1, + "_sampling_priority_v1": 1 + }, + "type": "web", + "span_links": [ + { + "trace_id": "XXXX", + "span_id": "XXXX", + "attributes": { + "ptr.kind": "aws.dynamodb.item", + "ptr.dir": "u", + "ptr.hash": "e2af34d333891f765c7f02d2da80895e", + "link.kind": "span-pointer" + } + }, + { + "trace_id": "XXXX", + "span_id": "XXXX", + "attributes": { + "ptr.kind": "aws.dynamodb.item", + "ptr.dir": "u", + "ptr.hash": "e2af34d333891f765c7f02d2da80895e", + "link.kind": "span-pointer" + } + }, + { + "trace_id": "XXXX", + "span_id": "XXXX", + "attributes": { + "ptr.kind": "aws.dynamodb.item", + "ptr.dir": "u", + "ptr.hash": "e2af34d333891f765c7f02d2da80895e", + "link.kind": "span-pointer" + } + } + ] + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "integration-tests-python", + "resource": "integration-tests-python-XXXX-async-metrics_python313", + "name": "aws.lambda", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "cold_start": "false", + "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-async-metrics_python313", + "function_version": "$LATEST", + "request_id": "XXXX", + "resource_names": "integration-tests-python-XXXX-async-metrics_python313", + "functionname": "integration-tests-python-XXXX-async-metrics_python313", + "datadog_lambda": "X.X.X", + "dd_trace": "X.X.X", + "span.name": "aws.lambda", + "function_trigger.event_source": "dynamodb", + "function_trigger.event_source_arn": "XXXX" + }, + "metrics": { + "_dd.top_level": 1 + }, + "type": "serverless" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://datadoghq.com/", + "out.host": "datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1 + }, + "type": "http" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.p.tid": "XXXX", + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://www.datadoghq.com/", + "out.host": "www.datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1 + }, + "type": "http" + } + ] + ] +} +END Duration: XXXX ms Memory Used: XXXX MB +START +{ + "m": "aws.lambda.enhanced.invocations", + "v": 1, + "e": XXXX, + "t": [ + "region:eu-west-1", + "account_id:XXXX", + "functionname:integration-tests-python-XXXX-async-metrics_python313", + "resource:integration-tests-python-XXXX-async-metrics_python313", + "memorysize:1024", + "cold_start:false", + "runtime:python3.13", + "datadog_lambda:vXX", + "dd_lambda_layer:datadog-python313_X.X.X" + ] +} +{ + "m": "hello.dog", + "v": 1, + "e": XXXX, + "t": [ + "team:serverless", + "role:hello", + "dd_lambda_layer:datadog-python313_X.X.X" + ] +} +{ + "m": "tests.integration.count", + "v": 21, + "e": XXXX, + "t": [ + "test:integration", + "role:hello", + "dd_lambda_layer:datadog-python313_X.X.X" + ] +} +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +{ + "traces": [ + [ + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "eventbridge.custom.event.sender", + "resource": "eventbridge.custom.event.sender", + "name": "aws.eventbridge", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "runtime-id": "XXXX", + "_dd.origin": "lambda", + "operation_name": "aws.eventbridge", + "resource_names": "eventbridge.custom.event.sender", + "span.kind": "server", + "detail_type": "testdetail", + "_inferred_span.synchronicity": "async", + "_inferred_span.tag_source": "self", + "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", + "_dd.p.dm": "-0", + "_dd.p.tid": "XXXX", + "language": "python" + }, + "metrics": { + "process_id": XXXX, + "_dd.top_level": 1, + "_sampling_priority_v1": 1 + }, + "type": "web" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "integration-tests-python", + "resource": "integration-tests-python-XXXX-async-metrics_python313", + "name": "aws.lambda", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "cold_start": "false", + "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-async-metrics_python313", + "function_version": "$LATEST", + "request_id": "XXXX", + "resource_names": "integration-tests-python-XXXX-async-metrics_python313", + "functionname": "integration-tests-python-XXXX-async-metrics_python313", + "datadog_lambda": "X.X.X", + "dd_trace": "X.X.X", + "span.name": "aws.lambda", + "function_trigger.event_source": "eventbridge" + }, + "metrics": { + "_dd.top_level": 1 + }, + "type": "serverless" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://datadoghq.com/", + "out.host": "datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1 + }, + "type": "http" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.p.tid": "XXXX", + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://www.datadoghq.com/", + "out.host": "www.datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1 + }, + "type": "http" + } + ] + ] +} +END Duration: XXXX ms Memory Used: XXXX MB +START +{ + "m": "aws.lambda.enhanced.invocations", + "v": 1, + "e": XXXX, + "t": [ + "region:eu-west-1", + "account_id:XXXX", + "functionname:integration-tests-python-XXXX-async-metrics_python313", + "resource:integration-tests-python-XXXX-async-metrics_python313", + "memorysize:1024", + "cold_start:false", + "runtime:python3.13", + "datadog_lambda:vXX", + "dd_lambda_layer:datadog-python313_X.X.X" + ] +} +{ + "m": "hello.dog", + "v": 1, + "e": XXXX, + "t": [ + "team:serverless", + "role:hello", + "dd_lambda_layer:datadog-python313_X.X.X" + ] +} +{ + "m": "tests.integration.count", + "v": 21, + "e": XXXX, + "t": [ + "test:integration", + "role:hello", + "dd_lambda_layer:datadog-python313_X.X.X" + ] +} +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +{ + "traces": [ + [ + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "XXXX.execute-api.eu-west-1.amazonaws.com", + "resource": "GET /httpapi/get", + "name": "aws.httpapi", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "runtime-id": "XXXX", + "_dd.origin": "lambda", + "operation_name": "aws.httpapi", + "endpoint": "/httpapi/get", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com/httpapi/get", + "http.method": "GET", + "http.protocol": "HTTP/1.1", + "http.source_ip": "XXXX", + "http.user_agent": "XXXX/7.64.1", + "resource_names": "GET /httpapi/get", + "request_id": "XXXX", + "apiid": "XXXX", + "apiname": "XXXX", + "stage": "$default", + "_inferred_span.synchronicity": "sync", + "_inferred_span.tag_source": "self", + "http.status_code": "200", + "http.route": "/httpapi/get", + "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", + "_dd.p.dm": "-0", + "_dd.p.tid": "XXXX", + "language": "python" + }, + "metrics": { + "process_id": XXXX, + "_dd.top_level": 1, + "_sampling_priority_v1": 1 + }, + "type": "http" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "integration-tests-python", + "resource": "integration-tests-python-XXXX-async-metrics_python313", + "name": "aws.lambda", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "cold_start": "false", + "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-async-metrics_python313", + "function_version": "$LATEST", + "request_id": "XXXX", + "resource_names": "integration-tests-python-XXXX-async-metrics_python313", + "functionname": "integration-tests-python-XXXX-async-metrics_python313", + "datadog_lambda": "X.X.X", + "dd_trace": "X.X.X", + "span.name": "aws.lambda", + "function_trigger.event_source": "api-gateway", + "function_trigger.event_source_arn": "XXXX$default", + "span.kind": "server", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com/httpapi/get", + "http.method": "GET", + "http.route": "/httpapi/get", + "http.status_code": "200" + }, + "metrics": { + "_dd.top_level": 1 + }, + "type": "serverless" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://datadoghq.com/", + "out.host": "datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1 + }, + "type": "http" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.p.tid": "XXXX", + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://www.datadoghq.com/", + "out.host": "www.datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1 + }, + "type": "http" + } + ] + ] +} +END Duration: XXXX ms Memory Used: XXXX MB +START +{ + "m": "aws.lambda.enhanced.invocations", + "v": 1, + "e": XXXX, + "t": [ + "region:eu-west-1", + "account_id:XXXX", + "functionname:integration-tests-python-XXXX-async-metrics_python313", + "resource:integration-tests-python-XXXX-async-metrics_python313", + "memorysize:1024", + "cold_start:false", + "runtime:python3.13", + "datadog_lambda:vXX", + "dd_lambda_layer:datadog-python313_X.X.X" + ] +} +{ + "m": "hello.dog", + "v": 1, + "e": XXXX, + "t": [ + "team:serverless", + "role:hello", + "dd_lambda_layer:datadog-python313_X.X.X" + ] +} +{ + "m": "tests.integration.count", + "v": 21, + "e": XXXX, + "t": [ + "test:integration", + "role:hello", + "dd_lambda_layer:datadog-python313_X.X.X" + ] +} +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +{ + "traces": [ + [ + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "EXAMPLE", + "resource": "EXAMPLE", + "name": "aws.kinesis", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "runtime-id": "XXXX", + "_dd.origin": "lambda", + "operation_name": "aws.kinesis", + "resource_names": "EXAMPLE", + "span.kind": "server", + "streamname": "EXAMPLE", + "shardid": "shardId-XXXX", + "event_source_arn": "arn:aws:kinesis:EXAMPLE", + "event_id": "XXXX", + "event_name": "aws:kinesis:record", + "event_version": "1.0", + "partition_key": "XXXX", + "_inferred_span.synchronicity": "async", + "_inferred_span.tag_source": "self", + "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", + "_dd.p.dm": "-0", + "_dd.p.tid": "XXXX", + "language": "python" + }, + "metrics": { + "process_id": XXXX, + "_dd.top_level": 1, + "_sampling_priority_v1": 1 + }, + "type": "web" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "integration-tests-python", + "resource": "integration-tests-python-XXXX-async-metrics_python313", + "name": "aws.lambda", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "cold_start": "false", + "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-async-metrics_python313", + "function_version": "$LATEST", + "request_id": "XXXX", + "resource_names": "integration-tests-python-XXXX-async-metrics_python313", + "functionname": "integration-tests-python-XXXX-async-metrics_python313", + "datadog_lambda": "X.X.X", + "dd_trace": "X.X.X", + "span.name": "aws.lambda", + "function_trigger.event_source": "kinesis", + "function_trigger.event_source_arn": "XXXX" + }, + "metrics": { + "_dd.top_level": 1 + }, + "type": "serverless" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://datadoghq.com/", + "out.host": "datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1 + }, + "type": "http" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.p.tid": "XXXX", + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://www.datadoghq.com/", + "out.host": "www.datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1 + }, + "type": "http" + } + ] + ] +} +END Duration: XXXX ms Memory Used: XXXX MB +START +{ + "m": "aws.lambda.enhanced.invocations", + "v": 1, + "e": XXXX, + "t": [ + "region:eu-west-1", + "account_id:XXXX", + "functionname:integration-tests-python-XXXX-async-metrics_python313", + "resource:integration-tests-python-XXXX-async-metrics_python313", + "memorysize:1024", + "cold_start:false", + "runtime:python3.13", + "datadog_lambda:vXX", + "dd_lambda_layer:datadog-python313_X.X.X" + ] +} +{ + "m": "hello.dog", + "v": 1, + "e": XXXX, + "t": [ + "team:serverless", + "role:hello", + "dd_lambda_layer:datadog-python313_X.X.X" + ] +} +{ + "m": "tests.integration.count", + "v": 21, + "e": XXXX, + "t": [ + "test:integration", + "role:hello", + "dd_lambda_layer:datadog-python313_X.X.X" + ] +} +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +{ + "traces": [ + [ + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "example-bucket", + "resource": "example-bucket", + "name": "aws.s3", + "error": 0, + "meta": { + "runtime-id": "XXXX", + "_dd.origin": "lambda", + "operation_name": "aws.s3", + "resource_names": "example-bucket", + "span.kind": "server", + "event_name": "ObjectCreated:Put", + "bucketname": "example-bucket", + "bucket_arn": "arn:aws:s3:::example-bucket", + "object_key": "test/key", + "object_size": "1024", + "object_etag": "XXXX", + "_inferred_span.synchronicity": "async", + "_inferred_span.tag_source": "self", + "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", + "_dd.p.dm": "-0", + "_dd.p.tid": "XXXX", + "language": "python" + }, + "metrics": { + "process_id": XXXX, + "_dd.top_level": 1, + "_sampling_priority_v1": 1 + }, + "type": "web", + "span_links": [ + { + "trace_id": "XXXX", + "span_id": "XXXX", + "attributes": { + "ptr.kind": "aws.s3.object", + "ptr.dir": "u", + "ptr.hash": "1dc3e5d00dae48c1f07d95371a747788", + "link.kind": "span-pointer" + } + } + ] + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "integration-tests-python", + "resource": "integration-tests-python-XXXX-async-metrics_python313", + "name": "aws.lambda", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "cold_start": "false", + "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-async-metrics_python313", + "function_version": "$LATEST", + "request_id": "XXXX", + "resource_names": "integration-tests-python-XXXX-async-metrics_python313", + "functionname": "integration-tests-python-XXXX-async-metrics_python313", + "datadog_lambda": "X.X.X", + "dd_trace": "X.X.X", + "span.name": "aws.lambda", + "function_trigger.event_source": "s3", + "function_trigger.event_source_arn": "XXXX" + }, + "metrics": { + "_dd.top_level": 1 + }, + "type": "serverless" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://datadoghq.com/", + "out.host": "datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1 + }, + "type": "http" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.p.tid": "XXXX", + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://www.datadoghq.com/", + "out.host": "www.datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1 + }, + "type": "http" + } + ] + ] +} +END Duration: XXXX ms Memory Used: XXXX MB +START +{ + "m": "aws.lambda.enhanced.invocations", + "v": 1, + "e": XXXX, + "t": [ + "region:eu-west-1", + "account_id:XXXX", + "functionname:integration-tests-python-XXXX-async-metrics_python313", + "resource:integration-tests-python-XXXX-async-metrics_python313", + "memorysize:1024", + "cold_start:false", + "runtime:python3.13", + "datadog_lambda:vXX", + "dd_lambda_layer:datadog-python313_X.X.X" + ] +} +{ + "m": "hello.dog", + "v": 1, + "e": XXXX, + "t": [ + "team:serverless", + "role:hello", + "dd_lambda_layer:datadog-python313_X.X.X" + ] +} +{ + "m": "tests.integration.count", + "v": 21, + "e": XXXX, + "t": [ + "test:integration", + "role:hello", + "dd_lambda_layer:datadog-python313_X.X.X" + ] +} +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +{ + "traces": [ + [ + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "sns-lambda", + "resource": "sns-lambda", + "name": "aws.sns", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "runtime-id": "XXXX", + "_dd.origin": "lambda", + "operation_name": "aws.sns", + "resource_names": "sns-lambda", + "span.kind": "server", + "topicname": "sns-lambda", + "topic_arn": "arn:aws:sns:us-east-2:XXXX:us-east-2-lambda", + "message_id": "XXXX", + "type": "Notification", + "subject": "TestInvoke", + "_inferred_span.synchronicity": "async", + "_inferred_span.tag_source": "self", + "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", + "_dd.p.dm": "-0", + "_dd.p.tid": "XXXX", + "language": "python" + }, + "metrics": { + "process_id": XXXX, + "_dd.top_level": 1, + "_sampling_priority_v1": 1 + }, + "type": "web" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "integration-tests-python", + "resource": "integration-tests-python-XXXX-async-metrics_python313", + "name": "aws.lambda", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "cold_start": "false", + "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-async-metrics_python313", + "function_version": "$LATEST", + "request_id": "XXXX", + "resource_names": "integration-tests-python-XXXX-async-metrics_python313", + "functionname": "integration-tests-python-XXXX-async-metrics_python313", + "datadog_lambda": "X.X.X", + "dd_trace": "X.X.X", + "span.name": "aws.lambda", + "function_trigger.event_source": "sns", + "function_trigger.event_source_arn": "XXXX" + }, + "metrics": { + "_dd.top_level": 1 + }, + "type": "serverless" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://datadoghq.com/", + "out.host": "datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1 + }, + "type": "http" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.p.tid": "XXXX", + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://www.datadoghq.com/", + "out.host": "www.datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1 + }, + "type": "http" + } + ] + ] +} +END Duration: XXXX ms Memory Used: XXXX MB +START +{ + "m": "aws.lambda.enhanced.invocations", + "v": 1, + "e": XXXX, + "t": [ + "region:eu-west-1", + "account_id:XXXX", + "functionname:integration-tests-python-XXXX-async-metrics_python313", + "resource:integration-tests-python-XXXX-async-metrics_python313", + "memorysize:1024", + "cold_start:false", + "runtime:python3.13", + "datadog_lambda:vXX", + "dd_lambda_layer:datadog-python313_X.X.X" + ] +} +{ + "m": "hello.dog", + "v": 1, + "e": XXXX, + "t": [ + "team:serverless", + "role:hello", + "dd_lambda_layer:datadog-python313_X.X.X" + ] +} +{ + "m": "tests.integration.count", + "v": 21, + "e": XXXX, + "t": [ + "test:integration", + "role:hello", + "dd_lambda_layer:datadog-python313_X.X.X" + ] +} +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +{ + "traces": [ + [ + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "my-queue", + "resource": "my-queue", + "name": "aws.sqs", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "runtime-id": "XXXX", + "_dd.origin": "lambda", + "operation_name": "aws.sqs", + "resource_names": "my-queue", + "span.kind": "server", + "queuename": "my-queue", + "event_source_arn": "arn:aws:sqs:us-east-2:XXXX:us-east-2-queue", + "receipt_handle": "AQEBwJnKyrHigUMZj6rYigCgxlaS3SLy0a...", + "sender_id": "AIDAIENQZJOLO23YVJ4VO", + "_inferred_span.synchronicity": "async", + "_inferred_span.tag_source": "self", + "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", + "_dd.p.dm": "-0", + "_dd.p.tid": "XXXX", + "language": "python" + }, + "metrics": { + "process_id": XXXX, + "_dd.top_level": 1, + "_sampling_priority_v1": 1 + }, + "type": "web" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "integration-tests-python", + "resource": "integration-tests-python-XXXX-async-metrics_python313", + "name": "aws.lambda", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "cold_start": "false", + "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-async-metrics_python313", + "function_version": "$LATEST", + "request_id": "XXXX", + "resource_names": "integration-tests-python-XXXX-async-metrics_python313", + "functionname": "integration-tests-python-XXXX-async-metrics_python313", + "datadog_lambda": "X.X.X", + "dd_trace": "X.X.X", + "span.name": "aws.lambda", + "function_trigger.event_source": "sqs", + "function_trigger.event_source_arn": "XXXX" + }, + "metrics": { + "_dd.top_level": 1 + }, + "type": "serverless" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://datadoghq.com/", + "out.host": "datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1 + }, + "type": "http" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.p.tid": "XXXX", + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://www.datadoghq.com/", + "out.host": "www.datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1 + }, + "type": "http" + } + ] + ] +} +END Duration: XXXX ms Memory Used: XXXX MB +START +{ + "m": "aws.lambda.enhanced.invocations", + "v": 1, + "e": XXXX, + "t": [ + "region:eu-west-1", + "account_id:XXXX", + "functionname:integration-tests-python-XXXX-async-metrics_python313", + "resource:integration-tests-python-XXXX-async-metrics_python313", + "memorysize:1024", + "cold_start:false", + "runtime:python3.13", + "datadog_lambda:vXX", + "dd_lambda_layer:datadog-python313_X.X.X" + ] +} +{ + "m": "hello.dog", + "v": 1, + "e": XXXX, + "t": [ + "team:serverless", + "role:hello", + "dd_lambda_layer:datadog-python313_X.X.X" + ] +} +{ + "m": "tests.integration.count", + "v": 21, + "e": XXXX, + "t": [ + "test:integration", + "role:hello", + "dd_lambda_layer:datadog-python313_X.X.X" + ] +} +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +{ + "traces": [ + [ + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "XXXX.execute-api.eu-west-1.amazonaws.com", + "resource": "$default", + "name": "aws.apigateway.websocket", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "runtime-id": "XXXX", + "_dd.origin": "lambda", + "operation_name": "aws.apigateway.websocket", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com$default/", + "endpoint": "$default", + "resource_names": "$default", + "span.kind": "server", + "apiid": "XXXX", + "apiname": "XXXX", + "stage": "dev", + "request_id": "XXXX", + "connection_id": "XXXX=", + "event_type": "MESSAGE", + "message_direction": "IN", + "_inferred_span.synchronicity": "sync", + "_inferred_span.tag_source": "self", + "http.status_code": "200", + "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", + "_dd.p.dm": "-0", + "_dd.p.tid": "XXXX", + "language": "python" + }, + "metrics": { + "process_id": XXXX, + "_dd.top_level": 1, + "_sampling_priority_v1": 1 + }, + "type": "web" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "integration-tests-python", + "resource": "integration-tests-python-XXXX-async-metrics_python313", + "name": "aws.lambda", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "cold_start": "false", + "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-async-metrics_python313", + "function_version": "$LATEST", + "request_id": "XXXX", + "resource_names": "integration-tests-python-XXXX-async-metrics_python313", + "functionname": "integration-tests-python-XXXX-async-metrics_python313", + "datadog_lambda": "X.X.X", + "dd_trace": "X.X.X", + "span.name": "aws.lambda", + "function_trigger.event_source": "api-gateway", + "function_trigger.event_source_arn": "XXXX", + "span.kind": "server", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com/", + "http.status_code": "200" + }, + "metrics": { + "_dd.top_level": 1 + }, + "type": "serverless" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://datadoghq.com/", + "out.host": "datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1 + }, + "type": "http" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.p.tid": "XXXX", + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://www.datadoghq.com/", + "out.host": "www.datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1 + }, + "type": "http" + } + ] + ] +} +END Duration: XXXX ms Memory Used: XXXX MB diff --git a/tests/integration/snapshots/logs/async-metrics_python38.log b/tests/integration/snapshots/logs/async-metrics_python38.log index ae5b719f7..5375fafec 100644 --- a/tests/integration/snapshots/logs/async-metrics_python38.log +++ b/tests/integration/snapshots/logs/async-metrics_python38.log @@ -9,8 +9,8 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-async-metrics_python38", "resource:integration-tests-python-XXXX-async-metrics_python38", - "cold_start:true", "memorysize:1024", + "cold_start:true", "runtime:python3.8", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python38_X.X.X" @@ -36,8 +36,8 @@ START "dd_lambda_layer:datadog-python38_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -55,10 +55,11 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "runtime-id": "XXXX", "_dd.origin": "lambda", "operation_name": "aws.apigateway.rest", - "http.url": "XXXX.execute-api.us-east-2.amazonaws.com/", + "http.url": "https://xxxx.execute-api.us-east-2.amazonaws.com/", "endpoint": "/", "http.method": "GET", "resource_names": "GET /", + "span.kind": "server", "apiid": "XXXX", "apiname": "XXXX", "stage": "Prod", @@ -66,12 +67,12 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "sync", "_inferred_span.tag_source": "self", "http.status_code": "200", + "http.route": "/", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -84,7 +85,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-async-metrics_python38", "name": "aws.lambda", "error": 0, @@ -103,11 +104,11 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "span.name": "aws.lambda", "function_trigger.event_source": "api-gateway", "function_trigger.event_source_arn": "XXXX", - "http.url": "XXXX.execute-api.us-east-2.amazonaws.com", - "http.url_details.path": "/Prod/", + "span.kind": "server", + "http.url": "https://xxxx.execute-api.us-east-2.amazonaws.com/Prod/", "http.method": "GET", - "http.status_code": "200", - "_dd.base_service": "integration-tests-python" + "http.route": "/", + "http.status_code": "200" }, "metrics": { "_dd.top_level": 1 @@ -118,8 +119,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -144,8 +145,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -180,13 +181,150 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-async-metrics_python38", "resource:integration-tests-python-XXXX-async-metrics_python38", + "memorysize:1024", "cold_start:false", + "runtime:python3.8", + "datadog_lambda:vXX", + "dd_lambda_layer:datadog-python38_X.X.X" + ] +} +{ + "m": "hello.dog", + "v": 1, + "e": XXXX, + "t": [ + "team:serverless", + "role:hello", + "dd_lambda_layer:datadog-python38_X.X.X" + ] +} +{ + "m": "tests.integration.count", + "v": 21, + "e": XXXX, + "t": [ + "test:integration", + "role:hello", + "dd_lambda_layer:datadog-python38_X.X.X" + ] +} +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +{ + "traces": [ + [ + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "integration-tests-python", + "resource": "integration-tests-python-XXXX-async-metrics_python38", + "name": "aws.lambda", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "runtime-id": "XXXX", + "_dd.origin": "lambda", + "cold_start": "false", + "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-async-metrics_python38", + "function_version": "$LATEST", + "request_id": "XXXX", + "resource_names": "integration-tests-python-XXXX-async-metrics_python38", + "functionname": "integration-tests-python-XXXX-async-metrics_python38", + "datadog_lambda": "X.X.X", + "dd_trace": "X.X.X", + "span.name": "aws.lambda", + "language": "python" + }, + "metrics": { + "process_id": XXXX, + "_dd.top_level": 1, + "_sampling_priority_v1": 1 + }, + "type": "serverless" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://datadoghq.com/", + "out.host": "datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1 + }, + "type": "http" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://www.datadoghq.com/", + "out.host": "www.datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1 + }, + "type": "http" + } + ] + ] +} +END Duration: XXXX ms Memory Used: XXXX MB +START +{ + "m": "aws.lambda.enhanced.invocations", + "v": 1, + "e": XXXX, + "t": [ + "region:eu-west-1", + "account_id:XXXX", + "functionname:integration-tests-python-XXXX-async-metrics_python38", + "resource:integration-tests-python-XXXX-async-metrics_python38", "memorysize:1024", + "cold_start:false", "runtime:python3.8", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python38_X.X.X" ] } +{ + "m": "datadog.serverless.dynamodb.stream.type", + "v": 1, + "e": XXXX, + "t": [ + "streamtype:NEW_AND_OLD_IMAGES", + "dd_lambda_layer:datadog-python38_X.X.X" + ] +} { "m": "hello.dog", "v": 1, @@ -207,8 +345,8 @@ START "dd_lambda_layer:datadog-python38_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -216,7 +354,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "dynamodb", + "service": "ExampleTableWithStream", "resource": "ExampleTableWithStream", "name": "aws.dynamodb", "error": 0, @@ -227,6 +365,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.dynamodb", "resource_names": "ExampleTableWithStream", + "span.kind": "server", "tablename": "ExampleTableWithStream", "event_source_arn": "arn:aws:dynamodb:us-east-1:XXXX:us-east-1/ExampleTableWithStream/stream/2015-06-27T00:48:05.899", "event_id": "XXXX", @@ -237,24 +376,55 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, - "type": "web" + "type": "web", + "span_links": [ + { + "trace_id": "XXXX", + "span_id": "XXXX", + "attributes": { + "ptr.kind": "aws.dynamodb.item", + "ptr.dir": "u", + "ptr.hash": "e2af34d333891f765c7f02d2da80895e", + "link.kind": "span-pointer" + } + }, + { + "trace_id": "XXXX", + "span_id": "XXXX", + "attributes": { + "ptr.kind": "aws.dynamodb.item", + "ptr.dir": "u", + "ptr.hash": "e2af34d333891f765c7f02d2da80895e", + "link.kind": "span-pointer" + } + }, + { + "trace_id": "XXXX", + "span_id": "XXXX", + "attributes": { + "ptr.kind": "aws.dynamodb.item", + "ptr.dir": "u", + "ptr.hash": "e2af34d333891f765c7f02d2da80895e", + "link.kind": "span-pointer" + } + } + ] }, { "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-async-metrics_python38", "name": "aws.lambda", "error": 0, @@ -272,8 +442,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "dynamodb", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -284,8 +453,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -310,8 +479,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -346,8 +515,8 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-async-metrics_python38", "resource:integration-tests-python-XXXX-async-metrics_python38", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.8", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python38_X.X.X" @@ -373,8 +542,8 @@ START "dd_lambda_layer:datadog-python38_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -382,7 +551,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "eventbridge", + "service": "eventbridge.custom.event.sender", "resource": "eventbridge.custom.event.sender", "name": "aws.eventbridge", "error": 0, @@ -393,15 +562,15 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.eventbridge", "resource_names": "eventbridge.custom.event.sender", + "span.kind": "server", "detail_type": "testdetail", "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -414,7 +583,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-async-metrics_python38", "name": "aws.lambda", "error": 0, @@ -431,8 +600,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "datadog_lambda": "X.X.X", "dd_trace": "X.X.X", "span.name": "aws.lambda", - "function_trigger.event_source": "eventbridge", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source": "eventbridge" }, "metrics": { "_dd.top_level": 1 @@ -443,8 +611,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -469,8 +637,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -505,8 +673,8 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-async-metrics_python38", "resource:integration-tests-python-XXXX-async-metrics_python38", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.8", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python38_X.X.X" @@ -532,8 +700,8 @@ START "dd_lambda_layer:datadog-python38_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -552,7 +720,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.httpapi", "endpoint": "/httpapi/get", - "http.url": "XXXX.execute-api.eu-west-1.amazonaws.com/httpapi/get", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com/httpapi/get", "http.method": "GET", "http.protocol": "HTTP/1.1", "http.source_ip": "XXXX", @@ -565,12 +733,12 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "sync", "_inferred_span.tag_source": "self", "http.status_code": "200", + "http.route": "/httpapi/get", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -583,7 +751,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-async-metrics_python38", "name": "aws.lambda", "error": 0, @@ -602,11 +770,11 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "span.name": "aws.lambda", "function_trigger.event_source": "api-gateway", "function_trigger.event_source_arn": "XXXX$default", - "http.url": "XXXX.execute-api.eu-west-1.amazonaws.com", - "http.url_details.path": "/httpapi/get", + "span.kind": "server", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com/httpapi/get", "http.method": "GET", - "http.status_code": "200", - "_dd.base_service": "integration-tests-python" + "http.route": "/httpapi/get", + "http.status_code": "200" }, "metrics": { "_dd.top_level": 1 @@ -617,8 +785,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -643,8 +811,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -679,8 +847,8 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-async-metrics_python38", "resource:integration-tests-python-XXXX-async-metrics_python38", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.8", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python38_X.X.X" @@ -706,8 +874,8 @@ START "dd_lambda_layer:datadog-python38_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -715,7 +883,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "kinesis", + "service": "EXAMPLE", "resource": "EXAMPLE", "name": "aws.kinesis", "error": 0, @@ -726,6 +894,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.kinesis", "resource_names": "EXAMPLE", + "span.kind": "server", "streamname": "EXAMPLE", "shardid": "shardId-XXXX", "event_source_arn": "arn:aws:kinesis:EXAMPLE", @@ -736,11 +905,10 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -753,7 +921,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-async-metrics_python38", "name": "aws.lambda", "error": 0, @@ -771,8 +939,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "kinesis", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -783,8 +950,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -809,8 +976,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -845,8 +1012,8 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-async-metrics_python38", "resource:integration-tests-python-XXXX-async-metrics_python38", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.8", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python38_X.X.X" @@ -872,8 +1039,8 @@ START "dd_lambda_layer:datadog-python38_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -881,7 +1048,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "s3", + "service": "example-bucket", "resource": "example-bucket", "name": "aws.s3", "error": 0, @@ -890,6 +1057,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.s3", "resource_names": "example-bucket", + "span.kind": "server", "event_name": "ObjectCreated:Put", "bucketname": "example-bucket", "bucket_arn": "arn:aws:s3:::example-bucket", @@ -899,24 +1067,35 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, - "type": "web" + "type": "web", + "span_links": [ + { + "trace_id": "XXXX", + "span_id": "XXXX", + "attributes": { + "ptr.kind": "aws.s3.object", + "ptr.dir": "u", + "ptr.hash": "1dc3e5d00dae48c1f07d95371a747788", + "link.kind": "span-pointer" + } + } + ] }, { "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-async-metrics_python38", "name": "aws.lambda", "error": 0, @@ -934,8 +1113,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "s3", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -946,8 +1124,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -972,8 +1150,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1008,8 +1186,8 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-async-metrics_python38", "resource:integration-tests-python-XXXX-async-metrics_python38", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.8", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python38_X.X.X" @@ -1035,8 +1213,8 @@ START "dd_lambda_layer:datadog-python38_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1044,7 +1222,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "sns", + "service": "sns-lambda", "resource": "sns-lambda", "name": "aws.sns", "error": 0, @@ -1055,6 +1233,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.sns", "resource_names": "sns-lambda", + "span.kind": "server", "topicname": "sns-lambda", "topic_arn": "arn:aws:sns:us-east-2:XXXX:us-east-2-lambda", "message_id": "XXXX", @@ -1063,11 +1242,10 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -1080,7 +1258,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-async-metrics_python38", "name": "aws.lambda", "error": 0, @@ -1098,8 +1276,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "sns", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -1110,8 +1287,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1136,8 +1313,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1172,8 +1349,8 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-async-metrics_python38", "resource:integration-tests-python-XXXX-async-metrics_python38", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.8", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python38_X.X.X" @@ -1199,8 +1376,8 @@ START "dd_lambda_layer:datadog-python38_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1208,7 +1385,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "sqs", + "service": "my-queue", "resource": "my-queue", "name": "aws.sqs", "error": 0, @@ -1219,6 +1396,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.sqs", "resource_names": "my-queue", + "span.kind": "server", "queuename": "my-queue", "event_source_arn": "arn:aws:sqs:us-east-2:XXXX:us-east-2-queue", "receipt_handle": "AQEBwJnKyrHigUMZj6rYigCgxlaS3SLy0a...", @@ -1226,11 +1404,10 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -1243,7 +1420,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-async-metrics_python38", "name": "aws.lambda", "error": 0, @@ -1261,8 +1438,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "sqs", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -1273,8 +1449,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1299,8 +1475,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1335,8 +1511,8 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-async-metrics_python38", "resource:integration-tests-python-XXXX-async-metrics_python38", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.8", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python38_X.X.X" @@ -1362,9 +1538,8 @@ START "dd_lambda_layer:datadog-python38_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -END Duration: XXXX ms Memory Used: XXXX MB +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1382,9 +1557,10 @@ END Duration: XXXX ms Memory Used: XXXX MB "runtime-id": "XXXX", "_dd.origin": "lambda", "operation_name": "aws.apigateway.websocket", - "http.url": "XXXX.execute-api.eu-west-1.amazonaws.com$default", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com$default/", "endpoint": "$default", "resource_names": "$default", + "span.kind": "server", "apiid": "XXXX", "apiname": "XXXX", "stage": "dev", @@ -1396,11 +1572,10 @@ END Duration: XXXX ms Memory Used: XXXX MB "_inferred_span.tag_source": "self", "http.status_code": "200", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -1413,7 +1588,7 @@ END Duration: XXXX ms Memory Used: XXXX MB "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-async-metrics_python38", "name": "aws.lambda", "error": 0, @@ -1432,9 +1607,9 @@ END Duration: XXXX ms Memory Used: XXXX MB "span.name": "aws.lambda", "function_trigger.event_source": "api-gateway", "function_trigger.event_source_arn": "XXXX", - "http.url": "XXXX.execute-api.eu-west-1.amazonaws.com", - "http.status_code": "200", - "_dd.base_service": "integration-tests-python" + "span.kind": "server", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com/", + "http.status_code": "200" }, "metrics": { "_dd.top_level": 1 @@ -1445,8 +1620,8 @@ END Duration: XXXX ms Memory Used: XXXX MB "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1471,8 +1646,8 @@ END Duration: XXXX ms Memory Used: XXXX MB "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1496,3 +1671,4 @@ END Duration: XXXX ms Memory Used: XXXX MB ] ] } +END Duration: XXXX ms Memory Used: XXXX MB diff --git a/tests/integration/snapshots/logs/async-metrics_python39.log b/tests/integration/snapshots/logs/async-metrics_python39.log index 53ef3d2f5..f16e9e2d5 100644 --- a/tests/integration/snapshots/logs/async-metrics_python39.log +++ b/tests/integration/snapshots/logs/async-metrics_python39.log @@ -9,8 +9,8 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-async-metrics_python39", "resource:integration-tests-python-XXXX-async-metrics_python39", - "cold_start:true", "memorysize:1024", + "cold_start:true", "runtime:python3.9", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python39_X.X.X" @@ -36,8 +36,8 @@ START "dd_lambda_layer:datadog-python39_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -55,10 +55,11 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "runtime-id": "XXXX", "_dd.origin": "lambda", "operation_name": "aws.apigateway.rest", - "http.url": "XXXX.execute-api.us-east-2.amazonaws.com/", + "http.url": "https://xxxx.execute-api.us-east-2.amazonaws.com/", "endpoint": "/", "http.method": "GET", "resource_names": "GET /", + "span.kind": "server", "apiid": "XXXX", "apiname": "XXXX", "stage": "Prod", @@ -66,12 +67,12 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "sync", "_inferred_span.tag_source": "self", "http.status_code": "200", + "http.route": "/", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -84,7 +85,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-async-metrics_python39", "name": "aws.lambda", "error": 0, @@ -103,11 +104,11 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "span.name": "aws.lambda", "function_trigger.event_source": "api-gateway", "function_trigger.event_source_arn": "XXXX", - "http.url": "XXXX.execute-api.us-east-2.amazonaws.com", - "http.url_details.path": "/Prod/", + "span.kind": "server", + "http.url": "https://xxxx.execute-api.us-east-2.amazonaws.com/Prod/", "http.method": "GET", - "http.status_code": "200", - "_dd.base_service": "integration-tests-python" + "http.route": "/", + "http.status_code": "200" }, "metrics": { "_dd.top_level": 1 @@ -118,8 +119,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -144,8 +145,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -180,13 +181,150 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-async-metrics_python39", "resource:integration-tests-python-XXXX-async-metrics_python39", + "memorysize:1024", "cold_start:false", + "runtime:python3.9", + "datadog_lambda:vXX", + "dd_lambda_layer:datadog-python39_X.X.X" + ] +} +{ + "m": "hello.dog", + "v": 1, + "e": XXXX, + "t": [ + "team:serverless", + "role:hello", + "dd_lambda_layer:datadog-python39_X.X.X" + ] +} +{ + "m": "tests.integration.count", + "v": 21, + "e": XXXX, + "t": [ + "test:integration", + "role:hello", + "dd_lambda_layer:datadog-python39_X.X.X" + ] +} +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +{ + "traces": [ + [ + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "integration-tests-python", + "resource": "integration-tests-python-XXXX-async-metrics_python39", + "name": "aws.lambda", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "runtime-id": "XXXX", + "_dd.origin": "lambda", + "cold_start": "false", + "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-async-metrics_python39", + "function_version": "$LATEST", + "request_id": "XXXX", + "resource_names": "integration-tests-python-XXXX-async-metrics_python39", + "functionname": "integration-tests-python-XXXX-async-metrics_python39", + "datadog_lambda": "X.X.X", + "dd_trace": "X.X.X", + "span.name": "aws.lambda", + "language": "python" + }, + "metrics": { + "process_id": XXXX, + "_dd.top_level": 1, + "_sampling_priority_v1": 1 + }, + "type": "serverless" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://datadoghq.com/", + "out.host": "datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1 + }, + "type": "http" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://www.datadoghq.com/", + "out.host": "www.datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1 + }, + "type": "http" + } + ] + ] +} +END Duration: XXXX ms Memory Used: XXXX MB +START +{ + "m": "aws.lambda.enhanced.invocations", + "v": 1, + "e": XXXX, + "t": [ + "region:eu-west-1", + "account_id:XXXX", + "functionname:integration-tests-python-XXXX-async-metrics_python39", + "resource:integration-tests-python-XXXX-async-metrics_python39", "memorysize:1024", + "cold_start:false", "runtime:python3.9", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python39_X.X.X" ] } +{ + "m": "datadog.serverless.dynamodb.stream.type", + "v": 1, + "e": XXXX, + "t": [ + "streamtype:NEW_AND_OLD_IMAGES", + "dd_lambda_layer:datadog-python39_X.X.X" + ] +} { "m": "hello.dog", "v": 1, @@ -207,8 +345,8 @@ START "dd_lambda_layer:datadog-python39_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -216,7 +354,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "dynamodb", + "service": "ExampleTableWithStream", "resource": "ExampleTableWithStream", "name": "aws.dynamodb", "error": 0, @@ -227,6 +365,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.dynamodb", "resource_names": "ExampleTableWithStream", + "span.kind": "server", "tablename": "ExampleTableWithStream", "event_source_arn": "arn:aws:dynamodb:us-east-1:XXXX:us-east-1/ExampleTableWithStream/stream/2015-06-27T00:48:05.899", "event_id": "XXXX", @@ -237,24 +376,55 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, - "type": "web" + "type": "web", + "span_links": [ + { + "trace_id": "XXXX", + "span_id": "XXXX", + "attributes": { + "ptr.kind": "aws.dynamodb.item", + "ptr.dir": "u", + "ptr.hash": "e2af34d333891f765c7f02d2da80895e", + "link.kind": "span-pointer" + } + }, + { + "trace_id": "XXXX", + "span_id": "XXXX", + "attributes": { + "ptr.kind": "aws.dynamodb.item", + "ptr.dir": "u", + "ptr.hash": "e2af34d333891f765c7f02d2da80895e", + "link.kind": "span-pointer" + } + }, + { + "trace_id": "XXXX", + "span_id": "XXXX", + "attributes": { + "ptr.kind": "aws.dynamodb.item", + "ptr.dir": "u", + "ptr.hash": "e2af34d333891f765c7f02d2da80895e", + "link.kind": "span-pointer" + } + } + ] }, { "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-async-metrics_python39", "name": "aws.lambda", "error": 0, @@ -272,8 +442,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "dynamodb", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -284,8 +453,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -310,8 +479,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -346,8 +515,8 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-async-metrics_python39", "resource:integration-tests-python-XXXX-async-metrics_python39", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.9", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python39_X.X.X" @@ -373,8 +542,8 @@ START "dd_lambda_layer:datadog-python39_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -382,7 +551,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "eventbridge", + "service": "eventbridge.custom.event.sender", "resource": "eventbridge.custom.event.sender", "name": "aws.eventbridge", "error": 0, @@ -393,15 +562,15 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.eventbridge", "resource_names": "eventbridge.custom.event.sender", + "span.kind": "server", "detail_type": "testdetail", "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -414,7 +583,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-async-metrics_python39", "name": "aws.lambda", "error": 0, @@ -431,8 +600,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "datadog_lambda": "X.X.X", "dd_trace": "X.X.X", "span.name": "aws.lambda", - "function_trigger.event_source": "eventbridge", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source": "eventbridge" }, "metrics": { "_dd.top_level": 1 @@ -443,8 +611,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -469,8 +637,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -505,8 +673,8 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-async-metrics_python39", "resource:integration-tests-python-XXXX-async-metrics_python39", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.9", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python39_X.X.X" @@ -532,8 +700,8 @@ START "dd_lambda_layer:datadog-python39_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -552,7 +720,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.httpapi", "endpoint": "/httpapi/get", - "http.url": "XXXX.execute-api.eu-west-1.amazonaws.com/httpapi/get", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com/httpapi/get", "http.method": "GET", "http.protocol": "HTTP/1.1", "http.source_ip": "XXXX", @@ -565,12 +733,12 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "sync", "_inferred_span.tag_source": "self", "http.status_code": "200", + "http.route": "/httpapi/get", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -583,7 +751,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-async-metrics_python39", "name": "aws.lambda", "error": 0, @@ -602,11 +770,11 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "span.name": "aws.lambda", "function_trigger.event_source": "api-gateway", "function_trigger.event_source_arn": "XXXX$default", - "http.url": "XXXX.execute-api.eu-west-1.amazonaws.com", - "http.url_details.path": "/httpapi/get", + "span.kind": "server", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com/httpapi/get", "http.method": "GET", - "http.status_code": "200", - "_dd.base_service": "integration-tests-python" + "http.route": "/httpapi/get", + "http.status_code": "200" }, "metrics": { "_dd.top_level": 1 @@ -617,8 +785,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -643,8 +811,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -679,8 +847,8 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-async-metrics_python39", "resource:integration-tests-python-XXXX-async-metrics_python39", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.9", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python39_X.X.X" @@ -706,8 +874,8 @@ START "dd_lambda_layer:datadog-python39_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -715,7 +883,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "kinesis", + "service": "EXAMPLE", "resource": "EXAMPLE", "name": "aws.kinesis", "error": 0, @@ -726,6 +894,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.kinesis", "resource_names": "EXAMPLE", + "span.kind": "server", "streamname": "EXAMPLE", "shardid": "shardId-XXXX", "event_source_arn": "arn:aws:kinesis:EXAMPLE", @@ -736,11 +905,10 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -753,7 +921,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-async-metrics_python39", "name": "aws.lambda", "error": 0, @@ -771,8 +939,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "kinesis", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -783,8 +950,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -809,8 +976,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -845,8 +1012,8 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-async-metrics_python39", "resource:integration-tests-python-XXXX-async-metrics_python39", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.9", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python39_X.X.X" @@ -872,8 +1039,8 @@ START "dd_lambda_layer:datadog-python39_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -881,7 +1048,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "s3", + "service": "example-bucket", "resource": "example-bucket", "name": "aws.s3", "error": 0, @@ -890,6 +1057,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.s3", "resource_names": "example-bucket", + "span.kind": "server", "event_name": "ObjectCreated:Put", "bucketname": "example-bucket", "bucket_arn": "arn:aws:s3:::example-bucket", @@ -899,24 +1067,35 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, - "type": "web" + "type": "web", + "span_links": [ + { + "trace_id": "XXXX", + "span_id": "XXXX", + "attributes": { + "ptr.kind": "aws.s3.object", + "ptr.dir": "u", + "ptr.hash": "1dc3e5d00dae48c1f07d95371a747788", + "link.kind": "span-pointer" + } + } + ] }, { "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-async-metrics_python39", "name": "aws.lambda", "error": 0, @@ -934,8 +1113,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "s3", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -946,8 +1124,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -972,8 +1150,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1008,8 +1186,8 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-async-metrics_python39", "resource:integration-tests-python-XXXX-async-metrics_python39", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.9", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python39_X.X.X" @@ -1035,8 +1213,8 @@ START "dd_lambda_layer:datadog-python39_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1044,7 +1222,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "sns", + "service": "sns-lambda", "resource": "sns-lambda", "name": "aws.sns", "error": 0, @@ -1055,6 +1233,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.sns", "resource_names": "sns-lambda", + "span.kind": "server", "topicname": "sns-lambda", "topic_arn": "arn:aws:sns:us-east-2:XXXX:us-east-2-lambda", "message_id": "XXXX", @@ -1063,11 +1242,10 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -1080,7 +1258,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-async-metrics_python39", "name": "aws.lambda", "error": 0, @@ -1098,8 +1276,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "sns", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -1110,8 +1287,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1136,8 +1313,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1172,8 +1349,8 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-async-metrics_python39", "resource:integration-tests-python-XXXX-async-metrics_python39", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.9", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python39_X.X.X" @@ -1199,8 +1376,8 @@ START "dd_lambda_layer:datadog-python39_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1208,7 +1385,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "sqs", + "service": "my-queue", "resource": "my-queue", "name": "aws.sqs", "error": 0, @@ -1219,6 +1396,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.sqs", "resource_names": "my-queue", + "span.kind": "server", "queuename": "my-queue", "event_source_arn": "arn:aws:sqs:us-east-2:XXXX:us-east-2-queue", "receipt_handle": "AQEBwJnKyrHigUMZj6rYigCgxlaS3SLy0a...", @@ -1226,11 +1404,10 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -1243,7 +1420,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-async-metrics_python39", "name": "aws.lambda", "error": 0, @@ -1261,8 +1438,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "sqs", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -1273,8 +1449,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1299,8 +1475,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1335,8 +1511,8 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-async-metrics_python39", "resource:integration-tests-python-XXXX-async-metrics_python39", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.9", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python39_X.X.X" @@ -1362,8 +1538,8 @@ START "dd_lambda_layer:datadog-python39_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1381,9 +1557,10 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "runtime-id": "XXXX", "_dd.origin": "lambda", "operation_name": "aws.apigateway.websocket", - "http.url": "XXXX.execute-api.eu-west-1.amazonaws.com$default", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com$default/", "endpoint": "$default", "resource_names": "$default", + "span.kind": "server", "apiid": "XXXX", "apiname": "XXXX", "stage": "dev", @@ -1395,11 +1572,10 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.tag_source": "self", "http.status_code": "200", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -1412,7 +1588,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-async-metrics_python39", "name": "aws.lambda", "error": 0, @@ -1431,9 +1607,9 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "span.name": "aws.lambda", "function_trigger.event_source": "api-gateway", "function_trigger.event_source_arn": "XXXX", - "http.url": "XXXX.execute-api.eu-west-1.amazonaws.com", - "http.status_code": "200", - "_dd.base_service": "integration-tests-python" + "span.kind": "server", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com/", + "http.status_code": "200" }, "metrics": { "_dd.top_level": 1 @@ -1444,8 +1620,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1470,8 +1646,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", diff --git a/tests/integration/snapshots/logs/sync-metrics_python310.log b/tests/integration/snapshots/logs/sync-metrics_python310.log index 07d37c408..1cbd91dd8 100644 --- a/tests/integration/snapshots/logs/sync-metrics_python310.log +++ b/tests/integration/snapshots/logs/sync-metrics_python310.log @@ -9,15 +9,15 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-sync-metrics_python310", "resource:integration-tests-python-XXXX-sync-metrics_python310", - "cold_start:true", "memorysize:1024", + "cold_start:true", "runtime:python3.10", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python310_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -35,10 +35,11 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "runtime-id": "XXXX", "_dd.origin": "lambda", "operation_name": "aws.apigateway.rest", - "http.url": "XXXX.execute-api.us-east-2.amazonaws.com/", + "http.url": "https://xxxx.execute-api.us-east-2.amazonaws.com/", "endpoint": "/", "http.method": "GET", "resource_names": "GET /", + "span.kind": "server", "apiid": "XXXX", "apiname": "XXXX", "stage": "Prod", @@ -46,12 +47,12 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "sync", "_inferred_span.tag_source": "self", "http.status_code": "200", + "http.route": "/", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -64,7 +65,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-sync-metrics_python310", "name": "aws.lambda", "error": 0, @@ -83,11 +84,11 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "span.name": "aws.lambda", "function_trigger.event_source": "api-gateway", "function_trigger.event_source_arn": "XXXX", - "http.url": "XXXX.execute-api.us-east-2.amazonaws.com", - "http.url_details.path": "/Prod/", + "span.kind": "server", + "http.url": "https://xxxx.execute-api.us-east-2.amazonaws.com/Prod/", "http.method": "GET", - "http.status_code": "200", - "_dd.base_service": "integration-tests-python" + "http.route": "/", + "http.status_code": "200" }, "metrics": { "_dd.top_level": 1 @@ -98,8 +99,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -124,8 +125,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -149,7 +150,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " ] ] } -HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "Content-Encoding:deflate", "Content-Length:XXXX", "Content-Type:application/json", "DD-API-KEY:XXXX", "User-Agent:datadogpy/XX (python XX; os linux; arch x86_64)", "traceparent:XXX", "tracestate:XXX +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -157,8 +158,8 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -172,7 +173,7 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "http.url": "https://api.datadoghq.com/api/v1/distribution_points", "out.host": "api.datadoghq.com", "http.status_code": "202", - "http.useragent": "datadogpy/XX (python XX; os linux; arch x86_64)", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", "language": "python" @@ -199,15 +200,171 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-sync-metrics_python310", "resource:integration-tests-python-XXXX-sync-metrics_python310", + "memorysize:1024", "cold_start:false", + "runtime:python3.10", + "datadog_lambda:vXX", + "dd_lambda_layer:datadog-python310_X.X.X" + ] +} +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +{ + "traces": [ + [ + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "integration-tests-python", + "resource": "integration-tests-python-XXXX-sync-metrics_python310", + "name": "aws.lambda", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "runtime-id": "XXXX", + "_dd.origin": "lambda", + "cold_start": "false", + "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-sync-metrics_python310", + "function_version": "$LATEST", + "request_id": "XXXX", + "resource_names": "integration-tests-python-XXXX-sync-metrics_python310", + "functionname": "integration-tests-python-XXXX-sync-metrics_python310", + "datadog_lambda": "X.X.X", + "dd_trace": "X.X.X", + "span.name": "aws.lambda", + "language": "python" + }, + "metrics": { + "process_id": XXXX, + "_dd.top_level": 1, + "_sampling_priority_v1": 1 + }, + "type": "serverless" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://datadoghq.com/", + "out.host": "datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1 + }, + "type": "http" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://www.datadoghq.com/", + "out.host": "www.datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1 + }, + "type": "http" + } + ] + ] +} +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX +{ + "traces": [ + [ + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "POST /api/v1/distribution_points", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "runtime-id": "XXXX", + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "POST", + "http.url": "https://api.datadoghq.com/api/v1/distribution_points", + "out.host": "api.datadoghq.com", + "http.status_code": "202", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", + "_dd.p.dm": "-0", + "_dd.p.tid": "XXXX", + "language": "python" + }, + "metrics": { + "process_id": XXXX, + "_dd.measured": 1, + "_dd.top_level": 1, + "_sampling_priority_v1": 1 + }, + "type": "http" + } + ] + ] +} +END Duration: XXXX ms Memory Used: XXXX MB +START +{ + "m": "aws.lambda.enhanced.invocations", + "v": 1, + "e": XXXX, + "t": [ + "region:eu-west-1", + "account_id:XXXX", + "functionname:integration-tests-python-XXXX-sync-metrics_python310", + "resource:integration-tests-python-XXXX-sync-metrics_python310", "memorysize:1024", + "cold_start:false", "runtime:python3.10", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python310_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +{ + "m": "datadog.serverless.dynamodb.stream.type", + "v": 1, + "e": XXXX, + "t": [ + "streamtype:NEW_AND_OLD_IMAGES", + "dd_lambda_layer:datadog-python310_X.X.X" + ] +} +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -215,7 +372,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "dynamodb", + "service": "ExampleTableWithStream", "resource": "ExampleTableWithStream", "name": "aws.dynamodb", "error": 0, @@ -226,6 +383,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.dynamodb", "resource_names": "ExampleTableWithStream", + "span.kind": "server", "tablename": "ExampleTableWithStream", "event_source_arn": "arn:aws:dynamodb:us-east-1:XXXX:us-east-1/ExampleTableWithStream/stream/2015-06-27T00:48:05.899", "event_id": "XXXX", @@ -236,24 +394,55 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, - "type": "web" + "type": "web", + "span_links": [ + { + "trace_id": "XXXX", + "span_id": "XXXX", + "attributes": { + "ptr.kind": "aws.dynamodb.item", + "ptr.dir": "u", + "ptr.hash": "e2af34d333891f765c7f02d2da80895e", + "link.kind": "span-pointer" + } + }, + { + "trace_id": "XXXX", + "span_id": "XXXX", + "attributes": { + "ptr.kind": "aws.dynamodb.item", + "ptr.dir": "u", + "ptr.hash": "e2af34d333891f765c7f02d2da80895e", + "link.kind": "span-pointer" + } + }, + { + "trace_id": "XXXX", + "span_id": "XXXX", + "attributes": { + "ptr.kind": "aws.dynamodb.item", + "ptr.dir": "u", + "ptr.hash": "e2af34d333891f765c7f02d2da80895e", + "link.kind": "span-pointer" + } + } + ] }, { "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-sync-metrics_python310", "name": "aws.lambda", "error": 0, @@ -271,8 +460,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "dynamodb", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -283,8 +471,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -309,8 +497,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -334,7 +522,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " ] ] } -HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "Content-Encoding:deflate", "Content-Length:XXXX", "Content-Type:application/json", "DD-API-KEY:XXXX", "User-Agent:datadogpy/XX (python XX; os linux; arch x86_64)", "traceparent:XXX", "tracestate:XXX +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -342,8 +530,8 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -357,7 +545,7 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "http.url": "https://api.datadoghq.com/api/v1/distribution_points", "out.host": "api.datadoghq.com", "http.status_code": "202", - "http.useragent": "datadogpy/XX (python XX; os linux; arch x86_64)", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", "language": "python" @@ -384,15 +572,15 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-sync-metrics_python310", "resource:integration-tests-python-XXXX-sync-metrics_python310", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.10", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python310_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -400,7 +588,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "eventbridge", + "service": "eventbridge.custom.event.sender", "resource": "eventbridge.custom.event.sender", "name": "aws.eventbridge", "error": 0, @@ -411,15 +599,15 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.eventbridge", "resource_names": "eventbridge.custom.event.sender", + "span.kind": "server", "detail_type": "testdetail", "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -432,7 +620,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-sync-metrics_python310", "name": "aws.lambda", "error": 0, @@ -449,8 +637,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "datadog_lambda": "X.X.X", "dd_trace": "X.X.X", "span.name": "aws.lambda", - "function_trigger.event_source": "eventbridge", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source": "eventbridge" }, "metrics": { "_dd.top_level": 1 @@ -461,8 +648,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -487,8 +674,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -512,7 +699,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " ] ] } -HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "Content-Encoding:deflate", "Content-Length:XXXX", "Content-Type:application/json", "DD-API-KEY:XXXX", "User-Agent:datadogpy/XX (python XX; os linux; arch x86_64)", "traceparent:XXX", "tracestate:XXX +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -520,8 +707,8 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -535,7 +722,7 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "http.url": "https://api.datadoghq.com/api/v1/distribution_points", "out.host": "api.datadoghq.com", "http.status_code": "202", - "http.useragent": "datadogpy/XX (python XX; os linux; arch x86_64)", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", "language": "python" @@ -562,15 +749,15 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-sync-metrics_python310", "resource:integration-tests-python-XXXX-sync-metrics_python310", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.10", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python310_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -589,7 +776,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.httpapi", "endpoint": "/httpapi/get", - "http.url": "XXXX.execute-api.eu-west-1.amazonaws.com/httpapi/get", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com/httpapi/get", "http.method": "GET", "http.protocol": "HTTP/1.1", "http.source_ip": "XXXX", @@ -602,12 +789,12 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "sync", "_inferred_span.tag_source": "self", "http.status_code": "200", + "http.route": "/httpapi/get", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -620,7 +807,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-sync-metrics_python310", "name": "aws.lambda", "error": 0, @@ -639,11 +826,11 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "span.name": "aws.lambda", "function_trigger.event_source": "api-gateway", "function_trigger.event_source_arn": "XXXX$default", - "http.url": "XXXX.execute-api.eu-west-1.amazonaws.com", - "http.url_details.path": "/httpapi/get", + "span.kind": "server", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com/httpapi/get", "http.method": "GET", - "http.status_code": "200", - "_dd.base_service": "integration-tests-python" + "http.route": "/httpapi/get", + "http.status_code": "200" }, "metrics": { "_dd.top_level": 1 @@ -654,8 +841,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -680,8 +867,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -705,7 +892,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " ] ] } -HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "Content-Encoding:deflate", "Content-Length:XXXX", "Content-Type:application/json", "DD-API-KEY:XXXX", "User-Agent:datadogpy/XX (python XX; os linux; arch x86_64)", "traceparent:XXX", "tracestate:XXX +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -713,8 +900,8 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -728,7 +915,7 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "http.url": "https://api.datadoghq.com/api/v1/distribution_points", "out.host": "api.datadoghq.com", "http.status_code": "202", - "http.useragent": "datadogpy/XX (python XX; os linux; arch x86_64)", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", "language": "python" @@ -755,15 +942,15 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-sync-metrics_python310", "resource:integration-tests-python-XXXX-sync-metrics_python310", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.10", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python310_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -771,7 +958,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "kinesis", + "service": "EXAMPLE", "resource": "EXAMPLE", "name": "aws.kinesis", "error": 0, @@ -782,6 +969,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.kinesis", "resource_names": "EXAMPLE", + "span.kind": "server", "streamname": "EXAMPLE", "shardid": "shardId-XXXX", "event_source_arn": "arn:aws:kinesis:EXAMPLE", @@ -792,11 +980,10 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -809,7 +996,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-sync-metrics_python310", "name": "aws.lambda", "error": 0, @@ -827,8 +1014,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "kinesis", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -839,8 +1025,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -865,8 +1051,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -890,7 +1076,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " ] ] } -HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "Content-Encoding:deflate", "Content-Length:XXXX", "Content-Type:application/json", "DD-API-KEY:XXXX", "User-Agent:datadogpy/XX (python XX; os linux; arch x86_64)", "traceparent:XXX", "tracestate:XXX +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -898,8 +1084,8 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -913,7 +1099,7 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "http.url": "https://api.datadoghq.com/api/v1/distribution_points", "out.host": "api.datadoghq.com", "http.status_code": "202", - "http.useragent": "datadogpy/XX (python XX; os linux; arch x86_64)", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", "language": "python" @@ -940,15 +1126,15 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-sync-metrics_python310", "resource:integration-tests-python-XXXX-sync-metrics_python310", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.10", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python310_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -956,7 +1142,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "s3", + "service": "example-bucket", "resource": "example-bucket", "name": "aws.s3", "error": 0, @@ -965,6 +1151,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.s3", "resource_names": "example-bucket", + "span.kind": "server", "event_name": "ObjectCreated:Put", "bucketname": "example-bucket", "bucket_arn": "arn:aws:s3:::example-bucket", @@ -974,24 +1161,35 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, - "type": "web" + "type": "web", + "span_links": [ + { + "trace_id": "XXXX", + "span_id": "XXXX", + "attributes": { + "ptr.kind": "aws.s3.object", + "ptr.dir": "u", + "ptr.hash": "1dc3e5d00dae48c1f07d95371a747788", + "link.kind": "span-pointer" + } + } + ] }, { "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-sync-metrics_python310", "name": "aws.lambda", "error": 0, @@ -1009,8 +1207,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "s3", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -1021,8 +1218,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1047,8 +1244,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1072,7 +1269,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " ] ] } -HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "Content-Encoding:deflate", "Content-Length:XXXX", "Content-Type:application/json", "DD-API-KEY:XXXX", "User-Agent:datadogpy/XX (python XX; os linux; arch x86_64)", "traceparent:XXX", "tracestate:XXX +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1080,8 +1277,8 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1095,7 +1292,7 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "http.url": "https://api.datadoghq.com/api/v1/distribution_points", "out.host": "api.datadoghq.com", "http.status_code": "202", - "http.useragent": "datadogpy/XX (python XX; os linux; arch x86_64)", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", "language": "python" @@ -1122,15 +1319,15 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-sync-metrics_python310", "resource:integration-tests-python-XXXX-sync-metrics_python310", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.10", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python310_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1138,7 +1335,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "sns", + "service": "sns-lambda", "resource": "sns-lambda", "name": "aws.sns", "error": 0, @@ -1149,6 +1346,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.sns", "resource_names": "sns-lambda", + "span.kind": "server", "topicname": "sns-lambda", "topic_arn": "arn:aws:sns:us-east-2:XXXX:us-east-2-lambda", "message_id": "XXXX", @@ -1157,11 +1355,10 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -1174,7 +1371,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-sync-metrics_python310", "name": "aws.lambda", "error": 0, @@ -1192,8 +1389,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "sns", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -1204,8 +1400,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1230,8 +1426,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1255,7 +1451,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " ] ] } -HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "Content-Encoding:deflate", "Content-Length:XXXX", "Content-Type:application/json", "DD-API-KEY:XXXX", "User-Agent:datadogpy/XX (python XX; os linux; arch x86_64)", "traceparent:XXX", "tracestate:XXX +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1263,8 +1459,8 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1278,7 +1474,7 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "http.url": "https://api.datadoghq.com/api/v1/distribution_points", "out.host": "api.datadoghq.com", "http.status_code": "202", - "http.useragent": "datadogpy/XX (python XX; os linux; arch x86_64)", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", "language": "python" @@ -1305,15 +1501,15 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-sync-metrics_python310", "resource:integration-tests-python-XXXX-sync-metrics_python310", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.10", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python310_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1321,7 +1517,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "sqs", + "service": "my-queue", "resource": "my-queue", "name": "aws.sqs", "error": 0, @@ -1332,6 +1528,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.sqs", "resource_names": "my-queue", + "span.kind": "server", "queuename": "my-queue", "event_source_arn": "arn:aws:sqs:us-east-2:XXXX:us-east-2-queue", "receipt_handle": "AQEBwJnKyrHigUMZj6rYigCgxlaS3SLy0a...", @@ -1339,11 +1536,10 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -1356,7 +1552,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-sync-metrics_python310", "name": "aws.lambda", "error": 0, @@ -1374,8 +1570,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "sqs", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -1386,8 +1581,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1412,8 +1607,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1437,7 +1632,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " ] ] } -HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "Content-Encoding:deflate", "Content-Length:XXXX", "Content-Type:application/json", "DD-API-KEY:XXXX", "User-Agent:datadogpy/XX (python XX; os linux; arch x86_64)", "traceparent:XXX", "tracestate:XXX +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1445,8 +1640,8 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1460,7 +1655,7 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "http.url": "https://api.datadoghq.com/api/v1/distribution_points", "out.host": "api.datadoghq.com", "http.status_code": "202", - "http.useragent": "datadogpy/XX (python XX; os linux; arch x86_64)", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", "language": "python" @@ -1487,15 +1682,15 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-sync-metrics_python310", "resource:integration-tests-python-XXXX-sync-metrics_python310", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.10", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python310_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1513,9 +1708,10 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "runtime-id": "XXXX", "_dd.origin": "lambda", "operation_name": "aws.apigateway.websocket", - "http.url": "XXXX.execute-api.eu-west-1.amazonaws.com$default", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com$default/", "endpoint": "$default", "resource_names": "$default", + "span.kind": "server", "apiid": "XXXX", "apiname": "XXXX", "stage": "dev", @@ -1527,11 +1723,10 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.tag_source": "self", "http.status_code": "200", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -1544,7 +1739,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-sync-metrics_python310", "name": "aws.lambda", "error": 0, @@ -1563,9 +1758,9 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "span.name": "aws.lambda", "function_trigger.event_source": "api-gateway", "function_trigger.event_source_arn": "XXXX", - "http.url": "XXXX.execute-api.eu-west-1.amazonaws.com", - "http.status_code": "200", - "_dd.base_service": "integration-tests-python" + "span.kind": "server", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com/", + "http.status_code": "200" }, "metrics": { "_dd.top_level": 1 @@ -1576,8 +1771,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1602,8 +1797,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1627,7 +1822,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " ] ] } -HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "Content-Encoding:deflate", "Content-Length:XXXX", "Content-Type:application/json", "DD-API-KEY:XXXX", "User-Agent:datadogpy/XX (python XX; os linux; arch x86_64)", "traceparent:XXX", "tracestate:XXX +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1635,8 +1830,8 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1650,7 +1845,7 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "http.url": "https://api.datadoghq.com/api/v1/distribution_points", "out.host": "api.datadoghq.com", "http.status_code": "202", - "http.useragent": "datadogpy/XX (python XX; os linux; arch x86_64)", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", "language": "python" diff --git a/tests/integration/snapshots/logs/sync-metrics_python311.log b/tests/integration/snapshots/logs/sync-metrics_python311.log index c2a3e5cdd..b043a8f47 100644 --- a/tests/integration/snapshots/logs/sync-metrics_python311.log +++ b/tests/integration/snapshots/logs/sync-metrics_python311.log @@ -9,15 +9,15 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-sync-metrics_python311", "resource:integration-tests-python-XXXX-sync-metrics_python311", - "cold_start:true", "memorysize:1024", + "cold_start:true", "runtime:python3.11", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python311_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -35,10 +35,11 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "runtime-id": "XXXX", "_dd.origin": "lambda", "operation_name": "aws.apigateway.rest", - "http.url": "XXXX.execute-api.us-east-2.amazonaws.com/", + "http.url": "https://xxxx.execute-api.us-east-2.amazonaws.com/", "endpoint": "/", "http.method": "GET", "resource_names": "GET /", + "span.kind": "server", "apiid": "XXXX", "apiname": "XXXX", "stage": "Prod", @@ -46,12 +47,12 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "sync", "_inferred_span.tag_source": "self", "http.status_code": "200", + "http.route": "/", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -64,7 +65,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-sync-metrics_python311", "name": "aws.lambda", "error": 0, @@ -83,11 +84,11 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "span.name": "aws.lambda", "function_trigger.event_source": "api-gateway", "function_trigger.event_source_arn": "XXXX", - "http.url": "XXXX.execute-api.us-east-2.amazonaws.com", - "http.url_details.path": "/Prod/", + "span.kind": "server", + "http.url": "https://xxxx.execute-api.us-east-2.amazonaws.com/Prod/", "http.method": "GET", - "http.status_code": "200", - "_dd.base_service": "integration-tests-python" + "http.route": "/", + "http.status_code": "200" }, "metrics": { "_dd.top_level": 1 @@ -98,8 +99,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -124,8 +125,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -149,7 +150,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " ] ] } -HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "Content-Encoding:deflate", "Content-Length:XXXX", "Content-Type:application/json", "DD-API-KEY:XXXX", "User-Agent:datadogpy/XX (python XX; os linux; arch x86_64)", "traceparent:XXX", "tracestate:XXX +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -157,8 +158,8 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -172,7 +173,7 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "http.url": "https://api.datadoghq.com/api/v1/distribution_points", "out.host": "api.datadoghq.com", "http.status_code": "202", - "http.useragent": "datadogpy/XX (python XX; os linux; arch x86_64)", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", "language": "python" @@ -199,15 +200,171 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-sync-metrics_python311", "resource:integration-tests-python-XXXX-sync-metrics_python311", + "memorysize:1024", "cold_start:false", + "runtime:python3.11", + "datadog_lambda:vXX", + "dd_lambda_layer:datadog-python311_X.X.X" + ] +} +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +{ + "traces": [ + [ + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "integration-tests-python", + "resource": "integration-tests-python-XXXX-sync-metrics_python311", + "name": "aws.lambda", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "runtime-id": "XXXX", + "_dd.origin": "lambda", + "cold_start": "false", + "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-sync-metrics_python311", + "function_version": "$LATEST", + "request_id": "XXXX", + "resource_names": "integration-tests-python-XXXX-sync-metrics_python311", + "functionname": "integration-tests-python-XXXX-sync-metrics_python311", + "datadog_lambda": "X.X.X", + "dd_trace": "X.X.X", + "span.name": "aws.lambda", + "language": "python" + }, + "metrics": { + "process_id": XXXX, + "_dd.top_level": 1, + "_sampling_priority_v1": 1 + }, + "type": "serverless" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://datadoghq.com/", + "out.host": "datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1 + }, + "type": "http" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://www.datadoghq.com/", + "out.host": "www.datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1 + }, + "type": "http" + } + ] + ] +} +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX +{ + "traces": [ + [ + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "POST /api/v1/distribution_points", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "runtime-id": "XXXX", + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "POST", + "http.url": "https://api.datadoghq.com/api/v1/distribution_points", + "out.host": "api.datadoghq.com", + "http.status_code": "202", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", + "_dd.p.dm": "-0", + "_dd.p.tid": "XXXX", + "language": "python" + }, + "metrics": { + "process_id": XXXX, + "_dd.measured": 1, + "_dd.top_level": 1, + "_sampling_priority_v1": 1 + }, + "type": "http" + } + ] + ] +} +END Duration: XXXX ms Memory Used: XXXX MB +START +{ + "m": "aws.lambda.enhanced.invocations", + "v": 1, + "e": XXXX, + "t": [ + "region:eu-west-1", + "account_id:XXXX", + "functionname:integration-tests-python-XXXX-sync-metrics_python311", + "resource:integration-tests-python-XXXX-sync-metrics_python311", "memorysize:1024", + "cold_start:false", "runtime:python3.11", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python311_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +{ + "m": "datadog.serverless.dynamodb.stream.type", + "v": 1, + "e": XXXX, + "t": [ + "streamtype:NEW_AND_OLD_IMAGES", + "dd_lambda_layer:datadog-python311_X.X.X" + ] +} +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -215,7 +372,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "dynamodb", + "service": "ExampleTableWithStream", "resource": "ExampleTableWithStream", "name": "aws.dynamodb", "error": 0, @@ -226,6 +383,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.dynamodb", "resource_names": "ExampleTableWithStream", + "span.kind": "server", "tablename": "ExampleTableWithStream", "event_source_arn": "arn:aws:dynamodb:us-east-1:XXXX:us-east-1/ExampleTableWithStream/stream/2015-06-27T00:48:05.899", "event_id": "XXXX", @@ -236,24 +394,55 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, - "type": "web" + "type": "web", + "span_links": [ + { + "trace_id": "XXXX", + "span_id": "XXXX", + "attributes": { + "ptr.kind": "aws.dynamodb.item", + "ptr.dir": "u", + "ptr.hash": "e2af34d333891f765c7f02d2da80895e", + "link.kind": "span-pointer" + } + }, + { + "trace_id": "XXXX", + "span_id": "XXXX", + "attributes": { + "ptr.kind": "aws.dynamodb.item", + "ptr.dir": "u", + "ptr.hash": "e2af34d333891f765c7f02d2da80895e", + "link.kind": "span-pointer" + } + }, + { + "trace_id": "XXXX", + "span_id": "XXXX", + "attributes": { + "ptr.kind": "aws.dynamodb.item", + "ptr.dir": "u", + "ptr.hash": "e2af34d333891f765c7f02d2da80895e", + "link.kind": "span-pointer" + } + } + ] }, { "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-sync-metrics_python311", "name": "aws.lambda", "error": 0, @@ -271,8 +460,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "dynamodb", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -283,8 +471,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -309,8 +497,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -334,7 +522,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " ] ] } -HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "Content-Encoding:deflate", "Content-Length:XXXX", "Content-Type:application/json", "DD-API-KEY:XXXX", "User-Agent:datadogpy/XX (python XX; os linux; arch x86_64)", "traceparent:XXX", "tracestate:XXX +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -342,8 +530,8 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -357,7 +545,7 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "http.url": "https://api.datadoghq.com/api/v1/distribution_points", "out.host": "api.datadoghq.com", "http.status_code": "202", - "http.useragent": "datadogpy/XX (python XX; os linux; arch x86_64)", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", "language": "python" @@ -384,15 +572,15 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-sync-metrics_python311", "resource:integration-tests-python-XXXX-sync-metrics_python311", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.11", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python311_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -400,7 +588,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "eventbridge", + "service": "eventbridge.custom.event.sender", "resource": "eventbridge.custom.event.sender", "name": "aws.eventbridge", "error": 0, @@ -411,15 +599,15 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.eventbridge", "resource_names": "eventbridge.custom.event.sender", + "span.kind": "server", "detail_type": "testdetail", "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -432,7 +620,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-sync-metrics_python311", "name": "aws.lambda", "error": 0, @@ -449,8 +637,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "datadog_lambda": "X.X.X", "dd_trace": "X.X.X", "span.name": "aws.lambda", - "function_trigger.event_source": "eventbridge", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source": "eventbridge" }, "metrics": { "_dd.top_level": 1 @@ -461,8 +648,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -487,8 +674,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -512,7 +699,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " ] ] } -HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "Content-Encoding:deflate", "Content-Length:XXXX", "Content-Type:application/json", "DD-API-KEY:XXXX", "User-Agent:datadogpy/XX (python XX; os linux; arch x86_64)", "traceparent:XXX", "tracestate:XXX +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -520,8 +707,8 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -535,7 +722,7 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "http.url": "https://api.datadoghq.com/api/v1/distribution_points", "out.host": "api.datadoghq.com", "http.status_code": "202", - "http.useragent": "datadogpy/XX (python XX; os linux; arch x86_64)", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", "language": "python" @@ -562,15 +749,15 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-sync-metrics_python311", "resource:integration-tests-python-XXXX-sync-metrics_python311", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.11", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python311_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -589,7 +776,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.httpapi", "endpoint": "/httpapi/get", - "http.url": "XXXX.execute-api.eu-west-1.amazonaws.com/httpapi/get", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com/httpapi/get", "http.method": "GET", "http.protocol": "HTTP/1.1", "http.source_ip": "XXXX", @@ -602,12 +789,12 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "sync", "_inferred_span.tag_source": "self", "http.status_code": "200", + "http.route": "/httpapi/get", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -620,7 +807,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-sync-metrics_python311", "name": "aws.lambda", "error": 0, @@ -639,11 +826,11 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "span.name": "aws.lambda", "function_trigger.event_source": "api-gateway", "function_trigger.event_source_arn": "XXXX$default", - "http.url": "XXXX.execute-api.eu-west-1.amazonaws.com", - "http.url_details.path": "/httpapi/get", + "span.kind": "server", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com/httpapi/get", "http.method": "GET", - "http.status_code": "200", - "_dd.base_service": "integration-tests-python" + "http.route": "/httpapi/get", + "http.status_code": "200" }, "metrics": { "_dd.top_level": 1 @@ -654,8 +841,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -680,8 +867,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -705,7 +892,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " ] ] } -HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "Content-Encoding:deflate", "Content-Length:XXXX", "Content-Type:application/json", "DD-API-KEY:XXXX", "User-Agent:datadogpy/XX (python XX; os linux; arch x86_64)", "traceparent:XXX", "tracestate:XXX +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -713,8 +900,8 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -728,7 +915,7 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "http.url": "https://api.datadoghq.com/api/v1/distribution_points", "out.host": "api.datadoghq.com", "http.status_code": "202", - "http.useragent": "datadogpy/XX (python XX; os linux; arch x86_64)", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", "language": "python" @@ -755,15 +942,15 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-sync-metrics_python311", "resource:integration-tests-python-XXXX-sync-metrics_python311", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.11", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python311_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -771,7 +958,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "kinesis", + "service": "EXAMPLE", "resource": "EXAMPLE", "name": "aws.kinesis", "error": 0, @@ -782,6 +969,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.kinesis", "resource_names": "EXAMPLE", + "span.kind": "server", "streamname": "EXAMPLE", "shardid": "shardId-XXXX", "event_source_arn": "arn:aws:kinesis:EXAMPLE", @@ -792,11 +980,10 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -809,7 +996,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-sync-metrics_python311", "name": "aws.lambda", "error": 0, @@ -827,8 +1014,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "kinesis", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -839,8 +1025,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -865,8 +1051,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -890,7 +1076,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " ] ] } -HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "Content-Encoding:deflate", "Content-Length:XXXX", "Content-Type:application/json", "DD-API-KEY:XXXX", "User-Agent:datadogpy/XX (python XX; os linux; arch x86_64)", "traceparent:XXX", "tracestate:XXX +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -898,8 +1084,8 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -913,7 +1099,7 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "http.url": "https://api.datadoghq.com/api/v1/distribution_points", "out.host": "api.datadoghq.com", "http.status_code": "202", - "http.useragent": "datadogpy/XX (python XX; os linux; arch x86_64)", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", "language": "python" @@ -940,15 +1126,15 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-sync-metrics_python311", "resource:integration-tests-python-XXXX-sync-metrics_python311", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.11", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python311_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -956,7 +1142,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "s3", + "service": "example-bucket", "resource": "example-bucket", "name": "aws.s3", "error": 0, @@ -965,6 +1151,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.s3", "resource_names": "example-bucket", + "span.kind": "server", "event_name": "ObjectCreated:Put", "bucketname": "example-bucket", "bucket_arn": "arn:aws:s3:::example-bucket", @@ -974,24 +1161,35 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, - "type": "web" + "type": "web", + "span_links": [ + { + "trace_id": "XXXX", + "span_id": "XXXX", + "attributes": { + "ptr.kind": "aws.s3.object", + "ptr.dir": "u", + "ptr.hash": "1dc3e5d00dae48c1f07d95371a747788", + "link.kind": "span-pointer" + } + } + ] }, { "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-sync-metrics_python311", "name": "aws.lambda", "error": 0, @@ -1009,8 +1207,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "s3", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -1021,8 +1218,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1047,8 +1244,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1072,7 +1269,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " ] ] } -HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "Content-Encoding:deflate", "Content-Length:XXXX", "Content-Type:application/json", "DD-API-KEY:XXXX", "User-Agent:datadogpy/XX (python XX; os linux; arch x86_64)", "traceparent:XXX", "tracestate:XXX +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1080,8 +1277,8 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1095,7 +1292,7 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "http.url": "https://api.datadoghq.com/api/v1/distribution_points", "out.host": "api.datadoghq.com", "http.status_code": "202", - "http.useragent": "datadogpy/XX (python XX; os linux; arch x86_64)", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", "language": "python" @@ -1122,15 +1319,15 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-sync-metrics_python311", "resource:integration-tests-python-XXXX-sync-metrics_python311", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.11", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python311_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1138,7 +1335,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "sns", + "service": "sns-lambda", "resource": "sns-lambda", "name": "aws.sns", "error": 0, @@ -1149,6 +1346,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.sns", "resource_names": "sns-lambda", + "span.kind": "server", "topicname": "sns-lambda", "topic_arn": "arn:aws:sns:us-east-2:XXXX:us-east-2-lambda", "message_id": "XXXX", @@ -1157,11 +1355,10 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -1174,7 +1371,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-sync-metrics_python311", "name": "aws.lambda", "error": 0, @@ -1192,8 +1389,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "sns", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -1204,8 +1400,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1230,8 +1426,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1255,7 +1451,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " ] ] } -HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "Content-Encoding:deflate", "Content-Length:XXXX", "Content-Type:application/json", "DD-API-KEY:XXXX", "User-Agent:datadogpy/XX (python XX; os linux; arch x86_64)", "traceparent:XXX", "tracestate:XXX +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1263,8 +1459,8 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1278,7 +1474,7 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "http.url": "https://api.datadoghq.com/api/v1/distribution_points", "out.host": "api.datadoghq.com", "http.status_code": "202", - "http.useragent": "datadogpy/XX (python XX; os linux; arch x86_64)", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", "language": "python" @@ -1305,15 +1501,15 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-sync-metrics_python311", "resource:integration-tests-python-XXXX-sync-metrics_python311", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.11", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python311_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1321,7 +1517,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "sqs", + "service": "my-queue", "resource": "my-queue", "name": "aws.sqs", "error": 0, @@ -1332,6 +1528,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.sqs", "resource_names": "my-queue", + "span.kind": "server", "queuename": "my-queue", "event_source_arn": "arn:aws:sqs:us-east-2:XXXX:us-east-2-queue", "receipt_handle": "AQEBwJnKyrHigUMZj6rYigCgxlaS3SLy0a...", @@ -1339,11 +1536,10 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -1356,7 +1552,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-sync-metrics_python311", "name": "aws.lambda", "error": 0, @@ -1374,8 +1570,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "sqs", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -1386,8 +1581,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1412,8 +1607,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1437,7 +1632,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " ] ] } -HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "Content-Encoding:deflate", "Content-Length:XXXX", "Content-Type:application/json", "DD-API-KEY:XXXX", "User-Agent:datadogpy/XX (python XX; os linux; arch x86_64)", "traceparent:XXX", "tracestate:XXX +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1445,8 +1640,8 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1460,7 +1655,7 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "http.url": "https://api.datadoghq.com/api/v1/distribution_points", "out.host": "api.datadoghq.com", "http.status_code": "202", - "http.useragent": "datadogpy/XX (python XX; os linux; arch x86_64)", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", "language": "python" @@ -1487,15 +1682,15 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-sync-metrics_python311", "resource:integration-tests-python-XXXX-sync-metrics_python311", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.11", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python311_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1513,9 +1708,10 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "runtime-id": "XXXX", "_dd.origin": "lambda", "operation_name": "aws.apigateway.websocket", - "http.url": "XXXX.execute-api.eu-west-1.amazonaws.com$default", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com$default/", "endpoint": "$default", "resource_names": "$default", + "span.kind": "server", "apiid": "XXXX", "apiname": "XXXX", "stage": "dev", @@ -1527,11 +1723,10 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.tag_source": "self", "http.status_code": "200", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -1544,7 +1739,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-sync-metrics_python311", "name": "aws.lambda", "error": 0, @@ -1563,9 +1758,9 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "span.name": "aws.lambda", "function_trigger.event_source": "api-gateway", "function_trigger.event_source_arn": "XXXX", - "http.url": "XXXX.execute-api.eu-west-1.amazonaws.com", - "http.status_code": "200", - "_dd.base_service": "integration-tests-python" + "span.kind": "server", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com/", + "http.status_code": "200" }, "metrics": { "_dd.top_level": 1 @@ -1576,8 +1771,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1602,8 +1797,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1627,7 +1822,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " ] ] } -HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "Content-Encoding:deflate", "Content-Length:XXXX", "Content-Type:application/json", "DD-API-KEY:XXXX", "User-Agent:datadogpy/XX (python XX; os linux; arch x86_64)", "traceparent:XXX", "tracestate:XXX +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1635,8 +1830,8 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1650,7 +1845,7 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "http.url": "https://api.datadoghq.com/api/v1/distribution_points", "out.host": "api.datadoghq.com", "http.status_code": "202", - "http.useragent": "datadogpy/XX (python XX; os linux; arch x86_64)", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", "language": "python" diff --git a/tests/integration/snapshots/logs/sync-metrics_python37.log b/tests/integration/snapshots/logs/sync-metrics_python312.log similarity index 73% rename from tests/integration/snapshots/logs/sync-metrics_python37.log rename to tests/integration/snapshots/logs/sync-metrics_python312.log index fb7b879b6..ff9bbdb75 100644 --- a/tests/integration/snapshots/logs/sync-metrics_python37.log +++ b/tests/integration/snapshots/logs/sync-metrics_python312.log @@ -1,4 +1,4 @@ -INIT_START Runtime Version: python:3.7.vX Runtime Version ARN: arn:aws:lambda:eu-west-1:XXXX:eu-west-1 +INIT_START Runtime Version: python:3.12.vX Runtime Version ARN: arn:aws:lambda:eu-west-1:XXXX:eu-west-1 START { "m": "aws.lambda.enhanced.invocations", @@ -7,17 +7,17 @@ START "t": [ "region:eu-west-1", "account_id:XXXX", - "functionname:integration-tests-python-XXXX-sync-metrics_python37", - "resource:integration-tests-python-XXXX-sync-metrics_python37", - "cold_start:true", + "functionname:integration-tests-python-XXXX-sync-metrics_python312", + "resource:integration-tests-python-XXXX-sync-metrics_python312", "memorysize:1024", - "runtime:python3.7", + "cold_start:true", + "runtime:python3.12", "datadog_lambda:vXX", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python312_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -35,10 +35,11 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "runtime-id": "XXXX", "_dd.origin": "lambda", "operation_name": "aws.apigateway.rest", - "http.url": "XXXX.execute-api.us-east-2.amazonaws.com/", + "http.url": "https://xxxx.execute-api.us-east-2.amazonaws.com/", "endpoint": "/", "http.method": "GET", "resource_names": "GET /", + "span.kind": "server", "apiid": "XXXX", "apiname": "XXXX", "stage": "Prod", @@ -46,12 +47,12 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "sync", "_inferred_span.tag_source": "self", "http.status_code": "200", + "http.route": "/", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -64,8 +65,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "integration-tests-python-XXXX-sync-metrics_python37", + "service": "integration-tests-python", + "resource": "integration-tests-python-XXXX-sync-metrics_python312", "name": "aws.lambda", "error": 0, "start": "XXXX", @@ -73,21 +74,21 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "meta": { "_dd.origin": "lambda", "cold_start": "true", - "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-sync-metrics_python37", + "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-sync-metrics_python312", "function_version": "$LATEST", "request_id": "XXXX", - "resource_names": "integration-tests-python-XXXX-sync-metrics_python37", - "functionname": "integration-tests-python-XXXX-sync-metrics_python37", + "resource_names": "integration-tests-python-XXXX-sync-metrics_python312", + "functionname": "integration-tests-python-XXXX-sync-metrics_python312", "datadog_lambda": "X.X.X", "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "api-gateway", "function_trigger.event_source_arn": "XXXX", - "http.url": "XXXX.execute-api.us-east-2.amazonaws.com", - "http.url_details.path": "/Prod/", + "span.kind": "server", + "http.url": "https://xxxx.execute-api.us-east-2.amazonaws.com/Prod/", "http.method": "GET", - "http.status_code": "200", - "_dd.base_service": "integration-tests-python" + "http.route": "/", + "http.status_code": "200" }, "metrics": { "_dd.top_level": 1 @@ -98,8 +99,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -124,8 +125,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -149,7 +150,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " ] ] } -HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "Content-Encoding:deflate", "Content-Length:XXXX", "Content-Type:application/json", "DD-API-KEY:XXXX", "User-Agent:datadogpy/XX (python XX; os linux; arch x86_64)", "traceparent:XXX", "tracestate:XXX +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -157,8 +158,8 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -172,7 +173,7 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "http.url": "https://api.datadoghq.com/api/v1/distribution_points", "out.host": "api.datadoghq.com", "http.status_code": "202", - "http.useragent": "datadogpy/XX (python XX; os linux; arch x86_64)", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", "language": "python" @@ -197,17 +198,173 @@ START "t": [ "region:eu-west-1", "account_id:XXXX", - "functionname:integration-tests-python-XXXX-sync-metrics_python37", - "resource:integration-tests-python-XXXX-sync-metrics_python37", + "functionname:integration-tests-python-XXXX-sync-metrics_python312", + "resource:integration-tests-python-XXXX-sync-metrics_python312", + "memorysize:1024", "cold_start:false", + "runtime:python3.12", + "datadog_lambda:vXX", + "dd_lambda_layer:datadog-python312_X.X.X" + ] +} +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +{ + "traces": [ + [ + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "integration-tests-python", + "resource": "integration-tests-python-XXXX-sync-metrics_python312", + "name": "aws.lambda", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "runtime-id": "XXXX", + "_dd.origin": "lambda", + "cold_start": "false", + "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-sync-metrics_python312", + "function_version": "$LATEST", + "request_id": "XXXX", + "resource_names": "integration-tests-python-XXXX-sync-metrics_python312", + "functionname": "integration-tests-python-XXXX-sync-metrics_python312", + "datadog_lambda": "X.X.X", + "dd_trace": "X.X.X", + "span.name": "aws.lambda", + "language": "python" + }, + "metrics": { + "process_id": XXXX, + "_dd.top_level": 1, + "_sampling_priority_v1": 1 + }, + "type": "serverless" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://datadoghq.com/", + "out.host": "datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1 + }, + "type": "http" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://www.datadoghq.com/", + "out.host": "www.datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1 + }, + "type": "http" + } + ] + ] +} +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX +{ + "traces": [ + [ + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "POST /api/v1/distribution_points", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "runtime-id": "XXXX", + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "POST", + "http.url": "https://api.datadoghq.com/api/v1/distribution_points", + "out.host": "api.datadoghq.com", + "http.status_code": "202", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", + "_dd.p.dm": "-0", + "_dd.p.tid": "XXXX", + "language": "python" + }, + "metrics": { + "process_id": XXXX, + "_dd.measured": 1, + "_dd.top_level": 1, + "_sampling_priority_v1": 1 + }, + "type": "http" + } + ] + ] +} +END Duration: XXXX ms Memory Used: XXXX MB +START +{ + "m": "aws.lambda.enhanced.invocations", + "v": 1, + "e": XXXX, + "t": [ + "region:eu-west-1", + "account_id:XXXX", + "functionname:integration-tests-python-XXXX-sync-metrics_python312", + "resource:integration-tests-python-XXXX-sync-metrics_python312", "memorysize:1024", - "runtime:python3.7", + "cold_start:false", + "runtime:python3.12", "datadog_lambda:vXX", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python312_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +{ + "m": "datadog.serverless.dynamodb.stream.type", + "v": 1, + "e": XXXX, + "t": [ + "streamtype:NEW_AND_OLD_IMAGES", + "dd_lambda_layer:datadog-python312_X.X.X" + ] +} +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -215,7 +372,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "dynamodb", + "service": "ExampleTableWithStream", "resource": "ExampleTableWithStream", "name": "aws.dynamodb", "error": 0, @@ -226,6 +383,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.dynamodb", "resource_names": "ExampleTableWithStream", + "span.kind": "server", "tablename": "ExampleTableWithStream", "event_source_arn": "arn:aws:dynamodb:us-east-1:XXXX:us-east-1/ExampleTableWithStream/stream/2015-06-27T00:48:05.899", "event_id": "XXXX", @@ -236,25 +394,56 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, - "type": "web" + "type": "web", + "span_links": [ + { + "trace_id": "XXXX", + "span_id": "XXXX", + "attributes": { + "ptr.kind": "aws.dynamodb.item", + "ptr.dir": "u", + "ptr.hash": "e2af34d333891f765c7f02d2da80895e", + "link.kind": "span-pointer" + } + }, + { + "trace_id": "XXXX", + "span_id": "XXXX", + "attributes": { + "ptr.kind": "aws.dynamodb.item", + "ptr.dir": "u", + "ptr.hash": "e2af34d333891f765c7f02d2da80895e", + "link.kind": "span-pointer" + } + }, + { + "trace_id": "XXXX", + "span_id": "XXXX", + "attributes": { + "ptr.kind": "aws.dynamodb.item", + "ptr.dir": "u", + "ptr.hash": "e2af34d333891f765c7f02d2da80895e", + "link.kind": "span-pointer" + } + } + ] }, { "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "integration-tests-python-XXXX-sync-metrics_python37", + "service": "integration-tests-python", + "resource": "integration-tests-python-XXXX-sync-metrics_python312", "name": "aws.lambda", "error": 0, "start": "XXXX", @@ -262,17 +451,16 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "meta": { "_dd.origin": "lambda", "cold_start": "false", - "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-sync-metrics_python37", + "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-sync-metrics_python312", "function_version": "$LATEST", "request_id": "XXXX", - "resource_names": "integration-tests-python-XXXX-sync-metrics_python37", - "functionname": "integration-tests-python-XXXX-sync-metrics_python37", + "resource_names": "integration-tests-python-XXXX-sync-metrics_python312", + "functionname": "integration-tests-python-XXXX-sync-metrics_python312", "datadog_lambda": "X.X.X", "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "dynamodb", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -283,8 +471,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -309,8 +497,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -334,7 +522,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " ] ] } -HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "Content-Encoding:deflate", "Content-Length:XXXX", "Content-Type:application/json", "DD-API-KEY:XXXX", "User-Agent:datadogpy/XX (python XX; os linux; arch x86_64)", "traceparent:XXX", "tracestate:XXX +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -342,8 +530,8 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -357,7 +545,7 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "http.url": "https://api.datadoghq.com/api/v1/distribution_points", "out.host": "api.datadoghq.com", "http.status_code": "202", - "http.useragent": "datadogpy/XX (python XX; os linux; arch x86_64)", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", "language": "python" @@ -382,17 +570,17 @@ START "t": [ "region:eu-west-1", "account_id:XXXX", - "functionname:integration-tests-python-XXXX-sync-metrics_python37", - "resource:integration-tests-python-XXXX-sync-metrics_python37", - "cold_start:false", + "functionname:integration-tests-python-XXXX-sync-metrics_python312", + "resource:integration-tests-python-XXXX-sync-metrics_python312", "memorysize:1024", - "runtime:python3.7", + "cold_start:false", + "runtime:python3.12", "datadog_lambda:vXX", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python312_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -400,7 +588,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "eventbridge", + "service": "eventbridge.custom.event.sender", "resource": "eventbridge.custom.event.sender", "name": "aws.eventbridge", "error": 0, @@ -411,15 +599,15 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.eventbridge", "resource_names": "eventbridge.custom.event.sender", + "span.kind": "server", "detail_type": "testdetail", "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -432,8 +620,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "integration-tests-python-XXXX-sync-metrics_python37", + "service": "integration-tests-python", + "resource": "integration-tests-python-XXXX-sync-metrics_python312", "name": "aws.lambda", "error": 0, "start": "XXXX", @@ -441,16 +629,15 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "meta": { "_dd.origin": "lambda", "cold_start": "false", - "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-sync-metrics_python37", + "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-sync-metrics_python312", "function_version": "$LATEST", "request_id": "XXXX", - "resource_names": "integration-tests-python-XXXX-sync-metrics_python37", - "functionname": "integration-tests-python-XXXX-sync-metrics_python37", + "resource_names": "integration-tests-python-XXXX-sync-metrics_python312", + "functionname": "integration-tests-python-XXXX-sync-metrics_python312", "datadog_lambda": "X.X.X", "dd_trace": "X.X.X", "span.name": "aws.lambda", - "function_trigger.event_source": "eventbridge", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source": "eventbridge" }, "metrics": { "_dd.top_level": 1 @@ -461,8 +648,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -487,8 +674,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -512,7 +699,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " ] ] } -HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "Content-Encoding:deflate", "Content-Length:XXXX", "Content-Type:application/json", "DD-API-KEY:XXXX", "User-Agent:datadogpy/XX (python XX; os linux; arch x86_64)", "traceparent:XXX", "tracestate:XXX +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -520,8 +707,8 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -535,7 +722,7 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "http.url": "https://api.datadoghq.com/api/v1/distribution_points", "out.host": "api.datadoghq.com", "http.status_code": "202", - "http.useragent": "datadogpy/XX (python XX; os linux; arch x86_64)", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", "language": "python" @@ -560,17 +747,17 @@ START "t": [ "region:eu-west-1", "account_id:XXXX", - "functionname:integration-tests-python-XXXX-sync-metrics_python37", - "resource:integration-tests-python-XXXX-sync-metrics_python37", - "cold_start:false", + "functionname:integration-tests-python-XXXX-sync-metrics_python312", + "resource:integration-tests-python-XXXX-sync-metrics_python312", "memorysize:1024", - "runtime:python3.7", + "cold_start:false", + "runtime:python3.12", "datadog_lambda:vXX", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python312_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -589,7 +776,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.httpapi", "endpoint": "/httpapi/get", - "http.url": "XXXX.execute-api.eu-west-1.amazonaws.com/httpapi/get", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com/httpapi/get", "http.method": "GET", "http.protocol": "HTTP/1.1", "http.source_ip": "XXXX", @@ -602,12 +789,12 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "sync", "_inferred_span.tag_source": "self", "http.status_code": "200", + "http.route": "/httpapi/get", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -620,8 +807,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "integration-tests-python-XXXX-sync-metrics_python37", + "service": "integration-tests-python", + "resource": "integration-tests-python-XXXX-sync-metrics_python312", "name": "aws.lambda", "error": 0, "start": "XXXX", @@ -629,21 +816,21 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "meta": { "_dd.origin": "lambda", "cold_start": "false", - "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-sync-metrics_python37", + "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-sync-metrics_python312", "function_version": "$LATEST", "request_id": "XXXX", - "resource_names": "integration-tests-python-XXXX-sync-metrics_python37", - "functionname": "integration-tests-python-XXXX-sync-metrics_python37", + "resource_names": "integration-tests-python-XXXX-sync-metrics_python312", + "functionname": "integration-tests-python-XXXX-sync-metrics_python312", "datadog_lambda": "X.X.X", "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "api-gateway", "function_trigger.event_source_arn": "XXXX$default", - "http.url": "XXXX.execute-api.eu-west-1.amazonaws.com", - "http.url_details.path": "/httpapi/get", + "span.kind": "server", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com/httpapi/get", "http.method": "GET", - "http.status_code": "200", - "_dd.base_service": "integration-tests-python" + "http.route": "/httpapi/get", + "http.status_code": "200" }, "metrics": { "_dd.top_level": 1 @@ -654,8 +841,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -680,8 +867,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -705,8 +892,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " ] ] } -HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "Content-Encoding:deflate", "Content-Length:XXXX", "Content-Type:application/json", "DD-API-KEY:XXXX", "User-Agent:datadogpy/XX (python XX; os linux; arch x86_64)", "traceparent:XXX", "tracestate:XXX -END Duration: XXXX ms Memory Used: XXXX MB +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -714,8 +900,8 @@ END Duration: XXXX ms Memory Used: XXXX MB "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -729,7 +915,7 @@ END Duration: XXXX ms Memory Used: XXXX MB "http.url": "https://api.datadoghq.com/api/v1/distribution_points", "out.host": "api.datadoghq.com", "http.status_code": "202", - "http.useragent": "datadogpy/XX (python XX; os linux; arch x86_64)", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", "language": "python" @@ -745,6 +931,7 @@ END Duration: XXXX ms Memory Used: XXXX MB ] ] } +END Duration: XXXX ms Memory Used: XXXX MB START { "m": "aws.lambda.enhanced.invocations", @@ -753,17 +940,17 @@ START "t": [ "region:eu-west-1", "account_id:XXXX", - "functionname:integration-tests-python-XXXX-sync-metrics_python37", - "resource:integration-tests-python-XXXX-sync-metrics_python37", - "cold_start:false", + "functionname:integration-tests-python-XXXX-sync-metrics_python312", + "resource:integration-tests-python-XXXX-sync-metrics_python312", "memorysize:1024", - "runtime:python3.7", + "cold_start:false", + "runtime:python3.12", "datadog_lambda:vXX", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python312_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -771,7 +958,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "kinesis", + "service": "EXAMPLE", "resource": "EXAMPLE", "name": "aws.kinesis", "error": 0, @@ -782,6 +969,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.kinesis", "resource_names": "EXAMPLE", + "span.kind": "server", "streamname": "EXAMPLE", "shardid": "shardId-XXXX", "event_source_arn": "arn:aws:kinesis:EXAMPLE", @@ -792,11 +980,10 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -809,8 +996,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "integration-tests-python-XXXX-sync-metrics_python37", + "service": "integration-tests-python", + "resource": "integration-tests-python-XXXX-sync-metrics_python312", "name": "aws.lambda", "error": 0, "start": "XXXX", @@ -818,17 +1005,16 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "meta": { "_dd.origin": "lambda", "cold_start": "false", - "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-sync-metrics_python37", + "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-sync-metrics_python312", "function_version": "$LATEST", "request_id": "XXXX", - "resource_names": "integration-tests-python-XXXX-sync-metrics_python37", - "functionname": "integration-tests-python-XXXX-sync-metrics_python37", + "resource_names": "integration-tests-python-XXXX-sync-metrics_python312", + "functionname": "integration-tests-python-XXXX-sync-metrics_python312", "datadog_lambda": "X.X.X", "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "kinesis", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -839,8 +1025,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -865,8 +1051,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -890,7 +1076,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " ] ] } -HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "Content-Encoding:deflate", "Content-Length:XXXX", "Content-Type:application/json", "DD-API-KEY:XXXX", "User-Agent:datadogpy/XX (python XX; os linux; arch x86_64)", "traceparent:XXX", "tracestate:XXX +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -898,8 +1084,8 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -913,7 +1099,7 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "http.url": "https://api.datadoghq.com/api/v1/distribution_points", "out.host": "api.datadoghq.com", "http.status_code": "202", - "http.useragent": "datadogpy/XX (python XX; os linux; arch x86_64)", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", "language": "python" @@ -938,17 +1124,17 @@ START "t": [ "region:eu-west-1", "account_id:XXXX", - "functionname:integration-tests-python-XXXX-sync-metrics_python37", - "resource:integration-tests-python-XXXX-sync-metrics_python37", - "cold_start:false", + "functionname:integration-tests-python-XXXX-sync-metrics_python312", + "resource:integration-tests-python-XXXX-sync-metrics_python312", "memorysize:1024", - "runtime:python3.7", + "cold_start:false", + "runtime:python3.12", "datadog_lambda:vXX", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python312_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -956,7 +1142,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "s3", + "service": "example-bucket", "resource": "example-bucket", "name": "aws.s3", "error": 0, @@ -965,6 +1151,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.s3", "resource_names": "example-bucket", + "span.kind": "server", "event_name": "ObjectCreated:Put", "bucketname": "example-bucket", "bucket_arn": "arn:aws:s3:::example-bucket", @@ -974,25 +1161,36 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, - "type": "web" + "type": "web", + "span_links": [ + { + "trace_id": "XXXX", + "span_id": "XXXX", + "attributes": { + "ptr.kind": "aws.s3.object", + "ptr.dir": "u", + "ptr.hash": "1dc3e5d00dae48c1f07d95371a747788", + "link.kind": "span-pointer" + } + } + ] }, { "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "integration-tests-python-XXXX-sync-metrics_python37", + "service": "integration-tests-python", + "resource": "integration-tests-python-XXXX-sync-metrics_python312", "name": "aws.lambda", "error": 0, "start": "XXXX", @@ -1000,17 +1198,16 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "meta": { "_dd.origin": "lambda", "cold_start": "false", - "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-sync-metrics_python37", + "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-sync-metrics_python312", "function_version": "$LATEST", "request_id": "XXXX", - "resource_names": "integration-tests-python-XXXX-sync-metrics_python37", - "functionname": "integration-tests-python-XXXX-sync-metrics_python37", + "resource_names": "integration-tests-python-XXXX-sync-metrics_python312", + "functionname": "integration-tests-python-XXXX-sync-metrics_python312", "datadog_lambda": "X.X.X", "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "s3", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -1021,8 +1218,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1047,8 +1244,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1072,7 +1269,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " ] ] } -HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "Content-Encoding:deflate", "Content-Length:XXXX", "Content-Type:application/json", "DD-API-KEY:XXXX", "User-Agent:datadogpy/XX (python XX; os linux; arch x86_64)", "traceparent:XXX", "tracestate:XXX +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1080,8 +1277,8 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1095,7 +1292,7 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "http.url": "https://api.datadoghq.com/api/v1/distribution_points", "out.host": "api.datadoghq.com", "http.status_code": "202", - "http.useragent": "datadogpy/XX (python XX; os linux; arch x86_64)", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", "language": "python" @@ -1120,17 +1317,17 @@ START "t": [ "region:eu-west-1", "account_id:XXXX", - "functionname:integration-tests-python-XXXX-sync-metrics_python37", - "resource:integration-tests-python-XXXX-sync-metrics_python37", - "cold_start:false", + "functionname:integration-tests-python-XXXX-sync-metrics_python312", + "resource:integration-tests-python-XXXX-sync-metrics_python312", "memorysize:1024", - "runtime:python3.7", + "cold_start:false", + "runtime:python3.12", "datadog_lambda:vXX", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python312_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1138,7 +1335,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "sns", + "service": "sns-lambda", "resource": "sns-lambda", "name": "aws.sns", "error": 0, @@ -1149,6 +1346,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.sns", "resource_names": "sns-lambda", + "span.kind": "server", "topicname": "sns-lambda", "topic_arn": "arn:aws:sns:us-east-2:XXXX:us-east-2-lambda", "message_id": "XXXX", @@ -1157,11 +1355,10 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -1174,8 +1371,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "integration-tests-python-XXXX-sync-metrics_python37", + "service": "integration-tests-python", + "resource": "integration-tests-python-XXXX-sync-metrics_python312", "name": "aws.lambda", "error": 0, "start": "XXXX", @@ -1183,17 +1380,16 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "meta": { "_dd.origin": "lambda", "cold_start": "false", - "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-sync-metrics_python37", + "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-sync-metrics_python312", "function_version": "$LATEST", "request_id": "XXXX", - "resource_names": "integration-tests-python-XXXX-sync-metrics_python37", - "functionname": "integration-tests-python-XXXX-sync-metrics_python37", + "resource_names": "integration-tests-python-XXXX-sync-metrics_python312", + "functionname": "integration-tests-python-XXXX-sync-metrics_python312", "datadog_lambda": "X.X.X", "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "sns", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -1204,8 +1400,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1230,8 +1426,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1255,7 +1451,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " ] ] } -HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "Content-Encoding:deflate", "Content-Length:XXXX", "Content-Type:application/json", "DD-API-KEY:XXXX", "User-Agent:datadogpy/XX (python XX; os linux; arch x86_64)", "traceparent:XXX", "tracestate:XXX +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1263,8 +1459,8 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1278,7 +1474,7 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "http.url": "https://api.datadoghq.com/api/v1/distribution_points", "out.host": "api.datadoghq.com", "http.status_code": "202", - "http.useragent": "datadogpy/XX (python XX; os linux; arch x86_64)", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", "language": "python" @@ -1303,17 +1499,17 @@ START "t": [ "region:eu-west-1", "account_id:XXXX", - "functionname:integration-tests-python-XXXX-sync-metrics_python37", - "resource:integration-tests-python-XXXX-sync-metrics_python37", - "cold_start:false", + "functionname:integration-tests-python-XXXX-sync-metrics_python312", + "resource:integration-tests-python-XXXX-sync-metrics_python312", "memorysize:1024", - "runtime:python3.7", + "cold_start:false", + "runtime:python3.12", "datadog_lambda:vXX", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python312_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1321,7 +1517,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "sqs", + "service": "my-queue", "resource": "my-queue", "name": "aws.sqs", "error": 0, @@ -1332,6 +1528,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.sqs", "resource_names": "my-queue", + "span.kind": "server", "queuename": "my-queue", "event_source_arn": "arn:aws:sqs:us-east-2:XXXX:us-east-2-queue", "receipt_handle": "AQEBwJnKyrHigUMZj6rYigCgxlaS3SLy0a...", @@ -1339,11 +1536,10 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -1356,8 +1552,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "integration-tests-python-XXXX-sync-metrics_python37", + "service": "integration-tests-python", + "resource": "integration-tests-python-XXXX-sync-metrics_python312", "name": "aws.lambda", "error": 0, "start": "XXXX", @@ -1365,17 +1561,16 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "meta": { "_dd.origin": "lambda", "cold_start": "false", - "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-sync-metrics_python37", + "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-sync-metrics_python312", "function_version": "$LATEST", "request_id": "XXXX", - "resource_names": "integration-tests-python-XXXX-sync-metrics_python37", - "functionname": "integration-tests-python-XXXX-sync-metrics_python37", + "resource_names": "integration-tests-python-XXXX-sync-metrics_python312", + "functionname": "integration-tests-python-XXXX-sync-metrics_python312", "datadog_lambda": "X.X.X", "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "sqs", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -1386,8 +1581,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1412,8 +1607,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1437,7 +1632,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " ] ] } -HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "Content-Encoding:deflate", "Content-Length:XXXX", "Content-Type:application/json", "DD-API-KEY:XXXX", "User-Agent:datadogpy/XX (python XX; os linux; arch x86_64)", "traceparent:XXX", "tracestate:XXX +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1445,8 +1640,8 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1460,7 +1655,7 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "http.url": "https://api.datadoghq.com/api/v1/distribution_points", "out.host": "api.datadoghq.com", "http.status_code": "202", - "http.useragent": "datadogpy/XX (python XX; os linux; arch x86_64)", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", "language": "python" @@ -1485,17 +1680,17 @@ START "t": [ "region:eu-west-1", "account_id:XXXX", - "functionname:integration-tests-python-XXXX-sync-metrics_python37", - "resource:integration-tests-python-XXXX-sync-metrics_python37", - "cold_start:false", + "functionname:integration-tests-python-XXXX-sync-metrics_python312", + "resource:integration-tests-python-XXXX-sync-metrics_python312", "memorysize:1024", - "runtime:python3.7", + "cold_start:false", + "runtime:python3.12", "datadog_lambda:vXX", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python312_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1513,9 +1708,10 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "runtime-id": "XXXX", "_dd.origin": "lambda", "operation_name": "aws.apigateway.websocket", - "http.url": "XXXX.execute-api.eu-west-1.amazonaws.com$default", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com$default/", "endpoint": "$default", "resource_names": "$default", + "span.kind": "server", "apiid": "XXXX", "apiname": "XXXX", "stage": "dev", @@ -1527,11 +1723,10 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.tag_source": "self", "http.status_code": "200", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -1544,8 +1739,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "integration-tests-python-XXXX-sync-metrics_python37", + "service": "integration-tests-python", + "resource": "integration-tests-python-XXXX-sync-metrics_python312", "name": "aws.lambda", "error": 0, "start": "XXXX", @@ -1553,19 +1748,19 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "meta": { "_dd.origin": "lambda", "cold_start": "false", - "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-sync-metrics_python37", + "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-sync-metrics_python312", "function_version": "$LATEST", "request_id": "XXXX", - "resource_names": "integration-tests-python-XXXX-sync-metrics_python37", - "functionname": "integration-tests-python-XXXX-sync-metrics_python37", + "resource_names": "integration-tests-python-XXXX-sync-metrics_python312", + "functionname": "integration-tests-python-XXXX-sync-metrics_python312", "datadog_lambda": "X.X.X", "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "api-gateway", "function_trigger.event_source_arn": "XXXX", - "http.url": "XXXX.execute-api.eu-west-1.amazonaws.com", - "http.status_code": "200", - "_dd.base_service": "integration-tests-python" + "span.kind": "server", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com/", + "http.status_code": "200" }, "metrics": { "_dd.top_level": 1 @@ -1576,8 +1771,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1602,8 +1797,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1627,7 +1822,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " ] ] } -HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "Content-Encoding:deflate", "Content-Length:XXXX", "Content-Type:application/json", "DD-API-KEY:XXXX", "User-Agent:datadogpy/XX (python XX; os linux; arch x86_64)", "traceparent:XXX", "tracestate:XXX +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1635,8 +1830,8 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1650,7 +1845,7 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "http.url": "https://api.datadoghq.com/api/v1/distribution_points", "out.host": "api.datadoghq.com", "http.status_code": "202", - "http.useragent": "datadogpy/XX (python XX; os linux; arch x86_64)", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", "language": "python" diff --git a/tests/integration/snapshots/logs/sync-metrics_python313.log b/tests/integration/snapshots/logs/sync-metrics_python313.log new file mode 100644 index 000000000..87352f25e --- /dev/null +++ b/tests/integration/snapshots/logs/sync-metrics_python313.log @@ -0,0 +1,1864 @@ +INIT_START Runtime Version: python:3.13.vX Runtime Version ARN: arn:aws:lambda:eu-west-1:XXXX:eu-west-1 +START +{ + "m": "aws.lambda.enhanced.invocations", + "v": 1, + "e": XXXX, + "t": [ + "region:eu-west-1", + "account_id:XXXX", + "functionname:integration-tests-python-XXXX-sync-metrics_python313", + "resource:integration-tests-python-XXXX-sync-metrics_python313", + "memorysize:1024", + "cold_start:true", + "runtime:python3.13", + "datadog_lambda:vXX", + "dd_lambda_layer:datadog-python313_X.X.X" + ] +} +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +{ + "traces": [ + [ + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "XXXX.execute-api.us-east-2.amazonaws.com", + "resource": "GET /", + "name": "aws.apigateway", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "runtime-id": "XXXX", + "_dd.origin": "lambda", + "operation_name": "aws.apigateway.rest", + "http.url": "https://xxxx.execute-api.us-east-2.amazonaws.com/", + "endpoint": "/", + "http.method": "GET", + "resource_names": "GET /", + "span.kind": "server", + "apiid": "XXXX", + "apiname": "XXXX", + "stage": "Prod", + "request_id": "XXXX", + "_inferred_span.synchronicity": "sync", + "_inferred_span.tag_source": "self", + "http.status_code": "200", + "http.route": "/", + "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", + "_dd.p.dm": "-0", + "_dd.p.tid": "XXXX", + "language": "python" + }, + "metrics": { + "process_id": XXXX, + "_dd.top_level": 1, + "_sampling_priority_v1": 1 + }, + "type": "http" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "integration-tests-python", + "resource": "integration-tests-python-XXXX-sync-metrics_python313", + "name": "aws.lambda", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "cold_start": "true", + "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-sync-metrics_python313", + "function_version": "$LATEST", + "request_id": "XXXX", + "resource_names": "integration-tests-python-XXXX-sync-metrics_python313", + "functionname": "integration-tests-python-XXXX-sync-metrics_python313", + "datadog_lambda": "X.X.X", + "dd_trace": "X.X.X", + "span.name": "aws.lambda", + "function_trigger.event_source": "api-gateway", + "function_trigger.event_source_arn": "XXXX", + "span.kind": "server", + "http.url": "https://xxxx.execute-api.us-east-2.amazonaws.com/Prod/", + "http.method": "GET", + "http.route": "/", + "http.status_code": "200" + }, + "metrics": { + "_dd.top_level": 1 + }, + "type": "serverless" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://datadoghq.com/", + "out.host": "datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1 + }, + "type": "http" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.p.tid": "XXXX", + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://www.datadoghq.com/", + "out.host": "www.datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1 + }, + "type": "http" + } + ] + ] +} +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX +{ + "traces": [ + [ + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "POST /api/v1/distribution_points", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "runtime-id": "XXXX", + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "POST", + "http.url": "https://api.datadoghq.com/api/v1/distribution_points", + "out.host": "api.datadoghq.com", + "http.status_code": "202", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", + "_dd.p.dm": "-0", + "_dd.p.tid": "XXXX", + "language": "python" + }, + "metrics": { + "process_id": XXXX, + "_dd.measured": 1, + "_dd.top_level": 1, + "_sampling_priority_v1": 1 + }, + "type": "http" + } + ] + ] +} +END Duration: XXXX ms (init: XXXX ms) Memory Used: XXXX MB +START +{ + "m": "aws.lambda.enhanced.invocations", + "v": 1, + "e": XXXX, + "t": [ + "region:eu-west-1", + "account_id:XXXX", + "functionname:integration-tests-python-XXXX-sync-metrics_python313", + "resource:integration-tests-python-XXXX-sync-metrics_python313", + "memorysize:1024", + "cold_start:false", + "runtime:python3.13", + "datadog_lambda:vXX", + "dd_lambda_layer:datadog-python313_X.X.X" + ] +} +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +{ + "traces": [ + [ + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "integration-tests-python", + "resource": "integration-tests-python-XXXX-sync-metrics_python313", + "name": "aws.lambda", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "runtime-id": "XXXX", + "_dd.origin": "lambda", + "cold_start": "false", + "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-sync-metrics_python313", + "function_version": "$LATEST", + "request_id": "XXXX", + "resource_names": "integration-tests-python-XXXX-sync-metrics_python313", + "functionname": "integration-tests-python-XXXX-sync-metrics_python313", + "datadog_lambda": "X.X.X", + "dd_trace": "X.X.X", + "span.name": "aws.lambda", + "language": "python" + }, + "metrics": { + "process_id": XXXX, + "_dd.top_level": 1, + "_sampling_priority_v1": 1 + }, + "type": "serverless" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://datadoghq.com/", + "out.host": "datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1 + }, + "type": "http" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://www.datadoghq.com/", + "out.host": "www.datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1 + }, + "type": "http" + } + ] + ] +} +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX +{ + "traces": [ + [ + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "POST /api/v1/distribution_points", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "runtime-id": "XXXX", + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "POST", + "http.url": "https://api.datadoghq.com/api/v1/distribution_points", + "out.host": "api.datadoghq.com", + "http.status_code": "202", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", + "_dd.p.dm": "-0", + "_dd.p.tid": "XXXX", + "language": "python" + }, + "metrics": { + "process_id": XXXX, + "_dd.measured": 1, + "_dd.top_level": 1, + "_sampling_priority_v1": 1 + }, + "type": "http" + } + ] + ] +} +END Duration: XXXX ms Memory Used: XXXX MB +START +{ + "m": "aws.lambda.enhanced.invocations", + "v": 1, + "e": XXXX, + "t": [ + "region:eu-west-1", + "account_id:XXXX", + "functionname:integration-tests-python-XXXX-sync-metrics_python313", + "resource:integration-tests-python-XXXX-sync-metrics_python313", + "memorysize:1024", + "cold_start:false", + "runtime:python3.13", + "datadog_lambda:vXX", + "dd_lambda_layer:datadog-python313_X.X.X" + ] +} +{ + "m": "datadog.serverless.dynamodb.stream.type", + "v": 1, + "e": XXXX, + "t": [ + "streamtype:NEW_AND_OLD_IMAGES", + "dd_lambda_layer:datadog-python313_X.X.X" + ] +} +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +{ + "traces": [ + [ + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "ExampleTableWithStream", + "resource": "ExampleTableWithStream", + "name": "aws.dynamodb", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "runtime-id": "XXXX", + "_dd.origin": "lambda", + "operation_name": "aws.dynamodb", + "resource_names": "ExampleTableWithStream", + "span.kind": "server", + "tablename": "ExampleTableWithStream", + "event_source_arn": "arn:aws:dynamodb:us-east-1:XXXX:us-east-1/ExampleTableWithStream/stream/2015-06-27T00:48:05.899", + "event_id": "XXXX", + "event_name": "INSERT", + "event_version": "1.1", + "stream_view_type": "NEW_AND_OLD_IMAGES", + "size_bytes": "26", + "_inferred_span.synchronicity": "async", + "_inferred_span.tag_source": "self", + "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", + "_dd.p.dm": "-0", + "_dd.p.tid": "XXXX", + "language": "python" + }, + "metrics": { + "process_id": XXXX, + "_dd.top_level": 1, + "_sampling_priority_v1": 1 + }, + "type": "web", + "span_links": [ + { + "trace_id": "XXXX", + "span_id": "XXXX", + "attributes": { + "ptr.kind": "aws.dynamodb.item", + "ptr.dir": "u", + "ptr.hash": "e2af34d333891f765c7f02d2da80895e", + "link.kind": "span-pointer" + } + }, + { + "trace_id": "XXXX", + "span_id": "XXXX", + "attributes": { + "ptr.kind": "aws.dynamodb.item", + "ptr.dir": "u", + "ptr.hash": "e2af34d333891f765c7f02d2da80895e", + "link.kind": "span-pointer" + } + }, + { + "trace_id": "XXXX", + "span_id": "XXXX", + "attributes": { + "ptr.kind": "aws.dynamodb.item", + "ptr.dir": "u", + "ptr.hash": "e2af34d333891f765c7f02d2da80895e", + "link.kind": "span-pointer" + } + } + ] + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "integration-tests-python", + "resource": "integration-tests-python-XXXX-sync-metrics_python313", + "name": "aws.lambda", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "cold_start": "false", + "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-sync-metrics_python313", + "function_version": "$LATEST", + "request_id": "XXXX", + "resource_names": "integration-tests-python-XXXX-sync-metrics_python313", + "functionname": "integration-tests-python-XXXX-sync-metrics_python313", + "datadog_lambda": "X.X.X", + "dd_trace": "X.X.X", + "span.name": "aws.lambda", + "function_trigger.event_source": "dynamodb", + "function_trigger.event_source_arn": "XXXX" + }, + "metrics": { + "_dd.top_level": 1 + }, + "type": "serverless" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://datadoghq.com/", + "out.host": "datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1 + }, + "type": "http" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.p.tid": "XXXX", + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://www.datadoghq.com/", + "out.host": "www.datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1 + }, + "type": "http" + } + ] + ] +} +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX +{ + "traces": [ + [ + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "POST /api/v1/distribution_points", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "runtime-id": "XXXX", + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "POST", + "http.url": "https://api.datadoghq.com/api/v1/distribution_points", + "out.host": "api.datadoghq.com", + "http.status_code": "202", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", + "_dd.p.dm": "-0", + "_dd.p.tid": "XXXX", + "language": "python" + }, + "metrics": { + "process_id": XXXX, + "_dd.measured": 1, + "_dd.top_level": 1, + "_sampling_priority_v1": 1 + }, + "type": "http" + } + ] + ] +} +END Duration: XXXX ms Memory Used: XXXX MB +START +{ + "m": "aws.lambda.enhanced.invocations", + "v": 1, + "e": XXXX, + "t": [ + "region:eu-west-1", + "account_id:XXXX", + "functionname:integration-tests-python-XXXX-sync-metrics_python313", + "resource:integration-tests-python-XXXX-sync-metrics_python313", + "memorysize:1024", + "cold_start:false", + "runtime:python3.13", + "datadog_lambda:vXX", + "dd_lambda_layer:datadog-python313_X.X.X" + ] +} +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +{ + "traces": [ + [ + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "eventbridge.custom.event.sender", + "resource": "eventbridge.custom.event.sender", + "name": "aws.eventbridge", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "runtime-id": "XXXX", + "_dd.origin": "lambda", + "operation_name": "aws.eventbridge", + "resource_names": "eventbridge.custom.event.sender", + "span.kind": "server", + "detail_type": "testdetail", + "_inferred_span.synchronicity": "async", + "_inferred_span.tag_source": "self", + "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", + "_dd.p.dm": "-0", + "_dd.p.tid": "XXXX", + "language": "python" + }, + "metrics": { + "process_id": XXXX, + "_dd.top_level": 1, + "_sampling_priority_v1": 1 + }, + "type": "web" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "integration-tests-python", + "resource": "integration-tests-python-XXXX-sync-metrics_python313", + "name": "aws.lambda", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "cold_start": "false", + "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-sync-metrics_python313", + "function_version": "$LATEST", + "request_id": "XXXX", + "resource_names": "integration-tests-python-XXXX-sync-metrics_python313", + "functionname": "integration-tests-python-XXXX-sync-metrics_python313", + "datadog_lambda": "X.X.X", + "dd_trace": "X.X.X", + "span.name": "aws.lambda", + "function_trigger.event_source": "eventbridge" + }, + "metrics": { + "_dd.top_level": 1 + }, + "type": "serverless" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://datadoghq.com/", + "out.host": "datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1 + }, + "type": "http" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.p.tid": "XXXX", + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://www.datadoghq.com/", + "out.host": "www.datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1 + }, + "type": "http" + } + ] + ] +} +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX +{ + "traces": [ + [ + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "POST /api/v1/distribution_points", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "runtime-id": "XXXX", + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "POST", + "http.url": "https://api.datadoghq.com/api/v1/distribution_points", + "out.host": "api.datadoghq.com", + "http.status_code": "202", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", + "_dd.p.dm": "-0", + "_dd.p.tid": "XXXX", + "language": "python" + }, + "metrics": { + "process_id": XXXX, + "_dd.measured": 1, + "_dd.top_level": 1, + "_sampling_priority_v1": 1 + }, + "type": "http" + } + ] + ] +} +END Duration: XXXX ms Memory Used: XXXX MB +START +{ + "m": "aws.lambda.enhanced.invocations", + "v": 1, + "e": XXXX, + "t": [ + "region:eu-west-1", + "account_id:XXXX", + "functionname:integration-tests-python-XXXX-sync-metrics_python313", + "resource:integration-tests-python-XXXX-sync-metrics_python313", + "memorysize:1024", + "cold_start:false", + "runtime:python3.13", + "datadog_lambda:vXX", + "dd_lambda_layer:datadog-python313_X.X.X" + ] +} +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +{ + "traces": [ + [ + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "XXXX.execute-api.eu-west-1.amazonaws.com", + "resource": "GET /httpapi/get", + "name": "aws.httpapi", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "runtime-id": "XXXX", + "_dd.origin": "lambda", + "operation_name": "aws.httpapi", + "endpoint": "/httpapi/get", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com/httpapi/get", + "http.method": "GET", + "http.protocol": "HTTP/1.1", + "http.source_ip": "XXXX", + "http.user_agent": "XXXX/7.64.1", + "resource_names": "GET /httpapi/get", + "request_id": "XXXX", + "apiid": "XXXX", + "apiname": "XXXX", + "stage": "$default", + "_inferred_span.synchronicity": "sync", + "_inferred_span.tag_source": "self", + "http.status_code": "200", + "http.route": "/httpapi/get", + "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", + "_dd.p.dm": "-0", + "_dd.p.tid": "XXXX", + "language": "python" + }, + "metrics": { + "process_id": XXXX, + "_dd.top_level": 1, + "_sampling_priority_v1": 1 + }, + "type": "http" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "integration-tests-python", + "resource": "integration-tests-python-XXXX-sync-metrics_python313", + "name": "aws.lambda", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "cold_start": "false", + "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-sync-metrics_python313", + "function_version": "$LATEST", + "request_id": "XXXX", + "resource_names": "integration-tests-python-XXXX-sync-metrics_python313", + "functionname": "integration-tests-python-XXXX-sync-metrics_python313", + "datadog_lambda": "X.X.X", + "dd_trace": "X.X.X", + "span.name": "aws.lambda", + "function_trigger.event_source": "api-gateway", + "function_trigger.event_source_arn": "XXXX$default", + "span.kind": "server", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com/httpapi/get", + "http.method": "GET", + "http.route": "/httpapi/get", + "http.status_code": "200" + }, + "metrics": { + "_dd.top_level": 1 + }, + "type": "serverless" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://datadoghq.com/", + "out.host": "datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1 + }, + "type": "http" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.p.tid": "XXXX", + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://www.datadoghq.com/", + "out.host": "www.datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1 + }, + "type": "http" + } + ] + ] +} +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX +{ + "traces": [ + [ + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "POST /api/v1/distribution_points", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "runtime-id": "XXXX", + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "POST", + "http.url": "https://api.datadoghq.com/api/v1/distribution_points", + "out.host": "api.datadoghq.com", + "http.status_code": "202", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", + "_dd.p.dm": "-0", + "_dd.p.tid": "XXXX", + "language": "python" + }, + "metrics": { + "process_id": XXXX, + "_dd.measured": 1, + "_dd.top_level": 1, + "_sampling_priority_v1": 1 + }, + "type": "http" + } + ] + ] +} +END Duration: XXXX ms Memory Used: XXXX MB +START +{ + "m": "aws.lambda.enhanced.invocations", + "v": 1, + "e": XXXX, + "t": [ + "region:eu-west-1", + "account_id:XXXX", + "functionname:integration-tests-python-XXXX-sync-metrics_python313", + "resource:integration-tests-python-XXXX-sync-metrics_python313", + "memorysize:1024", + "cold_start:false", + "runtime:python3.13", + "datadog_lambda:vXX", + "dd_lambda_layer:datadog-python313_X.X.X" + ] +} +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +{ + "traces": [ + [ + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "EXAMPLE", + "resource": "EXAMPLE", + "name": "aws.kinesis", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "runtime-id": "XXXX", + "_dd.origin": "lambda", + "operation_name": "aws.kinesis", + "resource_names": "EXAMPLE", + "span.kind": "server", + "streamname": "EXAMPLE", + "shardid": "shardId-XXXX", + "event_source_arn": "arn:aws:kinesis:EXAMPLE", + "event_id": "XXXX", + "event_name": "aws:kinesis:record", + "event_version": "1.0", + "partition_key": "XXXX", + "_inferred_span.synchronicity": "async", + "_inferred_span.tag_source": "self", + "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", + "_dd.p.dm": "-0", + "_dd.p.tid": "XXXX", + "language": "python" + }, + "metrics": { + "process_id": XXXX, + "_dd.top_level": 1, + "_sampling_priority_v1": 1 + }, + "type": "web" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "integration-tests-python", + "resource": "integration-tests-python-XXXX-sync-metrics_python313", + "name": "aws.lambda", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "cold_start": "false", + "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-sync-metrics_python313", + "function_version": "$LATEST", + "request_id": "XXXX", + "resource_names": "integration-tests-python-XXXX-sync-metrics_python313", + "functionname": "integration-tests-python-XXXX-sync-metrics_python313", + "datadog_lambda": "X.X.X", + "dd_trace": "X.X.X", + "span.name": "aws.lambda", + "function_trigger.event_source": "kinesis", + "function_trigger.event_source_arn": "XXXX" + }, + "metrics": { + "_dd.top_level": 1 + }, + "type": "serverless" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://datadoghq.com/", + "out.host": "datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1 + }, + "type": "http" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.p.tid": "XXXX", + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://www.datadoghq.com/", + "out.host": "www.datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1 + }, + "type": "http" + } + ] + ] +} +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX +{ + "traces": [ + [ + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "POST /api/v1/distribution_points", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "runtime-id": "XXXX", + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "POST", + "http.url": "https://api.datadoghq.com/api/v1/distribution_points", + "out.host": "api.datadoghq.com", + "http.status_code": "202", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", + "_dd.p.dm": "-0", + "_dd.p.tid": "XXXX", + "language": "python" + }, + "metrics": { + "process_id": XXXX, + "_dd.measured": 1, + "_dd.top_level": 1, + "_sampling_priority_v1": 1 + }, + "type": "http" + } + ] + ] +} +END Duration: XXXX ms Memory Used: XXXX MB +START +{ + "m": "aws.lambda.enhanced.invocations", + "v": 1, + "e": XXXX, + "t": [ + "region:eu-west-1", + "account_id:XXXX", + "functionname:integration-tests-python-XXXX-sync-metrics_python313", + "resource:integration-tests-python-XXXX-sync-metrics_python313", + "memorysize:1024", + "cold_start:false", + "runtime:python3.13", + "datadog_lambda:vXX", + "dd_lambda_layer:datadog-python313_X.X.X" + ] +} +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +{ + "traces": [ + [ + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "example-bucket", + "resource": "example-bucket", + "name": "aws.s3", + "error": 0, + "meta": { + "runtime-id": "XXXX", + "_dd.origin": "lambda", + "operation_name": "aws.s3", + "resource_names": "example-bucket", + "span.kind": "server", + "event_name": "ObjectCreated:Put", + "bucketname": "example-bucket", + "bucket_arn": "arn:aws:s3:::example-bucket", + "object_key": "test/key", + "object_size": "1024", + "object_etag": "XXXX", + "_inferred_span.synchronicity": "async", + "_inferred_span.tag_source": "self", + "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", + "_dd.p.dm": "-0", + "_dd.p.tid": "XXXX", + "language": "python" + }, + "metrics": { + "process_id": XXXX, + "_dd.top_level": 1, + "_sampling_priority_v1": 1 + }, + "type": "web", + "span_links": [ + { + "trace_id": "XXXX", + "span_id": "XXXX", + "attributes": { + "ptr.kind": "aws.s3.object", + "ptr.dir": "u", + "ptr.hash": "1dc3e5d00dae48c1f07d95371a747788", + "link.kind": "span-pointer" + } + } + ] + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "integration-tests-python", + "resource": "integration-tests-python-XXXX-sync-metrics_python313", + "name": "aws.lambda", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "cold_start": "false", + "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-sync-metrics_python313", + "function_version": "$LATEST", + "request_id": "XXXX", + "resource_names": "integration-tests-python-XXXX-sync-metrics_python313", + "functionname": "integration-tests-python-XXXX-sync-metrics_python313", + "datadog_lambda": "X.X.X", + "dd_trace": "X.X.X", + "span.name": "aws.lambda", + "function_trigger.event_source": "s3", + "function_trigger.event_source_arn": "XXXX" + }, + "metrics": { + "_dd.top_level": 1 + }, + "type": "serverless" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://datadoghq.com/", + "out.host": "datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1 + }, + "type": "http" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.p.tid": "XXXX", + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://www.datadoghq.com/", + "out.host": "www.datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1 + }, + "type": "http" + } + ] + ] +} +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX +{ + "traces": [ + [ + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "POST /api/v1/distribution_points", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "runtime-id": "XXXX", + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "POST", + "http.url": "https://api.datadoghq.com/api/v1/distribution_points", + "out.host": "api.datadoghq.com", + "http.status_code": "202", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", + "_dd.p.dm": "-0", + "_dd.p.tid": "XXXX", + "language": "python" + }, + "metrics": { + "process_id": XXXX, + "_dd.measured": 1, + "_dd.top_level": 1, + "_sampling_priority_v1": 1 + }, + "type": "http" + } + ] + ] +} +END Duration: XXXX ms Memory Used: XXXX MB +START +{ + "m": "aws.lambda.enhanced.invocations", + "v": 1, + "e": XXXX, + "t": [ + "region:eu-west-1", + "account_id:XXXX", + "functionname:integration-tests-python-XXXX-sync-metrics_python313", + "resource:integration-tests-python-XXXX-sync-metrics_python313", + "memorysize:1024", + "cold_start:false", + "runtime:python3.13", + "datadog_lambda:vXX", + "dd_lambda_layer:datadog-python313_X.X.X" + ] +} +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +{ + "traces": [ + [ + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "sns-lambda", + "resource": "sns-lambda", + "name": "aws.sns", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "runtime-id": "XXXX", + "_dd.origin": "lambda", + "operation_name": "aws.sns", + "resource_names": "sns-lambda", + "span.kind": "server", + "topicname": "sns-lambda", + "topic_arn": "arn:aws:sns:us-east-2:XXXX:us-east-2-lambda", + "message_id": "XXXX", + "type": "Notification", + "subject": "TestInvoke", + "_inferred_span.synchronicity": "async", + "_inferred_span.tag_source": "self", + "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", + "_dd.p.dm": "-0", + "_dd.p.tid": "XXXX", + "language": "python" + }, + "metrics": { + "process_id": XXXX, + "_dd.top_level": 1, + "_sampling_priority_v1": 1 + }, + "type": "web" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "integration-tests-python", + "resource": "integration-tests-python-XXXX-sync-metrics_python313", + "name": "aws.lambda", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "cold_start": "false", + "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-sync-metrics_python313", + "function_version": "$LATEST", + "request_id": "XXXX", + "resource_names": "integration-tests-python-XXXX-sync-metrics_python313", + "functionname": "integration-tests-python-XXXX-sync-metrics_python313", + "datadog_lambda": "X.X.X", + "dd_trace": "X.X.X", + "span.name": "aws.lambda", + "function_trigger.event_source": "sns", + "function_trigger.event_source_arn": "XXXX" + }, + "metrics": { + "_dd.top_level": 1 + }, + "type": "serverless" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://datadoghq.com/", + "out.host": "datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1 + }, + "type": "http" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.p.tid": "XXXX", + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://www.datadoghq.com/", + "out.host": "www.datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1 + }, + "type": "http" + } + ] + ] +} +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX +{ + "traces": [ + [ + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "POST /api/v1/distribution_points", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "runtime-id": "XXXX", + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "POST", + "http.url": "https://api.datadoghq.com/api/v1/distribution_points", + "out.host": "api.datadoghq.com", + "http.status_code": "202", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", + "_dd.p.dm": "-0", + "_dd.p.tid": "XXXX", + "language": "python" + }, + "metrics": { + "process_id": XXXX, + "_dd.measured": 1, + "_dd.top_level": 1, + "_sampling_priority_v1": 1 + }, + "type": "http" + } + ] + ] +} +END Duration: XXXX ms Memory Used: XXXX MB +START +{ + "m": "aws.lambda.enhanced.invocations", + "v": 1, + "e": XXXX, + "t": [ + "region:eu-west-1", + "account_id:XXXX", + "functionname:integration-tests-python-XXXX-sync-metrics_python313", + "resource:integration-tests-python-XXXX-sync-metrics_python313", + "memorysize:1024", + "cold_start:false", + "runtime:python3.13", + "datadog_lambda:vXX", + "dd_lambda_layer:datadog-python313_X.X.X" + ] +} +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +{ + "traces": [ + [ + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "my-queue", + "resource": "my-queue", + "name": "aws.sqs", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "runtime-id": "XXXX", + "_dd.origin": "lambda", + "operation_name": "aws.sqs", + "resource_names": "my-queue", + "span.kind": "server", + "queuename": "my-queue", + "event_source_arn": "arn:aws:sqs:us-east-2:XXXX:us-east-2-queue", + "receipt_handle": "AQEBwJnKyrHigUMZj6rYigCgxlaS3SLy0a...", + "sender_id": "AIDAIENQZJOLO23YVJ4VO", + "_inferred_span.synchronicity": "async", + "_inferred_span.tag_source": "self", + "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", + "_dd.p.dm": "-0", + "_dd.p.tid": "XXXX", + "language": "python" + }, + "metrics": { + "process_id": XXXX, + "_dd.top_level": 1, + "_sampling_priority_v1": 1 + }, + "type": "web" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "integration-tests-python", + "resource": "integration-tests-python-XXXX-sync-metrics_python313", + "name": "aws.lambda", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "cold_start": "false", + "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-sync-metrics_python313", + "function_version": "$LATEST", + "request_id": "XXXX", + "resource_names": "integration-tests-python-XXXX-sync-metrics_python313", + "functionname": "integration-tests-python-XXXX-sync-metrics_python313", + "datadog_lambda": "X.X.X", + "dd_trace": "X.X.X", + "span.name": "aws.lambda", + "function_trigger.event_source": "sqs", + "function_trigger.event_source_arn": "XXXX" + }, + "metrics": { + "_dd.top_level": 1 + }, + "type": "serverless" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://datadoghq.com/", + "out.host": "datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1 + }, + "type": "http" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.p.tid": "XXXX", + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://www.datadoghq.com/", + "out.host": "www.datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1 + }, + "type": "http" + } + ] + ] +} +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX +{ + "traces": [ + [ + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "POST /api/v1/distribution_points", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "runtime-id": "XXXX", + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "POST", + "http.url": "https://api.datadoghq.com/api/v1/distribution_points", + "out.host": "api.datadoghq.com", + "http.status_code": "202", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", + "_dd.p.dm": "-0", + "_dd.p.tid": "XXXX", + "language": "python" + }, + "metrics": { + "process_id": XXXX, + "_dd.measured": 1, + "_dd.top_level": 1, + "_sampling_priority_v1": 1 + }, + "type": "http" + } + ] + ] +} +END Duration: XXXX ms Memory Used: XXXX MB +START +{ + "m": "aws.lambda.enhanced.invocations", + "v": 1, + "e": XXXX, + "t": [ + "region:eu-west-1", + "account_id:XXXX", + "functionname:integration-tests-python-XXXX-sync-metrics_python313", + "resource:integration-tests-python-XXXX-sync-metrics_python313", + "memorysize:1024", + "cold_start:false", + "runtime:python3.13", + "datadog_lambda:vXX", + "dd_lambda_layer:datadog-python313_X.X.X" + ] +} +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +{ + "traces": [ + [ + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "XXXX.execute-api.eu-west-1.amazonaws.com", + "resource": "$default", + "name": "aws.apigateway.websocket", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "runtime-id": "XXXX", + "_dd.origin": "lambda", + "operation_name": "aws.apigateway.websocket", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com$default/", + "endpoint": "$default", + "resource_names": "$default", + "span.kind": "server", + "apiid": "XXXX", + "apiname": "XXXX", + "stage": "dev", + "request_id": "XXXX", + "connection_id": "XXXX=", + "event_type": "MESSAGE", + "message_direction": "IN", + "_inferred_span.synchronicity": "sync", + "_inferred_span.tag_source": "self", + "http.status_code": "200", + "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", + "_dd.p.dm": "-0", + "_dd.p.tid": "XXXX", + "language": "python" + }, + "metrics": { + "process_id": XXXX, + "_dd.top_level": 1, + "_sampling_priority_v1": 1 + }, + "type": "web" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "integration-tests-python", + "resource": "integration-tests-python-XXXX-sync-metrics_python313", + "name": "aws.lambda", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "cold_start": "false", + "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-sync-metrics_python313", + "function_version": "$LATEST", + "request_id": "XXXX", + "resource_names": "integration-tests-python-XXXX-sync-metrics_python313", + "functionname": "integration-tests-python-XXXX-sync-metrics_python313", + "datadog_lambda": "X.X.X", + "dd_trace": "X.X.X", + "span.name": "aws.lambda", + "function_trigger.event_source": "api-gateway", + "function_trigger.event_source_arn": "XXXX", + "span.kind": "server", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com/", + "http.status_code": "200" + }, + "metrics": { + "_dd.top_level": 1 + }, + "type": "serverless" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://datadoghq.com/", + "out.host": "datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1 + }, + "type": "http" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.p.tid": "XXXX", + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://www.datadoghq.com/", + "out.host": "www.datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1 + }, + "type": "http" + } + ] + ] +} +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX +{ + "traces": [ + [ + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "POST /api/v1/distribution_points", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "runtime-id": "XXXX", + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "POST", + "http.url": "https://api.datadoghq.com/api/v1/distribution_points", + "out.host": "api.datadoghq.com", + "http.status_code": "202", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", + "_dd.p.dm": "-0", + "_dd.p.tid": "XXXX", + "language": "python" + }, + "metrics": { + "process_id": XXXX, + "_dd.measured": 1, + "_dd.top_level": 1, + "_sampling_priority_v1": 1 + }, + "type": "http" + } + ] + ] +} +END Duration: XXXX ms Memory Used: XXXX MB diff --git a/tests/integration/snapshots/logs/sync-metrics_python38.log b/tests/integration/snapshots/logs/sync-metrics_python38.log index 81e776e1b..ae41bc18d 100644 --- a/tests/integration/snapshots/logs/sync-metrics_python38.log +++ b/tests/integration/snapshots/logs/sync-metrics_python38.log @@ -9,15 +9,15 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-sync-metrics_python38", "resource:integration-tests-python-XXXX-sync-metrics_python38", - "cold_start:true", "memorysize:1024", + "cold_start:true", "runtime:python3.8", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python38_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -35,10 +35,11 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "runtime-id": "XXXX", "_dd.origin": "lambda", "operation_name": "aws.apigateway.rest", - "http.url": "XXXX.execute-api.us-east-2.amazonaws.com/", + "http.url": "https://xxxx.execute-api.us-east-2.amazonaws.com/", "endpoint": "/", "http.method": "GET", "resource_names": "GET /", + "span.kind": "server", "apiid": "XXXX", "apiname": "XXXX", "stage": "Prod", @@ -46,12 +47,12 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "sync", "_inferred_span.tag_source": "self", "http.status_code": "200", + "http.route": "/", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -64,7 +65,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-sync-metrics_python38", "name": "aws.lambda", "error": 0, @@ -83,11 +84,11 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "span.name": "aws.lambda", "function_trigger.event_source": "api-gateway", "function_trigger.event_source_arn": "XXXX", - "http.url": "XXXX.execute-api.us-east-2.amazonaws.com", - "http.url_details.path": "/Prod/", + "span.kind": "server", + "http.url": "https://xxxx.execute-api.us-east-2.amazonaws.com/Prod/", "http.method": "GET", - "http.status_code": "200", - "_dd.base_service": "integration-tests-python" + "http.route": "/", + "http.status_code": "200" }, "metrics": { "_dd.top_level": 1 @@ -98,8 +99,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -124,8 +125,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -149,7 +150,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " ] ] } -HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "Content-Encoding:deflate", "Content-Length:XXXX", "Content-Type:application/json", "DD-API-KEY:XXXX", "User-Agent:datadogpy/XX (python XX; os linux; arch x86_64)", "traceparent:XXX", "tracestate:XXX +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -157,8 +158,8 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -172,7 +173,7 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "http.url": "https://api.datadoghq.com/api/v1/distribution_points", "out.host": "api.datadoghq.com", "http.status_code": "202", - "http.useragent": "datadogpy/XX (python XX; os linux; arch x86_64)", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", "language": "python" @@ -199,15 +200,171 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-sync-metrics_python38", "resource:integration-tests-python-XXXX-sync-metrics_python38", + "memorysize:1024", "cold_start:false", + "runtime:python3.8", + "datadog_lambda:vXX", + "dd_lambda_layer:datadog-python38_X.X.X" + ] +} +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +{ + "traces": [ + [ + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "integration-tests-python", + "resource": "integration-tests-python-XXXX-sync-metrics_python38", + "name": "aws.lambda", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "runtime-id": "XXXX", + "_dd.origin": "lambda", + "cold_start": "false", + "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-sync-metrics_python38", + "function_version": "$LATEST", + "request_id": "XXXX", + "resource_names": "integration-tests-python-XXXX-sync-metrics_python38", + "functionname": "integration-tests-python-XXXX-sync-metrics_python38", + "datadog_lambda": "X.X.X", + "dd_trace": "X.X.X", + "span.name": "aws.lambda", + "language": "python" + }, + "metrics": { + "process_id": XXXX, + "_dd.top_level": 1, + "_sampling_priority_v1": 1 + }, + "type": "serverless" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://datadoghq.com/", + "out.host": "datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1 + }, + "type": "http" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://www.datadoghq.com/", + "out.host": "www.datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1 + }, + "type": "http" + } + ] + ] +} +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX +{ + "traces": [ + [ + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "POST /api/v1/distribution_points", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "runtime-id": "XXXX", + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "POST", + "http.url": "https://api.datadoghq.com/api/v1/distribution_points", + "out.host": "api.datadoghq.com", + "http.status_code": "202", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", + "_dd.p.dm": "-0", + "_dd.p.tid": "XXXX", + "language": "python" + }, + "metrics": { + "process_id": XXXX, + "_dd.measured": 1, + "_dd.top_level": 1, + "_sampling_priority_v1": 1 + }, + "type": "http" + } + ] + ] +} +END Duration: XXXX ms Memory Used: XXXX MB +START +{ + "m": "aws.lambda.enhanced.invocations", + "v": 1, + "e": XXXX, + "t": [ + "region:eu-west-1", + "account_id:XXXX", + "functionname:integration-tests-python-XXXX-sync-metrics_python38", + "resource:integration-tests-python-XXXX-sync-metrics_python38", "memorysize:1024", + "cold_start:false", "runtime:python3.8", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python38_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +{ + "m": "datadog.serverless.dynamodb.stream.type", + "v": 1, + "e": XXXX, + "t": [ + "streamtype:NEW_AND_OLD_IMAGES", + "dd_lambda_layer:datadog-python38_X.X.X" + ] +} +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -215,7 +372,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "dynamodb", + "service": "ExampleTableWithStream", "resource": "ExampleTableWithStream", "name": "aws.dynamodb", "error": 0, @@ -226,6 +383,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.dynamodb", "resource_names": "ExampleTableWithStream", + "span.kind": "server", "tablename": "ExampleTableWithStream", "event_source_arn": "arn:aws:dynamodb:us-east-1:XXXX:us-east-1/ExampleTableWithStream/stream/2015-06-27T00:48:05.899", "event_id": "XXXX", @@ -236,24 +394,55 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, - "type": "web" + "type": "web", + "span_links": [ + { + "trace_id": "XXXX", + "span_id": "XXXX", + "attributes": { + "ptr.kind": "aws.dynamodb.item", + "ptr.dir": "u", + "ptr.hash": "e2af34d333891f765c7f02d2da80895e", + "link.kind": "span-pointer" + } + }, + { + "trace_id": "XXXX", + "span_id": "XXXX", + "attributes": { + "ptr.kind": "aws.dynamodb.item", + "ptr.dir": "u", + "ptr.hash": "e2af34d333891f765c7f02d2da80895e", + "link.kind": "span-pointer" + } + }, + { + "trace_id": "XXXX", + "span_id": "XXXX", + "attributes": { + "ptr.kind": "aws.dynamodb.item", + "ptr.dir": "u", + "ptr.hash": "e2af34d333891f765c7f02d2da80895e", + "link.kind": "span-pointer" + } + } + ] }, { "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-sync-metrics_python38", "name": "aws.lambda", "error": 0, @@ -271,8 +460,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "dynamodb", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -283,8 +471,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -309,8 +497,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -334,7 +522,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " ] ] } -HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "Content-Encoding:deflate", "Content-Length:XXXX", "Content-Type:application/json", "DD-API-KEY:XXXX", "User-Agent:datadogpy/XX (python XX; os linux; arch x86_64)", "traceparent:XXX", "tracestate:XXX +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -342,8 +530,8 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -357,7 +545,7 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "http.url": "https://api.datadoghq.com/api/v1/distribution_points", "out.host": "api.datadoghq.com", "http.status_code": "202", - "http.useragent": "datadogpy/XX (python XX; os linux; arch x86_64)", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", "language": "python" @@ -384,15 +572,15 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-sync-metrics_python38", "resource:integration-tests-python-XXXX-sync-metrics_python38", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.8", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python38_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -400,7 +588,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "eventbridge", + "service": "eventbridge.custom.event.sender", "resource": "eventbridge.custom.event.sender", "name": "aws.eventbridge", "error": 0, @@ -411,15 +599,15 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.eventbridge", "resource_names": "eventbridge.custom.event.sender", + "span.kind": "server", "detail_type": "testdetail", "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -432,7 +620,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-sync-metrics_python38", "name": "aws.lambda", "error": 0, @@ -449,8 +637,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "datadog_lambda": "X.X.X", "dd_trace": "X.X.X", "span.name": "aws.lambda", - "function_trigger.event_source": "eventbridge", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source": "eventbridge" }, "metrics": { "_dd.top_level": 1 @@ -461,8 +648,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -487,8 +674,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -512,7 +699,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " ] ] } -HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "Content-Encoding:deflate", "Content-Length:XXXX", "Content-Type:application/json", "DD-API-KEY:XXXX", "User-Agent:datadogpy/XX (python XX; os linux; arch x86_64)", "traceparent:XXX", "tracestate:XXX +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -520,8 +707,8 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -535,7 +722,7 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "http.url": "https://api.datadoghq.com/api/v1/distribution_points", "out.host": "api.datadoghq.com", "http.status_code": "202", - "http.useragent": "datadogpy/XX (python XX; os linux; arch x86_64)", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", "language": "python" @@ -562,15 +749,15 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-sync-metrics_python38", "resource:integration-tests-python-XXXX-sync-metrics_python38", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.8", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python38_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -589,7 +776,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.httpapi", "endpoint": "/httpapi/get", - "http.url": "XXXX.execute-api.eu-west-1.amazonaws.com/httpapi/get", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com/httpapi/get", "http.method": "GET", "http.protocol": "HTTP/1.1", "http.source_ip": "XXXX", @@ -602,12 +789,12 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "sync", "_inferred_span.tag_source": "self", "http.status_code": "200", + "http.route": "/httpapi/get", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -620,7 +807,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-sync-metrics_python38", "name": "aws.lambda", "error": 0, @@ -639,11 +826,11 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "span.name": "aws.lambda", "function_trigger.event_source": "api-gateway", "function_trigger.event_source_arn": "XXXX$default", - "http.url": "XXXX.execute-api.eu-west-1.amazonaws.com", - "http.url_details.path": "/httpapi/get", + "span.kind": "server", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com/httpapi/get", "http.method": "GET", - "http.status_code": "200", - "_dd.base_service": "integration-tests-python" + "http.route": "/httpapi/get", + "http.status_code": "200" }, "metrics": { "_dd.top_level": 1 @@ -654,8 +841,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -680,8 +867,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -705,7 +892,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " ] ] } -HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "Content-Encoding:deflate", "Content-Length:XXXX", "Content-Type:application/json", "DD-API-KEY:XXXX", "User-Agent:datadogpy/XX (python XX; os linux; arch x86_64)", "traceparent:XXX", "tracestate:XXX +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -713,8 +900,8 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -728,7 +915,7 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "http.url": "https://api.datadoghq.com/api/v1/distribution_points", "out.host": "api.datadoghq.com", "http.status_code": "202", - "http.useragent": "datadogpy/XX (python XX; os linux; arch x86_64)", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", "language": "python" @@ -755,15 +942,15 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-sync-metrics_python38", "resource:integration-tests-python-XXXX-sync-metrics_python38", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.8", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python38_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -771,7 +958,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "kinesis", + "service": "EXAMPLE", "resource": "EXAMPLE", "name": "aws.kinesis", "error": 0, @@ -782,6 +969,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.kinesis", "resource_names": "EXAMPLE", + "span.kind": "server", "streamname": "EXAMPLE", "shardid": "shardId-XXXX", "event_source_arn": "arn:aws:kinesis:EXAMPLE", @@ -792,11 +980,10 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -809,7 +996,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-sync-metrics_python38", "name": "aws.lambda", "error": 0, @@ -827,8 +1014,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "kinesis", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -839,8 +1025,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -865,8 +1051,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -890,7 +1076,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " ] ] } -HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "Content-Encoding:deflate", "Content-Length:XXXX", "Content-Type:application/json", "DD-API-KEY:XXXX", "User-Agent:datadogpy/XX (python XX; os linux; arch x86_64)", "traceparent:XXX", "tracestate:XXX +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -898,8 +1084,8 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -913,7 +1099,7 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "http.url": "https://api.datadoghq.com/api/v1/distribution_points", "out.host": "api.datadoghq.com", "http.status_code": "202", - "http.useragent": "datadogpy/XX (python XX; os linux; arch x86_64)", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", "language": "python" @@ -940,15 +1126,15 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-sync-metrics_python38", "resource:integration-tests-python-XXXX-sync-metrics_python38", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.8", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python38_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -956,7 +1142,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "s3", + "service": "example-bucket", "resource": "example-bucket", "name": "aws.s3", "error": 0, @@ -965,6 +1151,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.s3", "resource_names": "example-bucket", + "span.kind": "server", "event_name": "ObjectCreated:Put", "bucketname": "example-bucket", "bucket_arn": "arn:aws:s3:::example-bucket", @@ -974,24 +1161,35 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, - "type": "web" + "type": "web", + "span_links": [ + { + "trace_id": "XXXX", + "span_id": "XXXX", + "attributes": { + "ptr.kind": "aws.s3.object", + "ptr.dir": "u", + "ptr.hash": "1dc3e5d00dae48c1f07d95371a747788", + "link.kind": "span-pointer" + } + } + ] }, { "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-sync-metrics_python38", "name": "aws.lambda", "error": 0, @@ -1009,8 +1207,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "s3", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -1021,8 +1218,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1047,8 +1244,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1072,7 +1269,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " ] ] } -HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "Content-Encoding:deflate", "Content-Length:XXXX", "Content-Type:application/json", "DD-API-KEY:XXXX", "User-Agent:datadogpy/XX (python XX; os linux; arch x86_64)", "traceparent:XXX", "tracestate:XXX +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1080,8 +1277,8 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1095,7 +1292,7 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "http.url": "https://api.datadoghq.com/api/v1/distribution_points", "out.host": "api.datadoghq.com", "http.status_code": "202", - "http.useragent": "datadogpy/XX (python XX; os linux; arch x86_64)", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", "language": "python" @@ -1122,15 +1319,15 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-sync-metrics_python38", "resource:integration-tests-python-XXXX-sync-metrics_python38", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.8", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python38_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1138,7 +1335,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "sns", + "service": "sns-lambda", "resource": "sns-lambda", "name": "aws.sns", "error": 0, @@ -1149,6 +1346,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.sns", "resource_names": "sns-lambda", + "span.kind": "server", "topicname": "sns-lambda", "topic_arn": "arn:aws:sns:us-east-2:XXXX:us-east-2-lambda", "message_id": "XXXX", @@ -1157,11 +1355,10 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -1174,7 +1371,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-sync-metrics_python38", "name": "aws.lambda", "error": 0, @@ -1192,8 +1389,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "sns", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -1204,8 +1400,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1230,8 +1426,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1255,8 +1451,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " ] ] } -HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "Content-Encoding:deflate", "Content-Length:XXXX", "Content-Type:application/json", "DD-API-KEY:XXXX", "User-Agent:datadogpy/XX (python XX; os linux; arch x86_64)", "traceparent:XXX", "tracestate:XXX -END Duration: XXXX ms Memory Used: XXXX MB +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1264,8 +1459,8 @@ END Duration: XXXX ms Memory Used: XXXX MB "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1279,7 +1474,7 @@ END Duration: XXXX ms Memory Used: XXXX MB "http.url": "https://api.datadoghq.com/api/v1/distribution_points", "out.host": "api.datadoghq.com", "http.status_code": "202", - "http.useragent": "datadogpy/XX (python XX; os linux; arch x86_64)", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", "language": "python" @@ -1295,6 +1490,7 @@ END Duration: XXXX ms Memory Used: XXXX MB ] ] } +END Duration: XXXX ms Memory Used: XXXX MB START { "m": "aws.lambda.enhanced.invocations", @@ -1305,15 +1501,15 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-sync-metrics_python38", "resource:integration-tests-python-XXXX-sync-metrics_python38", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.8", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python38_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1321,7 +1517,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "sqs", + "service": "my-queue", "resource": "my-queue", "name": "aws.sqs", "error": 0, @@ -1332,6 +1528,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.sqs", "resource_names": "my-queue", + "span.kind": "server", "queuename": "my-queue", "event_source_arn": "arn:aws:sqs:us-east-2:XXXX:us-east-2-queue", "receipt_handle": "AQEBwJnKyrHigUMZj6rYigCgxlaS3SLy0a...", @@ -1339,11 +1536,10 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -1356,7 +1552,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-sync-metrics_python38", "name": "aws.lambda", "error": 0, @@ -1374,8 +1570,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "sqs", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -1386,8 +1581,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1412,8 +1607,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1437,7 +1632,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " ] ] } -HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "Content-Encoding:deflate", "Content-Length:XXXX", "Content-Type:application/json", "DD-API-KEY:XXXX", "User-Agent:datadogpy/XX (python XX; os linux; arch x86_64)", "traceparent:XXX", "tracestate:XXX +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1445,8 +1640,8 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1460,7 +1655,7 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "http.url": "https://api.datadoghq.com/api/v1/distribution_points", "out.host": "api.datadoghq.com", "http.status_code": "202", - "http.useragent": "datadogpy/XX (python XX; os linux; arch x86_64)", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", "language": "python" @@ -1487,15 +1682,15 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-sync-metrics_python38", "resource:integration-tests-python-XXXX-sync-metrics_python38", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.8", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python38_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1513,9 +1708,10 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "runtime-id": "XXXX", "_dd.origin": "lambda", "operation_name": "aws.apigateway.websocket", - "http.url": "XXXX.execute-api.eu-west-1.amazonaws.com$default", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com$default/", "endpoint": "$default", "resource_names": "$default", + "span.kind": "server", "apiid": "XXXX", "apiname": "XXXX", "stage": "dev", @@ -1527,11 +1723,10 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.tag_source": "self", "http.status_code": "200", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -1544,7 +1739,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-sync-metrics_python38", "name": "aws.lambda", "error": 0, @@ -1563,9 +1758,9 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "span.name": "aws.lambda", "function_trigger.event_source": "api-gateway", "function_trigger.event_source_arn": "XXXX", - "http.url": "XXXX.execute-api.eu-west-1.amazonaws.com", - "http.status_code": "200", - "_dd.base_service": "integration-tests-python" + "span.kind": "server", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com/", + "http.status_code": "200" }, "metrics": { "_dd.top_level": 1 @@ -1576,8 +1771,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1602,8 +1797,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1627,7 +1822,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " ] ] } -HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "Content-Encoding:deflate", "Content-Length:XXXX", "Content-Type:application/json", "DD-API-KEY:XXXX", "User-Agent:datadogpy/XX (python XX; os linux; arch x86_64)", "traceparent:XXX", "tracestate:XXX +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1635,8 +1830,8 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1650,7 +1845,7 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "http.url": "https://api.datadoghq.com/api/v1/distribution_points", "out.host": "api.datadoghq.com", "http.status_code": "202", - "http.useragent": "datadogpy/XX (python XX; os linux; arch x86_64)", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", "language": "python" diff --git a/tests/integration/snapshots/logs/sync-metrics_python39.log b/tests/integration/snapshots/logs/sync-metrics_python39.log index 0c7f56825..1acb7f0da 100644 --- a/tests/integration/snapshots/logs/sync-metrics_python39.log +++ b/tests/integration/snapshots/logs/sync-metrics_python39.log @@ -9,15 +9,15 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-sync-metrics_python39", "resource:integration-tests-python-XXXX-sync-metrics_python39", - "cold_start:true", "memorysize:1024", + "cold_start:true", "runtime:python3.9", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python39_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -35,10 +35,11 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "runtime-id": "XXXX", "_dd.origin": "lambda", "operation_name": "aws.apigateway.rest", - "http.url": "XXXX.execute-api.us-east-2.amazonaws.com/", + "http.url": "https://xxxx.execute-api.us-east-2.amazonaws.com/", "endpoint": "/", "http.method": "GET", "resource_names": "GET /", + "span.kind": "server", "apiid": "XXXX", "apiname": "XXXX", "stage": "Prod", @@ -46,12 +47,12 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "sync", "_inferred_span.tag_source": "self", "http.status_code": "200", + "http.route": "/", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -64,7 +65,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-sync-metrics_python39", "name": "aws.lambda", "error": 0, @@ -83,11 +84,11 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "span.name": "aws.lambda", "function_trigger.event_source": "api-gateway", "function_trigger.event_source_arn": "XXXX", - "http.url": "XXXX.execute-api.us-east-2.amazonaws.com", - "http.url_details.path": "/Prod/", + "span.kind": "server", + "http.url": "https://xxxx.execute-api.us-east-2.amazonaws.com/Prod/", "http.method": "GET", - "http.status_code": "200", - "_dd.base_service": "integration-tests-python" + "http.route": "/", + "http.status_code": "200" }, "metrics": { "_dd.top_level": 1 @@ -98,8 +99,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -124,8 +125,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -149,7 +150,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " ] ] } -HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "Content-Encoding:deflate", "Content-Length:XXXX", "Content-Type:application/json", "DD-API-KEY:XXXX", "User-Agent:datadogpy/XX (python XX; os linux; arch x86_64)", "traceparent:XXX", "tracestate:XXX +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -157,8 +158,8 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -172,7 +173,7 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "http.url": "https://api.datadoghq.com/api/v1/distribution_points", "out.host": "api.datadoghq.com", "http.status_code": "202", - "http.useragent": "datadogpy/XX (python XX; os linux; arch x86_64)", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", "language": "python" @@ -199,15 +200,171 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-sync-metrics_python39", "resource:integration-tests-python-XXXX-sync-metrics_python39", + "memorysize:1024", "cold_start:false", + "runtime:python3.9", + "datadog_lambda:vXX", + "dd_lambda_layer:datadog-python39_X.X.X" + ] +} +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +{ + "traces": [ + [ + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "integration-tests-python", + "resource": "integration-tests-python-XXXX-sync-metrics_python39", + "name": "aws.lambda", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "runtime-id": "XXXX", + "_dd.origin": "lambda", + "cold_start": "false", + "function_arn": "arn:aws:lambda:eu-west-1:XXXX:eu-west-1-tests-python-XXXX-sync-metrics_python39", + "function_version": "$LATEST", + "request_id": "XXXX", + "resource_names": "integration-tests-python-XXXX-sync-metrics_python39", + "functionname": "integration-tests-python-XXXX-sync-metrics_python39", + "datadog_lambda": "X.X.X", + "dd_trace": "X.X.X", + "span.name": "aws.lambda", + "language": "python" + }, + "metrics": { + "process_id": XXXX, + "_dd.top_level": 1, + "_sampling_priority_v1": 1 + }, + "type": "serverless" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://datadoghq.com/", + "out.host": "datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1, + "_dd.top_level": 1 + }, + "type": "http" + }, + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "GET /", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "GET", + "http.url": "https://www.datadoghq.com/", + "out.host": "www.datadoghq.com", + "http.status_code": "200", + "http.useragent": "python-requests/X.X.X" + }, + "metrics": { + "_dd.measured": 1 + }, + "type": "http" + } + ] + ] +} +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX +{ + "traces": [ + [ + { + "trace_id": "XXXX", + "parent_id": "XXXX", + "span_id": "XXXX", + "service": "requests", + "resource": "POST /api/v1/distribution_points", + "name": "requests.request", + "error": 0, + "start": "XXXX", + "duration": "XXXX", + "meta": { + "runtime-id": "XXXX", + "_dd.origin": "lambda", + "component": "requests", + "span.kind": "client", + "http.method": "POST", + "http.url": "https://api.datadoghq.com/api/v1/distribution_points", + "out.host": "api.datadoghq.com", + "http.status_code": "202", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", + "_dd.p.dm": "-0", + "_dd.p.tid": "XXXX", + "language": "python" + }, + "metrics": { + "process_id": XXXX, + "_dd.measured": 1, + "_dd.top_level": 1, + "_sampling_priority_v1": 1 + }, + "type": "http" + } + ] + ] +} +END Duration: XXXX ms Memory Used: XXXX MB +START +{ + "m": "aws.lambda.enhanced.invocations", + "v": 1, + "e": XXXX, + "t": [ + "region:eu-west-1", + "account_id:XXXX", + "functionname:integration-tests-python-XXXX-sync-metrics_python39", + "resource:integration-tests-python-XXXX-sync-metrics_python39", "memorysize:1024", + "cold_start:false", "runtime:python3.9", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python39_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +{ + "m": "datadog.serverless.dynamodb.stream.type", + "v": 1, + "e": XXXX, + "t": [ + "streamtype:NEW_AND_OLD_IMAGES", + "dd_lambda_layer:datadog-python39_X.X.X" + ] +} +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -215,7 +372,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "dynamodb", + "service": "ExampleTableWithStream", "resource": "ExampleTableWithStream", "name": "aws.dynamodb", "error": 0, @@ -226,6 +383,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.dynamodb", "resource_names": "ExampleTableWithStream", + "span.kind": "server", "tablename": "ExampleTableWithStream", "event_source_arn": "arn:aws:dynamodb:us-east-1:XXXX:us-east-1/ExampleTableWithStream/stream/2015-06-27T00:48:05.899", "event_id": "XXXX", @@ -236,24 +394,55 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, - "type": "web" + "type": "web", + "span_links": [ + { + "trace_id": "XXXX", + "span_id": "XXXX", + "attributes": { + "ptr.kind": "aws.dynamodb.item", + "ptr.dir": "u", + "ptr.hash": "e2af34d333891f765c7f02d2da80895e", + "link.kind": "span-pointer" + } + }, + { + "trace_id": "XXXX", + "span_id": "XXXX", + "attributes": { + "ptr.kind": "aws.dynamodb.item", + "ptr.dir": "u", + "ptr.hash": "e2af34d333891f765c7f02d2da80895e", + "link.kind": "span-pointer" + } + }, + { + "trace_id": "XXXX", + "span_id": "XXXX", + "attributes": { + "ptr.kind": "aws.dynamodb.item", + "ptr.dir": "u", + "ptr.hash": "e2af34d333891f765c7f02d2da80895e", + "link.kind": "span-pointer" + } + } + ] }, { "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-sync-metrics_python39", "name": "aws.lambda", "error": 0, @@ -271,8 +460,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "dynamodb", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -283,8 +471,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -309,8 +497,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -334,8 +522,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " ] ] } -HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "Content-Encoding:deflate", "Content-Length:XXXX", "Content-Type:application/json", "DD-API-KEY:XXXX", "User-Agent:datadogpy/XX (python XX; os linux; arch x86_64)", "traceparent:XXX", "tracestate:XXX -END Duration: XXXX ms Memory Used: XXXX MB +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -343,8 +530,8 @@ END Duration: XXXX ms Memory Used: XXXX MB "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -358,7 +545,7 @@ END Duration: XXXX ms Memory Used: XXXX MB "http.url": "https://api.datadoghq.com/api/v1/distribution_points", "out.host": "api.datadoghq.com", "http.status_code": "202", - "http.useragent": "datadogpy/XX (python XX; os linux; arch x86_64)", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", "language": "python" @@ -374,6 +561,7 @@ END Duration: XXXX ms Memory Used: XXXX MB ] ] } +END Duration: XXXX ms Memory Used: XXXX MB START { "m": "aws.lambda.enhanced.invocations", @@ -384,15 +572,15 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-sync-metrics_python39", "resource:integration-tests-python-XXXX-sync-metrics_python39", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.9", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python39_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -400,7 +588,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "eventbridge", + "service": "eventbridge.custom.event.sender", "resource": "eventbridge.custom.event.sender", "name": "aws.eventbridge", "error": 0, @@ -411,15 +599,15 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.eventbridge", "resource_names": "eventbridge.custom.event.sender", + "span.kind": "server", "detail_type": "testdetail", "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -432,7 +620,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-sync-metrics_python39", "name": "aws.lambda", "error": 0, @@ -449,8 +637,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "datadog_lambda": "X.X.X", "dd_trace": "X.X.X", "span.name": "aws.lambda", - "function_trigger.event_source": "eventbridge", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source": "eventbridge" }, "metrics": { "_dd.top_level": 1 @@ -461,8 +648,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -487,8 +674,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -512,7 +699,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " ] ] } -HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "Content-Encoding:deflate", "Content-Length:XXXX", "Content-Type:application/json", "DD-API-KEY:XXXX", "User-Agent:datadogpy/XX (python XX; os linux; arch x86_64)", "traceparent:XXX", "tracestate:XXX +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -520,8 +707,8 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -535,7 +722,7 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "http.url": "https://api.datadoghq.com/api/v1/distribution_points", "out.host": "api.datadoghq.com", "http.status_code": "202", - "http.useragent": "datadogpy/XX (python XX; os linux; arch x86_64)", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", "language": "python" @@ -562,15 +749,15 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-sync-metrics_python39", "resource:integration-tests-python-XXXX-sync-metrics_python39", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.9", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python39_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -589,7 +776,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.httpapi", "endpoint": "/httpapi/get", - "http.url": "XXXX.execute-api.eu-west-1.amazonaws.com/httpapi/get", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com/httpapi/get", "http.method": "GET", "http.protocol": "HTTP/1.1", "http.source_ip": "XXXX", @@ -602,12 +789,12 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "sync", "_inferred_span.tag_source": "self", "http.status_code": "200", + "http.route": "/httpapi/get", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -620,7 +807,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-sync-metrics_python39", "name": "aws.lambda", "error": 0, @@ -639,11 +826,11 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "span.name": "aws.lambda", "function_trigger.event_source": "api-gateway", "function_trigger.event_source_arn": "XXXX$default", - "http.url": "XXXX.execute-api.eu-west-1.amazonaws.com", - "http.url_details.path": "/httpapi/get", + "span.kind": "server", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com/httpapi/get", "http.method": "GET", - "http.status_code": "200", - "_dd.base_service": "integration-tests-python" + "http.route": "/httpapi/get", + "http.status_code": "200" }, "metrics": { "_dd.top_level": 1 @@ -654,8 +841,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -680,8 +867,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -705,7 +892,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " ] ] } -HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "Content-Encoding:deflate", "Content-Length:XXXX", "Content-Type:application/json", "DD-API-KEY:XXXX", "User-Agent:datadogpy/XX (python XX; os linux; arch x86_64)", "traceparent:XXX", "tracestate:XXX +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -713,8 +900,8 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -728,7 +915,7 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "http.url": "https://api.datadoghq.com/api/v1/distribution_points", "out.host": "api.datadoghq.com", "http.status_code": "202", - "http.useragent": "datadogpy/XX (python XX; os linux; arch x86_64)", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", "language": "python" @@ -755,15 +942,15 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-sync-metrics_python39", "resource:integration-tests-python-XXXX-sync-metrics_python39", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.9", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python39_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -771,7 +958,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "kinesis", + "service": "EXAMPLE", "resource": "EXAMPLE", "name": "aws.kinesis", "error": 0, @@ -782,6 +969,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.kinesis", "resource_names": "EXAMPLE", + "span.kind": "server", "streamname": "EXAMPLE", "shardid": "shardId-XXXX", "event_source_arn": "arn:aws:kinesis:EXAMPLE", @@ -792,11 +980,10 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -809,7 +996,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-sync-metrics_python39", "name": "aws.lambda", "error": 0, @@ -827,8 +1014,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "kinesis", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -839,8 +1025,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -865,8 +1051,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -890,7 +1076,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " ] ] } -HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "Content-Encoding:deflate", "Content-Length:XXXX", "Content-Type:application/json", "DD-API-KEY:XXXX", "User-Agent:datadogpy/XX (python XX; os linux; arch x86_64)", "traceparent:XXX", "tracestate:XXX +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -898,8 +1084,8 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -913,7 +1099,7 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "http.url": "https://api.datadoghq.com/api/v1/distribution_points", "out.host": "api.datadoghq.com", "http.status_code": "202", - "http.useragent": "datadogpy/XX (python XX; os linux; arch x86_64)", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", "language": "python" @@ -940,15 +1126,15 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-sync-metrics_python39", "resource:integration-tests-python-XXXX-sync-metrics_python39", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.9", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python39_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -956,7 +1142,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "s3", + "service": "example-bucket", "resource": "example-bucket", "name": "aws.s3", "error": 0, @@ -965,6 +1151,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.s3", "resource_names": "example-bucket", + "span.kind": "server", "event_name": "ObjectCreated:Put", "bucketname": "example-bucket", "bucket_arn": "arn:aws:s3:::example-bucket", @@ -974,24 +1161,35 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, - "type": "web" + "type": "web", + "span_links": [ + { + "trace_id": "XXXX", + "span_id": "XXXX", + "attributes": { + "ptr.kind": "aws.s3.object", + "ptr.dir": "u", + "ptr.hash": "1dc3e5d00dae48c1f07d95371a747788", + "link.kind": "span-pointer" + } + } + ] }, { "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-sync-metrics_python39", "name": "aws.lambda", "error": 0, @@ -1009,8 +1207,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "s3", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -1021,8 +1218,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1047,8 +1244,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1072,7 +1269,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " ] ] } -HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "Content-Encoding:deflate", "Content-Length:XXXX", "Content-Type:application/json", "DD-API-KEY:XXXX", "User-Agent:datadogpy/XX (python XX; os linux; arch x86_64)", "traceparent:XXX", "tracestate:XXX +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1080,8 +1277,8 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1095,7 +1292,7 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "http.url": "https://api.datadoghq.com/api/v1/distribution_points", "out.host": "api.datadoghq.com", "http.status_code": "202", - "http.useragent": "datadogpy/XX (python XX; os linux; arch x86_64)", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", "language": "python" @@ -1122,15 +1319,15 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-sync-metrics_python39", "resource:integration-tests-python-XXXX-sync-metrics_python39", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.9", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python39_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1138,7 +1335,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "sns", + "service": "sns-lambda", "resource": "sns-lambda", "name": "aws.sns", "error": 0, @@ -1149,6 +1346,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.sns", "resource_names": "sns-lambda", + "span.kind": "server", "topicname": "sns-lambda", "topic_arn": "arn:aws:sns:us-east-2:XXXX:us-east-2-lambda", "message_id": "XXXX", @@ -1157,11 +1355,10 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -1174,7 +1371,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-sync-metrics_python39", "name": "aws.lambda", "error": 0, @@ -1192,8 +1389,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "sns", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -1204,8 +1400,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1230,8 +1426,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1255,7 +1451,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " ] ] } -HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "Content-Encoding:deflate", "Content-Length:XXXX", "Content-Type:application/json", "DD-API-KEY:XXXX", "User-Agent:datadogpy/XX (python XX; os linux; arch x86_64)", "traceparent:XXX", "tracestate:XXX +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1263,8 +1459,8 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1278,7 +1474,7 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "http.url": "https://api.datadoghq.com/api/v1/distribution_points", "out.host": "api.datadoghq.com", "http.status_code": "202", - "http.useragent": "datadogpy/XX (python XX; os linux; arch x86_64)", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", "language": "python" @@ -1305,15 +1501,15 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-sync-metrics_python39", "resource:integration-tests-python-XXXX-sync-metrics_python39", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.9", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python39_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1321,7 +1517,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "sqs", + "service": "my-queue", "resource": "my-queue", "name": "aws.sqs", "error": 0, @@ -1332,6 +1528,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_dd.origin": "lambda", "operation_name": "aws.sqs", "resource_names": "my-queue", + "span.kind": "server", "queuename": "my-queue", "event_source_arn": "arn:aws:sqs:us-east-2:XXXX:us-east-2-queue", "receipt_handle": "AQEBwJnKyrHigUMZj6rYigCgxlaS3SLy0a...", @@ -1339,11 +1536,10 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.synchronicity": "async", "_inferred_span.tag_source": "self", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -1356,7 +1552,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-sync-metrics_python39", "name": "aws.lambda", "error": 0, @@ -1374,8 +1570,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "dd_trace": "X.X.X", "span.name": "aws.lambda", "function_trigger.event_source": "sqs", - "function_trigger.event_source_arn": "XXXX", - "_dd.base_service": "integration-tests-python" + "function_trigger.event_source_arn": "XXXX" }, "metrics": { "_dd.top_level": 1 @@ -1386,8 +1581,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1412,8 +1607,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1437,7 +1632,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " ] ] } -HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "Content-Encoding:deflate", "Content-Length:XXXX", "Content-Type:application/json", "DD-API-KEY:XXXX", "User-Agent:datadogpy/XX (python XX; os linux; arch x86_64)", "traceparent:XXX", "tracestate:XXX +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1445,8 +1640,8 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1460,7 +1655,7 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "http.url": "https://api.datadoghq.com/api/v1/distribution_points", "out.host": "api.datadoghq.com", "http.status_code": "202", - "http.useragent": "datadogpy/XX (python XX; os linux; arch x86_64)", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", "language": "python" @@ -1487,15 +1682,15 @@ START "account_id:XXXX", "functionname:integration-tests-python-XXXX-sync-metrics_python39", "resource:integration-tests-python-XXXX-sync-metrics_python39", - "cold_start:false", "memorysize:1024", + "cold_start:false", "runtime:python3.9", "datadog_lambda:vXX", "dd_lambda_layer:datadog-python39_X.X.X" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX -HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:XXX +HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX +HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","User-Agent:python-requests/X.X.X","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1513,9 +1708,10 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "runtime-id": "XXXX", "_dd.origin": "lambda", "operation_name": "aws.apigateway.websocket", - "http.url": "XXXX.execute-api.eu-west-1.amazonaws.com$default", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com$default/", "endpoint": "$default", "resource_names": "$default", + "span.kind": "server", "apiid": "XXXX", "apiname": "XXXX", "stage": "dev", @@ -1527,11 +1723,10 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_inferred_span.tag_source": "self", "http.status_code": "200", "peer.service": "integration-tests-python", + "_dd.peer.service.source": "peer.service", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", - "language": "python", - "_dd.peer.service.source": "peer.service", - "_dd.base_service": "integration-tests-python" + "language": "python" }, "metrics": { "process_id": XXXX, @@ -1544,7 +1739,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", + "service": "integration-tests-python", "resource": "integration-tests-python-XXXX-sync-metrics_python39", "name": "aws.lambda", "error": 0, @@ -1563,9 +1758,9 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "span.name": "aws.lambda", "function_trigger.event_source": "api-gateway", "function_trigger.event_source_arn": "XXXX", - "http.url": "XXXX.execute-api.eu-west-1.amazonaws.com", - "http.status_code": "200", - "_dd.base_service": "integration-tests-python" + "span.kind": "server", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com/", + "http.status_code": "200" }, "metrics": { "_dd.top_level": 1 @@ -1576,8 +1771,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1602,8 +1797,8 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1627,7 +1822,7 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " ] ] } -HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "Content-Encoding:deflate", "Content-Length:XXXX", "Content-Type:application/json", "DD-API-KEY:XXXX", "User-Agent:datadogpy/XX (python XX; os linux; arch x86_64)", "traceparent:XXX", "tracestate:XXX +HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept-Encoding:gzip, deflate","Accept:*/*","Connection:keep-alive","Content-Encoding:deflate","Content-Length:XXXX","Content-Type:application/json","DD-API-KEY:XXXX","User-Agent:datadogpy/XX (python XX; os linux; arch XXXX)","traceparent:XXX","tracestate:XXX { "traces": [ [ @@ -1635,8 +1830,8 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "integration-tests-python", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1650,7 +1845,7 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "http.url": "https://api.datadoghq.com/api/v1/distribution_points", "out.host": "api.datadoghq.com", "http.status_code": "202", - "http.useragent": "datadogpy/XX (python XX; os linux; arch x86_64)", + "http.useragent": "datadogpy/XX (python XX; os linux; arch XXXX)", "_dd.p.dm": "-0", "_dd.p.tid": "XXXX", "language": "python" diff --git a/tests/integration/snapshots/return_values/async-metrics_appsync.json b/tests/integration/snapshots/return_values/async-metrics_appsync.json new file mode 100644 index 000000000..1ad668ecc --- /dev/null +++ b/tests/integration/snapshots/return_values/async-metrics_appsync.json @@ -0,0 +1,8 @@ +{ + "statusCode": 200, + "body": { + "message": "hello, dog!", + "request_id": null, + "event_record_ids": [] + } +} diff --git a/tests/integration/snapshots/return_values/sync-metrics_appsync.json b/tests/integration/snapshots/return_values/sync-metrics_appsync.json new file mode 100644 index 000000000..1ad668ecc --- /dev/null +++ b/tests/integration/snapshots/return_values/sync-metrics_appsync.json @@ -0,0 +1,8 @@ +{ + "statusCode": 200, + "body": { + "message": "hello, dog!", + "request_id": null, + "event_record_ids": [] + } +} diff --git a/tests/integration/yarn.lock b/tests/integration/yarn.lock index 867a90abe..7477e8dae 100644 --- a/tests/integration/yarn.lock +++ b/tests/integration/yarn.lock @@ -2,7 +2,679 @@ # yarn lockfile v1 +"@iarna/toml@^2.2.5": + version "2.2.5" + resolved "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz" + integrity sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg== + +"2-thenable@^1.0.0": + version "1.0.0" + resolved "https://registry.npmjs.org/2-thenable/-/2-thenable-1.0.0.tgz" + integrity sha512-HqiDzaLDFCXkcCO/SwoyhRwqYtINFHF7t9BDRq4x90TOKNAJpiqUt9X5lQ08bwxYzc067HUywDjGySpebHcUpw== + dependencies: + d "1" + es5-ext "^0.10.47" + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^4.0.0: + version "4.3.0" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +appdirectory@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/appdirectory/-/appdirectory-0.1.0.tgz" + integrity sha512-DJ5DV8vZXBbusyiyPlH28xppwS8eAMRuuyMo88xeEcf4bV64lbLtbxRxqixZuJBXsZzLtXFmA13GwVjJc7vdQw== + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +bluebird@^3.7.2: + version "3.7.2" + resolved "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz" + integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== + +brace-expansion@^1.1.7: + version "1.1.12" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz" + integrity sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +camelcase@^5.0.0: + version "5.3.1" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +child-process-ext@^2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/child-process-ext/-/child-process-ext-2.1.1.tgz" + integrity sha512-0UQ55f51JBkOFa+fvR76ywRzxiPwQS3Xe8oe5bZRphpv+dIMeerW5Zn5e4cUy4COJwVtJyU0R79RMnw+aCqmGA== + dependencies: + cross-spawn "^6.0.5" + es5-ext "^0.10.53" + log "^6.0.0" + split2 "^3.1.1" + stream-promise "^3.2.0" + +cliui@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz" + integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^6.2.0" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + +cross-spawn@^6.0.5: + version "6.0.6" + resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz" + integrity sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw== + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + +d@^1.0.1, d@^1.0.2, d@1: + version "1.0.2" + resolved "https://registry.npmjs.org/d/-/d-1.0.2.tgz" + integrity sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw== + dependencies: + es5-ext "^0.10.64" + type "^2.7.2" + +decamelize@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz" + integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== + +duration@^0.2.2: + version "0.2.2" + resolved "https://registry.npmjs.org/duration/-/duration-0.2.2.tgz" + integrity sha512-06kgtea+bGreF5eKYgI/36A6pLXggY7oR4p1pq4SmdFBn1ReOL5D8RhG64VrqfTTKNucqqtBAwEj8aB88mcqrg== + dependencies: + d "1" + es5-ext "~0.10.46" + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +es5-ext@^0.10.35, es5-ext@^0.10.47, es5-ext@^0.10.49, es5-ext@^0.10.53, es5-ext@^0.10.62, es5-ext@^0.10.64, es5-ext@~0.10.14, es5-ext@~0.10.46: + version "0.10.64" + resolved "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz" + integrity sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg== + dependencies: + es6-iterator "^2.0.3" + es6-symbol "^3.1.3" + esniff "^2.0.1" + next-tick "^1.1.0" + +es6-iterator@^2.0.3: + version "2.0.3" + resolved "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz" + integrity sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g== + dependencies: + d "1" + es5-ext "^0.10.35" + es6-symbol "^3.1.1" + +es6-symbol@^3.1.1, es6-symbol@^3.1.3: + version "3.1.4" + resolved "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz" + integrity sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg== + dependencies: + d "^1.0.2" + ext "^1.7.0" + +esniff@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz" + integrity sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg== + dependencies: + d "^1.0.1" + es5-ext "^0.10.62" + event-emitter "^0.3.5" + type "^2.7.2" + +event-emitter@^0.3.5: + version "0.3.5" + resolved "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz" + integrity sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA== + dependencies: + d "1" + es5-ext "~0.10.14" + +ext@^1.7.0: + version "1.7.0" + resolved "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz" + integrity sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw== + dependencies: + type "^2.7.2" + +find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +fs-extra@^10.1.0: + version "10.1.0" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz" + integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +get-caller-file@^2.0.1: + version "2.0.5" + resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +glob-all@^3.3.1: + version "3.3.1" + resolved "https://registry.npmjs.org/glob-all/-/glob-all-3.3.1.tgz" + integrity sha512-Y+ESjdI7ZgMwfzanHZYQ87C59jOO0i+Hd+QYtVt9PhLi6d8wlOpzQnfBxWUlaTuAoR3TkybLqqbIoWveU4Ji7Q== + dependencies: + glob "^7.2.3" + yargs "^15.3.1" + +glob@^7.1.3, glob@^7.2.3: + version "7.2.3" + resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +graceful-fs@^4.1.6, graceful-fs@^4.2.0: + version "4.2.11" + resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +immediate@~3.0.5: + version "3.0.6" + resolved "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz" + integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@^2.0.3, inherits@~2.0.3, inherits@2: + version "2.0.4" + resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +is-docker@^2.0.0: + version "2.2.1" + resolved "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz" + integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +is-primitive@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/is-primitive/-/is-primitive-3.0.1.tgz" + integrity sha512-GljRxhWvlCNRfZyORiH77FwdFwGcMO620o37EOYC0ORWdq+WYNVqW0w2Juzew4M+L81l6/QS3t5gkkihyRqv9w== + +is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz" + integrity sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ== + +is-wsl@^2.2.0: + version "2.2.0" + resolved "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz" + integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== + dependencies: + is-docker "^2.0.0" + +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" + integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz" + integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== + +jsonfile@^6.0.1: + version "6.1.0" + resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz" + integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== + dependencies: + universalify "^2.0.0" + optionalDependencies: + graceful-fs "^4.1.6" + +jszip@^3.10.1: + version "3.10.1" + resolved "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz" + integrity sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g== + dependencies: + lie "~3.3.0" + pako "~1.0.2" + readable-stream "~2.3.6" + setimmediate "^1.0.5" + +lie@~3.3.0: + version "3.3.0" + resolved "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz" + integrity sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ== + dependencies: + immediate "~3.0.5" + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +lodash.get@^4.4.2: + version "4.4.2" + resolved "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz" + integrity sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ== + +lodash.uniqby@^4.7.0: + version "4.7.0" + resolved "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz" + integrity sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww== + +lodash.values@^4.3.0: + version "4.3.0" + resolved "https://registry.npmjs.org/lodash.values/-/lodash.values-4.3.0.tgz" + integrity sha512-r0RwvdCv8id9TUblb/O7rYPwVy6lerCbcawrfdo9iC/1t1wsNMJknO79WNBgwkH0hIeJ08jmvvESbFpNb4jH0Q== + +log@^6.0.0: + version "6.3.2" + resolved "https://registry.npmjs.org/log/-/log-6.3.2.tgz" + integrity sha512-ek8NRg/OPvS9ISOJNWNAz5vZcpYacWNFDWNJjj5OXsc6YuKacfey6wF04cXz/tOJIVrZ2nGSkHpAY5qKtF6ISg== + dependencies: + d "^1.0.2" + duration "^0.2.2" + es5-ext "^0.10.64" + event-emitter "^0.3.5" + sprintf-kit "^2.0.2" + type "^2.7.3" + uni-global "^1.0.0" + +minimatch@^3.1.1: + version "3.1.2" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +next-tick@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz" + integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ== + +nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz" + integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +pako@~1.0.2: + version "1.0.11" + resolved "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz" + integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz" + integrity sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw== + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +readable-stream@^3.0.0: + version "3.6.2" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readable-stream@~2.3.6: + version "2.3.8" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz" + integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +require-main-filename@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz" + integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== + +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +semver@^5.5.0: + version "5.7.2" + resolved "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz" + integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== + +semver@^7.6.0: + version "7.6.3" + resolved "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz" + integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== + serverless-plugin-datadog@^2.18.0: version "2.18.0" - resolved "https://registry.yarnpkg.com/serverless-plugin-datadog/-/serverless-plugin-datadog-2.18.0.tgz#8af9903f0867eaac4789c3908e100f4c0e11c578" + resolved "https://registry.npmjs.org/serverless-plugin-datadog/-/serverless-plugin-datadog-2.18.0.tgz" integrity sha512-RUdCNjUk+uUKQYgQBjK0WNeYJ7lM2/RScqg/LjVSfv5EACeJ3iIUPz1c4bS2jtiH05al8qXudNb6QDkv9zxG7w== + +serverless-python-requirements@^6.1.2: + version "6.1.2" + resolved "https://registry.npmjs.org/serverless-python-requirements/-/serverless-python-requirements-6.1.2.tgz" + integrity sha512-pas27CBxxaLTU5XMYnCVPJc+LVdm65Ys5olNvRWRqfUaZwTfD/7KSSt2XPSRme8BeJubroslaiOtWPP+IrxTVA== + dependencies: + "@iarna/toml" "^2.2.5" + appdirectory "^0.1.0" + bluebird "^3.7.2" + child-process-ext "^2.1.1" + fs-extra "^10.1.0" + glob-all "^3.3.1" + is-wsl "^2.2.0" + jszip "^3.10.1" + lodash.get "^4.4.2" + lodash.uniqby "^4.7.0" + lodash.values "^4.3.0" + rimraf "^3.0.2" + semver "^7.6.0" + set-value "^4.1.0" + sha256-file "1.0.0" + shell-quote "^1.8.1" + +set-blocking@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz" + integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== + +set-value@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/set-value/-/set-value-4.1.0.tgz" + integrity sha512-zTEg4HL0RwVrqcWs3ztF+x1vkxfm0lP+MQQFPiMJTKVceBwEV0A569Ou8l9IYQG8jOZdMVI1hGsc0tmeD2o/Lw== + dependencies: + is-plain-object "^2.0.4" + is-primitive "^3.0.1" + +setimmediate@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz" + integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== + +sha256-file@1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/sha256-file/-/sha256-file-1.0.0.tgz" + integrity sha512-nqf+g0veqgQAkDx0U2y2Tn2KWyADuuludZTw9A7J3D+61rKlIIl9V5TS4mfnwKuXZOH9B7fQyjYJ9pKRHIsAyg== + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz" + integrity sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg== + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz" + integrity sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ== + +shell-quote@^1.8.1: + version "1.8.2" + resolved "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz" + integrity sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA== + +split2@^3.1.1: + version "3.2.2" + resolved "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz" + integrity sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg== + dependencies: + readable-stream "^3.0.0" + +sprintf-kit@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/sprintf-kit/-/sprintf-kit-2.0.2.tgz" + integrity sha512-lnapdj6W4LflHZGKvl9eVkz5YF0xaTrqpRWVA4cNVOTedwqifIP8ooGImldzT/4IAN5KXFQAyXTdLidYVQdyag== + dependencies: + es5-ext "^0.10.64" + +stream-promise@^3.2.0: + version "3.2.0" + resolved "https://registry.npmjs.org/stream-promise/-/stream-promise-3.2.0.tgz" + integrity sha512-P+7muTGs2C8yRcgJw/PPt61q7O517tDHiwYEzMWo1GSBCcZedUMT/clz7vUNsSxFphIlJ6QUL4GexQKlfJoVtA== + dependencies: + "2-thenable" "^1.0.0" + es5-ext "^0.10.49" + is-stream "^1.1.0" + +string_decoder@^1.1.1, string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +string-width@^4.1.0, string-width@^4.2.0: + version "4.2.3" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +type@^2.5.0, type@^2.7.2, type@^2.7.3: + version "2.7.3" + resolved "https://registry.npmjs.org/type/-/type-2.7.3.tgz" + integrity sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ== + +uni-global@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/uni-global/-/uni-global-1.0.0.tgz" + integrity sha512-WWM3HP+siTxzIWPNUg7hZ4XO8clKi6NoCAJJWnuRL+BAqyFXF8gC03WNyTefGoUXYc47uYgXxpKLIEvo65PEHw== + dependencies: + type "^2.5.0" + +universalify@^2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz" + integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw== + +util-deprecate@^1.0.1, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +which-module@^2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz" + integrity sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ== + +which@^1.2.9: + version "1.3.1" + resolved "https://registry.npmjs.org/which/-/which-1.3.1.tgz" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +wrap-ansi@^6.2.0: + version "6.2.0" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz" + integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +y18n@^4.0.0: + version "4.0.3" + resolved "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz" + integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== + +yargs-parser@^18.1.2: + version "18.1.3" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz" + integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs@^15.3.1: + version "15.4.1" + resolved "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz" + integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A== + dependencies: + cliui "^6.0.0" + decamelize "^1.2.0" + find-up "^4.1.0" + get-caller-file "^2.0.1" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^4.2.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^18.1.2" diff --git a/tests/test_api.py b/tests/test_api.py new file mode 100644 index 000000000..7fcc3c221 --- /dev/null +++ b/tests/test_api.py @@ -0,0 +1,143 @@ +import os +import unittest +from unittest.mock import MagicMock, patch + +import datadog_lambda.api as api + + +class TestDatadogLambdaAPI(unittest.TestCase): + def setUp(self): + api.api_key = None + self.env_patcher = patch.dict( + os.environ, + { + "DD_API_KEY_SECRET_ARN": "", + "DD_API_KEY_SSM_NAME": "", + "DD_KMS_API_KEY": "", + "DD_API_KEY": "", + "DATADOG_API_KEY": "", + "AWS_REGION": "", + }, + clear=True, + ) + self.env_patcher.start() + + def tearDown(self): + del os.environ["AWS_REGION"] + + @patch("datadog_lambda.config.Config.fips_mode_enabled", True) + @patch("botocore.session.Session.create_client") + def test_secrets_manager_fips_endpoint(self, mock_boto3_client): + mock_client = MagicMock() + mock_client.get_secret_value.return_value = {"SecretString": "test-api-key"} + mock_boto3_client.return_value = mock_client + + os.environ["AWS_REGION"] = "us-gov-east-1" + os.environ[ + "DD_API_KEY_SECRET_ARN" + ] = "arn:aws:secretsmanager:us-gov-east-1:1234567890:secret:key-name-123ABC" + + api_key = api.get_api_key() + + mock_boto3_client.assert_called_with( + "secretsmanager", + endpoint_url="https://secretsmanager-fips.us-gov-east-1.amazonaws.com/", + region_name="us-gov-east-1", + ) + self.assertEqual(api_key, "test-api-key") + + @patch("botocore.session.Session.create_client") + def test_secrets_manager_different_region(self, mock_boto3_client): + mock_client = MagicMock() + mock_client.get_secret_value.return_value = {"SecretString": "test-api-key"} + mock_boto3_client.return_value = mock_client + + os.environ["AWS_REGION"] = "us-east-1" + os.environ[ + "DD_API_KEY_SECRET_ARN" + ] = "arn:aws:secretsmanager:us-west-1:1234567890:secret:key-name-123ABC" + + api_key = api.get_api_key() + + mock_boto3_client.assert_called_with( + "secretsmanager", + endpoint_url=None, + region_name="us-west-1", + ) + self.assertEqual(api_key, "test-api-key") + + @patch("datadog_lambda.config.Config.fips_mode_enabled", True) + @patch("botocore.session.Session.create_client") + def test_secrets_manager_different_region_but_still_fips(self, mock_boto3_client): + mock_client = MagicMock() + mock_client.get_secret_value.return_value = {"SecretString": "test-api-key"} + mock_boto3_client.return_value = mock_client + + os.environ["AWS_REGION"] = "us-east-1" + os.environ[ + "DD_API_KEY_SECRET_ARN" + ] = "arn:aws:secretsmanager:us-west-1:1234567890:secret:key-name-123ABC" + + api_key = api.get_api_key() + + mock_boto3_client.assert_called_with( + "secretsmanager", + endpoint_url="https://secretsmanager-fips.us-west-1.amazonaws.com/", + region_name="us-west-1", + ) + self.assertEqual(api_key, "test-api-key") + + @patch("datadog_lambda.config.Config.fips_mode_enabled", True) + @patch("botocore.session.Session.create_client") + def test_ssm_fips_endpoint(self, mock_boto3_client): + mock_client = MagicMock() + mock_client.get_parameter.return_value = { + "Parameter": {"Value": "test-api-key"} + } + mock_boto3_client.return_value = mock_client + + os.environ["AWS_REGION"] = "us-gov-west-1" + os.environ["DD_API_KEY_SSM_NAME"] = "test-ssm-param" + + api_key = api.get_api_key() + + mock_boto3_client.assert_called_with( + "ssm", endpoint_url="https://ssm-fips.us-gov-west-1.amazonaws.com/" + ) + self.assertEqual(api_key, "test-api-key") + + @patch("datadog_lambda.config.Config.fips_mode_enabled", True) + @patch("botocore.session.Session.create_client") + @patch("datadog_lambda.api.decrypt_kms_api_key") + def test_kms_fips_endpoint(self, mock_decrypt_kms, mock_boto3_client): + mock_client = MagicMock() + mock_boto3_client.return_value = mock_client + mock_decrypt_kms.return_value = "test-api-key" + + os.environ["AWS_REGION"] = "us-gov-west-1" + os.environ["DD_KMS_API_KEY"] = "encrypted-api-key" + + api_key = api.get_api_key() + + mock_boto3_client.assert_called_with( + "kms", endpoint_url="https://kms-fips.us-gov-west-1.amazonaws.com/" + ) + self.assertEqual(api_key, "test-api-key") + + @patch("botocore.session.Session.create_client") + def test_no_fips_for_standard_regions(self, mock_boto3_client): + mock_client = MagicMock() + mock_client.get_secret_value.return_value = {"SecretString": "test-api-key"} + mock_boto3_client.return_value = mock_client + + os.environ.clear() + os.environ["AWS_REGION"] = "us-west-2" + os.environ[ + "DD_API_KEY_SECRET_ARN" + ] = "arn:aws:secretsmanager:us-west-2:1234567890:secret:key-name-123ABC" + + api.get_api_key() + + mock_boto3_client.assert_called_with( + "secretsmanager", endpoint_url=None, region_name="us-west-2" + ) diff --git a/tests/test_asm.py b/tests/test_asm.py new file mode 100644 index 000000000..3aab8dd73 --- /dev/null +++ b/tests/test_asm.py @@ -0,0 +1,429 @@ +import json +import pytest +from unittest.mock import MagicMock, patch + +from datadog_lambda.asm import ( + asm_start_request, + asm_start_response, + get_asm_blocked_response, +) +from datadog_lambda.trigger import ( + EventSubtypes, + EventTypes, + _EventSource, + extract_trigger_tags, + parse_event_source, +) +from tests.utils import get_mock_context + +event_samples = "tests/event_samples/" + + +# Test cases for ASM start request +ASM_START_REQUEST_TEST_CASES = [ + ( + "application_load_balancer", + "application-load-balancer.json", + "72.12.164.125", + "/lambda?query=1234ABCD", + "GET", + "", + False, + {"query": "1234ABCD"}, + None, + None, + ), + ( + "application_load_balancer_multivalue_headers", + "application-load-balancer-multivalue-headers.json", + "72.12.164.125", + "/lambda?query=1234ABCD", + "GET", + "", + False, + {"query": "1234ABCD"}, + None, + None, + ), + ( + "lambda_function_url", + "lambda-url.json", + "71.195.30.42", + "/", + "GET", + None, + False, + None, + None, + None, + ), + ( + "api_gateway", + "api-gateway.json", + "127.0.0.1", + "/path/to/resource?foo=bar", + "POST", + "eyJ0ZXN0IjoiYm9keSJ9", + True, + {"foo": ["bar"]}, + {"proxy": "/path/to/resource"}, + "/{proxy+}", + ), + ( + "api_gateway_v2_parametrized", + "api-gateway-v2-parametrized.json", + "76.115.124.192", + "/user/42", + "GET", + None, + False, + None, + {"id": "42"}, + "/user/{id}", + ), + ( + "api_gateway_websocket", + "api-gateway-websocket-default.json", + "38.122.226.210", + None, + None, + '"What\'s good in the hood?"', + False, + None, + None, + None, + ), +] + + +# Test cases for ASM start response +ASM_START_RESPONSE_TEST_CASES = [ + ( + "application_load_balancer", + "application-load-balancer.json", + { + "statusCode": 200, + "headers": {"Content-Type": "text/html"}, + }, + "200", + {"Content-Type": "text/html"}, + None, + True, + ), + ( + "application_load_balancer_multivalue_headers", + "application-load-balancer-multivalue-headers.json", + { + "statusCode": 404, + "multiValueHeaders": { + "Content-Type": ["text/plain"], + "X-Error": ["Not Found"], + }, + }, + "404", + { + "Content-Type": "text/plain", + "X-Error": "Not Found", + }, + None, + True, + ), + ( + "lambda_function_url", + "lambda-url.json", + { + "statusCode": 201, + "headers": { + "Location": "/user/123", + "Content-Type": "application/json", + }, + }, + "201", + { + "Location": "/user/123", + "Content-Type": "application/json", + }, + None, + True, + ), + ( + "api_gateway", + "api-gateway.json", + { + "statusCode": 200, + "headers": { + "Content-Type": "application/json", + "X-Custom-Header": "test-value", + }, + "body": '{"message": "success"}', + }, + "200", + { + "Content-Type": "application/json", + "X-Custom-Header": "test-value", + }, + '{"message": "success"}', + True, + ), + ( + "api_gateway_v2_parametrized", + "api-gateway-v2-parametrized.json", + { + "statusCode": 200, + "headers": {"Content-Type": "application/json"}, + }, + "200", + {"Content-Type": "application/json"}, + None, + True, + ), + ( + "api_gateway_websocket", + "api-gateway-websocket-default.json", + { + "statusCode": 200, + "headers": {"Content-Type": "text/plain"}, + }, + "200", + {"Content-Type": "text/plain"}, + None, + True, + ), + ( + "non_http_event_s3", + "s3.json", + {"statusCode": 200}, + "200", + {}, + None, + False, # Should not dispatch for non-HTTP events + ), + ( + "api_gateway_v2_string_response", + "api-gateway-v2-parametrized.json", + "Hello, World!", + "200", + {"content-type": "application/json"}, + "Hello, World!", + True, + ), + ( + "api_gateway_v2_dict_response", + "api-gateway-v2-parametrized.json", + {"message": "Hello, World!"}, + "200", + {"content-type": "application/json"}, + {"message": "Hello, World!"}, + True, + ), +] + +ASM_BLOCKED_RESPONSE_TEST_CASES = [ + # JSON blocking response + ( + {"status_code": 403, "type": "auto", "content-type": "application/json"}, + 403, + {"content-type": "application/json"}, + ), + # HTML blocking response + ( + { + "status_code": 401, + "type": "html", + "content-type": "text/html", + }, + 401, + {"content-type": "text/html"}, + ), + # Plain text redirect response + ( + {"status_code": 301, "type": "none", "location": "https://example.com/blocked"}, + 301, + { + "content-type": "text/plain; charset=utf-8", + "location": "https://example.com/blocked", + }, + ), + # Default to content-type application/json and status code 403 when not provided + ( + {"type": "auto"}, + 403, + {"content-type": "application/json"}, + ), +] + + +@pytest.mark.parametrize( + "name,file,expected_ip,expected_uri,expected_method,expected_body,expected_base64,expected_query,expected_path_params,expected_route", + ASM_START_REQUEST_TEST_CASES, +) +@patch("datadog_lambda.asm.core") +def test_asm_start_request_parametrized( + mock_core, + name, + file, + expected_ip, + expected_uri, + expected_method, + expected_body, + expected_base64, + expected_query, + expected_path_params, + expected_route, +): + """Test ASM start request for various HTTP event types using parametrization""" + mock_span = MagicMock() + ctx = get_mock_context() + + # Reset mock for each test + mock_core.reset_mock() + mock_span.reset_mock() + + test_file = event_samples + file + with open(test_file, "r") as f: + event = json.load(f) + + event_source = parse_event_source(event) + trigger_tags = extract_trigger_tags(event, ctx) + + asm_start_request(mock_span, event, event_source, trigger_tags) + + # Verify core.dispatch was called + mock_core.dispatch.assert_called_once() + call_args = mock_core.dispatch.call_args + dispatch_args = call_args[0][1] + ( + span, + request_headers, + request_ip, + body, + is_base64_encoded, + raw_uri, + http_route, + http_method, + parsed_query, + request_path_parameters, + ) = dispatch_args + + # Common assertions + assert span == mock_span + assert isinstance(request_headers, dict) + + # Specific assertions based on test case + assert request_ip == expected_ip + assert raw_uri == expected_uri + assert http_method == expected_method + assert body == expected_body + assert is_base64_encoded == expected_base64 + + if expected_query is not None: + assert parsed_query == expected_query + else: + assert parsed_query is None + + if expected_path_params is not None: + assert request_path_parameters == expected_path_params + else: + assert request_path_parameters is None + + # Check route is correctly extracted and passed + assert http_route == expected_route + + # Check IP tags were set if IP is present + if expected_ip: + mock_span.set_tag.assert_any_call("http.client_ip", expected_ip) + mock_span.set_tag.assert_any_call("network.client.ip", expected_ip) + + +@pytest.mark.parametrize( + "name,event_file,response,status_code,expected_headers,expected_body,should_dispatch", + ASM_START_RESPONSE_TEST_CASES, +) +@patch("datadog_lambda.asm.core") +def test_asm_start_response_parametrized( + mock_core, + name, + event_file, + response, + status_code, + expected_headers, + expected_body, + should_dispatch, +): + """Test ASM start response for various HTTP event types using parametrization""" + mock_span = MagicMock() + + # Reset mock for each test + mock_core.reset_mock() + mock_span.reset_mock() + + test_file = event_samples + event_file + with open(test_file, "r") as f: + event = json.load(f) + + event_source = parse_event_source(event) + + asm_start_response(mock_span, status_code, event_source, response) + + if should_dispatch: + assert mock_core.dispatch.call_count == 2 + + assert mock_core.dispatch.call_args_list[0].args == ( + "aws_lambda.start_response", + (mock_span, status_code, expected_headers), + ) + + assert mock_core.dispatch.call_args_list[1].args == ( + "aws_lambda.parse_body", + (expected_body,), + ) + else: + # Verify core.dispatch was not called for non-HTTP events + mock_core.dispatch.assert_not_called() + + +@pytest.mark.parametrize( + "blocked_config, expected_status, expected_headers", + ASM_BLOCKED_RESPONSE_TEST_CASES, +) +@patch("datadog_lambda.asm.get_blocked") +def test_get_asm_blocked_response_blocked( + mock_get_blocked, + blocked_config, + expected_status, + expected_headers, +): + mock_get_blocked.return_value = blocked_config + event_source = _EventSource(event_type=EventTypes.API_GATEWAY) + response = get_asm_blocked_response(event_source) + assert response["statusCode"] == expected_status + assert response["headers"] == expected_headers + assert "multiValueHeaders" not in response + + +@patch("datadog_lambda.asm.get_blocked") +def test_get_asm_blocked_response_blocked_multi_value_headers( + mock_get_blocked, +): + # HTML blocking response + mock_get_blocked.return_value = { + "status_code": 401, + "type": "html", + "content-type": "text/html", + } + + event_source = _EventSource(EventTypes.ALB, EventSubtypes.ALB_MULTI_VALUE_HEADERS) + response = get_asm_blocked_response(event_source) + assert response["statusCode"] == 401 + assert response["multiValueHeaders"] == {"content-type": ["text/html"]} + assert "headers" not in response + + +@patch("datadog_lambda.asm.get_blocked") +def test_get_asm_blocked_response_not_blocked( + mock_get_blocked, +): + mock_get_blocked.return_value = None + event_source = _EventSource(event_type=EventTypes.API_GATEWAY) + response = get_asm_blocked_response(event_source) + assert response is None diff --git a/tests/test_benchmarks.py b/tests/test_benchmarks.py new file mode 100644 index 000000000..48598cb37 --- /dev/null +++ b/tests/test_benchmarks.py @@ -0,0 +1,97 @@ +import builtins +import json +import os +import pytest + +import ddtrace + +from datadog_lambda import metric +from datadog_lambda import tag_object +from datadog_lambda import tracing +from datadog_lambda import trigger +from datadog_lambda import xray + +from datadog_lambda.constants import XrayDaemon, XraySubsegment + +from tests.utils import get_mock_context, reset_xray_connection + + +event_samples_dir = "tests/event_samples" +event_samples = [f[:-5] for f in os.listdir(event_samples_dir) if f.endswith(".json")] + + +def test_metric_write_metric_point_to_stdout(benchmark, monkeypatch): + monkeypatch.setattr(builtins, "print", lambda *a, **k: None) + benchmark( + metric.write_metric_point_to_stdout, + "metric_name", + 1, + tags=[ + "tag1:value1", + "tag2:value2", + "tag3:value3", + ], + ) + + +@pytest.mark.parametrize("event", event_samples) +def test_tag_object_tag_object(event, benchmark): + with open(f"{event_samples_dir}/{event}.json") as f: + event = json.load(f) + span = ddtrace.trace.tracer.start_span("test") + benchmark(tag_object.tag_object, span, "function.request", event) + + +@pytest.mark.parametrize("event", event_samples) +def test_tracing_create_inferred_span(event, benchmark): + with open(f"{event_samples_dir}/{event}.json") as f: + event = json.load(f) + context = get_mock_context() + benchmark(tracing.create_inferred_span, event, context) + + +@pytest.mark.parametrize("event", event_samples) +def test_tracing_extract_dd_trace_context(event, benchmark): + with open(f"{event_samples_dir}/{event}.json") as f: + event = json.load(f) + context = get_mock_context() + benchmark(tracing.extract_dd_trace_context, event, context) + + +@pytest.mark.parametrize("event", event_samples) +def test_trigger_parse_event_source(event, benchmark): + with open(f"{event_samples_dir}/{event}.json") as f: + event = json.load(f) + benchmark(trigger.parse_event_source, event) + + +@pytest.mark.parametrize("event", event_samples) +def test_trigger_extract_trigger_tags(event, benchmark): + with open(f"{event_samples_dir}/{event}.json") as f: + event = json.load(f) + context = get_mock_context() + benchmark(trigger.extract_trigger_tags, event, context) + + +def test_xray_send_segment(benchmark, monkeypatch): + reset_xray_connection() + + monkeypatch.setenv(XrayDaemon.XRAY_DAEMON_ADDRESS, "localhost:9000") + monkeypatch.setenv( + XrayDaemon.XRAY_TRACE_ID_HEADER_NAME, + "Root=1-5e272390-8c398be037738dc042009320;Parent=94ae789b969f1cc5;Sampled=1;Lineage=c6c5b1b9:0", + ) + + def socket_send(*a, **k): + sends.append(True) + + sends = [] + monkeypatch.setattr("socket.socket.send", socket_send) + + key = { + "trace-id": "12345678901234567890123456789012", + "parent-id": "1234567890123456", + "sampling-priority": "1", + } + benchmark(xray.send_segment, XraySubsegment.TRACE_KEY, key) + assert sends diff --git a/tests/test_cold_start.py b/tests/test_cold_start.py index 65193e1de..d75b5f43a 100644 --- a/tests/test_cold_start.py +++ b/tests/test_cold_start.py @@ -1,10 +1,15 @@ +import os import time import unittest -import datadog_lambda.cold_start as cold_start + from sys import modules, meta_path -import os from unittest.mock import MagicMock +import datadog_lambda.cold_start as cold_start +import datadog_lambda.wrapper as wrapper + +from tests.utils import get_mock_context + class TestColdStartTracingSetup(unittest.TestCase): def test_proactive_init(self): @@ -234,3 +239,38 @@ def test_trace_ignore_libs(self): self.cold_start_tracer.trace(nodes) self.mock_activate.assert_called_once_with(self.mock_trace_ctx) self.assertEqual(self.output_spans, ["node_0", "unittest_cold_start"]) + + +def test_lazy_loaded_package_imports(monkeypatch): + spans = [] + + def finish(span): + spans.append(span) + + monkeypatch.setattr(wrapper.tracer, "_on_span_finish", finish) + monkeypatch.setattr(wrapper, "is_new_sandbox", lambda: True) + monkeypatch.setattr("datadog_lambda.config.Config.trace_enabled", True) + monkeypatch.setenv( + "DD_COLD_START_TRACE_SKIP_LIB", "ddtrace.contrib.logging,datadog_lambda.wrapper" + ) + monkeypatch.setenv("DD_MIN_COLD_START_DURATION", "0") + + @wrapper.datadog_lambda_wrapper + def handler(event, context): + import tabnanny + + lambda_context = get_mock_context() + + handler.cold_start_tracing = True + handler({}, lambda_context) + + function_span = import_span = None + for span in spans: + if span.resource == "tabnanny": + import_span = span + elif span.name == "aws.lambda": + function_span = span + + assert function_span is not None + assert import_span is not None + assert import_span.parent_id == function_span.span_id diff --git a/tests/test_config.py b/tests/test_config.py new file mode 100644 index 000000000..92002439d --- /dev/null +++ b/tests/test_config.py @@ -0,0 +1,240 @@ +import pytest + +from datadog_lambda.config import config, _get_env, Config + + +@pytest.fixture +def setenv(monkeypatch): + def set_env(key, value): + if value is None: + monkeypatch.delenv(key, raising=False) + else: + monkeypatch.setenv(key, value) + + return set_env + + +def _test_as_bool(env_key, conf_key, default): + return ( + (env_key, conf_key, None, default), + (env_key, conf_key, "", False), + (env_key, conf_key, "true", True), + (env_key, conf_key, "TRUE", True), + (env_key, conf_key, "false", False), + (env_key, conf_key, "FALSE", False), + (env_key, conf_key, "1", True), + (env_key, conf_key, "0", False), + (env_key, conf_key, "purple", False), + ) + + +def _test_int(env_key, conf_key, default): + return ( + (env_key, conf_key, None, default), + (env_key, conf_key, "", default), + (env_key, conf_key, "5", 5), + (env_key, conf_key, "0", 0), + (env_key, conf_key, "2.5", default), + (env_key, conf_key, "-1", -1), + (env_key, conf_key, "purple", default), + ) + + +def _test_as_list(env_key, conf_key, default): + return ( + (env_key, conf_key, None, default.split(",")), + (env_key, conf_key, "", []), + (env_key, conf_key, " ", []), + (env_key, conf_key, ",", []), + (env_key, conf_key, " , ", []), + (env_key, conf_key, "a", ["a"]), + (env_key, conf_key, "a,", ["a"]), + (env_key, conf_key, "a, ", ["a"]), + (env_key, conf_key, "a,b", ["a", "b"]), + (env_key, conf_key, "a, b", ["a", "b"]), + ) + + +_test_config_from_environ = ( + *_test_as_bool("DD_FLUSH_TO_LOG", "flush_to_log", default=False), + *_test_as_bool("DD_LOGS_INJECTION", "logs_injection", default=True), + *_test_as_bool("DD_TRACE_ENABLED", "trace_enabled", default=True), + *_test_as_bool("DD_COLD_START_TRACING", "cold_start_tracing", default=True), + *_test_as_bool("DD_TRACE_MANAGED_SERVICES", "make_inferred_span", default=True), + *_test_as_bool( + "DD_ENCODE_AUTHORIZER_CONTEXT", "encode_authorizer_context", default=True + ), + *_test_as_bool( + "DD_DECODE_AUTHORIZER_CONTEXT", "decode_authorizer_context", default=True + ), + *_test_as_bool("DD_FLUSH_IN_THREAD", "flush_in_thread", default=False), + *_test_as_bool("DD_ENHANCED_METRICS", "enhanced_metrics_enabled", default=True), + *_test_as_bool("DD_INTEGRATION_TEST", "integration_test", default=False), + *_test_as_bool("DD_BOTOCORE_ADD_SPAN_POINTERS", "add_span_pointers", default=True), + *_test_as_bool("DD_TRACE_OTEL_ENABLED", "otel_enabled", default=False), + *_test_as_bool( + "DD_INSTRUMENTATION_TELEMETRY_ENABLED", "telemetry_enabled", default=False + ), + *_test_as_bool("DD_MERGE_XRAY_TRACES", "merge_xray_traces", default=False), + *_test_as_bool("DD_PROFILING_ENABLED", "profiling_enabled", default=False), + *_test_as_bool("DD_LLMOBS_ENABLED", "llmobs_enabled", default=False), + *_test_as_bool( + "DD_EXCEPTION_REPLAY_ENABLED", "exception_replay_enabled", default=False + ), + *_test_as_bool( + "DD_CAPTURE_LAMBDA_PAYLOAD", "capture_payload_enabled", default=False + ), + *_test_as_bool("DD_LOCAL_TEST", "local_test", default=False), + *_test_as_bool("DD_DATA_STREAMS_ENABLED", "data_streams_enabled", default=False), + *_test_int( + "DD_CAPTURE_LAMBDA_PAYLOAD_MAX_DEPTH", "capture_payload_max_depth", default=10 + ), + *_test_int( + "DD_MIN_COLD_START_DURATION", "min_cold_start_trace_duration", default=3 + ), + *_test_as_list( + "DD_COLD_START_TRACE_SKIP_LIB", + "cold_start_trace_skip_lib", + default="ddtrace.internal.compat,ddtrace.filters", + ), + ("DD_SERVICE", "service", None, None), + ("DD_SERVICE", "service", "", ""), + ("DD_SERVICE", "service", "my_service", "my_service"), + ("AWS_LAMBDA_FUNCTION_NAME", "aws_lambda_function_name", None, None), + ("AWS_LAMBDA_FUNCTION_NAME", "aws_lambda_function_name", "", ""), + ( + "AWS_LAMBDA_FUNCTION_NAME", + "aws_lambda_function_name", + "my_function", + "my_function", + ), + ("AWS_LAMBDA_FUNCTION_NAME", "function_name", None, "function"), + ("AWS_LAMBDA_FUNCTION_NAME", "function_name", "", ""), + ("AWS_LAMBDA_FUNCTION_NAME", "function_name", "my_function", "my_function"), + ("AWS_LAMBDA_FUNCTION_NAME", "is_lambda_context", None, False), + ("AWS_LAMBDA_FUNCTION_NAME", "is_lambda_context", "", False), + ("AWS_LAMBDA_FUNCTION_NAME", "is_lambda_context", "my_function", True), + ("AWS_REGION", "is_gov_region", None, False), + ("AWS_REGION", "is_gov_region", "", False), + ("AWS_REGION", "is_gov_region", "us-gov-1", True), + ("AWS_REGION", "is_gov_region", "us-est-1", False), + ("DD_TRACE_EXTRACTOR", "trace_extractor", None, None), + ("DD_TRACE_EXTRACTOR", "trace_extractor", "", ""), + ("DD_TRACE_EXTRACTOR", "trace_extractor", "my_extractor", "my_extractor"), + ("DD_ENV", "env", None, None), + ("DD_ENV", "env", "", ""), + ("DD_ENV", "env", "my_env", "my_env"), +) + + +@pytest.mark.parametrize("env_key,conf_key,env_val,conf_val", _test_config_from_environ) +def test_config_from_environ(env_key, conf_key, env_val, conf_val, setenv): + setenv(env_key, env_val) + assert getattr(config, conf_key) == conf_val + + +_test_config_from_environ_depends_on_tracing = ( + *_test_as_bool("DD_COLD_START_TRACING", "cold_start_tracing", default=True), + *_test_as_bool("DD_TRACE_MANAGED_SERVICES", "make_inferred_span", default=True), + *_test_as_bool( + "DD_ENCODE_AUTHORIZER_CONTEXT", "encode_authorizer_context", default=True + ), + *_test_as_bool( + "DD_DECODE_AUTHORIZER_CONTEXT", "decode_authorizer_context", default=True + ), + *_test_as_bool("DD_DATA_STREAMS_ENABLED", "data_streams_enabled", default=False), + *_test_as_bool( + "DD_INSTRUMENTATION_TELEMETRY_ENABLED", "telemetry_enabled", default=False + ), +) + + +@pytest.mark.parametrize( + "env_key,conf_key,env_val,conf_val", _test_config_from_environ_depends_on_tracing +) +def test_config_from_environ_depends_on_tracing( + env_key, conf_key, env_val, conf_val, setenv +): + setenv(env_key, env_val) + setenv("DD_TRACE_ENABLED", "false") + assert getattr(config, conf_key) is False + + +def test_config_aws_lambda_function_name(setenv): + # these config values all access the same environment variable, test to + # ensure the wrong value is not cached + setenv("AWS_LAMBDA_FUNCTION_NAME", "my_function") + assert config.aws_lambda_function_name == "my_function" + assert config.function_name == "my_function" + assert config.is_lambda_context is True + + +_test_fips_mode_from_environ = ( + (None, None, False), + (None, "", False), + (None, "us-gov-1", True), + (None, "us-east-1", False), + ("", None, False), + ("", "", False), + ("", "us-gov-1", False), + ("", "us-east-1", False), + ("true", None, True), + ("true", "", True), + ("true", "us-gov-1", True), + ("true", "us-east-1", True), + ("TRUE", None, True), + ("TRUE", "", True), + ("TRUE", "us-gov-1", True), + ("TRUE", "us-east-1", True), + ("false", None, False), + ("false", "", False), + ("false", "us-gov-1", False), + ("false", "us-east-1", False), + ("FALSE", None, False), + ("FALSE", "", False), + ("FALSE", "us-gov-1", False), + ("FALSE", "us-east-1", False), + ("1", None, False), + ("1", "", False), + ("1", "us-gov-1", False), + ("1", "us-east-1", False), + ("0", None, False), + ("0", "", False), + ("0", "us-gov-1", False), + ("0", "us-east-1", False), +) + + +@pytest.mark.parametrize("fips_mode,region,conf_val", _test_fips_mode_from_environ) +def test_fips_mode_from_environ(fips_mode, region, conf_val, setenv): + setenv("DD_LAMBDA_FIPS_MODE", fips_mode) + setenv("AWS_REGION", region) + assert config.fips_mode_enabled == conf_val + + +def test__get_env_does_not_log_when_env_not_set(setenv, monkeypatch): + setenv("TEST_1", None) + setenv("TEST_2", None) + setenv("TEST_3", None) + setenv("TEST_4", None) + + class Testing(Config): + test_1 = _get_env("TEST_1") + test_2 = _get_env("TEST_2", "purple") + test_3 = _get_env("TEST_3", "true", bool) + test_4 = _get_env("TEST_4", "true", bool, depends_on_tracing=True) + + logs = [] + + def cap_warn(*args, **kwargs): + logs.append(args) + + monkeypatch.setattr("datadog_lambda.config.logger.warning", cap_warn) + + testing = Testing() + testing.test_1 + testing.test_2 + testing.test_3 + testing.test_4 + + assert not logs diff --git a/tests/test_dogstatsd.py b/tests/test_dogstatsd.py index 149e1a707..6fe79372d 100644 --- a/tests/test_dogstatsd.py +++ b/tests/test_dogstatsd.py @@ -1,5 +1,5 @@ -from collections import deque import unittest +from collections import deque from datadog_lambda.dogstatsd import statsd @@ -36,16 +36,24 @@ def test_init(self): self.assertEqual(statsd.port, 8125) self.assertEqual(statsd.encoding, "utf-8") - def test_distribution_no_tags(self): - statsd.distribution("my.test.metric", 3) + def _checkOnlyOneMetric(self, value): payload = self.recv() metrics = payload.split("\n") self.assertEqual(len(metrics), 1) - self.assertEqual("my.test.metric:3|d", metrics[0]) + self.assertEqual(value, metrics[0]) + + def test_distribution_no_tags(self): + statsd.distribution("my.test.metric", 3) + self._checkOnlyOneMetric("my.test.metric:3|d") def test_distribution_with_tags(self): statsd.distribution("my.test.tags.metric", 3, tags=["taga:valuea,tagb:valueb"]) - payload = self.recv() - metrics = payload.split("\n") - self.assertEqual(len(metrics), 1) - self.assertEqual("my.test.tags.metric:3|d|#taga:valuea_tagb:valueb", metrics[0]) + self._checkOnlyOneMetric("my.test.tags.metric:3|d|#taga:valuea_tagb:valueb") + + def test_distribution_with_timestamp(self): + statsd.distribution("my.test.timestamp.metric", 9, timestamp=123456789) + self._checkOnlyOneMetric("my.test.timestamp.metric:9|d|T123456789") + + def test_distribution_with_float_timestamp(self): + statsd.distribution("my.test.timestamp.metric", 9, timestamp=123456789.123) + self._checkOnlyOneMetric("my.test.timestamp.metric:9|d|T123456789") diff --git a/tests/test_extension.py b/tests/test_extension.py index 8882fa8f2..92142a9e3 100644 --- a/tests/test_extension.py +++ b/tests/test_extension.py @@ -1,71 +1,66 @@ +import http.server import os +import threading import unittest -import httpretty from unittest.mock import patch from datadog_lambda.extension import ( - is_extension_running, + is_extension_present, flush_extension, should_use_extension, ) -def exceptionCallback(request, uri, headers): - raise Exception("oopsy!") +class MockServer(threading.Thread): + def __init__(self): + super().__init__() + self.daemon = True + self.raises = False + self.called = False + + class handler(http.server.BaseHTTPRequestHandler): + def do_POST(sf): + self.called = True + sf.send_response(500 if self.raises else 200) + sf.end_headers() + + do_GET = do_POST + + self.server = http.server.HTTPServer(("127.0.0.1", 8124), handler) + + def run(self): + self.server.serve_forever() + + def stop(self): + self.server.shutdown() + self.server.server_close() + self.join(timeout=0) class TestLambdaExtension(unittest.TestCase): + def setUp(self): + self.server = MockServer() + self.server.start() + + def tearDown(self): + self.server.stop() + @patch("datadog_lambda.extension.EXTENSION_PATH", os.path.abspath(__file__)) def test_is_extension_running_true(self): - httpretty.enable() - last_request = httpretty.last_request() - httpretty.register_uri(httpretty.GET, "http://127.0.0.1:8124/lambda/hello") - assert is_extension_running() == True - assert httpretty.last_request() != last_request - httpretty.disable() + assert is_extension_present() def test_is_extension_running_file_not_found(self): - httpretty.enable() - last_request = httpretty.last_request() - httpretty.register_uri(httpretty.GET, "http://127.0.0.1:8124/lambda/hello") - assert is_extension_running() == False - assert httpretty.last_request() == last_request - httpretty.disable() - - @patch("datadog_lambda.extension.EXTENSION_PATH", os.path.abspath(__file__)) - def test_is_extension_running_http_failure(self): - httpretty.enable() - last_request = httpretty.last_request() - httpretty.register_uri( - httpretty.GET, - "http://127.0.0.1:8124/lambda/hello", - status=503, - body=exceptionCallback, - ) - assert is_extension_running() == False - assert httpretty.last_request() != last_request - httpretty.disable() + assert not is_extension_present() + assert not self.server.called @patch("datadog_lambda.extension.EXTENSION_PATH", os.path.abspath(__file__)) def test_flush_ok(self): - httpretty.enable() - last_request = httpretty.last_request() - httpretty.register_uri(httpretty.POST, "http://127.0.0.1:8124/lambda/flush") - assert flush_extension() == True - assert httpretty.last_request() != last_request - httpretty.disable() + assert flush_extension() + assert self.server.called @patch("datadog_lambda.extension.EXTENSION_PATH", os.path.abspath(__file__)) def test_flush_not_ok(self): - httpretty.enable() - last_request = httpretty.last_request() - httpretty.register_uri( - httpretty.POST, - "http://127.0.0.1:8124/lambda/flush", - status=503, - body=exceptionCallback, - ) - assert flush_extension() == False - assert httpretty.last_request() != last_request - httpretty.disable() + self.server.raises = True + assert not flush_extension() + assert self.server.called diff --git a/tests/test_handler.py b/tests/test_handler.py new file mode 100644 index 000000000..50f426dc9 --- /dev/null +++ b/tests/test_handler.py @@ -0,0 +1,72 @@ +import os +import sys +import unittest +from unittest.mock import patch + +from tests.utils import get_mock_context + + +class TestHandler(unittest.TestCase): + def tearDown(self): + for mod in sys.modules.copy(): + if mod.startswith("datadog_lambda.handler"): + del sys.modules[mod] + + def test_dd_lambda_handler_env_var_none(self): + with self.assertRaises(Exception) as context: + import datadog_lambda.handler as handler + + assert context.exception == handler.HandlerError( + "DD_LAMBDA_HANDLER is not defined. Can't use prebuilt datadog handler" + ) + + @patch.dict(os.environ, {"DD_LAMBDA_HANDLER": "malformed"}, clear=True) + def test_dd_lambda_handler_env_var_malformed(self): + with self.assertRaises(Exception) as context: + import datadog_lambda.handler as handler + + assert context.exception == handler.HandlerError( + "Value malformed for DD_LAMBDA_HANDLER has invalid format." + ) + + @patch.dict(os.environ, {"DD_LAMBDA_HANDLER": "nonsense.nonsense"}, clear=True) + @patch("datadog_lambda.tracing.emit_telemetry_on_exception_outside_of_handler") + @patch("time.time_ns", return_value=42) + def test_exception_importing_module(self, mock_time, mock_emit_telemetry): + with self.assertRaises(ModuleNotFoundError) as test_context: + import datadog_lambda.handler + + mock_emit_telemetry.assert_called_once_with( + test_context.exception, "nonsense", 42 + ) + + @patch.dict(os.environ, {"DD_LAMBDA_HANDLER": "nonsense.nonsense"}, clear=True) + @patch("importlib.import_module", return_value=None) + @patch("datadog_lambda.tracing.emit_telemetry_on_exception_outside_of_handler") + @patch("time.time_ns", return_value=42) + def test_exception_getting_handler_func( + self, mock_time, mock_emit_telemetry, mock_import + ): + with self.assertRaises(AttributeError) as test_context: + import datadog_lambda.handler + + mock_emit_telemetry.assert_called_once_with( + test_context.exception, "nonsense", 42 + ) + + @patch.dict(os.environ, {"DD_LAMBDA_HANDLER": "nonsense.nonsense"}, clear=True) + @patch("importlib.import_module") + @patch("datadog_lambda.tracing.emit_telemetry_on_exception_outside_of_handler") + @patch("datadog_lambda.wrapper.datadog_lambda_wrapper") + def test_handler_success( + self, mock_lambda_wrapper, mock_emit_telemetry, mock_import + ): + def nonsense(): + pass + + mock_import.nonsense.return_value = nonsense + + import datadog_lambda.handler + + mock_emit_telemetry.assert_not_called() + mock_lambda_wrapper.assert_called_once_with(mock_import().nonsense) diff --git a/tests/test_logger.py b/tests/test_logger.py new file mode 100644 index 000000000..eb2822f2f --- /dev/null +++ b/tests/test_logger.py @@ -0,0 +1,43 @@ +import io +import logging +import pytest + +from datadog_lambda.logger import initialize_logging + +_test_initialize_logging = ( + ("TRACE", (10, 20, 30, 40, 50)), + ("DEBUG", (10, 20, 30, 40, 50)), + ("debug", (10, 20, 30, 40, 50)), + ("INFO", (20, 30, 40, 50)), + ("WARNING", (30, 40, 50)), + ("WARN", (30, 40, 50)), + ("ERROR", (40, 50)), + ("CRITICAL", (50,)), + ("OFF", ()), + ("", (20, 30, 40, 50)), + (None, (20, 30, 40, 50)), + ("PURPLE", (30, 20, 30, 40, 50)), # log warning then default to INFO +) + + +@pytest.mark.parametrize("level,logged_levels", _test_initialize_logging) +def test_initialize_logging(level, logged_levels, monkeypatch): + if level is not None: + monkeypatch.setenv("DD_LOG_LEVEL", level) + + stream = io.StringIO() + handler = logging.StreamHandler(stream) + handler.setFormatter(logging.Formatter("%(levelno)s")) + logger = logging.getLogger(__name__) + logger.addHandler(handler) + + initialize_logging(__name__) + + logger.debug("debug") + logger.info("info") + logger.warning("warning") + logger.error("error") + logger.critical("critical") + + logged = tuple(map(int, stream.getvalue().strip().split())) + assert logged == logged_levels diff --git a/tests/test_metric.py b/tests/test_metric.py index 24c9a56da..fe3df247d 100644 --- a/tests/test_metric.py +++ b/tests/test_metric.py @@ -1,55 +1,190 @@ import os import unittest - -from unittest.mock import patch, call +from datetime import datetime, timedelta +from unittest.mock import call, patch from botocore.exceptions import ClientError as BotocoreClientError from datadog.api.exceptions import ClientError - -from datadog_lambda.metric import lambda_metric -from datadog_lambda.api import decrypt_kms_api_key, KMS_ENCRYPTION_CONTEXT_KEY +from datadog_lambda.api import KMS_ENCRYPTION_CONTEXT_KEY, decrypt_kms_api_key +from datadog_lambda.metric import ( + MetricsHandler, + _select_metrics_handler, + flush_stats, + lambda_metric, + submit_batch_item_failures_metric, +) +from datadog_lambda.tags import dd_lambda_layer_tag from datadog_lambda.thread_stats_writer import ThreadStatsWriter -from datadog_lambda.tags import _format_dd_lambda_layer_tag class TestLambdaMetric(unittest.TestCase): def setUp(self): - patcher = patch("datadog_lambda.metric.lambda_stats") - self.mock_metric_lambda_stats = patcher.start() - self.addCleanup(patcher.stop) + lambda_stats_patcher = patch("datadog_lambda.metric.lambda_stats") + self.mock_metric_lambda_stats = lambda_stats_patcher.start() + self.addCleanup(lambda_stats_patcher.stop) + + stdout_metric_patcher = patch( + "datadog_lambda.metric.write_metric_point_to_stdout" + ) + self.mock_write_metric_point_to_stdout = stdout_metric_patcher.start() + self.addCleanup(stdout_metric_patcher.stop) def test_lambda_metric_tagged_with_dd_lambda_layer(self): lambda_metric("test", 1) lambda_metric("test", 1, 123, []) lambda_metric("test", 1, tags=["tag1:test"]) - expected_tag = _format_dd_lambda_layer_tag() self.mock_metric_lambda_stats.distribution.assert_has_calls( [ - call("test", 1, timestamp=None, tags=[expected_tag]), - call("test", 1, timestamp=123, tags=[expected_tag]), - call("test", 1, timestamp=None, tags=["tag1:test", expected_tag]), + call("test", 1, timestamp=None, tags=[dd_lambda_layer_tag]), + call("test", 1, timestamp=123, tags=[dd_lambda_layer_tag]), + call( + "test", 1, timestamp=None, tags=["tag1:test", dd_lambda_layer_tag] + ), ] ) # let's fake that the extension is present, this should override DD_FLUSH_TO_LOG @patch("datadog_lambda.metric.should_use_extension", True) - def test_lambda_metric_flush_to_log_with_extension(self): + def test_select_metrics_handler_extension_despite_flush_to_logs(self): os.environ["DD_FLUSH_TO_LOG"] = "True" + self.assertEqual(MetricsHandler.EXTENSION, _select_metrics_handler()) + del os.environ["DD_FLUSH_TO_LOG"] + + @patch("datadog_lambda.metric.should_use_extension", False) + def test_select_metrics_handler_forwarder_when_flush_to_logs(self): + os.environ["DD_FLUSH_TO_LOG"] = "True" + self.assertEqual(MetricsHandler.FORWARDER, _select_metrics_handler()) + del os.environ["DD_FLUSH_TO_LOG"] + + @patch("datadog_lambda.metric.should_use_extension", False) + def test_select_metrics_handler_dd_api_fallback(self): + os.environ["DD_FLUSH_TO_LOG"] = "False" + self.assertEqual(MetricsHandler.DATADOG_API, _select_metrics_handler()) + del os.environ["DD_FLUSH_TO_LOG"] + + @patch("datadog_lambda.config.Config.fips_mode_enabled", True) + @patch("datadog_lambda.metric.should_use_extension", False) + def test_select_metrics_handler_has_no_fallback_in_fips_mode(self): + os.environ["DD_FLUSH_TO_LOG"] = "False" + self.assertEqual(MetricsHandler.NO_METRICS, _select_metrics_handler()) + del os.environ["DD_FLUSH_TO_LOG"] + + @patch("datadog_lambda.metric.metrics_handler", MetricsHandler.EXTENSION) + def test_lambda_metric_goes_to_extension_with_extension_handler(self): lambda_metric("test", 1) - expected_tag = _format_dd_lambda_layer_tag() self.mock_metric_lambda_stats.distribution.assert_has_calls( - [call("test", 1, timestamp=None, tags=[expected_tag])] + [call("test", 1, timestamp=None, tags=[dd_lambda_layer_tag])] ) - del os.environ["DD_FLUSH_TO_LOG"] - def test_lambda_metric_flush_to_log(self): - os.environ["DD_FLUSH_TO_LOG"] = "True" + @patch("datadog_lambda.metric.metrics_handler", MetricsHandler.NO_METRICS) + def test_lambda_metric_has_nowhere_to_go_with_no_metrics_handler(self): + lambda_metric("test", 1) + self.mock_metric_lambda_stats.distribution.assert_not_called() + self.mock_write_metric_point_to_stdout.assert_not_called() + + @patch("datadog_lambda.metric.metrics_handler", MetricsHandler.EXTENSION) + def test_lambda_metric_timestamp_with_extension(self): + delta = timedelta(minutes=1) + timestamp = int((datetime.now() - delta).timestamp()) + + lambda_metric("test_timestamp", 1, timestamp) + self.mock_metric_lambda_stats.distribution.assert_has_calls( + [call("test_timestamp", 1, timestamp=timestamp, tags=[dd_lambda_layer_tag])] + ) + self.mock_write_metric_point_to_stdout.assert_not_called() + + @patch("datadog_lambda.metric.metrics_handler", MetricsHandler.EXTENSION) + def test_lambda_metric_datetime_with_extension(self): + delta = timedelta(minutes=1) + timestamp = datetime.now() - delta + + lambda_metric("test_datetime_timestamp", 0, timestamp) + self.mock_metric_lambda_stats.distribution.assert_has_calls( + [ + call( + "test_datetime_timestamp", + 0, + timestamp=int(timestamp.timestamp()), + tags=[dd_lambda_layer_tag], + ) + ] + ) + self.mock_write_metric_point_to_stdout.assert_not_called() + + @patch("datadog_lambda.metric.metrics_handler", MetricsHandler.EXTENSION) + def test_lambda_metric_float_with_extension(self): + delta = timedelta(minutes=1) + timestamp_float = (datetime.now() - delta).timestamp() + timestamp_int = int(timestamp_float) + + lambda_metric("test_timestamp", 1, timestamp_float) + self.mock_metric_lambda_stats.distribution.assert_has_calls( + [ + call( + "test_timestamp", + 1, + timestamp=timestamp_int, + tags=[dd_lambda_layer_tag], + ) + ] + ) + self.mock_write_metric_point_to_stdout.assert_not_called() + + @patch("datadog_lambda.metric.metrics_handler", MetricsHandler.EXTENSION) + def test_lambda_metric_timestamp_junk_with_extension(self): + delta = timedelta(minutes=1) + timestamp = (datetime.now() - delta).isoformat() + + lambda_metric("test_timestamp", 1, timestamp) + self.mock_metric_lambda_stats.distribution.assert_not_called() + self.mock_write_metric_point_to_stdout.assert_not_called() + + @patch("datadog_lambda.metric.metrics_handler", MetricsHandler.EXTENSION) + def test_lambda_metric_invalid_timestamp_with_extension(self): + delta = timedelta(hours=5) + timestamp = int((datetime.now() - delta).timestamp()) + + lambda_metric("test_timestamp", 1, timestamp) + self.mock_metric_lambda_stats.distribution.assert_not_called() + self.mock_write_metric_point_to_stdout.assert_not_called() + @patch("datadog_lambda.metric.metrics_handler", MetricsHandler.FORWARDER) + def test_lambda_metric_flush_to_log(self): lambda_metric("test", 1) self.mock_metric_lambda_stats.distribution.assert_not_called() + self.mock_write_metric_point_to_stdout.assert_has_calls( + [call("test", 1, timestamp=None, tags=[dd_lambda_layer_tag])] + ) - del os.environ["DD_FLUSH_TO_LOG"] + @patch("datadog_lambda.metric.logger.warning") + def test_lambda_metric_invalid_metric_name_none(self, mock_logger_warning): + lambda_metric(None, 1) + self.mock_metric_lambda_stats.distribution.assert_not_called() + self.mock_write_metric_point_to_stdout.assert_not_called() + mock_logger_warning.assert_called_once_with( + "Ignoring metric submission. Invalid metric name: %s", None + ) + + @patch("datadog_lambda.metric.logger.warning") + def test_lambda_metric_invalid_metric_name_not_string(self, mock_logger_warning): + lambda_metric(123, 1) + self.mock_metric_lambda_stats.distribution.assert_not_called() + self.mock_write_metric_point_to_stdout.assert_not_called() + mock_logger_warning.assert_called_once_with( + "Ignoring metric submission. Invalid metric name: %s", 123 + ) + + @patch("datadog_lambda.metric.logger.warning") + def test_lambda_metric_non_numeric_value(self, mock_logger_warning): + lambda_metric("test.non_numeric", "oops") + self.mock_metric_lambda_stats.distribution.assert_not_called() + self.mock_write_metric_point_to_stdout.assert_not_called() + mock_logger_warning.assert_called_once_with( + "Ignoring metric submission for metric '%s' because the value is not numeric: %r", + "test.non_numeric", + "oops", + ) class TestFlushThreadStats(unittest.TestCase): @@ -72,6 +207,72 @@ def test_retry_on_remote_disconnected(self): lambda_stats.flush() self.assertEqual(self.mock_threadstats_flush_distributions.call_count, 2) + def test_flush_stats_with_tags(self): + lambda_stats = ThreadStatsWriter(True) + original_constant_tags = lambda_stats.thread_stats.constant_tags.copy() + tags = ["tag1:value1", "tag2:value2"] + + # Add a metric to be flushed + lambda_stats.distribution("test.metric", 1, tags=["metric:tag"]) + + with patch.object( + lambda_stats.thread_stats.reporter, "flush_distributions" + ) as mock_flush_distributions: + lambda_stats.flush(tags) + mock_flush_distributions.assert_called_once() + # Verify that after flush, constant_tags is reset to original + self.assertEqual( + lambda_stats.thread_stats.constant_tags, original_constant_tags + ) + + def test_flush_temp_constant_tags(self): + lambda_stats = ThreadStatsWriter(flush_in_thread=True) + lambda_stats.thread_stats.constant_tags = ["initial:tag"] + original_constant_tags = lambda_stats.thread_stats.constant_tags.copy() + + lambda_stats.distribution("test.metric", 1, tags=["metric:tag"]) + flush_tags = ["flush:tag1", "flush:tag2"] + + with patch.object( + lambda_stats.thread_stats.reporter, "flush_distributions" + ) as mock_flush_distributions: + lambda_stats.flush(tags=flush_tags) + mock_flush_distributions.assert_called_once() + flushed_dists = mock_flush_distributions.call_args[0][0] + + # Expected tags: original constant_tags + flush_tags + metric tags + expected_tags = original_constant_tags + flush_tags + ["metric:tag"] + + # Verify the tags on the metric + self.assertEqual(len(flushed_dists), 1) + metric = flushed_dists[0] + self.assertEqual(sorted(metric["tags"]), sorted(expected_tags)) + + # Verify that constant_tags is reset after flush + self.assertEqual( + lambda_stats.thread_stats.constant_tags, original_constant_tags + ) + + # Repeat to ensure tags do not accumulate over multiple flushes + new_flush_tags = ["flush:tag3"] + lambda_stats.distribution("test.metric2", 2, tags=["metric2:tag"]) + + with patch.object( + lambda_stats.thread_stats.reporter, "flush_distributions" + ) as mock_flush_distributions: + lambda_stats.flush(tags=new_flush_tags) + mock_flush_distributions.assert_called_once() + flushed_dists = mock_flush_distributions.call_args[0][0] + # Expected tags for the new metric + expected_tags = original_constant_tags + new_flush_tags + ["metric2:tag"] + + self.assertEqual(len(flushed_dists), 1) + metric = flushed_dists[0] + self.assertEqual(sorted(metric["tags"]), sorted(expected_tags)) + self.assertEqual( + lambda_stats.thread_stats.constant_tags, original_constant_tags + ) + MOCK_FUNCTION_NAME = "myFunction" @@ -124,3 +325,80 @@ def decrypt(self, CiphertextBlob=None, EncryptionContext={}): mock_kms_client, MOCK_ENCRYPTED_API_KEY_BASE64 ) self.assertEqual(decrypted_key, EXPECTED_DECRYPTED_API_KEY) + + +class TestBatchItemFailuresMetric(unittest.TestCase): + def setUp(self): + patcher = patch("datadog_lambda.metric.lambda_metric") + self.mock_lambda_metric = patcher.start() + self.addCleanup(patcher.stop) + + patcher = patch("datadog_lambda.config.Config.enhanced_metrics_enabled", True) + self.mock_enhanced_metrics_enabled = patcher.start() + self.addCleanup(patcher.stop) + + def test_submit_batch_item_failures_with_failures(self): + response = { + "batchItemFailures": [ + {"itemIdentifier": "msg-1"}, + {"itemIdentifier": "msg-2"}, + {"itemIdentifier": "msg-3"}, + ] + } + context = unittest.mock.Mock() + + with patch("datadog_lambda.metric.get_enhanced_metrics_tags") as mock_get_tags: + mock_get_tags.return_value = ["tag1:value1"] + submit_batch_item_failures_metric(response, context) + + self.mock_lambda_metric.assert_called_once_with( + "aws.lambda.enhanced.batch_item_failures", + 3, + timestamp=None, + tags=["tag1:value1"], + force_async=True, + ) + + def test_submit_batch_item_failures_with_no_failures(self): + response = {"batchItemFailures": []} + context = unittest.mock.Mock() + + with patch("datadog_lambda.metric.get_enhanced_metrics_tags") as mock_get_tags: + mock_get_tags.return_value = ["tag1:value1"] + submit_batch_item_failures_metric(response, context) + self.mock_lambda_metric.assert_called_once_with( + "aws.lambda.enhanced.batch_item_failures", + 0, + timestamp=None, + tags=["tag1:value1"], + force_async=True, + ) + + def test_submit_batch_item_failures_with_no_field(self): + response = {"statusCode": 200} + context = unittest.mock.Mock() + submit_batch_item_failures_metric(response, context) + self.mock_lambda_metric.assert_not_called() + + def test_submit_batch_item_failures_with_none_response(self): + response = None + context = unittest.mock.Mock() + submit_batch_item_failures_metric(response, context) + self.mock_lambda_metric.assert_not_called() + + def test_submit_batch_item_failures_with_non_list_value(self): + response = {"batchItemFailures": "invalid"} + context = unittest.mock.Mock() + submit_batch_item_failures_metric(response, context) + self.mock_lambda_metric.assert_not_called() + + @patch("datadog_lambda.config.Config.enhanced_metrics_enabled", False) + def test_submit_batch_item_failures_enhanced_metrics_disabled(self): + response = { + "batchItemFailures": [ + {"itemIdentifier": "msg-1"}, + ] + } + context = unittest.mock.Mock() + submit_batch_item_failures_metric(response, context) + self.mock_lambda_metric.assert_not_called() diff --git a/tests/test_module_name.py b/tests/test_module_name.py index 213964656..a6faf8298 100644 --- a/tests/test_module_name.py +++ b/tests/test_module_name.py @@ -1,7 +1,5 @@ import unittest -from unittest.mock import patch, call, MagicMock - from datadog_lambda.module_name import modify_module_name diff --git a/tests/test_patch.py b/tests/test_patch.py index bf9248756..b03d2e23e 100644 --- a/tests/test_patch.py +++ b/tests/test_patch.py @@ -1,3 +1,4 @@ +import pytest import unittest from unittest.mock import patch, MagicMock @@ -5,6 +6,13 @@ from datadog_lambda.patch import _patch_http, _ensure_patch_requests from datadog_lambda.constants import TraceHeader +from ddtrace.contrib.internal.requests.patch import unpatch as unpatch_requests + + +@pytest.fixture(scope="module", autouse=True) +def reset_patches(): + unpatch_requests() + class TestPatchHTTPClients(unittest.TestCase): def setUp(self): diff --git a/tests/test_span_pointers.py b/tests/test_span_pointers.py new file mode 100644 index 000000000..f4cd1b268 --- /dev/null +++ b/tests/test_span_pointers.py @@ -0,0 +1,185 @@ +from typing import List +from typing import NamedTuple + +from ddtrace._trace._span_pointer import _SpanPointerDirection +from ddtrace._trace._span_pointer import _SpanPointerDescription +from datadog_lambda.trigger import _EventSource +from datadog_lambda.trigger import EventTypes +from datadog_lambda.span_pointers import calculate_span_pointers +import pytest + + +class TestCalculateSpanPointers: + class SpanPointersCase(NamedTuple): + name: str + event_source: _EventSource + event: dict + dd_botocore_span_pointers: bool + span_pointers: List[_SpanPointerDescription] + + @pytest.mark.parametrize( + "test_case", + [ + SpanPointersCase( + name="some unsupported event", + event_source=_EventSource(EventTypes.UNKNOWN), + event={}, + dd_botocore_span_pointers=True, + span_pointers=[], + ), + SpanPointersCase( + name="empty s3 event", + event_source=_EventSource(EventTypes.S3), + event={}, + dd_botocore_span_pointers=True, + span_pointers=[], + ), + SpanPointersCase( + name="sensible s3 event", + event_source=_EventSource(EventTypes.S3), + event={ + "Records": [ + { + "eventName": "ObjectCreated:Put", + "s3": { + "bucket": { + "name": "mybucket", + }, + "object": { + "key": "mykey", + "eTag": "123abc", + }, + }, + }, + ], + }, + dd_botocore_span_pointers=True, + span_pointers=[ + _SpanPointerDescription( + pointer_kind="aws.s3.object", + pointer_direction=_SpanPointerDirection.UPSTREAM, + pointer_hash="8d49f5b0b742484159d4cd572bae1ce5", + extra_attributes={}, + ), + ], + ), + SpanPointersCase( + name="sensible s3 event with dd_botocore_span_pointers disabled", + event_source=_EventSource(EventTypes.S3), + event={ + "Records": [ + { + "eventName": "ObjectCreated:Put", + "s3": { + "bucket": { + "name": "mybucket", + }, + "object": { + "key": "mykey", + "eTag": "123abc", + }, + }, + }, + ], + }, + dd_botocore_span_pointers=False, + span_pointers=[], + ), + SpanPointersCase( + name="malformed s3 event", + event_source=_EventSource(EventTypes.S3), + event={ + "Records": [ + { + "eventName": "ObjectCreated:Put", + "s3": { + "bucket": { + "name": "mybucket", + }, + "object": { + "key": "mykey", + # missing eTag + }, + }, + }, + ], + }, + dd_botocore_span_pointers=True, + span_pointers=[], + ), + SpanPointersCase( + name="empty dynamodb event", + event_source=_EventSource(EventTypes.DYNAMODB), + event={}, + dd_botocore_span_pointers=True, + span_pointers=[], + ), + SpanPointersCase( + name="sensible dynamodb event", + event_source=_EventSource(EventTypes.DYNAMODB), + event={ + "Records": [ + { + "eventSourceARN": "arn:aws:dynamodb:us-west-2:123456789012:table/some-table/stream/2015-06-27T00:48:05.899", + "dynamodb": { + "Keys": { + "some-key": {"S": "some-value"}, + }, + }, + }, + { + "eventSourceARN": "arn:aws:dynamodb:us-west-2:123456789012:table/some-table/stream/2015-06-27T00:48:05.899", + "dynamodb": { + "Keys": { + "some-key": {"S": "some-other-value"}, + }, + }, + }, + ], + }, + dd_botocore_span_pointers=True, + span_pointers=[ + _SpanPointerDescription( + pointer_kind="aws.dynamodb.item", + pointer_direction=_SpanPointerDirection.UPSTREAM, + pointer_hash="7f1aee721472bcb48701d45c7c7f7821", + extra_attributes={}, + ), + _SpanPointerDescription( + pointer_kind="aws.dynamodb.item", + pointer_direction=_SpanPointerDirection.UPSTREAM, + pointer_hash="36b820424312a6069bd3f2185f1af584", + extra_attributes={}, + ), + ], + ), + SpanPointersCase( + name="malformed dynamodb event", + event_source=_EventSource(EventTypes.DYNAMODB), + event={ + "Records": [ + { + "eventSourceARN": "arn:aws:dynamodb:us-west-2:123456789012:table/some-table", # missing stream info + "dynamodb": { + "Keys": { + "some-key": {"S": "some-value"}, + }, + }, + }, + ], + }, + dd_botocore_span_pointers=True, + span_pointers=[], + ), + ], + ids=lambda test_case: test_case.name, + ) + def test_calculate_span_pointers(self, test_case: SpanPointersCase) -> None: + assert ( + calculate_span_pointers( + test_case.event_source, + test_case.event, + botocore_add_span_pointers=test_case.dd_botocore_span_pointers, + ) + == test_case.span_pointers + ) diff --git a/tests/test_tag_object.py b/tests/test_tag_object.py index 77512164f..574bb331a 100644 --- a/tests/test_tag_object.py +++ b/tests/test_tag_object.py @@ -29,6 +29,7 @@ def test_tag_object(self): True, ) + @patch("datadog_lambda.config.Config.capture_payload_max_depth", 2) def test_tag_object_max_depth(self): payload = { "hello": "world", @@ -41,11 +42,8 @@ def test_tag_object_max_depth(self): "vals": [{"thingOne": 1}, {"thingTwo": 2}], } spanMock = MagicMock() - import datadog_lambda.tag_object as lib_ref - lib_ref.max_depth = 2 # setting up the test tag_object(spanMock, "function.request", payload) - lib_ref.max_depth = 10 # revert the setup spanMock.set_tag.assert_has_calls( [ call("function.request.vals.0", "{'thingOne': 1}"), @@ -62,6 +60,7 @@ def test_tag_object_max_depth(self): True, ) + @patch("datadog_lambda.config.Config.capture_payload_max_depth", 0) def test_tag_object_max_depth_0(self): payload = { "hello": "world", @@ -74,11 +73,8 @@ def test_tag_object_max_depth_0(self): "vals": [{"thingOne": 1}, {"thingTwo": 2}], } spanMock = MagicMock() - import datadog_lambda.tag_object as lib_ref - lib_ref.max_depth = 0 # setting up the test tag_object(spanMock, "function.request", payload) - lib_ref.max_depth = 10 # revert the setup spanMock.set_tag.assert_has_calls( [ call( diff --git a/tests/test_tags.py b/tests/test_tags.py index 80b5f86db..07daa8e03 100644 --- a/tests/test_tags.py +++ b/tests/test_tags.py @@ -1,30 +1,25 @@ import unittest -from unittest.mock import patch, MagicMock +from unittest.mock import patch +from datadog_lambda.tags import parse_lambda_tags_from_arn -from datadog_lambda.tags import parse_lambda_tags_from_arn, get_runtime_tag - - -def get_mock_context( - invoked_function_arn="arn:aws:lambda:us-east-1:1234597598159:function:swf-hello-test:$Latest", - function_version="1", -): - lambda_context = MagicMock() - lambda_context.invoked_function_arn = invoked_function_arn - lambda_context.function_version = function_version - return lambda_context +from tests.utils import get_mock_context class TestMetricTags(unittest.TestCase): def setUp(self): - patcher = patch("datadog_lambda.tags.python_version_tuple") + patcher = patch("sys.version_info", (3, 12, 0)) self.mock_python_version_tuple = patcher.start() self.addCleanup(patcher.stop) def test_parse_lambda_tags_from_arn_latest(self): + lambda_context = get_mock_context() + lambda_context.invoked_function_arn = ( + "arn:aws:lambda:us-east-1:1234597598159:function:swf-hello-test:$Latest" + ) self.assertListEqual( - parse_lambda_tags_from_arn(get_mock_context()), + parse_lambda_tags_from_arn(lambda_context), [ "region:us-east-1", "account_id:1234597598159", @@ -63,7 +58,3 @@ def test_parse_lambda_tags_from_arn_alias(self): "resource:swf-hello-test:my_alias-1", ], ) - - def test_get_runtime_tag(self): - self.mock_python_version_tuple.return_value = ("3", "7", "2") - self.assertEqual(get_runtime_tag(), "runtime:python3.7") diff --git a/tests/test_tracing.py b/tests/test_tracing.py index 3a28a2a36..0fddd52ba 100644 --- a/tests/test_tracing.py +++ b/tests/test_tracing.py @@ -1,15 +1,20 @@ -import unittest +import base64 +import copy import functools import json +import traceback +import pytest import os -import copy +import unittest -from unittest.mock import MagicMock, Mock, patch, call +from unittest.mock import Mock, patch, call, ANY import ddtrace -from ddtrace import tracer -from ddtrace.context import Context +from ddtrace.trace import Context, tracer +from ddtrace._trace._span_pointer import _SpanPointer +from ddtrace._trace._span_pointer import _SpanPointerDirection +from ddtrace._trace._span_pointer import _SpanPointerDescription from datadog_lambda.constants import ( SamplingPriority, @@ -18,7 +23,9 @@ XraySubsegment, ) from datadog_lambda.tracing import ( - _deterministic_md5_hash, + HIGHER_64_BITS, + LOWER_64_BITS, + _deterministic_sha256_hash, create_inferred_span, extract_dd_trace_context, create_dd_dummy_metadata_subsegment, @@ -30,12 +37,19 @@ _convert_xray_trace_id, _convert_xray_entity_id, _convert_xray_sampling, - InferredSpanInfo, create_service_mapping, determine_service_name, service_mapping as global_service_mapping, + propagator, + emit_telemetry_on_exception_outside_of_handler, + _dsm_set_checkpoint, + extract_context_from_kinesis_event, + extract_context_from_sqs_or_sns_event_or_context, ) -from datadog_lambda.trigger import EventTypes + +from datadog_lambda.trigger import parse_event_source +from tests.utils import get_mock_context, ClientContext + function_arn = "arn:aws:lambda:us-west-1:123457598159:function:python-layer-test" @@ -47,55 +61,6 @@ event_samples = "tests/event_samples/" -span_to_finish = None - - -def _clean_up_span(): - global span_to_finish - if span_to_finish is not None: - span_to_finish.finish() - span_to_finish = None - - -def register_span(span): - global span_to_finish - _clean_up_span() - span_to_finish = span - return span - - -def wrapped_span_creator(span_creator_func): - def result_func(*args, **kwargs): - return register_span(span_creator_func(*args, **kwargs)) - - return result_func - - -create_inferred_span = wrapped_span_creator(create_inferred_span) - - -class ClientContext(object): - def __init__(self, custom=None): - self.custom = custom - - -def get_mock_context( - aws_request_id="request-id-1", - memory_limit_in_mb="256", - invoked_function_arn=function_arn, - function_version="1", - function_name="Function", - custom=None, -): - lambda_context = MagicMock() - lambda_context.aws_request_id = aws_request_id - lambda_context.memory_limit_in_mb = memory_limit_in_mb - lambda_context.invoked_function_arn = invoked_function_arn - lambda_context.function_version = function_version - lambda_context.function_name = function_name - lambda_context.client_context = ClientContext(custom) - return lambda_context - def with_trace_propagation_style(style): style_list = list(style.split(",")) @@ -120,22 +85,197 @@ def _wrap(*args, **kwargs): return _wrapper +_test_extract_dd_trace_context = ( + ("api-gateway", Context(trace_id=12345, span_id=67890, sampling_priority=2)), + ( + "api-gateway-no-apiid", + Context(trace_id=12345, span_id=67890, sampling_priority=2), + ), + ( + "api-gateway-non-proxy", + Context(trace_id=12345, span_id=67890, sampling_priority=2), + ), + ( + "api-gateway-non-proxy-async", + Context(trace_id=12345, span_id=67890, sampling_priority=2), + ), + ( + "api-gateway-websocket-connect", + Context(trace_id=12345, span_id=67890, sampling_priority=2), + ), + ( + "api-gateway-websocket-default", + Context(trace_id=12345, span_id=67890, sampling_priority=2), + ), + ( + "api-gateway-websocket-disconnect", + Context(trace_id=12345, span_id=67890, sampling_priority=2), + ), + ( + "authorizer-request-api-gateway-v1", + Context( + trace_id=13478705995797221209, + span_id=8471288263384216896, + sampling_priority=1, + ), + ), + ("authorizer-request-api-gateway-v1-cached", None), + ( + "authorizer-request-api-gateway-v2", + Context( + trace_id=14356983619852933354, + span_id=12658621083505413809, + sampling_priority=1, + ), + ), + ("authorizer-request-api-gateway-v2-cached", None), + ( + "authorizer-request-api-gateway-websocket-connect", + Context( + trace_id=5351047404834723189, + span_id=18230460631156161837, + sampling_priority=1, + ), + ), + ("authorizer-request-api-gateway-websocket-message", None), + ( + "authorizer-token-api-gateway-v1", + Context( + trace_id=17874798268144902712, + span_id=16184667399315372101, + sampling_priority=1, + ), + ), + ("authorizer-token-api-gateway-v1-cached", None), + ("cloudfront", None), + ("cloudwatch-events", None), + ("cloudwatch-logs", None), + ("custom", None), + ("dynamodb", None), + ("eventbridge-custom", Context(trace_id=12345, span_id=67890, sampling_priority=2)), + ( + "eventbridge-sqs", + Context( + trace_id=7379586022458917877, + span_id=2644033662113726488, + sampling_priority=1, + ), + ), + ("http-api", Context(trace_id=12345, span_id=67890, sampling_priority=2)), + ( + "kinesis", + Context( + trace_id=4948377316357291421, + span_id=2876253380018681026, + sampling_priority=1, + ), + ), + ( + "kinesis-batch", + Context( + trace_id=4948377316357291421, + span_id=2876253380018681026, + sampling_priority=1, + ), + ), + ("lambda-url", None), + ( + "rum-appsync", + Context( + trace_id=12345, + span_id=67890, + sampling_priority=1, + ), + ), + ("rum-appsync-no-headers", None), + ("rum-appsync-request-not-dict", None), + ("s3", None), + ( + "sns-b64-msg-attribute", + Context( + trace_id=4948377316357291421, + span_id=6746998015037429512, + sampling_priority=1, + ), + ), + ( + "sns-batch", + Context( + trace_id=4948377316357291421, + span_id=6746998015037429512, + sampling_priority=1, + ), + ), + ( + "sns-string-msg-attribute", + Context( + trace_id=4948377316357291421, + span_id=6746998015037429512, + sampling_priority=1, + ), + ), + ( + "sqs-batch", + Context( + trace_id=2684756524522091840, + span_id=7431398482019833808, + sampling_priority=1, + ), + ), + ( + "sqs-java-upstream", + Context( + trace_id=7925498337868555493, + span_id=5245570649555658903, + sampling_priority=1, + ), + ), + ( + "sns-sqs-java-upstream", + Context( + trace_id=4781801699472307582, + span_id=7752697518321801287, + sampling_priority=1, + ), + ), + ( + "sqs-string-msg-attribute", + Context( + trace_id=2684756524522091840, + span_id=7431398482019833808, + sampling_priority=1, + ), + ), + ({"headers": None}, None), +) + + +@pytest.mark.parametrize("event,expect", _test_extract_dd_trace_context) +def test_extract_dd_trace_context(event, expect): + if isinstance(event, str): + with open(f"{event_samples}{event}.json") as f: + event = json.load(f) + ctx = get_mock_context() + + actual, _, _ = extract_dd_trace_context(event, ctx) + assert (expect is None) is (actual is None) + assert (expect is None) or actual.trace_id == expect.trace_id + assert (expect is None) or actual.span_id == expect.span_id + assert (expect is None) or actual.sampling_priority == expect.sampling_priority + + class TestExtractAndGetDDTraceContext(unittest.TestCase): def setUp(self): - global dd_tracing_enabled - dd_tracing_enabled = False os.environ["_X_AMZN_TRACE_ID"] = fake_xray_header_value patcher = patch("datadog_lambda.tracing.send_segment") self.mock_send_segment = patcher.start() self.addCleanup(patcher.stop) - patcher = patch("datadog_lambda.tracing.is_lambda_context") + patcher = patch("datadog_lambda.config.Config.is_lambda_context") self.mock_is_lambda_context = patcher.start() self.mock_is_lambda_context.return_value = True self.addCleanup(patcher.stop) def tearDown(self): - global dd_tracing_enabled - dd_tracing_enabled = False del os.environ["_X_AMZN_TRACE_ID"] @with_trace_propagation_style("datadog") @@ -188,7 +328,7 @@ def test_with_non_object_event(self): def test_with_incomplete_datadog_trace_headers(self): lambda_ctx = get_mock_context() ctx, source, event_source = extract_dd_trace_context( - {"headers": {TraceHeader.TRACE_ID: "123", TraceHeader.PARENT_ID: "321"}}, + {"headers": {TraceHeader.TRACE_ID: "123"}}, lambda_ctx, ) self.assertEqual(source, "xray") @@ -209,73 +349,48 @@ def test_with_incomplete_datadog_trace_headers(self): }, ) - @with_trace_propagation_style("datadog") - def test_with_complete_datadog_trace_headers(self): - lambda_ctx = get_mock_context() + def common_tests_with_trace_context_extraction_injection( + self, headers, event_containing_headers, lambda_context=get_mock_context() + ): ctx, source, event_source = extract_dd_trace_context( - { - "headers": { - TraceHeader.TRACE_ID: "123", - TraceHeader.PARENT_ID: "321", - TraceHeader.SAMPLING_PRIORITY: "1", - } - }, - lambda_ctx, + event_containing_headers, + lambda_context, ) self.assertEqual(source, "event") - expected_context = Context(trace_id=123, span_id=321, sampling_priority=1) + expected_context = propagator.extract(headers) self.assertEqual(ctx, expected_context) - self.assertDictEqual( - get_dd_trace_context(), - { - TraceHeader.TRACE_ID: "123", - TraceHeader.PARENT_ID: fake_xray_header_value_parent_decimal, - TraceHeader.SAMPLING_PRIORITY: "1", - }, - ) create_dd_dummy_metadata_subsegment(ctx, XraySubsegment.TRACE_KEY) self.mock_send_segment.assert_called() self.mock_send_segment.assert_called_with( XraySubsegment.TRACE_KEY, expected_context, ) + # when no active ddtrace context, xray context would be used + expected_context.span_id = int(fake_xray_header_value_parent_decimal) + expected_headers = {} + propagator.inject(expected_context, expected_headers) + dd_context_headers = get_dd_trace_context() + self.assertDictEqual(expected_headers, dd_context_headers) + + @with_trace_propagation_style("datadog") + def test_with_complete_datadog_trace_headers(self): + headers = { + TraceHeader.TRACE_ID: "123", + TraceHeader.PARENT_ID: "321", + TraceHeader.SAMPLING_PRIORITY: "1", + } + self.common_tests_with_trace_context_extraction_injection( + headers, {"headers": headers} + ) @with_trace_propagation_style("tracecontext") def test_with_w3c_trace_headers(self): - lambda_ctx = get_mock_context() - ctx, source, event_source = extract_dd_trace_context( - { - "headers": { - "traceparent": "00-0000000000000000000000000000007b-0000000000000141-01", - "tracestate": "dd=s:2;t.dm:-0,rojo=00f067aa0ba902b7,congo=t61rcWkgMzE", - } - }, - lambda_ctx, - ) - self.assertEqual(source, "event") - expected_context = Context( - trace_id=123, - span_id=321, - sampling_priority=2, - meta={ - "traceparent": "00-0000000000000000000000000000007b-0000000000000141-01", - "tracestate": "dd=s:2;t.dm:-0,rojo=00f067aa0ba902b7,congo=t61rcWkgMzE", - "_dd.p.dm": "-0", - }, - ) - self.assertEqual(ctx, expected_context) - self.assertDictEqual( - get_dd_trace_context(), - { - "traceparent": "00-0000000000000000000000000000007b-94ae789b969f1cc5-01", - "tracestate": "dd=s:2;t.dm:-0,rojo=00f067aa0ba902b7,congo=t61rcWkgMzE", - }, - ) - create_dd_dummy_metadata_subsegment(ctx, XraySubsegment.TRACE_KEY) - self.mock_send_segment.assert_called() - self.mock_send_segment.assert_called_with( - XraySubsegment.TRACE_KEY, - expected_context, + headers = { + "traceparent": "00-0000000000000000000000000000007b-0000000000000141-01", + "tracestate": "dd=s:2;t.dm:-0,rojo=00f067aa0ba902b7,congo=t61rcWkgMzE", + } + self.common_tests_with_trace_context_extraction_injection( + headers, {"headers": headers} ) @with_trace_propagation_style("datadog") @@ -356,7 +471,11 @@ def extractor_raiser(event, context): @with_trace_propagation_style("datadog") def test_with_sqs_distributed_datadog_trace_data(self): - lambda_ctx = get_mock_context() + headers = { + TraceHeader.TRACE_ID: "123", + TraceHeader.PARENT_ID: "321", + TraceHeader.SAMPLING_PRIORITY: "1", + } sqs_event = { "Records": [ { @@ -371,13 +490,7 @@ def test_with_sqs_distributed_datadog_trace_data(self): }, "messageAttributes": { "_datadog": { - "stringValue": json.dumps( - { - TraceHeader.TRACE_ID: "123", - TraceHeader.PARENT_ID: "321", - TraceHeader.SAMPLING_PRIORITY: "1", - } - ), + "stringValue": json.dumps(headers), "dataType": "String", } }, @@ -388,31 +501,14 @@ def test_with_sqs_distributed_datadog_trace_data(self): } ] } - ctx, source, event_source = extract_dd_trace_context(sqs_event, lambda_ctx) - self.assertEqual(source, "event") - expected_context = Context( - trace_id=123, - span_id=321, - sampling_priority=1, - ) - self.assertEqual(ctx, expected_context) - self.assertDictEqual( - get_dd_trace_context(), - { - TraceHeader.TRACE_ID: "123", - TraceHeader.PARENT_ID: fake_xray_header_value_parent_decimal, - TraceHeader.SAMPLING_PRIORITY: "1", - }, - ) - create_dd_dummy_metadata_subsegment(ctx, XraySubsegment.TRACE_KEY) - self.mock_send_segment.assert_called_with( - XraySubsegment.TRACE_KEY, - expected_context, - ) + self.common_tests_with_trace_context_extraction_injection(headers, sqs_event) @with_trace_propagation_style("tracecontext") def test_with_sqs_distributed_w3c_trace_data(self): - lambda_ctx = get_mock_context() + headers = { + "traceparent": "00-0000000000000000000000000000007b-0000000000000141-01", + "tracestate": "dd=s:2;t.dm:-0,rojo=00f067aa0ba902b7,congo=t61rcWkgMzE", + } sqs_event = { "Records": [ { @@ -427,12 +523,7 @@ def test_with_sqs_distributed_w3c_trace_data(self): }, "messageAttributes": { "_datadog": { - "stringValue": json.dumps( - { - "traceparent": "00-0000000000000000000000000000007b-0000000000000141-01", - "tracestate": "dd=s:2;t.dm:-0,rojo=00f067aa0ba902b7,congo=t61rcWkgMzE", - } - ), + "stringValue": json.dumps(headers), "dataType": "String", } }, @@ -443,191 +534,71 @@ def test_with_sqs_distributed_w3c_trace_data(self): } ] } - ctx, source, event_source = extract_dd_trace_context(sqs_event, lambda_ctx) - self.assertEqual(source, "event") - expected_context = Context( - trace_id=123, - span_id=321, - sampling_priority=2, - meta={ - "traceparent": "00-0000000000000000000000000000007b-0000000000000141-01", - "tracestate": "dd=s:2;t.dm:-0,rojo=00f067aa0ba902b7,congo=t61rcWkgMzE", - "_dd.p.dm": "-0", - }, - ) - self.assertEqual(ctx, expected_context) - self.assertDictEqual( - get_dd_trace_context(), - { - "traceparent": "00-0000000000000000000000000000007b-94ae789b969f1cc5-01", - "tracestate": "dd=s:2;t.dm:-0,rojo=00f067aa0ba902b7,congo=t61rcWkgMzE", - }, - ) - create_dd_dummy_metadata_subsegment(ctx, XraySubsegment.TRACE_KEY) - self.mock_send_segment.assert_called_with( - XraySubsegment.TRACE_KEY, - expected_context, - ) + self.common_tests_with_trace_context_extraction_injection(headers, sqs_event) @with_trace_propagation_style("datadog") def test_with_legacy_client_context_datadog_trace_data(self): - lambda_ctx = get_mock_context( - custom={ - "_datadog": { - TraceHeader.TRACE_ID: "666", - TraceHeader.PARENT_ID: "777", - TraceHeader.SAMPLING_PRIORITY: "1", - } - } - ) - ctx, source, event_source = extract_dd_trace_context({}, lambda_ctx) - self.assertEqual(source, "event") - expected_context = Context( - trace_id=666, - span_id=777, - sampling_priority=1, - ) - self.assertEqual(ctx, expected_context) - self.assertDictEqual( - get_dd_trace_context(), - { - TraceHeader.TRACE_ID: "666", - TraceHeader.PARENT_ID: fake_xray_header_value_parent_decimal, - TraceHeader.SAMPLING_PRIORITY: "1", - }, - ) - create_dd_dummy_metadata_subsegment(ctx, XraySubsegment.TRACE_KEY) - self.mock_send_segment.assert_called() - self.mock_send_segment.assert_called_with( - XraySubsegment.TRACE_KEY, - expected_context, + headers = { + TraceHeader.TRACE_ID: "666", + TraceHeader.PARENT_ID: "777", + TraceHeader.SAMPLING_PRIORITY: "1", + } + lambda_ctx = get_mock_context(custom={"_datadog": headers}) + self.common_tests_with_trace_context_extraction_injection( + headers, {}, lambda_ctx ) @with_trace_propagation_style("tracecontext") def test_with_legacy_client_context_w3c_trace_data(self): - lambda_ctx = get_mock_context( - custom={ - "_datadog": { - "traceparent": "00-0000000000000000000000000000029a-0000000000000309-01", - "tracestate": "dd=s:1;t.dm:-0,rojo=00f067aa0ba902b7,congo=t61rcWkgMzE", - } - } - ) - ctx, source, event_source = extract_dd_trace_context({}, lambda_ctx) - self.assertEqual(source, "event") - expected_context = Context( - trace_id=666, - span_id=777, - sampling_priority=1, - meta={ - "traceparent": "00-0000000000000000000000000000029a-0000000000000309-01", - "tracestate": "dd=s:1;t.dm:-0,rojo=00f067aa0ba902b7,congo=t61rcWkgMzE", - "_dd.p.dm": "-0", - }, - ) - self.assertEqual(ctx, expected_context) - self.assertDictEqual( - get_dd_trace_context(), - { - "traceparent": "00-0000000000000000000000000000029a-94ae789b969f1cc5-01", - "tracestate": "dd=s:1;t.dm:-0,rojo=00f067aa0ba902b7,congo=t61rcWkgMzE", - }, - ) - create_dd_dummy_metadata_subsegment(ctx, XraySubsegment.TRACE_KEY) - self.mock_send_segment.assert_called() - self.mock_send_segment.assert_called_with( - XraySubsegment.TRACE_KEY, - expected_context, + headers = { + "traceparent": "00-0000000000000000000000000000029a-0000000000000309-01", + "tracestate": "dd=s:1;t.dm:-0,rojo=00f067aa0ba902b7,congo=t61rcWkgMzE", + } + lambda_ctx = get_mock_context(custom={"_datadog": headers}) + self.common_tests_with_trace_context_extraction_injection( + headers, {}, lambda_ctx ) @with_trace_propagation_style("datadog") def test_with_new_client_context_datadog_trace_data(self): - lambda_ctx = get_mock_context( - custom={ - TraceHeader.TRACE_ID: "666", - TraceHeader.PARENT_ID: "777", - TraceHeader.SAMPLING_PRIORITY: "1", - } - ) - ctx, source, event_source = extract_dd_trace_context({}, lambda_ctx) - self.assertEqual(source, "event") - expected_context = Context( - trace_id=666, - span_id=777, - sampling_priority=1, - ) - self.assertEqual(ctx, expected_context) - self.assertDictEqual( - get_dd_trace_context(), - { - TraceHeader.TRACE_ID: "666", - TraceHeader.PARENT_ID: fake_xray_header_value_parent_decimal, - TraceHeader.SAMPLING_PRIORITY: "1", - }, - ) - create_dd_dummy_metadata_subsegment(ctx, XraySubsegment.TRACE_KEY) - self.mock_send_segment.assert_called() - self.mock_send_segment.assert_called_with( - XraySubsegment.TRACE_KEY, - expected_context, + headers = { + TraceHeader.TRACE_ID: "666", + TraceHeader.PARENT_ID: "777", + TraceHeader.SAMPLING_PRIORITY: "1", + } + lambda_ctx = get_mock_context(custom=headers) + self.common_tests_with_trace_context_extraction_injection( + headers, {}, lambda_ctx ) @with_trace_propagation_style("tracecontext") def test_with_new_client_context_w3c_trace_data(self): - lambda_ctx = get_mock_context( - custom={ - "traceparent": "00-0000000000000000000000000000029a-0000000000000309-01", - "tracestate": "dd=s:1;t.dm:-0,rojo=00f067aa0ba902b7,congo=t61rcWkgMzE", - } - ) - ctx, source, event_source = extract_dd_trace_context({}, lambda_ctx) - self.assertEqual(source, "event") - expected_context = Context( - trace_id=666, - span_id=777, - sampling_priority=1, - meta={ - "traceparent": "00-0000000000000000000000000000029a-0000000000000309-01", - "tracestate": "dd=s:1;t.dm:-0,rojo=00f067aa0ba902b7,congo=t61rcWkgMzE", - "_dd.p.dm": "-0", - }, - ) - self.assertEqual(ctx, expected_context) - self.assertDictEqual( - get_dd_trace_context(), - { - "traceparent": "00-0000000000000000000000000000029a-94ae789b969f1cc5-01", - "tracestate": "dd=s:1;t.dm:-0,rojo=00f067aa0ba902b7,congo=t61rcWkgMzE", - }, - ) - create_dd_dummy_metadata_subsegment(ctx, XraySubsegment.TRACE_KEY) - self.mock_send_segment.assert_called() - self.mock_send_segment.assert_called_with( - XraySubsegment.TRACE_KEY, - expected_context, + headers = { + "traceparent": "00-0000000000000000000000000000029a-0000000000000309-01", + "tracestate": "dd=s:1;t.dm:-0,rojo=00f067aa0ba902b7,congo=t61rcWkgMzE", + } + lambda_ctx = get_mock_context(custom=headers) + self.common_tests_with_trace_context_extraction_injection( + headers, {}, lambda_ctx ) @with_trace_propagation_style("datadog") def test_with_complete_datadog_trace_headers_with_mixed_casing(self): lambda_ctx = get_mock_context() + headers = { + "X-Datadog-Trace-Id": "123", + "X-Datadog-Parent-Id": "321", + "X-Datadog-Sampling-Priority": "1", + } extract_dd_trace_context( - { - "headers": { - "X-Datadog-Trace-Id": "123", - "X-Datadog-Parent-Id": "321", - "X-Datadog-Sampling-Priority": "1", - } - }, + {"headers": headers}, lambda_ctx, ) - self.assertDictEqual( - get_dd_trace_context(), - { - TraceHeader.TRACE_ID: "123", - TraceHeader.PARENT_ID: fake_xray_header_value_parent_decimal, - TraceHeader.SAMPLING_PRIORITY: "1", - }, - ) + extract_headers = {} + context = propagator.extract(headers) + context.span_id = fake_xray_header_value_parent_decimal + propagator.inject(context, extract_headers) + self.assertDictEqual(extract_headers, get_dd_trace_context()) def test_with_complete_datadog_trace_headers_with_trigger_tags(self): trigger_tags = { @@ -650,41 +621,370 @@ def test_with_complete_datadog_trace_headers_with_trigger_tags(self): ] ) - @with_trace_propagation_style("datadog") - def test_step_function_trace_data(self): + def test_request_header_malformed(self): + """Testing that if a RUM AppSync event is malformed, the tracer will attempt + to get the trace context from the lambda context in the + extract_context_from_request_header_or_context function.""" lambda_ctx = get_mock_context() - sqs_event = { - "Execution": { - "Id": "665c417c-1237-4742-aaca-8b3becbb9e75", - }, - "StateMachine": {}, - "State": { - "Name": "my-awesome-state", - "EnteredTime": "Mon Nov 13 12:43:33 PST 2023", + lambda_ctx.client_context = ClientContext( + custom={ + "_datadog": { + "x-datadog-parent-id": "67890", + "x-datadog-sampling-priority": "1", + "x-datadog-trace-id": "12345", + } + } + ) + request_header_event = { + "identity": "None", + "info": { + "fieldName": "getItems", + "parentTypeName": "Query", + "selectionSetGraphQL": "{\n id\n}", + "selectionSetList": ["id"], }, + "prev": "None", + "request": "hello", + "source": "None", } - ctx, source, event_source = extract_dd_trace_context(sqs_event, lambda_ctx) - self.assertEqual(source, "event") + ctx, source, _ = extract_dd_trace_context(request_header_event, lambda_ctx) expected_context = Context( - trace_id=1074655265866231755, - span_id=4776286484851030060, + trace_id=12345, + span_id=67890, sampling_priority=1, ) + self.assertEqual(ctx, expected_context) - self.assertEqual( - get_dd_trace_context(), - { - TraceHeader.TRACE_ID: "1074655265866231755", - TraceHeader.PARENT_ID: fake_xray_header_value_parent_decimal, - TraceHeader.SAMPLING_PRIORITY: "1", - }, - ) - create_dd_dummy_metadata_subsegment(ctx, XraySubsegment.TRACE_KEY) - self.mock_send_segment.assert_called_with( + self.assertEqual(source, "event") + + def _test_step_function_trace_data_common( + self, event, expected_trace_id, expected_span_id, expected_tid + ): + """Common test logic for step function trace data tests""" + lambda_ctx = get_mock_context() + expected_context = Context( + trace_id=expected_trace_id, + span_id=expected_span_id, + sampling_priority=1, + meta={"_dd.p.tid": expected_tid}, + ) + expected_headers = { + TraceHeader.TRACE_ID: str(expected_trace_id), + TraceHeader.PARENT_ID: "10713633173203262661", + TraceHeader.SAMPLING_PRIORITY: "1", + TraceHeader.TAGS: f"_dd.p.tid={expected_tid}", + } + + ctx, source, _ = extract_dd_trace_context(event, lambda_ctx) + + self.assertEqual(source, "event") + self.assertEqual(ctx, expected_context) + self.assertEqual(get_dd_trace_context(), expected_headers) + + create_dd_dummy_metadata_subsegment(ctx, XraySubsegment.TRACE_KEY) + self.mock_send_segment.assert_called_with( XraySubsegment.TRACE_KEY, expected_context, ) + @with_trace_propagation_style("datadog") + def test_step_function_trace_data(self): + """Test basic step function trace data extraction""" + sfn_event = { + "Execution": { + "Id": "arn:aws:states:sa-east-1:425362996713:execution:abhinav-activity-state-machine:72a7ca3e-901c-41bb-b5a3-5f279b92a316", + "Name": "72a7ca3e-901c-41bb-b5a3-5f279b92a316", + "RoleArn": "arn:aws:iam::425362996713:role/service-role/StepFunctions-abhinav-activity-state-machine-role-22jpbgl6j", + "StartTime": "2024-12-04T19:38:04.069Z", + "RedriveCount": 0, + }, + "State": { + "Name": "Lambda Invoke", + "EnteredTime": "2024-12-04T19:38:04.118Z", + "RetryCount": 0, + }, + "StateMachine": { + "Id": "arn:aws:states:sa-east-1:425362996713:stateMachine:abhinav-activity-state-machine", + "Name": "abhinav-activity-state-machine", + }, + } + self._test_step_function_trace_data_common( + sfn_event, 435175499815315247, 3929055471293792800, "3e7a89d1b7310603" + ) + + @with_trace_propagation_style("datadog") + def test_step_function_trace_data_retry(self): + """Test step function trace data extraction with non-zero retry count""" + sfn_event = { + "Execution": { + "Id": "arn:aws:states:sa-east-1:425362996713:execution:abhinav-activity-state-machine:72a7ca3e-901c-41bb-b5a3-5f279b92a316", + "Name": "72a7ca3e-901c-41bb-b5a3-5f279b92a316", + "RoleArn": "arn:aws:iam::425362996713:role/service-role/StepFunctions-abhinav-activity-state-machine-role-22jpbgl6j", + "StartTime": "2024-12-04T19:38:04.069Z", + "RedriveCount": 0, + }, + "State": { + "Name": "Lambda Invoke", + "EnteredTime": "2024-12-04T19:38:04.118Z", + "RetryCount": 1, + }, + "StateMachine": { + "Id": "arn:aws:states:sa-east-1:425362996713:stateMachine:abhinav-activity-state-machine", + "Name": "abhinav-activity-state-machine", + }, + } + self._test_step_function_trace_data_common( + sfn_event, 435175499815315247, 5063839446130725204, "3e7a89d1b7310603" + ) + + # https://github.com/DataDog/logs-backend/blob/65ea567150f24e5498008f3cf8cabef9ea995f5d/domains/serverless/apps/logs-to-traces-reducer/src/test/resources/test-json-files/stepfunctions/RedriveTest/snapshots/RedriveLambdaSuccessTraceMerging.json#L45-L46 + @with_trace_propagation_style("datadog") + def test_step_function_trace_data_redrive(self): + """Test step function trace data extraction with non-zero redrive count""" + sfn_event = { + "Execution": { + "Id": "arn:aws:states:sa-east-1:425362996713:execution:abhinav-activity-state-machine:72a7ca3e-901c-41bb-b5a3-5f279b92a316", + "Name": "72a7ca3e-901c-41bb-b5a3-5f279b92a316", + "RoleArn": "arn:aws:iam::425362996713:role/service-role/StepFunctions-abhinav-activity-state-machine-role-22jpbgl6j", + "StartTime": "2024-12-04T19:38:04.069Z", + "RedriveCount": 1, + }, + "State": { + "Name": "Lambda Invoke", + "EnteredTime": "2024-12-04T19:38:04.118Z", + "RetryCount": 0, + }, + "StateMachine": { + "Id": "arn:aws:states:sa-east-1:425362996713:stateMachine:abhinav-activity-state-machine", + "Name": "abhinav-activity-state-machine", + }, + } + self._test_step_function_trace_data_common( + sfn_event, 435175499815315247, 8782364156266188026, "3e7a89d1b7310603" + ) + + @with_trace_propagation_style("datadog") + def test_step_function_trace_data_lambda_root(self): + """Test JSONata style step function trace data extraction where there's an upstream Lambda""" + sfn_event = { + "_datadog": { + "Execution": { + "Id": "665c417c-1237-4742-aaca-8b3becbb9e75", + "RedriveCount": 0, + }, + "StateMachine": {}, + "State": { + "Name": "my-awesome-state", + "EnteredTime": "Mon Nov 13 12:43:33 PST 2023", + "RetryCount": 0, + }, + "x-datadog-trace-id": "5821803790426892636", + "x-datadog-tags": "_dd.p.dm=-0,_dd.p.tid=672a7cb100000000", + "serverless-version": "v1", + } + } + self._test_step_function_trace_data_common( + sfn_event, 5821803790426892636, 6880978411788117524, "672a7cb100000000" + ) + + @with_trace_propagation_style("datadog") + def test_step_function_trace_data_sfn_root(self): + """Test JSONata style step function trace data extraction where there's an upstream step function""" + sfn_event = { + "_datadog": { + "Execution": { + "Id": "665c417c-1237-4742-aaca-8b3becbb9e75", + "RedriveCount": 0, + }, + "StateMachine": {}, + "State": { + "Name": "my-awesome-state", + "EnteredTime": "Mon Nov 13 12:43:33 PST 2023", + "RetryCount": 0, + }, + "RootExecutionId": "4875aba4-ae31-4a4c-bf8a-63e9eee31dad", + "serverless-version": "v1", + } + } + self._test_step_function_trace_data_common( + sfn_event, 4521899030418994483, 6880978411788117524, "12d1270d99cc5e03" + ) + + @with_trace_propagation_style("datadog") + def test_step_function_trace_data_eventbridge(self): + """Test step function trace data extraction through EventBridge""" + eventbridge_event = { + "version": "0", + "id": "eaacd8db-02de-ab13-ed5a-8ffb84048294", + "detail-type": "StepFunctionTask", + "source": "my.eventbridge", + "account": "425362996713", + "time": "2025-03-13T15:17:34Z", + "region": "sa-east-1", + "resources": [ + "arn:aws:states:sa-east-1:425362996713:stateMachine:abhinav-inner-state-machine", + "arn:aws:states:sa-east-1:425362996713:execution:abhinav-inner-state-machine:912eaa4c-291a-488a-bda3-d06bcc21203d", + ], + "detail": { + "Message": "Hello from Step Functions!", + "TaskToken": "AQCEAAAAKgAAAAMAAAAAAAAAAeMHr6sb8Ll5IKntjIiLGaBkaNeweo84kKYKDTvDaSAP1vjuYRJEGqFdHsKMyZL8ZcgAdanKpkbhPEN5hpoCe+BH9KblWeDsJxkDCk/meN5SaPlC1qS7Q/7/KqBq+tmAOCSy+MjdqFsnihy5Yo6g6C9uuPn7ccSB/609d8pznFm9nigEos/82emwi18lm67/+/bn4RTX4S7qV4RoGWUWUPeHfr34xWOipCt4SVDkoQPZdRVpq3wyRJP2zcK0zup24/opJqKKSCI5Q9orALNB2jEjDyQ9LE4mSrafoe0tcm/bOAGfrcpR3AwtArUiF6JPYd7Nw0XWWyPXFBjiQTJDhZFlGfllJ1N91eiN8wlzUX1+I0vw/t2PoEmuQ2VCJYCbl1ybjX/tQ97GZ9ogjY9N7VYy5uD5xfZ6VAyetUR06HUtbUIXTVxULm7wmsHb979W/fIQXsrxbFzc0+ypKaqGXJBoq7xX//irjpuNhWg1Wgfn0hxuXl5oN/LkqI83T8f9SdnJMxRDpaHDpttqbjVESB/Pf9o7gakjJj12+r2uiJNc81k50uhuHdFOGsImFHKV8hb1LGcq0ZzUKT5SbEDV2k+ezOP+O9Sk4c0unbpNLM3PKLKxVLhu2gtiIIVCHUHGmumW", + "_datadog": { + "Execution": { + "Id": "arn:aws:states:sa-east-1:425362996713:execution:abhinav-inner-state-machine:912eaa4c-291a-488a-bda3-d06bcc21203d", + "StartTime": "2025-03-13T15:17:33.972Z", + "Name": "912eaa4c-291a-488a-bda3-d06bcc21203d", + "RoleArn": "arn:aws:iam::425362996713:role/service-role/StepFunctions-abhinav-activity-state-machine-role-22jpbgl6j", + "RedriveCount": 0, + }, + "StateMachine": { + "Id": "arn:aws:states:sa-east-1:425362996713:stateMachine:abhinav-inner-state-machine", + "Name": "abhinav-inner-state-machine", + }, + "State": { + "Name": "EventBridge PutEvents", + "EnteredTime": "2025-03-13T15:17:34.008Z", + "RetryCount": 0, + }, + "Task": { + "Token": "AQCEAAAAKgAAAAMAAAAAAAAAAeMHr6sb8Ll5IKntjIiLGaBkaNeweo84kKYKDTvDaSAP1vjuYRJEGqFdHsKMyZL8ZcgAdanKpkbhPEN5hpoCe+BH9KblWeDsJxkDCk/meN5SaPlC1qS7Q/7/KqBq+tmAOCSy+MjdqFsnihy5Yo6g6C9uuPn7ccSB/609d8pznFm9nigEos/82emwi18lm67/+/bn4RTX4S7qV4RoGWUWUPeHfr34xWOipCt4SVDkoQPZdRVpq3wyRJP2zcK0zup24/opJqKKSCI5Q9orALNB2jEjDyQ9LE4mSrafoe0tcm/bOAGfrcpR3AwtArUiF6JPYd7Nw0XWWyPXFBjiQTJDhZFlGfllJ1N91eiN8wlzUX1+I0vw/t2PoEmuQ2VCJYCbl1ybjX/tQ97GZ9ogjY9N7VYy5uD5xfZ6VAyetUR06HUtbUIXTVxULm7wmsHb979W/fIQXsrxbFzc0+ypKaqGXJBoq7xX//irjpuNhWg1Wgfn0hxuXl5oN/LkqI83T8f9SdnJMxRDpaHDpttqbjVESB/Pf9o7gakjJj12+r2uiJNc81k50uhuHdFOGsImFHKV8hb1LGcq0ZzUKT5SbEDV2k+ezOP+O9Sk4c0unbpNLM3PKLKxVLhu2gtiIIVCHUHGmumW" + }, + "RootExecutionId": "arn:aws:states:sa-east-1:425362996713:execution:abhinav-inner-state-machine:912eaa4c-291a-488a-bda3-d06bcc21203d", + "serverless-version": "v1", + }, + }, + } + self._test_step_function_trace_data_common( + eventbridge_event, + 3401561763239692811, + 10430178702434539423, + "a49ff3b7fb47b0b", + ) + + @with_trace_propagation_style("datadog") + def test_step_function_trace_data_sqs(self): + """Test step function trace data extraction through SQS""" + sqs_event = { + "Records": [ + { + "EventSource": "aws:sns", + "EventVersion": "1.0", + "EventSubscriptionArn": "arn:aws:sns:sa-east-1:425362996713:logs-to-traces-dev-topic:f1653ba3-2ff7-4c8e-9381-45a7a62f9708", + "Sns": { + "Type": "Notification", + "MessageId": "e39184ea-bfd8-5efa-96fe-e4a64a457ff7", + "TopicArn": "arn:aws:sns:sa-east-1:425362996713:logs-to-traces-dev-topic", + "Subject": None, + "Message": "{}", + "Timestamp": "2025-03-13T15:01:49.942Z", + "SignatureVersion": "1", + "Signature": "WJHKq+pNOLgxa7+dB1dud02RM/30Jvz+KiMZzjRl38/Pphz90H24eGyIbnq3BJXYEyawFCHC6sq/5HcwXouGc5gbah6he+JpqXahMEs6cyMs2tg9SXxooRHEGv5iiZXKhnDcJYOrQ+iFExO9w+WFWfJjO2m/EDVVSYvuDjDV7mmTwAgEOD0zUvWpT7wOeKGG5Uk916Ppy3iMV7sCoHV/RwVikdhCWDDmxbdqteGduAXPdGESE/aj6kUx9ibEOKXyhC+7H1/j0tlhUchl6LZsTf1Gaiq2yEqKXKvsupcG3hRZ6FtIWP0jGlFhpW5EHc2oiHIVOsQceCYPqXYMCZvFuA==", + "SigningCertUrl": "https://sns.sa-east-1.amazonaws.com/SimpleNotificationService-9c6465fa7f48f5cacd23014631ec1136.pem", + "UnsubscribeUrl": "https://sns.sa-east-1.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:sa-east-1:425362996713:logs-to-traces-dev-topic:f1653ba3-2ff7-4c8e-9381-45a7a62f9708", + "MessageAttributes": { + "_datadog": { + "Type": "String", + "Value": '{"Execution":{"Id":"arn:aws:states:sa-east-1:425362996713:execution:abhinav-inner-state-machine:79478846-0cff-44de-91f5-02c96ff65762","StartTime":"2025-03-13T15:01:49.738Z","Name":"79478846-0cff-44de-91f5-02c96ff65762","RoleArn":"arn:aws:iam::425362996713:role/service-role/StepFunctions-abhinav-activity-state-machine-role-22jpbgl6j","RedriveCount":0},"StateMachine":{"Id":"arn:aws:states:sa-east-1:425362996713:stateMachine:abhinav-inner-state-machine","Name":"abhinav-inner-state-machine"},"State":{"Name":"SNS Publish","EnteredTime":"2025-03-13T15:01:49.768Z","RetryCount":0},"RootExecutionId":"arn:aws:states:sa-east-1:425362996713:execution:abhinav-inner-state-machine:79478846-0cff-44de-91f5-02c96ff65762","serverless-version":"v1"}', + } + }, + }, + } + ] + } + self._test_step_function_trace_data_common( + sqs_event, 3818106616964044169, 15912108710769293902, "3a4fd1a254eb514a" + ) + + @with_trace_propagation_style("datadog") + def test_step_function_trace_data_eventbridge_sqs(self): + """Test step function trace data extraction through EventBridge and SQS""" + eventbridge_sqs_event = { + "Records": [ + { + "messageId": "9ed082ad-2f4d-4309-ab99-9553d2be5613", + "receiptHandle": "AQEB6z7FatNIXbWOTC4Bx+udD0flrnT7XMehruTohl8O2KI2t9hvo5oxGIOhwcb+QtS5aRXsFE35TgGE8kZHlHK7Sa8jQUen6XmsPG7qB6BPdXjr0eunM2SDAtLj0mDSKx907VIKRYQG+qpI9ZyNK7Bi786oQIz2UkZGZru9zlXxJtAQiXBqfJ+OfTzhIwkPu04czU6lYfAbxdyNaBNdBEsTNJKPjquvcq1ZBVCHkn9L6wo8jha6XreoeS2WJ5N26ZLKtAl3wlSUByB92OKZU2mEuNboyY7bgK+nkx4N8fVVrafVXnY9YHuq60eQcZ/nusWFeJlVyN7NFypYP2IOn25xylltEACKbgUdEsFU2h5k7yI2DVk5eAt9vB6qmAJlgfkGsXG0SZrCADoIKXl9jpwajw==", + "body": '{"version":"0","id":"ff6d828b-b35e-abdf-64b6-6ea2cf698c0b","detail-type":"StepFunctionTask","source":"my.eventbridge","account":"425362996713","time":"2025-03-13T15:14:21Z","region":"sa-east-1","resources":["arn:aws:states:sa-east-1:425362996713:stateMachine:abhinav-inner-state-machine","arn:aws:states:sa-east-1:425362996713:execution:abhinav-inner-state-machine:fe087266-fe48-4a31-a21b-691f4e7ea985"],"detail":{"Message":"Hello from Step Functions!","TaskToken":"AQCEAAAAKgAAAAMAAAAAAAAAAfi3HMLTw3u9h0vSmkjyHlK1tv5bQUyA7i+6LIvrBWu+3S+DMuQ79JpMtAuCaMN/AGSuGPO7OPeTNA/9v7/kzAsLoPzwPhbrDPXP4SVF1YIO663PvtX/tEWxnAfwLqwDyx8G8VEsVLcmiiOafFCKJwn0OP/DoAWc0sjhWwRxIoQ0ipBGhOqU8rO8SFZVvxUbkosNejnhT7B6314pC89JZLpXU7SxFe+XrgN+uRAvFxsH/+RwDf94xk5hhtukH7HzhJKWN2WCtUISd84pM/1V7ppDuJ3FHgJT22xQIbEGA9Q4o+pLLehzE2SHCdo7eWYQqN+7BanxBNMI6kBMaf5nuh9izAp38lsrmHJyO8NvXgWg+F9hoTZX4RpV9CCwvRFrCRcCeDq4/uJzbvB4AwwA2q2Llm0X8yH0pKvPZ2v7pl4nCWdnEgj920I8AmBCuozbKP7gJRnAqfx3MnOSkpZTeGnHkp0ly8EevwCT2zX/1GQnCAx02kBaDJgUMputFeruMBzwVtlEVBFUUgaWbJwHzz2htuAw282pdATrKfv4VV1N962uLBJ32wd9a92rX7VXXToitvZGIvf/Z7cu4xfAzxQH1rIQ3M4ojkR9r48qoYtnYDlEf+BkIL8L4+xpbRFSBk3p","_datadog":{"Execution":{"Id":"arn:aws:states:sa-east-1:425362996713:execution:abhinav-inner-state-machine:fe087266-fe48-4a31-a21b-691f4e7ea985","StartTime":"2025-03-13T15:14:21.730Z","Name":"fe087266-fe48-4a31-a21b-691f4e7ea985","RoleArn":"arn:aws:iam::425362996713:role/service-role/StepFunctions-abhinav-activity-state-machine-role-22jpbgl6j","RedriveCount":0},"StateMachine":{"Id":"arn:aws:states:sa-east-1:425362996713:stateMachine:abhinav-inner-state-machine","Name":"abhinav-inner-state-machine"},"State":{"Name":"EventBridge PutEvents","EnteredTime":"2025-03-13T15:14:21.765Z","RetryCount":0},"Task":{"Token":"AQCEAAAAKgAAAAMAAAAAAAAAAfi3HMLTw3u9h0vSmkjyHlK1tv5bQUyA7i+6LIvrBWu+3S+DMuQ79JpMtAuCaMN/AGSuGPO7OPeTNA/9v7/kzAsLoPzwPhbrDPXP4SVF1YIO663PvtX/tEWxnAfwLqwDyx8G8VEsVLcmiiOafFCKJwn0OP/DoAWc0sjhWwRxIoQ0ipBGhOqU8rO8SFZVvxUbkosNejnhT7B6314pC89JZLpXU7SxFe+XrgN+uRAvFxsH/+RwDf94xk5hhtukH7HzhJKWN2WCtUISd84pM/1V7ppDuJ3FHgJT22xQIbEGA9Q4o+pLLehzE2SHCdo7eWYQqN+7BanxBNMI6kBMaf5nuh9izAp38lsrmHJyO8NvXgWg+F9hoTZX4RpV9CCwvRFrCRcCeDq4/uJzbvB4AwwA2q2Llm0X8yH0pKvPZ2v7pl4nCWdnEgj920I8AmBCuozbKP7gJRnAqfx3MnOSkpZTeGnHkp0ly8EevwCT2zX/1GQnCAx02kBaDJgUMputFeruMBzwVtlEVBFUUgaWbJwHzz2htuAw282pdATrKfv4VV1N962uLBJ32wd9a92rX7VXXToitvZGIvf/Z7cu4xfAzxQH1rIQ3M4ojkR9r48qoYtnYDlEf+BkIL8L4+xpbRFSBk3p"},"RootExecutionId":"arn:aws:states:sa-east-1:425362996713:execution:abhinav-inner-state-machine:fe087266-fe48-4a31-a21b-691f4e7ea985","serverless-version":"v1"}}}', + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "1741878862068", + "SenderId": "AROAWGCM4HXUUNHLDXVER:6145b5ba998f311c8ac27f5cade2b915", + "ApproximateFirstReceiveTimestamp": "1741878862075", + }, + "messageAttributes": {}, + "md5OfBody": "e5cf8197b304a4dd4fd5db8e4842484b", + "eventSource": "aws:sqs", + "eventSourceARN": "arn:aws:sqs:sa-east-1:425362996713:abhinav-q", + "awsRegion": "sa-east-1", + } + ] + } + self._test_step_function_trace_data_common( + eventbridge_sqs_event, + 6527209323865742984, + 14276854885394865473, + "2ee7d9862d048173", + ) + + @with_trace_propagation_style("datadog") + def test_step_function_trace_data_sns(self): + """Test step function trace data extraction through SNS""" + sns_event = { + "Records": [ + { + "EventSource": "aws:sns", + "EventVersion": "1.0", + "EventSubscriptionArn": "arn:aws:sns:sa-east-1:425362996713:logs-to-traces-dev-topic:f1653ba3-2ff7-4c8e-9381-45a7a62f9708", + "Sns": { + "Type": "Notification", + "MessageId": "7bc0c17d-bf88-5ff4-af7f-a131463a0d90", + "TopicArn": "arn:aws:sns:sa-east-1:425362996713:logs-to-traces-dev-topic", + "Subject": None, + "Message": "{}", + "Timestamp": "2025-03-13T15:19:14.245Z", + "SignatureVersion": "1", + "Signature": "r8RoYzq4uNcq0yj7sxcp8sTbFiDk8zqtocG7mJuE2MPVuR8O5eNg2ohofokUnC84xADlCq5k6ElP55lbbY36tQO+qDGdV6+TGN4bAL9FiQrDE6tQYYJdlv/sYE7iOOgnRBC9ljEdCIDNtQNGCfND/8JzatPg8KAy7xMRcLrGWu4xIMEysqNTz7rETfhdZjLQPssAht44KcoUJCH4/VuB+B9W1RhwA+M8Q3tqxzahIXzcgDM8OlmfkBlXo4FDVF3WUzjXLf9AMOg+66GupjQFtUpmRMkA8KXSV1HCso7e6nIIWtOnUoWeDDUfQPFFq4TNSlb6h2NuebaHdnW5nhxnJQ==", + "SigningCertUrl": "https://sns.sa-east-1.amazonaws.com/SimpleNotificationService-9c6465fa7f48f5cacd23014631ec1136.pem", + "UnsubscribeUrl": "https://sns.sa-east-1.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:sa-east-1:425362996713:logs-to-traces-dev-topic:f1653ba3-2ff7-4c8e-9381-45a7a62f9708", + "MessageAttributes": { + "_datadog": { + "Type": "String", + "Value": '{"Execution":{"Id":"arn:aws:states:sa-east-1:425362996713:execution:abhinav-inner-state-machine:11623e4f-70ee-4330-8fbe-955152dea54c","StartTime":"2025-03-13T15:19:14.019Z","Name":"11623e4f-70ee-4330-8fbe-955152dea54c","RoleArn":"arn:aws:iam::425362996713:role/service-role/StepFunctions-abhinav-activity-state-machine-role-22jpbgl6j","RedriveCount":0},"StateMachine":{"Id":"arn:aws:states:sa-east-1:425362996713:stateMachine:abhinav-inner-state-machine","Name":"abhinav-inner-state-machine"},"State":{"Name":"SNS Publish","EnteredTime":"2025-03-13T15:19:14.061Z","RetryCount":0},"RootExecutionId":"arn:aws:states:sa-east-1:425362996713:execution:abhinav-inner-state-machine:11623e4f-70ee-4330-8fbe-955152dea54c","serverless-version":"v1"}', + } + }, + }, + } + ] + } + self._test_step_function_trace_data_common( + sns_event, 1459500239678510857, 13193042003602978730, "fafc98885fd4647" + ) + + @with_trace_propagation_style("datadog") + def test_step_function_trace_data_sns_sqs(self): + """Test step function trace data extraction through SNS and SQS""" + sns_sqs_event = { + "Records": [ + { + "messageId": "9ec3339f-cd1a-43ba-9681-3e9113b430d3", + "receiptHandle": "AQEBJ5gIvqEWQt39NHPMAoK57cGgKtrgTtckWeWdDRi2FeucYr6pBhNjzXuUrmoHZMozX1WaoABtfQ5+kX5ucDBpA2Ci3Q07Z4MYvA6X0Sw13HCkiBnLrHPmH/F3rUBjvdRkIIKqA2ACX58MdkaYGNpqsHTJHB613wa8z4zurK0u7eUIXrr+e+gtsuPD39hiWlJo7cpBVv7y178rzMX8gPQTnRJv1cjhCHENtjWTSmfFC5N+BIQNIcjFsTTDRSovZlNIfAEuS+uowgzk0DUyoTJD5nFTL8lQHeXGRCUQe58/UY9OwRXEFVPGZOQR4OI9Wa4Kf/keFypTk9YwC9DhSeKvzZ0wBvejyl1n0ztT45+XYoWfi0mxGWM5b7r9wT36RDmjnM6vszH/d3fhZSRPASxWBQ==", + "body": '{\n "Type" : "Notification",\n "MessageId" : "1f3078d0-c792-5cf3-a130-189c3b846a3f",\n "TopicArn" : "arn:aws:sns:sa-east-1:425362996713:logs-to-traces-dev-topic",\n "Message" : "{}",\n "Timestamp" : "2025-03-13T15:29:26.348Z",\n "SignatureVersion" : "1",\n "Signature" : "mxOqAQ5o/isJrMS0PezHKRaA3g8Z/8YDbkToqhJub6I66LGtl+NYhyfTyllbgxvRP2XD2meKPRSgPI3nLyq8UHsWgyYwe3Tsv8QpRunCVE9Pebh+V1LGPWfjOiL0e+bnaj956QJD99560LJ6bzWP9QO584/zfOdcw6E5XQZfAI+pvEsf28Dy0WJO/lWTATRZDf8wGhmc7uKI1ZMsrOaNoUD8PXVqsI4yrJHxhzMb3SrC7YjI/PnNIbcn6ezwprbUdbZvyNAfJiE0k5IlppA089tMXC/ItgC7AgQhG9huPdKi5KdWGACK7gEwqmFwL+5T33sUXDaH2g58WhCs76pKEw==",\n "SigningCertURL" : "https://sns.sa-east-1.amazonaws.com/SimpleNotificationService-9c6465fa7f48f5cacd23014631ec1136.pem",\n "UnsubscribeURL" : "https://sns.sa-east-1.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:sa-east-1:425362996713:logs-to-traces-dev-topic:5f64545d-ae9a-4a5f-a7ee-798a0bd8519e",\n "MessageAttributes" : {\n "_datadog" : {"Type":"String","Value":"{\\"Execution\\":{\\"Id\\":\\"arn:aws:states:sa-east-1:425362996713:execution:abhinav-inner-state-machine:37ff72b8-0ee0-49e2-93c0-8a1764206a03\\",\\"StartTime\\":\\"2025-03-13T15:29:26.144Z\\",\\"Name\\":\\"37ff72b8-0ee0-49e2-93c0-8a1764206a03\\",\\"RoleArn\\":\\"arn:aws:iam::425362996713:role/service-role/StepFunctions-abhinav-activity-state-machine-role-22jpbgl6j\\",\\"RedriveCount\\":0},\\"StateMachine\\":{\\"Id\\":\\"arn:aws:states:sa-east-1:425362996713:stateMachine:abhinav-inner-state-machine\\",\\"Name\\":\\"abhinav-inner-state-machine\\"},\\"State\\":{\\"Name\\":\\"SNS Publish\\",\\"EnteredTime\\":\\"2025-03-13T15:29:26.182Z\\",\\"RetryCount\\":0},\\"RootExecutionId\\":\\"arn:aws:states:sa-east-1:425362996713:execution:abhinav-inner-state-machine:37ff72b8-0ee0-49e2-93c0-8a1764206a03\\",\\"serverless-version\\":\\"v1\\"}"}\n }\n}', + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "1741879766424", + "SenderId": "AIDAIOA2GYWSHW4E2VXIO", + "ApproximateFirstReceiveTimestamp": "1741879766432", + }, + "messageAttributes": {}, + "md5OfBody": "52af59de28507d7e67324b46c95337d8", + "eventSource": "aws:sqs", + "eventSourceARN": "arn:aws:sqs:sa-east-1:425362996713:abhinav-q", + "awsRegion": "sa-east-1", + } + ] + } + self._test_step_function_trace_data_common( + sns_sqs_event, 5708348677301000120, 18223515719478572006, "45457f5f3fde3fa1" + ) + class TestXRayContextConversion(unittest.TestCase): def test_convert_xray_trace_id(self): @@ -731,11 +1031,12 @@ def setUp(self): ) self.addCleanup(patcher.stop) - patcher = patch("datadog_lambda.tracing.is_lambda_context") + patcher = patch("datadog_lambda.config.Config.is_lambda_context") self.mock_is_lambda_context = patcher.start() self.mock_is_lambda_context.return_value = True self.addCleanup(patcher.stop) + @patch("datadog_lambda.config.Config.trace_enabled", False) def test_set_correlation_ids(self): set_correlation_ids() span = tracer.current_span() @@ -756,12 +1057,20 @@ class TestFunctionSpanTags(unittest.TestCase): def test_function(self): ctx = get_mock_context() span = create_function_execution_span( - ctx, "", False, False, {"source": ""}, False, {} + context=ctx, + function_name="", + is_cold_start=False, + is_proactive_init=False, + trace_context_source={"source": ""}, + merge_xray_traces=False, + trigger_tags={}, + span_pointers=None, ) self.assertEqual(span.get_tag("function_arn"), function_arn) self.assertEqual(span.get_tag("function_version"), "$LATEST") self.assertEqual(span.get_tag("resource_names"), "Function") self.assertEqual(span.get_tag("functionname"), "function") + self.assertEqual(span._links, []) def test_function_with_version(self): function_version = "1" @@ -769,7 +1078,13 @@ def test_function_with_version(self): invoked_function_arn=function_arn + ":" + function_version ) span = create_function_execution_span( - ctx, "", False, False, {"source": ""}, False, {} + context=ctx, + function_name="", + is_cold_start=False, + is_proactive_init=False, + trace_context_source={"source": ""}, + merge_xray_traces=False, + trigger_tags={}, ) self.assertEqual(span.get_tag("function_arn"), function_arn) self.assertEqual(span.get_tag("function_version"), function_version) @@ -780,7 +1095,13 @@ def test_function_with_alias(self): function_alias = "alias" ctx = get_mock_context(invoked_function_arn=function_arn + ":" + function_alias) span = create_function_execution_span( - ctx, "", False, False, {"source": ""}, False, {} + context=ctx, + function_name="", + is_cold_start=False, + is_proactive_init=False, + trace_context_source={"source": ""}, + merge_xray_traces=False, + trigger_tags={}, ) self.assertEqual(span.get_tag("function_arn"), function_arn) self.assertEqual(span.get_tag("function_version"), function_alias) @@ -790,13 +1111,13 @@ def test_function_with_alias(self): def test_function_with_trigger_tags(self): ctx = get_mock_context() span = create_function_execution_span( - ctx, - "", - False, - False, - {"source": ""}, - False, - {"function_trigger.event_source": "cloudwatch-logs"}, + context=ctx, + function_name="", + is_cold_start=False, + is_proactive_init=False, + trace_context_source={"source": ""}, + merge_xray_traces=False, + trigger_tags={"function_trigger.event_source": "cloudwatch-logs"}, ) self.assertEqual(span.get_tag("function_arn"), function_arn) self.assertEqual(span.get_tag("resource_names"), "Function") @@ -805,16 +1126,57 @@ def test_function_with_trigger_tags(self): span.get_tag("function_trigger.event_source"), "cloudwatch-logs" ) + def test_function_with_span_pointers(self): + ctx = get_mock_context() + span = create_function_execution_span( + context=ctx, + function_name="", + is_cold_start=False, + is_proactive_init=False, + trace_context_source={"source": ""}, + merge_xray_traces=False, + trigger_tags={}, + span_pointers=[ + _SpanPointerDescription( + pointer_kind="some.kind", + pointer_direction=_SpanPointerDirection.UPSTREAM, + pointer_hash="some.hash", + extra_attributes={}, + ), + _SpanPointerDescription( + pointer_kind="other.kind", + pointer_direction=_SpanPointerDirection.DOWNSTREAM, + pointer_hash="other.hash", + extra_attributes={"extra": "stuff"}, + ), + ], + ) + self.assertEqual( + span._links, + [ + _SpanPointer( + pointer_kind="some.kind", + pointer_direction=_SpanPointerDirection.UPSTREAM, + pointer_hash="some.hash", + extra_attributes={}, + ), + _SpanPointer( + pointer_kind="other.kind", + pointer_direction=_SpanPointerDirection.DOWNSTREAM, + pointer_hash="other.hash", + extra_attributes={"extra": "stuff"}, + ), + ], + ) + class TestSetTraceRootSpan(unittest.TestCase): def setUp(self): - global dd_tracing_enabled - dd_tracing_enabled = False os.environ["_X_AMZN_TRACE_ID"] = fake_xray_header_value patcher = patch("datadog_lambda.tracing.send_segment") self.mock_send_segment = patcher.start() self.addCleanup(patcher.stop) - patcher = patch("datadog_lambda.tracing.is_lambda_context") + patcher = patch("datadog_lambda.config.Config.is_lambda_context") self.mock_is_lambda_context = patcher.start() self.mock_is_lambda_context.return_value = True self.addCleanup(patcher.stop) @@ -822,10 +1184,11 @@ def setUp(self): self.mock_activate = patcher.start() self.mock_activate.return_value = True self.addCleanup(patcher.stop) + patcher = patch("datadog_lambda.tracing.dd_trace_context", None) + self.mock_dd_trace_context = patcher.start() + self.addCleanup(patcher.stop) def tearDown(self): - global dd_tracing_enabled - dd_tracing_enabled = False del os.environ["_X_AMZN_TRACE_ID"] def test_mixed_parent_context_when_merging(self): @@ -879,159 +1242,9 @@ def test_set_dd_trace_py_root_no_span_id(self): self.mock_activate.assert_called() self.mock_activate.assert_has_calls([call(expected_context)]) - -class TestAuthorizerInferredSpans(unittest.TestCase): - def setUp(self): - patcher = patch("ddtrace.Span.finish", autospec=True) - self.mock_span_stop = patcher.start() - self.addCleanup(patcher.stop) - - def tearDown(self): - _clean_up_span() - - def test_create_inferred_span_from_authorizer_request_api_gateway_v1_event(self): - event_sample_source = "authorizer-request-api-gateway-v1" - finish_time = ( - 1663295021.832 # request_time_epoch + integrationLatency for api-gateway-v1 - ) - span = self._authorizer_span_testing_items(event_sample_source, finish_time) - self._basic_common_checks(span, "aws.apigateway.rest") - - def test_create_inferred_span_from_authorizer_request_api_gateway_v1_cached_event( - self, - ): - event_sample_source = "authorizer-request-api-gateway-v1-cached" - test_file = event_samples + event_sample_source + ".json" - with open(test_file, "r") as event: - event = json.load(event) - ctx = get_mock_context() - ctx.aws_request_id = "abc123" # injected data's requestId is abc321 - span = create_inferred_span(event, ctx) - self.mock_span_stop.assert_not_called() # NO authorizer span is injected - self._basic_common_checks(span, "aws.apigateway.rest") - - def test_create_inferred_span_from_authorizer_token_api_gateway_v1_event(self): - event_sample_source = "authorizer-token-api-gateway-v1" - finish_time = ( - 1663295021.832 # request_time_epoch + integrationLatency for api-gateway-v1 - ) - span = self._authorizer_span_testing_items(event_sample_source, finish_time) - self._basic_common_checks(span, "aws.apigateway.rest") - - def test_create_inferred_span_from_authorizer_token_api_gateway_v2_cached_event( - self, - ): - event_sample_source = "authorizer-token-api-gateway-v1-cached" - test_file = event_samples + event_sample_source + ".json" - with open(test_file, "r") as event: - event = json.load(event) - ctx = get_mock_context() - ctx.aws_request_id = "abc123" # injected data's requestId is abc321 - span = create_inferred_span(event, ctx) - self.mock_span_stop.assert_not_called() # NO authorizer span is injected - self._basic_common_checks(span, "aws.apigateway.rest") - - def test_create_inferred_span_from_authorizer_request_api_gateway_v2_event(self): - event_sample_source = "authorizer-request-api-gateway-v2" - finish_time = 1664228639533775400 # use the injected parent span finish time as an approximation - test_file = event_samples + event_sample_source + ".json" - with open(test_file, "r") as event: - event = json.load(event) - ctx = get_mock_context() - ctx.aws_request_id = "abc123" - span = create_inferred_span(event, ctx) - self.assertEqual(span.get_tag(InferredSpanInfo.TAG_SOURCE), "self") - self.assertEqual(span.get_tag(InferredSpanInfo.SYNCHRONICITY), "sync") - self.mock_span_stop.assert_not_called() - self.assertEqual(span.start_ns, finish_time) - self._basic_common_checks(span, "aws.httpapi") - - def test_create_inferred_span_from_authorizer_request_api_gateway_v2_cached_event( - self, - ): - event_sample_source = "authorizer-request-api-gateway-v2-cached" - test_file = event_samples + event_sample_source + ".json" - with open(test_file, "r") as event: - event = json.load(event) - ctx = get_mock_context() - ctx.aws_request_id = "abc123" # injected data's requestId is abc321 - span = create_inferred_span(event, ctx) - self.mock_span_stop.assert_not_called() # NO authorizer span is injected - self._basic_common_checks(span, "aws.httpapi") - - def test_create_inferred_span_from_authorizer_request_api_gateway_websocket_connect_event( - self, - ): - event_sample_source = "authorizer-request-api-gateway-websocket-connect" - finish_time = ( - 1664388386.892 # request_time_epoch + integrationLatency in websocket case - ) - span = self._authorizer_span_testing_items(event_sample_source, finish_time) - self._basic_common_checks( - span, "aws.apigateway.websocket", "web", "$connect", None - ) - - def test_create_inferred_span_from_authorizer_request_api_gateway_websocket_message_event( - self, - ): - event_sample_source = "authorizer-request-api-gateway-websocket-message" - test_file = event_samples + event_sample_source + ".json" - with open(test_file, "r") as event: - event = json.load(event) - ctx = get_mock_context() - ctx.aws_request_id = "abc123" # injected data's requestId is abc321 - span = create_inferred_span(event, ctx) - self.mock_span_stop.assert_not_called() # NO authorizer span is injected - self._basic_common_checks(span, "aws.apigateway.websocket", "web", "main", None) - - def _authorizer_span_testing_items(self, event_sample_source, finish_time): - test_file = event_samples + event_sample_source + ".json" - with open(test_file, "r") as event: - event = json.load(event) - ctx = get_mock_context() - ctx.aws_request_id = "abc123" - span = create_inferred_span(event, ctx) - self.assertEqual(span.get_tag(InferredSpanInfo.TAG_SOURCE), "self") - self.assertEqual(span.get_tag(InferredSpanInfo.SYNCHRONICITY), "sync") - - # checking the upstream_authorizer_span - self.mock_span_stop.assert_called_once() - args, kwargs = self.mock_span_stop.call_args_list[0] - self.assertEqual(kwargs.get("finish_time", args[1]), finish_time) - self.assertEqual(span.start, finish_time) - authorizer_span = args[0] - self.assertEqual(authorizer_span.name, "aws.apigateway.authorizer") - self.assertEqual(span.parent_id, authorizer_span.span_id) - return span - - def _basic_common_checks( - self, - span, - operation_name, - span_type="http", - route_key="/hello", - http_method="GET", - ): - self.assertEqual(span.get_tag("apiid"), "amddr1rix9") - self.assertEqual(span.get_tag("apiname"), "amddr1rix9") - self.assertEqual(span.get_tag("stage"), "dev") - self.assertEqual(span.get_tag("operation_name"), operation_name) - self.assertEqual(span.span_type, span_type) - self.assertEqual( - span.service, - "amddr1rix9.execute-api.eu-west-1.amazonaws.com", - ) - self.assertEqual( - span.get_tag("http.url"), - "amddr1rix9.execute-api.eu-west-1.amazonaws.com" + route_key, - ) - self.assertEqual(span.get_tag("endpoint"), route_key) - self.assertEqual(span.get_tag("http.method"), http_method) - self.assertEqual( - span.get_tag("resource_names"), - f"{http_method} {route_key}" if http_method else route_key, - ) - self.assertEqual(span.get_tag("request_id"), "abc123") + def test_set_dd_trace_py_root_none_context(self): + set_dd_trace_py_root(TraceContextSource.EVENT, True) + self.mock_activate.assert_not_called() class TestServiceMapping(unittest.TestCase): @@ -1076,6 +1289,7 @@ def test_get_service_mapping(self): create_service_mapping(os.environ["DD_SERVICE_MAPPING"]) ) self.assertEqual(self.get_service_mapping(), expected_output) + del os.environ["DD_SERVICE_MAPPING"] def test_set_service_mapping(self): new_service_mapping = {"api3": "service3", "api4": "service4"} @@ -1116,6 +1330,44 @@ def test_determine_service_name(self): "default", ) + # Test with DD_TRACE_AWS_SERVICE_REPRESENTATION_ENABLED set to false + os.environ["DD_TRACE_AWS_SERVICE_REPRESENTATION_ENABLED"] = "false" + self.assertEqual( + determine_service_name( + self.get_service_mapping(), "api4", "api4", "extracted", "fallback" + ), + "fallback", + ) + + # Test with DD_TRACE_AWS_SERVICE_REPRESENTATION_ENABLED set to 0 + os.environ["DD_TRACE_AWS_SERVICE_REPRESENTATION_ENABLED"] = "0" + self.assertEqual( + determine_service_name( + self.get_service_mapping(), "api4", "api4", "extracted", "fallback" + ), + "fallback", + ) + + # Test with DD_TRACE_AWS_SERVICE_REPRESENTATION_ENABLED not set (default behavior) + if "DD_TRACE_AWS_SERVICE_REPRESENTATION_ENABLED" in os.environ: + del os.environ["DD_TRACE_AWS_SERVICE_REPRESENTATION_ENABLED"] + self.assertEqual( + determine_service_name( + self.get_service_mapping(), "api4", "api4", "extracted", "fallback" + ), + "extracted", + ) + + # Test with empty extracted key + self.assertEqual( + determine_service_name( + self.get_service_mapping(), "api4", "api4", " ", "fallback" + ), + "fallback", + ) + + del os.environ["DD_SERVICE_MAPPING"] + def test_remaps_all_inferred_span_service_names_from_api_gateway_event(self): new_service_mapping = {"lambda_api_gateway": "new-name"} self.set_service_mapping(new_service_mapping) @@ -1308,7 +1560,7 @@ def test_remaps_specific_inferred_span_service_names_from_sqs_event(self): ] = "arn:aws:sqs:eu-west-1:123456789012:different-sqs-url" span2 = create_inferred_span(event2, ctx) self.assertEqual(span2.get_tag("operation_name"), "aws.sqs") - self.assertEqual(span2.service, "sqs") + self.assertEqual(span2.service, "different-sqs-url") def test_remaps_all_inferred_span_service_names_from_sns_event(self): self.set_service_mapping({"lambda_sns": "new-name"}) @@ -1354,7 +1606,7 @@ def test_remaps_specific_inferred_span_service_names_from_sns_event(self): ] = "arn:aws:sns:us-west-2:123456789012:different-sns-topic" span2 = create_inferred_span(event2, ctx) self.assertEqual(span2.get_tag("operation_name"), "aws.sns") - self.assertEqual(span2.service, "sns") + self.assertEqual(span2.service, "different-sns-topic") def test_remaps_all_inferred_span_service_names_from_kinesis_event(self): self.set_service_mapping({"lambda_kinesis": "new-name"}) @@ -1391,7 +1643,7 @@ def test_remaps_specific_inferred_span_service_names_from_kinesis_event(self): span1 = create_inferred_span(original_event, ctx) self.assertEqual(span1.get_tag("operation_name"), "aws.kinesis") - self.assertEqual(span1.service, "kinesis") + self.assertEqual(span1.service, "kinesisStream") # Testing the second event event2 = copy.deepcopy(original_event) @@ -1400,7 +1652,7 @@ def test_remaps_specific_inferred_span_service_names_from_kinesis_event(self): ] = "arn:aws:kinesis:eu-west-1:601427279990:stream/DifferentKinesisStream" span2 = create_inferred_span(event2, ctx) self.assertEqual(span2.get_tag("operation_name"), "aws.kinesis") - self.assertEqual(span2.service, "kinesis") + self.assertEqual(span2.service, "DifferentKinesisStream") def test_remaps_all_inferred_span_service_names_from_s3_event(self): self.set_service_mapping({"lambda_s3": "new-name"}) @@ -1444,7 +1696,7 @@ def test_remaps_specific_inferred_span_service_names_from_s3_event(self): event2["Records"][0]["s3"]["bucket"]["name"] = "different-example-bucket" span2 = create_inferred_span(event2, ctx) self.assertEqual(span2.get_tag("operation_name"), "aws.s3") - self.assertEqual(span2.service, "s3") + self.assertEqual(span2.service, "different-example-bucket") def test_remaps_all_inferred_span_service_names_from_dynamodb_event(self): self.set_service_mapping({"lambda_dynamodb": "new-name"}) @@ -1490,7 +1742,7 @@ def test_remaps_specific_inferred_span_service_names_from_dynamodb_event(self): ] = "arn:aws:dynamodb:us-east-1:123456789012:table/DifferentExampleTableWithStream/stream/2015-06-27T00:48:05.899" span2 = create_inferred_span(event2, ctx) self.assertEqual(span2.get_tag("operation_name"), "aws.dynamodb") - self.assertEqual(span2.service, "dynamodb") + self.assertEqual(span2.service, "DifferentExampleTableWithStream") def test_remaps_all_inferred_span_service_names_from_eventbridge_event(self): self.set_service_mapping({"lambda_eventbridge": "new-name"}) @@ -1534,736 +1786,1667 @@ def test_remaps_specific_inferred_span_service_names_from_eventbridge_event( event2["source"] = "different.eventbridge.custom.event.sender" span2 = create_inferred_span(event2, ctx) self.assertEqual(span2.get_tag("operation_name"), "aws.eventbridge") - self.assertEqual(span2.service, "eventbridge") + self.assertEqual(span2.service, "different.eventbridge.custom.event.sender") + + +class _Span(object): + def __init__(self, service, start, span_type, parent_name=None, tags=None): + self.service = service + self.start = start + self.span_type = span_type + self.parent_name = parent_name + self.tags = tags or {} + + +_test_create_inferred_span = ( + ( + "api-gateway", + _Span( + service="70ixmpl4fl.execute-api.us-east-2.amazonaws.com", + start=1428582896.0, + span_type="http", + tags={ + "_dd.origin": "lambda", + "_inferred_span.synchronicity": "sync", + "_inferred_span.tag_source": "self", + "apiid": "1234567890", + "apiname": "1234567890", + "endpoint": "/path/to/resource", + "http.method": "POST", + "http.url": "https://70ixmpl4fl.execute-api.us-east-2.amazonaws.com/path/to/resource", + "operation_name": "aws.apigateway.rest", + "request_id": "123", + "resource_names": "POST /{proxy+}", + "stage": "prod", + }, + ), + ), + ( + "api-gateway-non-proxy-async", + _Span( + service="lgxbo6a518.execute-api.eu-west-1.amazonaws.com", + start=1631210915.2510002, + span_type="http", + tags={ + "_dd.origin": "lambda", + "_inferred_span.synchronicity": "async", + "_inferred_span.tag_source": "self", + "apiid": "lgxbo6a518", + "apiname": "lgxbo6a518", + "endpoint": "/http/get", + "http.method": "GET", + "http.url": "https://lgxbo6a518.execute-api.eu-west-1.amazonaws.com/http/get", + "operation_name": "aws.apigateway.rest", + "request_id": "123", + "resource_names": "GET /http/get", + "stage": "dev", + }, + ), + ), + ( + "api-gateway-non-proxy", + _Span( + service="lgxbo6a518.execute-api.eu-west-1.amazonaws.com", + start=1631210915.2510002, + span_type="http", + tags={ + "_dd.origin": "lambda", + "_inferred_span.synchronicity": "sync", + "_inferred_span.tag_source": "self", + "apiid": "lgxbo6a518", + "apiname": "lgxbo6a518", + "endpoint": "/http/get", + "http.method": "GET", + "http.url": "https://lgxbo6a518.execute-api.eu-west-1.amazonaws.com/http/get", + "operation_name": "aws.apigateway.rest", + "request_id": "123", + "resource_names": "GET /http/get", + "stage": "dev", + }, + ), + ), + ( + "http-api", + _Span( + service="x02yirxc7a.execute-api.eu-west-1.amazonaws.com", + start=1631212283.738, + span_type="http", + tags={ + "_dd.origin": "lambda", + "_inferred_span.synchronicity": "sync", + "_inferred_span.tag_source": "self", + "apiid": "x02yirxc7a", + "apiname": "x02yirxc7a", + "endpoint": "/httpapi/get", + "http.method": "GET", + "http.protocol": "HTTP/1.1", + "http.source_ip": "38.122.226.210", + "http.url": "https://x02yirxc7a.execute-api.eu-west-1.amazonaws.com/httpapi/get", + "http.user_agent": "curl/7.64.1", + "operation_name": "aws.httpapi", + "request_id": "123", + "resource_names": "GET /httpapi/get", + "stage": "$default", + }, + ), + ), + ( + "api-gateway-v1-parametrized", + _Span( + service="mcwkra0ya4.execute-api.sa-east-1.amazonaws.com", + start=1710529824.52, + span_type="http", + tags={ + "_dd.origin": "lambda", + "_inferred_span.synchronicity": "sync", + "_inferred_span.tag_source": "self", + "apiid": "mcwkra0ya4", + "apiname": "mcwkra0ya4", + "endpoint": "/user/42", + "http.method": "GET", + "http.url": "https://mcwkra0ya4.execute-api.sa-east-1.amazonaws.com/user/42", + "operation_name": "aws.apigateway.rest", + "request_id": "123", + "resource_names": "GET /user/{id}", + "stage": "dev", + }, + ), + ), + ( + "api-gateway-v2-parametrized", + _Span( + service="9vj54we5ih.execute-api.sa-east-1.amazonaws.com", + start=1710529905.066, + span_type="http", + tags={ + "_dd.origin": "lambda", + "_inferred_span.synchronicity": "sync", + "_inferred_span.tag_source": "self", + "apiid": "9vj54we5ih", + "apiname": "9vj54we5ih", + "endpoint": "/user/42", + "http.method": "GET", + "http.url": "https://9vj54we5ih.execute-api.sa-east-1.amazonaws.com/user/42", + "operation_name": "aws.httpapi", + "request_id": "123", + "resource_names": "GET /user/{id}", + "stage": "$default", + }, + ), + ), + ( + "api-gateway-websocket-default", + _Span( + service="p62c47itsb.execute-api.eu-west-1.amazonaws.com", + start=1631285061.365, + span_type="web", + tags={ + "_dd.origin": "lambda", + "_inferred_span.synchronicity": "sync", + "_inferred_span.tag_source": "self", + "apiid": "p62c47itsb", + "apiname": "p62c47itsb", + "connection_id": "Fc5SzcoYGjQCJlg=", + "endpoint": "$default", + "event_type": "MESSAGE", + "http.url": "https://p62c47itsb.execute-api.eu-west-1.amazonaws.com$default/", + "message_direction": "IN", + "operation_name": "aws.apigateway.websocket", + "request_id": "123", + "resource_names": "$default", + "stage": "dev", + }, + ), + ), + ( + "api-gateway-websocket-connect", + _Span( + service="p62c47itsb.execute-api.eu-west-1.amazonaws.com", + start=1631284003.071, + span_type="web", + tags={ + "_dd.origin": "lambda", + "_inferred_span.synchronicity": "sync", + "_inferred_span.tag_source": "self", + "apiid": "p62c47itsb", + "apiname": "p62c47itsb", + "connection_id": "Fc2tgfl3mjQCJfA=", + "endpoint": "$connect", + "event_type": "CONNECT", + "http.url": "https://p62c47itsb.execute-api.eu-west-1.amazonaws.com$connect/", + "message_direction": "IN", + "operation_name": "aws.apigateway.websocket", + "request_id": "123", + "resource_names": "$connect", + "stage": "dev", + }, + ), + ), + ( + "api-gateway-websocket-disconnect", + _Span( + service="p62c47itsb.execute-api.eu-west-1.amazonaws.com", + start=1631284034.737, + span_type="web", + tags={ + "_dd.origin": "lambda", + "_inferred_span.synchronicity": "sync", + "_inferred_span.tag_source": "self", + "apiid": "p62c47itsb", + "apiname": "p62c47itsb", + "connection_id": "Fc2tgfl3mjQCJfA=", + "endpoint": "$disconnect", + "event_type": "DISCONNECT", + "http.url": "https://p62c47itsb.execute-api.eu-west-1.amazonaws.com$disconnect/", + "message_direction": "IN", + "operation_name": "aws.apigateway.websocket", + "request_id": "123", + "resource_names": "$disconnect", + "stage": "dev", + }, + ), + ), + ( + "sqs-string-msg-attribute", + _Span( + service="InferredSpansQueueNode", + start=1634662094.538, + span_type="web", + tags={ + "_dd.origin": "lambda", + "_inferred_span.synchronicity": "async", + "_inferred_span.tag_source": "self", + "event_source_arn": "arn:aws:sqs:eu-west-1:601427279990:InferredSpansQueueNode", + "operation_name": "aws.sqs", + "queuename": "InferredSpansQueueNode", + "resource_names": "InferredSpansQueueNode", + "sender_id": "AROAYYB64AB3LSVUYFP5T:harv-inferred-spans-dev-initSender", + }, + ), + ), + ( + "sns-string-msg-attribute", + _Span( + service="serverlessTracingTopicPy", + start=1643638421.637, + span_type="web", + tags={ + "_dd.origin": "lambda", + "_inferred_span.synchronicity": "async", + "_inferred_span.tag_source": "self", + "message_id": "87056a47-f506-5d77-908b-303605d3b197", + "operation_name": "aws.sns", + "resource_names": "serverlessTracingTopicPy", + "topic_arn": "arn:aws:sns:eu-west-1:601427279990:serverlessTracingTopicPy", + "topicname": "serverlessTracingTopicPy", + "type": "Notification", + }, + ), + ), + ( + "sns-b64-msg-attribute", + _Span( + service="serverlessTracingTopicPy", + start=1643638421.637, + span_type="web", + tags={ + "_dd.origin": "lambda", + "_inferred_span.synchronicity": "async", + "_inferred_span.tag_source": "self", + "message_id": "87056a47-f506-5d77-908b-303605d3b197", + "operation_name": "aws.sns", + "resource_names": "serverlessTracingTopicPy", + "topic_arn": "arn:aws:sns:eu-west-1:601427279990:serverlessTracingTopicPy", + "topicname": "serverlessTracingTopicPy", + "type": "Notification", + }, + ), + ), + ( + "kinesisStream", + _Span( + service="kinesisStream", + start=1643638425.163, + span_type="web", + tags={ + "_dd.origin": "lambda", + "_inferred_span.synchronicity": "async", + "_inferred_span.tag_source": "self", + "endpoint": None, + "event_id": "shardId-000000000002:49624230154685806402418173680709770494154422022871973922", + "event_name": "aws:kinesis:record", + "event_source_arn": "arn:aws:kinesis:eu-west-1:601427279990:stream/kinesisStream", + "event_version": "1.0", + "http.method": None, + "http.url": None, + "operation_name": "aws.kinesis", + "partition_key": "partitionkey", + "request_id": None, + "resource_names": "kinesisStream", + "shardid": "shardId-000000000002", + "streamname": "kinesisStream", + }, + ), + ), + ( + "dynamodb", + _Span( + service="ExampleTableWithStream", + start=1428537600.0, + span_type="web", + tags={ + "_dd.origin": "lambda", + "_inferred_span.synchronicity": "async", + "_inferred_span.tag_source": "self", + "endpoint": None, + "event_id": "c4ca4238a0b923820dcc509a6f75849b", + "event_name": "INSERT", + "event_source_arn": "arn:aws:dynamodb:us-east-1:123456789012:table/ExampleTableWithStream/stream/2015-06-27T00:48:05.899", + "event_version": "1.1", + "http.method": None, + "http.url": None, + "operation_name": "aws.dynamodb", + "request_id": None, + "resource_names": "ExampleTableWithStream", + "size_bytes": "26", + "stream_view_type": "NEW_AND_OLD_IMAGES", + "tablename": "ExampleTableWithStream", + }, + ), + ), + ( + "s3", + _Span( + service="example-bucket", + start=0.0, + span_type="web", + tags={ + "_dd.origin": "lambda", + "_inferred_span.synchronicity": "async", + "_inferred_span.tag_source": "self", + "bucket_arn": "arn:aws:s3:::example-bucket", + "bucketname": "example-bucket", + "endpoint": None, + "event_name": "ObjectCreated:Put", + "http.method": None, + "http.url": None, + "object_etag": "0123456789abcdef0123456789abcdef", + "object_key": "test/key", + "object_size": "1024", + "operation_name": "aws.s3", + "request_id": None, + "resource_names": "example-bucket", + }, + ), + ), + ( + "eventbridge-custom", + _Span( + service="eventbridge.custom.event.sender", + start=1635989865.0, + span_type="web", + tags={ + "_dd.origin": "lambda", + "_inferred_span.synchronicity": "async", + "_inferred_span.tag_source": "self", + "endpoint": None, + "http.method": None, + "http.url": None, + "operation_name": "aws.eventbridge", + "request_id": None, + "resource_names": "eventbridge.custom.event.sender", + }, + ), + ), + ( + "eventbridge-sqs", + _Span( + service="eventbridge-sqs-queue", + start=1691102943.638, + span_type="web", + parent_name="aws.eventbridge", + tags={ + "_dd.origin": "lambda", + "_inferred_span.synchronicity": "async", + "_inferred_span.tag_source": "self", + "endpoint": None, + "event_source_arn": "arn:aws:sqs:us-east-1:425362996713:eventbridge-sqs-queue", + "http.method": None, + "http.url": None, + "operation_name": "aws.sqs", + "queuename": "eventbridge-sqs-queue", + "request_id": None, + "resource_names": "eventbridge-sqs-queue", + "sender_id": "AIDAJXNJGGKNS7OSV23OI", + }, + ), + ), + ( + "api-gateway-no-apiid", + _Span( + service="70ixmpl4fl.execute-api.us-east-2.amazonaws.com", + start=1428582896.0, + span_type="http", + tags={ + "_dd.origin": "lambda", + "_inferred_span.synchronicity": "sync", + "_inferred_span.tag_source": "self", + "apiid": "None", + "apiname": "None", + "endpoint": "/path/to/resource", + "http.method": "POST", + "http.url": "https://70ixmpl4fl.execute-api.us-east-2.amazonaws.com/path/to/resource", + "operation_name": "aws.apigateway.rest", + "request_id": "123", + "resource_names": "POST /{proxy+}", + "stage": "prod", + }, + ), + ), + ( + "authorizer-request-api-gateway-v1", + _Span( + service="amddr1rix9.execute-api.eu-west-1.amazonaws.com", + start=1663295021.832, + span_type="http", + parent_name="aws.apigateway.authorizer", + tags={ + "_dd.origin": "lambda", + "_inferred_span.synchronicity": "sync", + "_inferred_span.tag_source": "self", + "apiid": "amddr1rix9", + "apiname": "amddr1rix9", + "endpoint": "/hello", + "http.method": "GET", + "http.url": "https://amddr1rix9.execute-api.eu-west-1.amazonaws.com/hello", + "operation_name": "aws.apigateway.rest", + "request_id": "123", + "resource_names": "GET /hello", + "stage": "dev", + }, + ), + ), + ( + "authorizer-request-api-gateway-v1-cached", + _Span( + service="amddr1rix9.execute-api.eu-west-1.amazonaws.com", + start=1666714653.636, + span_type="http", + tags={ + "_dd.origin": "lambda", + "_inferred_span.synchronicity": "sync", + "_inferred_span.tag_source": "self", + "apiid": "amddr1rix9", + "apiname": "amddr1rix9", + "endpoint": "/hello", + "http.method": "GET", + "http.url": "https://amddr1rix9.execute-api.eu-west-1.amazonaws.com/hello", + "operation_name": "aws.apigateway.rest", + "request_id": "123", + "resource_names": "GET /hello", + "stage": "dev", + }, + ), + ), + ( + "authorizer-token-api-gateway-v1", + _Span( + service="amddr1rix9.execute-api.eu-west-1.amazonaws.com", + start=1663295021.832, + span_type="http", + parent_name="aws.apigateway.authorizer", + tags={ + "_dd.origin": "lambda", + "_inferred_span.synchronicity": "sync", + "_inferred_span.tag_source": "self", + "apiid": "amddr1rix9", + "apiname": "amddr1rix9", + "endpoint": "/hello", + "http.method": "GET", + "http.url": "https://amddr1rix9.execute-api.eu-west-1.amazonaws.com/hello", + "operation_name": "aws.apigateway.rest", + "request_id": "123", + "resource_names": "GET /hello", + "stage": "dev", + }, + ), + ), + ( + "authorizer-token-api-gateway-v1-cached", + _Span( + service="amddr1rix9.execute-api.eu-west-1.amazonaws.com", + start=1666803622.99, + span_type="http", + tags={ + "_dd.origin": "lambda", + "_inferred_span.synchronicity": "sync", + "_inferred_span.tag_source": "self", + "apiid": "amddr1rix9", + "apiname": "amddr1rix9", + "endpoint": "/hello", + "http.method": "GET", + "http.url": "https://amddr1rix9.execute-api.eu-west-1.amazonaws.com/hello", + "operation_name": "aws.apigateway.rest", + "request_id": "123", + "resource_names": "GET /hello", + "stage": "dev", + }, + ), + ), + ( + "authorizer-request-api-gateway-v2", + _Span( + service="amddr1rix9.execute-api.eu-west-1.amazonaws.com", + start=1664228639.5337753, + span_type="http", + tags={ + "_dd.origin": "lambda", + "_inferred_span.synchronicity": "sync", + "_inferred_span.tag_source": "self", + "apiid": "amddr1rix9", + "apiname": "amddr1rix9", + "endpoint": "/hello", + "http.method": "GET", + "http.url": "https://amddr1rix9.execute-api.eu-west-1.amazonaws.com/hello", + "operation_name": "aws.httpapi", + "request_id": "123", + "resource_names": "GET /hello", + "stage": "dev", + }, + ), + ), + ( + "authorizer-request-api-gateway-v2-cached", + _Span( + service="amddr1rix9.execute-api.eu-west-1.amazonaws.com", + start=1666715429.349, + span_type="http", + tags={ + "_dd.origin": "lambda", + "_inferred_span.synchronicity": "sync", + "_inferred_span.tag_source": "self", + "apiid": "amddr1rix9", + "apiname": "amddr1rix9", + "endpoint": "/hello", + "http.method": "GET", + "http.url": "https://amddr1rix9.execute-api.eu-west-1.amazonaws.com/hello", + "operation_name": "aws.httpapi", + "request_id": "123", + "resource_names": "GET /hello", + "stage": "dev", + }, + ), + ), + ( + "authorizer-request-api-gateway-websocket-connect", + _Span( + service="amddr1rix9.execute-api.eu-west-1.amazonaws.com", + start=1664388386.892, + span_type="web", + parent_name="aws.apigateway.authorizer", + tags={ + "_dd.origin": "lambda", + "_inferred_span.synchronicity": "sync", + "_inferred_span.tag_source": "self", + "apiid": "amddr1rix9", + "apiname": "amddr1rix9", + "connection_id": "ZLr9QeNLmjQCIZA=", + "endpoint": "$connect", + "event_type": "CONNECT", + "http.url": "https://amddr1rix9.execute-api.eu-west-1.amazonaws.com$connect/", + "message_direction": "IN", + "operation_name": "aws.apigateway.websocket", + "request_id": "123", + "resource_names": "$connect", + "stage": "dev", + }, + ), + ), + ( + "authorizer-request-api-gateway-websocket-message", + _Span( + service="amddr1rix9.execute-api.eu-west-1.amazonaws.com", + start=1664390397.1169999, + span_type="web", + tags={ + "_dd.origin": "lambda", + "_inferred_span.synchronicity": "sync", + "_inferred_span.tag_source": "self", + "apiid": "amddr1rix9", + "apiname": "amddr1rix9", + "connection_id": "ZLwtceO1mjQCI8Q=", + "endpoint": "main", + "event_type": "MESSAGE", + "http.url": "https://amddr1rix9.execute-api.eu-west-1.amazonaws.commain/", + "message_direction": "IN", + "operation_name": "aws.apigateway.websocket", + "request_id": "123", + "resource_names": "main", + "stage": "dev", + }, + ), + ), +) + + +@pytest.mark.parametrize("source,expect", _test_create_inferred_span) +@patch("ddtrace.trace.Span.finish", autospec=True) +def test_create_inferred_span(mock_span_finish, source, expect): + with open(f"{event_samples}{source}.json") as f: + event = json.load(f) + ctx = get_mock_context(aws_request_id="123") + + actual = create_inferred_span(event, ctx) + assert actual.service == expect.service + assert actual.start == expect.start + assert actual.span_type == expect.span_type + for tag, value in expect.tags.items(): + assert actual.get_tag(tag) == value, f"wrong value for tag {tag}" + + if expect.parent_name is not None: # there are two inferred spans + assert mock_span_finish.call_count == 1 + args, kwargs = mock_span_finish.call_args_list[0] + parent = args[0] + finish_time = kwargs.get("finish_time") or args[1] + assert parent.name == expect.parent_name + assert actual.parent_id == parent.span_id + assert finish_time == expect.start + else: # there is only one inferred span + assert mock_span_finish.call_count == 0 class TestInferredSpans(unittest.TestCase): - def tearDown(self): - _clean_up_span() + @patch("datadog_lambda.tracing.submit_errors_metric") + def test_mark_trace_as_error_for_5xx_responses_getting_400_response_code( + self, mock_submit_errors_metric + ): + mark_trace_as_error_for_5xx_responses( + context="fake_context", status_code="400", span="empty_span" + ) + mock_submit_errors_metric.assert_not_called() - def test_create_inferred_span_from_api_gateway_event(self): - event_sample_source = "api-gateway" - test_file = event_samples + event_sample_source + ".json" - with open(test_file, "r") as event: - event = json.load(event) - ctx = get_mock_context() - ctx.aws_request_id = "123" - span = create_inferred_span(event, ctx) - self.assertEqual(span.get_tag("operation_name"), "aws.apigateway.rest") - self.assertEqual( - span.service, - "70ixmpl4fl.execute-api.us-east-2.amazonaws.com", + @patch("datadog_lambda.tracing.submit_errors_metric") + def test_mark_trace_as_error_for_5xx_responses_sends_error_metric_and_set_error_tags( + self, mock_submit_errors_metric + ): + mock_span = Mock(ddtrace.trace.Span) + status_code = "500" + mark_trace_as_error_for_5xx_responses( + context="fake_context", status_code=status_code, span=mock_span ) - self.assertEqual( - span.get_tag("http.url"), - "70ixmpl4fl.execute-api.us-east-2.amazonaws.com/path/to/resource", + mock_submit_errors_metric.assert_called_once() + self.assertEqual(1, mock_span.error) + + +class TestStepFunctionsTraceContext(unittest.TestCase): + def test_deterministic_m5_hash(self): + result = _deterministic_sha256_hash("some_testing_random_string", LOWER_64_BITS) + self.assertEqual(7456137785171041414, result) + + def test_deterministic_m5_hash__result_the_same_as_backend_1(self): + result = _deterministic_sha256_hash( + "arn:aws:states:sa-east-1:425362996713:stateMachine:MyStateMachine-b276uka1j" + "#lambda#1", + HIGHER_64_BITS, ) - self.assertEqual(span.get_tag("endpoint"), "/path/to/resource") - self.assertEqual(span.get_tag("http.method"), "POST") - self.assertEqual( - span.get_tag("resource_names"), - "POST /path/to/resource", - ) - self.assertEqual(span.get_tag("request_id"), "123") - self.assertEqual(span.get_tag("apiid"), "1234567890") - self.assertEqual(span.get_tag("apiname"), "1234567890") - self.assertEqual(span.get_tag("stage"), "prod") - self.assertEqual(span.start, 1428582896.0) - self.assertEqual(span.span_type, "http") - self.assertEqual(span.get_tag(InferredSpanInfo.TAG_SOURCE), "self") - self.assertEqual(span.get_tag(InferredSpanInfo.SYNCHRONICITY), "sync") - - def test_create_inferred_span_from_api_gateway_non_proxy_event_async(self): - event_sample_source = "api-gateway-non-proxy-async" - test_file = event_samples + event_sample_source + ".json" - with open(test_file, "r") as event: - event = json.load(event) - ctx = get_mock_context() - ctx.aws_request_id = "123" - span = create_inferred_span(event, ctx) - self.assertEqual(span.get_tag("operation_name"), "aws.apigateway.rest") - self.assertEqual( - span.service, - "lgxbo6a518.execute-api.eu-west-1.amazonaws.com", - ) - self.assertEqual( - span.get_tag("http.url"), - "lgxbo6a518.execute-api.eu-west-1.amazonaws.com/http/get", - ) - self.assertEqual(span.get_tag("endpoint"), "/http/get") - self.assertEqual(span.get_tag("http.method"), "GET") - self.assertEqual( - span.get_tag("resource_names"), - "GET /http/get", - ) - self.assertEqual(span.get_tag("request_id"), "123") - self.assertEqual(span.get_tag("apiid"), "lgxbo6a518") - self.assertEqual(span.get_tag("apiname"), "lgxbo6a518") - self.assertEqual(span.get_tag("stage"), "dev") - self.assertEqual(span.start, 1631210915.2510002) - self.assertEqual(span.span_type, "http") - self.assertEqual(span.get_tag(InferredSpanInfo.TAG_SOURCE), "self") - self.assertEqual(span.get_tag(InferredSpanInfo.SYNCHRONICITY), "async") - - def test_create_inferred_span_from_api_gateway_non_proxy_event_sync(self): - event_sample_source = "api-gateway-non-proxy" - test_file = event_samples + event_sample_source + ".json" - with open(test_file, "r") as event: - event = json.load(event) - ctx = get_mock_context() - ctx.aws_request_id = "123" - span = create_inferred_span(event, ctx) - self.assertEqual(span.get_tag("operation_name"), "aws.apigateway.rest") - self.assertEqual( - span.service, - "lgxbo6a518.execute-api.eu-west-1.amazonaws.com", - ) - self.assertEqual( - span.get_tag("http.url"), - "lgxbo6a518.execute-api.eu-west-1.amazonaws.com/http/get", - ) - self.assertEqual(span.get_tag("endpoint"), "/http/get") - self.assertEqual(span.get_tag("http.method"), "GET") - self.assertEqual( - span.get_tag("resource_names"), - "GET /http/get", - ) - self.assertEqual(span.get_tag("request_id"), "123") - self.assertEqual(span.get_tag("apiid"), "lgxbo6a518") - self.assertEqual(span.get_tag("apiname"), "lgxbo6a518") - self.assertEqual(span.get_tag("stage"), "dev") - self.assertEqual(span.start, 1631210915.2510002) - self.assertEqual(span.span_type, "http") - self.assertEqual(span.get_tag(InferredSpanInfo.TAG_SOURCE), "self") - self.assertEqual(span.get_tag(InferredSpanInfo.SYNCHRONICITY), "sync") - - def test_create_inferred_span_from_http_api_event(self): - event_sample_source = "http-api" - test_file = event_samples + event_sample_source + ".json" - with open(test_file, "r") as event: - event = json.load(event) - ctx = get_mock_context() - ctx.aws_request_id = "123" - span = create_inferred_span(event, ctx) - self.assertEqual(span.get_tag("operation_name"), "aws.httpapi") - self.assertEqual( - span.service, - "x02yirxc7a.execute-api.eu-west-1.amazonaws.com", - ) - self.assertEqual( - span.get_tag("http.url"), - "x02yirxc7a.execute-api.eu-west-1.amazonaws.com/httpapi/get", - ) - self.assertEqual(span.get_tag("endpoint"), "/httpapi/get") - self.assertEqual(span.get_tag("http.method"), "GET") - self.assertEqual( - span.get_tag("resource_names"), - "GET /httpapi/get", - ) - self.assertEqual(span.get_tag("request_id"), "123") - self.assertEqual(span.get_tag("apiid"), "x02yirxc7a") - self.assertEqual(span.get_tag("apiname"), "x02yirxc7a") - self.assertEqual(span.get_tag("stage"), "$default") - self.assertEqual(span.get_tag("http.protocol"), "HTTP/1.1") - self.assertEqual(span.get_tag("http.source_ip"), "38.122.226.210") - self.assertEqual(span.get_tag("http.user_agent"), "curl/7.64.1") - self.assertEqual(span.start, 1631212283.738) - self.assertEqual(span.span_type, "http") - self.assertEqual(span.get_tag(InferredSpanInfo.TAG_SOURCE), "self") - self.assertEqual(span.get_tag(InferredSpanInfo.SYNCHRONICITY), "sync") - - def test_create_inferred_span_from_api_gateway_websocket_default_event(self): - event_sample_source = "api-gateway-websocket-default" - test_file = event_samples + event_sample_source + ".json" - with open(test_file, "r") as event: - event = json.load(event) - ctx = get_mock_context() - ctx.aws_request_id = "123" - span = create_inferred_span(event, ctx) - self.assertEqual(span.get_tag("operation_name"), "aws.apigateway.websocket") - self.assertEqual( - span.service, - "p62c47itsb.execute-api.eu-west-1.amazonaws.com", - ) - self.assertEqual( - span.get_tag("http.url"), - "p62c47itsb.execute-api.eu-west-1.amazonaws.com$default", - ) - self.assertEqual(span.get_tag("endpoint"), "$default") - self.assertEqual(span.get_tag("http.method"), None) - self.assertEqual( - span.get_tag("resource_names"), - "$default", - ) - self.assertEqual(span.get_tag("request_id"), "123") - self.assertEqual(span.get_tag("apiid"), "p62c47itsb") - self.assertEqual(span.get_tag("apiname"), "p62c47itsb") - self.assertEqual(span.get_tag("stage"), "dev") - self.assertEqual(span.get_tag("connection_id"), "Fc5SzcoYGjQCJlg=") - self.assertEqual(span.get_tag("event_type"), "MESSAGE") - self.assertEqual(span.get_tag("message_direction"), "IN") - self.assertEqual(span.start, 1631285061.365) - self.assertEqual(span.span_type, "web") - self.assertEqual(span.get_tag(InferredSpanInfo.TAG_SOURCE), "self") - self.assertEqual(span.get_tag(InferredSpanInfo.SYNCHRONICITY), "sync") - - def test_create_inferred_span_from_api_gateway_websocket_connect_event(self): - event_sample_source = "api-gateway-websocket-connect" - test_file = event_samples + event_sample_source + ".json" - with open(test_file, "r") as event: - event = json.load(event) - ctx = get_mock_context() - ctx.aws_request_id = "123" - span = create_inferred_span(event, ctx) - self.assertEqual(span.get_tag("operation_name"), "aws.apigateway.websocket") - self.assertEqual( - span.service, - "p62c47itsb.execute-api.eu-west-1.amazonaws.com", - ) - self.assertEqual( - span.get_tag("http.url"), - "p62c47itsb.execute-api.eu-west-1.amazonaws.com$connect", - ) - self.assertEqual(span.get_tag("endpoint"), "$connect") - self.assertEqual(span.get_tag("http.method"), None) - self.assertEqual( - span.get_tag("resource_names"), - "$connect", - ) - self.assertEqual(span.get_tag("request_id"), "123") - self.assertEqual(span.get_tag("apiid"), "p62c47itsb") - self.assertEqual(span.get_tag("apiname"), "p62c47itsb") - self.assertEqual(span.get_tag("stage"), "dev") - self.assertEqual(span.get_tag("connection_id"), "Fc2tgfl3mjQCJfA=") - self.assertEqual(span.get_tag("event_type"), "CONNECT") - self.assertEqual(span.get_tag("message_direction"), "IN") - self.assertEqual(span.start, 1631284003.071) - self.assertEqual(span.span_type, "web") - self.assertEqual(span.get_tag(InferredSpanInfo.TAG_SOURCE), "self") - self.assertEqual(span.get_tag(InferredSpanInfo.SYNCHRONICITY), "sync") - - def test_create_inferred_span_from_api_gateway_websocket_disconnect_event(self): - event_sample_source = "api-gateway-websocket-disconnect" - test_file = event_samples + event_sample_source + ".json" - with open(test_file, "r") as event: - event = json.load(event) - ctx = get_mock_context() - ctx.aws_request_id = "123" - span = create_inferred_span(event, ctx) - self.assertEqual(span.get_tag("operation_name"), "aws.apigateway.websocket") - self.assertEqual( - span.service, - "p62c47itsb.execute-api.eu-west-1.amazonaws.com", - ) - self.assertEqual( - span.get_tag("http.url"), - "p62c47itsb.execute-api.eu-west-1.amazonaws.com$disconnect", - ) - self.assertEqual(span.get_tag("endpoint"), "$disconnect") - self.assertEqual(span.get_tag("http.method"), None) - self.assertEqual( - span.get_tag("resource_names"), - "$disconnect", - ) - self.assertEqual(span.get_tag("request_id"), "123") - self.assertEqual(span.get_tag("apiid"), "p62c47itsb") - self.assertEqual(span.get_tag("apiname"), "p62c47itsb") - self.assertEqual(span.get_tag("stage"), "dev") - self.assertEqual(span.get_tag("connection_id"), "Fc2tgfl3mjQCJfA=") - self.assertEqual(span.get_tag("event_type"), "DISCONNECT") - self.assertEqual(span.get_tag("message_direction"), "IN") - self.assertEqual(span.start, 1631284034.737) - self.assertEqual(span.span_type, "web") - self.assertEqual(span.get_tag(InferredSpanInfo.TAG_SOURCE), "self") - self.assertEqual(span.get_tag(InferredSpanInfo.SYNCHRONICITY), "sync") - - def test_create_inferred_span_from_sqs_event_string_msg_attr(self): - event_sample_name = "sqs-string-msg-attribute" - test_file = event_samples + event_sample_name + ".json" - with open(test_file, "r") as event: - event = json.load(event) - ctx = get_mock_context() - ctx.aws_request_id = "123" - span = create_inferred_span(event, ctx) - self.assertEqual(span.get_tag("operation_name"), "aws.sqs") - self.assertEqual( - span.service, - "sqs", - ) - self.assertEqual( - span.get_tag("http.url"), - None, - ) - self.assertEqual(span.get_tag("endpoint"), None) - self.assertEqual(span.get_tag("http.method"), None) - self.assertEqual( - span.get_tag("resource_names"), - "InferredSpansQueueNode", - ) - self.assertEqual(span.get_tag("request_id"), None) - self.assertEqual(span.get_tag("queuename"), "InferredSpansQueueNode") - self.assertEqual( - span.get_tag("event_source_arn"), - "arn:aws:sqs:eu-west-1:601427279990:InferredSpansQueueNode", - ) - self.assertEqual( - span.get_tag("sender_id"), - "AROAYYB64AB3LSVUYFP5T:harv-inferred-spans-dev-initSender", - ) - self.assertEqual(span.start, 1634662094.538) - self.assertEqual(span.span_type, "web") - self.assertEqual(span.get_tag(InferredSpanInfo.TAG_SOURCE), "self") - self.assertEqual(span.get_tag(InferredSpanInfo.SYNCHRONICITY), "async") + self.assertEqual(3711631873188331089, result) - def test_create_inferred_span_from_sns_event_string_msg_attr(self): - event_sample_name = "sns-string-msg-attribute" - test_file = event_samples + event_sample_name + ".json" - with open(test_file, "r") as event: - event = json.load(event) - ctx = get_mock_context() - ctx.aws_request_id = "123" - span = create_inferred_span(event, ctx) - self.assertEqual(span.get_tag("operation_name"), "aws.sns") - self.assertEqual( - span.service, - "sns", - ) - self.assertEqual( - span.get_tag("http.url"), - None, - ) - self.assertEqual(span.get_tag("endpoint"), None) - self.assertEqual(span.get_tag("http.method"), None) - self.assertEqual( - span.get_tag("resource_names"), - "serverlessTracingTopicPy", - ) - self.assertEqual(span.get_tag("topicname"), "serverlessTracingTopicPy") - self.assertEqual( - span.get_tag("topic_arn"), - "arn:aws:sns:eu-west-1:601427279990:serverlessTracingTopicPy", + def test_deterministic_m5_hash__result_the_same_as_backend_2(self): + result = _deterministic_sha256_hash( + "arn:aws:states:sa-east-1:425362996713:stateMachine:MyStateMachine-b276uka1j" + "#lambda#2", + HIGHER_64_BITS, ) - self.assertEqual( - span.get_tag("message_id"), "87056a47-f506-5d77-908b-303605d3b197" - ) - self.assertEqual(span.get_tag("type"), "Notification") - self.assertEqual(span.get_tag("subject"), None) - self.assertEqual(span.start, 1643638421.637) - self.assertEqual(span.span_type, "web") - self.assertEqual(span.get_tag(InferredSpanInfo.TAG_SOURCE), "self") - self.assertEqual(span.get_tag(InferredSpanInfo.SYNCHRONICITY), "async") - - def test_create_inferred_span_from_sns_event_b64_msg_attr(self): - event_sample_name = "sns-b64-msg-attribute" - test_file = event_samples + event_sample_name + ".json" - with open(test_file, "r") as event: - event = json.load(event) - ctx = get_mock_context() - ctx.aws_request_id = "123" - span = create_inferred_span(event, ctx) - self.assertEqual(span.get_tag("operation_name"), "aws.sns") - self.assertEqual( - span.service, - "sns", - ) - self.assertEqual( - span.get_tag("http.url"), - None, - ) - self.assertEqual(span.get_tag("endpoint"), None) - self.assertEqual(span.get_tag("http.method"), None) - self.assertEqual( - span.get_tag("resource_names"), - "serverlessTracingTopicPy", - ) - self.assertEqual(span.get_tag("topicname"), "serverlessTracingTopicPy") - self.assertEqual( - span.get_tag("topic_arn"), - "arn:aws:sns:eu-west-1:601427279990:serverlessTracingTopicPy", - ) - self.assertEqual( - span.get_tag("message_id"), "87056a47-f506-5d77-908b-303605d3b197" - ) - self.assertEqual(span.get_tag("type"), "Notification") - self.assertEqual(span.get_tag("subject"), None) - self.assertEqual(span.start, 1643638421.637) - self.assertEqual(span.span_type, "web") - self.assertEqual(span.get_tag(InferredSpanInfo.TAG_SOURCE), "self") - self.assertEqual(span.get_tag(InferredSpanInfo.SYNCHRONICITY), "async") + self.assertEqual(5759173372325510050, result) - def test_create_inferred_span_from_kinesis_event(self): - event_sample_source = "kinesis" - test_file = event_samples + event_sample_source + ".json" - with open(test_file, "r") as event: - event = json.load(event) - ctx = get_mock_context() - ctx.aws_request_id = "123" - span = create_inferred_span(event, ctx) - self.assertEqual(span.get_tag("operation_name"), "aws.kinesis") - self.assertEqual( - span.service, - "kinesis", - ) - self.assertEqual( - span.get_tag("http.url"), - None, - ) - self.assertEqual(span.get_tag("endpoint"), None) - self.assertEqual(span.get_tag("http.method"), None) - self.assertEqual( - span.get_tag("resource_names"), - "stream/kinesisStream", + def test_deterministic_m5_hash__always_leading_with_zero(self): + for i in range(100): + result = _deterministic_sha256_hash(str(i), 64) + result_in_binary = bin(int(result)) + # Leading zeros will be omitted, so only test for full 64 bits present + if len(result_in_binary) == 66: # "0b" + 64 bits. + self.assertTrue(result_in_binary.startswith("0b0")) + + +class TestExceptionOutsideHandler(unittest.TestCase): + @patch("datadog_lambda.config.Config.trace_enabled", True) + @patch("datadog_lambda.tracing.submit_errors_metric") + @patch("time.time_ns", return_value=42) + def test_exception_outside_handler_tracing_enabled( + self, mock_time, mock_submit_errors_metric + ): + fake_error = ValueError("Some error message") + resource_name = "my_handler" + span_type = "aws.lambda" + mock_span = Mock() + with patch( + "datadog_lambda.tracing.tracer.trace", return_value=mock_span + ) as mock_trace: + emit_telemetry_on_exception_outside_of_handler( + fake_error, resource_name, 42 + ) + + mock_submit_errors_metric.assert_called_once_with(None) + + mock_trace.assert_called_once_with( + span_type, + service="aws.lambda", + resource=resource_name, + span_type="serverless", + ) + mock_span.set_tags.assert_called_once_with( + { + "error.status": 500, + "error.type": "ValueError", + "error.message": fake_error, + "error.stack": traceback.format_exc(), + "resource_names": resource_name, + "resource.name": resource_name, + "operation_name": span_type, + "status": "error", + } ) - self.assertEqual(span.get_tag("request_id"), None) - self.assertEqual(span.get_tag("streamname"), "stream/kinesisStream") - self.assertEqual(span.get_tag("shardid"), "shardId-000000000002") - self.assertEqual( - span.get_tag("event_source_arn"), - "arn:aws:kinesis:eu-west-1:601427279990:stream/kinesisStream", + mock_span.finish.assert_called_once() + assert mock_span.error == 1 + assert mock_span.start_ns == 42 + + @patch("datadog_lambda.config.Config.trace_enabled", False) + @patch("datadog_lambda.tracing.submit_errors_metric") + @patch("time.time_ns", return_value=42) + def test_exception_outside_handler_tracing_disabled( + self, mock_time, mock_submit_errors_metric + ): + fake_error = ValueError("Some error message") + resource_name = "my_handler" + with patch("datadog_lambda.tracing.tracer.trace") as mock_trace: + emit_telemetry_on_exception_outside_of_handler( + fake_error, resource_name, 42 + ) + + mock_submit_errors_metric.assert_called_once_with(None) + mock_trace.assert_not_called() + + +class TestExtractDDContextWithDSMLogic(unittest.TestCase): + def setUp(self): + checkpoint_patcher = patch("ddtrace.data_streams.set_consume_checkpoint") + self.mock_checkpoint = checkpoint_patcher.start() + self.addCleanup(checkpoint_patcher.stop) + self.lambda_context = get_mock_context() + config_patcher = patch( + "datadog_lambda.config.Config.data_streams_enabled", True ) - self.assertEqual( - span.get_tag("event_id"), - "shardId-000000000002:49624230154685806402418173680709770494154422022871973922", - ) - self.assertEqual(span.get_tag("event_name"), "aws:kinesis:record") - self.assertEqual(span.get_tag("event_version"), "1.0") - self.assertEqual(span.get_tag("partition_key"), "partitionkey") - self.assertEqual(span.start, 1643638425.163) - self.assertEqual(span.span_type, "web") - self.assertEqual(span.get_tag(InferredSpanInfo.TAG_SOURCE), "self") - self.assertEqual(span.get_tag(InferredSpanInfo.SYNCHRONICITY), "async") - - def test_create_inferred_span_from_dynamodb_event(self): - event_sample_source = "dynamodb" - test_file = event_samples + event_sample_source + ".json" - with open(test_file, "r") as event: - event = json.load(event) - ctx = get_mock_context() - ctx.aws_request_id = "123" - span = create_inferred_span(event, ctx) - self.assertEqual(span.get_tag("operation_name"), "aws.dynamodb") - self.assertEqual( - span.service, - "dynamodb", + config_patcher.start() + self.addCleanup(config_patcher.stop) + + # SQS TESTS + + def test_sqs_context_propagated_string_value(self): + dd_data = {"dd-pathway-ctx-base64": "12345"} + dd_json_data = json.dumps(dd_data) + + event = { + "Records": [ + { + "eventSourceARN": "arn:aws:sqs:us-east-1:123456789012:test-queue", + "messageAttributes": { + "_datadog": {"dataType": "String", "stringValue": dd_json_data} + }, + "eventSource": "aws:sqs", + } + ] + } + + extract_context_from_sqs_or_sns_event_or_context( + event, self.lambda_context, parse_event_source(event) ) - self.assertEqual( - span.get_tag("http.url"), - None, + + self.assertEqual(self.mock_checkpoint.call_count, 1) + args, _ = self.mock_checkpoint.call_args + self.assertEqual(args[0], "sqs") + self.assertEqual(args[1], "arn:aws:sqs:us-east-1:123456789012:test-queue") + carrier_get = args[2] + self.assertEqual(carrier_get("dd-pathway-ctx-base64"), "12345") + + def test_sqs_context_propagated_binary_value(self): + dd_data = {"dd-pathway-ctx-base64": "12345"} + dd_json_data = json.dumps(dd_data) + encoded_data = base64.b64encode(dd_json_data.encode()).decode() + + event = { + "Records": [ + { + "eventSourceARN": "arn:aws:sqs:us-east-1:123456789012:test-queue", + "messageAttributes": { + "_datadog": {"dataType": "Binary", "binaryValue": encoded_data} + }, + "eventSource": "aws:sqs", + } + ] + } + + extract_context_from_sqs_or_sns_event_or_context( + event, self.lambda_context, parse_event_source(event) ) - self.assertEqual(span.get_tag("endpoint"), None) - self.assertEqual(span.get_tag("http.method"), None) - self.assertEqual( - span.get_tag("resource_names"), - "ExampleTableWithStream", + + self.assertEqual(self.mock_checkpoint.call_count, 1) + args, _ = self.mock_checkpoint.call_args + self.assertEqual(args[0], "sqs") + self.assertEqual(args[1], "arn:aws:sqs:us-east-1:123456789012:test-queue") + carrier_get = args[2] + self.assertEqual(carrier_get("dd-pathway-ctx-base64"), "12345") + + def test_sqs_no_datadog_message_attribute(self): + event = { + "Records": [ + { + "eventSourceARN": "arn:aws:sqs:us-east-1:123456789012:test-queue", + "messageAttributes": {}, # No _datadog key + "eventSource": "aws:sqs", + } + ] + } + + extract_context_from_sqs_or_sns_event_or_context( + event, self.lambda_context, parse_event_source(event) ) - self.assertEqual(span.get_tag("request_id"), None) - self.assertEqual(span.get_tag("tablename"), "ExampleTableWithStream") - self.assertEqual( - span.get_tag("event_source_arn"), - "arn:aws:dynamodb:us-east-1:123456789012:table/ExampleTableWithStream/stream/2015-06-27T00:48:05.899", - ) - self.assertEqual(span.get_tag("event_id"), "c4ca4238a0b923820dcc509a6f75849b") - self.assertEqual(span.get_tag("event_name"), "INSERT") - self.assertEqual(span.get_tag("event_version"), "1.1") - self.assertEqual(span.get_tag("stream_view_type"), "NEW_AND_OLD_IMAGES") - self.assertEqual(span.get_tag("size_bytes"), "26") - self.assertEqual(span.start, 1428537600.0) - self.assertEqual(span.span_type, "web") - self.assertEqual(span.get_tag(InferredSpanInfo.TAG_SOURCE), "self") - self.assertEqual(span.get_tag(InferredSpanInfo.SYNCHRONICITY), "async") - - def test_create_inferred_span_from_s3_event(self): - event_sample_source = "s3" - test_file = event_samples + event_sample_source + ".json" - with open(test_file, "r") as event: - event = json.load(event) - ctx = get_mock_context() - ctx.aws_request_id = "123" - span = create_inferred_span(event, ctx) - self.assertEqual(span.get_tag("operation_name"), "aws.s3") - self.assertEqual( - span.service, - "s3", + self.assertEqual(self.mock_checkpoint.call_count, 1) + args, _ = self.mock_checkpoint.call_args + self.assertEqual(args[0], "sqs") + self.assertEqual(args[1], "arn:aws:sqs:us-east-1:123456789012:test-queue") + carrier_get = args[2] + # None indicates no DSM context propagation + self.assertEqual(carrier_get("dd-pathway-ctx-base64"), None) + + def test_sqs_empty_datadog_message_attribute(self): + event = { + "Records": [ + { + "eventSourceARN": "arn:aws:sqs:us-east-1:123456789012:test-queue", + "messageAttributes": { + "_datadog": { + "dataType": "String", + "stringValue": "null", + } # json.loads("null") => None + }, + "eventSource": "aws:sqs", + } + ] + } + + extract_context_from_sqs_or_sns_event_or_context( + event, self.lambda_context, parse_event_source(event) + ) + self.assertEqual(self.mock_checkpoint.call_count, 1) + args, _ = self.mock_checkpoint.call_args + self.assertEqual(args[0], "sqs") + self.assertEqual(args[1], "arn:aws:sqs:us-east-1:123456789012:test-queue") + carrier_get = args[2] + # None indicates no DSM context propagation + self.assertEqual(carrier_get("dd-pathway-ctx-base64"), None) + + def test_sqs_no_DSM_context_in_message_attribute(self): + dd_data = {"NOT-DSM-KEY": "12345"} + dd_json_data = json.dumps(dd_data) + event = { + "Records": [ + { + "eventSourceARN": "arn:aws:sqs:us-east-1:123456789012:test-queue", + "messageAttributes": { + "_datadog": {"dataType": "String", "stringValue": dd_json_data} + }, + "eventSource": "aws:sqs", + } + ] + } + + extract_context_from_sqs_or_sns_event_or_context( + event, self.lambda_context, parse_event_source(event) ) - self.assertEqual( - span.get_tag("http.url"), - None, + + self.assertEqual(self.mock_checkpoint.call_count, 1) + args, _ = self.mock_checkpoint.call_args + self.assertEqual(args[0], "sqs") + self.assertEqual(args[1], "arn:aws:sqs:us-east-1:123456789012:test-queue") + carrier_get = args[2] + # None indicates no DSM context propagation + self.assertEqual(carrier_get("dd-pathway-ctx-base64"), None) + + @patch("datadog_lambda.tracing.logger") + def test_sqs_invalid_datadog_message_attribute(self, mock_logger): + test_cases = [ + { + "name": "invalid_base64", + "event": { + "Records": [ + { + "eventSourceARN": "arn:aws:sqs:us-east-1:123456789012:test-queue", + "messageAttributes": { + "_datadog": { + "dataType": "Binary", + "binaryValue": "invalid-base64", + } + }, + "eventSource": "aws:sqs", + } + ] + }, + "expected_log": ("The trace extractor returned with error %s", ANY), + }, + { + "name": "unsupported_datatype", + "event": { + "Records": [ + { + "eventSourceARN": "arn:aws:sqs:us-east-1:123456789012:test-queue", + "messageAttributes": { + "_datadog": { + "dataType": "Number", + "numberValue": 123, + } # Unsupported type + }, + "eventSource": "aws:sqs", + } + ] + }, + "expected_log": ( + "Datadog Lambda Python only supports extracting trace" + "context from String or Binary SQS/SNS message attributes", + ), + }, + ] + + for test_case in test_cases: + with self.subTest(test_case=test_case["name"]): + mock_logger.reset_mock() + self.mock_checkpoint.reset_mock() + + extract_context_from_sqs_or_sns_event_or_context( + test_case["event"], + self.lambda_context, + parse_event_source(test_case["event"]), + ) + + # Exception triggers logger + mock_logger.debug.assert_any_call(*test_case["expected_log"]) + + self.assertEqual(self.mock_checkpoint.call_count, 1) + args, _ = self.mock_checkpoint.call_args + self.assertEqual(args[0], "sqs") + self.assertEqual( + args[1], "arn:aws:sqs:us-east-1:123456789012:test-queue" + ) + carrier_get = args[2] + # None indicates no DSM context propagation + self.assertEqual(carrier_get("dd-pathway-ctx-base64"), None) + + def test_sqs_source_arn_not_found(self): + event = { + "Records": [ + { + "eventSourceARN": "", + "messageAttributes": {}, + "eventSource": "aws:sqs", + } + ] + } + + extract_context_from_sqs_or_sns_event_or_context( + event, self.lambda_context, parse_event_source(event) ) - self.assertEqual(span.get_tag("endpoint"), None) - self.assertEqual(span.get_tag("http.method"), None) - self.assertEqual( - span.get_tag("resource_names"), - "example-bucket", - ) - self.assertEqual(span.get_tag("request_id"), None) - self.assertEqual(span.get_tag("event_name"), "ObjectCreated:Put") - self.assertEqual(span.get_tag("bucketname"), "example-bucket") - self.assertEqual(span.get_tag("bucket_arn"), "arn:aws:s3:::example-bucket") - self.assertEqual(span.get_tag("object_key"), "test/key") - self.assertEqual(span.get_tag("object_size"), "1024") - self.assertEqual( - span.get_tag("object_etag"), "0123456789abcdef0123456789abcdef" + + self.mock_checkpoint.assert_not_called() + + @patch("datadog_lambda.config.Config.data_streams_enabled", False) + def test_sqs_data_streams_disabled(self): + context_json = {"dd-pathway-ctx-base64": "12345"} + event_type = "sqs" + arn = "arn:aws:sqs:us-east-1:123456789012:test-queue" + + _dsm_set_checkpoint(context_json, event_type, arn) + + self.mock_checkpoint.assert_not_called() + + # SNS TESTS + + def test_sns_context_propagated_string_value(self): + dd_data = {"dd-pathway-ctx-base64": "12345"} + dd_json_data = json.dumps(dd_data) + + event = { + "Records": [ + { + "eventSourceARN": "", + "Sns": { + "TopicArn": "arn:aws:sns:us-east-1:123456789012:test-topic", + "MessageAttributes": { + "_datadog": {"Type": "String", "Value": dd_json_data} + }, + }, + "eventSource": "aws:sns", + } + ] + } + + extract_context_from_sqs_or_sns_event_or_context( + event, self.lambda_context, parse_event_source(event) ) - self.assertEqual(span.start, 0.0) - self.assertEqual(span.span_type, "web") - self.assertEqual(span.get_tag(InferredSpanInfo.TAG_SOURCE), "self") - self.assertEqual(span.get_tag(InferredSpanInfo.SYNCHRONICITY), "async") - def test_create_inferred_span_from_eventbridge_event(self): - event_sample_source = "eventbridge-custom" - test_file = event_samples + event_sample_source + ".json" - with open(test_file, "r") as event: - event = json.load(event) - ctx = get_mock_context() - ctx.aws_request_id = "123" - span = create_inferred_span(event, ctx) - self.assertEqual(span.get_tag("operation_name"), "aws.eventbridge") - self.assertEqual( - span.service, - "eventbridge", + self.assertEqual(self.mock_checkpoint.call_count, 1) + args, _ = self.mock_checkpoint.call_args + self.assertEqual(args[0], "sns") + self.assertEqual(args[1], "arn:aws:sns:us-east-1:123456789012:test-topic") + carrier_get = args[2] + self.assertEqual(carrier_get("dd-pathway-ctx-base64"), "12345") + + def test_sns_context_propagated_binary_value(self): + dd_data = {"dd-pathway-ctx-base64": "12345"} + dd_json_data = json.dumps(dd_data) + encoded_data = base64.b64encode(dd_json_data.encode()).decode() + + event = { + "Records": [ + { + "eventSourceARN": "", + "Sns": { + "TopicArn": "arn:aws:sns:us-east-1:123456789012:test-topic", + "MessageAttributes": { + "_datadog": {"Type": "Binary", "Value": encoded_data} + }, + }, + "eventSource": "aws:sns", + } + ] + } + + extract_context_from_sqs_or_sns_event_or_context( + event, self.lambda_context, parse_event_source(event) ) - self.assertEqual( - span.get_tag("http.url"), - None, + + self.assertEqual(self.mock_checkpoint.call_count, 1) + args, _ = self.mock_checkpoint.call_args + self.assertEqual(args[0], "sns") + self.assertEqual(args[1], "arn:aws:sns:us-east-1:123456789012:test-topic") + carrier_get = args[2] + self.assertEqual(carrier_get("dd-pathway-ctx-base64"), "12345") + + def test_sns_no_datadog_message_attribute(self): + event = { + "Records": [ + { + "Sns": { + "TopicArn": "arn:aws:sns:us-east-1:123456789012:test-topic", + "MessageAttributes": {}, # No _datadog key + }, + "eventSource": "aws:sns", + } + ] + } + + extract_context_from_sqs_or_sns_event_or_context( + event, self.lambda_context, parse_event_source(event) ) - self.assertEqual(span.get_tag("endpoint"), None) - self.assertEqual(span.get_tag("http.method"), None) - self.assertEqual( - span.get_tag("resource_names"), - "eventbridge.custom.event.sender", - ) - self.assertEqual(span.get_tag("request_id"), None) - self.assertEqual(span.start, 1635989865.0) - self.assertEqual(span.span_type, "web") - self.assertEqual(span.get_tag(InferredSpanInfo.TAG_SOURCE), "self") - self.assertEqual(span.get_tag(InferredSpanInfo.SYNCHRONICITY), "async") - - def test_create_inferred_span_from_eventbridge_sqs_event(self): - event_sample_name = "eventbridge-sqs" - test_file = event_samples + event_sample_name + ".json" - with open(test_file, "r") as event: - event = json.load(event) - ctx = get_mock_context() - ctx.aws_request_id = "123" - span = create_inferred_span(event, ctx) - self.assertEqual(span.get_tag("operation_name"), "aws.sqs") - self.assertEqual( - span.service, - "sqs", + self.assertEqual(self.mock_checkpoint.call_count, 1) + args, _ = self.mock_checkpoint.call_args + self.assertEqual(args[0], "sns") + self.assertEqual(args[1], "arn:aws:sns:us-east-1:123456789012:test-topic") + carrier_get = args[2] + # None indicates no DSM context propagation + self.assertEqual(carrier_get("dd-pathway-ctx-base64"), None) + + def test_sns_empty_datadog_message_attribute(self): + event = { + "Records": [ + { + "Sns": { + "TopicArn": "arn:aws:sns:us-east-1:123456789012:test-topic", + "MessageAttributes": { + "_datadog": { + "Type": "String", + "Value": "null", + } # json.loads("null") => None + }, + }, + "eventSource": "aws:sns", + } + ] + } + + extract_context_from_sqs_or_sns_event_or_context( + event, self.lambda_context, parse_event_source(event) ) - self.assertEqual( - span.get_tag("http.url"), - None, + self.assertEqual(self.mock_checkpoint.call_count, 1) + args, _ = self.mock_checkpoint.call_args + self.assertEqual(args[0], "sns") + self.assertEqual(args[1], "arn:aws:sns:us-east-1:123456789012:test-topic") + carrier_get = args[2] + # None indicates no DSM context propagation + self.assertEqual(carrier_get("dd-pathway-ctx-base64"), None) + + def test_sns_no_DSM_context_in_message_attribute(self): + dd_data = {"NOT-DSM-KEY": "12345"} + dd_json_data = json.dumps(dd_data) + + event = { + "Records": [ + { + "eventSourceARN": "", + "Sns": { + "TopicArn": "arn:aws:sns:us-east-1:123456789012:test-topic", + "MessageAttributes": { + "_datadog": {"Type": "String", "Value": dd_json_data} + }, + }, + "eventSource": "aws:sns", + } + ] + } + + extract_context_from_sqs_or_sns_event_or_context( + event, self.lambda_context, parse_event_source(event) ) - self.assertEqual(span.get_tag("endpoint"), None) - self.assertEqual(span.get_tag("http.method"), None) - self.assertEqual( - span.get_tag("resource_names"), - "eventbridge-sqs-queue", + + self.assertEqual(self.mock_checkpoint.call_count, 1) + args, _ = self.mock_checkpoint.call_args + self.assertEqual(args[0], "sns") + self.assertEqual(args[1], "arn:aws:sns:us-east-1:123456789012:test-topic") + carrier_get = args[2] + # None indicates no DSM context propagation + self.assertEqual(carrier_get("dd-pathway-ctx-base64"), None) + + @patch("datadog_lambda.tracing.logger") + def test_sns_invalid_datadog_message_attribute(self, mock_logger): + test_cases = [ + { + "name": "invalid_base64", + "event": { + "Records": [ + { + "Sns": { + "TopicArn": "arn:aws:sns:us-east-1:123456789012:test-topic", + "MessageAttributes": { + "_datadog": { + "Type": "Binary", + "Value": "invalid-base64", + } + }, + }, + "eventSource": "aws:sns", + } + ] + }, + "expected_log": ("The trace extractor returned with error %s", ANY), + }, + { + "name": "unsupported_datatype", + "event": { + "Records": [ + { + "Sns": { + "TopicArn": "arn:aws:sns:us-east-1:123456789012:test-topic", + "MessageAttributes": { + "_datadog": { + "Type": "Number", + "numberValue": 123, + } # Unsupported type + }, + }, + "eventSource": "aws:sns", + } + ] + }, + "expected_log": ( + "Datadog Lambda Python only supports extracting trace" + "context from String or Binary SQS/SNS message attributes", + ), + }, + ] + + for test_case in test_cases: + with self.subTest(test_case=test_case["name"]): + mock_logger.reset_mock() + self.mock_checkpoint.reset_mock() + + extract_context_from_sqs_or_sns_event_or_context( + test_case["event"], + self.lambda_context, + parse_event_source(test_case["event"]), + ) + + # Exception triggers logger + mock_logger.debug.assert_any_call(*test_case["expected_log"]) + + self.assertEqual(self.mock_checkpoint.call_count, 1) + args, _ = self.mock_checkpoint.call_args + self.assertEqual(args[0], "sns") + self.assertEqual( + args[1], "arn:aws:sns:us-east-1:123456789012:test-topic" + ) + carrier_get = args[2] + # None indicates no DSM context propagation + self.assertEqual(carrier_get("dd-pathway-ctx-base64"), None) + + def test_sns_source_arn_not_found(self): + event = { + "Records": [ + { + "Sns": { + "TopicArn": "", + "MessageAttributes": {}, + }, + "eventSource": "aws:sns", + "eventSourceARN": "", + } + ] + } + + extract_context_from_sqs_or_sns_event_or_context( + event, self.lambda_context, parse_event_source(event) ) - self.assertEqual(span.get_tag("request_id"), None) - self.assertEqual(span.get_tag("queuename"), "eventbridge-sqs-queue") - self.assertEqual( - span.get_tag("event_source_arn"), - "arn:aws:sqs:us-east-1:425362996713:eventbridge-sqs-queue", + + self.mock_checkpoint.assert_not_called() + + @patch("datadog_lambda.config.Config.data_streams_enabled", False) + def test_sns_data_streams_disabled(self): + context_json = {"dd-pathway-ctx-base64": "12345"} + event_type = "sns" + arn = "arn:aws:sns:us-east-1:123456789012:test-topic" + + _dsm_set_checkpoint(context_json, event_type, arn) + + self.mock_checkpoint.assert_not_called() + + # SNS -> SQS TESTS + + def test_sns_to_sqs_context_propagated_string_value(self): + dd_data = {"dd-pathway-ctx-base64": "12345"} + dd_json_data = json.dumps(dd_data) + + sns_notification = { + "Type": "Notification", + "TopicArn": "arn:aws:sns:us-east-1:123456789012:test-topic", + "MessageAttributes": { + "_datadog": {"Type": "String", "Value": dd_json_data} + }, + "Message": "test message", + } + + event = { + "Records": [ + { + "eventSourceARN": "arn:aws:sqs:us-east-1:123456789012:test-queue", + "body": json.dumps(sns_notification), + "eventSource": "aws:sqs", + } + ] + } + + extract_context_from_sqs_or_sns_event_or_context( + event, self.lambda_context, parse_event_source(event) ) - self.assertEqual( - span.get_tag("sender_id"), - "AIDAJXNJGGKNS7OSV23OI", + + self.assertEqual(self.mock_checkpoint.call_count, 1) + args, _ = self.mock_checkpoint.call_args + self.assertEqual(args[0], "sqs") + # Should use SQS ARN, not SNS ARN + self.assertEqual(args[1], "arn:aws:sqs:us-east-1:123456789012:test-queue") + carrier_get = args[2] + self.assertEqual(carrier_get("dd-pathway-ctx-base64"), "12345") + + def test_sns_to_sqs_context_propagated_binary_value(self): + dd_data = {"dd-pathway-ctx-base64": "12345"} + dd_json_data = json.dumps(dd_data) + encoded_data = base64.b64encode(dd_json_data.encode()).decode() + + sns_notification = { + "Type": "Notification", + "TopicArn": "arn:aws:sns:us-east-1:123456789012:test-topic", + "MessageAttributes": { + "_datadog": {"Type": "Binary", "Value": encoded_data} + }, + "Message": "test message", + } + + event = { + "Records": [ + { + "eventSourceARN": "arn:aws:sqs:us-east-1:123456789012:test-queue", + "body": json.dumps(sns_notification), + "eventSource": "aws:sqs", + } + ] + } + + extract_context_from_sqs_or_sns_event_or_context( + event, self.lambda_context, parse_event_source(event) + ) + self.assertEqual(self.mock_checkpoint.call_count, 1) + args, _ = self.mock_checkpoint.call_args + self.assertEqual(args[0], "sqs") + # Should use SQS ARN, not SNS ARN + self.assertEqual(args[1], "arn:aws:sqs:us-east-1:123456789012:test-queue") + carrier_get = args[2] + self.assertEqual(carrier_get("dd-pathway-ctx-base64"), "12345") + + def test_sns_to_sqs_no_datadog_message_attribute(self): + sns_notification = { + "Type": "Notification", + "TopicArn": "arn:aws:sns:us-east-1:123456789012:test-topic", + "MessageAttributes": {}, # No _datadog key + "Message": "test message", + } + + event = { + "Records": [ + { + "eventSourceARN": "arn:aws:sqs:us-east-1:123456789012:test-queue", + "body": json.dumps(sns_notification), + "eventSource": "aws:sqs", + } + ] + } + + extract_context_from_sqs_or_sns_event_or_context( + event, self.lambda_context, parse_event_source(event) + ) + self.assertEqual(self.mock_checkpoint.call_count, 1) + args, _ = self.mock_checkpoint.call_args + self.assertEqual(args[0], "sqs") + # Should use SQS ARN, not SNS ARN + self.assertEqual(args[1], "arn:aws:sqs:us-east-1:123456789012:test-queue") + carrier_get = args[2] + # None indicates no DSM context propagation + self.assertEqual(carrier_get("dd-pathway-ctx-base64"), None) + + def test_sns_to_sqs_empty_datadog_message_attribute(self): + sns_notification = { + "Type": "Notification", + "TopicArn": "arn:aws:sns:us-east-1:123456789012:test-topic", + "MessageAttributes": { + "_datadog": { + "Type": "String", + "Value": "null", + } # json.loads("null") => None + }, + "Message": "test message", + } + + event = { + "Records": [ + { + "eventSourceARN": "arn:aws:sqs:us-east-1:123456789012:test-queue", + "body": json.dumps(sns_notification), + "eventSource": "aws:sqs", + } + ] + } + + extract_context_from_sqs_or_sns_event_or_context( + event, self.lambda_context, parse_event_source(event) + ) + self.assertEqual(self.mock_checkpoint.call_count, 1) + args, _ = self.mock_checkpoint.call_args + self.assertEqual(args[0], "sqs") + # Should use SQS ARN, not SNS ARN + self.assertEqual(args[1], "arn:aws:sqs:us-east-1:123456789012:test-queue") + carrier_get = args[2] + # None indicates no DSM context propagation + self.assertEqual(carrier_get("dd-pathway-ctx-base64"), None) + + def test_sns_to_sqs_no_DSM_context_in_message_attribute(self): + dd_data = {"NOT-DSM-KEY": "12345"} + dd_json_data = json.dumps(dd_data) + encoded_data = base64.b64encode(dd_json_data.encode()).decode() + + sns_notification = { + "Type": "Notification", + "TopicArn": "arn:aws:sns:us-east-1:123456789012:test-topic", + "MessageAttributes": { + "_datadog": {"Type": "Binary", "Value": encoded_data} + }, + "Message": "test message", + } + + event = { + "Records": [ + { + "eventSourceARN": "arn:aws:sqs:us-east-1:123456789012:test-queue", + "body": json.dumps(sns_notification), + "eventSource": "aws:sqs", + } + ] + } + + extract_context_from_sqs_or_sns_event_or_context( + event, self.lambda_context, parse_event_source(event) ) - self.assertEqual(span.start, 1691102943.638) - self.assertEqual(span.span_type, "web") - self.assertEqual(span.get_tag(InferredSpanInfo.TAG_SOURCE), "self") - self.assertEqual(span.get_tag(InferredSpanInfo.SYNCHRONICITY), "async") - def test_extract_context_from_eventbridge_event(self): - event_sample_source = "eventbridge-custom" - test_file = event_samples + event_sample_source + ".json" - with open(test_file, "r") as event: - event = json.load(event) - ctx = get_mock_context() - context, source, event_type = extract_dd_trace_context(event, ctx) - self.assertEqual(context.trace_id, 12345) - self.assertEqual(context.span_id, 67890), - self.assertEqual(context.sampling_priority, 2) + self.assertEqual(self.mock_checkpoint.call_count, 1) + args, _ = self.mock_checkpoint.call_args + self.assertEqual(args[0], "sqs") + # Should use SQS ARN, not SNS ARN + self.assertEqual(args[1], "arn:aws:sqs:us-east-1:123456789012:test-queue") + carrier_get = args[2] + # None indicates no DSM context propagation + self.assertEqual(carrier_get("dd-pathway-ctx-base64"), None) - def test_extract_dd_trace_context_for_eventbridge(self): - event_sample_source = "eventbridge-custom" - test_file = event_samples + event_sample_source + ".json" - with open(test_file, "r") as event: - event = json.load(event) - ctx = get_mock_context() - context, source, event_type = extract_dd_trace_context(event, ctx) - self.assertEqual(context.trace_id, 12345) - self.assertEqual(context.span_id, 67890) + @patch("datadog_lambda.tracing.logger") + def test_sns_to_sqs_invalid_datadog_message_attribute(self, mock_logger): + test_cases = [ + { + "name": "invalid_base64", + "sns_notification": { + "Type": "Notification", + "TopicArn": "arn:aws:sns:us-east-1:123456789012:test-topic", + "MessageAttributes": { + "_datadog": {"Type": "Binary", "Value": "not-base64"} + }, + "Message": "test message", + }, + "expected_log": ("The trace extractor returned with error %s", ANY), + }, + { + "name": "unsupported_datatype", + "sns_notification": { + "Type": "Notification", + "TopicArn": "arn:aws:sns:us-east-1:123456789012:test-topic", + "MessageAttributes": { + "_datadog": { + "Type": "Number", + "numberValue": 123, + } # Unsupported type + }, + "Message": "test message", + }, + "expected_log": ( + "Datadog Lambda Python only supports extracting trace" + "context from String or Binary SQS/SNS message attributes", + ), + }, + ] + + for test_case in test_cases: + with self.subTest(test_case=test_case["name"]): + mock_logger.reset_mock() + self.mock_checkpoint.reset_mock() + + event = { + "Records": [ + { + "eventSourceARN": "arn:aws:sqs:us-east-1:123456789012:test-queue", + "body": json.dumps(test_case["sns_notification"]), + "eventSource": "aws:sqs", + } + ] + } - def test_extract_context_from_eventbridge_sqs_event(self): - event_sample_source = "eventbridge-sqs" - test_file = event_samples + event_sample_source + ".json" - with open(test_file, "r") as event: - event = json.load(event) + extract_context_from_sqs_or_sns_event_or_context( + event, self.lambda_context, parse_event_source(event) + ) + + # Exception triggers logger + mock_logger.debug.assert_any_call(*test_case["expected_log"]) + + self.assertEqual(self.mock_checkpoint.call_count, 1) + args, _ = self.mock_checkpoint.call_args + self.assertEqual(args[0], "sqs") + # Should use SQS ARN, not SNS ARN + self.assertEqual( + args[1], "arn:aws:sqs:us-east-1:123456789012:test-queue" + ) + carrier_get = args[2] + # None indicates no DSM context propagation + self.assertEqual(carrier_get("dd-pathway-ctx-base64"), None) + + def test_sns_to_sqs_source_arn_not_found(self): + sns_notification = { + "Type": "Notification", + "TopicArn": "arn:aws:sns:us-east-1:123456789012:test-topic", + "MessageAttributes": {}, + "Message": "test message", + } - ctx = get_mock_context() - context, source, event_type = extract_dd_trace_context(event, ctx) - self.assertEqual(context.trace_id, 7379586022458917877) - self.assertEqual(context.span_id, 2644033662113726488) - self.assertEqual(context.sampling_priority, 1) + event = { + "Records": [ + { + "eventSourceARN": "", # Empty SQS ARN + "body": json.dumps(sns_notification), + "eventSource": "aws:sqs", + } + ] + } - def test_extract_context_from_sqs_event_with_string_msg_attr(self): - event_sample_source = "sqs-string-msg-attribute" - test_file = event_samples + event_sample_source + ".json" - with open(test_file, "r") as event: - event = json.load(event) - ctx = get_mock_context() - context, source, event_type = extract_dd_trace_context(event, ctx) - self.assertEqual(context.trace_id, 2684756524522091840) - self.assertEqual(context.span_id, 7431398482019833808) - self.assertEqual(context.sampling_priority, 1) + extract_context_from_sqs_or_sns_event_or_context( + event, self.lambda_context, parse_event_source(event) + ) - def test_extract_context_from_sqs_batch_event(self): - event_sample_source = "sqs-batch" - test_file = event_samples + event_sample_source + ".json" - with open(test_file, "r") as event: - event = json.load(event) - ctx = get_mock_context() - context, source, event_source = extract_dd_trace_context(event, ctx) - self.assertEqual(context.trace_id, 2684756524522091840) - self.assertEqual(context.span_id, 7431398482019833808) - self.assertEqual(context.sampling_priority, 1) + self.mock_checkpoint.assert_not_called() - def test_extract_context_from_sns_event_with_string_msg_attr(self): - event_sample_source = "sns-string-msg-attribute" - test_file = event_samples + event_sample_source + ".json" - with open(test_file, "r") as event: - event = json.load(event) - ctx = get_mock_context() - context, source, event_source = extract_dd_trace_context(event, ctx) - self.assertEqual(context.trace_id, 4948377316357291421) - self.assertEqual(context.span_id, 6746998015037429512) - self.assertEqual(context.sampling_priority, 1) + @patch("datadog_lambda.config.Config.data_streams_enabled", False) + def test_sns_to_sqs_data_streams_disabled(self): + context_json = {"dd-pathway-ctx-base64": "12345"} + event_type = "sqs" + arn = "arn:aws:sqs:us-east-1:123456789012:test-queue" - def test_extract_context_from_sns_event_with_b64_msg_attr(self): - event_sample_source = "sns-b64-msg-attribute" - test_file = event_samples + event_sample_source + ".json" - with open(test_file, "r") as event: - event = json.load(event) - ctx = get_mock_context() - context, source, event_source = extract_dd_trace_context(event, ctx) - self.assertEqual(context.trace_id, 4948377316357291421) - self.assertEqual(context.span_id, 6746998015037429512) - self.assertEqual(context.sampling_priority, 1) + _dsm_set_checkpoint(context_json, event_type, arn) - def test_extract_context_from_sns_batch_event(self): - event_sample_source = "sns-batch" - test_file = event_samples + event_sample_source + ".json" - with open(test_file, "r") as event: - event = json.load(event) - ctx = get_mock_context() - context, source, event_source = extract_dd_trace_context(event, ctx) - self.assertEqual(context.trace_id, 4948377316357291421) - self.assertEqual(context.span_id, 6746998015037429512) - self.assertEqual(context.sampling_priority, 1) + self.mock_checkpoint.assert_not_called() - def test_extract_context_from_kinesis_event(self): - event_sample_source = "kinesis" - test_file = event_samples + event_sample_source + ".json" - with open(test_file, "r") as event: - event = json.load(event) - ctx = get_mock_context() - context, source, event_source = extract_dd_trace_context(event, ctx) - self.assertEqual(context.trace_id, 4948377316357291421) - self.assertEqual(context.span_id, 2876253380018681026) - self.assertEqual(context.sampling_priority, 1) + # KINESIS TESTS - def test_extract_context_from_kinesis_batch_event(self): - event_sample_source = "kinesis-batch" - test_file = event_samples + event_sample_source + ".json" - with open(test_file, "r") as event: - event = json.load(event) - ctx = get_mock_context() - context, source, event_source = extract_dd_trace_context(event, ctx) - self.assertEqual(context.trace_id, 4948377316357291421) - self.assertEqual(context.span_id, 2876253380018681026) - self.assertEqual(context.sampling_priority, 1) + def test_kinesis_context_propagated_binary_value(self): + dd_data = {"dd-pathway-ctx-base64": "12345"} + kinesis_data = {"_datadog": dd_data, "message": "test"} + kinesis_data_str = json.dumps(kinesis_data) + encoded_data = base64.b64encode(kinesis_data_str.encode()).decode() - def test_create_inferred_span_from_api_gateway_event_no_apiid(self): - event_sample_source = "api-gateway-no-apiid" - test_file = event_samples + event_sample_source + ".json" - with open(test_file, "r") as event: - event = json.load(event) - ctx = get_mock_context() - ctx.aws_request_id = "123" - span = create_inferred_span(event, ctx) - self.assertEqual(span.get_tag("operation_name"), "aws.apigateway.rest") + event = { + "Records": [ + { + "eventSourceARN": "arn:aws:kinesis:us-east-1:123456789012:stream/test-stream", + "kinesis": {"data": encoded_data}, + } + ] + } + + extract_context_from_kinesis_event(event, self.lambda_context) + + self.assertEqual(self.mock_checkpoint.call_count, 1) + args, _ = self.mock_checkpoint.call_args + self.assertEqual(args[0], "kinesis") self.assertEqual( - span.service, - "70ixmpl4fl.execute-api.us-east-2.amazonaws.com", + args[1], "arn:aws:kinesis:us-east-1:123456789012:stream/test-stream" ) + carrier_get = args[2] + self.assertEqual(carrier_get("dd-pathway-ctx-base64"), "12345") + + def test_kinesis_no_datadog_message_attribute(self): + kinesis_data = {"message": "test"} # No _datadog key + kinesis_data_str = json.dumps(kinesis_data) + encoded_data = base64.b64encode(kinesis_data_str.encode()).decode() + + event = { + "Records": [ + { + "eventSourceARN": "arn:aws:kinesis:us-east-1:123456789012:stream/test-stream", + "kinesis": {"data": encoded_data}, + } + ] + } + + extract_context_from_kinesis_event(event, self.lambda_context) + + self.assertEqual(self.mock_checkpoint.call_count, 1) + args, _ = self.mock_checkpoint.call_args + self.assertEqual(args[0], "kinesis") self.assertEqual( - span.get_tag("http.url"), - "70ixmpl4fl.execute-api.us-east-2.amazonaws.com/path/to/resource", + args[1], "arn:aws:kinesis:us-east-1:123456789012:stream/test-stream" ) - self.assertEqual(span.get_tag("endpoint"), "/path/to/resource") - self.assertEqual(span.get_tag("http.method"), "POST") - self.assertEqual( - span.get_tag("resource_names"), - "POST /path/to/resource", - ) - self.assertEqual(span.get_tag("request_id"), "123") - self.assertEqual(span.get_tag("apiid"), "None") - self.assertEqual(span.get_tag("apiname"), "None") - self.assertEqual(span.get_tag("stage"), "prod") - self.assertEqual(span.start, 1428582896.0) - self.assertEqual(span.span_type, "http") - self.assertEqual(span.get_tag(InferredSpanInfo.TAG_SOURCE), "self") - self.assertEqual(span.get_tag(InferredSpanInfo.SYNCHRONICITY), "sync") + carrier_get = args[2] + # None indicates no DSM context propagation + self.assertEqual(carrier_get("dd-pathway-ctx-base64"), None) - @patch("datadog_lambda.tracing.submit_errors_metric") - def test_mark_trace_as_error_for_5xx_responses_getting_400_response_code( - self, mock_submit_errors_metric - ): - mark_trace_as_error_for_5xx_responses( - context="fake_context", status_code="400", span="empty_span" + def test_kinesis_empty_message_attribute(self): + kinesis_data = {"_datadog": None, "message": "test"} # _datadog is None + kinesis_data_str = json.dumps(kinesis_data) + encoded_data = base64.b64encode(kinesis_data_str.encode()).decode() + + event = { + "Records": [ + { + "eventSourceARN": "arn:aws:kinesis:us-east-1:123456789012:stream/test-stream", + "kinesis": {"data": encoded_data}, + } + ] + } + + extract_context_from_kinesis_event(event, self.lambda_context) + self.assertEqual(self.mock_checkpoint.call_count, 1) + args, _ = self.mock_checkpoint.call_args + self.assertEqual(args[0], "kinesis") + self.assertEqual( + args[1], "arn:aws:kinesis:us-east-1:123456789012:stream/test-stream" ) - mock_submit_errors_metric.assert_not_called() + carrier_get = args[2] + # None indicates no DSM context propagation + self.assertEqual(carrier_get("dd-pathway-ctx-base64"), None) - @patch("datadog_lambda.tracing.submit_errors_metric") - def test_mark_trace_as_error_for_5xx_responses_sends_error_metric_and_set_error_tags( - self, mock_submit_errors_metric - ): - mock_span = Mock(ddtrace.span.Span) - status_code = "500" - mark_trace_as_error_for_5xx_responses( - context="fake_context", status_code=status_code, span=mock_span + def test_kinesis_no_DSM_context_in_message_attribute(self): + dd_data = {"NOT-DSM-KEY": "12345"} + kinesis_data = {"_datadog": dd_data, "message": "test"} + kinesis_data_str = json.dumps(kinesis_data) + encoded_data = base64.b64encode(kinesis_data_str.encode()).decode() + + event = { + "Records": [ + { + "eventSourceARN": "arn:aws:kinesis:us-east-1:123456789012:stream/test-stream", + "kinesis": {"data": encoded_data}, + } + ] + } + + extract_context_from_kinesis_event(event, self.lambda_context) + + self.assertEqual(self.mock_checkpoint.call_count, 1) + args, _ = self.mock_checkpoint.call_args + self.assertEqual(args[0], "kinesis") + self.assertEqual( + args[1], "arn:aws:kinesis:us-east-1:123456789012:stream/test-stream" ) - mock_submit_errors_metric.assert_called_once() - self.assertEqual(1, mock_span.error) + carrier_get = args[2] + # None indicates no DSM context propagation + self.assertEqual(carrier_get("dd-pathway-ctx-base64"), None) - def test_no_error_with_nonetype_headers(self): - lambda_ctx = get_mock_context() - ctx, source, event_type = extract_dd_trace_context( - {"headers": None}, - lambda_ctx, + @patch("datadog_lambda.tracing.logger") + def test_kinesis_invalid_datadog_message_attribute(self, mock_logger): + event = { + "Records": [ + { + "eventSourceARN": "arn:aws:kinesis:us-east-1:123456789012:stream/test-stream", + "kinesis": {"data": "invalid-base64"}, + } + ] + } + + extract_context_from_kinesis_event(event, self.lambda_context) + # Exception triggers logger + mock_logger.debug.assert_any_call( + "The trace extractor returned with error %s", + ANY, ) - self.assertEqual(ctx, None) + self.assertEqual(self.mock_checkpoint.call_count, 1) + args, _ = self.mock_checkpoint.call_args + self.assertEqual(args[0], "kinesis") + self.assertEqual( + args[1], "arn:aws:kinesis:us-east-1:123456789012:stream/test-stream" + ) + carrier_get = args[2] + # None indicates no DSM context propagation + self.assertEqual(carrier_get("dd-pathway-ctx-base64"), None) + def test_kinesis_source_arn_not_found(self): + kinesis_data = {"message": "test"} + kinesis_data_str = json.dumps(kinesis_data) + encoded_data = base64.b64encode(kinesis_data_str.encode()).decode() -class TestStepFunctionsTraceContext(unittest.TestCase): - def test_deterministic_m5_hash(self): - result = _deterministic_md5_hash("some_testing_random_string") - self.assertEqual(2251275791555400689, result) + event = { + "Records": [ + { + "eventSourceARN": "", + "kinesis": {"data": encoded_data}, + } + ] + } - def test_deterministic_m5_hash__result_the_same_as_backend(self): - result = _deterministic_md5_hash( - "arn:aws:states:sa-east-1:601427271234:express:DatadogStateMachine:acaf1a67-336a-e854-1599-2a627eb2dd8a" - ":c8baf081-31f1-464d-971f-70cb17d01111#step-one#2022-12-08T21:08:19.224Z" - ) - self.assertEqual(8034507082463708833, result) + extract_context_from_kinesis_event(event, self.lambda_context) - def test_deterministic_m5_hash__always_leading_with_zero(self): - for i in range(100): - result = _deterministic_md5_hash(str(i)) - result_in_binary = bin(int(result)) - # Leading zeros will be omitted, so only test for full 64 bits present - if len(result_in_binary) == 66: # "0b" + 64 bits. - self.assertTrue(result_in_binary.startswith("0b0")) + self.mock_checkpoint.assert_not_called() + + @patch("datadog_lambda.config.Config.data_streams_enabled", False) + def test_kinesis_data_streams_disabled(self): + context_json = {"dd-pathway-ctx-base64": "12345"} + event_type = "kinesis" + arn = "arn:aws:kinesis:us-east-1:123456789012:stream/test-stream" + + _dsm_set_checkpoint(context_json, event_type, arn) diff --git a/tests/test_trigger.py b/tests/test_trigger.py index 2f5148113..f10fcbbf0 100644 --- a/tests/test_trigger.py +++ b/tests/test_trigger.py @@ -5,22 +5,20 @@ from datadog_lambda.trigger import ( EventSubtypes, + EventTypes, parse_event_source, get_event_source_arn, extract_trigger_tags, extract_http_status_code_tag, + is_step_function_event, ) +from tests.utils import get_mock_context + event_samples = "tests/event_samples/" function_arn = "arn:aws:lambda:us-west-1:123457598159:function:python-layer-test" -def get_mock_context(invoked_function_arn=function_arn): - lambda_context = MagicMock() - lambda_context.invoked_function_arn = invoked_function_arn - return lambda_context - - class TestGetEventSourceAndARN(unittest.TestCase): def test_event_source_api_gateway(self): event_sample_source = "api-gateway" @@ -120,6 +118,22 @@ def test_event_source_application_load_balancer(self): event_source = parse_event_source(event) event_source_arn = get_event_source_arn(event_source, event, ctx) self.assertEqual(event_source.to_string(), event_sample_source) + self.assertEqual(event_source.subtype, EventSubtypes.ALB) + self.assertEqual( + event_source_arn, + "arn:aws:elasticloadbalancing:us-east-2:123456789012:targetgroup/lambda-xyz/123abc", + ) + + def test_event_source_application_load_balancer_multi_value_headers(self): + event_sample_source = "application-load-balancer-multivalue-headers" + test_file = event_samples + event_sample_source + ".json" + with open(test_file, "r") as event: + event = json.load(event) + ctx = get_mock_context() + event_source = parse_event_source(event) + event_source_arn = get_event_source_arn(event_source, event, ctx) + self.assertEqual(event_source.event_type, EventTypes.ALB) + self.assertEqual(event_source.subtype, EventSubtypes.ALB_MULTI_VALUE_HEADERS) self.assertEqual( event_source_arn, "arn:aws:elasticloadbalancing:us-east-2:123456789012:targetgroup/lambda-xyz/123abc", @@ -234,6 +248,20 @@ def test_event_source_sqs(self): "arn:aws:sqs:eu-west-1:601427279990:InferredSpansQueueNode", ) + def test_event_source_stepfunctions(self): + event_sample_source = "states" + test_file = event_samples + event_sample_source + ".json" + with open(test_file, "r") as event: + event = json.load(event) + ctx = get_mock_context() + event_source = parse_event_source(event) + event_source_arn = get_event_source_arn(event_source, event, ctx) + self.assertEqual(event_source.to_string(), event_sample_source) + self.assertEqual( + event_source_arn, + "arn:aws:states:ca-central-1:425362996713:stateMachine:MyStateMachine-wsx8chv4d", + ) + def test_event_source_unsupported(self): event_sample_source = "custom" test_file = event_samples + event_sample_source + ".json" @@ -245,6 +273,37 @@ def test_event_source_unsupported(self): self.assertEqual(event_source.to_string(), "unknown") self.assertEqual(event_source_arn, None) + def test_event_source_with_non_dict_request_context(self): + # Test with requestContext as a string instead of a dict + event = {"requestContext": "not_a_dict"} + event_source = parse_event_source(event) + # Should still return a valid event source (unknown in this case) + self.assertEqual(event_source.to_string(), "unknown") + + def test_event_source_with_invalid_domain_name(self): + # Test with domainName that isn't a string + event = {"requestContext": {"stage": "prod", "domainName": 12345}} + event_source = parse_event_source(event) + # Should detect as API Gateway since stage is present + self.assertEqual(event_source.to_string(), "api-gateway") + + def test_detect_lambda_function_url_domain_with_invalid_input(self): + from datadog_lambda.trigger import detect_lambda_function_url_domain + + # Test with non-string input + self.assertFalse(detect_lambda_function_url_domain(None)) + self.assertFalse(detect_lambda_function_url_domain(12345)) + self.assertFalse(detect_lambda_function_url_domain({"not": "a-string"})) + # Test with string that would normally cause an exception when split + self.assertFalse(detect_lambda_function_url_domain("")) + + def test_event_source_with_non_dict_event_record(self): + # Test with event_record that's not a dictionary + event = {"Records": "not_a_dict"} + event_source = parse_event_source(event) + # Should handle the first non-dict record gracefully and return unknown + self.assertEqual(event_source.to_string(), "unknown") + class GetTriggerTags(unittest.TestCase): def test_extract_trigger_tags_api_gateway(self): @@ -259,9 +318,10 @@ def test_extract_trigger_tags_api_gateway(self): { "function_trigger.event_source": "api-gateway", "function_trigger.event_source_arn": "arn:aws:apigateway:us-west-1::/restapis/1234567890/stages/prod", - "http.url": "70ixmpl4fl.execute-api.us-east-2.amazonaws.com", - "http.url_details.path": "/prod/path/to/resource", + "http.url": "https://70ixmpl4fl.execute-api.us-east-2.amazonaws.com/prod/path/to/resource", "http.method": "POST", + "http.route": "/{proxy+}", + "span.kind": "server", }, ) @@ -277,9 +337,10 @@ def test_extract_trigger_tags_api_gateway_non_proxy(self): { "function_trigger.event_source": "api-gateway", "function_trigger.event_source_arn": "arn:aws:apigateway:us-west-1::/restapis/lgxbo6a518/stages/dev", - "http.url": "lgxbo6a518.execute-api.eu-west-1.amazonaws.com", - "http.url_details.path": "/dev/http/get", + "http.url": "https://lgxbo6a518.execute-api.eu-west-1.amazonaws.com/dev/http/get", "http.method": "GET", + "http.route": "/http/get", + "span.kind": "server", }, ) @@ -295,7 +356,8 @@ def test_extract_trigger_tags_api_gateway_websocket_connect(self): { "function_trigger.event_source": "api-gateway", "function_trigger.event_source_arn": "arn:aws:apigateway:us-west-1::/restapis/p62c47itsb/stages/dev", - "http.url": "p62c47itsb.execute-api.eu-west-1.amazonaws.com", + "http.url": "https://p62c47itsb.execute-api.eu-west-1.amazonaws.com/", + "span.kind": "server", }, ) @@ -311,7 +373,8 @@ def test_extract_trigger_tags_api_gateway_websocket_default(self): { "function_trigger.event_source": "api-gateway", "function_trigger.event_source_arn": "arn:aws:apigateway:us-west-1::/restapis/p62c47itsb/stages/dev", - "http.url": "p62c47itsb.execute-api.eu-west-1.amazonaws.com", + "http.url": "https://p62c47itsb.execute-api.eu-west-1.amazonaws.com/", + "span.kind": "server", }, ) @@ -327,7 +390,8 @@ def test_extract_trigger_tags_api_gateway_websocket_disconnect(self): { "function_trigger.event_source": "api-gateway", "function_trigger.event_source_arn": "arn:aws:apigateway:us-west-1::/restapis/p62c47itsb/stages/dev", - "http.url": "p62c47itsb.execute-api.eu-west-1.amazonaws.com", + "http.url": "https://p62c47itsb.execute-api.eu-west-1.amazonaws.com/", + "span.kind": "server", }, ) @@ -343,9 +407,10 @@ def test_extract_trigger_tags_api_gateway_http_api(self): { "function_trigger.event_source": "api-gateway", "function_trigger.event_source_arn": "arn:aws:apigateway:us-west-1::/restapis/x02yirxc7a/stages/$default", - "http.url": "x02yirxc7a.execute-api.eu-west-1.amazonaws.com", - "http.url_details.path": "/httpapi/get", + "http.url": "https://x02yirxc7a.execute-api.eu-west-1.amazonaws.com/httpapi/get", "http.method": "GET", + "span.kind": "server", + "http.route": "/httpapi/get", }, ) @@ -361,8 +426,8 @@ def test_extract_trigger_tags_application_load_balancer(self): { "function_trigger.event_source": "application-load-balancer", "function_trigger.event_source_arn": "arn:aws:elasticloadbalancing:us-east-2:123456789012:targetgroup/lambda-xyz/123abc", - "http.url_details.path": "/lambda", "http.method": "GET", + "span.kind": "server", }, ) @@ -486,6 +551,21 @@ def test_extract_trigger_tags_sqs(self): }, ) + def test_extract_trigger_tags_stepfunctions(self): + event_sample_source = "states" + test_file = event_samples + event_sample_source + ".json" + ctx = get_mock_context() + with open(test_file, "r") as event: + event = json.load(event) + tags = extract_trigger_tags(event, ctx) + self.assertEqual( + tags, + { + "function_trigger.event_source": "states", + "function_trigger.event_source_arn": "arn:aws:states:ca-central-1:425362996713:stateMachine:MyStateMachine-wsx8chv4d", + }, + ) + def test_extract_trigger_tags_unsupported(self): event_sample_source = "custom" test_file = event_samples + event_sample_source + ".json" @@ -501,6 +581,51 @@ def test_extract_trigger_tags_list_type_event(self): tags = extract_trigger_tags(event, ctx) self.assertEqual(tags, {}) + def test_extract_http_tags_with_invalid_request_context(self): + from datadog_lambda.trigger import extract_http_tags + + # Test with requestContext as a string instead of a dict + event = {"requestContext": "not_a_dict", "path": "/test", "httpMethod": "GET"} + http_tags = extract_http_tags(event) + # Should still extract valid tags from the event + self.assertEqual( + http_tags, + { + "span.kind": "server", + "http.method": "GET", + }, + ) + + def test_extract_http_tags_with_invalid_apigateway_http(self): + from datadog_lambda.trigger import extract_http_tags + + # Test with http in requestContext that's not a dict + event = { + "requestContext": {"stage": "prod", "http": "not_a_dict"}, + "version": "2.0", + } + http_tags = extract_http_tags(event) + # Should not raise an exception + self.assertEqual(http_tags, {"span.kind": "server"}) + + def test_extract_http_tags_with_invalid_headers(self): + from datadog_lambda.trigger import extract_http_tags + + # Test with headers that's not a dict + event = {"headers": "not_a_dict"} + http_tags = extract_http_tags(event) + # Should not raise an exception + self.assertEqual(http_tags, {"span.kind": "server"}) + + def test_extract_http_tags_with_invalid_route(self): + from datadog_lambda.trigger import extract_http_tags + + # Test with routeKey that would cause a split error + event = {"routeKey": 12345} # Not a string + http_tags = extract_http_tags(event) + # Should not raise an exception + self.assertEqual(http_tags, {"span.kind": "server"}) + class ExtractHTTPStatusCodeTag(unittest.TestCase): def test_extract_http_status_code_tag_from_response_dict(self): @@ -515,3 +640,68 @@ def test_extract_http_status_code_tag_from_response_object(self): response.status_code = 403 status_code = extract_http_status_code_tag(trigger_tags, response) self.assertEqual(status_code, "403") + + +class IsStepFunctionEvent(unittest.TestCase): + def test_is_step_function_event_jsonata(self): + event = { + "_datadog": { + "Execution": { + "Id": "665c417c-1237-4742-aaca-8b3becbb9e75", + "RedriveCount": 0, + }, + "StateMachine": {}, + "State": { + "Name": "my-awesome-state", + "EnteredTime": "Mon Nov 13 12:43:33 PST 2023", + "RetryCount": 0, + }, + "x-datadog-trace-id": "5821803790426892636", + "x-datadog-tags": "_dd.p.dm=-0,_dd.p.tid=672a7cb100000000", + "serverless-version": "v1", + } + } + self.assertTrue(is_step_function_event(event)) + + def test_is_step_function_event_jsonpath(self): + event = { + "Execution": { + "Id": "665c417c-1237-4742-aaca-8b3becbb9e75", + "RedriveCount": 0, + }, + "StateMachine": {}, + "State": { + "Name": "my-awesome-state", + "EnteredTime": "Mon Nov 13 12:43:33 PST 2023", + "RetryCount": 0, + }, + } + self.assertTrue(is_step_function_event(event)) + + def test_is_step_function_event_legacy_lambda(self): + event = { + "Payload": { + "Execution": { + "Id": "665c417c-1237-4742-aaca-8b3becbb9e75", + "RedriveCount": 0, + }, + "StateMachine": {}, + "State": { + "Name": "my-awesome-state", + "EnteredTime": "Mon Nov 13 12:43:33 PST 2023", + "RetryCount": 0, + }, + } + } + self.assertTrue(is_step_function_event(event)) + + def test_is_step_function_event_dd_header(self): + event = { + "_datadog": { + "x-datadog-trace-id": "5821803790426892636", + "x-datadog-parent-id": "5821803790426892636", + "x-datadog-tags": "_dd.p.dm=-0,_dd.p.tid=672a7cb100000000", + "x-datadog-sampling-priority": "1", + } + } + self.assertFalse(is_step_function_event(event)) diff --git a/tests/test_version.py b/tests/test_version.py new file mode 100644 index 000000000..ca3c8f03e --- /dev/null +++ b/tests/test_version.py @@ -0,0 +1,7 @@ +import importlib.metadata +from datadog_lambda import __version__ + + +def test_version(): + # test version in __init__ matches version in pyproject.toml + assert importlib.metadata.version("datadog-lambda") == __version__ diff --git a/tests/test_wrapper.py b/tests/test_wrapper.py index 57c5de45d..512a51f89 100644 --- a/tests/test_wrapper.py +++ b/tests/test_wrapper.py @@ -2,30 +2,21 @@ import json import os import unittest +import importlib -from unittest.mock import patch, call, ANY, MagicMock +from unittest.mock import MagicMock, patch, call, ANY from datadog_lambda.constants import TraceHeader import datadog_lambda.wrapper as wrapper +import datadog_lambda.xray as xray + +from datadog_lambda.config import config from datadog_lambda.metric import lambda_metric from datadog_lambda.thread_stats_writer import ThreadStatsWriter -from ddtrace import Span - +from ddtrace.trace import Span, tracer +from ddtrace.internal.constants import MAX_UINT_64BITS -def get_mock_context( - aws_request_id="request-id-1", - memory_limit_in_mb="256", - invoked_function_arn="arn:aws:lambda:us-west-1:123457598159:function:python-layer-test:1", - function_version="1", - client_context={}, -): - lambda_context = MagicMock() - lambda_context.aws_request_id = aws_request_id - lambda_context.memory_limit_in_mb = memory_limit_in_mb - lambda_context.invoked_function_arn = invoked_function_arn - lambda_context.function_version = function_version - lambda_context.client_context = client_context - return lambda_context +from tests.utils import get_mock_context, reset_xray_connection class TestDatadogLambdaWrapper(unittest.TestCase): @@ -36,7 +27,6 @@ def setUp(self): patch("ddtrace.internal.writer.AgentWriter.flush_queue").start() wrapper.datadog_lambda_wrapper._force_wrap = True - wrapper.dd_tracing_enabled = True patcher = patch( "datadog.threadstats.reporters.HttpReporter.flush_distributions" ) @@ -56,40 +46,36 @@ def setUp(self): self.mock_inject_correlation_ids = patcher.start() self.addCleanup(patcher.stop) - patcher = patch("datadog_lambda.wrapper.patch_all") - self.mock_patch_all = patcher.start() + patcher = patch("datadog_lambda.tags.get_cold_start_tag") + self.mock_get_cold_start_tag = patcher.start() + self.mock_get_cold_start_tag.return_value = "cold_start:true" self.addCleanup(patcher.stop) - patcher = patch("datadog_lambda.cold_start.is_cold_start") - self.mock_is_cold_start = patcher.start() - self.mock_is_cold_start.return_value = True - self.addCleanup(patcher.stop) - - patcher = patch("datadog_lambda.tags.python_version_tuple") - self.mock_python_version_tuple = patcher.start() - self.mock_python_version_tuple.return_value = ("3", "9", "10") + patcher = patch("datadog_lambda.tags.runtime_tag", "runtime:python3.9") + self.mock_runtime_tag = patcher.start() self.addCleanup(patcher.stop) patcher = patch("datadog_lambda.metric.write_metric_point_to_stdout") self.mock_write_metric_point_to_stdout = patcher.start() self.addCleanup(patcher.stop) - patcher = patch("datadog_lambda.tags.get_library_version_tag") - self.mock_format_dd_lambda_layer_tag = patcher.start() + patcher = patch( + "datadog_lambda.tags.library_version_tag", "datadog_lambda:v6.6.6" + ) # Mock the layer version so we don't have to update tests on every version bump - self.mock_format_dd_lambda_layer_tag.return_value = "datadog_lambda:v6.6.6" + self.mock_library_version_tag = patcher.start() + self.addCleanup(patcher.stop) - patcher = patch("datadog_lambda.tags._format_dd_lambda_layer_tag") - self.mock_format_dd_lambda_layer_tag = patcher.start() - # Mock the layer version so we don't have to update tests on every version bump - self.mock_format_dd_lambda_layer_tag.return_value = ( - "dd_lambda_layer:datadog-python39_X.X.X" + patcher = patch( + "datadog_lambda.metric.dd_lambda_layer_tag", + "dd_lambda_layer:datadog-python39_X.X.X", ) + # Mock the layer version so we don't have to update tests on every version bump + self.mock_dd_lambda_layer_tag = patcher.start() self.addCleanup(patcher.stop) + @patch("datadog_lambda.config.Config.trace_enabled", False) def test_datadog_lambda_wrapper(self): - wrapper.dd_tracing_enabled = False - @wrapper.datadog_lambda_wrapper def lambda_handler(event, context): lambda_metric("test.metric", 100) @@ -99,7 +85,6 @@ def lambda_handler(event, context): lambda_context = get_mock_context() lambda_handler(lambda_event, lambda_context) - wrapper.dd_tracing_enabled = True self.mock_threadstats_flush_distributions.assert_has_calls( [ call( @@ -125,7 +110,6 @@ def lambda_handler(event, context): ) self.mock_set_correlation_ids.assert_called() self.mock_inject_correlation_ids.assert_called() - self.mock_patch_all.assert_called() def test_datadog_lambda_wrapper_flush_to_log(self): os.environ["DD_FLUSH_TO_LOG"] = "True" @@ -155,6 +139,7 @@ def lambda_handler(event, context): lambda_metric("test.metric", 100) time.sleep(11) # assert flushing in the thread + # TODO(astuyve) flaky test here, sometimes this is zero self.assertEqual(self.mock_threadstats_flush_distributions.call_count, 1) lambda_metric("test.metric", 200) @@ -195,9 +180,9 @@ def lambda_handler(event, context): metric_module.lambda_stats.stop() metric_module.lambda_stats = ThreadStatsWriter(False) + @patch("datadog_lambda.config.Config.trace_enabled", False) def test_datadog_lambda_wrapper_inject_correlation_ids(self): os.environ["DD_LOGS_INJECTION"] = "True" - wrapper.dd_tracing_enabled = False @wrapper.datadog_lambda_wrapper def lambda_handler(event, context): @@ -205,7 +190,6 @@ def lambda_handler(event, context): lambda_event = {} lambda_handler(lambda_event, get_mock_context()) - wrapper.dd_tracing_enabled = True self.mock_set_correlation_ids.assert_called() self.mock_inject_correlation_ids.assert_called() @@ -229,9 +213,9 @@ def lambda_handler(event, context): "region:us-west-1", "account_id:123457598159", "functionname:python-layer-test", - "resource:python-layer-test:1", - "cold_start:true", + "resource:python-layer-test", "memorysize:256", + "cold_start:true", "runtime:python3.9", "datadog_lambda:v6.6.6", "dd_lambda_layer:datadog-python39_X.X.X", @@ -260,9 +244,9 @@ def lambda_handler(event, context): "region:us-west-1", "account_id:123457598159", "functionname:python-layer-test", - "resource:python-layer-test:1", - "cold_start:true", + "resource:python-layer-test", "memorysize:256", + "cold_start:true", "runtime:python3.9", "datadog_lambda:v6.6.6", "dd_lambda_layer:datadog-python39_X.X.X", @@ -276,9 +260,9 @@ def lambda_handler(event, context): "region:us-west-1", "account_id:123457598159", "functionname:python-layer-test", - "resource:python-layer-test:1", - "cold_start:true", + "resource:python-layer-test", "memorysize:256", + "cold_start:true", "runtime:python3.9", "datadog_lambda:v6.6.6", "dd_lambda_layer:datadog-python39_X.X.X", @@ -293,7 +277,7 @@ def test_5xx_sends_errors_metric_and_set_tags(self, mock_extract_trigger_tags): mock_extract_trigger_tags.return_value = { "function_trigger.event_source": "api-gateway", "function_trigger.event_source_arn": "arn:aws:apigateway:us-west-1::/restapis/1234567890/stages/prod", - "http.url": "70ixmpl4fl.execute-api.us-east-2.amazonaws.com", + "http.url": "https://70ixmpl4fl.execute-api.us-east-2.amazonaws.com/", "http.url_details.path": "/prod/path/to/resource", "http.method": "GET", } @@ -315,9 +299,9 @@ def lambda_handler(event, context): "region:us-west-1", "account_id:123457598159", "functionname:python-layer-test", - "resource:python-layer-test:1", - "cold_start:true", + "resource:python-layer-test", "memorysize:256", + "cold_start:true", "runtime:python3.9", "datadog_lambda:v6.6.6", "dd_lambda_layer:datadog-python39_X.X.X", @@ -331,9 +315,9 @@ def lambda_handler(event, context): "region:us-west-1", "account_id:123457598159", "functionname:python-layer-test", - "resource:python-layer-test:1", - "cold_start:true", + "resource:python-layer-test", "memorysize:256", + "cold_start:true", "runtime:python3.9", "datadog_lambda:v6.6.6", "dd_lambda_layer:datadog-python39_X.X.X", @@ -352,7 +336,7 @@ def lambda_handler(event, context): lambda_handler(lambda_event, get_mock_context()) - self.mock_is_cold_start.return_value = False + self.mock_get_cold_start_tag.return_value = "cold_start:false" lambda_handler( lambda_event, get_mock_context(aws_request_id="second-request-id") @@ -367,9 +351,9 @@ def lambda_handler(event, context): "region:us-west-1", "account_id:123457598159", "functionname:python-layer-test", - "resource:python-layer-test:1", - "cold_start:true", + "resource:python-layer-test", "memorysize:256", + "cold_start:true", "runtime:python3.9", "datadog_lambda:v6.6.6", "dd_lambda_layer:datadog-python39_X.X.X", @@ -383,9 +367,9 @@ def lambda_handler(event, context): "region:us-west-1", "account_id:123457598159", "functionname:python-layer-test", - "resource:python-layer-test:1", - "cold_start:false", + "resource:python-layer-test", "memorysize:256", + "cold_start:false", "runtime:python3.9", "datadog_lambda:v6.6.6", "dd_lambda_layer:datadog-python39_X.X.X", @@ -418,8 +402,8 @@ def lambda_handler(event, context): "account_id:123457598159", "functionname:python-layer-test", "resource:python-layer-test:Latest", - "cold_start:true", "memorysize:256", + "cold_start:true", "runtime:python3.9", "datadog_lambda:v6.6.6", "dd_lambda_layer:datadog-python39_X.X.X", @@ -452,8 +436,8 @@ def lambda_handler(event, context): "functionname:python-layer-test", "executedversion:1", "resource:python-layer-test:My_alias-1", - "cold_start:true", "memorysize:256", + "cold_start:true", "runtime:python3.9", "datadog_lambda:v6.6.6", "dd_lambda_layer:datadog-python39_X.X.X", @@ -463,9 +447,8 @@ def lambda_handler(event, context): ] ) + @patch("datadog_lambda.config.Config.enhanced_metrics_enabled", False) def test_no_enhanced_metrics_without_env_var(self): - os.environ["DD_ENHANCED_METRICS"] = "false" - @wrapper.datadog_lambda_wrapper def lambda_handler(event, context): raise RuntimeError() @@ -477,10 +460,8 @@ def lambda_handler(event, context): self.mock_write_metric_point_to_stdout.assert_not_called() - del os.environ["DD_ENHANCED_METRICS"] - def test_only_one_wrapper_in_use(self): - patcher = patch("datadog_lambda.wrapper.submit_invocations_metric") + patcher = patch("datadog_lambda.metric.submit_invocations_metric") self.mock_submit_invocations_metric = patcher.start() self.addCleanup(patcher.stop) @@ -498,10 +479,12 @@ def lambda_handler(event, context): lambda_handler_double_wrapped(lambda_event, get_mock_context()) - self.mock_patch_all.assert_called_once() self.mock_submit_invocations_metric.assert_called_once() def test_dd_requests_service_name_default(self): + # TODO(astuyve) this is now set by CI, so we need to null it out for this case + os.environ["DD_SERVICE"] = "aws.lambda" + @wrapper.datadog_lambda_wrapper def lambda_handler(event, context): pass @@ -518,6 +501,7 @@ def lambda_handler(event, context): self.assertEqual(os.environ.get("DD_REQUESTS_SERVICE_NAME"), "myAwesomeService") del os.environ["DD_SERVICE"] + @patch("datadog_lambda.config.Config.make_inferred_span", False) def test_encode_authorizer_span(self): @wrapper.datadog_lambda_wrapper def lambda_handler(event, context): @@ -539,21 +523,21 @@ def lambda_handler(event, context): lambda_event = {} lambda_context = get_mock_context() - mock_span = Span(name="my_inferred_span", span_id=123, trace_id=456) - mock_span.context.sampling_priority = "1" - mock_span.context.dd_origin = None - mock_span.start_ns = 1668127541671386817 - mock_span.duration_ns = 1e8 - lambda_handler.inferred_span = mock_span - lambda_handler.make_inferred_span = False + test_span = tracer.trace("test_span") + trace_ctx = tracer.current_trace_context() + trace_ctx.sampling_priority = 1 + test_span.finish() + lambda_handler.inferred_span = test_span result = lambda_handler(lambda_event, lambda_context) raw_inject_data = result["context"]["_datadog"] self.assertIsInstance(raw_inject_data, str) inject_data = json.loads(base64.b64decode(raw_inject_data)) - self.assertEquals(inject_data[TraceHeader.PARENT_ID], "123") - self.assertEquals(inject_data[TraceHeader.TRACE_ID], "456") - self.assertEquals(inject_data[TraceHeader.SAMPLING_PRIORITY], "1") - self.assertEquals(result["context"]["scope"], "still here") + self.assertEqual(inject_data[TraceHeader.PARENT_ID], str(trace_ctx.span_id)) + self.assertEqual( + inject_data[TraceHeader.TRACE_ID], str(MAX_UINT_64BITS & trace_ctx.trace_id) + ) + self.assertEqual(inject_data[TraceHeader.SAMPLING_PRIORITY], "1") + self.assertEqual(result["context"]["scope"], "still here") @patch("traceback.print_exc") def test_different_return_type_no_error(self, MockPrintExc): @@ -566,17 +550,410 @@ def return_type_test(event, context): return test_result result = return_type_test({}, mock_context) - self.assertEquals(result, test_result) + self.assertEqual(result, test_result) self.assertFalse(MockPrintExc.called) -class TestLambdaDecoratorSettings(unittest.TestCase): - def test_some_envs_should_depend_on_dd_tracing_enabled(self): - wrapper.dd_tracing_enabled = False - os.environ[wrapper.DD_TRACE_MANAGED_SERVICES] = "true" - os.environ[wrapper.DD_ENCODE_AUTHORIZER_CONTEXT] = "true" - os.environ[wrapper.DD_DECODE_AUTHORIZER_CONTEXT] = "true" - decorator = wrapper._LambdaDecorator(func=None) - self.assertFalse(decorator.make_inferred_span) - self.assertFalse(decorator.encode_authorizer_context) - self.assertFalse(decorator.decode_authorizer_context) +class TestLambdaWrapperWithTraceContext(unittest.TestCase): + xray_root = "1-5e272390-8c398be037738dc042009320" + xray_parent = "94ae789b969f1cc5" + xray_daemon_envvar = "localhost:1234" + xray_trace_envvar = ( + f"Root={xray_root};Parent={xray_parent};Sampled=1;Lineage=c6c5b1b9:0" + ) + + @patch( + "os.environ", + { + "AWS_XRAY_DAEMON_ADDRESS": xray_daemon_envvar, + "_X_AMZN_TRACE_ID": xray_trace_envvar, + }, + ) + def test_event_bridge_sqs_payload(self): + reset_xray_connection() + + patcher = patch("datadog_lambda.xray.sock.send") + mock_send = patcher.start() + self.addCleanup(patcher.stop) + + def handler(event, context): + return tracer.current_trace_context() + + wrapper.dd_tracing_enabled = True + wrapped_handler = wrapper.datadog_lambda_wrapper(handler) + + event_trace_id = 3047453991382739997 + event_parent_id = 3047453991382739997 + event = { + "headers": { + "traceparent": ( + f"00-0000000000000000{hex(event_trace_id)[2:]}-{hex(event_parent_id)[2:]}-01" + ), + "tracestate": "dd=s:1;t.dm:-1", + "x-datadog-trace-id": str(event_trace_id), + "x-datadog-parent-id": str(event_parent_id), + "x-datadog-sampling-priority": "1", + }, + } + context = get_mock_context() + + result = wrapped_handler(event, context) + aws_lambda_span = wrapped_handler.span + + self.assertIsNotNone(result) + self.assertEqual(result.trace_id, event_trace_id) + self.assertEqual(result.span_id, aws_lambda_span.span_id) + self.assertEqual(result.sampling_priority, 1) + mock_send.assert_called_once() + (raw_payload,), _ = mock_send.call_args + payload = json.loads(raw_payload[33:]) # strip formatting prefix + self.assertEqual(self.xray_root, payload["trace_id"]) + self.assertEqual(self.xray_parent, payload["parent_id"]) + self.assertDictEqual( + { + "datadog": { + "trace": { + "trace-id": str(event_trace_id), + "parent-id": str(event_parent_id), + "sampling-priority": "1", + }, + }, + }, + payload["metadata"], + ) + + +class TestLambdaWrapperFlushExtension(unittest.TestCase): + @patch("datadog_lambda.config.Config.local_test", True) + @patch("datadog_lambda.wrapper.should_use_extension", True) + def test_local_test_true_flushing(self): + flushes = [] + lambda_event = {} + lambda_context = get_mock_context() + + def flush(): + flushes.append(1) + + @patch("datadog_lambda.wrapper.flush_extension", flush) + @wrapper.datadog_lambda_wrapper + def lambda_handler(event, context): + pass + + lambda_handler(lambda_event, lambda_context) + + self.assertEqual(len(flushes), 1) + + @patch("datadog_lambda.config.Config.local_test", False) + @patch("datadog_lambda.wrapper.should_use_extension", True) + def test_local_test_false_flushing(self): + flushes = [] + lambda_event = {} + lambda_context = get_mock_context() + + def flush(): + flushes.append(1) + + @patch("datadog_lambda.wrapper.flush_extension", flush) + @wrapper.datadog_lambda_wrapper + def lambda_handler(event, context): + pass + + lambda_handler(lambda_event, lambda_context) + + self.assertEqual(len(flushes), 0) + + +class TestLambdaWrapperAppsecBlocking(unittest.TestCase): + def setUp(self): + os.environ["DD_APPSEC_ENABLED"] = "true" + os.environ["DD_TRACE_ENABLED"] = "true" + + importlib.reload(wrapper) + + self.addCleanup(os.environ.pop, "DD_APPSEC_ENABLED", None) + self.addCleanup(os.environ.pop, "DD_TRACE_ENABLED", None) + self.addCleanup(lambda: importlib.reload(wrapper)) + + patcher = patch("datadog_lambda.wrapper.asm_set_context") + self.mock_asm_set_context = patcher.start() + self.addCleanup(patcher.stop) + + patcher = patch("datadog_lambda.wrapper.asm_start_request") + self.mock_asm_start_request = patcher.start() + self.addCleanup(patcher.stop) + + patcher = patch("datadog_lambda.wrapper.asm_start_response") + self.mock_asm_start_response = patcher.start() + self.addCleanup(patcher.stop) + + patcher = patch("datadog_lambda.wrapper.get_asm_blocked_response") + self.mock_get_asm_blocking_response = patcher.start() + self.addCleanup(patcher.stop) + + with open("tests/event_samples/api-gateway.json") as f: + self.api_gateway_request = json.loads(f.read()) + + self.fake_blocking_response = { + "statusCode": "403", + "headers": { + "Content-Type": "application/json", + }, + "body": '{"message": "Blocked by AppSec"}', + "isBase64Encoded": False, + } + + def test_blocking_before(self): + self.mock_get_asm_blocking_response.return_value = self.fake_blocking_response + + mock_handler = MagicMock() + + lambda_handler = wrapper.datadog_lambda_wrapper(mock_handler) + + response = lambda_handler(self.api_gateway_request, get_mock_context()) + self.assertEqual(response, self.fake_blocking_response) + + mock_handler.assert_not_called() + + self.mock_asm_set_context.assert_called_once() + self.mock_asm_start_request.assert_called_once() + self.mock_asm_start_response.assert_not_called() + + assert lambda_handler.span.get_tag("http.status_code") == "403" + + def test_blocking_during(self): + self.mock_get_asm_blocking_response.return_value = None + + def lambda_handler(event, context): + self.mock_get_asm_blocking_response.return_value = ( + self.fake_blocking_response + ) + raise wrapper.BlockingException() + + lambda_handler = wrapper.datadog_lambda_wrapper(lambda_handler) + + response = lambda_handler(self.api_gateway_request, get_mock_context()) + self.assertEqual(response, self.fake_blocking_response) + + self.mock_asm_set_context.assert_called_once() + self.mock_asm_start_request.assert_called_once() + self.mock_asm_start_response.assert_not_called() + + assert lambda_handler.span.get_tag("http.status_code") == "403" + + def test_blocking_after(self): + self.mock_get_asm_blocking_response.return_value = None + + def lambda_handler(event, context): + self.mock_get_asm_blocking_response.return_value = ( + self.fake_blocking_response + ) + return { + "statusCode": 200, + "body": "This should not be returned", + } + + lambda_handler = wrapper.datadog_lambda_wrapper(lambda_handler) + + response = lambda_handler(self.api_gateway_request, get_mock_context()) + self.assertEqual(response, self.fake_blocking_response) + + self.mock_asm_set_context.assert_called_once() + self.mock_asm_start_request.assert_called_once() + self.mock_asm_start_response.assert_called_once() + + assert lambda_handler.span.get_tag("http.status_code") == "403" + + def test_no_blocking_appsec_disabled(self): + os.environ["DD_APPSEC_ENABLED"] = "false" + + importlib.reload(wrapper) + + self.mock_get_asm_blocking_response.return_value = self.fake_blocking_response + + expected_response = { + "statusCode": 200, + "body": "This should be returned", + } + + def lambda_handler(event, context): + return expected_response + + lambda_handler = wrapper.datadog_lambda_wrapper(lambda_handler) + + response = lambda_handler(self.api_gateway_request, get_mock_context()) + self.assertEqual(response, expected_response) + + self.mock_get_asm_blocking_response.assert_not_called() + self.mock_asm_set_context.assert_not_called() + self.mock_asm_start_request.assert_not_called() + self.mock_asm_start_response.assert_not_called() + + assert lambda_handler.span.get_tag("http.status_code") == "200" + + +@patch("datadog_lambda.config.Config.exception_replay_enabled", True) +def test_exception_replay_enabled(monkeypatch): + importlib.reload(wrapper) + + original_SpanExceptionHandler_enable = wrapper.SpanExceptionHandler.enable + SpanExceptionHandler_enable_calls = [] + + def SpanExceptionHandler_enable(*args, **kwargs): + SpanExceptionHandler_enable_calls.append((args, kwargs)) + return original_SpanExceptionHandler_enable(*args, **kwargs) + + original_SignalUploader_periodic = wrapper.SignalUploader.periodic + SignalUploader_periodic_calls = [] + + def SignalUploader_periodic(*args, **kwargs): + SignalUploader_periodic_calls.append((args, kwargs)) + return original_SignalUploader_periodic(*args, **kwargs) + + monkeypatch.setattr( + "datadog_lambda.wrapper.SpanExceptionHandler.enable", + SpanExceptionHandler_enable, + ) + monkeypatch.setattr( + "datadog_lambda.wrapper.SignalUploader.periodic", SignalUploader_periodic + ) + + expected_response = { + "statusCode": 200, + "body": "This should be returned", + } + + @wrapper.datadog_lambda_wrapper + def lambda_handler(event, context): + return expected_response + + response = lambda_handler({}, get_mock_context()) + + assert response == expected_response + assert len(SpanExceptionHandler_enable_calls) == 1 + assert len(SignalUploader_periodic_calls) == 1 + + +@patch("datadog_lambda.config.Config.profiling_enabled", True) +def test_profiling_enabled(monkeypatch): + importlib.reload(wrapper) + + original_Profiler_start = wrapper.profiler.Profiler.start + Profiler_start_calls = [] + + def Profiler_start(*args, **kwargs): + Profiler_start_calls.append((args, kwargs)) + return original_Profiler_start(*args, **kwargs) + + monkeypatch.setattr("datadog_lambda.wrapper.is_new_sandbox", lambda: True) + monkeypatch.setattr( + "datadog_lambda.wrapper.profiler.Profiler.start", Profiler_start + ) + + expected_response = { + "statusCode": 200, + "body": "This should be returned", + } + + @wrapper.datadog_lambda_wrapper + def lambda_handler(event, context): + return expected_response + + response = lambda_handler({}, get_mock_context()) + + assert response == expected_response + assert len(Profiler_start_calls) == 1 + + +@patch("datadog_lambda.config.Config.llmobs_enabled", True) +def test_llmobs_enabled(monkeypatch): + importlib.reload(wrapper) + + original_LLMObs_enable = wrapper.LLMObs.enable + LLMObs_enable_calls = [] + + def LLMObs_enable(*args, **kwargs): + LLMObs_enable_calls.append((args, kwargs)) + return original_LLMObs_enable(*args, **kwargs) + + original_LLMObs_flush = wrapper.LLMObs.flush + LLMObs_flush_calls = [] + + def LLMObs_flush(*args, **kwargs): + LLMObs_flush_calls.append((args, kwargs)) + return original_LLMObs_flush(*args, **kwargs) + + monkeypatch.setattr("datadog_lambda.wrapper.LLMObs.enable", LLMObs_enable) + monkeypatch.setattr("datadog_lambda.wrapper.LLMObs.flush", LLMObs_flush) + + expected_response = { + "statusCode": 200, + "body": "This should be returned", + } + + @wrapper.datadog_lambda_wrapper + def lambda_handler(event, context): + return expected_response + + response = lambda_handler({}, get_mock_context()) + + assert response == expected_response + assert len(LLMObs_enable_calls) == 1 + assert len(LLMObs_flush_calls) == 1 + + +@patch("datadog_lambda.config.Config.trace_enabled", False) +def test_batch_item_failures_metric(): + with patch( + "datadog_lambda.metric.submit_batch_item_failures_metric" + ) as mock_submit: + + @wrapper.datadog_lambda_wrapper + def lambda_handler(event, context): + return { + "batchItemFailures": [ + {"itemIdentifier": "msg-1"}, + {"itemIdentifier": "msg-2"}, + ] + } + + lambda_handler({}, get_mock_context()) + mock_submit.assert_called_once() + call_args = mock_submit.call_args[0] + assert call_args[0] == { + "batchItemFailures": [ + {"itemIdentifier": "msg-1"}, + {"itemIdentifier": "msg-2"}, + ] + } + + +@patch("datadog_lambda.config.Config.trace_enabled", False) +def test_batch_item_failures_metric_no_failures(): + with patch( + "datadog_lambda.metric.submit_batch_item_failures_metric" + ) as mock_submit: + + @wrapper.datadog_lambda_wrapper + def lambda_handler(event, context): + return {"batchItemFailures": []} + + lambda_handler({}, get_mock_context()) + mock_submit.assert_called_once() + call_args = mock_submit.call_args[0] + assert call_args[0] == {"batchItemFailures": []} + + +@patch("datadog_lambda.config.Config.trace_enabled", False) +def test_batch_item_failures_metric_no_response(): + with patch( + "datadog_lambda.metric.submit_batch_item_failures_metric" + ) as mock_submit: + + @wrapper.datadog_lambda_wrapper + def lambda_handler(event, context): + return None + + lambda_handler({}, get_mock_context()) + mock_submit.assert_called_once() + call_args = mock_submit.call_args[0] + assert call_args[0] is None diff --git a/tests/test_xray.py b/tests/test_xray.py index ac3594a99..7f33f8915 100644 --- a/tests/test_xray.py +++ b/tests/test_xray.py @@ -4,15 +4,14 @@ from unittest.mock import MagicMock, patch -from datadog_lambda.xray import ( - get_xray_host_port, - build_segment_payload, - build_segment, - send_segment, -) +from datadog_lambda.xray import build_segment_payload, build_segment, send_segment, sock +from tests.utils import reset_xray_connection class TestXRay(unittest.TestCase): + def setUp(self): + reset_xray_connection() + def tearDown(self): if os.environ.get("_X_AMZN_TRACE_ID"): os.environ.pop("_X_AMZN_TRACE_ID") @@ -21,15 +20,15 @@ def tearDown(self): return super().tearDown() def test_get_xray_host_port_empty_(self): - result = get_xray_host_port("") + result = sock._get_xray_host_port("") self.assertIsNone(result) def test_get_xray_host_port_invalid_value(self): - result = get_xray_host_port("myVar") + result = sock._get_xray_host_port("myVar") self.assertIsNone(result) def test_get_xray_host_port_success(self): - result = get_xray_host_port("mySuperHost:1000") + result = sock._get_xray_host_port("mySuperHost:1000") self.assertEqual("mySuperHost", result[0]) self.assertEqual(1000, result[1]) @@ -40,7 +39,7 @@ def test_send_segment_sampled_out(self): ] = "Root=1-5e272390-8c398be037738dc042009320;Parent=94ae789b969f1cc5;Sampled=0;Lineage=c6c5b1b9:0" with patch( - "datadog_lambda.xray.send", MagicMock(return_value=None) + "datadog_lambda.xray.sock.send", MagicMock(return_value=None) ) as mock_send: # XRay trace won't be sampled according to the trace header. send_segment("my_key", {"data": "value"}) @@ -52,7 +51,7 @@ def test_send_segment_sampled(self): "_X_AMZN_TRACE_ID" ] = "Root=1-5e272390-8c398be037738dc042009320;Parent=94ae789b969f1cc5;Sampled=1;Lineage=c6c5b1b9:0" with patch( - "datadog_lambda.xray.send", MagicMock(return_value=None) + "datadog_lambda.xray.sock.send", MagicMock(return_value=None) ) as mock_send: # X-Ray trace will be sampled according to the trace header. send_segment("my_key", {"data": "value"}) diff --git a/tests/utils.py b/tests/utils.py new file mode 100644 index 000000000..2d56ca0c0 --- /dev/null +++ b/tests/utils.py @@ -0,0 +1,37 @@ +from unittest.mock import MagicMock + +function_arn = "arn:aws:lambda:us-west-1:123457598159:function:python-layer-test" + + +class ClientContext(object): + def __init__(self, custom=None): + self.custom = custom + + +def get_mock_context( + aws_request_id="request-id-1", + memory_limit_in_mb="256", + invoked_function_arn=function_arn, + function_version="1", + function_name="Function", + custom=None, +): + lambda_context = MagicMock() + lambda_context.aws_request_id = aws_request_id + lambda_context.memory_limit_in_mb = memory_limit_in_mb + lambda_context.invoked_function_arn = invoked_function_arn + lambda_context.function_version = function_version + lambda_context.function_name = function_name + lambda_context.get_remaining_time_in_millis = lambda: 100 + lambda_context.client_context = ClientContext(custom) + return lambda_context + + +def reset_xray_connection(): + from datadog_lambda.xray import sock + + if hasattr(sock, "_host_port_tuple"): + del sock._host_port_tuple + if sock.sock: + sock.sock.close() + sock.sock = None