Uh oh!
There was an error while loading. Please reload this page.
Generate KnownTags from tag-conventions via the tag-registry code generator (phase 2) - #12047
Generate KnownTags from tag-conventions via the tag-registry code generator (phase 2)#12047dougqh wants to merge 6 commits into
Conversation
Bits has a CI fix ready🟢 Investigated · 🟢 Fix prepared · ⚪ Validation skipped · 🟠 Ready
View in Datadog | Reviewed commit e6800b8 · Any feedback? Reach out in #deveng-pr-agent |
🎯 Code Coverage (details) 🔗 Commit SHA: 33f32c4 | Docs | View more details | Give us feedback! |
🟢 Java Benchmark SLOs — All performance SLOs passed
PR vs. master results
Commit: Load and DaCapo benchmarks can be triggered manually in the GitLab pipeline. Results will appear in the Benchmarking Platform UI after completion. |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
7f3d0b1 to
e6800b8Comparee6800b8 to
9b7c3d1CompareReconciles #11901's SizingHint half onto the colored generator-v2 base as its own layer. A per-operation SizingHint (kept in a bounded, self-tuning SizingHintTable keyed by operation name, two lanes for entry vs child spans) sizes a span's dense TagMap at create and records the observed known-tag high-water mark back on finish, so the reused hint converges to the operation's real size. Erases the fixed KNOWN_INIT_CAP dense-array floor tax that regressed bare/small spans in the #12047-vs-1.65 A/B; the id-keyed write API stacks on top of this as a separate layer. New: SizingHint, SizingHelper, SizingHintTable, FlatHashtable (+ tests, jmh). TagMap: create(SizingHint), recordSize, denseCapHint. DDSpanContext threads a sizingHint through the primary ctor + recordDenseSize on finish; DDSpan hooks it at finishAndAddToTrace; CoreTracer resolves the per-operation hint/lane. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reconciles #11901's SizingHint half onto the colored generator-v2 base as its own layer. A per-operation SizingHint (kept in a bounded, self-tuning SizingHintTable keyed by operation name, two lanes for entry vs child spans) sizes a span's dense TagMap at create and records the observed known-tag high-water mark back on finish, so the reused hint converges to the operation's real size. Erases the fixed KNOWN_INIT_CAP dense-array floor tax that regressed bare/small spans in the #12047-vs-1.65 A/B; the id-keyed write API stacks on top of this as a separate layer. New: SizingHint, SizingHelper, SizingHintTable, FlatHashtable (+ tests, jmh). TagMap: create(SizingHint), recordSize, denseCapHint. DDSpanContext threads a sizingHint through the primary ctor + recordDenseSize on finish; DDSpan hooks it at finishAndAddToTrace; CoreTracer resolves the per-operation hint/lane. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
dougqh
commented
Aug 18, 2026
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit:098070fd3e
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
Uh oh!
There was an error while loading. Please reload this page.
| this.traceDenseTagsEnabled = | ||
| configProvider.getBoolean(TracerConfig.TRACE_DENSE_TAGS_ENABLED, false); |
There was a problem hiding this comment.
Log the new dense-tags configuration
The new configuration is stored and exposed but never added to Config.toString(). Consequently, startup/configuration diagnostics omit whether this experimental path is enabled, making deployment and experiment failures unnecessarily difficult to diagnose; the repository's configuration procedure explicitly requires every new configuration to be included there.
AGENTS.md reference: AGENTS.md:L37-L43
Useful? React with 👍 / 👎.
| val outDir = destinationDirectory.get().asFile | ||
| TagRegistryGenerator.generate(domainYaml.get().asFile, overlayYaml.get().asFile, outDir) |
There was a problem hiding this comment.
Remove obsolete outputs before regenerating
When a later generator revision renames or stops emitting a report/source file, generateKnownTags only overwrites current outputs and leaves the retired file in src/generated. verifyKnownTags then reports that file as stale while instructing developers to rerun this task, but rerunning cannot resolve the failure; clear the owned destination tree before generating so it represents the exact current output set.
Useful? React with 👍 / 👎.
| Tag( | ||
| name = m["tag"].toString(), | ||
| type = (m["type"] as? String) ?: "string", | ||
| required = (m["required"] as? String) ?: "optional", | ||
| ) |
There was a problem hiding this comment.
Preserve aliases when parsing tag declarations
When dense tags are enabled and instrumentation uses one of the aliases explicitly declared in the new source of truth—such as http.request.method, http.response.status_code, url.full, or db.system—the parser discards aliases, so KnownTags.RESOLVER.keyOf(...) treats that key as unknown and leaves it on the bucket path instead of associating it with the declared known tag. Parse and emit alias-to-ID entries so the generated registry actually covers the semantic aliases represented by the YAML.
Useful? React with 👍 / 👎.
| // ignore embedded test projects and everything in build dir, e.g. generated sources | ||
| targetExclude('src/test/resources/**', buildDirectoryFiles) | ||
| // src/generated/** is emitted by code generators (e.g. the tag registry) — verified by their own freshness gate | ||
| targetExclude('src/test/resources/**', 'src/generated/**', buildDirectoryFiles) |
There was a problem hiding this comment.
Keep generated Java subject to the formatting standard
Excluding every src/generated/** Java source removes the repository's mandatory Google Java Format check from committed generated code, and the newly committed KnownTags.java already contains an assignment that the formatter wraps differently. This lets future emitter changes accumulate nonconforming Java undetected; make the emitter produce formatter-clean output or format generated Java before freshness verification rather than globally bypassing Spotless.
AGENTS.md reference: AGENTS.md:L56-L59
Useful? React with 👍 / 👎.
| a.appendLine("# STORED serial slot int lvl id required name") | ||
| for (t in reg.stored) { | ||
| a.appendLine( | ||
| " %6d %5s %s %s %-18s %-12s %s".format( |
There was a problem hiding this comment.
Make generated reports independent of the default locale
On machines whose JVM default locale uses non-ASCII decimal digits, the unqualified String.format calls localize %d output, so the generated report bytes differ from the committed files even with identical YAML inputs. This contradicts the generator's byte-identical-output invariant and makes verifyKnownTags fail solely because of the developer or CI locale; format all generated output with Locale.ROOT.
Useful? React with 👍 / 👎.
Reconciles #11901's SizingHint half onto the colored generator-v2 base as its own layer. A per-operation SizingHint (kept in a bounded, self-tuning SizingHintTable keyed by operation name, two lanes for entry vs child spans) sizes a span's dense TagMap at create and records the observed known-tag high-water mark back on finish, so the reused hint converges to the operation's real size. Erases the fixed KNOWN_INIT_CAP dense-array floor tax that regressed bare/small spans in the #12047-vs-1.65 A/B; the id-keyed write API stacks on top of this as a separate layer. New: SizingHint, SizingHelper, SizingHintTable, FlatHashtable (+ tests, jmh). TagMap: create(SizingHint), recordSize, denseCapHint. DDSpanContext threads a sizingHint through the primary ctor + recordDenseSize on finish; DDSpan hooks it at finishAndAddToTrace; CoreTracer resolves the per-operation hint/lane. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Introduce the tag-registry code generator (buildSrc plugin + tag-conventions YAML) and use it to assign the colored slots from the previous commit by graph-coloring the tag co-occurrence graph (each concrete span type's resolved set plus the <trace> clique), packing all stored tags into SLOT_COUNT=16 slots. Relocates the hand-maintained KnownTags from src/main to the generated src/generated source set and renames the codec accessors to their generated form (serialNum/makeTagId). Adds the generator verify task so CI fails if the checked-in KnownTags drifts from the conventions. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Expose the known-tag id on EntryReader: TagMap.Entry resolves it lazily via KnownTagCodec.keyOf (same memoized-field idiom as lazyTagHash; 0L means unknown tag / inactive codec, so the sentinel is Long.MIN_VALUE). The dense reader flyweight already has the id in hand at emit time and records it directly, skipping the keyOf resolve. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ting Address two Codex robustness findings on the generator: - generateKnownTags now clears its owned destination tree before regenerating, so a report/source file retired by a later revision cannot linger and fail verifyKnownTags with no way for the fix task to remove it. - All String.format calls in the report/emitter use Locale.ROOT, so %d output no longer localizes on machines whose default locale uses non-ASCII digits, preserving the byte-identical-output invariant verifyKnownTags relies on. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Address the Codex finding that the new experimental dense-tags flag was stored but never surfaced in Config.toString (repo convention requires new configs appear there for diagnostics). Surface it only when it diverges from the default, so normal config dumps stay uncluttered, and compare against a new DEFAULT_TRACE_DENSE_TAGS_ENABLED constant (also now the getBoolean default) so the condition stays correct if the default ever changes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Address the Codex finding that gradle/spotless.gradle excluded src/generated/**, bypassing google-java-format on committed generated code. Drop the exclude and make KnownTagsEmitter emit google-java-format-clean output (blank line before the keyOf static initializer; wrap the long id-assignment), so spotlessCheck and the byte-identical verifyKnownTags gate both pass on the emitted file. internal-api is the only module with a committed src/generated Java tree, so the exclude removal is otherwise a no-op. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds a per-namespace name to the tag registry: each tag may declare an `open-telemetry-name` (replacing the vestigial `aliases` list). The generator now: - parses it off both YAMLs into the model, - validates it (an OTel name may not collide with a canonical tag name nor be claimed by two tags -> build fails loudly rather than silently picking one), - emits it into the keyOf table so keyOf(otelName) resolves to the canonical tag's id (inbound, many->one), and - emits a reverse switch so openTelemetryNameOf(tagId) recovers it (outbound). KnownTagCodec gains datadogTagOf(tagId) (== nameOf, the canonical name) and openTelemetryTagOf(tagId) (the OTel name, or null). nameOf is unchanged and still returns the Datadog name -- outbound is namespace-specific, not normalized. Serializer applicability (when a span renders under OTel names, fallback policy) and additional namespaces are a follow-on concern. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
19222e1 to
33f32c4Comparedougqh
commented
Aug 18, 2026
@codex review |
Codex Review: Didn't find any major issues. 👍 Reviewed commit: ℹ️ About Codex in GitHubCodex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback". |
What Does This Do
Replaces the hand-maintained known-tag table with one generated from a single source of truth (
tag-conventions.yaml+ a Java overlay), so tag ids / the id↔name resolver / (later) per-type layouts stop drifting across core, instrumentation, and language tracers.Generator (buildSrc)
Modeled on
SupportedConfigPlugin(data file →.javaviaPrintWriter):TagRegistryGeneratorPlugin+GenerateKnownTagsTask— readtag-conventions.yaml(domain) +tag-conventions.java.yaml(Java overlay:interceptedhints + virtual/special registry), resolve per-type tag sets (extends/include/applies, de-duped), assign ids in stable serial order, and greedily graph-color the colorable set into slots.KnownTagsEmitter— emits google-java-format-clean Java to committedinternal-api/src/generatedwith a literal id +// tagId(serial=…, group=…, field=…)audit comment (literal ⟹ javac constant-folds; comment ⟹ auditable).verifyKnownTags— regenerates + git-diffs to catch stale commits. Generated classes are jacoco-excluded.Committing the generated sources also lets us audit what ids/layout any release branch shipped via
git checkout.internal-api
src/main/.../KnownTags.javain favor of the generatedsrc/generated/.../KnownTags.java(byte-equal ids — the equivalence gate).parentDenseVisibleover the pre-reconcile single-level form.StringIndex.EmbeddingSupport(matching the tagset base rename) in both the emitter and its committed output, so regeneration is drift-free.Verification
:internal-api:generateKnownTags(no drift),verifyKnownTags,KnownTagsTest,TagMapDenseForkedTest,TagMapDenseFuzzForkedTest,spotlessJavaCheck,spotbugsMain— all green.Stack
tagset → dense-store (#12045) → two-tier bloom (#12046) → **generator**. Basedougqh/bloom-v2. Supersedes old #11961.Non-goals (follow-on)
Wiring
SpanLayoutsinto the dense store; full virtual-dispatch table →TagInterceptorretirement; bandwidth-minimizing packer (greedy is v1).🤖 Generated with Claude Code