Skip to content

Replace Groovy DSL runtime with ANTLR4 + Javassist for MAL, LAL, and Hierarchy#13723

Open
wu-sheng wants to merge 42 commits intomasterfrom
groovy-replace
Open

Replace Groovy DSL runtime with ANTLR4 + Javassist for MAL, LAL, and Hierarchy#13723
wu-sheng wants to merge 42 commits intomasterfrom
groovy-replace

Conversation

@wu-sheng
Copy link
Member

@wu-sheng wu-sheng commented Mar 3, 2026

Replace Groovy DSL runtime with ANTLR4 + Javassist for MAL, LAL, and Hierarchy

  • This is a non-trivial feature. Design doc: docs/en/academy/dsl-compiler-design.md

  • Documentation updated to include this new feature.

  • Tests (UT, IT, E2E) are added to verify the new feature.

  • If this pull request closes/resolves/fixes an existing issue, replace the issue number. Closes #.

  • Update the CHANGES log.

What this PR does

Replaces the Groovy-based DSL runtime for MAL (Meter Analysis Language), LAL (Log Analysis Language), and Hierarchy matching rules with compile-time ANTLR4 parsing and Javassist bytecode generation — the same approach already used by the OAL v2 engine.

All three DSL compilers follow the same pipeline:

DSL string → ANTLR4 parse → Immutable AST → Javassist bytecode → Direct Java execution

Why

  • Remove Groovy runtime dependency (~7MB) from the OAP server classpath
  • Eliminate runtime interpretation — generated bytecode uses direct method calls with zero reflection at runtime
  • Thread-safe by design — all generated instances are stateless singletons; per-request state passed as parameters (no ThreadLocal, no mutable wrappers)
  • Fail-fast at boot — DSL compilation errors are caught during startup with file/line/column reporting, not at first log/metric arrival
  • Debugger-friendly — all generated methods include LocalVariableTable (LVT) entries with named variables

Architecture

DSL Compiled Interface Runtime Signature State Passing
MAL MalExpression SampleFamily run(Map<String, SampleFamily>) Parameter
LAL LalExpression void execute(FilterSpec, ExecutionContext) Parameter
Hierarchy BiFunction<Service, Service, Boolean> Boolean apply(Service, Service) Parameter

All v2 classes live under .v2. packages to avoid FQCN conflicts with v1 (Groovy) classes, which remain in test/script-cases/script-runtime-with-groovy/ for comparison testing.


Compiled Code Examples

MAL Example 1 — Simple aggregation

DSL: instance_jvm_cpu.sum(['service', 'instance'])

Generated run() method:

public SampleFamily run(Map samples) {
  SampleFamily sf;
  sf = ((SampleFamily) samples.getOrDefault("instance_jvm_cpu", SampleFamily.EMPTY));
  sf = sf.sum(new String[]{"service", "instance"});
  return sf;
}
MAL Example 2 — Tag closure (compiled as a separate class)

DSL: metric.tag({tags -> tags.service_name = 'APISIX::' + tags.skywalking_service})

Generated main class run():

public SampleFamily run(Map samples) {
  SampleFamily sf;
  sf = ((SampleFamily) samples.getOrDefault("metric", SampleFamily.EMPTY));
  sf = sf.tag(this._tag);          // _tag field holds pre-compiled closure instance
  return sf;
}

Generated closure class apply() (separate MalExpr_N$_tag):

public Map apply(Map tags) {
  tags.put("service_name", "APISIX::" + tags.get("skywalking_service"));
  return tags;
}

Closures become separate Javassist classes (Javassist cannot compile lambdas/anonymous classes), stored as fields on the main class, wired via reflection at compile time.

MAL Example 3 — Regex match with ternary

DSL: metric.tag({ tags -> def matcher = (tags.metrics_name =~ /\.ssl\.certificate\.([^.]+)\.expiration/); tags.secret_name = matcher ? matcher[0][1] : "unknown" })

Generated closure class apply():

