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 bc76a699c..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'] + 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'] - 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 277bac103..cc9e9d70f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ ARG image -FROM $image +FROM $image as builder ARG runtime @@ -7,13 +7,78 @@ ARG runtime RUN mkdir -p /build/python/lib/$runtime/site-packages WORKDIR /build +# 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 + +# 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 + # Install datadog_lambda and dependencies from local COPY . . -RUN pip install . -t ./python/lib/$runtime/site-packages - -# Remove *.pyc files -RUN find ./python/lib/$runtime/site-packages -name \*.pyc -delete +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 and symbols that are not needed for relocation +# processing using strip --strip-unneeded for all .so files. 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 -name "*.so" -exec strip --strip-unneeded {} \; + +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 87ec805c6..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, and 3.10) 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 @@ -16,6 +16,22 @@ Follow the [installation instructions](https://docs.datadoghq.com/serverless/ins Follow the [configuration instructions](https://docs.datadoghq.com/serverless/configuration) to tag your telemetry, capture request/response payloads, filter or scrub sensitive information from logs or traces, and more. +For additional tracing configuration options, check out the [official documentation for Datadog trace client](https://ddtrace.readthedocs.io/en/stable/configuration.html). + +Besides the environment variables supported by dd-trace-py, the datadog-lambda-python library added following environment variables. + +| Environment Variables | Description | Default Value | +| -------------------- | ------------ | ------------- | +| 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 | 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 If you encounter a bug with this package, we want to hear about it. Before opening a new issue, search the existing issues to avoid duplicates. @@ -32,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. @@ -51,3 +73,5 @@ For product feedback and questions, join the `#serverless` channel in the [Datad 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. + +[1]: https://www.datadoghq.com/blog/troubleshoot-lambda-function-request-response-payloads/ 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..059cead9e 100644 --- a/datadog_lambda/__init__.py +++ b/datadog_lambda/__init__.py @@ -1,17 +1,20 @@ -import os -import logging +import datadog_lambda.config # noqa: F401 needs to be imported before `ddtrace` from datadog_lambda.cold_start import initialize_cold_start_tracing + 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 a10a2ad7a..a40e2fcb3 100644 --- a/datadog_lambda/cold_start.py +++ b/datadog_lambda/cold_start.py @@ -1,23 +1,38 @@ 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(): +def set_cold_start(init_timestamp_ns): """Set the value of the cold start global This should be executed once per Lambda execution before the execution """ global _cold_start global _lambda_container_initialized - _cold_start = not _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: + _cold_start = False + _proactive_initialization = True + else: + _cold_start = not _lambda_container_initialized + else: + _cold_start = False + _proactive_initialization = False _lambda_container_initialized = True + from ddtrace.trace import tracer as _tracer def is_cold_start(): @@ -25,9 +40,27 @@ def is_cold_start(): return _cold_start +def is_proactive_init(): + """Returns the value of the global proactive_initialization""" + return _proactive_initialization + + +def is_new_sandbox(): + return is_cold_start() or is_proactive_init() + + 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:true" + if _proactive_initialization + else "proactive_initialization:false" + ) class ImportNode(object): @@ -37,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] = [] @@ -45,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() @@ -69,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) @@ -114,19 +145,14 @@ def wrapped_find_spec(*args, **kwargs): def initialize_cold_start_tracing(): - if ( - is_cold_start() - 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): @@ -159,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..eda6b5828 --- /dev/null +++ b/datadog_lambda/config.py @@ -0,0 +1,149 @@ +# 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) + + 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) + sca_enabled = _get_env("DD_APPSEC_SCA_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", + ) + + +if ( + "DD_INSTRUMENTATION_TELEMETRY_ENABLED" not in os.environ + and not config.sca_enabled + and not config.appsec_enabled +): + os.environ["DD_INSTRUMENTATION_TELEMETRY_ENABLED"] = "false" 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 02dc3ebef..744e48933 100644 --- a/datadog_lambda/tag_object.py +++ b/datadog_lambda/tag_object.py @@ -4,21 +4,19 @@ # 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 depth >= max_depth: - return - else: - depth += 1 if obj is None: return span.set_tag(key, obj) + 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): parsed = None try: @@ -28,18 +26,27 @@ def tag_object(span, key, obj, depth=0): redacted = _redact_val(key, obj[0:5000]) return span.set_tag(key, redacted) if isinstance(obj, int) or isinstance(obj, float) or isinstance(obj, Decimal): - return span.set_tag(key, obj) + 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 isinstance(obj, object): - for k in obj: - v = obj.get(k) - formatted_key = "{}.{}".format(key, k) + if hasattr(obj, "items"): + for k, v in obj.items(): + 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 = f"{key}.{k}" + tag_object(span, formatted_key, v, depth) + return + try: + value_as_str = str(obj) + except Exception: + value_as_str = "UNKNOWN" + return span.set_tag(key, value_as_str) def _should_try_string(obj): 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 7879697ee..225f5dd82 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 @@ -20,7 +20,6 @@ from datadog_lambda.constants import ( SamplingPriority, - TraceHeader, TraceContextSource, XrayDaemon, Headers, @@ -29,53 +28,82 @@ 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.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, ) +if config.otel_enabled: + from opentelemetry.trace import set_tracer_provider + from ddtrace.opentelemetry import TracerProvider + + set_tracer_provider(TracerProvider()) + + logger = logging.getLogger(__name__) -dd_trace_context = {} -dd_tracing_enabled = os.environ.get("DD_TRACE_ENABLED", "false").lower() == "true" +dd_trace_context = None 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): """ Convert X-Ray trace id (hex)'s last 63 bits to a Datadog trace id (int). """ - return str(0x7FFFFFFFFFFFFFFF & int(xray_trace_id[-16:], 16)) + return 0x7FFFFFFFFFFFFFFF & int(xray_trace_id[-16:], 16) def _convert_xray_entity_id(xray_entity_id): """ Convert X-Ray (sub)segement id (hex) to a Datadog span id (int). """ - return str(int(xray_entity_id, 16)) + return int(xray_entity_id, 16) def _convert_xray_sampling(xray_sampled): """ Convert X-Ray sampled (True/False) to its Datadog counterpart. """ - return ( - str(SamplingPriority.USER_KEEP) - if xray_sampled - else str(SamplingPriority.USER_REJECT) - ) + return SamplingPriority.USER_KEEP if xray_sampled else SamplingPriority.USER_REJECT def _get_xray_trace_context(): - if not is_lambda_context(): + if not config.is_lambda_context: return None xray_trace_entity = parse_xray_header( @@ -83,19 +111,15 @@ def _get_xray_trace_context(): ) if xray_trace_entity is None: return None - trace_context = { - "trace-id": _convert_xray_trace_id(xray_trace_entity.get("trace_id")), - "parent-id": _convert_xray_entity_id(xray_trace_entity.get("parent_id")), - "sampling-priority": _convert_xray_sampling(xray_trace_entity.get("sampled")), - } + trace_context = Context( + trace_id=_convert_xray_trace_id(xray_trace_entity.get("trace_id")), + span_id=_convert_xray_entity_id(xray_trace_entity.get("parent_id")), + sampling_priority=_convert_xray_sampling(xray_trace_entity.get("sampled")), + ) 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 @@ -105,26 +129,21 @@ def _get_dd_trace_py_context(): if not span: return None - parent_id = span.context.span_id - trace_id = span.context.trace_id - sampling_priority = span.context.sampling_priority 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 { - "parent-id": str(parent_id), - "trace-id": str(trace_id), - "sampling-priority": str(sampling_priority), - "source": TraceContextSource.DDTRACE, - } + return span.context -def _context_obj_to_headers(obj): - return { - TraceHeader.TRACE_ID: str(obj.get("trace-id")), - TraceHeader.PARENT_ID: str(obj.get("parent-id")), - TraceHeader.SAMPLING_PRIORITY: str(obj.get("sampling-priority")), - } +def _is_context_complete(context): + return ( + context + and context.trace_id + and context.span_id + and context.sampling_priority is not None + ) def create_dd_dummy_metadata_subsegment( @@ -145,28 +164,14 @@ def extract_context_from_lambda_context(lambda_context): dd_trace libraries inject this trace context on synchronous invocations """ + dd_data = None client_context = lambda_context.client_context - trace_id = None - parent_id = None - sampling_priority = None if client_context and client_context.custom: + dd_data = client_context.custom if "_datadog" in client_context.custom: # Legacy trace propagation dict - dd_data = client_context.custom.get("_datadog", {}) - trace_id = dd_data.get(TraceHeader.TRACE_ID) - parent_id = dd_data.get(TraceHeader.PARENT_ID) - sampling_priority = dd_data.get(TraceHeader.SAMPLING_PRIORITY) - elif ( - TraceHeader.TRACE_ID in client_context.custom - and TraceHeader.PARENT_ID in client_context.custom - and TraceHeader.SAMPLING_PRIORITY in client_context.custom - ): - # New trace propagation keys - trace_id = client_context.custom.get(TraceHeader.TRACE_ID) - parent_id = client_context.custom.get(TraceHeader.PARENT_ID) - sampling_priority = client_context.custom.get(TraceHeader.SAMPLING_PRIORITY) - - return trace_id, parent_id, sampling_priority + dd_data = client_context.custom.get("_datadog") + return propagator.extract(dd_data) def extract_context_from_http_event_or_context( @@ -186,33 +191,31 @@ def extract_context_from_http_event_or_context( EventTypes.API_GATEWAY, subtype=EventSubtypes.HTTP_API ) injected_authorizer_data = get_injected_authorizer_data(event, is_http_api) - if injected_authorizer_data: - try: - # fail fast on any KeyError here - trace_id = injected_authorizer_data[TraceHeader.TRACE_ID] - parent_id = injected_authorizer_data[TraceHeader.PARENT_ID] - sampling_priority = injected_authorizer_data.get( - TraceHeader.SAMPLING_PRIORITY - ) - return trace_id, parent_id, sampling_priority - except Exception as e: - logger.debug( - "extract_context_from_authorizer_event returned with error. \ - Continue without injecting the authorizer span %s", - e, - ) + context = propagator.extract(injected_authorizer_data) + if _is_context_complete(context): + return context - headers = event.get("headers", {}) or {} - lowercase_headers = {k.lower(): v for k, v in headers.items()} + headers = event.get("headers") + context = propagator.extract(headers) - trace_id = lowercase_headers.get(TraceHeader.TRACE_ID) - parent_id = lowercase_headers.get(TraceHeader.PARENT_ID) - sampling_priority = lowercase_headers.get(TraceHeader.SAMPLING_PRIORITY) - - if not trace_id or not parent_id or not sampling_priority: + if not _is_context_complete(context): return extract_context_from_lambda_context(lambda_context) - return trace_id, parent_id, sampling_priority + 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): @@ -227,76 +230,167 @@ 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 the first SQS message attributes. + Extract Datadog trace context from an SQS event. + + The extraction chain goes as follows: + EB => SQS (First records body contains EB context), or + SNS => SQS (First records body contains SNS context), or + SQS or SNS (`messageAttributes` for SQS context, + `MessageAttributes` for SNS context), else + 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: + context = _extract_context_from_eventbridge_sqs_event(event) + if _is_context_complete(context): + return context + except Exception: + logger.debug("Failed extracting context as EventBridge to SQS.") + 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"{}"), - ) - else: - logger.debug( - "Datadog Lambda Python only supports extracting trace" - "context from String or Binary SQS/SNS message attributes" - ) - dd_data = json.loads(dd_json_data) - trace_id = dd_data.get(TraceHeader.TRACE_ID) - parent_id = dd_data.get(TraceHeader.PARENT_ID) - sampling_priority = dd_data.get(TraceHeader.SAMPLING_PRIORITY) + 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" + ) - return trace_id, parent_id, sampling_priority + 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: + # 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) +def _extract_context_from_eventbridge_sqs_event(event): + """ + Extracts Datadog trace context from an SQS event triggered by + EventBridge. + + This is only possible if first record in `Records` contains a + `body` field which contains the EventBridge `detail` as a JSON string. + """ + first_record = event.get("Records")[0] + body_str = first_record.get("body") + 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) + + 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) - trace_id = dd_context.get(TraceHeader.TRACE_ID) - parent_id = dd_context.get(TraceHeader.PARENT_ID) - sampling_priority = dd_context.get(TraceHeader.SAMPLING_PRIORITY) - return trace_id, parent_id, sampling_priority + + 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) return extract_context_from_lambda_context(lambda_context) @@ -305,57 +399,148 @@ 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) - - trace_id = dd_ctx.get(TraceHeader.TRACE_ID) - parent_id = dd_ctx.get(TraceHeader.PARENT_ID) - sampling_priority = dd_ctx.get(TraceHeader.SAMPLING_PRIORITY) - return trace_id, parent_id, sampling_priority + 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_sha256_hash(s: str, part: str) -> int: + import hashlib -def _deterministic_md5_hash(s: str) -> str: - """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 = str(int(most_significant_64_bits_without_leading_1, 2)) - if result == "0" * 64: - return "1" + 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 trace_id, parent_id, sampling_priority + return Context( + 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) return extract_context_from_lambda_context(lambda_context) @@ -366,17 +551,15 @@ 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) - return trace_id, parent_id, sampling_priority + trace_id, parent_id, sampling_priority = extractor(event, lambda_context) + return Context( + trace_id=int(trace_id), + span_id=int(parent_id), + sampling_priority=int(sampling_priority), + ) except Exception as e: logger.debug("The trace extractor returned with error %s", e) - return None, None, None - def is_authorizer_response(response) -> bool: try: @@ -394,19 +577,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 @@ -416,16 +606,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( @@ -442,56 +635,31 @@ def extract_dd_trace_context( event_source = parse_event_source(event) if extractor is not None: - ( - trace_id, - parent_id, - sampling_priority, - ) = extract_context_custom_extractor(extractor, event, lambda_context) + 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: - ( - trace_id, - parent_id, - sampling_priority, - ) = extract_context_from_http_event_or_context( + 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): - ( - trace_id, - parent_id, - sampling_priority, - ) = extract_context_from_sqs_or_sns_event_or_context(event, lambda_context) + context = extract_context_from_sqs_or_sns_event_or_context( + event, lambda_context, event_source + ) elif event_source.equals(EventTypes.EVENTBRIDGE): - ( - trace_id, - parent_id, - sampling_priority, - ) = extract_context_from_eventbridge_event(event, lambda_context) + context = extract_context_from_eventbridge_event(event, lambda_context) elif event_source.equals(EventTypes.KINESIS): - ( - trace_id, - parent_id, - sampling_priority, - ) = extract_context_from_kinesis_event(event, lambda_context) + context = extract_context_from_kinesis_event(event, lambda_context) elif event_source.equals(EventTypes.STEPFUNCTIONS): - ( - trace_id, - parent_id, - sampling_priority, - ) = extract_context_from_step_functions(event, lambda_context) + context = extract_context_from_step_functions(event, lambda_context) else: - trace_id, parent_id, sampling_priority = extract_context_from_lambda_context( - lambda_context - ) + context = extract_context_from_lambda_context(lambda_context) - if trace_id and parent_id and sampling_priority: + if _is_context_complete(context): logger.debug("Extracted Datadog trace context from event or context") - metadata = { - "trace-id": trace_id, - "parent-id": parent_id, - "sampling-priority": sampling_priority, - } - dd_trace_context = metadata.copy() + dd_trace_context = context trace_context_source = TraceContextSource.EVENT else: # AWS Lambda runtime caches global variables between invocations, @@ -503,7 +671,7 @@ def extract_dd_trace_context( return dd_trace_context, trace_context_source, event_source -def get_dd_trace_context(): +def get_dd_trace_context_obj(): """ Return the Datadog trace context to be propagated on the outgoing requests. @@ -515,34 +683,45 @@ def get_dd_trace_context(): automatically, but this function can be used to manually inject the trace context to an outgoing request. """ - global dd_trace_context - - context = None - xray_context = None + 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 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 - if xray_context and not dd_trace_context: - context = xray_context - elif xray_context and dd_trace_context: - context = dd_trace_context.copy() - context["parent-id"] = xray_context.get("parent-id") - logger.debug( - "Set parent id from xray trace context: %s", context.get("parent-id") - ) + if not _is_context_complete(dd_trace_context): + return xray_context + + logger.debug("Set parent id from xray trace context: %s", xray_context.span_id) + return Context( + trace_id=dd_trace_context.trace_id, + span_id=xray_context.span_id, + sampling_priority=dd_trace_context.sampling_priority, + meta=dd_trace_context._meta.copy(), + metrics=dd_trace_context._metrics.copy(), + ) - if dd_tracing_enabled: - dd_trace_py_context = _get_dd_trace_py_context() - if dd_trace_py_context is not None: - context = dd_trace_py_context - return _context_obj_to_headers(context) if context is not None else {} +def get_dd_trace_context(): + """ + Return the Datadog trace context to be propagated on the outgoing requests, + as a dict of headers. + """ + headers = {} + context = get_dd_trace_context_obj() + if not _is_context_complete(context): + return headers + propagator.inject(context, headers) + return headers def set_correlation_ids(): @@ -553,19 +732,19 @@ 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 - context = get_dd_trace_context() - - span = tracer.trace("dummy.span") - span.trace_id = int(context[TraceHeader.TRACE_ID]) - span.span_id = int(context[TraceHeader.PARENT_ID]) + context = get_dd_trace_context_obj() + if not _is_context_complete(context): + return + tracer.context_provider.activate(context) + tracer.trace("dummy.span") logger.debug("correlation ids set") @@ -580,9 +759,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( @@ -598,28 +776,25 @@ 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 = dict(dd_trace_context) + context = Context( + trace_id=dd_trace_context.trace_id, + span_id=dd_trace_context.span_id, + sampling_priority=dd_trace_context.sampling_priority, + ) if merge_xray_traces: xray_context = _get_xray_trace_context() - if xray_context is not None: - context["parent-id"] = xray_context.get("parent-id") + if xray_context and xray_context.span_id: + context.span_id = xray_context.span_id - headers = _context_obj_to_headers(context) - span_context = propagator.extract(headers) - tracer.context_provider.activate(span_context) + tracer.context_provider.activate(context) logger.debug( - "Set dd trace root context to: %s", - (span_context.trace_id, span_context.span_id), + "Set dd trace root context to: trace_id=%s span_id=%s", + context.trace_id, + context.span_id, ) @@ -680,45 +855,87 @@ 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): + new_service_mapping = {} + for entry in val.split(","): + parts = entry.split(":") + if len(parts) == 2: + key = parts[0].strip() + value = parts[1].strip() + if key != value and key and value: + new_service_mapping[key] = value + return new_service_mapping + + +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 + ) + + +# Initialization code +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") - method = request_context.get("http", {}).get("method") - path = request_context.get("http", {}).get("path") - resource = "{0} {1}".format(method, path) + service_name = determine_service_name(service_mapping, api_id, "lambda_url", domain) + 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": domain, - "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( @@ -790,13 +1007,20 @@ 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( + service_mapping, api_id, "lambda_api_gateway", domain + ) tags = { "operation_name": "aws.apigateway.websocket", - "http.url": domain + endpoint, + "http.url": http_url, "endpoint": endpoint, "resource_names": endpoint, - "apiid": request_context.get("apiId"), - "apiname": request_context.get("apiId"), + "span.kind": "server", + "apiid": api_id, + "apiname": api_id, "stage": request_context.get("stage"), "request_id": context.aws_request_id, "connection_id": request_context.get("connectionId"), @@ -809,11 +1033,11 @@ def create_inferred_span_from_api_gateway_websocket_event( else: InferredSpanInfo.set_tags(tags, tag_source="self", synchronicity="sync") args = { - "service": domain, + "service": service_name, "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: @@ -838,17 +1062,24 @@ def create_inferred_span_from_api_gateway_event( ): request_context = event.get("requestContext") domain = request_context.get("domainName", "") + api_id = request_context.get("apiId") + service_name = determine_service_name( + service_mapping, api_id, "lambda_api_gateway", domain + ) 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, - "apiid": request_context.get("apiId"), - "apiname": request_context.get("apiId"), + "span.kind": "server", + "apiid": api_id, + "apiname": api_id, "stage": request_context.get("stage"), "request_id": context.aws_request_id, } @@ -858,11 +1089,11 @@ def create_inferred_span_from_api_gateway_event( else: InferredSpanInfo.set_tags(tags, tag_source="self", synchronicity="sync") args = { - "service": domain, + "service": service_name, "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: @@ -883,26 +1114,43 @@ 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 ): request_context = event.get("requestContext") domain = request_context.get("domainName") - method = request_context.get("http", {}).get("method") + api_id = request_context.get("apiId") + service_name = determine_service_name( + service_mapping, api_id, "lambda_api_gateway", domain + ) + 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": request_context.get("apiId"), - "apiname": request_context.get("apiId"), + "apiid": api_id, + "apiname": api_id, "stage": request_context.get("stage"), } request_time_epoch_ms = int(request_context.get("timeEpoch")) @@ -910,12 +1158,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": domain, - "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) @@ -923,7 +1166,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) @@ -936,63 +1181,81 @@ def create_inferred_span_from_sqs_event(event, context): event_record = get_first_record(event) 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", 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": "sqs", - "resource": queue_name, - "span_type": "web", - } + request_time_epoch = attrs.get("SentTimestamp") start_time = int(request_time_epoch) / 1000 - # logic to deal with SNS => SQS event - sns_span = None + upstream_span = None if "body" in event_record: body_str = event_record.get("body", {}) try: body = json.loads(body_str) + + # logic to deal with SNS => SQS event if body.get("Type", "") == "Notification" and "TopicArn" in body: logger.debug("Found SNS message inside SQS event") - sns_span = create_inferred_span_from_sns_event( + upstream_span = create_inferred_span_from_sns_event( create_sns_event(body), context ) - sns_span.finish(finish_time=start_time) + upstream_span.finish(finish_time=start_time) + + # EventBridge => SQS + elif body.get("detail"): + detail = body.get("detail") + if detail.get("_datadog"): + logger.debug("Found an EventBridge message inside SQS event") + upstream_span = create_inferred_span_from_eventbridge_event( + body, context + ) + upstream_span.finish(finish_time=start_time) + except Exception as e: logger.debug( - "Unable to create SNS 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 - if sns_span: - span.parent_id = sns_span.span_id + if upstream_span: + span.parent_id = upstream_span.span_id return span 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", 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"), @@ -1000,21 +1263,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": "sns", - "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() @@ -1025,31 +1286,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", 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": "kinesis", - "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 @@ -1060,10 +1321,14 @@ def create_inferred_span_from_dynamodb_event(event, context): event_record = get_first_record(event) event_source_arn = event_record.get("eventSourceARN") table_name = event_source_arn.split("/")[1] - dynamodb_message = event_record.get("dynamodb") + service_name = determine_service_name( + service_mapping, table_name, "lambda_dynamodb", table_name, "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"), @@ -1073,16 +1338,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": "dynamodb", - "resource": table_name, - "span_type": "web", - } - tracer.set_tags({"_dd.origin": "lambda"}) - span = tracer.trace("aws.dynamodb", **args) if span: span.set_tags(tags) @@ -1092,29 +1352,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", 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": "s3", - "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() @@ -1123,9 +1387,13 @@ 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", source, "eventbridge" + ) tags = { "operation_name": "aws.eventbridge", "resource_names": source, + "span.kind": "server", "detail_type": event.get("detail-type"), } InferredSpanInfo.set_tags( @@ -1133,20 +1401,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": "eventbridge", - "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 @@ -1154,12 +1434,14 @@ def create_function_execution_span( context, function_name, is_cold_start, + is_proactive_init, trace_context_source, 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(":") @@ -1171,27 +1453,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 @@ -1243,3 +1549,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 fb849cec9..8dbd7e359 100644 --- a/datadog_lambda/wrapper.py +++ b/datadog_lambda/wrapper.py @@ -2,34 +2,35 @@ # 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, is_cold_start, ColdStartTracer +from datadog_lambda.cold_start import ( + set_cold_start, + is_cold_start, + is_proactive_init, + 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, @@ -38,24 +39,48 @@ InferredSpanInfo, is_authorizer_response, tracer, + propagator, ) from datadog_lambda.trigger import ( extract_trigger_tags, extract_http_status_code_tag, ) -from datadog_lambda.tag_object import tag_object -profiling_env_var = os.environ.get("DD_PROFILING_ENABLED", "false").lower() == "true" -if profiling_env_var: +# 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. + +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() + +if config.profiling_enabled: from ddtrace.profiling import profiler +if config.llmobs_enabled: + from ddtrace.llmobs import LLMObs + +if config.exception_replay_enabled: + from ddtrace.debugging._exception.replay import SpanExceptionHandler + + try: + from ddtrace.debugging._uploader import SignalUploader + except ImportError: + from ddtrace.debugging._uploader import LogsIntakeUploaderV1 as SignalUploader + logger = logging.getLogger(__name__) -dd_capture_lambda_payload_enabled = ( - os.environ.get("DD_CAPTURE_LAMBDA_PAYLOAD", "false").lower() == "true" -) -service_env_var = os.environ.get("DD_SERVICE", "DefaultServiceName") -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() """ Usage: @@ -102,62 +127,25 @@ def __new__(cls, func): else: logger.debug("datadog_lambda_wrapper already wrapped") return _NoopDecorator(func) - except Exception: - traceback.print_exc() + except Exception as e: + logger.error(format_err_with_traceback(e)) return func 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.extractor_env = os.environ.get("DD_TRACE_EXTRACTOR", None) self.trace_extractor = None self.span = None self.inferred_span = None - self.make_inferred_span = ( - os.environ.get("DD_TRACE_MANAGED_SERVICES", "true").lower() == "true" - ) - self.encode_authorizer_context = ( - os.environ.get("DD_ENCODE_AUTHORIZER_CONTEXT", "true").lower() == "true" - ) - self.decode_authorizer_context = ( - os.environ.get("DD_DECODE_AUTHORIZER_CONTEXT", "true").lower() == "true" - ) - self.cold_start_tracing = ( - os.environ.get("DD_COLD_START_TRACING", "true").lower() == "true" - ) - self.min_cold_start_trace_duration = 3 - if "DD_MIN_COLD_START_DURATION" in os.environ: - try: - self.min_cold_start_trace_duration = int( - os.environ["DD_MIN_COLD_START_DURATION"] - ) - except Exception: - logger.debug("Malformatted env DD_MIN_COLD_START_DURATION") - 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("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=service_env_var) - 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) @@ -165,34 +153,50 @@ 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 # in requests-related spans - os.environ["DD_REQUESTS_SERVICE_NAME"] = os.environ.get( - "DD_SERVICE", "aws.lambda" + 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: - traceback.print_exc() + except Exception as e: + logger.error(format_err_with_traceback(e)) 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 @@ -209,66 +213,117 @@ 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()) + + 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 - set_cold_start() - submit_invocations_metric(context) + self.blocking_response = None + set_cold_start(init_timestamp_ns) + + 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(), - 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_cold_start(): + 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: - traceback.print_exc() + except Exception as e: + logger.error(format_err_with_traceback(e)) 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) @@ -279,25 +334,20 @@ def _after(self, event, context): create_dd_dummy_metadata_subsegment( self.trigger_tags, XraySubsegment.LAMBDA_FUNCTION_TAGS_KEY ) - should_trace_cold_start = ( - dd_tracing_enabled and self.cold_start_tracing and is_cold_start() - ) + 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(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 self.inferred_span: if status_code: self.inferred_span.set_tag("http.status_code", status_code) + 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) else: @@ -308,27 +358,46 @@ 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") ) logger.debug("datadog_lambda_wrapper _after() done") - except Exception: - traceback.print_exc() + except Exception as e: + logger.error(format_err_with_traceback(e)) + + +def format_err_with_traceback(e): + 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 bbaecb2ed..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): @@ -75,7 +88,6 @@ def generate_random_id(): def build_segment(context, key, metadata): - segment = json.dumps( { "id": generate_random_id(), @@ -90,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, "") @@ -116,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 c1946f576..4c37bf871 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,353 +1,311 @@ -# This file is automatically @generated by Poetry and should not be changed by hand. - -[[package]] -name = "attrs" -version = "22.2.0" -description = "Classes Without Boilerplate" -category = "main" -optional = false -python-versions = ">=3.6" -files = [ - {file = "attrs-22.2.0-py3-none-any.whl", hash = "sha256:29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836"}, - {file = "attrs-22.2.0.tar.gz", hash = "sha256:c9227bfc2f01993c03f68db37d1d15c9690188323c067c641f1a35ca58185f99"}, -] - -[package.extras] -cov = ["attrs[tests]", "coverage-enable-subprocess", "coverage[toml] (>=5.3)"] -dev = ["attrs[docs,tests]"] -docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope.interface"] -tests = ["attrs[tests-no-zope]", "zope.interface"] -tests-no-zope = ["cloudpickle", "cloudpickle", "hypothesis", "hypothesis", "mypy (>=0.971,<0.990)", "mypy (>=0.971,<0.990)", "pympler", "pympler", "pytest (>=4.3.0)", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-mypy-plugins", "pytest-xdist[psutil]", "pytest-xdist[psutil]"] - -[[package]] -name = "boto3" -version = "1.26.41" -description = "The AWS SDK for Python" -category = "main" -optional = true -python-versions = ">= 3.7" -files = [ - {file = "boto3-1.26.41-py3-none-any.whl", hash = "sha256:05a5ce3af2d7419e39d93498c7f56fd5c2cc17870c92c4abc75659553b0b16de"}, - {file = "boto3-1.26.41.tar.gz", hash = "sha256:8cbea352f28ec6b241f348356bcb8f331fc433bec3ad76ebf6194227f1a7f613"}, -] - -[package.dependencies] -botocore = ">=1.29.41,<1.30.0" -jmespath = ">=0.7.1,<2.0.0" -s3transfer = ">=0.6.0,<0.7.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.29.41" +version = "1.36.8" description = "Low-level, data-driven core of boto 3." -category = "main" optional = true -python-versions = ">= 3.7" +python-versions = ">=3.8" +groups = ["main"] +markers = "extra == \"dev\"" files = [ - {file = "botocore-1.29.41-py3-none-any.whl", hash = "sha256:b670b7f8958a2908167081efb6ea39794bf61d618be729984629a63d85cf8bfe"}, - {file = "botocore-1.29.41.tar.gz", hash = "sha256:78761227d986d393956b6d08fdadcfe142748828e0e9db33f2f4c42a482dcd35"}, + {file = "botocore-1.36.8-py3-none-any.whl", hash = "sha256:59d3fdfbae6d916b046e973bebcbeb70a102f9e570ca86d5ba512f1854b78fc2"}, + {file = "botocore-1.36.8.tar.gz", hash = "sha256:81c88e5566cf018e1411a68304dc1fb9e4156ca2b50a3a0f0befc274299e67fa"}, ] [package.dependencies] jmespath = ">=0.7.1,<2.0.0" python-dateutil = ">=2.1,<3.0.0" -urllib3 = ">=1.25.4,<1.27" +urllib3 = [ + {version = ">=1.25.4,<1.27", 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.15.3)"] - -[[package]] -name = "bytecode" -version = "0.13.0" -description = "Python module to generate and modify bytecode" -category = "main" -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"}, -] +crt = ["awscrt (==0.23.4)"] [[package]] name = "bytecode" -version = "0.14.0" +version = "0.16.1" description = "Python module to generate and modify bytecode" -category = "main" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ - {file = "bytecode-0.14.0-py3-none-any.whl", hash = "sha256:f7b7cbed3239acee036d6c0f9d04286b100921114601bf844ae569b95bf91a9f"}, - {file = "bytecode-0.14.0.tar.gz", hash = "sha256:d41ad53c657ba0bef1cb4828d9d6e450766e31cb66c6f91fc1851f052889d1b7"}, + {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 = "22.2.0" -description = "Composable complex class support for attrs and dataclasses." -category = "main" -optional = false -python-versions = ">=3.7" -files = [ - {file = "cattrs-22.2.0-py3-none-any.whl", hash = "sha256:bc12b1f0d000b9f9bee83335887d532a1d3e99a833d1bf0882151c97d3e68c21"}, - {file = "cattrs-22.2.0.tar.gz", hash = "sha256:f0eed5642399423cf656e7b66ce92cdc5b963ecafd041d1b24d136fdde7acf6d"}, -] - -[package.dependencies] -attrs = ">=20" -exceptiongroup = {version = "*", markers = "python_version < \"3.11\""} -typing_extensions = {version = "*", markers = "python_version < \"3.8\""} +typing_extensions = {version = "*", markers = "python_version < \"3.10\""} [[package]] name = "certifi" -version = "2022.12.7" +version = "2024.12.14" description = "Python package for providing Mozilla's CA Bundle." -category = "main" optional = false python-versions = ">=3.6" +groups = ["main"] files = [ - {file = "certifi-2022.12.7-py3-none-any.whl", hash = "sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18"}, - {file = "certifi-2022.12.7.tar.gz", hash = "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3"}, + {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 = "2.1.1" +version = "3.4.1" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -category = "main" optional = false -python-versions = ">=3.6.0" -files = [ - {file = "charset-normalizer-2.1.1.tar.gz", hash = "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845"}, - {file = "charset_normalizer-2.1.1-py3-none-any.whl", hash = "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f"}, -] - -[package.extras] -unicode-backport = ["unicodedata2"] - -[[package]] -name = "coverage" -version = "7.0.1" -description = "Code coverage measurement for Python" -category = "main" -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.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b3695c4f4750bca943b3e1f74ad4be8d29e4aeab927d50772c41359107bd5d5c"}, - {file = "coverage-7.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fa6a5a224b7f4cfb226f4fc55a57e8537fcc096f42219128c2c74c0e7d0953e1"}, - {file = "coverage-7.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:74f70cd92669394eaf8d7756d1b195c8032cf7bbbdfce3bc489d4e15b3b8cf73"}, - {file = "coverage-7.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b66bb21a23680dee0be66557dc6b02a3152ddb55edf9f6723fa4a93368f7158d"}, - {file = "coverage-7.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d87717959d4d0ee9db08a0f1d80d21eb585aafe30f9b0a54ecf779a69cb015f6"}, - {file = "coverage-7.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:854f22fa361d1ff914c7efa347398374cc7d567bdafa48ac3aa22334650dfba2"}, - {file = "coverage-7.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:1e414dc32ee5c3f36544ea466b6f52f28a7af788653744b8570d0bf12ff34bc0"}, - {file = "coverage-7.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6c5ad996c6fa4d8ed669cfa1e8551348729d008a2caf81489ab9ea67cfbc7498"}, - {file = "coverage-7.0.1-cp310-cp310-win32.whl", hash = "sha256:691571f31ace1837838b7e421d3a09a8c00b4aac32efacb4fc9bd0a5c647d25a"}, - {file = "coverage-7.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:89caf4425fe88889e2973a8e9a3f6f5f9bbe5dd411d7d521e86428c08a873a4a"}, - {file = "coverage-7.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:63d56165a7c76265468d7e0c5548215a5ba515fc2cba5232d17df97bffa10f6c"}, - {file = "coverage-7.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4f943a3b2bc520102dd3e0bb465e1286e12c9a54f58accd71b9e65324d9c7c01"}, - {file = "coverage-7.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:830525361249dc4cd013652b0efad645a385707a5ae49350c894b67d23fbb07c"}, - {file = "coverage-7.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd1b9c5adc066db699ccf7fa839189a649afcdd9e02cb5dc9d24e67e7922737d"}, - {file = "coverage-7.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e00c14720b8b3b6c23b487e70bd406abafc976ddc50490f645166f111c419c39"}, - {file = "coverage-7.0.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6d55d840e1b8c0002fce66443e124e8581f30f9ead2e54fbf6709fb593181f2c"}, - {file = "coverage-7.0.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:66b18c3cf8bbab0cce0d7b9e4262dc830e93588986865a8c78ab2ae324b3ed56"}, - {file = "coverage-7.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:12a5aa77783d49e05439fbe6e6b427484f8a0f9f456b46a51d8aac022cfd024d"}, - {file = "coverage-7.0.1-cp311-cp311-win32.whl", hash = "sha256:b77015d1cb8fe941be1222a5a8b4e3fbca88180cfa7e2d4a4e58aeabadef0ab7"}, - {file = "coverage-7.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:fb992c47cb1e5bd6a01e97182400bcc2ba2077080a17fcd7be23aaa6e572e390"}, - {file = "coverage-7.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e78e9dcbf4f3853d3ae18a8f9272111242531535ec9e1009fa8ec4a2b74557dc"}, - {file = "coverage-7.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e60bef2e2416f15fdc05772bf87db06c6a6f9870d1db08fdd019fbec98ae24a9"}, - {file = "coverage-7.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9823e4789ab70f3ec88724bba1a203f2856331986cd893dedbe3e23a6cfc1e4e"}, - {file = "coverage-7.0.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9158f8fb06747ac17bd237930c4372336edc85b6e13bdc778e60f9d685c3ca37"}, - {file = "coverage-7.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:486ee81fa694b4b796fc5617e376326a088f7b9729c74d9defa211813f3861e4"}, - {file = "coverage-7.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:1285648428a6101b5f41a18991c84f1c3959cee359e51b8375c5882fc364a13f"}, - {file = "coverage-7.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2c44fcfb3781b41409d0f060a4ed748537557de9362a8a9282182fafb7a76ab4"}, - {file = "coverage-7.0.1-cp37-cp37m-win32.whl", hash = "sha256:d6814854c02cbcd9c873c0f3286a02e3ac1250625cca822ca6bc1018c5b19f1c"}, - {file = "coverage-7.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:f66460f17c9319ea4f91c165d46840314f0a7c004720b20be58594d162a441d8"}, - {file = "coverage-7.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9b373c9345c584bb4b5f5b8840df7f4ab48c4cbb7934b58d52c57020d911b856"}, - {file = "coverage-7.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d3022c3007d3267a880b5adcf18c2a9bf1fc64469b394a804886b401959b8742"}, - {file = "coverage-7.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:92651580bd46519067e36493acb394ea0607b55b45bd81dd4e26379ed1871f55"}, - {file = "coverage-7.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3cfc595d2af13856505631be072835c59f1acf30028d1c860b435c5fc9c15b69"}, - {file = "coverage-7.0.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b4b3a4d9915b2be879aff6299c0a6129f3d08a775d5a061f503cf79571f73e4"}, - {file = "coverage-7.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b6f22bb64cc39bcb883e5910f99a27b200fdc14cdd79df8696fa96b0005c9444"}, - {file = "coverage-7.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:72d1507f152abacea81f65fee38e4ef3ac3c02ff8bc16f21d935fd3a8a4ad910"}, - {file = "coverage-7.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0a79137fc99815fff6a852c233628e735ec15903cfd16da0f229d9c4d45926ab"}, - {file = "coverage-7.0.1-cp38-cp38-win32.whl", hash = "sha256:b3763e7fcade2ff6c8e62340af9277f54336920489ceb6a8cd6cc96da52fcc62"}, - {file = "coverage-7.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:09f6b5a8415b6b3e136d5fec62b552972187265cb705097bf030eb9d4ffb9b60"}, - {file = "coverage-7.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:978258fec36c154b5e250d356c59af7d4c3ba02bef4b99cda90b6029441d797d"}, - {file = "coverage-7.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:19ec666533f0f70a0993f88b8273057b96c07b9d26457b41863ccd021a043b9a"}, - {file = "coverage-7.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cfded268092a84605f1cc19e5c737f9ce630a8900a3589e9289622db161967e9"}, - {file = "coverage-7.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07bcfb1d8ac94af886b54e18a88b393f6a73d5959bb31e46644a02453c36e475"}, - {file = "coverage-7.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:397b4a923cc7566bbc7ae2dfd0ba5a039b61d19c740f1373791f2ebd11caea59"}, - {file = "coverage-7.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:aec2d1515d9d39ff270059fd3afbb3b44e6ec5758af73caf18991807138c7118"}, - {file = "coverage-7.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:c20cfebcc149a4c212f6491a5f9ff56f41829cd4f607b5be71bb2d530ef243b1"}, - {file = "coverage-7.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:fd556ff16a57a070ce4f31c635953cc44e25244f91a0378c6e9bdfd40fdb249f"}, - {file = "coverage-7.0.1-cp39-cp39-win32.whl", hash = "sha256:b9ea158775c7c2d3e54530a92da79496fb3fb577c876eec761c23e028f1e216c"}, - {file = "coverage-7.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:d1991f1dd95eba69d2cd7708ff6c2bbd2426160ffc73c2b81f617a053ebcb1a8"}, - {file = "coverage-7.0.1-pp37.pp38.pp39-none-any.whl", hash = "sha256:3dd4ee135e08037f458425b8842d24a95a0961831a33f89685ff86b77d378f89"}, - {file = "coverage-7.0.1.tar.gz", hash = "sha256:a4a574a19eeb67575a5328a5760bbbb737faa685616586a9f9da4281f940109c"}, + {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.41.0" +version = "0.51.0" description = "The Datadog Python library" -category = "main" optional = false -python-versions = "*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["main"] files = [ - {file = "datadog-0.41.0-py2.py3-none-any.whl", hash = "sha256:ab79ed38fb09ff1942c341e32849c4eeaf8b2e4d467b9e6bb1c6071808f454d6"}, - {file = "datadog-0.41.0.tar.gz", hash = "sha256:3de1a43b8a8d5f6b19d162ec1b482dc5ab2636c59cf65e60589702304510a689"}, + {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] -decorator = ">=3.3.2" requests = ">=2.6.0" -[[package]] -name = "ddsketch" -version = "2.0.4" -description = "Distributed quantile sketches" -category = "main" -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 = "1.6.4" +version = "2.20.0" description = "Datadog APM client library" -category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -files = [ - {file = "ddtrace-1.6.4-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:3c4c9a18cf3270fc10801e286410c30a1a603cb848ee1f08bbd118e0b97ddfcc"}, - {file = "ddtrace-1.6.4-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:204c560719c31d3f9ff8456a4c6ca4d0d6b527c13951815cbcf1012ea48ff759"}, - {file = "ddtrace-1.6.4-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:c97a1cf8a8e50a12c6bd09f0f15e172c447ac5a5350a7bd256f6685897c9efbf"}, - {file = "ddtrace-1.6.4-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:93ad24ff023d9c364288f422e0d46eb7b866c91e6c0453a36e5a3fdbfb01a627"}, - {file = "ddtrace-1.6.4-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:6e65f860656488d6b6e005301c7138ba573b5cbf03270ec811c6d34f8aebf0b5"}, - {file = "ddtrace-1.6.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b77e7d7e2e4de5851d8ff332e63957a46a367e6e3c5c94d4ad37dcaf047f11e1"}, - {file = "ddtrace-1.6.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:96d141807d5e446c67a4dcb16178cfa25523cedd075d73dad254f13a62a1231f"}, - {file = "ddtrace-1.6.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d65e211995e379b06a809dcaa229c09a08a02b161d574ca4716d055a65d9db05"}, - {file = "ddtrace-1.6.4-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0ed65ebd21f80acccba804fe671646e2476ce5e96162b9b2bfb0b8fd417fa6fa"}, - {file = "ddtrace-1.6.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07ffa019d48175e23f1ccd449c45b0250656cbe210a0603900a981c29ae7786e"}, - {file = "ddtrace-1.6.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:5d9ab8cba1a808da3f6da7aa0303a227245d8b25617e0673a299c3e4cae16506"}, - {file = "ddtrace-1.6.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:72ddb4bfa46660d082be50ae09faec026c46a295524a3a722570c770bf632f98"}, - {file = "ddtrace-1.6.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:03e52db04d3ada8d234d050e66988b8ec559e4db57a03fd56112e50885bc2767"}, - {file = "ddtrace-1.6.4-cp310-cp310-win32.whl", hash = "sha256:aba27dd41468e06fbe0534ce45b182e7cf7fa582eb70a03fd341da63fea07032"}, - {file = "ddtrace-1.6.4-cp310-cp310-win_amd64.whl", hash = "sha256:cf0754548216361ce9de00b750b5a5ff8eb57e9fd1fd85f223b5f23cc36ba68a"}, - {file = "ddtrace-1.6.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4464d1e886450d8c2c149ced95c4ecbe4481bc80225ebc5301385d0bf450e162"}, - {file = "ddtrace-1.6.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d32a006a1919282394e9095abb92d99efbadca7fec304bf07952e2d6f90383c5"}, - {file = "ddtrace-1.6.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a121b3417c444e9bb827c6d0a0b183f1c5517a9c8769c7ca43787ec48ad08bb1"}, - {file = "ddtrace-1.6.4-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7372e54b27d4359fa6d86d664880852a96a1786304ab2580e81796889ada449b"}, - {file = "ddtrace-1.6.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb88df54546891cb738af2d00208d10ab4c391c03b489bbd6a8745f1c8a10d5c"}, - {file = "ddtrace-1.6.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:52ffa9c4324d26f58c4ddf4ca22abcc160386f53bfbdfd56bb772580a72cf958"}, - {file = "ddtrace-1.6.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:bc33cb8501db1d049160a312d9a4e68e2fb35d61fec4a3fa9665c940489246e3"}, - {file = "ddtrace-1.6.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f64498947e696efd1ff192d56f63987cd9b09beabb481e443aa802cca51eb841"}, - {file = "ddtrace-1.6.4-cp311-cp311-win32.whl", hash = "sha256:7766d7253ccab625c07203da36e10c1926d565e465897fdb34f03f532b0610b9"}, - {file = "ddtrace-1.6.4-cp311-cp311-win_amd64.whl", hash = "sha256:981cfe27a13e4347a8fdea9d7a8936b592359ad879df1de98077b1b70e5eeace"}, - {file = "ddtrace-1.6.4-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:cd25cf8e1457c94bb7fe5fc2bab700a9e22378f137cbb73a2fe847dbd2305020"}, - {file = "ddtrace-1.6.4-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:b9bfe5e83a1ea8c8673068a5218f4a80054d87eb9c3e2b581bacbdbac67a28ec"}, - {file = "ddtrace-1.6.4-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:57613420ae32d56a76d67f571210cc134368cbef17607e71b8eb66a5b1ea2d72"}, - {file = "ddtrace-1.6.4-cp35-cp35m-win32.whl", hash = "sha256:d574f29ab02b4f43bd93214891423f27145ff54c34242db6a47fc5a591e0e5d0"}, - {file = "ddtrace-1.6.4-cp35-cp35m-win_amd64.whl", hash = "sha256:89618a300428d53b25428d728bf2ba026a5e996bbd65d82917e8a47a4a0c7815"}, - {file = "ddtrace-1.6.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:ee954e1ebc8dc47328b7e145736e7b6d7167cec1d43ba661056210d08594ade8"}, - {file = "ddtrace-1.6.4-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cbda998fd438701a20461cd819a1d1a1d168ea7b3bcaa0ced6f41bac30ba359"}, - {file = "ddtrace-1.6.4-cp36-cp36m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fcbffb017cdeb468d083b4c07c91fa024a0652416acc35fcfabfbff366f522d2"}, - {file = "ddtrace-1.6.4-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f36f85ff84a7535fbdcbeed40d430f6d047a2cdd0c4de6dc7bc375e82708f646"}, - {file = "ddtrace-1.6.4-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:0a016a8d2f666e0e677d00d1f4057035ac5dc753f9b0e4fb378dd4f7882f2ade"}, - {file = "ddtrace-1.6.4-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:0a1be96afa6df810a32cc403a0d133ad87d6c5a9eeec861b178aaa3048d47da6"}, - {file = "ddtrace-1.6.4-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:10accb64d6ad8cc5dfddbb3150c0dd1c96ed5f62161d521d264b0afbaf3f075c"}, - {file = "ddtrace-1.6.4-cp36-cp36m-win32.whl", hash = "sha256:c1c35e16c71dd22c6f21e0d4a135071237fe988082048bc361a3213031e77170"}, - {file = "ddtrace-1.6.4-cp36-cp36m-win_amd64.whl", hash = "sha256:51156177b60331c2d9b024487d25418b1d1308b4d1eaa196cf4673a649bcc057"}, - {file = "ddtrace-1.6.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:04284a33f831ec5efb396f2b7e664d326982008ef8761d4054c3d663e13166bb"}, - {file = "ddtrace-1.6.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1dd4c3743fb93228c7470f447eff1d986417298b7242e80753ec406f67288a75"}, - {file = "ddtrace-1.6.4-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88c90fbfb22b707e6ab07d5c109634c17986d8090363f1e69cc0fb43ccb77098"}, - {file = "ddtrace-1.6.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14430eda72c2d28b92b782201ea4edc6efdc8c74845a407039c1f6a4f244fb24"}, - {file = "ddtrace-1.6.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:a056086975d607acaa0377231615fa1a94c632fd4ece979f0d5554a423663e61"}, - {file = "ddtrace-1.6.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:dae04139b42b42e5eda3f544c7fe9875a5b190aeca9ce09eb01853d35a7f0054"}, - {file = "ddtrace-1.6.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:86a91dc39cc2f2a1c301e8549fb7bd84da78122d4c6ff4b60a97d89601d1c66c"}, - {file = "ddtrace-1.6.4-cp37-cp37m-win32.whl", hash = "sha256:e1efd72c2377f605dc053c763e9449b7188659190d48efb75669158db5a92844"}, - {file = "ddtrace-1.6.4-cp37-cp37m-win_amd64.whl", hash = "sha256:108c045b332a034f3e8e0df8d87b6b7a26e9e94007a8a84000f445450c11c44b"}, - {file = "ddtrace-1.6.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:121c2d6212142fb6815d2dcc56a82fb06e9e3568ee217015e6d72ec3caad7268"}, - {file = "ddtrace-1.6.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3da580615a97e61ffbf564782679b98b81ba026248926619b030d648ff389a40"}, - {file = "ddtrace-1.6.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:73be527f3a2912e74045ee60e9d37fc8f1a8410b90ae3ac8fb94f01e6ee3f6d3"}, - {file = "ddtrace-1.6.4-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae70de026c79a895b2a5beecbbc0e46bb0c07d27af77a1662352a5608068b005"}, - {file = "ddtrace-1.6.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45a4f2c200c22ab4b6dbeb16b6f6b9aafa2a674b3c3e175f86cb2c2e16f69fff"}, - {file = "ddtrace-1.6.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4a183627202355377d9e369f8d4d18ceee82dd2312d0d098fb1242f387ebcb2b"}, - {file = "ddtrace-1.6.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:97f1ed98e1a14091515aa482d528846ee4437260d68e819bb6ba09af4774fb3c"}, - {file = "ddtrace-1.6.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f08d858a045a9117295e3008ba7c9586865ed16690c682441347508744c338e2"}, - {file = "ddtrace-1.6.4-cp38-cp38-win32.whl", hash = "sha256:71fae938615e77cb5cd04978a36874fa97c1d929c1b697c690affedd538914ed"}, - {file = "ddtrace-1.6.4-cp38-cp38-win_amd64.whl", hash = "sha256:53a0db94ae562222338490e5f409d3e2740d03f7d1099fdd02e769690ca70de2"}, - {file = "ddtrace-1.6.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d727012ee9b4725cdbb0666e40e4e99cae3418c88b98159e073ec1479d30db73"}, - {file = "ddtrace-1.6.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:102c49d38d67efe6da378509ed7f9f88bc9c6c9a95bcc493c06e02a15e4865c2"}, - {file = "ddtrace-1.6.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5e6cc5ad17a456c6e93d25c6bd06580436fb5c007cef27c89b060a277e35b7a"}, - {file = "ddtrace-1.6.4-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ad9abf5879abad5b143ef9fcd9b557193b19000d8ff798b06ec86f1fe992cb89"}, - {file = "ddtrace-1.6.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:289edf7ea4f506f329b20394b08971487bf72351b0a9b9a63a5c7f4d18e1cda8"}, - {file = "ddtrace-1.6.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:3a3432c72a082e8f4090a55833cda1b6840676b5f58dbaca041d566f581a3062"}, - {file = "ddtrace-1.6.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7504b21d88ce528e86eb8727270e677a7b4a254ee070e54d0e81111bd68a6d0b"}, - {file = "ddtrace-1.6.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5e744e81727d1328e6830de6a749378e7cd31fc0e1c0aceb19b17685e90cb8fa"}, - {file = "ddtrace-1.6.4-cp39-cp39-win32.whl", hash = "sha256:2aed59c1a0ed33f0b752daa801980d9ab395f89ea8fbc2c788fea0b11a3ea826"}, - {file = "ddtrace-1.6.4-cp39-cp39-win_amd64.whl", hash = "sha256:4fb94ee5113141becb7e447bdf57e30bb447f9347785bf20211d0cf06e1e98e7"}, - {file = "ddtrace-1.6.4.tar.gz", hash = "sha256:33effab386caaaab314e08900b798c02ab5771f88697acb9bf64e5ba98c8009a"}, +python-versions = ">=3.7" +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 = {version = ">=20", markers = "python_version > \"2.7\""} bytecode = [ - {version = ">=0.13.0,<0.14.0", markers = "python_version == \"3.7\""}, - {version = "*", markers = "python_version >= \"3.8\""}, -] -cattrs = "*" -ddsketch = ">=2.0.1" -envier = "*" -importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} -jsonschema = "*" -packaging = ">=17.1" -protobuf = {version = ">=3", markers = "python_version >= \"3.7\""} -six = ">=1.12.0" -tenacity = ">=5" -typing-extensions = "*" + {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\""}, +] +envier = ">=0.5,<1.0" +legacy-cgi = {version = ">=2.0.0", markers = "python_version >= \"3.13.0\""} +opentelemetry-api = ">=1" +protobuf = ">=3" +typing_extensions = "*" +wrapt = ">=1" xmltodict = ">=0.12" [package.extras] +openai = ["tiktoken"] opentracing = ["opentracing (>=2.0.0)"] [[package]] -name = "decorator" -version = "5.1.1" -description = "Decorators for Humans" -category = "main" +name = "deprecated" +version = "1.2.18" +description = "Python @deprecated decorator to deprecate old python classes, functions or methods." optional = false -python-versions = ">=3.5" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" +groups = ["main"] files = [ - {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"}, - {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"}, + {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)", "setuptools ; python_version >= \"3.12\"", "tox"] + [[package]] name = "envier" -version = "0.4.0" +version = "0.6.1" description = "Python application configuration via the environment" -category = "main" 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] @@ -355,14 +313,15 @@ mypy = ["mypy"] [[package]] name = "exceptiongroup" -version = "1.1.0" +version = "1.2.2" description = "Backport of PEP 654 (exception groups)" -category = "main" -optional = false +optional = true python-versions = ">=3.7" +groups = ["main"] +markers = "extra == \"dev\" and python_version <= \"3.10\"" files = [ - {file = "exceptiongroup-1.1.0-py3-none-any.whl", hash = "sha256:327cbda3da756e2de031a3107b81ab7b3770a602c4d16ca618298c526f4bec1e"}, - {file = "exceptiongroup-1.1.0.tar.gz", hash = "sha256:bcb67d800a4497e1b404c2dd44fca47d3b7a5e5433dbab67f96c1a685cdfdf23"}, + {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, + {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, ] [package.extras] @@ -370,273 +329,276 @@ test = ["pytest (>=6)"] [[package]] name = "flake8" -version = "3.9.2" +version = "5.0.4" description = "the modular source code checker: pep8 pyflakes and co" -category = "main" 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" -category = "main" -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)" -category = "main" 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 = "1.7.0" +version = "8.5.0" description = "Read metadata from Python packages" -category = "main" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" +python-versions = ">=3.8" +groups = ["main"] files = [ - {file = "importlib_metadata-1.7.0-py2.py3-none-any.whl", hash = "sha256:dc15b2969b4ce36305c51eebe62d418ac7791e9a157911d58bfb1f9ccd8e2070"}, - {file = "importlib_metadata-1.7.0.tar.gz", hash = "sha256:90bb658cdbbf6d1735b6341ce708fc7024a3e14e99ffdc5783edea9f9b077f83"}, + {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] -zipp = ">=0.5" +zipp = ">=3.20" [package.extras] -docs = ["rst.linker", "sphinx"] -testing = ["importlib-resources (>=1.3)", "packaging", "pep517"] - -[[package]] -name = "importlib-resources" -version = "5.10.2" -description = "Read resources from Python packages" -category = "main" -optional = false +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"] +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 = "importlib_resources-5.10.2-py3-none-any.whl", hash = "sha256:7d543798b0beca10b6a01ac7cafda9f822c54db9e8376a6bf57e0cbd74d486b6"}, - {file = "importlib_resources-5.10.2.tar.gz", hash = "sha256:e4a96c8cc0339647ff9a5e0550d9f276fc5a01ffa276012b58ec108cfd7b8484"}, + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] -[package.dependencies] -zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} - -[package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["flake8 (<5)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] - [[package]] name = "jmespath" version = "1.0.1" description = "JSON Matching Expressions" -category = "main" 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 = "jsonschema" -version = "4.17.3" -description = "An implementation of JSON Schema validation for Python" -category = "main" +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.7" +python-versions = ">=3.10" +groups = ["main"] +markers = "python_version >= \"3.13.0\"" files = [ - {file = "jsonschema-4.17.3-py3-none-any.whl", hash = "sha256:a870ad254da1a8ca84b6a2905cac29d265f805acc57af304784962a2aa6508f6"}, - {file = "jsonschema-4.17.3.tar.gz", hash = "sha256:0f864437ab8b6076ba6707453ef8f98a6a0d512a80e93f8abdb676f737ecb60d"}, + {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.dependencies] -attrs = ">=17.4.0" -importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} -importlib-resources = {version = ">=1.4.0", markers = "python_version < \"3.9\""} -pkgutil-resolve-name = {version = ">=1.3.10", markers = "python_version < \"3.9\""} -pyrsistent = ">=0.14.0,<0.17.0 || >0.17.0,<0.17.1 || >0.17.1,<0.17.2 || >0.17.2" -typing-extensions = {version = "*", markers = "python_version < \"3.8\""} - -[package.extras] -format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"] -format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=1.11)"] - [[package]] name = "mccabe" -version = "0.6.1" +version = "0.7.0" description = "McCabe checker, plugin for flake8" -category = "main" optional = true -python-versions = "*" +python-versions = ">=3.6" +groups = ["main"] +markers = "extra == \"dev\"" 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 = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, + {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, ] [[package]] -name = "nose2" -version = "0.9.2" -description = "unittest2 with plugins, the succesor to nose" -category = "main" -optional = true -python-versions = "*" +name = "opentelemetry-api" +version = "1.29.0" +description = "OpenTelemetry Python API" +optional = false +python-versions = ">=3.8" +groups = ["main"] 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 = "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] -coverage = ">=4.4.1" -six = ">=1.7" - -[package.extras] -coverage-plugin = ["coverage (>=4.4.1)"] -doc = ["Sphinx (>=1.6.5)", "mock", "sphinx-rtd-theme"] +deprecated = ">=1.2.6" +importlib-metadata = ">=6.0,<=8.5.0" [[package]] name = "packaging" -version = "22.0" +version = "24.2" description = "Core utilities for Python packages" -category = "main" -optional = false -python-versions = ">=3.7" +optional = true +python-versions = ">=3.8" +groups = ["main"] +markers = "extra == \"dev\"" files = [ - {file = "packaging-22.0-py3-none-any.whl", hash = "sha256:957e2148ba0e1a3b282772e791ef1d8083648bc131c8ab0c1feba110ce1146c3"}, - {file = "packaging-22.0.tar.gz", hash = "sha256:2198ec20bd4c017b8f9717e00f0c8714076fc2fd93816750ab48e2c41de2cfd3"}, + {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, + {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, ] [[package]] -name = "pkgutil-resolve-name" -version = "1.3.10" -description = "Resolve a name to an object." -category = "main" -optional = false -python-versions = ">=3.6" +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 = "pkgutil_resolve_name-1.3.10-py3-none-any.whl", hash = "sha256:ca27cc078d25c5ad71a9de0a7a330146c4e014c2462d9af19c6b828280649c5e"}, - {file = "pkgutil_resolve_name-1.3.10.tar.gz", hash = "sha256:357d6c9e6a755653cfd78893817c0853af365dd51ec97f3d358a819373bbd174"}, + {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.21.12" +version = "5.29.5" description = "" -category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" +groups = ["main"] +files = [ + {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 = "protobuf-4.21.12-cp310-abi3-win32.whl", hash = "sha256:b135410244ebe777db80298297a97fbb4c862c881b4403b71bac9d4107d61fd1"}, - {file = "protobuf-4.21.12-cp310-abi3-win_amd64.whl", hash = "sha256:89f9149e4a0169cddfc44c74f230d7743002e3aa0b9472d8c28f0388102fc4c2"}, - {file = "protobuf-4.21.12-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:299ea899484ee6f44604deb71f424234f654606b983cb496ea2a53e3c63ab791"}, - {file = "protobuf-4.21.12-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:d1736130bce8cf131ac7957fa26880ca19227d4ad68b4888b3be0dea1f95df97"}, - {file = "protobuf-4.21.12-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:78a28c9fa223998472886c77042e9b9afb6fe4242bd2a2a5aced88e3f4422aa7"}, - {file = "protobuf-4.21.12-cp37-cp37m-win32.whl", hash = "sha256:3d164928ff0727d97022957c2b849250ca0e64777ee31efd7d6de2e07c494717"}, - {file = "protobuf-4.21.12-cp37-cp37m-win_amd64.whl", hash = "sha256:f45460f9ee70a0ec1b6694c6e4e348ad2019275680bd68a1d9314b8c7e01e574"}, - {file = "protobuf-4.21.12-cp38-cp38-win32.whl", hash = "sha256:6ab80df09e3208f742c98443b6166bcb70d65f52cfeb67357d52032ea1ae9bec"}, - {file = "protobuf-4.21.12-cp38-cp38-win_amd64.whl", hash = "sha256:1f22ac0ca65bb70a876060d96d914dae09ac98d114294f77584b0d2644fa9c30"}, - {file = "protobuf-4.21.12-cp39-cp39-win32.whl", hash = "sha256:27f4d15021da6d2b706ddc3860fac0a5ddaba34ab679dc182b60a8bb4e1121cc"}, - {file = "protobuf-4.21.12-cp39-cp39-win_amd64.whl", hash = "sha256:237216c3326d46808a9f7c26fd1bd4b20015fb6867dc5d263a493ef9a539293b"}, - {file = "protobuf-4.21.12-py2.py3-none-any.whl", hash = "sha256:a53fd3f03e578553623272dc46ac2f189de23862e68565e83dde203d41b76fc5"}, - {file = "protobuf-4.21.12-py3-none-any.whl", hash = "sha256:b98d0148f84e3a3c569e19f52103ca1feacdac0d2df8d6533cf983d1fda28462"}, - {file = "protobuf-4.21.12.tar.gz", hash = "sha256:7cd532c4566d0e6feafecc1059d04c7915aec8e182d1cf7adee8b24ef1e2e6ab"}, + {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" -category = "main" 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" -category = "main" 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 = "pyrsistent" -version = "0.19.3" -description = "Persistent/Functional/Immutable data structures" -category = "main" -optional = false +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 = "pyrsistent-0.19.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:20460ac0ea439a3e79caa1dbd560344b64ed75e85d8703943e0b66c2a6150e4a"}, - {file = "pyrsistent-0.19.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c18264cb84b5e68e7085a43723f9e4c1fd1d935ab240ce02c0324a8e01ccb64"}, - {file = "pyrsistent-0.19.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b774f9288dda8d425adb6544e5903f1fb6c273ab3128a355c6b972b7df39dcf"}, - {file = "pyrsistent-0.19.3-cp310-cp310-win32.whl", hash = "sha256:5a474fb80f5e0d6c9394d8db0fc19e90fa540b82ee52dba7d246a7791712f74a"}, - {file = "pyrsistent-0.19.3-cp310-cp310-win_amd64.whl", hash = "sha256:49c32f216c17148695ca0e02a5c521e28a4ee6c5089f97e34fe24163113722da"}, - {file = "pyrsistent-0.19.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f0774bf48631f3a20471dd7c5989657b639fd2d285b861237ea9e82c36a415a9"}, - {file = "pyrsistent-0.19.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ab2204234c0ecd8b9368dbd6a53e83c3d4f3cab10ecaf6d0e772f456c442393"}, - {file = "pyrsistent-0.19.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e42296a09e83028b3476f7073fcb69ffebac0e66dbbfd1bd847d61f74db30f19"}, - {file = "pyrsistent-0.19.3-cp311-cp311-win32.whl", hash = "sha256:64220c429e42a7150f4bfd280f6f4bb2850f95956bde93c6fda1b70507af6ef3"}, - {file = "pyrsistent-0.19.3-cp311-cp311-win_amd64.whl", hash = "sha256:016ad1afadf318eb7911baa24b049909f7f3bb2c5b1ed7b6a8f21db21ea3faa8"}, - {file = "pyrsistent-0.19.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c4db1bd596fefd66b296a3d5d943c94f4fac5bcd13e99bffe2ba6a759d959a28"}, - {file = "pyrsistent-0.19.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aeda827381f5e5d65cced3024126529ddc4289d944f75e090572c77ceb19adbf"}, - {file = "pyrsistent-0.19.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:42ac0b2f44607eb92ae88609eda931a4f0dfa03038c44c772e07f43e738bcac9"}, - {file = "pyrsistent-0.19.3-cp37-cp37m-win32.whl", hash = "sha256:e8f2b814a3dc6225964fa03d8582c6e0b6650d68a232df41e3cc1b66a5d2f8d1"}, - {file = "pyrsistent-0.19.3-cp37-cp37m-win_amd64.whl", hash = "sha256:c9bb60a40a0ab9aba40a59f68214eed5a29c6274c83b2cc206a359c4a89fa41b"}, - {file = "pyrsistent-0.19.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:a2471f3f8693101975b1ff85ffd19bb7ca7dd7c38f8a81701f67d6b4f97b87d8"}, - {file = "pyrsistent-0.19.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc5d149f31706762c1f8bda2e8c4f8fead6e80312e3692619a75301d3dbb819a"}, - {file = "pyrsistent-0.19.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3311cb4237a341aa52ab8448c27e3a9931e2ee09561ad150ba94e4cfd3fc888c"}, - {file = "pyrsistent-0.19.3-cp38-cp38-win32.whl", hash = "sha256:f0e7c4b2f77593871e918be000b96c8107da48444d57005b6a6bc61fb4331b2c"}, - {file = "pyrsistent-0.19.3-cp38-cp38-win_amd64.whl", hash = "sha256:c147257a92374fde8498491f53ffa8f4822cd70c0d85037e09028e478cababb7"}, - {file = "pyrsistent-0.19.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b735e538f74ec31378f5a1e3886a26d2ca6351106b4dfde376a26fc32a044edc"}, - {file = "pyrsistent-0.19.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99abb85579e2165bd8522f0c0138864da97847875ecbd45f3e7e2af569bfc6f2"}, - {file = "pyrsistent-0.19.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3a8cb235fa6d3fd7aae6a4f1429bbb1fec1577d978098da1252f0489937786f3"}, - {file = "pyrsistent-0.19.3-cp39-cp39-win32.whl", hash = "sha256:c74bed51f9b41c48366a286395c67f4e894374306b197e62810e0fdaf2364da2"}, - {file = "pyrsistent-0.19.3-cp39-cp39-win_amd64.whl", hash = "sha256:878433581fc23e906d947a6814336eee031a00e6defba224234169ae3d3d6a98"}, - {file = "pyrsistent-0.19.3-py3-none-any.whl", hash = "sha256:ccf0d6bd208f8111179f0c26fdf84ed7c3891982f2edaeae7422575f47e66b64"}, - {file = "pyrsistent-0.19.3.tar.gz", hash = "sha256:1a2994773706bbb4995c31a97bc94f1418314923bd1048c6d964837040376440"}, + {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" -category = "main" 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] @@ -644,206 +606,344 @@ six = ">=1.5" [[package]] name = "requests" -version = "2.28.1" +version = "2.32.4" description = "Python HTTP for Humans." -category = "main" optional = false -python-versions = ">=3.7, <4" +python-versions = ">=3.8" +groups = ["main"] files = [ - {file = "requests-2.28.1-py3-none-any.whl", hash = "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"}, - {file = "requests-2.28.1.tar.gz", hash = "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983"}, + {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,<3" +charset_normalizer = ">=2,<4" idna = ">=2.5,<4" -urllib3 = ">=1.21.1,<1.27" +urllib3 = ">=1.21.1,<3" [package.extras] socks = ["PySocks (>=1.5.6,!=1.5.7)"] use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] -name = "s3transfer" -version = "0.6.0" -description = "An Amazon S3 Transfer Manager" -category = "main" +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.6.0-py3-none-any.whl", hash = "sha256:06176b74f3a15f61f1b4f25a1fc29a4429040b7647133a463da8fa5bd28d5ecd"}, - {file = "s3transfer-0.6.0.tar.gz", hash = "sha256:2ed07d3866f523cc561bf4a00fc5535827981b117dd7876f036b0c1aca42c947"}, + {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 = "tomli" +version = "2.2.1" +description = "A lil' TOML parser" +optional = true +python-versions = ">=3.8" +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]] -name = "six" -version = "1.16.0" -description = "Python 2 and 3 compatibility utilities" -category = "main" +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 = "tenacity" -version = "8.1.0" -description = "Retry code until it succeeds" -category = "main" +name = "ujson" +version = "5.10.0" +description = "Ultra fast JSON encoder and decoder for Python" optional = false -python-versions = ">=3.6" -files = [ - {file = "tenacity-8.1.0-py3-none-any.whl", hash = "sha256:35525cd47f82830069f0d6b73f7eb83bc5b73ee2fff0437952cedf98b27653ac"}, - {file = "tenacity-8.1.0.tar.gz", hash = "sha256:e48c437fdf9340f5666b92cd7990e96bc5fc955e1298baf4a907e3972067a445"}, +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.extras] -doc = ["reno", "sphinx", "tornado (>=4.5)"] - [[package]] -name = "typing-extensions" -version = "4.4.0" -description = "Backported and Experimental Type Hints for Python 3.7+" -category = "main" +name = "urllib3" +version = "1.26.20" +description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false -python-versions = ">=3.7" +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 = "typing_extensions-4.4.0-py3-none-any.whl", hash = "sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e"}, - {file = "typing_extensions-4.4.0.tar.gz", hash = "sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa"}, + {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) ; 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 = "1.26.13" +version = "2.3.0" description = "HTTP library with thread-safe connection pooling, file post, and more." -category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +python-versions = ">=3.9" +groups = ["main"] +markers = "python_version >= \"3.10\"" files = [ - {file = "urllib3-1.26.13-py2.py3-none-any.whl", hash = "sha256:47cc05d99aaa09c9e72ed5809b60e7ba354e64b59c9c173ac3018642d8bb41fc"}, - {file = "urllib3-1.26.13.tar.gz", hash = "sha256:c083dd0dce68dbfbe1129d5271cb90f9447dea7d52097c6e0126120c521ddea8"}, + {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)", "brotlipy (>=0.6.0)"] -secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] -socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] +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.14.1" +version = "1.17.2" description = "Module for decorators, wrappers and monkey patching." -category = "main" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" -files = [ - {file = "wrapt-1.14.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:1b376b3f4896e7930f1f772ac4b064ac12598d1c38d04907e696cc4d794b43d3"}, - {file = "wrapt-1.14.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:903500616422a40a98a5a3c4ff4ed9d0066f3b4c951fa286018ecdf0750194ef"}, - {file = "wrapt-1.14.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5a9a0d155deafd9448baff28c08e150d9b24ff010e899311ddd63c45c2445e28"}, - {file = "wrapt-1.14.1-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:ddaea91abf8b0d13443f6dac52e89051a5063c7d014710dcb4d4abb2ff811a59"}, - {file = "wrapt-1.14.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:36f582d0c6bc99d5f39cd3ac2a9062e57f3cf606ade29a0a0d6b323462f4dd87"}, - {file = "wrapt-1.14.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:7ef58fb89674095bfc57c4069e95d7a31cfdc0939e2a579882ac7d55aadfd2a1"}, - {file = "wrapt-1.14.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:e2f83e18fe2f4c9e7db597e988f72712c0c3676d337d8b101f6758107c42425b"}, - {file = "wrapt-1.14.1-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:ee2b1b1769f6707a8a445162ea16dddf74285c3964f605877a20e38545c3c462"}, - {file = "wrapt-1.14.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:833b58d5d0b7e5b9832869f039203389ac7cbf01765639c7309fd50ef619e0b1"}, - {file = "wrapt-1.14.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:80bb5c256f1415f747011dc3604b59bc1f91c6e7150bd7db03b19170ee06b320"}, - {file = "wrapt-1.14.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:07f7a7d0f388028b2df1d916e94bbb40624c59b48ecc6cbc232546706fac74c2"}, - {file = "wrapt-1.14.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:02b41b633c6261feff8ddd8d11c711df6842aba629fdd3da10249a53211a72c4"}, - {file = "wrapt-1.14.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2fe803deacd09a233e4762a1adcea5db5d31e6be577a43352936179d14d90069"}, - {file = "wrapt-1.14.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:257fd78c513e0fb5cdbe058c27a0624c9884e735bbd131935fd49e9fe719d310"}, - {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4fcc4649dc762cddacd193e6b55bc02edca674067f5f98166d7713b193932b7f"}, - {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:11871514607b15cfeb87c547a49bca19fde402f32e2b1c24a632506c0a756656"}, - {file = "wrapt-1.14.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8ad85f7f4e20964db4daadcab70b47ab05c7c1cf2a7c1e51087bfaa83831854c"}, - {file = "wrapt-1.14.1-cp310-cp310-win32.whl", hash = "sha256:a9a52172be0b5aae932bef82a79ec0a0ce87288c7d132946d645eba03f0ad8a8"}, - {file = "wrapt-1.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:6d323e1554b3d22cfc03cd3243b5bb815a51f5249fdcbb86fda4bf62bab9e164"}, - {file = "wrapt-1.14.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:43ca3bbbe97af00f49efb06e352eae40434ca9d915906f77def219b88e85d907"}, - {file = "wrapt-1.14.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:6b1a564e6cb69922c7fe3a678b9f9a3c54e72b469875aa8018f18b4d1dd1adf3"}, - {file = "wrapt-1.14.1-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:00b6d4ea20a906c0ca56d84f93065b398ab74b927a7a3dbd470f6fc503f95dc3"}, - {file = "wrapt-1.14.1-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:a85d2b46be66a71bedde836d9e41859879cc54a2a04fad1191eb50c2066f6e9d"}, - {file = "wrapt-1.14.1-cp35-cp35m-win32.whl", hash = "sha256:dbcda74c67263139358f4d188ae5faae95c30929281bc6866d00573783c422b7"}, - {file = "wrapt-1.14.1-cp35-cp35m-win_amd64.whl", hash = "sha256:b21bb4c09ffabfa0e85e3a6b623e19b80e7acd709b9f91452b8297ace2a8ab00"}, - {file = "wrapt-1.14.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:9e0fd32e0148dd5dea6af5fee42beb949098564cc23211a88d799e434255a1f4"}, - {file = "wrapt-1.14.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9736af4641846491aedb3c3f56b9bc5568d92b0692303b5a305301a95dfd38b1"}, - {file = "wrapt-1.14.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b02d65b9ccf0ef6c34cba6cf5bf2aab1bb2f49c6090bafeecc9cd81ad4ea1c1"}, - {file = "wrapt-1.14.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21ac0156c4b089b330b7666db40feee30a5d52634cc4560e1905d6529a3897ff"}, - {file = "wrapt-1.14.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:9f3e6f9e05148ff90002b884fbc2a86bd303ae847e472f44ecc06c2cd2fcdb2d"}, - {file = "wrapt-1.14.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:6e743de5e9c3d1b7185870f480587b75b1cb604832e380d64f9504a0535912d1"}, - {file = "wrapt-1.14.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:d79d7d5dc8a32b7093e81e97dad755127ff77bcc899e845f41bf71747af0c569"}, - {file = "wrapt-1.14.1-cp36-cp36m-win32.whl", hash = "sha256:81b19725065dcb43df02b37e03278c011a09e49757287dca60c5aecdd5a0b8ed"}, - {file = "wrapt-1.14.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b014c23646a467558be7da3d6b9fa409b2c567d2110599b7cf9a0c5992b3b471"}, - {file = "wrapt-1.14.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:88bd7b6bd70a5b6803c1abf6bca012f7ed963e58c68d76ee20b9d751c74a3248"}, - {file = "wrapt-1.14.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5901a312f4d14c59918c221323068fad0540e34324925c8475263841dbdfe68"}, - {file = "wrapt-1.14.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d77c85fedff92cf788face9bfa3ebaa364448ebb1d765302e9af11bf449ca36d"}, - {file = "wrapt-1.14.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d649d616e5c6a678b26d15ece345354f7c2286acd6db868e65fcc5ff7c24a77"}, - {file = "wrapt-1.14.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7d2872609603cb35ca513d7404a94d6d608fc13211563571117046c9d2bcc3d7"}, - {file = "wrapt-1.14.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:ee6acae74a2b91865910eef5e7de37dc6895ad96fa23603d1d27ea69df545015"}, - {file = "wrapt-1.14.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2b39d38039a1fdad98c87279b48bc5dce2c0ca0d73483b12cb72aa9609278e8a"}, - {file = "wrapt-1.14.1-cp37-cp37m-win32.whl", hash = "sha256:60db23fa423575eeb65ea430cee741acb7c26a1365d103f7b0f6ec412b893853"}, - {file = "wrapt-1.14.1-cp37-cp37m-win_amd64.whl", hash = "sha256:709fe01086a55cf79d20f741f39325018f4df051ef39fe921b1ebe780a66184c"}, - {file = "wrapt-1.14.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8c0ce1e99116d5ab21355d8ebe53d9460366704ea38ae4d9f6933188f327b456"}, - {file = "wrapt-1.14.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e3fb1677c720409d5f671e39bac6c9e0e422584e5f518bfd50aa4cbbea02433f"}, - {file = "wrapt-1.14.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:642c2e7a804fcf18c222e1060df25fc210b9c58db7c91416fb055897fc27e8cc"}, - {file = "wrapt-1.14.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b7c050ae976e286906dd3f26009e117eb000fb2cf3533398c5ad9ccc86867b1"}, - {file = "wrapt-1.14.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef3f72c9666bba2bab70d2a8b79f2c6d2c1a42a7f7e2b0ec83bb2f9e383950af"}, - {file = "wrapt-1.14.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:01c205616a89d09827986bc4e859bcabd64f5a0662a7fe95e0d359424e0e071b"}, - {file = "wrapt-1.14.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5a0f54ce2c092aaf439813735584b9537cad479575a09892b8352fea5e988dc0"}, - {file = "wrapt-1.14.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2cf71233a0ed05ccdabe209c606fe0bac7379fdcf687f39b944420d2a09fdb57"}, - {file = "wrapt-1.14.1-cp38-cp38-win32.whl", hash = "sha256:aa31fdcc33fef9eb2552cbcbfee7773d5a6792c137b359e82879c101e98584c5"}, - {file = "wrapt-1.14.1-cp38-cp38-win_amd64.whl", hash = "sha256:d1967f46ea8f2db647c786e78d8cc7e4313dbd1b0aca360592d8027b8508e24d"}, - {file = "wrapt-1.14.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3232822c7d98d23895ccc443bbdf57c7412c5a65996c30442ebe6ed3df335383"}, - {file = "wrapt-1.14.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:988635d122aaf2bdcef9e795435662bcd65b02f4f4c1ae37fbee7401c440b3a7"}, - {file = "wrapt-1.14.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cca3c2cdadb362116235fdbd411735de4328c61425b0aa9f872fd76d02c4e86"}, - {file = "wrapt-1.14.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d52a25136894c63de15a35bc0bdc5adb4b0e173b9c0d07a2be9d3ca64a332735"}, - {file = "wrapt-1.14.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40e7bc81c9e2b2734ea4bc1aceb8a8f0ceaac7c5299bc5d69e37c44d9081d43b"}, - {file = "wrapt-1.14.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b9b7a708dd92306328117d8c4b62e2194d00c365f18eff11a9b53c6f923b01e3"}, - {file = "wrapt-1.14.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6a9a25751acb379b466ff6be78a315e2b439d4c94c1e99cb7266d40a537995d3"}, - {file = "wrapt-1.14.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:34aa51c45f28ba7f12accd624225e2b1e5a3a45206aa191f6f9aac931d9d56fe"}, - {file = "wrapt-1.14.1-cp39-cp39-win32.whl", hash = "sha256:dee0ce50c6a2dd9056c20db781e9c1cfd33e77d2d569f5d1d9321c641bb903d5"}, - {file = "wrapt-1.14.1-cp39-cp39-win_amd64.whl", hash = "sha256:dee60e1de1898bde3b238f18340eec6148986da0455d8ba7848d50470a7a32fb"}, - {file = "wrapt-1.14.1.tar.gz", hash = "sha256:380a85cf89e0e69b7cfbe2ea9f765f004ff419f34194018a6827ac0e3edfed4d"}, +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" -category = "main" 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.11.0" +version = "3.20.2" description = "Backport of pathlib-compatible object wrapper for zip files" -category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" +groups = ["main"] files = [ - {file = "zipp-3.11.0-py3-none-any.whl", hash = "sha256:83a28fcb75844b5c0cdaf5aa4003c2d728c77e05f5aeabe8e95e56727005fbaa"}, - {file = "zipp-3.11.0.tar.gz", hash = "sha256:a7a22e05929290a67401440b39690ae6563279bced5f314609d9d03798f56766"}, + {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)"] -testing = ["flake8 (<5)", "func-timeout", "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", "requests", "nose2", "flake8", "httpretty"] +dev = ["botocore", "flake8", "pytest", "pytest-benchmark", "requests"] [metadata] -lock-version = "2.0" -python-versions = ">=3.7.0,<4" -content-hash = "6ba474ff11bf0665dea4165d426c582eda61054671cd1d0d75889a24bb1bd48c" +lock-version = "2.1" +python-versions = ">=3.8.0,<4" +content-hash = "f6a2f7355200da107aa5b027d6fe4fb6bdb5a898ce8298a56e6ac39fe8d8e34d" diff --git a/pyproject.toml b/pyproject.toml index 495c1247c..d135e085b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "datadog_lambda" -version = "4.71.0" +version = "8.117.0.dev0" description = "The Datadog AWS Lambda Library" authors = ["Datadog, Inc. "] license = "Apache-2.0" @@ -16,35 +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 = "^1.6.4" -importlib_metadata = {version = "^1.0", python = "<3.8"} -boto3 = { version = "^1.10.33", 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 12a27b695..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") -PYTHON_VERSIONS_FOR_AWS_CLI=("python3.7" "python3.8" "python3.8" "python3.9" "python3.9" "python3.10" "python3.10") +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 1a35a5953..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") +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, tar its generatd `python` directory to sdout, - # then extract it to a temp directory. - docker run datadog-lambda-python-${arch}:$1 tar cf - python | tar -xf - -C $temp_dir - + --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 e3da8ed52..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") -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 2039f31e8..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") +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 88b2741f5..8c78093f8 100755 --- a/scripts/publish_layers.sh +++ b/scripts/publish_layers.sh @@ -13,12 +13,56 @@ 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") -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") -AVAILABLE_LAYERS=("Datadog-Python37" "Datadog-Python38" "Datadog-Python38-ARM" "Datadog-Python39" "Datadog-Python39-ARM" "Datadog-Python310" "Datadog-Python310-ARM") -ARCHS=("amd64" "amd64" "amd64""amd64" "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 +PIDS=() + +# Makes sure any subprocesses will be terminated with this process +trap "pkill -P $$; exit 1;" INT + # Check that the layer files exist for layer_file in "${LAYER_PATHS[@]}" do @@ -102,6 +146,35 @@ publish_layer() { echo $version_nbr } +wait_for_processes() { + for pid in "${PIDS[@]}"; do + wait $pid + done + PIDS=() +} + +backfill_layers() { + latest_version=$1 + region=$2 + layer_name=$3 + aws_version_key=$4 + layer_path=$5 + + while [ $latest_version -lt $VERSION ]; do + latest_version=$(publish_layer $region $layer_name $aws_version_key $layer_path) + echo "Published version $latest_version for layer $layer_name in region $region" + + # 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 + echo "ERROR: Published version $latest_version is greater than the desired version $VERSION!" + echo "Exiting" + exit 1 + fi + done +} + for region in $REGIONS do echo "Starting publishing layer for region $region..." @@ -112,31 +185,20 @@ do echo "Layer $layer_name version $VERSION already exists in region $region, skipping..." continue elif [ $latest_version -lt $((VERSION-1)) ]; then - read -p "WARNING: The latest version of layer $layer_name in region $region is $latest_version, publish all the missing versions including $VERSION or EXIT the script (y/n)?" CONT - if [ "$CONT" != "y" ]; then - echo "Exiting" - exit 1 - fi + echo "WARNING: The latest version of layer $layer_name in region $region is $latest_version, this will publish all the missing versions including $VERSION" fi index=$(index_of_layer $layer_name) aws_version_key="${PYTHON_VERSIONS_FOR_AWS_CLI[$index]}" layer_path="${LAYER_PATHS[$index]}" - while [ $latest_version -lt $VERSION ]; do - latest_version=$(publish_layer $region $layer_name $aws_version_key $layer_path) - echo "Published version $latest_version for layer $layer_name in region $region" - - # This shouldn't happen unless someone manually deleted the latest version, say 28 - # and then try to republish it again. The published version is 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 - echo "ERROR: Published version $latest_version is greater than the desired version $VERSION!" - echo "Exiting" - exit 1 - fi - done + backfill_layers $latest_version $region $layer_name $aws_version_key $layer_path & + PIDS+=($!) + if [ ${#PIDS[@]} -ge $BATCH_SIZE ]; then + wait_for_processes + fi done done +wait_for_processes echo "Done !" diff --git a/scripts/publish_prod.sh b/scripts/publish_prod.sh index a1bd55966..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 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..." @@ -64,34 +73,48 @@ echo "Building layers..." echo echo "Signing layers for commercial AWS regions" -aws-vault exec prod-engineering -- ./scripts/sign_layers.sh prod +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 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 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/publish_sandbox.sh b/scripts/publish_sandbox.sh index 4dec5889b..8f7d1de54 100755 --- a/scripts/publish_sandbox.sh +++ b/scripts/publish_sandbox.sh @@ -4,8 +4,8 @@ set -e ./scripts/build_layers.sh -aws-vault exec serverless-sandbox-account-admin -- ./scripts/sign_layers.sh sandbox -aws-vault exec serverless-sandbox-account-admin -- ./scripts/publish_layers.sh +aws-vault exec sso-serverless-sandbox-account-admin -- ./scripts/sign_layers.sh sandbox +aws-vault exec sso-serverless-sandbox-account-admin -- ./scripts/publish_layers.sh # Automatically create PR against github.com/DataDog/documentation # If you'd like to test, please uncomment the below line diff --git a/scripts/run_integration_tests.sh b/scripts/run_integration_tests.sh index 85a3dd2f2..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 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 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") LOGS_WAIT_SECONDS=20 @@ -28,12 +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") +PARAMETERS_SETS=("python38" "python39" "python310" "python311" "python312" "python313") if [ -z "$RUNTIME_PARAM" ]; then echo "Python version not specified, running for all python versions." @@ -56,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 @@ -71,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) @@ -84,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] @@ -100,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" @@ -114,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 @@ -156,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 @@ -199,9 +209,11 @@ for handler_name in "${LAMBDA_HANDLERS[@]}"; do sed -E "s/(api_key=|'api_key': '|DD-API-KEY:)[a-z0-9\.\-]+/\1XXXX/g" | # Normalize package version so that these snapshots aren't broken on version bumps sed -E "s/(dd_lambda_layer:datadog-python[0-9]+_)[0-9]+\.[0-9]+\.[0-9]+/\1X\.X\.X/g" | - 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/(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 @@ -230,11 +242,15 @@ for handler_name in "${LAMBDA_HANDLERS[@]}"; do sed -E "s/(\"connection_id\"\:\ \")[a-zA-Z0-9\-]+/\1XXXX/g" | sed -E "s/(\"shardId\-)([0-9]+)\:([a-zA-Z0-9]+)[a-zA-Z0-9]/\1XXXX:XXXX/g" | sed -E "s/(\"shardId\-)[0-9a-zA-Z]+/\1XXXX/g" | - sed -E "s/(\"datadog_lambda\"\: \")([0-9]+\.[0-9]+\.[0-9])/\1X.X.X/g" | + sed -E "s/(\"datadog_lambda\"\: \")([0-9]+\.[0-9]+\.[0-9]+)/\1X.X.X/g" | sed -E "s/(\"partition_key\"\:\ \")[a-zA-Z0-9\-]+/\1XXXX/g" | sed -E "s/(\"object_etag\"\:\ \")[a-zA-Z0-9\-]+/\1XXXX/g" | - sed -E "s/(\"dd_trace\"\: \")([0-9]+\.[0-9]+\.[0-9])/\1X.X.X/g" | + sed -E "s/(\"dd_trace\"\: \")([0-9]+\.[0-9]+\.[0-9]+)/\1X.X.X/g" | sed -E "s/(traceparent\:)([A-Za-z0-9\-]+)/\1XXX/g" | + 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 a5bf09b7e..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") +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 166093a44..eb40062f0 100755 --- a/scripts/sign_layers.sh +++ b/scripts/sign_layers.sh @@ -9,13 +9,18 @@ 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" "datadog_lambda_py-arm64-3.9.zip" "datadog_lambda_py-amd64-3.10.zip" "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" @@ -38,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/eventbridge-sqs.json b/tests/event_samples/eventbridge-sqs.json new file mode 100644 index 000000000..606abc094 --- /dev/null +++ b/tests/event_samples/eventbridge-sqs.json @@ -0,0 +1,21 @@ +{ + "Records": [ + { + "messageId": "e995e54f-1724-41fa-82c0-8b81821f854e", + "receiptHandle": "AQEB4mIfRcyqtzn1X5Ss+ConhTejVGc+qnAcmu3/Z9ZvbNkaPcpuDLX/bzvPD/ZkAXJUXZcemGSJmd7L3snZHKMP2Ck8runZiyl4mubiLb444pZvdiNPuGRJ6a3FvgS/GQPzho/9nNMyOi66m8Viwh70v4EUCPGO4JmD3TTDAUrrcAnqU4WSObjfC/NAp9bI6wH2CEyAYEfex6Nxplbl/jBf9ZUG0I3m3vQd0Q4l4gd4jIR4oxQUglU2Tldl4Kx5fMUAhTRLAENri6HsY81avBkKd9FAuxONlsITB5uj02kOkvLlRGEcalqsKyPJ7AFaDLrOLaL3U+yReroPEJ5R5nwhLOEbeN5HROlZRXeaAwZOIN8BjqdeooYTIOrtvMEVb7a6OPLMdH1XB+ddevtKAH8K9Tm2ZjpaA7dtBGh1zFVHzBk=", + "body": "{\"version\":\"0\",\"id\":\"af718b2a-b987-e8c0-7a2b-a188fad2661a\",\"detail-type\":\"my.Detail\",\"source\":\"my.Source\",\"account\":\"425362996713\",\"time\":\"2023-08-03T22:49:03Z\",\"region\":\"us-east-1\",\"resources\":[],\"detail\":{\"text\":\"Hello, world!\",\"_datadog\":{\"x-datadog-trace-id\":\"7379586022458917877\",\"x-datadog-parent-id\":\"2644033662113726488\",\"x-datadog-sampling-priority\":\"1\",\"x-datadog-tags\":\"_dd.p.dm=-0\",\"traceparent\":\"00-000000000000000066698e63821a03f5-24b17e9b6476c018-01\",\"tracestate\":\"dd=t.dm:-0;s:1\"}}}", + "attributes": { + "ApproximateReceiveCount": "1", + "AWSTraceHeader": "Root=1-64cc2edd-112fbf1701d1355973a11d57;Parent=7d5a9776024b2d42;Sampled=0", + "SentTimestamp": "1691102943638", + "SenderId": "AIDAJXNJGGKNS7OSV23OI", + "ApproximateFirstReceiveTimestamp": "1691102943647" + }, + "messageAttributes": {}, + "md5OfBody": "93d9f0cd8886d1e000a1a0b7007bffc4", + "eventSource": "aws:sqs", + "eventSourceARN": "arn:aws:sqs:us-east-1:425362996713:eventbridge-sqs-queue", + "awsRegion": "us-east-1" + } + ] +} 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/lambda-url.json b/tests/event_samples/lambda-url.json new file mode 100644 index 000000000..8e78650a8 --- /dev/null +++ b/tests/event_samples/lambda-url.json @@ -0,0 +1,47 @@ +{ + "version": "2.0", + "routeKey": "$default", + "rawPath": "/", + "rawQueryString": "", + "headers": { + "sec-fetch-mode": "navigate", + "sec-fetch-site": "none", + "accept-language": "en-US,en;q=0.9", + "x-forwarded-proto": "https", + "x-forwarded-port": "443", + "x-forwarded-for": "71.195.30.42", + "sec-fetch-user": "?1", + "pragma": "no-cache", + "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", + "sec-ch-ua": "\"Google Chrome\";v=\"95\", \"Chromium\";v=\"95\", \";Not A Brand\";v=\"99\"", + "sec-ch-ua-mobile": "?0", + "x-amzn-trace-id": "Root=1-61953929-1ec00c3011062a48477b169e", + "sec-ch-ua-platform": "\"macOS\"", + "host": "a8hyhsshac.lambda-url.eu-south-1.amazonaws.com", + "upgrade-insecure-requests": "1", + "cache-control": "no-cache", + "accept-encoding": "gzip, deflate, br", + "sec-fetch-dest": "document", + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36" + }, + "requestContext": { + "accountId": "601427279990", + "apiId": "a8hyhsshac", + "domainName": "a8hyhsshac.lambda-url.eu-south-1.amazonaws.com", + "domainPrefix": "a8hyhsshac", + "http": { + "method": "GET", + "path": "/", + "protocol": "HTTP/1.1", + "sourceIp": "71.195.30.42", + "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36" + }, + "requestId": "ec4d58f8-2b8b-4ceb-a1d5-2be7bff58505", + "routeKey": "$default", + "stage": "$default", + "time": "17/Nov/2021:17:17:29 +0000", + "timeEpoch": 1637169449721 + }, + "isBase64Encoded": false + } + \ No newline at end of file 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 27112f542..8c7e62f08 100644 --- a/tests/integration/serverless.yml +++ b/tests/integration/serverless.yml @@ -6,23 +6,40 @@ provider: region: eu-west-1 tracing: lambda: "PassThrough" + architecture: ${env:SLS_ARCH} environment: DD_INTEGRATION_TEST: true DD_TRACE_ENABLED: true DD_API_KEY: ${env:DD_API_KEY} DD_TRACE_MANAGED_SERVICES: true DD_COLD_START_TRACING: false + DD_SERVICE: ${self:service} timeout: 15 deploymentBucket: name: integration-tests-serververless-deployment-bucket 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) @@ -30,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 @@ -40,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 a7ad8826f..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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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,15 @@ 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" }, "metrics": { "process_id": XXXX, - "_dd.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -81,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, @@ -100,9 +104,10 @@ 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.route": "/", "http.status_code": "200" }, "metrics": { @@ -114,8 +119,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -126,11 +131,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -138,18 +145,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -172,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, @@ -199,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -208,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, @@ -219,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", @@ -228,22 +375,56 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.agent_psr": 1, "_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 +453,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -284,11 +465,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -296,18 +479,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -330,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" @@ -357,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -366,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, @@ -377,15 +562,18 @@ 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" }, "metrics": { "process_id": XXXX, - "_dd.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -395,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, @@ -423,8 +611,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -435,11 +623,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -447,18 +637,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -481,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" @@ -508,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -528,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", @@ -541,12 +733,15 @@ 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" }, "metrics": { "process_id": XXXX, - "_dd.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -556,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, @@ -575,9 +770,10 @@ 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.route": "/httpapi/get", "http.status_code": "200" }, "metrics": { @@ -589,8 +785,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -601,11 +797,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -613,18 +811,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -647,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" @@ -674,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -683,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, @@ -694,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", @@ -703,12 +904,14 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -718,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, @@ -747,8 +950,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -759,11 +962,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -771,18 +976,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -805,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" @@ -832,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -841,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, @@ -850,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", @@ -858,22 +1066,36 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.agent_psr": 1, "_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, @@ -902,8 +1124,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -914,11 +1136,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -926,18 +1150,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -960,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" @@ -987,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -996,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, @@ -1007,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", @@ -1014,12 +1241,14 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -1029,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, @@ -1058,8 +1287,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1070,11 +1299,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -1082,18 +1313,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -1116,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" @@ -1143,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -1152,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, @@ -1163,18 +1396,21 @@ 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...", "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.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -1184,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, @@ -1213,8 +1449,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1225,11 +1461,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -1237,18 +1475,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -1271,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" @@ -1298,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -1317,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", @@ -1330,12 +1571,14 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_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.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -1345,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, @@ -1364,7 +1607,8 @@ 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", + "span.kind": "server", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com/", "http.status_code": "200" }, "metrics": { @@ -1376,8 +1620,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1388,11 +1632,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -1400,18 +1646,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, diff --git a/tests/integration/snapshots/logs/async-metrics_python311.log b/tests/integration/snapshots/logs/async-metrics_python311.log new file mode 100644 index 000000000..9f14ff15c --- /dev/null +++ b/tests/integration/snapshots/logs/async-metrics_python311.log @@ -0,0 +1,1674 @@ +INIT_START Runtime Version: python:3.11.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_python311", + "resource:integration-tests-python-XXXX-async-metrics_python311", + "memorysize:1024", + "cold_start:true", + "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": "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_python311", + "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_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", + "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_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, + "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": "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_python311", + "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_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", + "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_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": "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_python311", + "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_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", + "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_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": "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_python311", + "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_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", + "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_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": "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_python311", + "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_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", + "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_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": "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_python311", + "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_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", + "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_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": "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_python311", + "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_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", + "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_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": "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_python311", + "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_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", + "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_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": "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_python311", + "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_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", + "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_python312.log b/tests/integration/snapshots/logs/async-metrics_python312.log new file mode 100644 index 000000000..789a39551 --- /dev/null +++ b/tests/integration/snapshots/logs/async-metrics_python312.log @@ -0,0 +1,1674 @@ +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", + "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", + "cold_start:true", + "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": "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_python312", + "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_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", + "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_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", + "cold_start:false", + "runtime:python3.12", + "datadog_lambda:vXX", + "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" + ] +} +{ + "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": "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_python312", + "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_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", + "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_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": "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_python312", + "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_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", + "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_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": "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_python312", + "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_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", + "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_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": "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_python312", + "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_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", + "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_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": "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_python312", + "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_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", + "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_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": "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_python312", + "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_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", + "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_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": "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_python312", + "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_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", + "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_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": "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_python312", + "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_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", + "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_python37.log b/tests/integration/snapshots/logs/async-metrics_python313.log similarity index 70% rename from tests/integration/snapshots/logs/async-metrics_python37.log rename to tests/integration/snapshots/logs/async-metrics_python313.log index 46a4f3364..78ade6a7a 100644 --- a/tests/integration/snapshots/logs/async-metrics_python37.log +++ b/tests/integration/snapshots/logs/async-metrics_python313.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.13.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_python313", + "resource:integration-tests-python-XXXX-async-metrics_python313", "memorysize:1024", - "runtime:python3.7", + "cold_start:true", + "runtime:python3.13", "datadog_lambda:vXX", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python313_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-python313_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-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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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,15 @@ 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" }, "metrics": { "process_id": XXXX, - "_dd.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -81,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_python313", "name": "aws.lambda", "error": 0, "start": "XXXX", @@ -90,19 +94,20 @@ 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_python313", "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_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", - "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.route": "/", "http.status_code": "200" }, "metrics": { @@ -114,8 +119,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -126,11 +131,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -138,18 +145,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -170,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_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", - "runtime:python3.7", + "cold_start:false", + "runtime:python3.13", "datadog_lambda:vXX", - "dd_lambda_layer:datadog-python37_X.X.X" + "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" ] } { @@ -186,7 +332,7 @@ START "t": [ "team:serverless", "role:hello", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python313_X.X.X" ] } { @@ -196,11 +342,11 @@ START "t": [ "test:integration", "role:hello", - "dd_lambda_layer:datadog-python37_X.X.X" + "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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -208,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, @@ -219,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", @@ -228,23 +375,57 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.agent_psr": 1, "_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_python313", "name": "aws.lambda", "error": 0, "start": "XXXX", @@ -252,11 +433,11 @@ 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_python313", "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_python313", + "functionname": "integration-tests-python-XXXX-async-metrics_python313", "datadog_lambda": "X.X.X", "dd_trace": "X.X.X", "span.name": "aws.lambda", @@ -272,8 +453,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -284,11 +465,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -296,18 +479,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -328,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_python313", + "resource:integration-tests-python-XXXX-async-metrics_python313", "memorysize:1024", - "runtime:python3.7", + "cold_start:false", + "runtime:python3.13", "datadog_lambda:vXX", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python313_X.X.X" ] } { @@ -344,7 +529,7 @@ START "t": [ "team:serverless", "role:hello", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python313_X.X.X" ] } { @@ -354,11 +539,11 @@ START "t": [ "test:integration", "role:hello", - "dd_lambda_layer:datadog-python37_X.X.X" + "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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -366,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, @@ -377,15 +562,18 @@ 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" }, "metrics": { "process_id": XXXX, - "_dd.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -395,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_python313", "name": "aws.lambda", "error": 0, "start": "XXXX", @@ -404,11 +592,11 @@ 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_python313", "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_python313", + "functionname": "integration-tests-python-XXXX-async-metrics_python313", "datadog_lambda": "X.X.X", "dd_trace": "X.X.X", "span.name": "aws.lambda", @@ -423,8 +611,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -435,11 +623,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -447,18 +637,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -479,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_python313", + "resource:integration-tests-python-XXXX-async-metrics_python313", "memorysize:1024", - "runtime:python3.7", + "cold_start:false", + "runtime:python3.13", "datadog_lambda:vXX", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python313_X.X.X" ] } { @@ -495,7 +687,7 @@ START "t": [ "team:serverless", "role:hello", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python313_X.X.X" ] } { @@ -505,11 +697,11 @@ START "t": [ "test:integration", "role:hello", - "dd_lambda_layer:datadog-python37_X.X.X" + "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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -528,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", @@ -541,12 +733,15 @@ 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" }, "metrics": { "process_id": XXXX, - "_dd.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -556,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_python313", "name": "aws.lambda", "error": 0, "start": "XXXX", @@ -565,19 +760,20 @@ 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_python313", "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_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", - "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.route": "/httpapi/get", "http.status_code": "200" }, "metrics": { @@ -589,8 +785,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -601,11 +797,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -613,18 +811,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -645,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_python313", + "resource:integration-tests-python-XXXX-async-metrics_python313", "memorysize:1024", - "runtime:python3.7", + "cold_start:false", + "runtime:python3.13", "datadog_lambda:vXX", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python313_X.X.X" ] } { @@ -661,7 +861,7 @@ START "t": [ "team:serverless", "role:hello", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python313_X.X.X" ] } { @@ -671,11 +871,11 @@ START "t": [ "test:integration", "role:hello", - "dd_lambda_layer:datadog-python37_X.X.X" + "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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -683,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, @@ -694,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", @@ -703,12 +904,14 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -718,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_python313", "name": "aws.lambda", "error": 0, "start": "XXXX", @@ -727,11 +930,11 @@ 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_python313", "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_python313", + "functionname": "integration-tests-python-XXXX-async-metrics_python313", "datadog_lambda": "X.X.X", "dd_trace": "X.X.X", "span.name": "aws.lambda", @@ -747,8 +950,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -759,11 +962,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -771,18 +976,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -803,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_python313", + "resource:integration-tests-python-XXXX-async-metrics_python313", "memorysize:1024", - "runtime:python3.7", + "cold_start:false", + "runtime:python3.13", "datadog_lambda:vXX", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python313_X.X.X" ] } { @@ -819,7 +1026,7 @@ START "t": [ "team:serverless", "role:hello", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python313_X.X.X" ] } { @@ -829,11 +1036,11 @@ START "t": [ "test:integration", "role:hello", - "dd_lambda_layer:datadog-python37_X.X.X" + "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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -841,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, @@ -850,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", @@ -858,23 +1066,37 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.agent_psr": 1, "_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_python313", "name": "aws.lambda", "error": 0, "start": "XXXX", @@ -882,11 +1104,11 @@ 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_python313", "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_python313", + "functionname": "integration-tests-python-XXXX-async-metrics_python313", "datadog_lambda": "X.X.X", "dd_trace": "X.X.X", "span.name": "aws.lambda", @@ -902,8 +1124,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -914,11 +1136,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -926,18 +1150,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -958,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_python313", + "resource:integration-tests-python-XXXX-async-metrics_python313", "memorysize:1024", - "runtime:python3.7", + "cold_start:false", + "runtime:python3.13", "datadog_lambda:vXX", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python313_X.X.X" ] } { @@ -974,7 +1200,7 @@ START "t": [ "team:serverless", "role:hello", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python313_X.X.X" ] } { @@ -984,11 +1210,11 @@ START "t": [ "test:integration", "role:hello", - "dd_lambda_layer:datadog-python37_X.X.X" + "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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -996,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, @@ -1007,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", @@ -1014,12 +1241,14 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -1029,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_python313", "name": "aws.lambda", "error": 0, "start": "XXXX", @@ -1038,11 +1267,11 @@ 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_python313", "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_python313", + "functionname": "integration-tests-python-XXXX-async-metrics_python313", "datadog_lambda": "X.X.X", "dd_trace": "X.X.X", "span.name": "aws.lambda", @@ -1058,8 +1287,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1070,11 +1299,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -1082,18 +1313,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -1114,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_python313", + "resource:integration-tests-python-XXXX-async-metrics_python313", "memorysize:1024", - "runtime:python3.7", + "cold_start:false", + "runtime:python3.13", "datadog_lambda:vXX", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python313_X.X.X" ] } { @@ -1130,7 +1363,7 @@ START "t": [ "team:serverless", "role:hello", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python313_X.X.X" ] } { @@ -1140,11 +1373,11 @@ START "t": [ "test:integration", "role:hello", - "dd_lambda_layer:datadog-python37_X.X.X" + "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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -1152,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, @@ -1163,18 +1396,21 @@ 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...", "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.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -1184,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_python313", "name": "aws.lambda", "error": 0, "start": "XXXX", @@ -1193,11 +1429,11 @@ 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_python313", "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_python313", + "functionname": "integration-tests-python-XXXX-async-metrics_python313", "datadog_lambda": "X.X.X", "dd_trace": "X.X.X", "span.name": "aws.lambda", @@ -1213,8 +1449,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1225,11 +1461,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -1237,18 +1475,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -1269,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_python313", + "resource:integration-tests-python-XXXX-async-metrics_python313", "memorysize:1024", - "runtime:python3.7", + "cold_start:false", + "runtime:python3.13", "datadog_lambda:vXX", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python313_X.X.X" ] } { @@ -1285,7 +1525,7 @@ START "t": [ "team:serverless", "role:hello", - "dd_lambda_layer:datadog-python37_X.X.X" + "dd_lambda_layer:datadog-python313_X.X.X" ] } { @@ -1295,11 +1535,11 @@ START "t": [ "test:integration", "role:hello", - "dd_lambda_layer:datadog-python37_X.X.X" + "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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -1317,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", @@ -1330,12 +1571,14 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_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.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -1345,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_python313", "name": "aws.lambda", "error": 0, "start": "XXXX", @@ -1354,17 +1597,18 @@ 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_python313", "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_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", - "http.url": "XXXX.execute-api.eu-west-1.amazonaws.com", + "span.kind": "server", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com/", "http.status_code": "200" }, "metrics": { @@ -1376,8 +1620,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1388,11 +1632,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -1400,18 +1646,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, diff --git a/tests/integration/snapshots/logs/async-metrics_python38.log b/tests/integration/snapshots/logs/async-metrics_python38.log index f27dfcd99..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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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,15 @@ 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" }, "metrics": { "process_id": XXXX, - "_dd.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -81,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, @@ -100,9 +104,10 @@ 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.route": "/", "http.status_code": "200" }, "metrics": { @@ -114,8 +119,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -126,11 +131,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -138,18 +145,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -172,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, @@ -199,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -208,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, @@ -219,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", @@ -228,22 +375,56 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.agent_psr": 1, "_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 +453,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -284,11 +465,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -296,18 +479,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -330,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" @@ -357,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -366,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, @@ -377,15 +562,18 @@ 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" }, "metrics": { "process_id": XXXX, - "_dd.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -395,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, @@ -423,8 +611,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -435,11 +623,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -447,18 +637,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -481,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" @@ -508,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -528,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", @@ -541,12 +733,15 @@ 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" }, "metrics": { "process_id": XXXX, - "_dd.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -556,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, @@ -575,9 +770,10 @@ 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.route": "/httpapi/get", "http.status_code": "200" }, "metrics": { @@ -589,8 +785,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -601,11 +797,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -613,18 +811,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -647,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" @@ -674,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -683,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, @@ -694,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", @@ -703,12 +904,14 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -718,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, @@ -747,8 +950,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -759,11 +962,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -771,18 +976,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -805,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" @@ -832,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -841,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, @@ -850,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", @@ -858,22 +1066,36 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.agent_psr": 1, "_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, @@ -902,8 +1124,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -914,11 +1136,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -926,18 +1150,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -960,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" @@ -987,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -996,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, @@ -1007,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", @@ -1014,12 +1241,14 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -1029,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, @@ -1058,8 +1287,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1070,11 +1299,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -1082,18 +1313,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -1116,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" @@ -1143,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -1152,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, @@ -1163,18 +1396,21 @@ 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...", "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.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -1184,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, @@ -1213,8 +1449,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1225,11 +1461,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -1237,18 +1475,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -1271,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" @@ -1298,8 +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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -1317,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", @@ -1330,12 +1571,14 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_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.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -1345,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_python38", "name": "aws.lambda", "error": 0, @@ -1364,7 +1607,8 @@ 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", + "span.kind": "server", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com/", "http.status_code": "200" }, "metrics": { @@ -1376,8 +1620,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1388,11 +1632,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -1400,18 +1646,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, diff --git a/tests/integration/snapshots/logs/async-metrics_python39.log b/tests/integration/snapshots/logs/async-metrics_python39.log index 1968de5e5..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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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,15 @@ 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" }, "metrics": { "process_id": XXXX, - "_dd.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -81,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, @@ -100,9 +104,10 @@ 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.route": "/", "http.status_code": "200" }, "metrics": { @@ -114,8 +119,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -126,11 +131,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -138,18 +145,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -172,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, @@ -199,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -208,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, @@ -219,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", @@ -228,22 +375,56 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.agent_psr": 1, "_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 +453,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -284,11 +465,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -296,18 +479,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -330,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" @@ -357,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -366,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, @@ -377,15 +562,18 @@ 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" }, "metrics": { "process_id": XXXX, - "_dd.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -395,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, @@ -423,8 +611,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -435,11 +623,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -447,18 +637,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -481,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" @@ -508,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -528,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", @@ -541,12 +733,15 @@ 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" }, "metrics": { "process_id": XXXX, - "_dd.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -556,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, @@ -575,9 +770,10 @@ 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.route": "/httpapi/get", "http.status_code": "200" }, "metrics": { @@ -589,8 +785,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -601,11 +797,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -613,18 +811,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -647,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" @@ -674,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -683,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, @@ -694,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", @@ -703,12 +904,14 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -718,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, @@ -747,8 +950,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -759,11 +962,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -771,18 +976,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -805,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" @@ -832,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -841,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, @@ -850,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", @@ -858,22 +1066,36 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.agent_psr": 1, "_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, @@ -902,8 +1124,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -914,11 +1136,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -926,18 +1150,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -960,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" @@ -987,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -996,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, @@ -1007,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", @@ -1014,12 +1241,14 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -1029,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, @@ -1058,8 +1287,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1070,11 +1299,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -1082,18 +1313,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -1116,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" @@ -1143,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -1152,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, @@ -1163,18 +1396,21 @@ 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...", "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.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -1184,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, @@ -1213,8 +1449,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1225,11 +1461,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -1237,18 +1475,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -1271,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" @@ -1298,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -1317,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", @@ -1330,12 +1571,14 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_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.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -1345,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, @@ -1364,7 +1607,8 @@ 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", + "span.kind": "server", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com/", "http.status_code": "200" }, "metrics": { @@ -1376,8 +1620,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1388,11 +1632,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -1400,18 +1646,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, diff --git a/tests/integration/snapshots/logs/sync-metrics_python310.log b/tests/integration/snapshots/logs/sync-metrics_python310.log index a82665520..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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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,15 @@ 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" }, "metrics": { "process_id": XXXX, - "_dd.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -61,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, @@ -80,9 +84,10 @@ 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.route": "/", "http.status_code": "200" }, "metrics": { @@ -94,8 +99,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -106,11 +111,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -118,18 +125,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -141,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {"series": [{"metric": "hello.dog", "points": [[XXXX, [1.0]]], "type": "distribution", "host": null, "device": null, "tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python310_X.X.X"], "interval": 10}, {"metric": "tests.integration.count", "points": [[XXXX, [21.0]]], "type": "distribution", "host": null, "device": null, "tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python310_X.X.X"], "interval": 10}]} +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": [ [ @@ -149,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": "aws.lambda", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -162,14 +171,15 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "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 x86_64)", + "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.agent_psr": 1, "_dd.measured": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 @@ -190,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +{ + "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": [ [ @@ -206,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, @@ -217,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", @@ -226,22 +393,56 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.agent_psr": 1, "_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, @@ -270,8 +471,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -282,11 +483,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -294,18 +497,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -317,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {"series": [{"metric": "hello.dog", "points": [[XXXX, [1.0]]], "type": "distribution", "host": null, "device": null, "tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python310_X.X.X"], "interval": 10}, {"metric": "tests.integration.count", "points": [[XXXX, [21.0]]], "type": "distribution", "host": null, "device": null, "tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python310_X.X.X"], "interval": 10}]} +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": [ [ @@ -325,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": "aws.lambda", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -338,14 +543,15 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "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 x86_64)", + "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.agent_psr": 1, "_dd.measured": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 @@ -366,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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 +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, @@ -393,15 +599,18 @@ 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" }, "metrics": { "process_id": XXXX, - "_dd.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -411,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, @@ -439,8 +648,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -451,11 +660,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -463,18 +674,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -486,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {"series": [{"metric": "hello.dog", "points": [[XXXX, [1.0]]], "type": "distribution", "host": null, "device": null, "tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python310_X.X.X"], "interval": 10}, {"metric": "tests.integration.count", "points": [[XXXX, [21.0]]], "type": "distribution", "host": null, "device": null, "tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python310_X.X.X"], "interval": 10}]} +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": [ [ @@ -494,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": "aws.lambda", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -507,14 +720,15 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "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 x86_64)", + "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.agent_psr": 1, "_dd.measured": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 @@ -535,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -562,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", @@ -575,12 +789,15 @@ 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" }, "metrics": { "process_id": XXXX, - "_dd.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -590,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, @@ -609,9 +826,10 @@ 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.route": "/httpapi/get", "http.status_code": "200" }, "metrics": { @@ -623,8 +841,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -635,11 +853,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -647,18 +867,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -670,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {"series": [{"metric": "hello.dog", "points": [[XXXX, [1.0]]], "type": "distribution", "host": null, "device": null, "tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python310_X.X.X"], "interval": 10}, {"metric": "tests.integration.count", "points": [[XXXX, [21.0]]], "type": "distribution", "host": null, "device": null, "tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python310_X.X.X"], "interval": 10}]} +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": [ [ @@ -678,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": "aws.lambda", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -691,14 +913,15 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "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 x86_64)", + "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.agent_psr": 1, "_dd.measured": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 @@ -719,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -735,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, @@ -746,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", @@ -755,12 +979,14 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -770,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, @@ -799,8 +1025,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -811,11 +1037,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -823,18 +1051,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -846,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {"series": [{"metric": "hello.dog", "points": [[XXXX, [1.0]]], "type": "distribution", "host": null, "device": null, "tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python310_X.X.X"], "interval": 10}, {"metric": "tests.integration.count", "points": [[XXXX, [21.0]]], "type": "distribution", "host": null, "device": null, "tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python310_X.X.X"], "interval": 10}]} +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": [ [ @@ -854,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": "aws.lambda", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -867,14 +1097,15 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "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 x86_64)", + "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.agent_psr": 1, "_dd.measured": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 @@ -895,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -911,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, @@ -920,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", @@ -928,22 +1160,36 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.agent_psr": 1, "_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, @@ -972,8 +1218,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -984,11 +1230,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -996,18 +1244,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -1019,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {"series": [{"metric": "hello.dog", "points": [[XXXX, [1.0]]], "type": "distribution", "host": null, "device": null, "tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python310_X.X.X"], "interval": 10}, {"metric": "tests.integration.count", "points": [[XXXX, [21.0]]], "type": "distribution", "host": null, "device": null, "tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python310_X.X.X"], "interval": 10}]} +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": [ [ @@ -1027,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": "aws.lambda", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1040,14 +1290,15 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "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 x86_64)", + "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.agent_psr": 1, "_dd.measured": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 @@ -1068,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -1084,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, @@ -1095,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", @@ -1102,12 +1354,14 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -1117,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, @@ -1146,8 +1400,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1158,11 +1412,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -1170,18 +1426,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -1193,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {"series": [{"metric": "hello.dog", "points": [[XXXX, [1.0]]], "type": "distribution", "host": null, "device": null, "tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python310_X.X.X"], "interval": 10}, {"metric": "tests.integration.count", "points": [[XXXX, [21.0]]], "type": "distribution", "host": null, "device": null, "tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python310_X.X.X"], "interval": 10}]} +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": [ [ @@ -1201,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": "aws.lambda", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1214,14 +1472,15 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "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 x86_64)", + "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.agent_psr": 1, "_dd.measured": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 @@ -1242,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -1258,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, @@ -1269,18 +1528,21 @@ 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...", "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.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -1290,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, @@ -1319,8 +1581,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1331,11 +1593,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -1343,18 +1607,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -1366,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {"series": [{"metric": "hello.dog", "points": [[XXXX, [1.0]]], "type": "distribution", "host": null, "device": null, "tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python310_X.X.X"], "interval": 10}, {"metric": "tests.integration.count", "points": [[XXXX, [21.0]]], "type": "distribution", "host": null, "device": null, "tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python310_X.X.X"], "interval": 10}]} +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": [ [ @@ -1374,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": "aws.lambda", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1387,14 +1653,15 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "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 x86_64)", + "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.agent_psr": 1, "_dd.measured": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 @@ -1415,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -1441,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", @@ -1454,12 +1722,14 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_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.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -1469,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, @@ -1488,7 +1758,8 @@ 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", + "span.kind": "server", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com/", "http.status_code": "200" }, "metrics": { @@ -1500,8 +1771,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1512,11 +1783,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -1524,18 +1797,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -1547,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {"series": [{"metric": "hello.dog", "points": [[XXXX, [1.0]]], "type": "distribution", "host": null, "device": null, "tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python310_X.X.X"], "interval": 10}, {"metric": "tests.integration.count", "points": [[XXXX, [21.0]]], "type": "distribution", "host": null, "device": null, "tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python310_X.X.X"], "interval": 10}]} +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": [ [ @@ -1555,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": "aws.lambda", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1568,14 +1843,15 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "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 x86_64)", + "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.agent_psr": 1, "_dd.measured": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 diff --git a/tests/integration/snapshots/logs/sync-metrics_python37.log b/tests/integration/snapshots/logs/sync-metrics_python311.log similarity index 67% rename from tests/integration/snapshots/logs/sync-metrics_python37.log rename to tests/integration/snapshots/logs/sync-metrics_python311.log index 338532935..b043a8f47 100644 --- a/tests/integration/snapshots/logs/sync-metrics_python37.log +++ b/tests/integration/snapshots/logs/sync-metrics_python311.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.11.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_python311", + "resource:integration-tests-python-XXXX-sync-metrics_python311", "memorysize:1024", - "runtime:python3.7", + "cold_start:true", + "runtime:python3.11", "datadog_lambda:vXX", - "dd_lambda_layer:datadog-python37_X.X.X" + "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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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,15 @@ 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" }, "metrics": { "process_id": XXXX, - "_dd.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -61,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_python311", "name": "aws.lambda", "error": 0, "start": "XXXX", @@ -70,19 +74,20 @@ 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_python311", "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_python311", + "functionname": "integration-tests-python-XXXX-sync-metrics_python311", "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.route": "/", "http.status_code": "200" }, "metrics": { @@ -94,8 +99,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -106,11 +111,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -118,18 +125,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -141,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {"series": [{"metric": "hello.dog", "points": [[XXXX, [1.0]]], "type": "distribution", "host": null, "device": null, "tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python37_X.X.X"], "interval": 10}, {"metric": "tests.integration.count", "points": [[XXXX, [21.0]]], "type": "distribution", "host": null, "device": null, "tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python37_X.X.X"], "interval": 10}]} +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": [ [ @@ -149,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": "aws.lambda", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -162,14 +171,15 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "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 x86_64)", + "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.agent_psr": 1, "_dd.measured": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 @@ -188,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_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", - "runtime:python3.7", + "cold_start:false", + "runtime:python3.11", "datadog_lambda:vXX", - "dd_lambda_layer:datadog-python37_X.X.X" + "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" ] } -HTTP GET https://datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", "Accept:*/*", "Connection:keep-alive", "User-Agent:python-requests/X.X.X", "traceparent:XXX", "tracestate:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -206,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, @@ -217,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", @@ -226,23 +393,57 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.agent_psr": 1, "_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_python311", "name": "aws.lambda", "error": 0, "start": "XXXX", @@ -250,11 +451,11 @@ 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_python311", "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_python311", + "functionname": "integration-tests-python-XXXX-sync-metrics_python311", "datadog_lambda": "X.X.X", "dd_trace": "X.X.X", "span.name": "aws.lambda", @@ -270,8 +471,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -282,11 +483,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -294,18 +497,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -317,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {"series": [{"metric": "hello.dog", "points": [[XXXX, [1.0]]], "type": "distribution", "host": null, "device": null, "tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python37_X.X.X"], "interval": 10}, {"metric": "tests.integration.count", "points": [[XXXX, [21.0]]], "type": "distribution", "host": null, "device": null, "tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python37_X.X.X"], "interval": 10}]} +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": [ [ @@ -325,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": "aws.lambda", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -338,14 +543,15 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "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 x86_64)", + "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.agent_psr": 1, "_dd.measured": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 @@ -364,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_python311", + "resource:integration-tests-python-XXXX-sync-metrics_python311", "memorysize:1024", - "runtime:python3.7", + "cold_start:false", + "runtime:python3.11", "datadog_lambda:vXX", - "dd_lambda_layer:datadog-python37_X.X.X" + "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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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 +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, @@ -393,15 +599,18 @@ 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" }, "metrics": { "process_id": XXXX, - "_dd.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -411,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_python311", "name": "aws.lambda", "error": 0, "start": "XXXX", @@ -420,11 +629,11 @@ 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_python311", "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_python311", + "functionname": "integration-tests-python-XXXX-sync-metrics_python311", "datadog_lambda": "X.X.X", "dd_trace": "X.X.X", "span.name": "aws.lambda", @@ -439,8 +648,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -451,11 +660,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -463,18 +674,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -486,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {"series": [{"metric": "hello.dog", "points": [[XXXX, [1.0]]], "type": "distribution", "host": null, "device": null, "tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python37_X.X.X"], "interval": 10}, {"metric": "tests.integration.count", "points": [[XXXX, [21.0]]], "type": "distribution", "host": null, "device": null, "tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python37_X.X.X"], "interval": 10}]} +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": [ [ @@ -494,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": "aws.lambda", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -507,14 +720,15 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "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 x86_64)", + "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.agent_psr": 1, "_dd.measured": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 @@ -533,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_python311", + "resource:integration-tests-python-XXXX-sync-metrics_python311", "memorysize:1024", - "runtime:python3.7", + "cold_start:false", + "runtime:python3.11", "datadog_lambda:vXX", - "dd_lambda_layer:datadog-python37_X.X.X" + "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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -562,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", @@ -575,12 +789,15 @@ 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" }, "metrics": { "process_id": XXXX, - "_dd.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -590,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_python311", "name": "aws.lambda", "error": 0, "start": "XXXX", @@ -599,19 +816,20 @@ 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_python311", "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_python311", + "functionname": "integration-tests-python-XXXX-sync-metrics_python311", "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.route": "/httpapi/get", "http.status_code": "200" }, "metrics": { @@ -623,8 +841,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -635,11 +853,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -647,18 +867,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -670,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {"series": [{"metric": "hello.dog", "points": [[XXXX, [1.0]]], "type": "distribution", "host": null, "device": null, "tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python37_X.X.X"], "interval": 10}, {"metric": "tests.integration.count", "points": [[XXXX, [21.0]]], "type": "distribution", "host": null, "device": null, "tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python37_X.X.X"], "interval": 10}]} +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": [ [ @@ -678,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": "aws.lambda", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -691,14 +913,15 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "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 x86_64)", + "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.agent_psr": 1, "_dd.measured": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 @@ -717,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_python311", + "resource:integration-tests-python-XXXX-sync-metrics_python311", "memorysize:1024", - "runtime:python3.7", + "cold_start:false", + "runtime:python3.11", "datadog_lambda:vXX", - "dd_lambda_layer:datadog-python37_X.X.X" + "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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -735,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, @@ -746,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", @@ -755,12 +979,14 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -770,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_python311", "name": "aws.lambda", "error": 0, "start": "XXXX", @@ -779,11 +1005,11 @@ 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_python311", "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_python311", + "functionname": "integration-tests-python-XXXX-sync-metrics_python311", "datadog_lambda": "X.X.X", "dd_trace": "X.X.X", "span.name": "aws.lambda", @@ -799,8 +1025,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -811,11 +1037,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -823,18 +1051,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -846,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {"series": [{"metric": "hello.dog", "points": [[XXXX, [1.0]]], "type": "distribution", "host": null, "device": null, "tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python37_X.X.X"], "interval": 10}, {"metric": "tests.integration.count", "points": [[XXXX, [21.0]]], "type": "distribution", "host": null, "device": null, "tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python37_X.X.X"], "interval": 10}]} +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": [ [ @@ -854,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": "aws.lambda", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -867,14 +1097,15 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "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 x86_64)", + "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.agent_psr": 1, "_dd.measured": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 @@ -893,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_python311", + "resource:integration-tests-python-XXXX-sync-metrics_python311", "memorysize:1024", - "runtime:python3.7", + "cold_start:false", + "runtime:python3.11", "datadog_lambda:vXX", - "dd_lambda_layer:datadog-python37_X.X.X" + "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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -911,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, @@ -920,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", @@ -928,23 +1160,37 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.agent_psr": 1, "_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_python311", "name": "aws.lambda", "error": 0, "start": "XXXX", @@ -952,11 +1198,11 @@ 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_python311", "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_python311", + "functionname": "integration-tests-python-XXXX-sync-metrics_python311", "datadog_lambda": "X.X.X", "dd_trace": "X.X.X", "span.name": "aws.lambda", @@ -972,8 +1218,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -984,11 +1230,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -996,18 +1244,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -1019,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {"series": [{"metric": "hello.dog", "points": [[XXXX, [1.0]]], "type": "distribution", "host": null, "device": null, "tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python37_X.X.X"], "interval": 10}, {"metric": "tests.integration.count", "points": [[XXXX, [21.0]]], "type": "distribution", "host": null, "device": null, "tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python37_X.X.X"], "interval": 10}]} +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": [ [ @@ -1027,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": "aws.lambda", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1040,14 +1290,15 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "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 x86_64)", + "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.agent_psr": 1, "_dd.measured": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 @@ -1066,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_python311", + "resource:integration-tests-python-XXXX-sync-metrics_python311", "memorysize:1024", - "runtime:python3.7", + "cold_start:false", + "runtime:python3.11", "datadog_lambda:vXX", - "dd_lambda_layer:datadog-python37_X.X.X" + "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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -1084,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, @@ -1095,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", @@ -1102,12 +1354,14 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -1117,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_python311", "name": "aws.lambda", "error": 0, "start": "XXXX", @@ -1126,11 +1380,11 @@ 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_python311", "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_python311", + "functionname": "integration-tests-python-XXXX-sync-metrics_python311", "datadog_lambda": "X.X.X", "dd_trace": "X.X.X", "span.name": "aws.lambda", @@ -1146,8 +1400,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1158,11 +1412,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -1170,18 +1426,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -1193,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {"series": [{"metric": "hello.dog", "points": [[XXXX, [1.0]]], "type": "distribution", "host": null, "device": null, "tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python37_X.X.X"], "interval": 10}, {"metric": "tests.integration.count", "points": [[XXXX, [21.0]]], "type": "distribution", "host": null, "device": null, "tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python37_X.X.X"], "interval": 10}]} +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": [ [ @@ -1201,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": "aws.lambda", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1214,14 +1472,15 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "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 x86_64)", + "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.agent_psr": 1, "_dd.measured": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 @@ -1240,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_python311", + "resource:integration-tests-python-XXXX-sync-metrics_python311", "memorysize:1024", - "runtime:python3.7", + "cold_start:false", + "runtime:python3.11", "datadog_lambda:vXX", - "dd_lambda_layer:datadog-python37_X.X.X" + "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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -1258,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, @@ -1269,18 +1528,21 @@ 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...", "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.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -1290,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_python311", "name": "aws.lambda", "error": 0, "start": "XXXX", @@ -1299,11 +1561,11 @@ 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_python311", "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_python311", + "functionname": "integration-tests-python-XXXX-sync-metrics_python311", "datadog_lambda": "X.X.X", "dd_trace": "X.X.X", "span.name": "aws.lambda", @@ -1319,8 +1581,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1331,11 +1593,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -1343,18 +1607,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -1366,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {"series": [{"metric": "hello.dog", "points": [[XXXX, [1.0]]], "type": "distribution", "host": null, "device": null, "tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python37_X.X.X"], "interval": 10}, {"metric": "tests.integration.count", "points": [[XXXX, [21.0]]], "type": "distribution", "host": null, "device": null, "tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python37_X.X.X"], "interval": 10}]} +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": [ [ @@ -1374,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": "aws.lambda", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1387,14 +1653,15 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "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 x86_64)", + "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.agent_psr": 1, "_dd.measured": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 @@ -1413,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_python311", + "resource:integration-tests-python-XXXX-sync-metrics_python311", "memorysize:1024", - "runtime:python3.7", + "cold_start:false", + "runtime:python3.11", "datadog_lambda:vXX", - "dd_lambda_layer:datadog-python37_X.X.X" + "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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -1441,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", @@ -1454,12 +1722,14 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_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.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -1469,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_python311", "name": "aws.lambda", "error": 0, "start": "XXXX", @@ -1478,17 +1748,18 @@ 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_python311", "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_python311", + "functionname": "integration-tests-python-XXXX-sync-metrics_python311", "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", + "span.kind": "server", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com/", "http.status_code": "200" }, "metrics": { @@ -1500,8 +1771,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1512,11 +1783,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -1524,18 +1797,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -1547,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {"series": [{"metric": "hello.dog", "points": [[XXXX, [1.0]]], "type": "distribution", "host": null, "device": null, "tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python37_X.X.X"], "interval": 10}, {"metric": "tests.integration.count", "points": [[XXXX, [21.0]]], "type": "distribution", "host": null, "device": null, "tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python37_X.X.X"], "interval": 10}]} +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": [ [ @@ -1555,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": "aws.lambda", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1568,14 +1843,15 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "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 x86_64)", + "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.agent_psr": 1, "_dd.measured": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 diff --git a/tests/integration/snapshots/logs/sync-metrics_python312.log b/tests/integration/snapshots/logs/sync-metrics_python312.log new file mode 100644 index 000000000..ff9bbdb75 --- /dev/null +++ b/tests/integration/snapshots/logs/sync-metrics_python312.log @@ -0,0 +1,1864 @@ +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", + "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", + "cold_start:true", + "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": "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_python312", + "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_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", + "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_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", + "cold_start:false", + "runtime:python3.12", + "datadog_lambda:vXX", + "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" + ] +} +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_python312", + "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_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", + "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_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": "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_python312", + "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_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", + "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_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": "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_python312", + "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_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", + "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_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": "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_python312", + "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_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", + "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_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": "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_python312", + "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_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", + "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_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": "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_python312", + "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_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", + "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_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": "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_python312", + "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_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", + "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_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": "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_python312", + "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_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", + "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_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 c62928a3d..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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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,15 @@ 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" }, "metrics": { "process_id": XXXX, - "_dd.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -61,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, @@ -80,9 +84,10 @@ 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.route": "/", "http.status_code": "200" }, "metrics": { @@ -94,8 +99,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -106,11 +111,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -118,18 +125,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -141,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {"series": [{"metric": "hello.dog", "points": [[XXXX, [1.0]]], "type": "distribution", "host": null, "device": null, "tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python38_X.X.X"], "interval": 10}, {"metric": "tests.integration.count", "points": [[XXXX, [21.0]]], "type": "distribution", "host": null, "device": null, "tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python38_X.X.X"], "interval": 10}]} +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": [ [ @@ -149,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": "aws.lambda", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -162,14 +171,15 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "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 x86_64)", + "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.agent_psr": 1, "_dd.measured": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 @@ -190,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +{ + "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": [ [ @@ -206,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, @@ -217,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", @@ -226,22 +393,56 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.agent_psr": 1, "_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, @@ -270,8 +471,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -282,11 +483,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -294,18 +497,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -317,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {"series": [{"metric": "hello.dog", "points": [[XXXX, [1.0]]], "type": "distribution", "host": null, "device": null, "tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python38_X.X.X"], "interval": 10}, {"metric": "tests.integration.count", "points": [[XXXX, [21.0]]], "type": "distribution", "host": null, "device": null, "tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python38_X.X.X"], "interval": 10}]} +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": [ [ @@ -325,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": "aws.lambda", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -338,14 +543,15 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "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 x86_64)", + "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.agent_psr": 1, "_dd.measured": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 @@ -366,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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 +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, @@ -393,15 +599,18 @@ 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" }, "metrics": { "process_id": XXXX, - "_dd.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -411,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, @@ -439,8 +648,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -451,11 +660,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -463,18 +674,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -486,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {"series": [{"metric": "hello.dog", "points": [[XXXX, [1.0]]], "type": "distribution", "host": null, "device": null, "tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python38_X.X.X"], "interval": 10}, {"metric": "tests.integration.count", "points": [[XXXX, [21.0]]], "type": "distribution", "host": null, "device": null, "tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python38_X.X.X"], "interval": 10}]} +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": [ [ @@ -494,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": "aws.lambda", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -507,14 +720,15 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "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 x86_64)", + "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.agent_psr": 1, "_dd.measured": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 @@ -535,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -562,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", @@ -575,12 +789,15 @@ 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" }, "metrics": { "process_id": XXXX, - "_dd.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -590,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, @@ -609,9 +826,10 @@ 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.route": "/httpapi/get", "http.status_code": "200" }, "metrics": { @@ -623,8 +841,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -635,11 +853,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -647,18 +867,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -670,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {"series": [{"metric": "hello.dog", "points": [[XXXX, [1.0]]], "type": "distribution", "host": null, "device": null, "tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python38_X.X.X"], "interval": 10}, {"metric": "tests.integration.count", "points": [[XXXX, [21.0]]], "type": "distribution", "host": null, "device": null, "tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python38_X.X.X"], "interval": 10}]} +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": [ [ @@ -678,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": "aws.lambda", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -691,14 +913,15 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "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 x86_64)", + "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.agent_psr": 1, "_dd.measured": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 @@ -719,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -735,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, @@ -746,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", @@ -755,12 +979,14 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -770,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, @@ -799,8 +1025,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -811,11 +1037,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -823,18 +1051,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -846,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {"series": [{"metric": "hello.dog", "points": [[XXXX, [1.0]]], "type": "distribution", "host": null, "device": null, "tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python38_X.X.X"], "interval": 10}, {"metric": "tests.integration.count", "points": [[XXXX, [21.0]]], "type": "distribution", "host": null, "device": null, "tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python38_X.X.X"], "interval": 10}]} +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": [ [ @@ -854,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": "aws.lambda", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -867,14 +1097,15 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "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 x86_64)", + "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.agent_psr": 1, "_dd.measured": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 @@ -895,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -911,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, @@ -920,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", @@ -928,22 +1160,36 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.agent_psr": 1, "_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, @@ -972,8 +1218,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -984,11 +1230,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -996,18 +1244,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -1019,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {"series": [{"metric": "hello.dog", "points": [[XXXX, [1.0]]], "type": "distribution", "host": null, "device": null, "tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python38_X.X.X"], "interval": 10}, {"metric": "tests.integration.count", "points": [[XXXX, [21.0]]], "type": "distribution", "host": null, "device": null, "tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python38_X.X.X"], "interval": 10}]} +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": [ [ @@ -1027,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": "aws.lambda", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1040,14 +1290,15 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "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 x86_64)", + "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.agent_psr": 1, "_dd.measured": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 @@ -1068,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -1084,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, @@ -1095,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", @@ -1102,12 +1354,14 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -1117,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, @@ -1146,8 +1400,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1158,11 +1412,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -1170,18 +1426,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -1193,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {"series": [{"metric": "hello.dog", "points": [[XXXX, [1.0]]], "type": "distribution", "host": null, "device": null, "tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python38_X.X.X"], "interval": 10}, {"metric": "tests.integration.count", "points": [[XXXX, [21.0]]], "type": "distribution", "host": null, "device": null, "tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python38_X.X.X"], "interval": 10}]} +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": [ [ @@ -1201,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": "aws.lambda", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1214,14 +1472,15 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "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 x86_64)", + "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.agent_psr": 1, "_dd.measured": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 @@ -1242,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -1258,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, @@ -1269,18 +1528,21 @@ 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...", "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.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -1290,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, @@ -1319,8 +1581,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1331,11 +1593,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -1343,18 +1607,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -1366,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {"series": [{"metric": "hello.dog", "points": [[XXXX, [1.0]]], "type": "distribution", "host": null, "device": null, "tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python38_X.X.X"], "interval": 10}, {"metric": "tests.integration.count", "points": [[XXXX, [21.0]]], "type": "distribution", "host": null, "device": null, "tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python38_X.X.X"], "interval": 10}]} +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": [ [ @@ -1374,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": "aws.lambda", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1387,14 +1653,15 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "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 x86_64)", + "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.agent_psr": 1, "_dd.measured": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 @@ -1415,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -1441,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", @@ -1454,12 +1722,14 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_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.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -1469,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, @@ -1488,7 +1758,8 @@ 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", + "span.kind": "server", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com/", "http.status_code": "200" }, "metrics": { @@ -1500,8 +1771,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1512,11 +1783,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -1524,18 +1797,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -1547,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {"series": [{"metric": "hello.dog", "points": [[XXXX, [1.0]]], "type": "distribution", "host": null, "device": null, "tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python38_X.X.X"], "interval": 10}, {"metric": "tests.integration.count", "points": [[XXXX, [21.0]]], "type": "distribution", "host": null, "device": null, "tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python38_X.X.X"], "interval": 10}]} +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": [ [ @@ -1555,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": "aws.lambda", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1568,14 +1843,15 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "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 x86_64)", + "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.agent_psr": 1, "_dd.measured": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 diff --git a/tests/integration/snapshots/logs/sync-metrics_python39.log b/tests/integration/snapshots/logs/sync-metrics_python39.log index fbde4bcda..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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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,15 @@ 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" }, "metrics": { "process_id": XXXX, - "_dd.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -61,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, @@ -80,9 +84,10 @@ 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.route": "/", "http.status_code": "200" }, "metrics": { @@ -94,8 +99,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -106,11 +111,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -118,18 +125,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -141,8 +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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {"series": [{"metric": "hello.dog", "points": [[XXXX, [1.0]]], "type": "distribution", "host": null, "device": null, "tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python39_X.X.X"], "interval": 10}, {"metric": "tests.integration.count", "points": [[XXXX, [21.0]]], "type": "distribution", "host": null, "device": null, "tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python39_X.X.X"], "interval": 10}]} -END Duration: XXXX ms (init: 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": [ [ @@ -150,8 +158,8 @@ END Duration: XXXX ms (init: XXXX ms) Memory Used: XXXX MB "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -163,14 +171,15 @@ END Duration: XXXX ms (init: XXXX ms) Memory Used: XXXX MB "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 x86_64)", + "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.agent_psr": 1, "_dd.measured": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 @@ -180,6 +189,7 @@ END Duration: XXXX ms (init: XXXX ms) Memory Used: XXXX MB ] ] } +END Duration: XXXX ms (init: XXXX ms) Memory Used: XXXX MB START { "m": "aws.lambda.enhanced.invocations", @@ -190,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +{ + "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": [ [ @@ -206,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, @@ -217,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", @@ -226,22 +393,56 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.agent_psr": 1, "_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, @@ -270,8 +471,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -282,11 +483,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -294,18 +497,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -317,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {"series": [{"metric": "hello.dog", "points": [[XXXX, [1.0]]], "type": "distribution", "host": null, "device": null, "tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python39_X.X.X"], "interval": 10}, {"metric": "tests.integration.count", "points": [[XXXX, [21.0]]], "type": "distribution", "host": null, "device": null, "tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python39_X.X.X"], "interval": 10}]} +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": [ [ @@ -325,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": "aws.lambda", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -338,14 +543,15 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "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 x86_64)", + "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.agent_psr": 1, "_dd.measured": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 @@ -366,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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 +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, @@ -393,15 +599,18 @@ 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" }, "metrics": { "process_id": XXXX, - "_dd.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -411,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, @@ -439,8 +648,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -451,11 +660,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -463,18 +674,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -486,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {"series": [{"metric": "hello.dog", "points": [[XXXX, [1.0]]], "type": "distribution", "host": null, "device": null, "tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python39_X.X.X"], "interval": 10}, {"metric": "tests.integration.count", "points": [[XXXX, [21.0]]], "type": "distribution", "host": null, "device": null, "tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python39_X.X.X"], "interval": 10}]} +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": [ [ @@ -494,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": "aws.lambda", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -507,14 +720,15 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "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 x86_64)", + "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.agent_psr": 1, "_dd.measured": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 @@ -535,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -562,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", @@ -575,12 +789,15 @@ 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" }, "metrics": { "process_id": XXXX, - "_dd.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -590,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, @@ -609,9 +826,10 @@ 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.route": "/httpapi/get", "http.status_code": "200" }, "metrics": { @@ -623,8 +841,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -635,11 +853,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -647,18 +867,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -670,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {"series": [{"metric": "hello.dog", "points": [[XXXX, [1.0]]], "type": "distribution", "host": null, "device": null, "tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python39_X.X.X"], "interval": 10}, {"metric": "tests.integration.count", "points": [[XXXX, [21.0]]], "type": "distribution", "host": null, "device": null, "tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python39_X.X.X"], "interval": 10}]} +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": [ [ @@ -678,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": "aws.lambda", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -691,14 +913,15 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "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 x86_64)", + "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.agent_psr": 1, "_dd.measured": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 @@ -719,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -735,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, @@ -746,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", @@ -755,12 +979,14 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -770,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, @@ -799,8 +1025,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -811,11 +1037,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -823,18 +1051,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -846,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {"series": [{"metric": "hello.dog", "points": [[XXXX, [1.0]]], "type": "distribution", "host": null, "device": null, "tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python39_X.X.X"], "interval": 10}, {"metric": "tests.integration.count", "points": [[XXXX, [21.0]]], "type": "distribution", "host": null, "device": null, "tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python39_X.X.X"], "interval": 10}]} +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": [ [ @@ -854,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": "aws.lambda", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -867,14 +1097,15 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "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 x86_64)", + "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.agent_psr": 1, "_dd.measured": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 @@ -895,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -911,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, @@ -920,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", @@ -928,22 +1160,36 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.agent_psr": 1, "_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, @@ -972,8 +1218,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -984,11 +1230,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -996,18 +1244,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -1019,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {"series": [{"metric": "hello.dog", "points": [[XXXX, [1.0]]], "type": "distribution", "host": null, "device": null, "tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python39_X.X.X"], "interval": 10}, {"metric": "tests.integration.count", "points": [[XXXX, [21.0]]], "type": "distribution", "host": null, "device": null, "tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python39_X.X.X"], "interval": 10}]} +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": [ [ @@ -1027,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": "aws.lambda", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1040,14 +1290,15 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "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 x86_64)", + "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.agent_psr": 1, "_dd.measured": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 @@ -1068,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -1084,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, @@ -1095,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", @@ -1102,12 +1354,14 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -1117,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, @@ -1146,8 +1400,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1158,11 +1412,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -1170,18 +1426,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -1193,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {"series": [{"metric": "hello.dog", "points": [[XXXX, [1.0]]], "type": "distribution", "host": null, "device": null, "tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python39_X.X.X"], "interval": 10}, {"metric": "tests.integration.count", "points": [[XXXX, [21.0]]], "type": "distribution", "host": null, "device": null, "tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python39_X.X.X"], "interval": 10}]} +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": [ [ @@ -1201,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": "aws.lambda", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1214,14 +1472,15 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "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 x86_64)", + "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.agent_psr": 1, "_dd.measured": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 @@ -1242,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -1258,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, @@ -1269,18 +1528,21 @@ 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...", "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.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -1290,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, @@ -1319,8 +1581,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1331,11 +1593,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -1343,18 +1607,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -1366,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {"series": [{"metric": "hello.dog", "points": [[XXXX, [1.0]]], "type": "distribution", "host": null, "device": null, "tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python39_X.X.X"], "interval": 10}, {"metric": "tests.integration.count", "points": [[XXXX, [21.0]]], "type": "distribution", "host": null, "device": null, "tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python39_X.X.X"], "interval": 10}]} +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": [ [ @@ -1374,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": "aws.lambda", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1387,14 +1653,15 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "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 x86_64)", + "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.agent_psr": 1, "_dd.measured": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 @@ -1415,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} -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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {} +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": [ [ @@ -1441,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", @@ -1454,12 +1722,14 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "_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.agent_psr": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 }, @@ -1469,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, @@ -1488,7 +1758,8 @@ 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", + "span.kind": "server", + "http.url": "https://xxxx.execute-api.eu-west-1.amazonaws.com/", "http.status_code": "200" }, "metrics": { @@ -1500,8 +1771,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": "requests.request", + "service": "requests", + "resource": "GET /", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1512,11 +1783,13 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "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.measured": 1, + "_dd.top_level": 1 }, "type": "http" }, @@ -1524,18 +1797,20 @@ HTTP GET https://www.datadoghq.com/ Headers: ["Accept-Encoding:gzip, deflate", " "trace_id": "XXXX", "parent_id": "XXXX", "span_id": "XXXX", - "service": "aws.lambda", - "resource": "requests.request", + "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" }, @@ -1547,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:dd=s:1;t.dm:-0", "x-datadog-parent-id:XXXX", "x-datadog-sampling-priority:1", "x-datadog-tags:_dd.p.dm=-0", "x-datadog-trace-id:XXXX"] Data: {"series": [{"metric": "hello.dog", "points": [[XXXX, [1.0]]], "type": "distribution", "host": null, "device": null, "tags": ["team:serverless", "role:hello", "dd_lambda_layer:datadog-python39_X.X.X"], "interval": 10}, {"metric": "tests.integration.count", "points": [[XXXX, [21.0]]], "type": "distribution", "host": null, "device": null, "tags": ["test:integration", "role:hello", "dd_lambda_layer:datadog-python39_X.X.X"], "interval": 10}]} +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": [ [ @@ -1555,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": "aws.lambda", - "resource": "requests.request", + "service": "requests", + "resource": "POST /api/v1/distribution_points", "name": "requests.request", "error": 0, "start": "XXXX", @@ -1568,14 +1843,15 @@ HTTP POST https://api.datadoghq.com/api/v1/distribution_points Headers: ["Accept "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 x86_64)", + "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.agent_psr": 1, "_dd.measured": 1, "_dd.top_level": 1, "_sampling_priority_v1": 1 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 56636deca..d75b5f43a 100644 --- a/tests/test_cold_start.py +++ b/tests/test_cold_start.py @@ -1,11 +1,45 @@ +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): + cold_start._cold_start = True + cold_start._proactive_initialization = False + cold_start._lambda_container_initialized = False + fifteen_seconds_ago = time.time_ns() - 15_000_000_000 + cold_start.set_cold_start(fifteen_seconds_ago) + self.assertTrue(cold_start.is_proactive_init()) + self.assertTrue(cold_start.is_new_sandbox()) + self.assertFalse(cold_start.is_cold_start()) + self.assertEqual( + cold_start.get_proactive_init_tag(), "proactive_initialization:true" + ) + self.assertEqual(cold_start.get_cold_start_tag(), "cold_start:false") + + def test_cold_start(self): + cold_start._cold_start = True + cold_start._proactive_initialization = False + cold_start._lambda_container_initialized = False + one_second_ago = time.time_ns() - 1_000_000_000 + cold_start.set_cold_start(one_second_ago) + self.assertFalse(cold_start.is_proactive_init()) + self.assertTrue(cold_start.is_new_sandbox()) + self.assertTrue(cold_start.is_cold_start()) + self.assertEqual( + cold_start.get_proactive_init_tag(), "proactive_initialization:false" + ) + self.assertEqual(cold_start.get_cold_start_tag(), "cold_start:true") + def test_initialize_cold_start_tracing(self): cold_start._cold_start = True cold_start.initialize_cold_start_tracing() # testing double wrapping @@ -205,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..9c5da63a2 --- /dev/null +++ b/tests/test_config.py @@ -0,0 +1,262 @@ +import importlib +import sys + +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_config_import_does_not_import_ddtrace(monkeypatch): + import datadog_lambda + + with monkeypatch.context() as mp: + for name in list(sys.modules): + if name == "ddtrace" or name.startswith("ddtrace."): + mp.delitem(sys.modules, name, raising=False) + + class _BlockDdtrace(importlib.abc.MetaPathFinder): + def find_spec(self, fullname, path=None, target=None): + if fullname == "ddtrace" or fullname.startswith("ddtrace."): + raise ImportError("ddtrace must not be imported during this test") + return None + + blocker = _BlockDdtrace() + mp.setattr(sys, "meta_path", [blocker] + sys.meta_path, raising=False) + + mp.delattr(datadog_lambda, "config", raising=False) + mp.delitem(sys.modules, "datadog_lambda.config", raising=False) + importlib.invalidate_caches() + importlib.import_module("datadog_lambda.config") + + +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_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_as_bool("DD_APPSEC_ENABLED", "appsec_enabled", default=False), + *_test_as_bool("DD_APPSEC_SCA_ENABLED", "sca_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), +) + + +@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 67622afe7..574bb331a 100644 --- a/tests/test_tag_object.py +++ b/tests/test_tag_object.py @@ -19,16 +19,71 @@ def test_tag_object(self): tag_object(spanMock, "function.request", payload) spanMock.set_tag.assert_has_calls( [ - call("function.request.vals.0.thingOne", 1), - call("function.request.vals.1.thingTwo", 2), + call("function.request.vals.0.thingOne", "1"), + call("function.request.vals.1.thingTwo", "2"), call("function.request.hello", "world"), call("function.request.anotherThing.blah", None), call("function.request.anotherThing.foo", "bar"), - call("function.request.anotherThing.nice", True), + call("function.request.anotherThing.nice", "True"), + ], + True, + ) + + @patch("datadog_lambda.config.Config.capture_payload_max_depth", 2) + def test_tag_object_max_depth(self): + payload = { + "hello": "world", + "level1": { + "level2_dict": {"level3": 3}, + "level2_list": [None, True, "nice", {"l3": "v3"}], + "level2_bool": True, + "level2_int": 2, + }, + "vals": [{"thingOne": 1}, {"thingTwo": 2}], + } + spanMock = MagicMock() + + tag_object(spanMock, "function.request", payload) + spanMock.set_tag.assert_has_calls( + [ + call("function.request.vals.0", "{'thingOne': 1}"), + call("function.request.vals.1", "{'thingTwo': 2}"), + call("function.request.hello", "world"), + call("function.request.level1.level2_dict", "{'level3': 3}"), + call( + "function.request.level1.level2_list", + "[None, True, 'nice', {'l3': 'v3'}]", + ), + call("function.request.level1.level2_bool", "True"), + call("function.request.level1.level2_int", "2"), + ], + True, + ) + + @patch("datadog_lambda.config.Config.capture_payload_max_depth", 0) + def test_tag_object_max_depth_0(self): + payload = { + "hello": "world", + "level1": { + "level2_dict": {"level3": 3}, + "level2_list": [None, True, "nice", {"l3": "v3"}], + "level2_bool": True, + "level2_int": 2, + }, + "vals": [{"thingOne": 1}, {"thingTwo": 2}], + } + spanMock = MagicMock() + + tag_object(spanMock, "function.request", payload) + spanMock.set_tag.assert_has_calls( + [ + call( + "function.request", + "{'hello': 'world', 'level1': {'level2_dict': {'level3': 3}, 'level2_list': [None, True, 'nice', {'l3': 'v3'}], 'level2_bool': True, 'level2_int': 2}, 'vals': [{'thingOne': 1}, {'thingTwo': 2}]}", + ), ], True, ) - self.assertEqual(1, 1) def test_redacted_tag_object(self): payload = { @@ -40,12 +95,12 @@ def test_redacted_tag_object(self): tag_object(spanMock, "function.request", payload) spanMock.set_tag.assert_has_calls( [ - call("function.request.vals.0.thingOne", 1), - call("function.request.vals.1.thingTwo", 2), + call("function.request.vals.0.thingOne", "1"), + call("function.request.vals.1.thingTwo", "2"), call("function.request.authorization", "redacted"), call("function.request.anotherThing.blah", None), call("function.request.anotherThing.password", "redacted"), - call("function.request.anotherThing.nice", True), + call("function.request.anotherThing.nice", "True"), ], True, ) @@ -62,7 +117,7 @@ def test_json_tag_object(self): call("function.request.token", "redacted"), call("function.request.jsonString.stringifyThisJson.0.here", "is"), call("function.request.jsonString.stringifyThisJson.0.an", "object"), - call("function.request.jsonString.stringifyThisJson.0.number", 1), + call("function.request.jsonString.stringifyThisJson.0.number", "1"), ], True, ) @@ -79,18 +134,59 @@ def test_unicode_tag_object(self): call("function.request.token", "redacted"), call("function.request.jsonString.stringifyThisJson.0.here", "is"), call("function.request.jsonString.stringifyThisJson.0.an", "object"), - call("function.request.jsonString.stringifyThisJson.0.number", 1), + call("function.request.jsonString.stringifyThisJson.0.number", "1"), ], True, ) def test_decimal_tag_object(self): - payload = {"myValue": Decimal(500.50)} + payload = {"myValue": Decimal(500.5)} spanMock = MagicMock() tag_object(spanMock, "function.request", payload) spanMock.set_tag.assert_has_calls( [ - call("function.request.myValue", Decimal(500.50)), + call("function.request.myValue", "500.5"), + ], + True, + ) + + class CustomResponse(object): + """ + For example, chalice.app.Response class + """ + + def __init__(self, body, headers=None, status_code: int = 200): + self.body = body + if headers is None: + headers = {} + self.headers = headers + self.status_code = status_code + + def __str__(self): + return str(self.body) + + class ResponseHasToDict(CustomResponse): + def to_dict(self): + return self.headers + + def test_custom_response(self): + payload = self.CustomResponse({"hello": "world"}, {"key1": "val1"}, 200) + spanMock = MagicMock() + tag_object(spanMock, "function.response", payload) + spanMock.set_tag.assert_has_calls( + [ + call("function.response", "{'hello': 'world'}"), + ], + True, + ) + + def test_custom_response_to_dict(self): + payload = self.ResponseHasToDict({"hello": "world"}, {"key1": "val1"}, 200) + spanMock = MagicMock() + tag_object(spanMock, "function.response", payload) + spanMock.set_tag.assert_has_calls( + [ + call("function.response.key1", "val1"), ], True, ) 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 e19c66aa4..0fddd52ba 100644 --- a/tests/test_tracing.py +++ b/tests/test_tracing.py @@ -1,21 +1,31 @@ -import unittest +import base64 +import copy +import functools import json +import traceback +import pytest import os +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, TraceHeader, + TraceContextSource, 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, @@ -27,10 +37,19 @@ _convert_xray_trace_id, _convert_xray_entity_id, _convert_xray_sampling, - InferredSpanInfo, - extract_context_from_eventbridge_event, + 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" @@ -43,58 +62,234 @@ event_samples = "tests/event_samples/" -class ClientContext(object): - def __init__(self, custom=None): - self.custom = custom +def with_trace_propagation_style(style): + style_list = list(style.split(",")) + + def _wrapper(fn): + @functools.wraps(fn) + def _wrap(*args, **kwargs): + from ddtrace.propagation.http import config + + orig_extract = config._propagation_style_extract + orig_inject = config._propagation_style_inject + config._propagation_style_extract = style_list + config._propagation_style_inject = style_list + try: + return fn(*args, **kwargs) + finally: + config._propagation_style_extract = orig_extract + config._propagation_style_inject = orig_inject + + return _wrap + + 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() -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 + 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") def test_without_datadog_trace_headers(self): lambda_ctx = get_mock_context() ctx, source, event_source = extract_dd_trace_context({}, lambda_ctx) self.assertEqual(source, "xray") - self.assertDictEqual( + self.assertEqual( ctx, - { - "trace-id": fake_xray_header_value_root_decimal, - "parent-id": fake_xray_header_value_parent_decimal, - "sampling-priority": "2", - }, + Context( + trace_id=int(fake_xray_header_value_root_decimal), + span_id=int(fake_xray_header_value_parent_decimal), + sampling_priority=2, + ), ) self.assertDictEqual( get_dd_trace_context(), @@ -106,17 +301,18 @@ def test_without_datadog_trace_headers(self): {}, ) + @with_trace_propagation_style("datadog") def test_with_non_object_event(self): lambda_ctx = get_mock_context() ctx, source, event_source = extract_dd_trace_context(b"", lambda_ctx) self.assertEqual(source, "xray") - self.assertDictEqual( + self.assertEqual( ctx, - { - "trace-id": fake_xray_header_value_root_decimal, - "parent-id": fake_xray_header_value_parent_decimal, - "sampling-priority": "2", - }, + Context( + trace_id=int(fake_xray_header_value_root_decimal), + span_id=int(fake_xray_header_value_parent_decimal), + sampling_priority=2, + ), ) self.assertDictEqual( get_dd_trace_context(), @@ -128,20 +324,21 @@ def test_with_non_object_event(self): {}, ) + @with_trace_propagation_style("datadog") 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") - self.assertDictEqual( + self.assertEqual( ctx, - { - "trace-id": fake_xray_header_value_root_decimal, - "parent-id": fake_xray_header_value_parent_decimal, - "sampling-priority": "2", - }, + Context( + trace_id=int(fake_xray_header_value_root_decimal), + span_id=int(fake_xray_header_value_parent_decimal), + sampling_priority=2, + ), ) self.assertDictEqual( get_dd_trace_context(), @@ -152,38 +349,51 @@ def test_with_incomplete_datadog_trace_headers(self): }, ) - 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") - self.assertDictEqual( - ctx, - {"trace-id": "123", "parent-id": "321", "sampling-priority": "1"}, - ) - self.assertDictEqual( - get_dd_trace_context(), - { - TraceHeader.TRACE_ID: "123", - TraceHeader.PARENT_ID: fake_xray_header_value_parent_decimal, - TraceHeader.SAMPLING_PRIORITY: "1", - }, - ) + expected_context = propagator.extract(headers) + self.assertEqual(ctx, expected_context) 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, - {"trace-id": "123", "parent-id": "321", "sampling-priority": "1"}, + 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): + 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") def test_with_extractor_function(self): def extractor_foo(event, context): foo = event.get("foo", {}) @@ -207,13 +417,13 @@ def extractor_foo(event, context): extractor=extractor_foo, ) self.assertEqual(ctx_source, "event") - self.assertDictEqual( + self.assertEqual( ctx, - { - "trace-id": "123", - "parent-id": "321", - "sampling-priority": "1", - }, + Context( + trace_id=123, + span_id=321, + sampling_priority=1, + ), ) self.assertDictEqual( get_dd_trace_context(), @@ -224,6 +434,7 @@ def extractor_foo(event, context): }, ) + @with_trace_propagation_style("datadog") def test_graceful_fail_of_extractor_function(self): def extractor_raiser(event, context): raise Exception("kreator") @@ -241,13 +452,13 @@ def extractor_raiser(event, context): extractor=extractor_raiser, ) self.assertEqual(ctx_source, "xray") - self.assertDictEqual( + self.assertEqual( ctx, - { - "trace-id": fake_xray_header_value_root_decimal, - "parent-id": fake_xray_header_value_parent_decimal, - "sampling-priority": "2", - }, + Context( + trace_id=int(fake_xray_header_value_root_decimal), + span_id=int(fake_xray_header_value_parent_decimal), + sampling_priority=2, + ), ) self.assertDictEqual( get_dd_trace_context(), @@ -258,8 +469,13 @@ 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": [ { @@ -274,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", } }, @@ -291,118 +501,104 @@ 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") - self.assertDictEqual( - ctx, - { - "trace-id": "123", - "parent-id": "321", - "sampling-priority": "1", - }, - ) - 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, - {"trace-id": "123", "parent-id": "321", "sampling-priority": "1"}, - ) + self.common_tests_with_trace_context_extraction_injection(headers, sqs_event) - 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", + @with_trace_propagation_style("tracecontext") + def test_with_sqs_distributed_w3c_trace_data(self): + headers = { + "traceparent": "00-0000000000000000000000000000007b-0000000000000141-01", + "tracestate": "dd=s:2;t.dm:-0,rojo=00f067aa0ba902b7,congo=t61rcWkgMzE", + } + sqs_event = { + "Records": [ + { + "messageId": "059f36b4-87a3-44ab-83d2-661975830a7d", + "receiptHandle": "AQEBwJnKyrHigUMZj6rYigCgxlaS3SLy0a...", + "body": "Test message.", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "1545082649183", + "SenderId": "AIDAIENQZJOLO23YVJ4VO", + "ApproximateFirstReceiveTimestamp": "1545082649185", + }, + "messageAttributes": { + "_datadog": { + "stringValue": json.dumps(headers), + "dataType": "String", + } + }, + "md5OfBody": "e4e68fb7bd0e697a0ae8f1bb342846b3", + "eventSource": "aws:sqs", + "eventSourceARN": "arn:aws:sqs:us-east-2:123456789012:my-queue", + "awsRegion": "us-east-2", } - } - ) - ctx, source, event_source = extract_dd_trace_context({}, lambda_ctx) - self.assertEqual(source, "event") - self.assertDictEqual( - ctx, - { - "trace-id": "666", - "parent-id": "777", - "sampling-priority": "1", - }, - ) - self.assertDictEqual( - get_dd_trace_context(), - { - TraceHeader.TRACE_ID: "666", - TraceHeader.PARENT_ID: fake_xray_header_value_parent_decimal, - TraceHeader.SAMPLING_PRIORITY: "1", - }, + ] + } + 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): + 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 ) - 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, - {"trace-id": "666", "parent-id": "777", "sampling-priority": "1"}, + + @with_trace_propagation_style("tracecontext") + def test_with_legacy_client_context_w3c_trace_data(self): + 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") - self.assertDictEqual( - ctx, - { - "trace-id": "666", - "parent-id": "777", - "sampling-priority": "1", - }, - ) - self.assertDictEqual( - get_dd_trace_context(), - { - TraceHeader.TRACE_ID: "666", - TraceHeader.PARENT_ID: fake_xray_header_value_parent_decimal, - TraceHeader.SAMPLING_PRIORITY: "1", - }, + 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 ) - 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, - {"trace-id": "666", "parent-id": "777", "sampling-priority": "1"}, + + @with_trace_propagation_style("tracecontext") + def test_with_new_client_context_w3c_trace_data(self): + 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 = { @@ -425,80 +621,471 @@ def test_with_complete_datadog_trace_headers_with_trigger_tags(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() + 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, _ = extract_dd_trace_context(request_header_event, lambda_ctx) + expected_context = Context( + trace_id=12345, + span_id=67890, + sampling_priority=1, + ) + + self.assertEqual(ctx, expected_context) + 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): self.assertEqual( - _convert_xray_trace_id("00000000e1be46a994272793"), "7043144561403045779" + _convert_xray_trace_id("00000000e1be46a994272793"), 7043144561403045779 ) self.assertEqual( - _convert_xray_trace_id("bd862e3fe1be46a994272793"), "7043144561403045779" + _convert_xray_trace_id("bd862e3fe1be46a994272793"), 7043144561403045779 ) self.assertEqual( _convert_xray_trace_id("ffffffffffffffffffffffff"), - "9223372036854775807", # 0x7FFFFFFFFFFFFFFF + 9223372036854775807, # 0x7FFFFFFFFFFFFFFF ) def test_convert_xray_entity_id(self): self.assertEqual( - _convert_xray_entity_id("53995c3f42cd8ad8"), "6023947403358210776" + _convert_xray_entity_id("53995c3f42cd8ad8"), 6023947403358210776 ) self.assertEqual( - _convert_xray_entity_id("1000000000000000"), "1152921504606846976" + _convert_xray_entity_id("1000000000000000"), 1152921504606846976 ) self.assertEqual( - _convert_xray_entity_id("ffffffffffffffff"), "18446744073709551615" + _convert_xray_entity_id("ffffffffffffffff"), 18446744073709551615 ) def test_convert_xray_sampling(self): - self.assertEqual(_convert_xray_sampling(True), str(SamplingPriority.USER_KEEP)) + self.assertEqual(_convert_xray_sampling(True), SamplingPriority.USER_KEEP) - self.assertEqual( - _convert_xray_sampling(False), str(SamplingPriority.USER_REJECT) - ) + self.assertEqual(_convert_xray_sampling(False), SamplingPriority.USER_REJECT) class TestLogsInjection(unittest.TestCase): def setUp(self): - patcher = patch("datadog_lambda.tracing.get_dd_trace_context") + patcher = patch("datadog_lambda.tracing.get_dd_trace_context_obj") self.mock_get_dd_trace_context = patcher.start() - self.mock_get_dd_trace_context.return_value = { - TraceHeader.TRACE_ID: "123", - TraceHeader.PARENT_ID: "456", - } + self.mock_get_dd_trace_context.return_value = Context( + trace_id=int(fake_xray_header_value_root_decimal), + span_id=int(fake_xray_header_value_parent_decimal), + sampling_priority=1, + ) 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() - self.assertEqual(span.trace_id, 123) - self.assertEqual(span.span_id, 456) + self.assertEqual(span.trace_id, int(fake_xray_header_value_root_decimal)) + self.assertEqual(span.parent_id, int(fake_xray_header_value_parent_decimal)) + span.finish() + + def test_set_correlation_ids_handle_empty_trace_context(self): + # neither x-ray or ddtrace is used. no tracing context at all. + self.mock_get_dd_trace_context.return_value = Context() + # no exception thrown + set_correlation_ids() + span = tracer.current_span() + self.assertIsNone(span) class TestFunctionSpanTags(unittest.TestCase): def test_function(self): ctx = get_mock_context() - span = create_function_execution_span(ctx, "", False, {"source": ""}, False, {}) + 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=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" ctx = get_mock_context( invoked_function_arn=function_arn + ":" + function_version ) - span = create_function_execution_span(ctx, "", False, {"source": ""}, False, {}) + 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={}, + ) self.assertEqual(span.get_tag("function_arn"), function_arn) self.assertEqual(span.get_tag("function_version"), function_version) self.assertEqual(span.get_tag("resource_names"), "Function") @@ -507,7 +1094,15 @@ def test_function_with_version(self): 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, {"source": ""}, False, {}) + 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={}, + ) self.assertEqual(span.get_tag("function_arn"), function_arn) self.assertEqual(span.get_tag("function_version"), function_alias) self.assertEqual(span.get_tag("resource_names"), "Function") @@ -516,12 +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, - {"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") @@ -530,27 +1126,69 @@ 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) - patcher = patch("ddtrace.tracer.context_provider.activate") + patcher = patch("datadog_lambda.tracing.tracer.context_provider.activate") 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): @@ -580,786 +1218,1204 @@ def test_mixed_parent_context_when_merging(self): self.mock_activate.assert_called() self.mock_activate.assert_has_calls([call(expected_context)]) + def test_set_dd_trace_py_root_no_span_id(self): + os.environ["_X_AMZN_TRACE_ID"] = "Root=1-5e272390-8c398be037738dc042009320" + + lambda_ctx = get_mock_context() + ctx, source, event_type = extract_dd_trace_context( + { + "headers": { + TraceHeader.TRACE_ID: "123", + TraceHeader.PARENT_ID: "321", + TraceHeader.SAMPLING_PRIORITY: "1", + } + }, + lambda_ctx, + ) + set_dd_trace_py_root(TraceContextSource.EVENT, True) + + expected_context = Context( + trace_id=123, # Trace Id from incomming context + span_id=321, # Span Id from incoming context + sampling_priority=1, # Sampling priority from incomming context + ) + self.mock_activate.assert_called() + self.mock_activate.assert_has_calls([call(expected_context)]) + + 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 TestAuthorizerInferredSpans(unittest.TestCase): +class TestServiceMapping(unittest.TestCase): def setUp(self): - patcher = patch("ddtrace.Span.finish", autospec=True) - self.mock_span_stop = patcher.start() - self.addCleanup(patcher.stop) + self.service_mapping = {} + + def get_service_mapping(self): + return global_service_mapping - 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 + def set_service_mapping(self, new_service_mapping): + global_service_mapping.clear() + global_service_mapping.update(new_service_mapping) + + def test_create_service_mapping_invalid_input(self): + # Test case where the input is a string without a colon to split on + val = "api1" + self.assertEqual(create_service_mapping(val), {}) + + # Test case where the input is an empty string + val = "" + self.assertEqual(create_service_mapping(val), {}) + + # Test case where the key and value are identical + val = "api1:api1" + self.assertEqual(create_service_mapping(val), {}) + + # Test case where the key or value is missing + val = ":api1" + self.assertEqual(create_service_mapping(val), {}) + val = "api1:" + self.assertEqual(create_service_mapping(val), {}) + + def test_create_service_mapping(self): + val = "api1:service1,api2:service2" + expected_output = {"api1": "service1", "api2": "service2"} + self.assertEqual(create_service_mapping(val), expected_output) + + def test_get_service_mapping(self): + os.environ["DD_SERVICE_MAPPING"] = "api1:service1,api2:service2" + expected_output = {"api1": "service1", "api2": "service2"} + self.set_service_mapping( + create_service_mapping(os.environ["DD_SERVICE_MAPPING"]) ) - span = self._authorizer_span_testing_items(event_sample_source, finish_time) - self._basic_common_checks(span, "aws.apigateway.rest") + self.assertEqual(self.get_service_mapping(), expected_output) + del os.environ["DD_SERVICE_MAPPING"] - 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_set_service_mapping(self): + new_service_mapping = {"api3": "service3", "api4": "service4"} + self.set_service_mapping(new_service_mapping) + self.assertEqual(self.get_service_mapping(), new_service_mapping) - 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 + def test_determine_service_name(self): + # Prepare the environment + os.environ["DD_SERVICE_MAPPING"] = "api1:service1,api2:service2" + self.set_service_mapping( + create_service_mapping(os.environ["DD_SERVICE_MAPPING"]) ) - 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") + # Case where specific key is in the service mapping + specific_key = "api1" + self.assertEqual( + determine_service_name( + self.get_service_mapping(), specific_key, "lambda_url", "default" + ), + "service1", + ) - 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 + # Case where specific key is not in the service mapping, but generic key is + specific_key = "api3" + self.assertEqual( + determine_service_name( + self.get_service_mapping(), specific_key, "api2", "default" + ), + "service2", ) - span = self._authorizer_span_testing_items(event_sample_source, finish_time) - self._basic_common_checks( - span, "aws.apigateway.websocket", "web", "$connect", None + + # Case where neither specific nor generic keys are in the service mapping + specific_key = "api3" + self.assertEqual( + determine_service_name( + self.get_service_mapping(), specific_key, "api3", "default" + ), + "default", ) - 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) + # 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", + ) - 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) + # Test with DD_TRACE_AWS_SERVICE_REPRESENTATION_ENABLED set to 0 + os.environ["DD_TRACE_AWS_SERVICE_REPRESENTATION_ENABLED"] = "0" self.assertEqual( - span.service, - "amddr1rix9.execute-api.eu-west-1.amazonaws.com", + 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( - span.get_tag("http.url"), - "amddr1rix9.execute-api.eu-west-1.amazonaws.com" + route_key, + determine_service_name( + self.get_service_mapping(), "api4", "api4", "extracted", "fallback" + ), + "extracted", ) - self.assertEqual(span.get_tag("endpoint"), route_key) - self.assertEqual(span.get_tag("http.method"), http_method) + + # Test with empty extracted key self.assertEqual( - span.get_tag("resource_names"), - f"{http_method} {route_key}" if http_method else route_key, + determine_service_name( + self.get_service_mapping(), "api4", "api4", " ", "fallback" + ), + "fallback", ) - self.assertEqual(span.get_tag("request_id"), "abc123") + del os.environ["DD_SERVICE_MAPPING"] -class TestInferredSpans(unittest.TestCase): - def test_create_inferred_span_from_api_gateway_event(self): + 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) event_sample_source = "api-gateway" test_file = event_samples + event_sample_source + ".json" with open(test_file, "r") as event: - event = json.load(event) + original_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", - ) - self.assertEqual( - span.get_tag("http.url"), - "70ixmpl4fl.execute-api.us-east-2.amazonaws.com/path/to/resource", - ) - 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" + + span1 = create_inferred_span(original_event, ctx) + self.assertEqual(span1.get_tag("operation_name"), "aws.apigateway.rest") + self.assertEqual(span1.service, "new-name") + + # Testing the second event + event2 = copy.deepcopy(original_event) + event2["requestContext"][ + "domainName" + ] = "different.execute-api.us-east-2.amazonaws.com" + span2 = create_inferred_span(event2, ctx) + self.assertEqual(span2.get_tag("operation_name"), "aws.apigateway.rest") + self.assertEqual(span2.service, "new-name") + + def test_remaps_specific_inferred_span_service_names_from_api_gateway_event( + self, + ): + new_service_mapping = {"1234567890": "new-name"} + self.set_service_mapping(new_service_mapping) + event_sample_source = "api-gateway" test_file = event_samples + event_sample_source + ".json" with open(test_file, "r") as event: - event = json.load(event) + original_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", - ) + + span1 = create_inferred_span(original_event, ctx) + self.assertEqual(span1.get_tag("operation_name"), "aws.apigateway.rest") + self.assertEqual(span1.service, "new-name") + + # Testing the second event + event2 = copy.deepcopy(original_event) + event2["requestContext"]["apiId"] = "different" + span2 = create_inferred_span(event2, ctx) + self.assertEqual(span2.get_tag("operation_name"), "aws.apigateway.rest") self.assertEqual( - span.get_tag("http.url"), - "lgxbo6a518.execute-api.eu-west-1.amazonaws.com/http/get", + span2.service, "70ixmpl4fl.execute-api.us-east-2.amazonaws.com" ) - 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" + + def test_remaps_specific_inferred_span_service_names_from_api_gateway_websocket_event( + self, + ): + self.set_service_mapping({"p62c47itsb": "new-name"}) + 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) + original_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", - ) + + span1 = create_inferred_span(original_event, ctx) + self.assertEqual(span1.get_tag("operation_name"), "aws.apigateway.websocket") + self.assertEqual(span1.service, "new-name") + + # Testing the second event + event2 = copy.deepcopy(original_event) + event2["requestContext"]["apiId"] = "different" + span2 = create_inferred_span(event2, ctx) + self.assertEqual(span2.get_tag("operation_name"), "aws.apigateway.websocket") self.assertEqual( - span.get_tag("http.url"), - "lgxbo6a518.execute-api.eu-west-1.amazonaws.com/http/get", + span2.service, "p62c47itsb.execute-api.eu-west-1.amazonaws.com" ) - 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): + + def test_remaps_specific_inferred_span_service_names_from_api_gateway_http_event( + self, + ): + self.set_service_mapping({"x02yirxc7a": "new-name"}) event_sample_source = "http-api" test_file = event_samples + event_sample_source + ".json" with open(test_file, "r") as event: - event = json.load(event) + original_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", - ) + + span1 = create_inferred_span(original_event, ctx) + self.assertEqual(span1.get_tag("operation_name"), "aws.httpapi") + self.assertEqual(span1.service, "new-name") + + # Testing the second event + event2 = copy.deepcopy(original_event) + event2["requestContext"]["apiId"] = "different" + span2 = create_inferred_span(event2, ctx) + self.assertEqual(span2.get_tag("operation_name"), "aws.httpapi") self.assertEqual( - span.get_tag("http.url"), - "x02yirxc7a.execute-api.eu-west-1.amazonaws.com/httpapi/get", + span2.service, "x02yirxc7a.execute-api.eu-west-1.amazonaws.com" ) - 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" + + def test_remaps_all_inferred_span_service_names_from_lambda_url_event(self): + self.set_service_mapping({"lambda_url": "new-name"}) + event_sample_source = "lambda-url" test_file = event_samples + event_sample_source + ".json" with open(test_file, "r") as event: - event = json.load(event) + original_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" + + span1 = create_inferred_span(original_event, ctx) + self.assertEqual(span1.get_tag("operation_name"), "aws.lambda.url") + self.assertEqual(span1.service, "new-name") + + # Testing the second event + event2 = copy.deepcopy(original_event) + event2["requestContext"][ + "domainName" + ] = "different.lambda-url.eu-south-1.amazonaws.com" + span2 = create_inferred_span(event2, ctx) + self.assertEqual(span2.get_tag("operation_name"), "aws.lambda.url") + self.assertEqual(span2.service, "new-name") + + def test_remaps_specific_inferred_span_service_names_from_lambda_url_event( + self, + ): + self.set_service_mapping({"a8hyhsshac": "new-name"}) + event_sample_source = "lambda-url" test_file = event_samples + event_sample_source + ".json" with open(test_file, "r") as event: - event = json.load(event) + original_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", - ) + + span1 = create_inferred_span(original_event, ctx) + self.assertEqual(span1.get_tag("operation_name"), "aws.lambda.url") + self.assertEqual(span1.service, "new-name") + + # Testing the second event + event2 = copy.deepcopy(original_event) + event2["requestContext"]["apiId"] = "different" + span2 = create_inferred_span(event2, ctx) + self.assertEqual(span2.get_tag("operation_name"), "aws.lambda.url") self.assertEqual( - span.get_tag("http.url"), - "p62c47itsb.execute-api.eu-west-1.amazonaws.com$connect", + span2.service, "a8hyhsshac.lambda-url.eu-south-1.amazonaws.com" ) - 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" + + def test_remaps_all_inferred_span_service_names_from_sqs_event(self): + self.set_service_mapping({"lambda_sqs": "new-name"}) + 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) + original_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" + + span1 = create_inferred_span(original_event, ctx) + self.assertEqual(span1.get_tag("operation_name"), "aws.sqs") + self.assertEqual(span1.service, "new-name") + + # Testing the second event + event2 = copy.deepcopy(original_event) + event2["Records"][0][ + "eventSourceARN" + ] = "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, "new-name") + + def test_remaps_specific_inferred_span_service_names_from_sqs_event(self): + self.set_service_mapping({"InferredSpansQueueNode": "new-name"}) + 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) + original_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") - 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" + span1 = create_inferred_span(original_event, ctx) + self.assertEqual(span1.get_tag("operation_name"), "aws.sqs") + self.assertEqual(span1.service, "new-name") + + # Testing the second event + event2 = copy.deepcopy(original_event) + event2["Records"][0][ + "eventSourceARN" + ] = "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, "different-sqs-url") + + def test_remaps_all_inferred_span_service_names_from_sns_event(self): + self.set_service_mapping({"lambda_sns": "new-name"}) + 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) + original_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") - - 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" + + span1 = create_inferred_span(original_event, ctx) + self.assertEqual(span1.get_tag("operation_name"), "aws.sns") + self.assertEqual(span1.service, "new-name") + + # Testing the second event + event2 = copy.deepcopy(original_event) + event2["Records"][0]["Sns"][ + "TopicArn" + ] = "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, "new-name") + + def test_remaps_specific_inferred_span_service_names_from_sns_event(self): + self.set_service_mapping({"serverlessTracingTopicPy": "new-name"}) + 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) + original_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") - def test_create_inferred_span_from_kinesis_event(self): + span1 = create_inferred_span(original_event, ctx) + self.assertEqual(span1.get_tag("operation_name"), "aws.sns") + self.assertEqual(span1.service, "new-name") + + # Testing the second event + event2 = copy.deepcopy(original_event) + event2["Records"][0]["Sns"][ + "TopicArn" + ] = "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, "different-sns-topic") + + def test_remaps_all_inferred_span_service_names_from_kinesis_event(self): + self.set_service_mapping({"lambda_kinesis": "new-name"}) event_sample_source = "kinesis" test_file = event_samples + event_sample_source + ".json" with open(test_file, "r") as event: - event = json.load(event) + original_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", - ) - 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", - ) - 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" + + span1 = create_inferred_span(original_event, ctx) + self.assertEqual(span1.get_tag("operation_name"), "aws.kinesis") + self.assertEqual(span1.service, "new-name") + + # Testing the second event + event2 = copy.deepcopy(original_event) + event2["Records"][0][ + "eventSourceARN" + ] = "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, "new-name") + + def test_remaps_specific_inferred_span_service_names_from_kinesis_event(self): + self.set_service_mapping({"Different_EXAMPLE": "new-name"}) + event_sample_source = "kinesis" test_file = event_samples + event_sample_source + ".json" with open(test_file, "r") as event: - event = json.load(event) + original_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", - ) - 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"), - "ExampleTableWithStream", - ) - 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): + + span1 = create_inferred_span(original_event, ctx) + self.assertEqual(span1.get_tag("operation_name"), "aws.kinesis") + self.assertEqual(span1.service, "kinesisStream") + + # Testing the second event + event2 = copy.deepcopy(original_event) + event2["Records"][0][ + "eventSourceARN" + ] = "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, "DifferentKinesisStream") + + def test_remaps_all_inferred_span_service_names_from_s3_event(self): + self.set_service_mapping({"lambda_s3": "new-name"}) event_sample_source = "s3" test_file = event_samples + event_sample_source + ".json" with open(test_file, "r") as event: - event = json.load(event) + original_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( - 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"), - "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.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" + span1 = create_inferred_span(original_event, ctx) + self.assertEqual(span1.get_tag("operation_name"), "aws.s3") + self.assertEqual(span1.service, "new-name") + + # Testing the second event + event2 = copy.deepcopy(original_event) + event2["Records"][0]["s3"]["bucket"][ + "arn" + ] = "arn:aws:s3:::different-example-bucket" + span2 = create_inferred_span(event2, ctx) + self.assertEqual(span2.get_tag("operation_name"), "aws.s3") + self.assertEqual(span2.service, "new-name") + + def test_remaps_specific_inferred_span_service_names_from_s3_event(self): + self.set_service_mapping({"example-bucket": "new-name"}) + event_sample_source = "s3" test_file = event_samples + event_sample_source + ".json" with open(test_file, "r") as event: - event = json.load(event) + original_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( - 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"), - "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_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() - trace, parent, sampling = extract_context_from_eventbridge_event(event, ctx) - self.assertEqual(trace, "12345") - self.assertEqual(parent, "67890"), - self.assertEqual(sampling, "2") + span1 = create_inferred_span(original_event, ctx) + self.assertEqual(span1.get_tag("operation_name"), "aws.s3") + self.assertEqual(span1.service, "new-name") - 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["parent-id"], "67890") + # Testing the second event + event2 = copy.deepcopy(original_event) + 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, "different-example-bucket") - def test_extract_context_from_sqs_event_with_string_msg_attr(self): - event_sample_source = "sqs-string-msg-attribute" + def test_remaps_all_inferred_span_service_names_from_dynamodb_event(self): + self.set_service_mapping({"lambda_dynamodb": "new-name"}) + event_sample_source = "dynamodb" test_file = event_samples + event_sample_source + ".json" with open(test_file, "r") as event: - event = json.load(event) + original_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["parent-id"], "7431398482019833808") - self.assertEqual(context["sampling-priority"], "1") + ctx.aws_request_id = "123" - def test_extract_context_from_sqs_batch_event(self): - event_sample_source = "sqs-batch" + span1 = create_inferred_span(original_event, ctx) + self.assertEqual(span1.get_tag("operation_name"), "aws.dynamodb") + self.assertEqual(span1.service, "new-name") + + # Testing the second event + event2 = copy.deepcopy(original_event) + event2["Records"][0][ + "eventSourceARN" + ] = "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, "new-name") + + def test_remaps_specific_inferred_span_service_names_from_dynamodb_event(self): + self.set_service_mapping({"ExampleTableWithStream": "new-name"}) + event_sample_source = "dynamodb" test_file = event_samples + event_sample_source + ".json" with open(test_file, "r") as event: - event = json.load(event) + original_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["parent-id"], "7431398482019833808") - self.assertEqual(context["sampling-priority"], "1") + ctx.aws_request_id = "123" - def test_extract_context_from_sns_event_with_string_msg_attr(self): - event_sample_source = "sns-string-msg-attribute" + span1 = create_inferred_span(original_event, ctx) + self.assertEqual(span1.get_tag("operation_name"), "aws.dynamodb") + self.assertEqual(span1.service, "new-name") + + # Testing the second event + event2 = copy.deepcopy(original_event) + event2["Records"][0][ + "eventSourceARN" + ] = "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, "DifferentExampleTableWithStream") + + def test_remaps_all_inferred_span_service_names_from_eventbridge_event(self): + self.set_service_mapping({"lambda_eventbridge": "new-name"}) + event_sample_source = "eventbridge-custom" test_file = event_samples + event_sample_source + ".json" with open(test_file, "r") as event: - event = json.load(event) + original_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["parent-id"], "6746998015037429512") - self.assertEqual(context["sampling-priority"], "1") + ctx.aws_request_id = "123" - 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["parent-id"], "6746998015037429512") - self.assertEqual(context["sampling-priority"], "1") - - 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["parent-id"], "6746998015037429512") - self.assertEqual(context["sampling-priority"], "1") + span1 = create_inferred_span(original_event, ctx) + self.assertEqual(span1.get_tag("operation_name"), "aws.eventbridge") + self.assertEqual(span1.service, "new-name") - 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["parent-id"], "2876253380018681026") - self.assertEqual(context["sampling-priority"], "1") + # Testing the second event + event2 = copy.deepcopy(original_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, "new-name") - def test_extract_context_from_kinesis_batch_event(self): - event_sample_source = "kinesis-batch" + def test_remaps_specific_inferred_span_service_names_from_eventbridge_event( + self, + ): + self.set_service_mapping({"eventbridge.custom.event.sender": "new-name"}) + 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_source = extract_dd_trace_context(event, ctx) - self.assertEqual(context["trace-id"], "4948377316357291421") - self.assertEqual(context["parent-id"], "2876253380018681026") - self.assertEqual(context["sampling-priority"], "1") + original_event = json.load(event) - 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") - self.assertEqual( - span.service, - "70ixmpl4fl.execute-api.us-east-2.amazonaws.com", - ) - self.assertEqual( - span.get_tag("http.url"), - "70ixmpl4fl.execute-api.us-east-2.amazonaws.com/path/to/resource", - ) - 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") + span1 = create_inferred_span(original_event, ctx) + self.assertEqual(span1.get_tag("operation_name"), "aws.eventbridge") + self.assertEqual(span1.service, "new-name") + + # Testing the second event + event2 = copy.deepcopy(original_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, "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): @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 @@ -1373,7 +2429,7 @@ def test_mark_trace_as_error_for_5xx_responses_getting_400_response_code( 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) + 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 @@ -1381,31 +2437,1016 @@ def test_mark_trace_as_error_for_5xx_responses_sends_error_metric_and_set_error_ mock_submit_errors_metric.assert_called_once() self.assertEqual(1, mock_span.error) - 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, - ) - self.assertEqual(ctx, None) - class TestStepFunctionsTraceContext(unittest.TestCase): def test_deterministic_m5_hash(self): - result = _deterministic_md5_hash("some_testing_random_string") - self.assertEqual("2251275791555400689", result) + 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(3711631873188331089, result) - 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" + 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("8034507082463708833", result) + self.assertEqual(5759173372325510050, result) def test_deterministic_m5_hash__always_leading_with_zero(self): for i in range(100): - result = _deterministic_md5_hash(str(i)) + 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", + } + ) + 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 + ) + 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(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(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(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(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.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(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(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(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(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(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.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(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(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) + + @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", + } + ] + } + + 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", + } + + event = { + "Records": [ + { + "eventSourceARN": "", # Empty SQS ARN + "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.mock_checkpoint.assert_not_called() + + @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" + + _dsm_set_checkpoint(context_json, event_type, arn) + + self.mock_checkpoint.assert_not_called() + + # KINESIS TESTS + + 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() + + 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" + ) + 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( + 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_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" + ) + carrier_get = args[2] + # None indicates no DSM context propagation + self.assertEqual(carrier_get("dd-pathway-ctx-base64"), None) + + 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" + ) + 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_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(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() + + event = { + "Records": [ + { + "eventSourceARN": "", + "kinesis": {"data": encoded_data}, + } + ] + } + + extract_context_from_kinesis_event(event, self.lambda_context) + + 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 bde397c29..512a51f89 100644 --- a/tests/test_wrapper.py +++ b/tests/test_wrapper.py @@ -2,37 +2,31 @@ 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 -from datadog_lambda.wrapper import datadog_lambda_wrapper +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.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): def setUp(self): # Force @datadog_lambda_wrapper to always create a real # (not no-op) wrapper. - datadog_lambda_wrapper._force_wrap = True + patch("ddtrace.internal.remoteconfig.worker.RemoteConfigPoller").start() + patch("ddtrace.internal.writer.AgentWriter.flush_queue").start() + wrapper.datadog_lambda_wrapper._force_wrap = True patcher = patch( "datadog.threadstats.reporters.HttpReporter.flush_distributions" ) @@ -52,39 +46,37 @@ 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() - 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 + 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.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): - @datadog_lambda_wrapper + @wrapper.datadog_lambda_wrapper def lambda_handler(event, context): lambda_metric("test.metric", 100) @@ -93,7 +85,6 @@ def lambda_handler(event, context): lambda_context = get_mock_context() lambda_handler(lambda_event, lambda_context) - self.mock_threadstats_flush_distributions.assert_has_calls( [ call( @@ -112,16 +103,18 @@ def lambda_handler(event, context): ] ) self.mock_extract_dd_trace_context.assert_called_with( - lambda_event, lambda_context, extractor=None, decode_authorizer_context=True + lambda_event, + lambda_context, + extractor=None, + decode_authorizer_context=False, ) 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" - @datadog_lambda_wrapper + @wrapper.datadog_lambda_wrapper def lambda_handler(event, context): lambda_metric("test.metric", 100) @@ -139,13 +132,14 @@ def test_datadog_lambda_wrapper_flush_in_thread(self): metric_module.lambda_stats.stop() metric_module.lambda_stats = ThreadStatsWriter(True) - @datadog_lambda_wrapper + @wrapper.datadog_lambda_wrapper def lambda_handler(event, context): import time 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) @@ -166,7 +160,7 @@ def test_datadog_lambda_wrapper_not_flush_in_thread(self): metric_module.lambda_stats.stop() metric_module.lambda_stats = ThreadStatsWriter(False) - @datadog_lambda_wrapper + @wrapper.datadog_lambda_wrapper def lambda_handler(event, context): import time @@ -186,23 +180,23 @@ 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" - @datadog_lambda_wrapper + @wrapper.datadog_lambda_wrapper def lambda_handler(event, context): lambda_metric("test.metric", 100) lambda_event = {} lambda_handler(lambda_event, get_mock_context()) - self.mock_set_correlation_ids.assert_called() self.mock_inject_correlation_ids.assert_called() del os.environ["DD_LOGS_INJECTION"] def test_invocations_metric(self): - @datadog_lambda_wrapper + @wrapper.datadog_lambda_wrapper def lambda_handler(event, context): lambda_metric("test.metric", 100) @@ -219,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", @@ -232,7 +226,7 @@ def lambda_handler(event, context): ) def test_errors_metric(self): - @datadog_lambda_wrapper + @wrapper.datadog_lambda_wrapper def lambda_handler(event, context): raise RuntimeError() @@ -250,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", @@ -266,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", @@ -283,12 +277,12 @@ 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", } - @datadog_lambda_wrapper + @wrapper.datadog_lambda_wrapper def lambda_handler(event, context): return {"statusCode": 500, "body": "fake response body"} @@ -305,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", @@ -321,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", @@ -334,7 +328,7 @@ def lambda_handler(event, context): ) def test_enhanced_metrics_cold_start_tag(self): - @datadog_lambda_wrapper + @wrapper.datadog_lambda_wrapper def lambda_handler(event, context): lambda_metric("test.metric", 100) @@ -342,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") @@ -357,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", @@ -373,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", @@ -386,7 +380,7 @@ def lambda_handler(event, context): ) def test_enhanced_metrics_latest(self): - @datadog_lambda_wrapper + @wrapper.datadog_lambda_wrapper def lambda_handler(event, context): lambda_metric("test.metric", 100) @@ -408,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", @@ -420,7 +414,7 @@ def lambda_handler(event, context): ) def test_enhanced_metrics_alias(self): - @datadog_lambda_wrapper + @wrapper.datadog_lambda_wrapper def lambda_handler(event, context): lambda_metric("test.metric", 100) @@ -442,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", @@ -453,10 +447,9 @@ 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" - - @datadog_lambda_wrapper + @wrapper.datadog_lambda_wrapper def lambda_handler(event, context): raise RuntimeError() @@ -467,32 +460,32 @@ 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) - @datadog_lambda_wrapper + @wrapper.datadog_lambda_wrapper def lambda_handler(event, context): lambda_metric("test.metric", 100) # Turn off _force_wrap to emulate the nested wrapper scenario, # the second @datadog_lambda_wrapper should actually be no-op. - datadog_lambda_wrapper._force_wrap = False + wrapper.datadog_lambda_wrapper._force_wrap = False - lambda_handler_double_wrapped = datadog_lambda_wrapper(lambda_handler) + lambda_handler_double_wrapped = wrapper.datadog_lambda_wrapper(lambda_handler) lambda_event = {} 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): - @datadog_lambda_wrapper + # 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 @@ -501,15 +494,16 @@ def lambda_handler(event, context): def test_dd_requests_service_name_set(self): os.environ["DD_SERVICE"] = "myAwesomeService" - @datadog_lambda_wrapper + @wrapper.datadog_lambda_wrapper def lambda_handler(event, context): pass 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): - @datadog_lambda_wrapper + @wrapper.datadog_lambda_wrapper def lambda_handler(event, context): return { "principalId": "foo", @@ -529,21 +523,21 @@ def lambda_handler(event, context): lambda_event = {} lambda_context = get_mock_context() - mock_span = MagicMock() - mock_span.context.span_id = "123" - mock_span.context.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 - + 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) - inject_data = json.loads(base64.b64decode(result["context"]["_datadog"])) - 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") + raw_inject_data = result["context"]["_datadog"] + self.assertIsInstance(raw_inject_data, str) + inject_data = json.loads(base64.b64decode(raw_inject_data)) + 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): @@ -551,10 +545,415 @@ def test_different_return_type_no_error(self, MockPrintExc): mock_context = get_mock_context() for test_result in TEST_RESULTS: - @datadog_lambda_wrapper + @wrapper.datadog_lambda_wrapper 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 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