ddapm-test-agent 1.34.0__tar.gz → 1.36.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.
Files changed (271) hide show
  1. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/.github/workflows/main.yml +15 -7
  2. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/PKG-INFO +30 -2
  3. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/README.md +27 -1
  4. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/ddapm_test_agent/agent.py +399 -1
  5. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/ddapm_test_agent/trace_snapshot.py +29 -4
  6. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/ddapm_test_agent/vcr_proxy.py +27 -7
  7. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/ddapm_test_agent.egg-info/PKG-INFO +30 -2
  8. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/ddapm_test_agent.egg-info/SOURCES.txt +4 -0
  9. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/ddapm_test_agent.egg-info/requires.txt +4 -0
  10. ddapm_test_agent-1.36.0/releasenotes/notes/add-errors-intake-proxy-endpoint-7e0f31d72a130f1a.yaml +4 -0
  11. ddapm_test_agent-1.36.0/releasenotes/notes/named-pipe-ded0ebbbeee2e7fa.yaml +4 -0
  12. ddapm_test_agent-1.36.0/releasenotes/notes/vcr-custom-providers-map-a43b7e2d62d02015.yaml +6 -0
  13. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/riotfile.py +1 -0
  14. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/setup.py +1 -0
  15. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/test_deps.txt +1 -0
  16. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/tests/conftest.py +38 -17
  17. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/tests/test_agent.py +81 -0
  18. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/tests/test_container.py +18 -0
  19. ddapm_test_agent-1.36.0/tests/test_vcr_proxy.py +197 -0
  20. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/.dockerignore +0 -0
  21. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/.github/workflows/docker.yml +0 -0
  22. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/.github/workflows/publish_pypi.yml +0 -0
  23. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/.github/workflows/releasenote.yml +0 -0
  24. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/.gitignore +0 -0
  25. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/Dockerfile +0 -0
  26. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/Dockerfile.windows +0 -0
  27. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/LICENSE.BSD3 +0 -0
  28. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/LICENSE.apache2 +0 -0
  29. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/ddapm_test_agent/__init__.py +0 -0
  30. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/ddapm_test_agent/apmtelemetry.py +0 -0
  31. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/ddapm_test_agent/checks.py +0 -0
  32. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/ddapm_test_agent/client.py +0 -0
  33. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/ddapm_test_agent/cmd.py +0 -0
  34. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/ddapm_test_agent/context.py +0 -0
  35. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/ddapm_test_agent/fmt.py +0 -0
  36. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/ddapm_test_agent/integration.py +0 -0
  37. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/ddapm_test_agent/logs.py +0 -0
  38. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/ddapm_test_agent/metrics.py +0 -0
  39. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/ddapm_test_agent/remoteconfig.py +0 -0
  40. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/ddapm_test_agent/trace.py +0 -0
  41. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/ddapm_test_agent/trace_checks.py +0 -0
  42. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/ddapm_test_agent/tracerflare.py +0 -0
  43. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/ddapm_test_agent/tracestats.py +0 -0
  44. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/ddapm_test_agent/tracestats_snapshot.py +0 -0
  45. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/ddapm_test_agent.egg-info/dependency_links.txt +0 -0
  46. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/ddapm_test_agent.egg-info/entry_points.txt +0 -0
  47. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/ddapm_test_agent.egg-info/not-zip-safe +0 -0
  48. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/ddapm_test_agent.egg-info/top_level.txt +0 -0
  49. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/pyproject.toml +0 -0
  50. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/check-releasenotes +0 -0
  51. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/config.yaml +0 -0
  52. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/1.0-e192f5064e917083.yaml +0 -0
  53. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/Add-metrics.process_id-to-ignored-attributes-62b264f0ea591326.yaml +0 -0
  54. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/Add-values-handling-to-span_event-array_value-to-mirror-agent-ee7483c90c263ff4.yaml +0 -0
  55. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/Checks-changed-to-opt-in-8716cac4ecdbb1c2.yaml +0 -0
  56. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/SNAPSHOT_REGEX_PLACEHOLDERS-1d2c5e2711d1953b.yaml +0 -0
  57. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/SNAPSHOT_REGEX_PLACEHOLDERS-compare-c829e7a4df4fa1f4.yaml +0 -0
  58. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/Settings-endpoint-928ae5b6e8ddc625.yaml +0 -0
  59. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/Telemetry-requests-delay-2586180b286ce393.yaml +0 -0
  60. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/Use-default-value-for-null-fields-in-tracestats-55d465f489efb2ba.yaml +0 -0
  61. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/acceptV1TracePayloads-5435cff37cfb6a85.yaml +0 -0
  62. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/add-datadog-proxy-7e2e608c101a564b.yaml +0 -0
  63. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/add-distributed-trace-c35a314698a3b966.yaml +0 -0
  64. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/add-fmt-command-cc31769942a5fec3.yaml +0 -0
  65. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/add-nix-build-support-29dc8a347e3bd7c1.yaml +0 -0
  66. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/add-optional-json-parser-10aac54bd1cbe322.yaml +0 -0
  67. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/add-otel-metrics-support-a2ebeb28cae2f0ba.yaml +0 -0
  68. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/add-python-3.13-support-ae7b96f4a10f20f4.yaml +0 -0
  69. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/add-rcm-endpoints-7e1f949e83e21039.yaml +0 -0
  70. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/add-request-forwarding-middleware-d3f325166b0f8e9e.yaml +0 -0
  71. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/add-service-naming-checks-2b68ff51d1b5496d.yaml +0 -0
  72. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/add-session-to-rcm-endpoints-d97e925a04a99a65.yaml +0 -0
  73. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/add-span-events-306e697168373899.yaml +0 -0
  74. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/add-support-for-plain-text-responses-00d20bf7b335e75b.yaml +0 -0
  75. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/add-support-telemetry-requests-10737cd3da802ca6.yaml +0 -0
  76. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/add-tracer_flare-endpoint-b2c81510920974d7.yaml +0 -0
  77. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/addAgentStateToInfo-f9a179ce88f2ab9e.yaml +0 -0
  78. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/addPeerTagsToInfo-4ccc2539d22c2993.yaml +0 -0
  79. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/allow-attribute-removal-snapshots-314b744b043b97c5.yaml +0 -0
  80. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/args-88f664c83a96075d.yaml +0 -0
  81. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/change-trace-proxy-headers-f9fcbb4efc4fcb95.yaml +0 -0
  82. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/check-http-header-sensitivity-daaa9d9595ae86d6.yaml +0 -0
  83. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/clearing-sessions-now-only-removes-6b0311673d8b37aa.yaml +0 -0
  84. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/client-173dbc6655e42337.yaml +0 -0
  85. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/content_length-e1bab75580aa1dcb.yaml +0 -0
  86. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/disable-error-responses-and-collect-trace-failures-in-memory-4a199bc7be416709.yaml +0 -0
  87. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/docker-arm64-images-a4b6b2cc527327d6.yaml +0 -0
  88. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/evp-proxy-on-info-d65cd077575306ca.yaml +0 -0
  89. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/exception-messages-21ee64461020edd1.yaml +0 -0
  90. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/fix-docker-image-tags-785d40f5bfdb8003.yaml +0 -0
  91. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/fix-fmt-logging-6a323fd8d5d4eb28.yaml +0 -0
  92. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/fix-getting-tested-integrations-multiple-session-tokens-4ee41d545754f87f.yaml +0 -0
  93. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/fix-matching-319744b82d2514c1.yaml +0 -0
  94. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/fix-missing-slim-deps-fa3b0fc0292a09b3.yaml +0 -0
  95. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/fix-partial-chunks-0db14ce3017e6173.yaml +0 -0
  96. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/fix-racecondition-9bd0ef15b7da60fa.yaml +0 -0
  97. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/fix-tracerflare-request-parsing-fae18ff9997c216d.yaml +0 -0
  98. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/genai-vcr-support-b499ec54df84eaa3.yaml +0 -0
  99. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/ignore-dsm-pathway-hash-during-trace-snapshots-f0b99ea267fbad48.yaml +0 -0
  100. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/image-optimization-d614eccb59441217.yaml +0 -0
  101. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/improve-test-agent-debugging-5759413f1fc5f7fa.yaml +0 -0
  102. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/improve-test-agent-proxying-a207f0fc81b3ab2d.yaml +0 -0
  103. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/improve-trace-check-results-endpoints-6ab4132628520793.yaml +0 -0
  104. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/info-34dcd9cbcc382487.yaml +0 -0
  105. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/info-drop-p0s-c207889f590340fb.yaml +0 -0
  106. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/llmobs-eval-metric-endpoint-8b5222491969ab4f.yaml +0 -0
  107. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/llmobs-evp-proxy-1383f4b4962ac7c9.yaml +0 -0
  108. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/meta-struct-2cce08475cb05470.yaml +0 -0
  109. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/more-oai-cass-908eb5ea46bd2985.yaml +0 -0
  110. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/new-process-id-tag-f0ab0daf652e05cc.yaml +0 -0
  111. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/oai-incomplete-cass-795ad19b6a226c1f.yaml +0 -0
  112. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/otlp-logs-grpc-45365879c22969aa.yaml +0 -0
  113. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/otlp-logs-support-d5a150d9f5304d7c.yaml +0 -0
  114. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/pipeline_stats_endpoint-e8ad6da735dc2647.yaml +0 -0
  115. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/profiling-endpoint-0cd209e4e5b6cfc0.yaml +0 -0
  116. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/provider-snapshot-server-f6a307acbf11d214.yaml +0 -0
  117. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/proxy-37c94e2fb428c6fc.yaml +0 -0
  118. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/python-3.12-952e06c6158af67d.yaml +0 -0
  119. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/python-support-1c447acc4607abc7.yaml +0 -0
  120. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/python310-025fbc190363de98.yaml +0 -0
  121. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/python310-docker-image-d4e329cfecf6510e.yaml +0 -0
  122. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/rc-encoding-length-fix-cc011edea7f8f5b2.yaml +0 -0
  123. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/rc-get-endpoint-e502f55b7df544e2.yaml +0 -0
  124. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/remoteconfig-requests-1af7abb99c61c069.yaml +0 -0
  125. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/remove-agent-state-header-from-info-87f920bf4ce5785c.yaml +0 -0
  126. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/remove-nix-ec1c4aca7dc002c4.yaml +0 -0
  127. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/remove-old-pythons-4667b182aacf0ce6.yaml +0 -0
  128. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/reuse-session-1670aa569907cf68.yaml +0 -0
  129. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/sample-rate-1e06ae4cdc933b14.yaml +0 -0
  130. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/session-requests-b8057811f976220e.yaml +0 -0
  131. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/session-tracerflares-400ce9b3d3838b40.yaml +0 -0
  132. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/snapshot-cmds-de4a561911afee11.yaml +0 -0
  133. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/snapshot-empty-maps-2cbe8cea3e7112fa.yaml +0 -0
  134. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/snapshot-error-messages-de41d9e3207fa30a.yaml +0 -0
  135. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/snapshot-filename-c068de1bc3e50c04.yaml +0 -0
  136. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/snapshot-order-type-2d6424e380b2c88f.yaml +0 -0
  137. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/snapshot-parent-id-7abb860008702e70.yaml +0 -0
  138. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/span-links-1ec76bd2b47a3880.yaml +0 -0
  139. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/span-ordering-1a7b383aa015bddc.yaml +0 -0
  140. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/span-parent-id-a4d7d63fa623361c.yaml +0 -0
  141. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/support-ant-vcr-1eff9a40caa0aba0.yaml +0 -0
  142. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/support-tracking-of-tested-integrations-ac19ccd1f8333c00.yaml +0 -0
  143. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/throttling-590bf58ecb3cc4a5.yaml +0 -0
  144. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/trace-stats-97da3a478dabfa99.yaml +0 -0
  145. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/trace-stats-snapshot-718ca37385c93e1e.yaml +0 -0
  146. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/traces-endpoint-f4f9c1d94d6ceda2.yaml +0 -0
  147. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/tracestats-fixes-07152c708e73ef96.yaml +0 -0
  148. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/tracestats-post-65ce788f81862532.yaml +0 -0
  149. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/tracestats-service-2a0a178cbd21b07d.yaml +0 -0
  150. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/uds-64b11960931d8b77.yaml +0 -0
  151. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/uds-c99ea5d099e67156.yaml +0 -0
  152. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/uds-container-8138f8b1438b1a0a.yaml +0 -0
  153. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/uds-permissions-903266ac6445b873.yaml +0 -0
  154. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/v0.5-traces-cf469b0b71398d97.yaml +0 -0
  155. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/v0.7-traces-7ea3ebbed7502d01.yaml +0 -0
  156. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/vcr-aws-bedrock-proxy-3bf018b1712d5105.yaml +0 -0
  157. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/vcr-cassette-name-middleware-fix-9e47c395892a9fe7.yaml +0 -0
  158. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/vcr-cassettes-for-openai-v5-6e9d78091de1f0c2.yaml +0 -0
  159. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/vcr-cassettes-for-vercel-ai-7a8275f9c2b48bc7.yaml +0 -0
  160. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/vcr-ci-mode-99dbd2940fff8d7a.yaml +0 -0
  161. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/vcr-prefix-instead-of-suffix-4c56dcb5038d222e.yaml +0 -0
  162. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/vcr-proxy-aws-recalculation-fix-2184c10270a7bca5.yaml +0 -0
  163. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/vcr-proxy-use-test-name-bugfix-be758294ba30ac78.yaml +0 -0
  164. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/vcr-proxy-use-test-name-e47891994c961c52.yaml +0 -0
  165. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/vcr-support-querystring-b06555fb9a7c90ae.yaml +0 -0
  166. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/version-0c32d2752f154eb9.yaml +0 -0
  167. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/wheels-68a7dc2f4b00e0c4.yaml +0 -0
  168. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/releasenotes/notes/windows-docker-image-1f5d5e894558bb4b.yaml +0 -0
  169. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/setup.cfg +0 -0
  170. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/tests/__init__.py +0 -0
  171. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/tests/integration_snapshots/test_multi_trace.json +0 -0
  172. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/tests/integration_snapshots/test_single_trace.json +0 -0
  173. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/tests/integration_snapshots/test_trace_distributed_propagated.json +0 -0
  174. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/tests/integration_snapshots/test_trace_distributed_same_payload.json +0 -0
  175. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/tests/integration_snapshots/test_trace_missing_received.json +0 -0
  176. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/tests/integration_snapshots/test_trace_stats_tracestats.json +0 -0
  177. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/tests/test_apmtelemetry.py +0 -0
  178. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/tests/test_checks.py +0 -0
  179. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/tests/test_client.py +0 -0
  180. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/tests/test_logs.py +0 -0
  181. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/tests/test_metrics.py +0 -0
  182. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/tests/test_remoteconfig.py +0 -0
  183. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/tests/test_session.py +0 -0
  184. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/tests/test_snapshot.py +0 -0
  185. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/tests/test_snapshot_integration.py +0 -0
  186. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/tests/test_trace.py +0 -0
  187. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/tests/test_tracerflare.py +0 -0
  188. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/tests/test_tracestats.py +0 -0
  189. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/tests/trace_utils.py +0 -0
  190. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/anthropic/anthropic_v1_messages_post_26d618ee.yaml +0 -0
  191. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/anthropic/anthropic_v1_messages_post_595f439c.yaml +0 -0
  192. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/anthropic/anthropic_v1_messages_post_717ba0b4.yaml +0 -0
  193. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/anthropic/anthropic_v1_messages_post_a1af2c12.yaml +0 -0
  194. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/deepseek/deepseek_chat_completions_post_afb6ccab.yaml +0 -0
  195. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_audio_transcriptions_post_173af3e5.yaml +0 -0
  196. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_audio_transcriptions_post_71305a25.yaml +0 -0
  197. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_audio_translations_post_d5b5b8d6.yaml +0 -0
  198. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_audio_translations_post_dd92a18a.yaml +0 -0
  199. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_chat_completions_post_0f1514e1.yaml +0 -0
  200. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_chat_completions_post_172294b4.yaml +0 -0
  201. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_chat_completions_post_193ae44a.yaml +0 -0
  202. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_chat_completions_post_23558eed.yaml +0 -0
  203. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_chat_completions_post_2edb59ae.yaml +0 -0
  204. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_chat_completions_post_3517e44e.yaml +0 -0
  205. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_chat_completions_post_36bdc0cb.yaml +0 -0
  206. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_chat_completions_post_3c045664.yaml +0 -0
  207. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_chat_completions_post_432a8e46.yaml +0 -0
  208. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_chat_completions_post_4749eff9.yaml +0 -0
  209. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_chat_completions_post_4dce8db6.yaml +0 -0
  210. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_chat_completions_post_57612363.yaml +0 -0
  211. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_chat_completions_post_649d8162.yaml +0 -0
  212. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_chat_completions_post_655a8ef2.yaml +0 -0
  213. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_chat_completions_post_66dfc80e.yaml +0 -0
  214. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_chat_completions_post_67e8e833.yaml +0 -0
  215. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_chat_completions_post_6df851cc.yaml +0 -0
  216. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_chat_completions_post_7c2d1ac5.yaml +0 -0
  217. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_chat_completions_post_82a4bb3c.yaml +0 -0
  218. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_chat_completions_post_9122b1ae.yaml +0 -0
  219. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_chat_completions_post_917478d0.yaml +0 -0
  220. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_chat_completions_post_a73ecd7a.yaml +0 -0
  221. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_chat_completions_post_a925b737.yaml +0 -0
  222. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_chat_completions_post_ae4728c2.yaml +0 -0
  223. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_chat_completions_post_b29f1a87.yaml +0 -0
  224. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_chat_completions_post_ce69ed91.yaml +0 -0
  225. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_chat_completions_post_d8fb132a.yaml +0 -0
  226. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_chat_completions_post_d94d5844.yaml +0 -0
  227. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_chat_completions_post_d98ce00d.yaml +0 -0
  228. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_chat_completions_post_ebff79da.yaml +0 -0
  229. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_completions_post_33681ea4.yaml +0 -0
  230. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_completions_post_5d2418d4.yaml +0 -0
  231. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_completions_post_619dee1c.yaml +0 -0
  232. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_completions_post_6224acff.yaml +0 -0
  233. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_completions_post_87f617af.yaml +0 -0
  234. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_completions_post_98c30019.yaml +0 -0
  235. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_completions_post_9bb49464.yaml +0 -0
  236. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_completions_post_b24dbf7d.yaml +0 -0
  237. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_embeddings_post_0381abe4.yaml +0 -0
  238. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_embeddings_post_48694087.yaml +0 -0
  239. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_embeddings_post_541bd4d0.yaml +0 -0
  240. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_files_file-RpTpuvRVtnKpdKZb7DDGto_content_get_60bd10ef.yaml +0 -0
  241. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_files_file-RpTpuvRVtnKpdKZb7DDGto_delete_3ee48409.yaml +0 -0
  242. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_files_file-RpTpuvRVtnKpdKZb7DDGto_get_1afefb93.yaml +0 -0
  243. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_files_get_68efa25d.yaml +0 -0
  244. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_files_post_2fcf9545.yaml +0 -0
  245. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_files_post_957d63ba.yaml +0 -0
  246. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_fine_tuning_jobs_ftjob-q9CUUUsHJemGUVQ1Ecc01zcf_cancel_post_d7c16b38.yaml +0 -0
  247. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_fine_tuning_jobs_ftjob-q9CUUUsHJemGUVQ1Ecc01zcf_events_get_557d820e.yaml +0 -0
  248. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_fine_tuning_jobs_ftjob-q9CUUUsHJemGUVQ1Ecc01zcf_get_265489e7.yaml +0 -0
  249. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_fine_tuning_jobs_get_ebc57c6f.yaml +0 -0
  250. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_fine_tuning_jobs_post_c3b6e4a9.yaml +0 -0
  251. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_images_edits_post_075386c4.yaml +0 -0
  252. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_images_edits_post_57b4f4da.yaml +0 -0
  253. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_images_edits_post_660e9dd7.yaml +0 -0
  254. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_images_edits_post_993e0192.yaml +0 -0
  255. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_images_edits_post_a2f1eb43.yaml +0 -0
  256. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_images_edits_post_ae72c45f.yaml +0 -0
  257. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_images_edits_post_cf5af376.yaml +0 -0
  258. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_images_edits_post_dbefb624.yaml +0 -0
  259. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_images_generations_post_48272841.yaml +0 -0
  260. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_images_generations_post_736070ea.yaml +0 -0
  261. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_images_variations_post_5971e285.yaml +0 -0
  262. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_images_variations_post_f2f62f6c.yaml +0 -0
  263. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_models_ft_gpt-4.1-mini-2025-04-14_datadog-staging__BkaILRSh_delete_c70f2992.yaml +0 -0
  264. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_models_get_e04cf04b.yaml +0 -0
  265. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_models_gpt-4_get_b13c5b23.yaml +0 -0
  266. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_moderations_post_532b3315.yaml +0 -0
  267. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_responses_post_33fb1f66.yaml +0 -0
  268. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_responses_post_5ca556ec.yaml +0 -0
  269. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_responses_post_c05c936e.yaml +0 -0
  270. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.0}/vcr-cassettes/openai/openai_responses_post_c61e3067.yaml +0 -0
  271. {ddapm_test_agent-1.34.0 → ddapm_test_agent-1.36.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@7f4fc3e22c37d6ff65e88745f38bd3157c663f7c # v4.9.1
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
- - run: |
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.34.0
3
+ Version: 1.36.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 DeepSeek.
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 DeepSeek.
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."""
@@ -274,6 +329,7 @@ class Agent:
274
329
  "/evp_proxy/v2/api/v2/llmobs",
275
330
  "/evp_proxy/v2/api/intake/llm-obs/v1/eval-metric",
276
331
  "/evp_proxy/v2/api/intake/llm-obs/v2/eval-metric",
332
+ "/evp_proxy/v4/api/v2/errorsintake",
277
333
  ]
278
334
 
279
335
  # Note that sessions are not cleared at any point since we don't know
@@ -746,6 +802,9 @@ class Agent:
746
802
  async def handle_evp_proxy_v2_llmobs_eval_metric(self, request: Request) -> web.Response:
747
803
  return web.HTTPOk()
748
804
 
805
+ async def handle_evp_proxy_v4_api_v2_errorsintake(self, request: Request) -> web.Response:
806
+ return web.HTTPOk()
807
+
749
808
  async def handle_put_tested_integrations(self, request: Request) -> web.Response:
750
809
  # we need to store the request manually since this is not a real DD agent endpoint
751
810
  await self._store_request(request)
@@ -823,6 +882,7 @@ class Agent:
823
882
  "/v0.7/config",
824
883
  "/tracer_flare/v1",
825
884
  "/evp_proxy/v2/",
885
+ "/evp_proxy/v4/",
826
886
  ],
827
887
  "feature_flags": [],
828
888
  "config": {},
@@ -1069,6 +1129,7 @@ class Agent:
1069
1129
  self.handle_v1_tracer_flare,
1070
1130
  self.handle_evp_proxy_v2_api_v2_llmobs,
1071
1131
  self.handle_evp_proxy_v2_llmobs_eval_metric,
1132
+ self.handle_evp_proxy_v4_api_v2_errorsintake,
1072
1133
  self.handle_v1_logs,
1073
1134
  self.handle_v1_metrics,
1074
1135
  ):
@@ -1287,6 +1348,175 @@ class Agent:
1287
1348
  raise web.HTTPBadRequest(body=msg)
1288
1349
  return response
1289
1350
 
1351
+ def _parse_http_request(self, data: bytes) -> tuple[str, str, Dict[str, str], bytes]:
1352
+ """Parse HTTP request from raw bytes.
1353
+
1354
+ Returns:
1355
+ tuple: (method, path, headers_dict, body)
1356
+ """
1357
+ try:
1358
+ # Split request into headers and body
1359
+ if b"\r\n\r\n" in data:
1360
+ header_data, body = data.split(b"\r\n\r\n", 1)
1361
+ else:
1362
+ header_data, body = data, b""
1363
+
1364
+ # Parse headers
1365
+ header_lines = header_data.decode("utf-8", errors="ignore").split("\r\n")
1366
+ if not header_lines:
1367
+ raise ValueError("No request line found")
1368
+
1369
+ # Parse request line (e.g., "POST /v0.4/traces HTTP/1.1")
1370
+ request_line = header_lines[0]
1371
+ parts = request_line.split(" ")
1372
+ if len(parts) < 2:
1373
+ raise ValueError(f"Invalid request line: {request_line}")
1374
+
1375
+ method = parts[0]
1376
+ path = parts[1]
1377
+
1378
+ # Parse headers
1379
+ headers: Dict[str, str] = {}
1380
+ for line in header_lines[1:]:
1381
+ if ":" in line:
1382
+ key, value = line.split(":", 1)
1383
+ headers[key.strip()] = value.strip()
1384
+
1385
+ return method, path, headers, body
1386
+
1387
+ except Exception as e:
1388
+ log.error(f"Error parsing HTTP request: {e}")
1389
+ raise ValueError(f"Failed to parse HTTP request: {e}") from e
1390
+
1391
+ def _process_named_pipe_request(self, data: bytes, app: web.Application) -> bytes:
1392
+ """Process a request using the existing Agent infrastructure."""
1393
+ try:
1394
+ # Parse the HTTP request
1395
+ method, path, headers, body = self._parse_http_request(data)
1396
+
1397
+ log.info(f"Processing Named Pipe request: {method} {path}")
1398
+
1399
+ # Create a mock Request object
1400
+ mock_request = MockRequest(method, path, headers, body, self, app)
1401
+
1402
+ # Extract session token like the middleware does
1403
+ token = None
1404
+ if "X-Datadog-Test-Session-Token" in headers:
1405
+ token = headers["X-Datadog-Test-Session-Token"]
1406
+ mock_request["session_token"] = token
1407
+
1408
+ # Store request data for agent processing
1409
+ mock_request["_testagent_data"] = body
1410
+
1411
+ # Route to appropriate handler based on path using dictionary lookup
1412
+ path_handlers = {
1413
+ "/v0.4/traces": self.handle_v04_traces,
1414
+ "/v0.5/traces": self.handle_v05_traces,
1415
+ "/v0.7/traces": self.handle_v07_traces,
1416
+ "/v1.0/traces": self.handle_v1_traces,
1417
+ "/v0.6/stats": self.handle_v06_tracestats,
1418
+ "/v0.1/pipeline_stats": self.handle_v01_pipelinestats,
1419
+ "/v0.7/config": self.handle_v07_remoteconfig,
1420
+ "/telemetry/proxy/api/v2/apmtelemetry": self.handle_v2_apmtelemetry,
1421
+ "/profiling/v1/input": self.handle_v1_profiling,
1422
+ "/tracer_flare/v1": self.handle_v1_tracer_flare,
1423
+ "/evp_proxy/v2/api/v2/llmobs": self.handle_evp_proxy_v2_api_v2_llmobs,
1424
+ "/evp_proxy/v2/api/intake/llm-obs/v1/eval-metric": self.handle_evp_proxy_v2_llmobs_eval_metric,
1425
+ "/evp_proxy/v2/api/intake/llm-obs/v2/eval-metric": self.handle_evp_proxy_v2_llmobs_eval_metric,
1426
+ "/evp_proxy/v4/api/v2/errorsintake": self.handle_evp_proxy_v4_api_v2_errorsintake,
1427
+ "/info": self.handle_info,
1428
+ # Test endpoints
1429
+ "/test/session/start": self.handle_session_start,
1430
+ "/test/session/clear": self.handle_session_clear,
1431
+ "/test/session/snapshot": self.handle_snapshot,
1432
+ "/test/session/traces": self.handle_session_traces,
1433
+ "/test/session/apmtelemetry": self.handle_session_apmtelemetry,
1434
+ "/test/session/tracerflares": self.handle_session_tracerflares,
1435
+ "/test/session/stats": self.handle_session_tracestats,
1436
+ "/test/session/requests": self.handle_session_requests,
1437
+ "/test/session/responses/config": self.handle_v07_remoteconfig_create,
1438
+ "/test/session/responses/config/path": self.handle_v07_remoteconfig_path_create,
1439
+ "/test/traces": self.handle_test_traces,
1440
+ "/test/apmtelemetry": self.handle_test_apmtelemetry,
1441
+ "/test/trace/analyze": self.handle_trace_analyze,
1442
+ "/test/trace_check/failures": self.get_trace_check_failures,
1443
+ "/test/trace_check/clear": self.clear_trace_check_failures,
1444
+ "/test/trace_check/summary": self.get_trace_check_summary,
1445
+ "/test/integrations/tested_versions": self.handle_get_tested_integrations,
1446
+ "/test/settings": self.handle_settings,
1447
+ }
1448
+
1449
+ # Get handler from dictionary lookup
1450
+ handler = path_handlers.get(path)
1451
+ if not handler:
1452
+ return self._create_error_response(404, "Not Found")
1453
+
1454
+ try:
1455
+ # Create a new event loop for this thread if one doesn't exist
1456
+ loop = asyncio.get_event_loop()
1457
+ except RuntimeError:
1458
+ loop = asyncio.new_event_loop()
1459
+ asyncio.set_event_loop(loop)
1460
+
1461
+ # Initialize the CheckTrace context like middleware does
1462
+ start_trace("named_pipe_request %s %s" % (method, path))
1463
+
1464
+ # Run the handler
1465
+ response = loop.run_until_complete(handler(mock_request)) # type: ignore[arg-type]
1466
+
1467
+ # Convert aiohttp response to HTTP bytes
1468
+ return self._convert_response_to_http(response)
1469
+
1470
+ except Exception as e:
1471
+ log.error(f"Error processing Named Pipe request: {e}", exc_info=True)
1472
+ return self._create_error_response(500, "Internal Server Error")
1473
+
1474
+ def _convert_response_to_http(self, response: web.Response) -> bytes:
1475
+ """Convert aiohttp Response to HTTP response bytes."""
1476
+ try:
1477
+ # Build HTTP response
1478
+ status_line = f"HTTP/1.1 {response.status} {response.reason}\r\n"
1479
+
1480
+ # Build headers
1481
+ headers_lines = []
1482
+ for key, value in response.headers.items():
1483
+ headers_lines.append(f"{key}: {value}\r\n")
1484
+
1485
+ # Get response body
1486
+ body_data: bytes
1487
+ if hasattr(response, "body") and response.body:
1488
+ if isinstance(response.body, bytes):
1489
+ body_data = response.body
1490
+ elif isinstance(response.body, str):
1491
+ body_data = response.body.encode()
1492
+ else:
1493
+ # Handle Payload or other types by converting to string first
1494
+ body_data = str(response.body).encode()
1495
+ else:
1496
+ body_data = b""
1497
+
1498
+ # Add Content-Length header if not present
1499
+ if "Content-Length" not in response.headers:
1500
+ headers_lines.append(f"Content-Length: {len(body_data)}\r\n")
1501
+
1502
+ # Combine all parts
1503
+ headers_str = "".join(headers_lines)
1504
+ http_response = status_line + headers_str + "\r\n"
1505
+ return http_response.encode("utf-8") + body_data
1506
+
1507
+ except Exception as e:
1508
+ log.error(f"Error converting response to HTTP: {e}")
1509
+ return self._create_error_response(500, "Internal Server Error")
1510
+
1511
+ def _create_error_response(self, status_code: int, reason: str) -> bytes:
1512
+ """Create an HTTP error response."""
1513
+ body = f"{status_code} {reason}".encode("utf-8")
1514
+ response = f"HTTP/1.1 {status_code} {reason}\r\n"
1515
+ response += f"Content-Length: {len(body)}\r\n"
1516
+ response += "Content-Type: text/plain\r\n"
1517
+ response += "\r\n"
1518
+ return response.encode("utf-8") + body
1519
+
1290
1520
 
1291
1521
  def make_otlp_http_app(agent: Agent) -> web.Application:
1292
1522
  """Create a separate HTTP application for OTLP endpoints using the shared agent instance."""
@@ -1356,6 +1586,8 @@ def make_app(
1356
1586
  snapshot_regex_placeholders: Dict[str, str],
1357
1587
  vcr_cassettes_directory: str,
1358
1588
  vcr_ci_mode: bool,
1589
+ vcr_provider_map: str,
1590
+ vcr_ignore_headers: str,
1359
1591
  ) -> web.Application:
1360
1592
  agent = Agent()
1361
1593
  app = web.Application(
@@ -1390,6 +1622,7 @@ def make_app(
1390
1622
  web.post("/evp_proxy/v2/api/v2/llmobs", agent.handle_evp_proxy_v2_api_v2_llmobs),
1391
1623
  web.post("/evp_proxy/v2/api/intake/llm-obs/v1/eval-metric", agent.handle_evp_proxy_v2_llmobs_eval_metric),
1392
1624
  web.post("/evp_proxy/v2/api/intake/llm-obs/v2/eval-metric", agent.handle_evp_proxy_v2_llmobs_eval_metric),
1625
+ web.post("/evp_proxy/v4/api/v2/errorsintake", agent.handle_evp_proxy_v4_api_v2_errorsintake),
1393
1626
  web.get("/info", agent.handle_info),
1394
1627
  web.get("/test/session/start", agent.handle_session_start),
1395
1628
  web.get("/test/session/clear", agent.handle_session_clear),
@@ -1417,7 +1650,9 @@ def make_app(
1417
1650
  web.route(
1418
1651
  "*",
1419
1652
  "/vcr/{path:.*}",
1420
- lambda request: proxy_request(request, vcr_cassettes_directory, vcr_ci_mode),
1653
+ lambda request: proxy_request(
1654
+ request, vcr_cassettes_directory, vcr_ci_mode, vcr_provider_map, vcr_ignore_headers
1655
+ ),
1421
1656
  ),
1422
1657
  ]
1423
1658
  )
@@ -1449,6 +1684,137 @@ def make_app(
1449
1684
  return app
1450
1685
 
1451
1686
 
1687
+ def _start_named_pipe_server(pipe_path: str, agent: "Agent", app: web.Application) -> None:
1688
+ """Start Windows named pipe server."""
1689
+ if platform.system() != "Windows":
1690
+ log.warning("Named pipes are only supported on Windows, ignoring --trace-named-pipe")
1691
+ return
1692
+
1693
+ # Import Windows-specific modules here to avoid import errors on other platforms
1694
+ try:
1695
+ import win32file
1696
+ import win32pipe
1697
+ except ImportError as e:
1698
+ log.error(f"Failed to import Windows modules for named pipes: {e}")
1699
+ return
1700
+
1701
+ _start_windows_named_pipe_server(pipe_path, agent, app, win32pipe, win32file)
1702
+
1703
+
1704
+ def _create_and_wait_for_client(
1705
+ pipe_path: str, agent: "Agent", app: web.Application, win32pipe: Any, win32file: Any
1706
+ ) -> None:
1707
+ """Create a single pipe instance and wait for a client connection."""
1708
+ while True:
1709
+ try:
1710
+ # Create named pipe instance
1711
+ pipe_handle = win32pipe.CreateNamedPipe(
1712
+ pipe_path,
1713
+ win32pipe.PIPE_ACCESS_DUPLEX,
1714
+ win32pipe.PIPE_TYPE_MESSAGE | win32pipe.PIPE_READMODE_MESSAGE | win32pipe.PIPE_WAIT,
1715
+ win32pipe.PIPE_UNLIMITED_INSTANCES, # allow multiple concurrent connections
1716
+ 65536, # output buffer size
1717
+ 65536, # input buffer size
1718
+ 0, # default timeout
1719
+ None, # security attributes
1720
+ )
1721
+
1722
+ if pipe_handle == win32file.INVALID_HANDLE_VALUE:
1723
+ log.error("Failed to create named pipe instance")
1724
+ import time
1725
+
1726
+ time.sleep(1) # Wait before retrying
1727
+ continue
1728
+
1729
+ log.debug("Named pipe instance created, waiting for client...")
1730
+
1731
+ # Wait for client connection
1732
+ win32pipe.ConnectNamedPipe(pipe_handle, None)
1733
+ log.info("Client connected to named pipe instance")
1734
+
1735
+ # Handle the client request
1736
+ _handle_windows_named_pipe_client(pipe_handle, agent, app, win32pipe, win32file)
1737
+
1738
+ except Exception as e:
1739
+ log.error(f"Error in named pipe instance: {e}")
1740
+ import time
1741
+
1742
+ time.sleep(1) # Wait before retrying
1743
+
1744
+
1745
+ def _start_windows_named_pipe_server(
1746
+ pipe_path: str, agent: "Agent", app: web.Application, win32pipe: Any, win32file: Any
1747
+ ) -> None:
1748
+ """Start a Windows named pipe server with multiple instances."""
1749
+ if win32pipe is None:
1750
+ log.error("Windows named pipe support not available (pywin32 not installed)")
1751
+ return
1752
+
1753
+ log.info(f"Starting Windows named pipe server on: {pipe_path}")
1754
+
1755
+ # Create multiple pipe instances for better concurrency
1756
+ num_instances = 10 # Support up to 10 concurrent connections
1757
+ threads = []
1758
+
1759
+ for _ in range(num_instances):
1760
+ thread = threading.Thread(
1761
+ target=_create_and_wait_for_client, args=(pipe_path, agent, app, win32pipe, win32file), daemon=True
1762
+ )
1763
+ thread.start()
1764
+ threads.append(thread)
1765
+
1766
+ log.info(f"Started {num_instances} named pipe instances")
1767
+
1768
+ # Keep the main thread alive and monitor instance threads
1769
+ try:
1770
+ while True:
1771
+ import time
1772
+
1773
+ time.sleep(5)
1774
+
1775
+ # Check if any threads have died and restart them
1776
+ for i, thread in enumerate(threads):
1777
+ if not thread.is_alive():
1778
+ log.warning(f"Restarting named pipe instance {i}")
1779
+ new_thread = threading.Thread(
1780
+ target=_create_and_wait_for_client,
1781
+ args=(pipe_path, agent, app, win32pipe, win32file),
1782
+ daemon=True,
1783
+ )
1784
+ new_thread.start()
1785
+ threads[i] = new_thread
1786
+
1787
+ except KeyboardInterrupt:
1788
+ log.info("Named pipe server shutting down")
1789
+
1790
+
1791
+ def _handle_windows_named_pipe_client(
1792
+ pipe_handle: Any, agent: "Agent", app: web.Application, win32pipe: Any, win32file: Any
1793
+ ) -> None:
1794
+ """Handle a Windows named pipe client connection."""
1795
+ try:
1796
+ # Read request data
1797
+ result, data = win32file.ReadFile(pipe_handle, 65536)
1798
+ if result == 0: # SUCCESS
1799
+ log.info(f"Received {len(data)} bytes from named pipe client")
1800
+
1801
+ # Process request
1802
+ response = agent._process_named_pipe_request(data, app)
1803
+
1804
+ # Write response
1805
+ win32file.WriteFile(pipe_handle, response)
1806
+ log.info(f"Sent {len(response)} bytes response to named pipe client")
1807
+
1808
+ except Exception as e:
1809
+ log.error(f"Error handling Windows named pipe client: {e}")
1810
+ finally:
1811
+ try:
1812
+ win32pipe.DisconnectNamedPipe(pipe_handle)
1813
+ win32file.CloseHandle(pipe_handle)
1814
+ except Exception:
1815
+ pass
1816
+
1817
+
1452
1818
  def main(args: Optional[List[str]] = None) -> None:
1453
1819
  if args is None:
1454
1820
  args = sys.argv[1:]
@@ -1550,6 +1916,12 @@ def main(args: Optional[List[str]] = None) -> None:
1550
1916
  default=os.environ.get("DD_APM_RECEIVER_SOCKET", None),
1551
1917
  help=("Will listen for traces on the specified socket path"),
1552
1918
  )
1919
+ parser.add_argument(
1920
+ "--trace-named-pipe",
1921
+ type=str,
1922
+ default=os.environ.get("DD_APM_RECEIVER_NAMED_PIPE", None),
1923
+ help=("Will listen for traces on the specified named pipe path"),
1924
+ )
1553
1925
  parser.add_argument(
1554
1926
  "--trace-request-delay",
1555
1927
  type=float,
@@ -1588,6 +1960,18 @@ def main(args: Optional[List[str]] = None) -> None:
1588
1960
  default=os.environ.get("VCR_CI_MODE", False),
1589
1961
  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
1962
  )
1963
+ parser.add_argument(
1964
+ "--vcr-provider-map",
1965
+ type=str,
1966
+ default=os.environ.get("VCR_PROVIDER_MAP", ""),
1967
+ help="Comma-separated list of provider=base_url tuples to map providers to paths. Used in addition to the default provider paths.",
1968
+ )
1969
+ parser.add_argument(
1970
+ "--vcr-ignore-headers",
1971
+ type=str,
1972
+ default=os.environ.get("VCR_IGNORE_HEADERS", ""),
1973
+ help="Comma-separated list of headers to ignore when recording VCR cassettes.",
1974
+ )
1591
1975
  parsed_args = parser.parse_args(args=args)
1592
1976
  logging.basicConfig(level=parsed_args.log_level)
1593
1977
 
@@ -1632,6 +2016,8 @@ def main(args: Optional[List[str]] = None) -> None:
1632
2016
  snapshot_regex_placeholders=parsed_args.snapshot_regex_placeholders,
1633
2017
  vcr_cassettes_directory=parsed_args.vcr_cassettes_directory,
1634
2018
  vcr_ci_mode=parsed_args.vcr_ci_mode,
2019
+ vcr_provider_map=parsed_args.vcr_provider_map,
2020
+ vcr_ignore_headers=parsed_args.vcr_ignore_headers,
1635
2021
  )
1636
2022
 
1637
2023
  # Validate port configuration
@@ -1644,6 +2030,18 @@ def main(args: Optional[List[str]] = None) -> None:
1644
2030
 
1645
2031
  # Get the shared agent instance from the main app
1646
2032
  agent = app["agent"]
2033
+
2034
+ # Named pipe setup (after agent is available)
2035
+ named_pipe_thread = None
2036
+ if parsed_args.trace_named_pipe is not None:
2037
+
2038
+ def start_named_pipe_server():
2039
+ _start_named_pipe_server(parsed_args.trace_named_pipe, agent, app)
2040
+
2041
+ named_pipe_thread = threading.Thread(target=start_named_pipe_server, daemon=True)
2042
+ named_pipe_thread.start()
2043
+ log.info(f"Started named pipe server on: {parsed_args.trace_named_pipe}")
2044
+
1647
2045
  otlp_http_app = make_otlp_http_app(agent)
1648
2046
 
1649
2047
  async def run_servers():