public Map apply(Map tags) {
  String[][] matcher = MalRuntimeHelper.regexMatch(
      (String) tags.get("metrics_name"),
      "\\.ssl\\.certificate\\.([^.]+)\\.expiration");
  tags.put("secret_name", (((Object)(matcher)) != null ? (matcher[0][1]) : ("unknown")));
  return tags;
}

def type inferred as String[][] from =~ regex match. Ternary compiles to Java ternary with null-check on Object cast.


LAL Example 1 — JSON parser with extractor

DSL:

filter {
  json {}
  extractor {
    service parsed.service as String
    instance parsed.instance as String
  }
  sink {}
}

Generated class:

public void execute(FilterSpec filterSpec, ExecutionContext ctx) {
  LalRuntimeHelper h = new LalRuntimeHelper(ctx);
  filterSpec.json(ctx);
  if (!ctx.shouldAbort()) { _extractor(filterSpec.extractor(), h); }
  filterSpec.sink(ctx);
}

private void _extractor(ExtractorSpec _e, LalRuntimeHelper h) {
  _e.service(h.ctx(), h.toStr(h.mapVal("service")));
  _e.instance(h.ctx(), h.toStr(h.mapVal("instance")));
}

Single class, no closures. h.mapVal() accesses JSON parsed map. h.toStr() preserves null (unlike String.valueOf() which returns "null").

LAL Example 2 — Proto-based with extraLogType (Envoy ALS)

DSL:

filter {
  if (parsed?.response?.responseCode?.value as Integer < 400) { abort {} }
  extractor {
    if (parsed?.response?.responseCode) {
      tag 'status.code': parsed?.response?.responseCode?.value
    }
    tag 'response.flag': parsed?.commonProperties?.responseFlags
  }
  sink {}
}

Generated class (with extraLogType = HTTPAccessLogEntry):

public void execute(FilterSpec filterSpec, ExecutionContext ctx) {
  LalRuntimeHelper h = new LalRuntimeHelper(ctx);
  // Cast once, reuse as _p
  HTTPAccessLogEntry _p = (HTTPAccessLogEntry) h.ctx().extraLog();
  // Safe-nav chain cached in local variables
  HTTPResponseProperties _t0 = _p == null ? null : _p.getResponse();
  UInt32Value _t1 = _t0 == null ? null : _t0.getResponseCode();
  if (_t1 != null && _t1.getValue() < 400) { filterSpec.abort(ctx); }
  if (!ctx.shouldAbort()) { _extractor(filterSpec.extractor(), h); }
  filterSpec.sink(ctx);
}

private void _extractor(ExtractorSpec _e, LalRuntimeHelper h) {
  HTTPAccessLogEntry _p = (HTTPAccessLogEntry) h.ctx().extraLog();
  HTTPResponseProperties _t0 = _p == null ? null : _p.getResponse();
  UInt32Value _t1 = _t0 == null ? null : _t0.getResponseCode();
  if (_t1 != null) {
    _e.tag(h.ctx(), "status.code", h.toStr(Integer.valueOf(_t1.getValue())));
  }
  AccessLogCommon _t2 = _p == null ? null : _p.getCommonProperties();
  _e.tag(h.ctx(), "response.flag", h.toStr(_t2 == null ? null : _t2.getResponseFlags()));
}

Proto getter chains resolved via Java reflection at compile time — at runtime it's direct method calls. ?. safe navigation emits == null ? null : ternaries. Intermediate values cached in _tN local variables for readability and dedup.


Hierarchy Example 1 — Simple name match

DSL: { (u, l) -> u.name == l.name }

Generated class:

public Object apply(Object arg0, Object arg1) {
  Service u = (Service) arg0;
  Service l = (Service) arg1;
  return Boolean.valueOf(java.util.Objects.equals(u.getName(), l.getName()));
}
Hierarchy Example 2 — Block body with if/return

DSL: { (u, l) -> { if (l.shortName.lastIndexOf('.') > 0) { return u.shortName == l.shortName.substring(0, l.shortName.lastIndexOf('.')); } return false; } }

Generated class:

public Object apply(Object arg0, Object arg1) {
  Service u = (Service) arg0;
  Service l = (Service) arg1;
  if (l.getShortName().lastIndexOf(".") > 0) {
    return Boolean.valueOf(java.util.Objects.equals(
        u.getShortName(),
        l.getShortName().substring(0, l.getShortName().lastIndexOf("."))));
  }
  return Boolean.valueOf(false);
}

