ddapm-test-agent 1.34.0__tar.gz → 1.35.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/.github/workflows/main.yml +15 -7
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/PKG-INFO +30 -2
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/README.md +27 -1
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent/agent.py +391 -1
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent/trace_snapshot.py +29 -4
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent/vcr_proxy.py +27 -7
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent.egg-info/PKG-INFO +30 -2
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent.egg-info/SOURCES.txt +3 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent.egg-info/requires.txt +4 -0
- ddapm_test_agent-1.35.0/releasenotes/notes/named-pipe-ded0ebbbeee2e7fa.yaml +4 -0
- ddapm_test_agent-1.35.0/releasenotes/notes/vcr-custom-providers-map-a43b7e2d62d02015.yaml +6 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/riotfile.py +1 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/setup.py +1 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/test_deps.txt +1 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/tests/conftest.py +38 -17
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/tests/test_agent.py +70 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/tests/test_container.py +18 -0
- ddapm_test_agent-1.35.0/tests/test_vcr_proxy.py +197 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/.dockerignore +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/.github/workflows/docker.yml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/.github/workflows/publish_pypi.yml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/.github/workflows/releasenote.yml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/.gitignore +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/Dockerfile +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/Dockerfile.windows +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/LICENSE.BSD3 +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/LICENSE.apache2 +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent/__init__.py +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent/apmtelemetry.py +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent/checks.py +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent/client.py +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent/cmd.py +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent/context.py +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent/fmt.py +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent/integration.py +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent/logs.py +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent/metrics.py +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent/remoteconfig.py +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent/trace.py +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent/trace_checks.py +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent/tracerflare.py +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent/tracestats.py +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent/tracestats_snapshot.py +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent.egg-info/dependency_links.txt +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent.egg-info/entry_points.txt +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent.egg-info/not-zip-safe +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/ddapm_test_agent.egg-info/top_level.txt +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/pyproject.toml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/check-releasenotes +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/config.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/1.0-e192f5064e917083.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/Add-metrics.process_id-to-ignored-attributes-62b264f0ea591326.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/Add-values-handling-to-span_event-array_value-to-mirror-agent-ee7483c90c263ff4.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/Checks-changed-to-opt-in-8716cac4ecdbb1c2.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/SNAPSHOT_REGEX_PLACEHOLDERS-1d2c5e2711d1953b.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/SNAPSHOT_REGEX_PLACEHOLDERS-compare-c829e7a4df4fa1f4.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/Settings-endpoint-928ae5b6e8ddc625.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/Telemetry-requests-delay-2586180b286ce393.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/Use-default-value-for-null-fields-in-tracestats-55d465f489efb2ba.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/acceptV1TracePayloads-5435cff37cfb6a85.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/add-datadog-proxy-7e2e608c101a564b.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/add-distributed-trace-c35a314698a3b966.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/add-fmt-command-cc31769942a5fec3.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/add-nix-build-support-29dc8a347e3bd7c1.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/add-optional-json-parser-10aac54bd1cbe322.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/add-otel-metrics-support-a2ebeb28cae2f0ba.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/add-python-3.13-support-ae7b96f4a10f20f4.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/add-rcm-endpoints-7e1f949e83e21039.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/add-request-forwarding-middleware-d3f325166b0f8e9e.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/add-service-naming-checks-2b68ff51d1b5496d.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/add-session-to-rcm-endpoints-d97e925a04a99a65.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/add-span-events-306e697168373899.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/add-support-for-plain-text-responses-00d20bf7b335e75b.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/add-support-telemetry-requests-10737cd3da802ca6.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/add-tracer_flare-endpoint-b2c81510920974d7.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/addAgentStateToInfo-f9a179ce88f2ab9e.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/addPeerTagsToInfo-4ccc2539d22c2993.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/allow-attribute-removal-snapshots-314b744b043b97c5.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/args-88f664c83a96075d.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/change-trace-proxy-headers-f9fcbb4efc4fcb95.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/check-http-header-sensitivity-daaa9d9595ae86d6.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/clearing-sessions-now-only-removes-6b0311673d8b37aa.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/client-173dbc6655e42337.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/content_length-e1bab75580aa1dcb.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/disable-error-responses-and-collect-trace-failures-in-memory-4a199bc7be416709.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/docker-arm64-images-a4b6b2cc527327d6.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/evp-proxy-on-info-d65cd077575306ca.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/exception-messages-21ee64461020edd1.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/fix-docker-image-tags-785d40f5bfdb8003.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/fix-fmt-logging-6a323fd8d5d4eb28.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/fix-getting-tested-integrations-multiple-session-tokens-4ee41d545754f87f.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/fix-matching-319744b82d2514c1.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/fix-missing-slim-deps-fa3b0fc0292a09b3.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/fix-partial-chunks-0db14ce3017e6173.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/fix-racecondition-9bd0ef15b7da60fa.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/fix-tracerflare-request-parsing-fae18ff9997c216d.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/genai-vcr-support-b499ec54df84eaa3.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/ignore-dsm-pathway-hash-during-trace-snapshots-f0b99ea267fbad48.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/image-optimization-d614eccb59441217.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/improve-test-agent-debugging-5759413f1fc5f7fa.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/improve-test-agent-proxying-a207f0fc81b3ab2d.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/improve-trace-check-results-endpoints-6ab4132628520793.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/info-34dcd9cbcc382487.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/info-drop-p0s-c207889f590340fb.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/llmobs-eval-metric-endpoint-8b5222491969ab4f.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/llmobs-evp-proxy-1383f4b4962ac7c9.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/meta-struct-2cce08475cb05470.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/more-oai-cass-908eb5ea46bd2985.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/new-process-id-tag-f0ab0daf652e05cc.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/oai-incomplete-cass-795ad19b6a226c1f.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/otlp-logs-grpc-45365879c22969aa.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/otlp-logs-support-d5a150d9f5304d7c.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/pipeline_stats_endpoint-e8ad6da735dc2647.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/profiling-endpoint-0cd209e4e5b6cfc0.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/provider-snapshot-server-f6a307acbf11d214.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/proxy-37c94e2fb428c6fc.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/python-3.12-952e06c6158af67d.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/python-support-1c447acc4607abc7.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/python310-025fbc190363de98.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/python310-docker-image-d4e329cfecf6510e.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/rc-encoding-length-fix-cc011edea7f8f5b2.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/rc-get-endpoint-e502f55b7df544e2.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/remoteconfig-requests-1af7abb99c61c069.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/remove-agent-state-header-from-info-87f920bf4ce5785c.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/remove-nix-ec1c4aca7dc002c4.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/remove-old-pythons-4667b182aacf0ce6.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/reuse-session-1670aa569907cf68.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/sample-rate-1e06ae4cdc933b14.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/session-requests-b8057811f976220e.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/session-tracerflares-400ce9b3d3838b40.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/snapshot-cmds-de4a561911afee11.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/snapshot-empty-maps-2cbe8cea3e7112fa.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/snapshot-error-messages-de41d9e3207fa30a.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/snapshot-filename-c068de1bc3e50c04.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/snapshot-order-type-2d6424e380b2c88f.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/snapshot-parent-id-7abb860008702e70.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/span-links-1ec76bd2b47a3880.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/span-ordering-1a7b383aa015bddc.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/span-parent-id-a4d7d63fa623361c.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/support-ant-vcr-1eff9a40caa0aba0.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/support-tracking-of-tested-integrations-ac19ccd1f8333c00.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/throttling-590bf58ecb3cc4a5.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/trace-stats-97da3a478dabfa99.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/trace-stats-snapshot-718ca37385c93e1e.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/traces-endpoint-f4f9c1d94d6ceda2.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/tracestats-fixes-07152c708e73ef96.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/tracestats-post-65ce788f81862532.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/tracestats-service-2a0a178cbd21b07d.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/uds-64b11960931d8b77.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/uds-c99ea5d099e67156.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/uds-container-8138f8b1438b1a0a.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/uds-permissions-903266ac6445b873.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/v0.5-traces-cf469b0b71398d97.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/v0.7-traces-7ea3ebbed7502d01.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/vcr-aws-bedrock-proxy-3bf018b1712d5105.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/vcr-cassette-name-middleware-fix-9e47c395892a9fe7.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/vcr-cassettes-for-openai-v5-6e9d78091de1f0c2.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/vcr-cassettes-for-vercel-ai-7a8275f9c2b48bc7.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/vcr-ci-mode-99dbd2940fff8d7a.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/vcr-prefix-instead-of-suffix-4c56dcb5038d222e.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/vcr-proxy-aws-recalculation-fix-2184c10270a7bca5.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/vcr-proxy-use-test-name-bugfix-be758294ba30ac78.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/vcr-proxy-use-test-name-e47891994c961c52.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/vcr-support-querystring-b06555fb9a7c90ae.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/version-0c32d2752f154eb9.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/wheels-68a7dc2f4b00e0c4.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/releasenotes/notes/windows-docker-image-1f5d5e894558bb4b.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/setup.cfg +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/tests/__init__.py +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/tests/integration_snapshots/test_multi_trace.json +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/tests/integration_snapshots/test_single_trace.json +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/tests/integration_snapshots/test_trace_distributed_propagated.json +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/tests/integration_snapshots/test_trace_distributed_same_payload.json +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/tests/integration_snapshots/test_trace_missing_received.json +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/tests/integration_snapshots/test_trace_stats_tracestats.json +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/tests/test_apmtelemetry.py +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/tests/test_checks.py +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/tests/test_client.py +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/tests/test_logs.py +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/tests/test_metrics.py +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/tests/test_remoteconfig.py +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/tests/test_session.py +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/tests/test_snapshot.py +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/tests/test_snapshot_integration.py +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/tests/test_trace.py +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/tests/test_tracerflare.py +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/tests/test_tracestats.py +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/tests/trace_utils.py +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/anthropic/anthropic_v1_messages_post_26d618ee.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/anthropic/anthropic_v1_messages_post_595f439c.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/anthropic/anthropic_v1_messages_post_717ba0b4.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/anthropic/anthropic_v1_messages_post_a1af2c12.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/deepseek/deepseek_chat_completions_post_afb6ccab.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_audio_transcriptions_post_173af3e5.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_audio_transcriptions_post_71305a25.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_audio_translations_post_d5b5b8d6.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_audio_translations_post_dd92a18a.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_0f1514e1.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_172294b4.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_193ae44a.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_23558eed.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_2edb59ae.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_3517e44e.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_36bdc0cb.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_3c045664.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_432a8e46.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_4749eff9.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_4dce8db6.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_57612363.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_649d8162.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_655a8ef2.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_66dfc80e.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_67e8e833.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_6df851cc.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_7c2d1ac5.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_82a4bb3c.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_9122b1ae.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_917478d0.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_a73ecd7a.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_a925b737.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_ae4728c2.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_b29f1a87.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_ce69ed91.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_d8fb132a.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_d94d5844.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_d98ce00d.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_chat_completions_post_ebff79da.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_completions_post_33681ea4.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_completions_post_5d2418d4.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_completions_post_619dee1c.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_completions_post_6224acff.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_completions_post_87f617af.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_completions_post_98c30019.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_completions_post_9bb49464.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_completions_post_b24dbf7d.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_embeddings_post_0381abe4.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_embeddings_post_48694087.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_embeddings_post_541bd4d0.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_files_file-RpTpuvRVtnKpdKZb7DDGto_content_get_60bd10ef.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_files_file-RpTpuvRVtnKpdKZb7DDGto_delete_3ee48409.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_files_file-RpTpuvRVtnKpdKZb7DDGto_get_1afefb93.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_files_get_68efa25d.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_files_post_2fcf9545.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_files_post_957d63ba.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_fine_tuning_jobs_ftjob-q9CUUUsHJemGUVQ1Ecc01zcf_cancel_post_d7c16b38.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_fine_tuning_jobs_ftjob-q9CUUUsHJemGUVQ1Ecc01zcf_events_get_557d820e.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_fine_tuning_jobs_ftjob-q9CUUUsHJemGUVQ1Ecc01zcf_get_265489e7.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_fine_tuning_jobs_get_ebc57c6f.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_fine_tuning_jobs_post_c3b6e4a9.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_images_edits_post_075386c4.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_images_edits_post_57b4f4da.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_images_edits_post_660e9dd7.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_images_edits_post_993e0192.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_images_edits_post_a2f1eb43.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_images_edits_post_ae72c45f.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_images_edits_post_cf5af376.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_images_edits_post_dbefb624.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_images_generations_post_48272841.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_images_generations_post_736070ea.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_images_variations_post_5971e285.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_images_variations_post_f2f62f6c.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_models_ft_gpt-4.1-mini-2025-04-14_datadog-staging__BkaILRSh_delete_c70f2992.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_models_get_e04cf04b.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_models_gpt-4_get_b13c5b23.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_moderations_post_532b3315.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_responses_post_33fb1f66.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_responses_post_5ca556ec.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_responses_post_c05c936e.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_responses_post_c61e3067.yaml +0 -0
- {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.35.0}/vcr-cassettes/openai/openai_responses_post_ee2423e6.yaml +0 -0
|
@@ -22,17 +22,25 @@ jobs:
|
|
|
22
22
|
test:
|
|
23
23
|
strategy:
|
|
24
24
|
matrix:
|
|
25
|
-
os: [ubuntu-latest, macos-latest]
|
|
25
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
26
26
|
python-version: ["3.11", "3.12", "3.13"]
|
|
27
27
|
runs-on: ${{ matrix.os }}
|
|
28
28
|
steps:
|
|
29
29
|
- uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
|
|
30
|
-
- uses: actions/setup-python@
|
|
30
|
+
- uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
|
|
31
31
|
with:
|
|
32
32
|
python-version: ${{ matrix.python-version }}
|
|
33
33
|
- name: install deps
|
|
34
34
|
run: pip install .[testing]
|
|
35
|
-
|
|
35
|
+
# Windows: Use vanilla pytest (riot doesn't support Windows - see https://github.com/DataDog/riot/issues/74)
|
|
36
|
+
- name: Run tests (Windows - direct pytest)
|
|
37
|
+
if: runner.os == 'Windows'
|
|
38
|
+
run: |
|
|
39
|
+
echo "Using pytest directly due to riot Windows limitation (https://github.com/DataDog/riot/issues/74)"
|
|
40
|
+
python -m pytest -v --basetemp=$env:TEMP\pytest tests/ --ignore=tests/test_container.py
|
|
41
|
+
- name: Run tests (Unix - riot)
|
|
42
|
+
if: runner.os != 'Windows'
|
|
43
|
+
run: |
|
|
36
44
|
riot run --pass-env -p ${{ matrix.python-version}} test
|
|
37
45
|
cassettes-size:
|
|
38
46
|
runs-on: ubuntu-latest
|
|
@@ -41,12 +49,12 @@ jobs:
|
|
|
41
49
|
- name: Check VCR cassettes size
|
|
42
50
|
run: |
|
|
43
51
|
CASSETTES_SIZE=$(du -sb vcr-cassettes/ 2>/dev/null | cut -f1 || echo "0")
|
|
44
|
-
|
|
52
|
+
|
|
45
53
|
MAX_SIZE=2097152
|
|
46
|
-
|
|
54
|
+
|
|
47
55
|
echo "VCR cassettes size: ${CASSETTES_SIZE} bytes ($((CASSETTES_SIZE / 1024 / 1024))MB)"
|
|
48
56
|
echo "Maximum allowed size: ${MAX_SIZE} bytes (2MB)"
|
|
49
|
-
|
|
57
|
+
|
|
50
58
|
if [ "$CASSETTES_SIZE" -gt "$MAX_SIZE" ]; then
|
|
51
59
|
echo "❌ VCR cassettes directory is larger than 2MB!"
|
|
52
60
|
echo "Current size: $((CASSETTES_SIZE / 1024 / 1024))MB"
|
|
@@ -55,4 +63,4 @@ jobs:
|
|
|
55
63
|
else
|
|
56
64
|
echo "✅ VCR cassettes directory size is within limits"
|
|
57
65
|
fi
|
|
58
|
-
|
|
66
|
+
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ddapm-test-agent
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.35.0
|
|
4
4
|
Summary: Test agent for Datadog APM client libraries
|
|
5
5
|
Home-page: https://github.com/Datadog/dd-apm-test-agent
|
|
6
6
|
Author: Kyle Verhoog
|
|
@@ -25,10 +25,12 @@ Requires-Dist: requests-aws4auth
|
|
|
25
25
|
Requires-Dist: opentelemetry-proto<1.37.0,>1.33.0
|
|
26
26
|
Requires-Dist: protobuf>=3.19.0
|
|
27
27
|
Requires-Dist: grpcio<2.0,>=1.66.2
|
|
28
|
+
Requires-Dist: pywin32; sys_platform == "win32"
|
|
28
29
|
Provides-Extra: testing
|
|
29
30
|
Requires-Dist: ddtrace==3.11.0; extra == "testing"
|
|
30
31
|
Requires-Dist: pytest; extra == "testing"
|
|
31
32
|
Requires-Dist: riot==0.20.1; extra == "testing"
|
|
33
|
+
Requires-Dist: PyYAML==6.0.3; extra == "testing"
|
|
32
34
|
Dynamic: author
|
|
33
35
|
Dynamic: author-email
|
|
34
36
|
Dynamic: classifier
|
|
@@ -183,7 +185,33 @@ The cassettes are matched based on the path, method, and body of the request. To
|
|
|
183
185
|
-v $PWD/vcr-cassettes:/vcr-cassettes
|
|
184
186
|
ghcr.io/datadog/dd-apm-test-agent/ddapm-test-agent:latest
|
|
185
187
|
|
|
186
|
-
Optionally specifying whatever mounted path is used for the cassettes directory. The test agent comes with a default set of cassettes for OpenAI, Azure OpenAI, and
|
|
188
|
+
Optionally specifying whatever mounted path is used for the cassettes directory. The test agent comes with a default set of cassettes for OpenAI, Azure OpenAI, DeepSeek, Anthropic, Google GenAI, and AWS Bedrock Runtime.
|
|
189
|
+
|
|
190
|
+
#### Custom 3rd Party Providers
|
|
191
|
+
|
|
192
|
+
The test agent can be configured to also register custom 3rd party providers. This is done by setting the `VCR_PROVIDER_MAP` environment variable or the `--vcr-provider-map` command-line option to a comma-separated list of provider names and their corresponding base URLs.
|
|
193
|
+
|
|
194
|
+
```shell
|
|
195
|
+
VCR_PROVIDER_MAP="provider1=http://provider1.com/,provider2=http://provider2.com/"
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
or
|
|
199
|
+
|
|
200
|
+
```shell
|
|
201
|
+
--vcr-provider-map="provider1=http://provider1.com/,provider2=http://provider2.com/"
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
The provider names are used to match the provider name in the request path, and the base URLs are used to proxy the request to the corresponding provider API endpoint.
|
|
205
|
+
|
|
206
|
+
With this configuration set, you can make the following request to the test agent without error:
|
|
207
|
+
|
|
208
|
+
```shell
|
|
209
|
+
curl -X POST 'http://127.0.0.1:9126/vcr/provider1/some/path'
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
#### Ignoring Headers in Recorded Cassettes
|
|
213
|
+
|
|
214
|
+
To ignore headers in recorded cassettes, you can use the `--vcr-ignore-headers` flag or `VCR_IGNORE_HEADERS` environment variable. The list should take the form of `header1,header2,header3`, and will be omitted from the recorded cassettes.
|
|
187
215
|
|
|
188
216
|
#### AWS Services
|
|
189
217
|
AWS service proxying, specifically recording cassettes for the first time, requires a `AWS_SECRET_ACCESS_KEY` environment variable to be set for the container running the test agent. This is used to recalculate the AWS signature for the request, as the one generated client-side likely used `{test-agent-host}:{test-agent-port}/vcr/{aws-service}` as the host, and the signature will mismatch that on the actual AWS service.
|
|
@@ -139,7 +139,33 @@ The cassettes are matched based on the path, method, and body of the request. To
|
|
|
139
139
|
-v $PWD/vcr-cassettes:/vcr-cassettes
|
|
140
140
|
ghcr.io/datadog/dd-apm-test-agent/ddapm-test-agent:latest
|
|
141
141
|
|
|
142
|
-
Optionally specifying whatever mounted path is used for the cassettes directory. The test agent comes with a default set of cassettes for OpenAI, Azure OpenAI, and
|
|
142
|
+
Optionally specifying whatever mounted path is used for the cassettes directory. The test agent comes with a default set of cassettes for OpenAI, Azure OpenAI, DeepSeek, Anthropic, Google GenAI, and AWS Bedrock Runtime.
|
|
143
|
+
|
|
144
|
+
#### Custom 3rd Party Providers
|
|
145
|
+
|
|
146
|
+
The test agent can be configured to also register custom 3rd party providers. This is done by setting the `VCR_PROVIDER_MAP` environment variable or the `--vcr-provider-map` command-line option to a comma-separated list of provider names and their corresponding base URLs.
|
|
147
|
+
|
|
148
|
+
```shell
|
|
149
|
+
VCR_PROVIDER_MAP="provider1=http://provider1.com/,provider2=http://provider2.com/"
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
or
|
|
153
|
+
|
|
154
|
+
```shell
|
|
155
|
+
--vcr-provider-map="provider1=http://provider1.com/,provider2=http://provider2.com/"
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
The provider names are used to match the provider name in the request path, and the base URLs are used to proxy the request to the corresponding provider API endpoint.
|
|
159
|
+
|
|
160
|
+
With this configuration set, you can make the following request to the test agent without error:
|
|
161
|
+
|
|
162
|
+
```shell
|
|
163
|
+
curl -X POST 'http://127.0.0.1:9126/vcr/provider1/some/path'
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
#### Ignoring Headers in Recorded Cassettes
|
|
167
|
+
|
|
168
|
+
To ignore headers in recorded cassettes, you can use the `--vcr-ignore-headers` flag or `VCR_IGNORE_HEADERS` environment variable. The list should take the form of `header1,header2,header3`, and will be omitted from the recorded cassettes.
|
|
143
169
|
|
|
144
170
|
#### AWS Services
|
|
145
171
|
AWS service proxying, specifically recording cassettes for the first time, requires a `AWS_SECRET_ACCESS_KEY` environment variable to be set for the container running the test agent. This is used to recalculate the AWS signature for the request, as the one generated client-side likely used `{test-agent-host}:{test-agent-port}/vcr/{aws-service}` as the host, and the signature will mismatch that on the actual AWS service.
|
|
@@ -9,10 +9,12 @@ from dataclasses import field
|
|
|
9
9
|
import json
|
|
10
10
|
import logging
|
|
11
11
|
import os
|
|
12
|
+
import platform
|
|
12
13
|
import pprint
|
|
13
14
|
import re
|
|
14
15
|
import socket
|
|
15
16
|
import sys
|
|
17
|
+
import threading
|
|
16
18
|
from typing import Any
|
|
17
19
|
from typing import Awaitable
|
|
18
20
|
from typing import Callable
|
|
@@ -240,6 +242,59 @@ def default_value_trace_results_summary():
|
|
|
240
242
|
}
|
|
241
243
|
|
|
242
244
|
|
|
245
|
+
class MockQuery:
|
|
246
|
+
"""Mock query object that behaves like a dict."""
|
|
247
|
+
|
|
248
|
+
def __init__(self):
|
|
249
|
+
self._data = {} # Empty query params for named pipe processing
|
|
250
|
+
|
|
251
|
+
def get(self, key, default=None):
|
|
252
|
+
return self._data.get(key, default)
|
|
253
|
+
|
|
254
|
+
def __getitem__(self, key):
|
|
255
|
+
return self._data[key]
|
|
256
|
+
|
|
257
|
+
def __contains__(self, key):
|
|
258
|
+
return key in self._data
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
class MockURL:
|
|
262
|
+
"""Mock URL object for named pipe processing."""
|
|
263
|
+
|
|
264
|
+
def __init__(self, path: str):
|
|
265
|
+
self.path = path
|
|
266
|
+
self.query = MockQuery()
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
class MockRequest:
|
|
270
|
+
"""Mock Request object for named pipe processing."""
|
|
271
|
+
|
|
272
|
+
def __init__(
|
|
273
|
+
self, method: str, path: str, headers: Dict[str, str], body: bytes, agent: "Agent", app: web.Application
|
|
274
|
+
):
|
|
275
|
+
self.method = method
|
|
276
|
+
self.path = path
|
|
277
|
+
self.headers = headers
|
|
278
|
+
self._body = body
|
|
279
|
+
self._data: Dict[str, Any] = {}
|
|
280
|
+
self.url = MockURL(path)
|
|
281
|
+
self.content_type = headers.get("Content-Type", "application/msgpack")
|
|
282
|
+
self.app = app
|
|
283
|
+
|
|
284
|
+
async def read(self) -> bytes:
|
|
285
|
+
"""Mock read() method that returns the body data."""
|
|
286
|
+
return self._body
|
|
287
|
+
|
|
288
|
+
def __getitem__(self, key):
|
|
289
|
+
return self._data.get(key)
|
|
290
|
+
|
|
291
|
+
def __setitem__(self, key, value):
|
|
292
|
+
self._data[key] = value
|
|
293
|
+
|
|
294
|
+
def get(self, key, default=None):
|
|
295
|
+
return self._data.get(key, default)
|
|
296
|
+
|
|
297
|
+
|
|
243
298
|
@dataclass
|
|
244
299
|
class _AgentSession:
|
|
245
300
|
"""Maintain Agent state across requests."""
|
|
@@ -1287,6 +1342,174 @@ class Agent:
|
|
|
1287
1342
|
raise web.HTTPBadRequest(body=msg)
|
|
1288
1343
|
return response
|
|
1289
1344
|
|
|
1345
|
+
def _parse_http_request(self, data: bytes) -> tuple[str, str, Dict[str, str], bytes]:
|
|
1346
|
+
"""Parse HTTP request from raw bytes.
|
|
1347
|
+
|
|
1348
|
+
Returns:
|
|
1349
|
+
tuple: (method, path, headers_dict, body)
|
|
1350
|
+
"""
|
|
1351
|
+
try:
|
|
1352
|
+
# Split request into headers and body
|
|
1353
|
+
if b"\r\n\r\n" in data:
|
|
1354
|
+
header_data, body = data.split(b"\r\n\r\n", 1)
|
|
1355
|
+
else:
|
|
1356
|
+
header_data, body = data, b""
|
|
1357
|
+
|
|
1358
|
+
# Parse headers
|
|
1359
|
+
header_lines = header_data.decode("utf-8", errors="ignore").split("\r\n")
|
|
1360
|
+
if not header_lines:
|
|
1361
|
+
raise ValueError("No request line found")
|
|
1362
|
+
|
|
1363
|
+
# Parse request line (e.g., "POST /v0.4/traces HTTP/1.1")
|
|
1364
|
+
request_line = header_lines[0]
|
|
1365
|
+
parts = request_line.split(" ")
|
|
1366
|
+
if len(parts) < 2:
|
|
1367
|
+
raise ValueError(f"Invalid request line: {request_line}")
|
|
1368
|
+
|
|
1369
|
+
method = parts[0]
|
|
1370
|
+
path = parts[1]
|
|
1371
|
+
|
|
1372
|
+
# Parse headers
|
|
1373
|
+
headers: Dict[str, str] = {}
|
|
1374
|
+
for line in header_lines[1:]:
|
|
1375
|
+
if ":" in line:
|
|
1376
|
+
key, value = line.split(":", 1)
|
|
1377
|
+
headers[key.strip()] = value.strip()
|
|
1378
|
+
|
|
1379
|
+
return method, path, headers, body
|
|
1380
|
+
|
|
1381
|
+
except Exception as e:
|
|
1382
|
+
log.error(f"Error parsing HTTP request: {e}")
|
|
1383
|
+
raise ValueError(f"Failed to parse HTTP request: {e}") from e
|
|
1384
|
+
|
|
1385
|
+
def _process_named_pipe_request(self, data: bytes, app: web.Application) -> bytes:
|
|
1386
|
+
"""Process a request using the existing Agent infrastructure."""
|
|
1387
|
+
try:
|
|
1388
|
+
# Parse the HTTP request
|
|
1389
|
+
method, path, headers, body = self._parse_http_request(data)
|
|
1390
|
+
|
|
1391
|
+
log.info(f"Processing Named Pipe request: {method} {path}")
|
|
1392
|
+
|
|
1393
|
+
# Create a mock Request object
|
|
1394
|
+
mock_request = MockRequest(method, path, headers, body, self, app)
|
|
1395
|
+
|
|
1396
|
+
# Extract session token like the middleware does
|
|
1397
|
+
token = None
|
|
1398
|
+
if "X-Datadog-Test-Session-Token" in headers:
|
|
1399
|
+
token = headers["X-Datadog-Test-Session-Token"]
|
|
1400
|
+
mock_request["session_token"] = token
|
|
1401
|
+
|
|
1402
|
+
# Store request data for agent processing
|
|
1403
|
+
mock_request["_testagent_data"] = body
|
|
1404
|
+
|
|
1405
|
+
# Route to appropriate handler based on path using dictionary lookup
|
|
1406
|
+
path_handlers = {
|
|
1407
|
+
"/v0.4/traces": self.handle_v04_traces,
|
|
1408
|
+
"/v0.5/traces": self.handle_v05_traces,
|
|
1409
|
+
"/v0.7/traces": self.handle_v07_traces,
|
|
1410
|
+
"/v1.0/traces": self.handle_v1_traces,
|
|
1411
|
+
"/v0.6/stats": self.handle_v06_tracestats,
|
|
1412
|
+
"/v0.1/pipeline_stats": self.handle_v01_pipelinestats,
|
|
1413
|
+
"/v0.7/config": self.handle_v07_remoteconfig,
|
|
1414
|
+
"/telemetry/proxy/api/v2/apmtelemetry": self.handle_v2_apmtelemetry,
|
|
1415
|
+
"/profiling/v1/input": self.handle_v1_profiling,
|
|
1416
|
+
"/tracer_flare/v1": self.handle_v1_tracer_flare,
|
|
1417
|
+
"/evp_proxy/v2/api/v2/llmobs": self.handle_evp_proxy_v2_api_v2_llmobs,
|
|
1418
|
+
"/evp_proxy/v2/api/intake/llm-obs/v1/eval-metric": self.handle_evp_proxy_v2_llmobs_eval_metric,
|
|
1419
|
+
"/evp_proxy/v2/api/intake/llm-obs/v2/eval-metric": self.handle_evp_proxy_v2_llmobs_eval_metric,
|
|
1420
|
+
"/info": self.handle_info,
|
|
1421
|
+
# Test endpoints
|
|
1422
|
+
"/test/session/start": self.handle_session_start,
|
|
1423
|
+
"/test/session/clear": self.handle_session_clear,
|
|
1424
|
+
"/test/session/snapshot": self.handle_snapshot,
|
|
1425
|
+
"/test/session/traces": self.handle_session_traces,
|
|
1426
|
+
"/test/session/apmtelemetry": self.handle_session_apmtelemetry,
|
|
1427
|
+
"/test/session/tracerflares": self.handle_session_tracerflares,
|
|
1428
|
+
"/test/session/stats": self.handle_session_tracestats,
|
|
1429
|
+
"/test/session/requests": self.handle_session_requests,
|
|
1430
|
+
"/test/session/responses/config": self.handle_v07_remoteconfig_create,
|
|
1431
|
+
"/test/session/responses/config/path": self.handle_v07_remoteconfig_path_create,
|
|
1432
|
+
"/test/traces": self.handle_test_traces,
|
|
1433
|
+
"/test/apmtelemetry": self.handle_test_apmtelemetry,
|
|
1434
|
+
"/test/trace/analyze": self.handle_trace_analyze,
|
|
1435
|
+
"/test/trace_check/failures": self.get_trace_check_failures,
|
|
1436
|
+
"/test/trace_check/clear": self.clear_trace_check_failures,
|
|
1437
|
+
"/test/trace_check/summary": self.get_trace_check_summary,
|
|
1438
|
+
"/test/integrations/tested_versions": self.handle_get_tested_integrations,
|
|
1439
|
+
"/test/settings": self.handle_settings,
|
|
1440
|
+
}
|
|
1441
|
+
|
|
1442
|
+
# Get handler from dictionary lookup
|
|
1443
|
+
handler = path_handlers.get(path)
|
|
1444
|
+
if not handler:
|
|
1445
|
+
return self._create_error_response(404, "Not Found")
|
|
1446
|
+
|
|
1447
|
+
try:
|
|
1448
|
+
# Create a new event loop for this thread if one doesn't exist
|
|
1449
|
+
loop = asyncio.get_event_loop()
|
|
1450
|
+
except RuntimeError:
|
|
1451
|
+
loop = asyncio.new_event_loop()
|
|
1452
|
+
asyncio.set_event_loop(loop)
|
|
1453
|
+
|
|
1454
|
+
# Initialize the CheckTrace context like middleware does
|
|
1455
|
+
start_trace("named_pipe_request %s %s" % (method, path))
|
|
1456
|
+
|
|
1457
|
+
# Run the handler
|
|
1458
|
+
response = loop.run_until_complete(handler(mock_request)) # type: ignore[arg-type]
|
|
1459
|
+
|
|
1460
|
+
# Convert aiohttp response to HTTP bytes
|
|
1461
|
+
return self._convert_response_to_http(response)
|
|
1462
|
+
|
|
1463
|
+
except Exception as e:
|
|
1464
|
+
log.error(f"Error processing Named Pipe request: {e}", exc_info=True)
|
|
1465
|
+
return self._create_error_response(500, "Internal Server Error")
|
|
1466
|
+
|
|
1467
|
+
def _convert_response_to_http(self, response: web.Response) -> bytes:
|
|
1468
|
+
"""Convert aiohttp Response to HTTP response bytes."""
|
|
1469
|
+
try:
|
|
1470
|
+
# Build HTTP response
|
|
1471
|
+
status_line = f"HTTP/1.1 {response.status} {response.reason}\r\n"
|
|
1472
|
+
|
|
1473
|
+
# Build headers
|
|
1474
|
+
headers_lines = []
|
|
1475
|
+
for key, value in response.headers.items():
|
|
1476
|
+
headers_lines.append(f"{key}: {value}\r\n")
|
|
1477
|
+
|
|
1478
|
+
# Get response body
|
|
1479
|
+
body_data: bytes
|
|
1480
|
+
if hasattr(response, "body") and response.body:
|
|
1481
|
+
if isinstance(response.body, bytes):
|
|
1482
|
+
body_data = response.body
|
|
1483
|
+
elif isinstance(response.body, str):
|
|
1484
|
+
body_data = response.body.encode()
|
|
1485
|
+
else:
|
|
1486
|
+
# Handle Payload or other types by converting to string first
|
|
1487
|
+
body_data = str(response.body).encode()
|
|
1488
|
+
else:
|
|
1489
|
+
body_data = b""
|
|
1490
|
+
|
|
1491
|
+
# Add Content-Length header if not present
|
|
1492
|
+
if "Content-Length" not in response.headers:
|
|
1493
|
+
headers_lines.append(f"Content-Length: {len(body_data)}\r\n")
|
|
1494
|
+
|
|
1495
|
+
# Combine all parts
|
|
1496
|
+
headers_str = "".join(headers_lines)
|
|
1497
|
+
http_response = status_line + headers_str + "\r\n"
|
|
1498
|
+
return http_response.encode("utf-8") + body_data
|
|
1499
|
+
|
|
1500
|
+
except Exception as e:
|
|
1501
|
+
log.error(f"Error converting response to HTTP: {e}")
|
|
1502
|
+
return self._create_error_response(500, "Internal Server Error")
|
|
1503
|
+
|
|
1504
|
+
def _create_error_response(self, status_code: int, reason: str) -> bytes:
|
|
1505
|
+
"""Create an HTTP error response."""
|
|
1506
|
+
body = f"{status_code} {reason}".encode("utf-8")
|
|
1507
|
+
response = f"HTTP/1.1 {status_code} {reason}\r\n"
|
|
1508
|
+
response += f"Content-Length: {len(body)}\r\n"
|
|
1509
|
+
response += "Content-Type: text/plain\r\n"
|
|
1510
|
+
response += "\r\n"
|
|
1511
|
+
return response.encode("utf-8") + body
|
|
1512
|
+
|
|
1290
1513
|
|
|
1291
1514
|
def make_otlp_http_app(agent: Agent) -> web.Application:
|
|
1292
1515
|
"""Create a separate HTTP application for OTLP endpoints using the shared agent instance."""
|
|
@@ -1356,6 +1579,8 @@ def make_app(
|
|
|
1356
1579
|
snapshot_regex_placeholders: Dict[str, str],
|
|
1357
1580
|
vcr_cassettes_directory: str,
|
|
1358
1581
|
vcr_ci_mode: bool,
|
|
1582
|
+
vcr_provider_map: str,
|
|
1583
|
+
vcr_ignore_headers: str,
|
|
1359
1584
|
) -> web.Application:
|
|
1360
1585
|
agent = Agent()
|
|
1361
1586
|
app = web.Application(
|
|
@@ -1417,7 +1642,9 @@ def make_app(
|
|
|
1417
1642
|
web.route(
|
|
1418
1643
|
"*",
|
|
1419
1644
|
"/vcr/{path:.*}",
|
|
1420
|
-
lambda request: proxy_request(
|
|
1645
|
+
lambda request: proxy_request(
|
|
1646
|
+
request, vcr_cassettes_directory, vcr_ci_mode, vcr_provider_map, vcr_ignore_headers
|
|
1647
|
+
),
|
|
1421
1648
|
),
|
|
1422
1649
|
]
|
|
1423
1650
|
)
|
|
@@ -1449,6 +1676,137 @@ def make_app(
|
|
|
1449
1676
|
return app
|
|
1450
1677
|
|
|
1451
1678
|
|
|
1679
|
+
def _start_named_pipe_server(pipe_path: str, agent: "Agent", app: web.Application) -> None:
|
|
1680
|
+
"""Start Windows named pipe server."""
|
|
1681
|
+
if platform.system() != "Windows":
|
|
1682
|
+
log.warning("Named pipes are only supported on Windows, ignoring --trace-named-pipe")
|
|
1683
|
+
return
|
|
1684
|
+
|
|
1685
|
+
# Import Windows-specific modules here to avoid import errors on other platforms
|
|
1686
|
+
try:
|
|
1687
|
+
import win32file
|
|
1688
|
+
import win32pipe
|
|
1689
|
+
except ImportError as e:
|
|
1690
|
+
log.error(f"Failed to import Windows modules for named pipes: {e}")
|
|
1691
|
+
return
|
|
1692
|
+
|
|
1693
|
+
_start_windows_named_pipe_server(pipe_path, agent, app, win32pipe, win32file)
|
|
1694
|
+
|
|
1695
|
+
|
|
1696
|
+
def _create_and_wait_for_client(
|
|
1697
|
+
pipe_path: str, agent: "Agent", app: web.Application, win32pipe: Any, win32file: Any
|
|
1698
|
+
) -> None:
|
|
1699
|
+
"""Create a single pipe instance and wait for a client connection."""
|
|
1700
|
+
while True:
|
|
1701
|
+
try:
|
|
1702
|
+
# Create named pipe instance
|
|
1703
|
+
pipe_handle = win32pipe.CreateNamedPipe(
|
|
1704
|
+
pipe_path,
|
|
1705
|
+
win32pipe.PIPE_ACCESS_DUPLEX,
|
|
1706
|
+
win32pipe.PIPE_TYPE_MESSAGE | win32pipe.PIPE_READMODE_MESSAGE | win32pipe.PIPE_WAIT,
|
|
1707
|
+
win32pipe.PIPE_UNLIMITED_INSTANCES, # allow multiple concurrent connections
|
|
1708
|
+
65536, # output buffer size
|
|
1709
|
+
65536, # input buffer size
|
|
1710
|
+
0, # default timeout
|
|
1711
|
+
None, # security attributes
|
|
1712
|
+
)
|
|
1713
|
+
|
|
1714
|
+
if pipe_handle == win32file.INVALID_HANDLE_VALUE:
|
|
1715
|
+
log.error("Failed to create named pipe instance")
|
|
1716
|
+
import time
|
|
1717
|
+
|
|
1718
|
+
time.sleep(1) # Wait before retrying
|
|
1719
|
+
continue
|
|
1720
|
+
|
|
1721
|
+
log.debug("Named pipe instance created, waiting for client...")
|
|
1722
|
+
|
|
1723
|
+
# Wait for client connection
|
|
1724
|
+
win32pipe.ConnectNamedPipe(pipe_handle, None)
|
|
1725
|
+
log.info("Client connected to named pipe instance")
|
|
1726
|
+
|
|
1727
|
+
# Handle the client request
|
|
1728
|
+
_handle_windows_named_pipe_client(pipe_handle, agent, app, win32pipe, win32file)
|
|
1729
|
+
|
|
1730
|
+
except Exception as e:
|
|
1731
|
+
log.error(f"Error in named pipe instance: {e}")
|
|
1732
|
+
import time
|
|
1733
|
+
|
|
1734
|
+
time.sleep(1) # Wait before retrying
|
|
1735
|
+
|
|
1736
|
+
|
|
1737
|
+
def _start_windows_named_pipe_server(
|
|
1738
|
+
pipe_path: str, agent: "Agent", app: web.Application, win32pipe: Any, win32file: Any
|
|
1739
|
+
) -> None:
|
|
1740
|
+
"""Start a Windows named pipe server with multiple instances."""
|
|
1741
|
+
if win32pipe is None:
|
|
1742
|
+
log.error("Windows named pipe support not available (pywin32 not installed)")
|
|
1743
|
+
return
|
|
1744
|
+
|
|
1745
|
+
log.info(f"Starting Windows named pipe server on: {pipe_path}")
|
|
1746
|
+
|
|
1747
|
+
# Create multiple pipe instances for better concurrency
|
|
1748
|
+
num_instances = 10 # Support up to 10 concurrent connections
|
|
1749
|
+
threads = []
|
|
1750
|
+
|
|
1751
|
+
for _ in range(num_instances):
|
|
1752
|
+
thread = threading.Thread(
|
|
1753
|
+
target=_create_and_wait_for_client, args=(pipe_path, agent, app, win32pipe, win32file), daemon=True
|
|
1754
|
+
)
|
|
1755
|
+
thread.start()
|
|
1756
|
+
threads.append(thread)
|
|
1757
|
+
|
|
1758
|
+
log.info(f"Started {num_instances} named pipe instances")
|
|
1759
|
+
|
|
1760
|
+
# Keep the main thread alive and monitor instance threads
|
|
1761
|
+
try:
|
|
1762
|
+
while True:
|
|
1763
|
+
import time
|
|
1764
|
+
|
|
1765
|
+
time.sleep(5)
|
|
1766
|
+
|
|
1767
|
+
# Check if any threads have died and restart them
|
|
1768
|
+
for i, thread in enumerate(threads):
|
|
1769
|
+
if not thread.is_alive():
|
|
1770
|
+
log.warning(f"Restarting named pipe instance {i}")
|
|
1771
|
+
new_thread = threading.Thread(
|
|
1772
|
+
target=_create_and_wait_for_client,
|
|
1773
|
+
args=(pipe_path, agent, app, win32pipe, win32file),
|
|
1774
|
+
daemon=True,
|
|
1775
|
+
)
|
|
1776
|
+
new_thread.start()
|
|
1777
|
+
threads[i] = new_thread
|
|
1778
|
+
|
|
1779
|
+
except KeyboardInterrupt:
|
|
1780
|
+
log.info("Named pipe server shutting down")
|
|
1781
|
+
|
|
1782
|
+
|
|
1783
|
+
def _handle_windows_named_pipe_client(
|
|
1784
|
+
pipe_handle: Any, agent: "Agent", app: web.Application, win32pipe: Any, win32file: Any
|
|
1785
|
+
) -> None:
|
|
1786
|
+
"""Handle a Windows named pipe client connection."""
|
|
1787
|
+
try:
|
|
1788
|
+
# Read request data
|
|
1789
|
+
result, data = win32file.ReadFile(pipe_handle, 65536)
|
|
1790
|
+
if result == 0: # SUCCESS
|
|
1791
|
+
log.info(f"Received {len(data)} bytes from named pipe client")
|
|
1792
|
+
|
|
1793
|
+
# Process request
|
|
1794
|
+
response = agent._process_named_pipe_request(data, app)
|
|
1795
|
+
|
|
1796
|
+
# Write response
|
|
1797
|
+
win32file.WriteFile(pipe_handle, response)
|
|
1798
|
+
log.info(f"Sent {len(response)} bytes response to named pipe client")
|
|
1799
|
+
|
|
1800
|
+
except Exception as e:
|
|
1801
|
+
log.error(f"Error handling Windows named pipe client: {e}")
|
|
1802
|
+
finally:
|
|
1803
|
+
try:
|
|
1804
|
+
win32pipe.DisconnectNamedPipe(pipe_handle)
|
|
1805
|
+
win32file.CloseHandle(pipe_handle)
|
|
1806
|
+
except Exception:
|
|
1807
|
+
pass
|
|
1808
|
+
|
|
1809
|
+
|
|
1452
1810
|
def main(args: Optional[List[str]] = None) -> None:
|
|
1453
1811
|
if args is None:
|
|
1454
1812
|
args = sys.argv[1:]
|
|
@@ -1550,6 +1908,12 @@ def main(args: Optional[List[str]] = None) -> None:
|
|
|
1550
1908
|
default=os.environ.get("DD_APM_RECEIVER_SOCKET", None),
|
|
1551
1909
|
help=("Will listen for traces on the specified socket path"),
|
|
1552
1910
|
)
|
|
1911
|
+
parser.add_argument(
|
|
1912
|
+
"--trace-named-pipe",
|
|
1913
|
+
type=str,
|
|
1914
|
+
default=os.environ.get("DD_APM_RECEIVER_NAMED_PIPE", None),
|
|
1915
|
+
help=("Will listen for traces on the specified named pipe path"),
|
|
1916
|
+
)
|
|
1553
1917
|
parser.add_argument(
|
|
1554
1918
|
"--trace-request-delay",
|
|
1555
1919
|
type=float,
|
|
@@ -1588,6 +1952,18 @@ def main(args: Optional[List[str]] = None) -> None:
|
|
|
1588
1952
|
default=os.environ.get("VCR_CI_MODE", False),
|
|
1589
1953
|
help="Will change the test agent to record VCR cassettes in CI mode, throwing an error if a cassette is not found on /vcr/{provider}",
|
|
1590
1954
|
)
|
|
1955
|
+
parser.add_argument(
|
|
1956
|
+
"--vcr-provider-map",
|
|
1957
|
+
type=str,
|
|
1958
|
+
default=os.environ.get("VCR_PROVIDER_MAP", ""),
|
|
1959
|
+
help="Comma-separated list of provider=base_url tuples to map providers to paths. Used in addition to the default provider paths.",
|
|
1960
|
+
)
|
|
1961
|
+
parser.add_argument(
|
|
1962
|
+
"--vcr-ignore-headers",
|
|
1963
|
+
type=str,
|
|
1964
|
+
default=os.environ.get("VCR_IGNORE_HEADERS", ""),
|
|
1965
|
+
help="Comma-separated list of headers to ignore when recording VCR cassettes.",
|
|
1966
|
+
)
|
|
1591
1967
|
parsed_args = parser.parse_args(args=args)
|
|
1592
1968
|
logging.basicConfig(level=parsed_args.log_level)
|
|
1593
1969
|
|
|
@@ -1632,6 +2008,8 @@ def main(args: Optional[List[str]] = None) -> None:
|
|
|
1632
2008
|
snapshot_regex_placeholders=parsed_args.snapshot_regex_placeholders,
|
|
1633
2009
|
vcr_cassettes_directory=parsed_args.vcr_cassettes_directory,
|
|
1634
2010
|
vcr_ci_mode=parsed_args.vcr_ci_mode,
|
|
2011
|
+
vcr_provider_map=parsed_args.vcr_provider_map,
|
|
2012
|
+
vcr_ignore_headers=parsed_args.vcr_ignore_headers,
|
|
1635
2013
|
)
|
|
1636
2014
|
|
|
1637
2015
|
# Validate port configuration
|
|
@@ -1644,6 +2022,18 @@ def main(args: Optional[List[str]] = None) -> None:
|
|
|
1644
2022
|
|
|
1645
2023
|
# Get the shared agent instance from the main app
|
|
1646
2024
|
agent = app["agent"]
|
|
2025
|
+
|
|
2026
|
+
# Named pipe setup (after agent is available)
|
|
2027
|
+
named_pipe_thread = None
|
|
2028
|
+
if parsed_args.trace_named_pipe is not None:
|
|
2029
|
+
|
|
2030
|
+
def start_named_pipe_server():
|
|
2031
|
+
_start_named_pipe_server(parsed_args.trace_named_pipe, agent, app)
|
|
2032
|
+
|
|
2033
|
+
named_pipe_thread = threading.Thread(target=start_named_pipe_server, daemon=True)
|
|
2034
|
+
named_pipe_thread.start()
|
|
2035
|
+
log.info(f"Started named pipe server on: {parsed_args.trace_named_pipe}")
|
|
2036
|
+
|
|
1647
2037
|
otlp_http_app = make_otlp_http_app(agent)
|
|
1648
2038
|
|
|
1649
2039
|
async def run_servers():
|
|
@@ -34,6 +34,27 @@ log = logging.getLogger(__name__)
|
|
|
34
34
|
DEFAULT_SNAPSHOT_IGNORES = "span_id,trace_id,parent_id,duration,start,metrics.system.pid,metrics.system.process_id,metrics.process_id,metrics._dd.tracer_kr,meta.runtime-id,span_links.trace_id_high,span_events.time_unix_nano,meta.pathway.hash,meta._dd.p.tid"
|
|
35
35
|
|
|
36
36
|
|
|
37
|
+
def _normalize_span_for_comparison(span: Span) -> Span:
|
|
38
|
+
"""Normalize span for cross-platform comparison (Windows vs Unix).
|
|
39
|
+
|
|
40
|
+
Handles differences in how ddtrace creates spans on different platforms:
|
|
41
|
+
- Windows may omit fields with default values (error, type)
|
|
42
|
+
- Windows may use None instead of empty string for service
|
|
43
|
+
"""
|
|
44
|
+
normalized = dict(span)
|
|
45
|
+
|
|
46
|
+
if "error" not in normalized:
|
|
47
|
+
normalized["error"] = 0
|
|
48
|
+
|
|
49
|
+
if "type" not in normalized:
|
|
50
|
+
normalized["type"] = ""
|
|
51
|
+
|
|
52
|
+
if normalized.get("service") is None:
|
|
53
|
+
normalized["service"] = ""
|
|
54
|
+
|
|
55
|
+
return cast(Span, normalized)
|
|
56
|
+
|
|
57
|
+
|
|
37
58
|
def _key_match(d1: Dict[str, Any], d2: Dict[str, Any], key: str) -> bool:
|
|
38
59
|
"""
|
|
39
60
|
>>> _key_match({"a": 1}, {"a": 2}, "a")
|
|
@@ -347,6 +368,10 @@ def _compare_traces(expected: Trace, received: Trace, ignored: Set[str]) -> None
|
|
|
347
368
|
)
|
|
348
369
|
|
|
349
370
|
for s_exp, s_rec in zip(expected, received):
|
|
371
|
+
# Normalize spans for cross-platform comparison (Windows vs Unix)
|
|
372
|
+
s_exp_norm = _normalize_span_for_comparison(s_exp)
|
|
373
|
+
s_rec_norm = _normalize_span_for_comparison(s_rec)
|
|
374
|
+
|
|
350
375
|
with CheckTrace.add_frame(
|
|
351
376
|
f"snapshot compare of span '{s_exp['name']}' at position {s_exp['span_id']} in trace"
|
|
352
377
|
) as frame:
|
|
@@ -358,12 +383,12 @@ def _compare_traces(expected: Trace, received: Trace, ignored: Set[str]) -> None
|
|
|
358
383
|
metrics_diffs,
|
|
359
384
|
span_link_diffs,
|
|
360
385
|
span_event_diffs,
|
|
361
|
-
) = _diff_spans(
|
|
386
|
+
) = _diff_spans(s_exp_norm, s_rec_norm, ignored)
|
|
362
387
|
|
|
363
388
|
for diffs, diff_type, d_exp, d_rec in [
|
|
364
|
-
(top_level_diffs, "span",
|
|
365
|
-
(meta_diffs, "meta",
|
|
366
|
-
(metrics_diffs, "metrics",
|
|
389
|
+
(top_level_diffs, "span", s_exp_norm, s_rec_norm),
|
|
390
|
+
(meta_diffs, "meta", s_exp_norm["meta"], s_rec_norm["meta"]),
|
|
391
|
+
(metrics_diffs, "metrics", s_exp_norm["metrics"], s_rec_norm["metrics"]),
|
|
367
392
|
]:
|
|
368
393
|
for diff_key in diffs:
|
|
369
394
|
if diff_key not in d_exp:
|