diff --git a/internal-api/src/test/java/datadog/trace/api/TagConstantsRegistryCoverageTest.java b/internal-api/src/test/java/datadog/trace/api/TagConstantsRegistryCoverageTest.java index 9a0cc104520..2129b6f184f 100644 --- a/internal-api/src/test/java/datadog/trace/api/TagConstantsRegistryCoverageTest.java +++ b/internal-api/src/test/java/datadog/trace/api/TagConstantsRegistryCoverageTest.java @@ -73,25 +73,9 @@ class TagConstantsRegistryCoverageTest { NEVER_REGISTERED.put("Tags.SPAN_KIND_*", "values of span.kind"); } - /** Families not registered yet, with the reason. */ + /** Families not registered yet, with the reason. Empty: every family is registered. */ static final Map NOT_YET_REGISTERED_FAMILIES = new TreeMap<>(); - static { - NOT_YET_REGISTERED_FAMILIES.put("Tags.OS_*", "CI Visibility, in a follow-up PR"); - NOT_YET_REGISTERED_FAMILIES.put("Tags.RUNTIME_*", "CI Visibility, in a follow-up PR"); - NOT_YET_REGISTERED_FAMILIES.put("DDTags.HOST_VCPU_COUNT", "CI Visibility, in a follow-up PR"); - NOT_YET_REGISTERED_FAMILIES.put( - "DDTags.LIBRARY_VERSION_TAG_KEY", "CI Visibility, in a follow-up PR"); - NOT_YET_REGISTERED_FAMILIES.put("Tags.ITR_CORRELATION_ID", "CI Visibility, in a follow-up PR"); - NOT_YET_REGISTERED_FAMILIES.put("Tags.PULL_REQUEST_NUMBER", "CI Visibility, in a follow-up PR"); - NOT_YET_REGISTERED_FAMILIES.put("DDTags.CI_*", "CI Visibility, in a follow-up PR"); - NOT_YET_REGISTERED_FAMILIES.put("DDTags.TEST_*", "CI Visibility, in a follow-up PR"); - NOT_YET_REGISTERED_FAMILIES.put("Tags.CI_*", "CI Visibility, in a follow-up PR"); - NOT_YET_REGISTERED_FAMILIES.put( - "Tags.GIT_*", "CI Visibility and source code metadata, in a follow-up PR"); - NOT_YET_REGISTERED_FAMILIES.put("Tags.TEST_*", "CI Visibility, in a follow-up PR"); - } - /** * Single constants not registered yet. Remove an entry when its tag is registered. Empty: every * constant outside the families above is registered or deliberately never registered. diff --git a/tag-conventions-java.yaml b/tag-conventions-java.yaml index f853c33adab..8a53268f16d 100644 --- a/tag-conventions-java.yaml +++ b/tag-conventions-java.yaml @@ -138,6 +138,44 @@ span_types: - { dd-name: hystrix.group, type: string, required: optional } - { dd-name: hystrix.circuit-open, type: boolean, required: optional } + # Gradle and Maven specifics on CI Visibility's session and module spans. + test.gradle.session: + extends: test.session + tags: + - { dd-name: test.gradle.nested_build, type: boolean, required: optional } + - { dd-name: test.is_android, type: boolean, required: optional } + + test.gradle.module: + extends: test.module + tags: + - { ref: test.is_android } + + test.maven.module: + extends: test.module + tags: + - { dd-name: test.execution, type: string, required: recommended } # artifactId:goal:executionId + + # An Android test run under Robolectric. + test.android: + extends: test + tags: + - { dd-name: test.android.api_level, type: int, required: optional } + - { dd-name: test.android.release, type: string, required: optional } + - { dd-name: test.android.codename, type: string, required: optional } + - { dd-name: test.android.robolectric.version, type: string, required: optional } + + # A JUnit 5 test, which may be a dynamic test. + test.junit5: + extends: test + tags: + - { dd-name: test.junit5.is_dynamic, type: boolean, required: optional } + + # JUnit's before and after callbacks (span.kind unset). + junit.callback: + extends: internal + tags: + - { dd-name: test.callback, type: string, required: recommended } # Before, AfterAll, ... + tags: - { dd-name: resource.name, type: string } - { dd-name: span.type, type: string } diff --git a/tag-conventions.yaml b/tag-conventions.yaml index d2579b5fe74..516ba791b74 100644 --- a/tag-conventions.yaml +++ b/tag-conventions.yaml @@ -312,6 +312,163 @@ span_types: span-kind: server include: [ peer_address, inbound_peer ] + # CI Visibility: one span per test session, module, suite and test. Their span.kind is + # test_session_end, test_module_end, test_suite_end or test, none of which has a direction. + # Standard enrichment (TestDecoratorImpl.afterStart) puts the CI environment on every one of them, + # so its tags are recommended. A test span carries more tags than the dense store has slots; tags + # set only some of the time stay optional, and those share slots so the recommended ones don't. + ci.span: + abstract: true + extends: base + tags: + - { dd-name: test_session.name, type: string, required: required } + - { dd-name: test.type, type: string, required: required } # "browser" on Selenium tests + - { dd-name: test.status, type: string, required: required } + - { dd-name: test.framework, type: string, required: recommended } + - { dd-name: test.framework_version, type: string, required: recommended } + - { dd-name: test_session_id, type: long, required: required } # hoisted to a top-level field by the CI intake mapper + - { dd-name: _dd.host.vcpu_count, type: int, required: recommended } + - { dd-name: _dd.ci.env_vars, type: string, required: recommended } + - { dd-name: library_version, type: string, required: recommended } # every span of a CI trace + # the CI provider and the commit, from the environment + - { dd-name: ci.provider.name, type: string, required: recommended } + - { dd-name: ci.pipeline.id, type: string, required: recommended } + - { dd-name: ci.pipeline.name, type: string, required: recommended } + - { dd-name: ci.pipeline.display_name, type: string, required: recommended } + - { dd-name: ci.pipeline.number, type: string, required: recommended } + - { dd-name: ci.pipeline.url, type: string, required: recommended } + - { dd-name: ci.stage.name, type: string, required: recommended } + - { dd-name: ci.job.id, type: string, required: recommended } + - { dd-name: ci.job.name, type: string, required: recommended } + - { dd-name: ci.job.url, type: string, required: recommended } + - { dd-name: ci.workspace_path, type: string, required: recommended } + - { dd-name: ci.node.name, type: string, required: recommended } + - { dd-name: ci.node.labels, type: string, required: recommended } + - { dd-name: git.repository_url, type: string, required: recommended } + - { dd-name: git.commit.sha, type: string, required: recommended } + - { dd-name: git.branch, type: string, required: recommended } + - { dd-name: git.tag, type: string, required: recommended } + - { dd-name: git.commit.author.name, type: string, required: recommended } + - { dd-name: git.commit.author.email, type: string, required: recommended } + - { dd-name: git.commit.author.date, type: string, required: recommended } + - { dd-name: git.commit.committer.name, type: string, required: recommended } + - { dd-name: git.commit.committer.email, type: string, required: recommended } + - { dd-name: git.commit.committer.date, type: string, required: recommended } + - { dd-name: git.commit.message, type: string, required: recommended } + # pull request builds only + - { dd-name: git.pull_request.base_branch, type: string, required: optional } + - { dd-name: git.pull_request.base_branch_sha, type: string, required: optional } + - { dd-name: git.pull_request.base_branch_head_sha, type: string, required: optional } + - { dd-name: git.commit.head.sha, type: string, required: optional } + - { dd-name: git.commit.head.author.name, type: string, required: optional } + - { dd-name: git.commit.head.author.email, type: string, required: optional } + - { dd-name: git.commit.head.author.date, type: string, required: optional } + - { dd-name: git.commit.head.committer.name, type: string, required: optional } + - { dd-name: git.commit.head.committer.email, type: string, required: optional } + - { dd-name: git.commit.head.committer.date, type: string, required: optional } + - { dd-name: git.commit.head.message, type: string, required: optional } + - { dd-name: pr.number, type: string, required: optional } + - { dd-name: test.skip_reason, type: string, required: optional } + - { dd-name: test.itr.tests_skipping.enabled, type: boolean, required: optional } + # when fetching that part of the library configuration failed + - { dd-name: _dd.ci.library_configuration_error.settings, type: boolean, required: optional } + - { dd-name: _dd.ci.library_configuration_error.skippable_tests, type: boolean, required: optional } + - { dd-name: _dd.ci.library_configuration_error.flaky_tests, type: boolean, required: optional } + - { dd-name: _dd.ci.library_configuration_error.known_tests, type: boolean, required: optional } + - { dd-name: _dd.ci.library_configuration_error.test_management_tests, type: boolean, required: optional } + + # Session and module spans: what a build-system run aggregates. + ci.aggregate: + abstract: true + extends: ci.span + tags: + - { dd-name: test.command, type: string, required: recommended } + - { dd-name: test.code_coverage.enabled, type: boolean, required: optional } + - { dd-name: test.code_coverage.lines_pct, type: long, required: optional } + - { dd-name: test.code_coverage.backfilled, type: boolean, required: optional } + - { dd-name: test.itr.tests_skipping.type, type: string, required: optional } + - { dd-name: test.itr.tests_skipping.count, type: long, required: optional } + - { dd-name: test.early_flake.enabled, type: boolean, required: optional } + - { dd-name: test.early_flake.abort_reason, type: string, required: optional } + - { dd-name: test.test_management.enabled, type: boolean, required: optional } + - { dd-name: _dd.ci.itr.tests_skipped, type: boolean, required: optional } + - { dd-name: _dd.test.has_failed_test_replay, type: boolean, required: optional } + + test.session: + extends: ci.aggregate + tags: + - { dd-name: test.toolchain, type: string, required: optional } # build-system sessions + + test.module: + extends: ci.aggregate + tags: + - { dd-name: test.module, type: string, required: required } + - { dd-name: test_module_id, type: long, required: required } + + test.suite: + extends: ci.span + tags: + - { ref: test.module } + - { ref: test_module_id } + - { dd-name: test.suite, type: string, required: required } + - { dd-name: test_suite_id, type: long, required: required } + - { dd-name: test.source.file, type: string, required: recommended } + - { dd-name: test.source.start, type: int, required: recommended } + - { dd-name: test.source.end, type: int, required: recommended } + - { dd-name: test.codeowners, type: string, required: optional } + - { dd-name: test.traits, type: string, required: optional } + + test: + extends: ci.span + tags: + - { ref: test.module } + - { ref: test_module_id } + - { ref: test.suite } + - { ref: test_suite_id } + - { ref: test.source.file } + - { ref: test.source.start } + - { ref: test.source.end } + - { ref: test.codeowners } + - { ref: test.traits } + - { dd-name: test.name, type: string, required: required } + - { dd-name: test.final_status, type: string, required: recommended } + - { dd-name: test.source.method, type: string, required: recommended } + - { dd-name: test.source.class, type: string, required: optional } # when it differs from the suite + - { dd-name: test.parameters, type: string, required: optional } + - { dd-name: test.skipped_by_itr, type: boolean, required: optional } + - { dd-name: test.itr.unskippable, type: boolean, required: optional } + - { dd-name: test.itr.forced_run, type: boolean, required: optional } + - { dd-name: test.is_new, type: boolean, required: optional } + - { dd-name: test.is_modified, type: boolean, required: optional } + - { dd-name: test.is_retry, type: boolean, required: optional } + - { dd-name: test.has_failed_all_retries, type: boolean, required: optional } + - { dd-name: test.failure_suppressed, type: boolean, required: optional } + - { dd-name: test.test_management.is_quarantined, type: boolean, required: optional } + - { dd-name: test.test_management.is_test_disabled, type: boolean, required: optional } + - { dd-name: test.test_management.is_attempt_to_fix, type: boolean, required: optional } + - { dd-name: test.test_management.attempt_to_fix_passed, type: boolean, required: optional } + - { dd-name: test.retry_reason, type: string, required: optional } + - { dd-name: itr_correlation_id, type: string, required: optional } + # set as tags only when CI Visibility reports through the APM protocol; otherwise the CI intake + # mapper writes them into its metadata header + - { dd-name: os.architecture, type: string, required: optional } + - { dd-name: os.platform, type: string, required: optional } + - { dd-name: os.version, type: string, required: optional } + - { dd-name: runtime.name, type: string, required: optional } + - { dd-name: runtime.vendor, type: string, required: optional } + - { dd-name: runtime.version, type: string, required: optional } + - { dd-name: _dd.test.is_user_provided_service, type: string, required: optional } + + # A browser test (Selenium). + test.browser: + extends: test + tags: + - { dd-name: test.browser.driver, type: string, required: optional } + - { dd-name: test.browser.driver_version, type: string, required: optional } + - { dd-name: test.browser.name, type: string, required: optional } + - { dd-name: test.browser.version, type: string, required: optional } + - { dd-name: test.is_rum_active, type: boolean, required: optional } + # An internal span no other type models, e.g. an integration platform's process or action step. internal: extends: base @@ -473,20 +630,6 @@ mixins: - { dd-name: _dd.dm.service, type: string, required: optional } - { dd-name: _dd.dm.resource, type: string, required: optional } - # ci_visibility — per-span test tags. Its capability flag (_dd.civisibility.enabled) lives in - # trace_level, outside this mixin (general rule: capability flags are trace-level, mixins hold the - # per-span tags). Applies to the `test` span type, which is not modeled here yet — so these tags - # get ids (identity does not depend on layout) but contribute to no type's resolved set until it - # is. The generator reports that gap in resolved-tags.txt. - ci_visibility: - enabled_by: dd.civisibility.enabled - applies: [ test ] - tags: - - { dd-name: test.name, type: string, required: recommended } - - { dd-name: test.suite, type: string, required: recommended } - - { dd-name: test.status, type: string, required: recommended } - - { dd-name: test.framework, type: string, required: recommended } - # --------------------------------------------------------------------------- # Notes # - Product .enabled flags moved to `trace_level` (process-constant) — the old product mixins held