Property access → getter methods. ==Objects.equals(). Numeric > → direct operator.


v1 vs v2 Cross-Verification

The test/script-cases/script-runtime-with-groovy/ module runs every production DSL expression through both Groovy v1 and Javassist v2, then asserts identical results. Both v1 and v2 must pass — v1 failure also fail()s (no silent skip).

How it works
For each DSL expression in production YAML configs:
  1. Compile with v1 (Groovy)    → run with mock data → collect output
  2. Compile with v2 (Javassist) → run with same data → collect output
  3. Assert v1 output == v2 output field by field

v1 and v2 coexist in the same JVM via package isolation (*.dsl.* vs *.v2.dsl.*), each with its own ModuleManager mock.

What is compared
DSL Fields compared
MAL (metadata) samples (input metric names), scopeType, downsampling, isHistogram, scopeLabels, aggregationLabels
MAL (runtime) Output Sample[] arrays — label sets and values, after running both with identical SampleFamily input
LAL shouldAbort, shouldSave, log.service, log.serviceInstance, log.endpoint, log.layer, log.timestamp, log.tags
Hierarchy Boolean result for each (upper, lower) Service pair
Test data
  • MAL: 73 companion .data.yaml files provide realistic mock SampleFamily input per YAML config. For increase()/rate() expressions, the checker primes the counter window with initial data before the comparison run. Expressions without companion data fall back to auto-generated mock data.
  • LAL: Mock LogData protobuf built with service/instance/endpoint/timestamp/traceContext. Rules with extraLogType (e.g., envoy-als proto) use .input.data files with proto-json mock data and the LALSourceTypeProvider SPI to resolve the proto type per layer at compile time.
  • Hierarchy: Test pairs from .data.yaml with (upper, lower, expected) tuples per rule.
Verification counts
DSL Expressions Source
MAL expressions 1,229 73 YAML files across 4 directories
MAL filter closures 31 Separate MalFilterComparisonTest
LAL scripts 29 oap-cases + feature-cases
Hierarchy rules 4 rules × test pairs test-hierarchy-definition.data.yaml
Total ~1,290

Files changed

537 files, +40,436 / -1,480 (bulk from new test data files, POM version changes, and generated grammar sources)

wu-sheng and others added 29 commits February 28, 2026 14:10
Document the detailed implementation plan for eliminating Groovy from
OAP runtime via build-time transpilers (MAL/LAL) and v1/v2 module
split (hierarchy), based on Discussion #13716 and skywalking-graalvm-distro.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add MalExpression, MalFilter, LalExpression functional interfaces and
SampleFamilyFunctions (TagFunction, SampleFilter, ForEachFunction,
DecorateFunction, PropertiesExtractor). Add Java functional interface
overloads alongside existing Groovy Closure methods in SampleFamily,
FilterSpec, ExtractorSpec, and SinkSpec. Change InstanceEntityDescription
to use Function instead of Closure. All 129 existing tests pass.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…hase 2)

Ports MalToJavaTranspiler from skywalking-graalvm-distro into a new
mal-transpiler analyzer submodule. The transpiler parses Groovy MAL
expressions/filters via AST at CONVERSION phase and emits equivalent
Java classes implementing MalExpression/MalFilter interfaces from Phase 1.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…hase 3)

Introduces lal-transpiler module that parses LAL Groovy DSL scripts into
AST at Phases.CONVERSION and emits pure Java classes implementing
LalExpression. Handles filter/text/json/yaml/extractor/sink/abort blocks,
parsed property access, safe navigation, cast expressions, GString
interpolation, and SHA-256 deduplication. Makes MalToJavaTranspiler.escapeJava()
public for cross-module reuse. Includes 37 comprehensive tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ing (Phase 4)

