DSL debugger (OAL): emit source @ScopeDefaultColumn fields on output sample via codegen#13867
Merged
DSL debugger (OAL): emit source @ScopeDefaultColumn fields on output sample via codegen#13867
Conversation
…sample via codegen The terminal `output` sample of an OAL debug session was missing the source-derived @column fields that the OAL-generated subclass carries on its instance — entityId + attr0..attr5 for any Service-style scope. Operators inspecting `service_cpm` saw only `total` / `value` from CPMMetrics.appendDebugFields; the layer name written to attr0 by ServiceDecorator (and any other source attributes) was on the live object and in the storage row, but invisible in the debug capture. Why the gap: `attr0..attr5` are NOT inherited from a fixed parent for OAL — they're declared on the source class via `@ScopeDefaultColumn.DefinedByField` and copied to the generated metrics subclass at OAL boot by `OALClassGeneratorV2.generateMetricsClass` (line 220, the per-source-field `addField` loop). The family parent (CPMMetrics, SumMetrics, ...) doesn't know they exist, so its `appendDebugFields` override can't surface them. Reflection-based or `Convert2Storage` shim approaches were considered; codegen-side generation is the right scope — the same pass that materialises the fields also emits their debug projection. Adds `appendDebugFields` to METRICS_CLASS_METHODS so the existing template loop generates an override on every OAL-generated `*Metrics` subclass. The override calls `super.appendDebugFields(obj)` first (delegating the family's value columns — total / value / summation / ...) then iterates `fieldsFromSource` to emit each @ScopeDefaultColumn-declared field with the right typed `obj.addProperty(...)` overload (Long / Integer / Double / Float / Boolean wrappers for primitives so Javassist resolves the `addProperty(String, Number)` overload unambiguously; null-safe `toString()` for object types). Verification: - `mvn test -pl oap-server/oal-rt`: 98/98 pass. - After deploy, an OAL debug session against `oal/core.oal` / `service_cpm` will show `payload.attr0=GENERAL` (set by ServiceDecorator) on the terminal output sample, alongside the family's `total` and `value`. Cost: zero when `SW_DSL_DEBUGGING_INJECTION_ENABLED=false` (codegen emits an `appendDebugFields` override either way; it's only invoked from `Metrics.toJson()` which is only called by the gated debug recorder). When debug is on, one extra method call per probed emit per debug session.
There was a problem hiding this comment.
Pull request overview
This PR updates the OAL (OAL v2) code generation pipeline so that OAL-generated *Metrics subclasses include @ScopeDefaultColumn-derived fields (e.g., entity_id, attr0..attr5) in DSL debugging JSON output by generating an appendDebugFields(JsonObject) override.
Changes:
- Add a new FreeMarker template to generate
appendDebugFields(JsonObject)for OAL-generated metrics classes, emittingfieldsFromSourceinto the JSON debug payload. - Register the new template/method in
OALClassGeneratorV2.METRICS_CLASS_METHODSso it is generated for all OAL metrics subclasses.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
oap-server/oal-rt/src/main/resources/code-templates-v2/metrics/appendDebugFields.ftl |
New template that emits source-derived columns into the metrics debug JSON via a generated appendDebugFields override. |
oap-server/oal-rt/src/main/java/org/apache/skywalking/oal/v2/generator/OALClassGeneratorV2.java |
Adds appendDebugFields to the method-generation list so the template is applied to generated metrics classes. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+1
to
+5
| protected void appendDebugFields(com.google.gson.JsonObject obj) { | ||
| super.appendDebugFields(obj); | ||
| <#list fieldsFromSource as field> | ||
| <#if field.typeName == "long"> | ||
| obj.addProperty("${field.columnName}", java.lang.Long.valueOf(${field.fieldGetter}())); |
wankai123
approved these changes
May 9, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fix missing
attr0..5/entityIdcolumns in OAL debug captureBug. A debug session against any OAL metric (e.g.
oal/core.oal/service_cpm) shows the terminaloutputsample with onlythe family parent's value columns:
{ "type": "ServiceCpmMetrics", "timeBucket": …, "id": …, "total": 1, "value": 0 }The source-derived storage columns
attr0..attr5andentityIdareabsent — even though the OAL-generated subclass DOES carry them on the
live instance, the entry function copied them from the Source, and the
storage row in BanyanDB DOES persist them. Operators verifying e.g. the
layer name written to
attr0byServiceDecoratorcannot see it inthe debugger; they have to cross-reference with a storage query.
Why the gap. For OAL-generated metrics,
attr0..5are NOTinherited from a fixed parent — they are declared on the source class
via
@ScopeDefaultColumn.DefinedByField, surfaced bySourceColumnsFactory.getColumns(), and copied to the generatedmetrics subclass at OAL boot by
OALClassGeneratorV2.generateMetricsClass(line 220, the
for (CodeGenModel.SourceFieldV2 field : model.getFieldsFromSource()) metricsClass.addField(...)loop). Thefamily parent (CPMMetrics, SumMetrics, …) doesn't know the dynamic
fields exist, so its
appendDebugFields(JsonObject)override onlyemits its own value columns.
Metrics.toJson()then renders just{type, timeBucket, lastUpdateTimestamp, id} + family fields.The fix. Codegen-side. The same OAL pass that materialises the
dynamic fields now also emits an
appendDebugFields(JsonObject)override on the generated subclass:
Mechanically: a new FreeMarker template
oap-server/oal-rt/src/main/resources/code-templates-v2/metrics/appendDebugFields.ftliterates
fieldsFromSourceand emits the right typedobj.addProperty(...)overload (Long / Integer / Double / Float /Boolean wrappers for primitives so Javassist resolves the
addProperty(String, Number)overload unambiguously; null-safetoString()for object types). The generator picks it up by listing"appendDebugFields"inMETRICS_CLASS_METHODS, the same array thatalready drives
id.ftl,serialize.ftl, etc.Why codegen, not reflection / a
Convert2Storageshim. The fieldsare codegen-materialised — putting their debug projection in the same
codegen pass keeps the field list literally hard-coded in the bytecode
(zero reflection at runtime, exact parity with what the generator
declared). Recorder-side reflection or a JsonObject-backed
Convert2Storagewould also work but adds a runtime walker per probedemit; codegen is strictly cheaper.
Add a unit test to verify that the fix works.
oap-server/oal-rtunit tests pass against the newMETRICS_CLASS_METHODS entry — the existing
OALClassGeneratorV2TestandRuntimeOALGenerationTestexercisethe full template-driven generator. The generated method is loaded
onto every
*Metricssubclass at OAP boot, so a generator failurewould surface as a class-load error before a single source event
is dispatched.
oal/core.oal/service_cpmnow shows the dynamic columns on theterminal sample in addition to the family parent's value fields.
Explain briefly why the bug exists and how to fix it.
always correct, only the wire payload missed the dynamic columns.
The fix is debug-only and zero-cost when
SW_DSL_DEBUGGING_INJECTION_ENABLED=false(the override is onlyinvoked from
Metrics.toJson(), which is only called by thegated dsl-debugging recorder).
If this pull request closes/resolves/fixes an existing issue, replace the issue number. Closes #.
Update the
CHANGESlog.SWIP-13 surface that PR DSL debugger (MAL): surface terminal payload.value with two-phase calculate; reduce session record cap to 100 #13865 just landed against, already
covered by the 10.5.0 changelog entry.