Introduces meter-analyzer-v2 and log-analyzer-v2 modules that provide
same-FQCN replacement classes for DSL.java, Expression.java, and
FilterExpression.java. The v2 classes load transpiled MalExpression/
MalFilter/LalExpression implementations from META-INF manifests via
Class.forName() instead of Groovy GroovyShell/ExpandoMetaClass/
DelegatingScript. Uses maven-shade-plugin to overlay the upstream
Groovy-dependent classes. Includes 7 unit tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… (Phase 5)

Extract hierarchy matching rules from HierarchyDefinitionService into
pluggable HierarchyRuleProvider interface. Remove Groovy imports from
server-core by replacing Closure<Boolean> with BiFunction<Service,Service,Boolean>.

- hierarchy-v1: GroovyHierarchyRuleProvider (for CI checker only)
- hierarchy-v2: JavaHierarchyRuleProvider with 4 built-in rules + 12 tests
- HierarchyDefinitionService: add HierarchyRuleProvider interface, DefaultJavaRuleProvider
- HierarchyService: .getClosure().call() → .match()

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ase 6)

Three checker modules verify v1 (Groovy) and v2 (transpiled Java) produce
identical results: hierarchy rules (22 tests), MAL expressions (1187 tests),
MAL filters (29 tests), and LAL scripts (10 tests). Zero behavioral
divergences found when both paths succeed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…L to on-the-fly compilation

- Merge mal-grammar + mal-compiler into meter-analyzer
- Merge lal-grammar + lal-compiler into log-analyzer
- Merge hierarchy-rule-grammar + hierarchy-rule-compiler into hierarchy
- Remove 6 standalone modules (3 grammar + 3 compiler)
- Update DSL.java to compile MAL expressions on-the-fly via MALClassGenerator
  instead of loading from non-existent manifest file
- Add varargs handling for tagEqual/tagNotEqual/tagMatch/tagNotMatch in
  generated Javassist code (wrap String args in new String[]{})
- Update test/script-compiler checker POMs to reference merged module names
- Update CLAUDE.md files with merged file structure and paths

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix MAL sample collection regression: skip downsampling() method
  arguments to prevent enum values (MAX, SUM, MIN) from being
  collected as sample names
- Fix MAL safe navigation (?.): parser now correctly propagates
  safeNav flag to chain segments; code generator uses local
  StringBuilder to avoid corrupting parent buffer
- Fix MAL filter grammar: add closureCondition alternatives to
  closureBody rule for bare conditions like { tags -> tags.x == 'v' }
- Fix MAL downsampling detection for bare identifiers parsed as
  ExprArgument wrapping MetricExpr
- Fix MAL sample ordering: use LinkedHashSet for consistent order
- Fix LAL tag() function call: add functionName rule allowing TAG
  token in functionInvocation for if(tag("LOG_KIND") == ...) patterns
- Fix LAL ProcessRegistry support: add PROCESS_REGISTRY to
  valueAccessPrimary grammar rule
- Fix LAL tag statement code generation: wrap single tag entries in
  Collections.singletonMap() since ExtractorSpec.tag() accepts Map
- Fix LAL makeComparison to handle CondFunctionCallContext properly
- Add debug logging to all three code generators (MAL, LAL, Hierarchy)
  showing AST and generated Java source at DEBUG level
- Add generateFilterSource() to MALClassGenerator for testing
- Add error handling unit tests with demo error comments for MAL (5),
  LAL (4), and Hierarchy (4) generators
- All 1248 checker tests pass: MAL 1187, Filter 29, LAL 10, Hierarchy 22

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ng all four DSL compilers (OAL, MAL, LAL, Hierarchy). Remove Groovy references from docs: LAL code blocks, hierarchy matching rule labels, and stale MeterProcessor comment.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Provides a /run-e2e slash command with prerequisites (e2e CLI,
swctl, yq install instructions), rebuild detection, test execution,
and failure debugging workflow.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…, interpolated sampler IDs

Address five critical gaps in the LAL v2 compiler that broke shipped production rules:

1. tag("LOG_KIND") in conditions now emits tagValue() helper instead of null
2. Safe navigation (?.) for method calls emits safeCall() helper to prevent NPE
3. Metrics, slowSql, sampledTrace, sampler/rateLimit blocks generate proper
   sub-consumer classes with BindingAware wiring
4. else-if chains build nested IfBlock AST nodes instead of dropping
   intermediate branches
5. GString interpolation in rateLimit IDs (e.g. "${log.service}:${parsed.code}")
   parsed into InterpolationPart segments and emitted as string concatenation

Also fixes ProcessRegistry static calls to pass arguments through, and adds
comprehensive tests (55 total: 35 generator + 20 parser) covering all gaps
including production-like envoy-als, nginx, and k8s-service rule patterns.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…cripts and runtime comparison

- Rename test/script-compiler to test/script-cases/script-runtime-with-groovy
- Copy all shipped production configs into test/script-cases/scripts/ as test copies
  (MAL: test-otel-rules, test-meter-analyzer-config, test-log-mal-rules, test-envoy-metrics-rules;
   LAL: test-lal; Hierarchy: test-hierarchy-definition.yml)
- Update all checker tests to load from shared scripts/ directory
- Upgrade LAL checker from compile-only to full runtime execution comparison
  (v1 Groovy vs v2 ANTLR4+Javassist, comparing Binding state: service, layer, tags, abort/save)
- Update Maven coordinates and root pom module path

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move benchmarks from the standalone oap-server/microbench module into
the src/test/ directories of the modules they actually test (server-core
and library-util). Drop AbstractMicrobenchmark base class in favor of
self-contained @test run() methods. Bump JMH 1.21 -> 1.37 and remove
the obsolete -XX:BiasedLockingStartupDelay=0 JVM flag (removed in JDK 18).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
MAL compiler fixes (closes 38 previously failing expressions):
- Add ternary operator (?:) support in closures (grammar, AST, codegen)
- Fix valueEqual() and other primitive-double methods with numeric literal args
- Support double-paren argument syntax: sum((['cluster']))
- Handle NUMBER / SampleFamily via MalRuntimeHelper.divReverse() in v2 package
- Add variable declarations, map literals, forEach/instance closure types
- Add ProcessRegistry class references, improved safe navigation

LAL compiler fixes:
- Fix null-to-string conversion: use null-safe toStr() instead of String.valueOf()
- Add camelToSnake field name fallback for protobuf field access
- Add typed execute(FilterSpec, Binding) method signature
- Reorganize LAL test scripts into oap-cases/ and feature-cases/
- Add data-driven LALExpressionExecutionTest with 27 test cases

MAL checker enhancements:
- Add runtime execution comparison (mock SampleFamily data, execute both
  v1 and v2, compare output samples with labels and values)
- Handle increase()/rate() by priming CounterWindow with initial run
- Extract tagEqual patterns from expressions for matching mock data

All 1,187 MAL + 29 LAL + 22 hierarchy expressions now pass with zero gaps.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…L typed signature

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Give v2 (ANTLR4+Javassist) classes distinct FQCNs from v1 (Groovy)
so both can coexist on the classpath without source duplication in
v1-with-groovy test modules.

Package mapping:
- MAL: meter.analyzer.* → meter.analyzer.v2.*
- LAL: log.analyzer.* → log.analyzer.v2.*
- Hierarchy: config.compiler.* → config.v2.compiler.*

Also: remove v2-only files (MalExpression, MalFilter, LalExpression)
from v1-with-groovy modules, add mal-v1-with-groovy dependency to
lal-v1-with-groovy, fix cross-version enum comparison by name.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ime() scalar in MAL compiler

Add ANTLR4 lexer mode for regex literals (=~ /pattern/), def keyword with
type inference from initializer (String[][] for regex, String[] for split),
GString interpolation expansion, .size() to .length translation, decorate()
bean-mode closures, and time() as a scalar function in binary expressions.
Verified with 1,228 v1-v2 checker tests (1,197 MAL + 31 filter).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…v1-v2 checker data

Rewrite MAL run() code generation to use a single reassigned 'sf' variable
instead of multiple intermediate variables, producing cleaner decompiled output.
Add LocalVariableTable attribute so decompilers show 'samples' and 'sf' instead
of 'var1' and 'var2'. Integrate v2 compilers with runtime wiring, add checker
test data files, and clean up unused code across MAL/LAL/Hierarchy modules.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add LVT attribute to LAL execute() and consumer accept() methods, and to
Hierarchy apply() method, so decompilers show meaningful variable names
(filterSpec, binding, _t, u, l) instead of var0, var1, etc.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move 8 helper methods (getAt, toLong, toInt, toStr, toBool, isTruthy,
tagValue, safeCall) from being duplicated in every generated class via
addHelperMethods() to a shared LalRuntimeHelper in the rt package.
Generated code now calls LalRuntimeHelper.toStr() etc. via FQCN.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…th typed methods

Fix rateLimit() calls inside if-blocks within sampler generating empty bytecode
by handling the samplerContent grammar alternative in LALScriptParser.visitIfBody().

Replace generic LalRuntimeHelper.safeCall() and isTruthy() with specific typed
methods: isTrue() for Boolean conditions, isNotEmpty() for String non-emptiness,
toString() and trim() for null-safe navigation — making generated code explicit
about intended type semantics.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…licitly, add LVT

- Merge consumer sub-classes into single generated class with private methods
- Remove BINDING ThreadLocal from AbstractSpec; all spec methods take ExecutionContext explicitly
- Delete BindingAware.java and Binding.java, replace with ExecutionContext
- Add abort guard before _extractor/_sink calls matching v1 Groovy behavior
- Add LocalVariableTable to all generated methods (execute, _extractor, _sink)
- Rename binding→ctx throughout for consistency
- Add extraLogType to envoy-als.yaml for compile-time proto resolution
- Remove all Consumer callback methods from spec files
- Add finalizeSink abort check in FilterSpec

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…es, filters)

Previously only run() had LVT. Now all generated methods have named locals
in debuggers/decompilers instead of var0/var1/var2:
- metadata(): this, _samples, _scopeLabels, _aggLabels, _pct
- tag/instance apply(Map): this, param name
- tag/instance apply(Object) bridge: this, o
- forEach accept(): this, element, tags
- decorate accept(): this, _arg, param name
- filter test(): this, param name

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…version 10.4.0-SNAPSHOT

Replace CI-friendly ${revision} with hardcoded 10.4.0-SNAPSHOT in all 104 POMs.
This eliminates persistent "Could not find artifact ...pom:${revision}" errors
when building individual modules without -am. Also removes flatten-maven-plugin
(no longer needed), updates release scripts to use versions:set, and wires
LALSourceTypeProvider SPI for envoy-als extraLog type resolution in tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…chains

Cache the extraLog cast in a _p local variable and break safe-nav chains
into sequential _tN locals instead of deeply nested ternaries. Repeated
access to the same chain prefix reuses existing variables (dedup).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove bind()/evaluate() two-phase pattern from DSL. The mutable
ExecutionContext field made DSL unsafe for concurrent use. Now
evaluate(ExecutionContext) takes ctx as a parameter, matching the
stateless pattern already used by MAL and Hierarchy v2 runtimes.

Update LogFilterListener to store per-request contexts in a list
and pass each to the corresponding DSL.evaluate(ctx) call.
Update LogTestQuery to use the new single-call API.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@wu-sheng wu-sheng added the core feature Core and important feature. Sometimes, break backwards compatibility. label Mar 3, 2026
@wu-sheng wu-sheng added feature New feature complexity:high Relate to multiple(>4) components of SkyWalking labels Mar 3, 2026
@wu-sheng wu-sheng added this to the 10.4.0 milestone Mar 3, 2026
wu-sheng and others added 13 commits March 3, 2026 22:51
Add Apache license headers to SPI service files and YAML config that were
missing them. Fix javadoc error (HTML entity for `>` in MALExpressionModel)
and add missing @throws tags in MALClassGenerator. Update DSL compiler
design doc to reflect LAL ExecutionContext refactoring.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Downgrade h3→h2 and h4→h3 to comply with javadoc's implicit h1 class heading.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace <h3> with <h2> in class javadoc (BatchQueue, GRPCServer,
  HTTPServer, LalRuntimeHelper, RebalanceBenchmark, BatchQueueBenchmark)
- Fix broken {@link DSL#evaluate()} reference in LogFilterListener
- Remove stale level label from LogTestQueryTest LAL snippet
- Add javadoc guidance section to CLAUDE.md

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove flatten:flatten from skywalking.yaml CI commands since
  ${revision} property and flatten-maven-plugin were already removed
- Fix bare > in javadoc <pre> blocks in HierarchyRuleModel and
  HierarchyRuleScriptParser (bad use of '>' on JDK 21 javadoc)
- Add CI-equivalent build command to CLAUDE.md

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…E.md

Extract operational workflows from CLAUDE.md into dedicated skill files:
- /compile: build commands, javadoc checks, checkstyle, heading rules
- /license: header check/fix, dependency license resolution
- /test: unit tests, integration tests, slow integration tests

Remove duplicated content from CLAUDE.md now covered by skills.
Update LICENSE to remove Groovy dependency (replaced by ANTLR4+Javassist).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Prerequisites and Maven profiles are now in the compile skill.
Build commands were already covered by compile and test skills.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… index codegen

- Fix ANTLR4 closureExpr precedence: MUL/DIV > ADD/SUB > regex > ternary
  (was reversed, causing ternary to bind tighter than arithmetic)
- Wrap String casts in parentheses: ((String) tags.get(key)) so subsequent
  method calls like .split() resolve on String, not Object
- Track pastMapAccess in general chain: first IndexAccess uses .get() (Map),
  subsequent ones use [(int) index] (array access)
- Detect boolean-returning methods via String.class reflection for
  ClosureExprCondition instead of wrapping with != null
- Add eBPF e2e override network-profiling-ebpf.yaml to v1-v2 checker
- Add ci-e2e-debug skill for downloading CI artifact logs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Create gh-pull-request skill with pre-flight checks (compile,
  checkstyle, license headers) and PR template instructions
- Move PR submission section from CLAUDE.md into the skill
- Fix ci-e2e-debug from plain file to directory/SKILL.md structure

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The skill now runs pre-flight checks (compile, checkstyle, license)
before every commit+push, not just PR creation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The skill auto-detects PR state via gh pr view on the current branch.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…hod chaining

The eBPF network-profiling e2e test uses LAL patterns that the v2 parser
didn't support: string concatenation with +, parenthesized cast expressions
like (expr as String).split(":")[0].endsWith(".1"), and array indexing.

- Grammar: split valueAccess into valueAccessTerm with PLUS concat,
  add valueParen primary, segmentIndex segment, condParenGroup
- AST: add concatParts, parenInner/parenCast to ValueAccess, IndexSegment
- Parser: refactor visitValueAccess to handle terms, paren, index
- Codegen: add generateParenAccess, IndexSegment handling, concat codegen
- Runtime: add boolean overloads for isNotEmpty/isTrue (primitive returns)
- Test: add network-profiling-e2e.yaml checker case from e2e Helm override
- Add compile-time validation for decorate(): must follow service(),
  not instance()/endpoint(), and not with histogram metrics
- Add MeterEntity comparison to MAL v1-v2 checker: validates service,
  instance, and endpoint names match between v1 and v2
- Include scopeLabels in auto-generated mock data so entity names are
  realistic (not null/empty) during comparison
- Extract MALClosureCodegen and MALCodegenHelper from MALClassGenerator
- Extract LALBlockCodegen and LALCodegenHelper from LALClassGenerator
- Feed real .input.data into LalComparisonTest instead of synthetic LogData
- Add sampledTrace field comparison (traceId, serviceName, latency, etc.)
  between v1 and v2 paths in the checker
- Verify v2 dispatches trace via sourceReceiver.receive()
- Add missing .input.data entries for nginx-error-log,
  envoy-als/network-profiling-slow-trace, and network-profiling-e2e
- Add traceId/serviceName/serviceInstanceName/timestamp cases to
  LALExpressionExecutionTest.assertSampledTrace()
- Update all sampledTrace expect blocks with log-context fields
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

complexity:high Relate to multiple(>4) components of SkyWalking core feature Core and important feature. Sometimes, break backwards compatibility. feature New feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant