This is an automated email from the ASF dual-hosted git repository.
wankai123 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/skywalking.git
The following commit(s) were added to refs/heads/master by this push:
new 2822f125ae Route LAL rules within a layer by input type; add
envoy-als-tcp rule (#13955)
2822f125ae is described below
commit 2822f125ae3ec397c5339ba172aee9ca3a09245f
Author: Wan Kai <[email protected]>
AuthorDate: Tue Jul 21 14:17:03 2026 +0800
Route LAL rules within a layer by input type; add envoy-als-tcp rule
(#13955)
---
docs/en/changes/changes.md | 1 +
.../analyzer/v2/compiler/LALClassGenerator.java | 17 +++-
.../skywalking/oap/log/analyzer/v2/dsl/DSL.java | 16 ++-
.../provider/log/listener/LogFilterListener.java | 26 ++++-
.../compiler/LALClassGeneratorExtractorTest.java | 62 ++++++++++++
.../log/listener/LogFilterListenerRoutingTest.java | 108 +++++++++++++++++++++
.../lal/test-lal/oap-cases/envoy-als.data.yaml | 23 +++++
.../scripts/lal/test-lal/oap-cases/envoy-als.yaml | 27 ++++++
.../src/main/resources/lal/envoy-als.yaml | 27 ++++++
9 files changed, 300 insertions(+), 7 deletions(-)
diff --git a/docs/en/changes/changes.md b/docs/en/changes/changes.md
index f762cba9ad..12ff3aae95 100644
--- a/docs/en/changes/changes.md
+++ b/docs/en/changes/changes.md
@@ -336,6 +336,7 @@
* Surface the effective BanyanDB configuration (`bydb.yml` / `bydb-topn.yml`)
in the `/debugging/config/dump` admin API. Because the BanyanDB config moved to
a separate file in 10.2.0, a BanyanDB deployment previously showed an empty
`storage.banyandb` block in the dump; its post-environment-resolution values
are now merged into the same response under `storage.banyandb.*` (TopN rules
under `storage.banyandb.topN.*`), masked by the same secret-keyword list, via a
generic `ConfigDumpExten [...]
* Fix: an MQE `top_n(metric, N, order, attrX='value')` query whose attribute
is not a column of the target metric now returns a descriptive MQE error
instead of a raw storage `IOException` surfaced as `Internal IO exception,
query metrics error.`. Attribute columns (`attr0..attrN`) exist only on
decorated metrics (`service_*` / `endpoint_*` / `kubernetes_service_*`, set to
the layer name via OAL `.decorator(...)`) and the MAL meter base; metrics such
as relations or database / cache / mq [...]
* Migrate all BanyanDB storage read queries from the typed query-builder API
to BydbQL.
+* Route LAL rules within a layer by their input type, so a single layer can
host rules over different proto inputs. Each compiled rule now carries its
effective input type (the proto class its `parsed.*` getters cast to, or `null`
for parser-based / untyped rules), and `LogFilterListener` skips any rule whose
type doesn't match the incoming log instead of running every rule in the layer.
This fixes a latent `ClassCastException` (caught and logged per log) that fired
whenever a `MESH` log [...]
#### UI
* Add Airflow layer dashboards and menu i18n under Workflow Scheduler in
Horizon UI (SWIP-7).
diff --git
a/oap-server/analyzer/log-analyzer/src/main/java/org/apache/skywalking/oap/log/analyzer/v2/compiler/LALClassGenerator.java
b/oap-server/analyzer/log-analyzer/src/main/java/org/apache/skywalking/oap/log/analyzer/v2/compiler/LALClassGenerator.java
index 4c0cc8d7bc..5453b29d33 100644
---
a/oap-server/analyzer/log-analyzer/src/main/java/org/apache/skywalking/oap/log/analyzer/v2/compiler/LALClassGenerator.java
+++
b/oap-server/analyzer/log-analyzer/src/main/java/org/apache/skywalking/oap/log/analyzer/v2/compiler/LALClassGenerator.java
@@ -84,6 +84,15 @@ public final class LALClassGenerator {
private String classNameHint;
private Class<?> inputType;
private Class<?> outputType;
+ /**
+ * The input type actually used for {@code parsed.*} proto getter codegen:
+ * equals {@link #inputType} for parser-less rules, and {@code null} when a
+ * json/yaml/text parser is present (the parser reads the map, so no proto
+ * cast is emitted). Exposed so the runtime can route a log to this rule
+ * only when the incoming object matches, without re-parsing the DSL. Set
+ * by {@link #compileFromModel}.
+ */
+ private Class<?> effectiveInputType;
private String yamlSource;
/**
* Optional content hash threaded into every generated rule's {@code
GateHolder}
@@ -248,6 +257,10 @@ public final class LALClassGenerator {
this.outputType = outputType;
}
+ public Class<?> getEffectiveInputType() {
+ return effectiveInputType;
+ }
+
public void setYamlSource(final String yamlSource) {
this.yamlSource = yamlSource;
}
@@ -523,9 +536,9 @@ public final class LALClassGenerator {
// generates direct proto getter calls. When a parser is present
(json/yaml/text),
// parsed.* reads from the parsed map and tag() reads from
LogData.Builder tags,
// so inputType must be null to avoid mis-guarding codegen branches.
- final Class<?> effectiveInputType =
+ this.effectiveInputType =
parserType == ParserType.NONE ? this.inputType : null;
- final GenCtx genCtx = new GenCtx(parserType, effectiveInputType,
resolvedOutput);
+ final GenCtx genCtx = new GenCtx(parserType, this.effectiveInputType,
resolvedOutput);
if (parserType == ParserType.NONE && this.inputType != null) {
log.info("LAL rule has no parser — using inputType {} for "
diff --git
a/oap-server/analyzer/log-analyzer/src/main/java/org/apache/skywalking/oap/log/analyzer/v2/dsl/DSL.java
b/oap-server/analyzer/log-analyzer/src/main/java/org/apache/skywalking/oap/log/analyzer/v2/dsl/DSL.java
index 0993bc6a0a..6dbaf23212 100644
---
a/oap-server/analyzer/log-analyzer/src/main/java/org/apache/skywalking/oap/log/analyzer/v2/dsl/DSL.java
+++
b/oap-server/analyzer/log-analyzer/src/main/java/org/apache/skywalking/oap/log/analyzer/v2/dsl/DSL.java
@@ -47,6 +47,19 @@ public class DSL {
@Getter
private final LalExpression expression;
private final FilterSpec filterSpec;
+ /**
+ * The <b>effective</b> proto input type this rule's {@code parsed.*}
getters
+ * cast to, or {@code null} for parser-based / untyped rules (which run
+ * against any input). This is NOT the declared/resolved input type from
the
+ * YAML {@code inputType} field or the SPI ({@code
LALConfig#getInputType()}):
+ * a parser-based rule has a declared type but a {@code null} effective
type,
+ * because it reads the parsed map rather than casting the proto. The
runtime
+ * skips a rule whose effective type doesn't match the incoming log — this
is
+ * how HTTP and TCP envoy access logs, which share {@code Layer.MESH},
route
+ * to their own rules without cross-type {@code ClassCastException}.
+ */
+ @Getter
+ private final Class<?> effectiveInputType;
public static DSL of(final ModuleManager moduleManager,
final LogAnalyzerModuleConfig config,
@@ -105,6 +118,7 @@ public class DSL {
// inline. SHA-256 hash isn't useful to operators; raw text is.
generator.setContent(dsl);
final LalExpression expression = generator.compile(dsl);
+ final Class<?> effectiveInputType =
generator.getEffectiveInputType();
// Stamp the structured rule metadata onto the per-rule GateHolder
so
// dsl-debugging records render {ruleName, layer, outputClass}
alongside
// the verbatim DSL. Only effective when codegen injection is
enabled
@@ -124,7 +138,7 @@ public class DSL {
holder.setMetadata(meta);
}
final FilterSpec filterSpec = new FilterSpec(moduleManager,
config);
- return new DSL(ruleName, expression, filterSpec);
+ return new DSL(ruleName, expression, filterSpec,
effectiveInputType);
} catch (Exception e) {
throw new ModuleStartException(
"Failed to compile LAL expression: " + dsl, e);
diff --git
a/oap-server/analyzer/log-analyzer/src/main/java/org/apache/skywalking/oap/log/analyzer/v2/provider/log/listener/LogFilterListener.java
b/oap-server/analyzer/log-analyzer/src/main/java/org/apache/skywalking/oap/log/analyzer/v2/provider/log/listener/LogFilterListener.java
index 6568b10bab..ec043d477f 100644
---
a/oap-server/analyzer/log-analyzer/src/main/java/org/apache/skywalking/oap/log/analyzer/v2/provider/log/listener/LogFilterListener.java
+++
b/oap-server/analyzer/log-analyzer/src/main/java/org/apache/skywalking/oap/log/analyzer/v2/provider/log/listener/LogFilterListener.java
@@ -76,6 +76,12 @@ public class LogFilterListener implements
LogAnalysisListener {
* not the provider.
*/
private final LALSourceTypeProvider sourceTypeProvider;
+ /**
+ * Rules selected for the current log — the subset of {@link #dsls} whose
+ * declared input type matches the incoming object. Index-aligned with
+ * {@link #contexts}. Rebuilt on every {@link #parse}.
+ */
+ private List<DSL> activeDsls;
private List<ExecutionContext> contexts;
LogFilterListener(final Collection<DSL> dsls, final boolean autoMode,
@@ -87,11 +93,11 @@ public class LogFilterListener implements
LogAnalysisListener {
@Override
public void build() {
- for (int i = 0; i < dsls.size(); i++) {
+ for (int i = 0; i < activeDsls.size(); i++) {
try {
- dsls.get(i).evaluate(contexts.get(i));
+ activeDsls.get(i).evaluate(contexts.get(i));
} catch (final Exception e) {
- log.warn("Failed to evaluate dsl: {}", dsls.get(i), e);
+ log.warn("Failed to evaluate dsl: {}", activeDsls.get(i), e);
}
}
}
@@ -113,13 +119,25 @@ public class LogFilterListener implements
LogAnalysisListener {
@Override
public LogAnalysisListener parse(final LogMetadata metadata,
final Object input) {
+ activeDsls = new ArrayList<>(dsls.size());
contexts = new ArrayList<>(dsls.size());
- for (int i = 0; i < dsls.size(); i++) {
+ for (final DSL dsl : dsls) {
+ // A rule whose parsed.* getters cast to a proto type only applies
to
+ // logs of that type. Envoy HTTP and TCP access logs both dispatch
+ // under Layer.MESH, so without this guard a TCP entry would hit
the
+ // HTTP rule (and vice versa) and throw ClassCastException on the
+ // generated proto cast. Parser-based / untyped rules have a null
+ // effective input type and run against any input, unchanged.
+ final Class<?> effectiveInputType = dsl.getEffectiveInputType();
+ if (effectiveInputType != null &&
!effectiveInputType.isInstance(input)) {
+ continue;
+ }
final ExecutionContext ctx = new ExecutionContext().init(metadata,
input);
ctx.setSourceTypeProvider(sourceTypeProvider);
if (autoMode) {
ctx.autoLayerMode(true);
}
+ activeDsls.add(dsl);
contexts.add(ctx);
}
return this;
diff --git
a/oap-server/analyzer/log-analyzer/src/test/java/org/apache/skywalking/oap/log/analyzer/v2/compiler/LALClassGeneratorExtractorTest.java
b/oap-server/analyzer/log-analyzer/src/test/java/org/apache/skywalking/oap/log/analyzer/v2/compiler/LALClassGeneratorExtractorTest.java
index 179a6a0cdb..5798a929c1 100644
---
a/oap-server/analyzer/log-analyzer/src/test/java/org/apache/skywalking/oap/log/analyzer/v2/compiler/LALClassGeneratorExtractorTest.java
+++
b/oap-server/analyzer/log-analyzer/src/test/java/org/apache/skywalking/oap/log/analyzer/v2/compiler/LALClassGeneratorExtractorTest.java
@@ -19,7 +19,9 @@ package org.apache.skywalking.oap.log.analyzer.v2.compiler;
import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -184,6 +186,66 @@ class LALClassGeneratorExtractorTest extends
LALClassGeneratorTestBase {
compileAndAssert(dsl);
}
+ @Test
+ void effectiveInputTypeKeepsInputTypeWithoutParser() throws Exception {
+ // Parser-less rule: parsed.* casts to the declared proto type, so the
+ // effective input type equals inputType — this is the routing key the
+ // runtime uses to skip type-mismatched rules
(LogFilterListener#parse).
+ generator.setInputType(
+ io.envoyproxy.envoy.data.accesslog.v3.HTTPAccessLogEntry.class);
+ compileAndAssert("filter {\n sink {}\n}");
+ assertEquals(
+ io.envoyproxy.envoy.data.accesslog.v3.HTTPAccessLogEntry.class,
+ generator.getEffectiveInputType());
+ }
+
+ @Test
+ void compileEnvoyTcpAlsRule() throws Exception {
+ // Guards the shipped envoy-als-tcp rule: verifies its parsed.* chains
+ // resolve against TCPAccessLogEntry (commonProperties.responseFlags),
+ // so a field-name typo fails here instead of crashing OAP at startup.
+ generator.setInputType(
+ io.envoyproxy.envoy.data.accesslog.v3.TCPAccessLogEntry.class);
+ final String dsl =
+ "filter {\n"
+ + " if
(!parsed?.commonProperties?.responseFlags?.toString()?.trim()) {\n"
+ + " abort {}\n"
+ + " }\n"
+ + " extractor {\n"
+ + " tag 'response.flag':
parsed?.commonProperties?.responseFlags\n"
+ + " }\n"
+ + " sink {\n"
+ + " sampler {\n"
+ + " rateLimit(\"${log.service}:"
+ + "${parsed?.commonProperties?.responseFlags?.toString()}\") {\n"
+ + " rpm 6000\n"
+ + " }\n"
+ + " }\n"
+ + " }\n"
+ + "}";
+ final String source = generator.generateSource(dsl);
+ final String fqcn =
+ "io.envoyproxy.envoy.data.accesslog.v3.TCPAccessLogEntry";
+ assertTrue(source.contains(
+ fqcn + " _p = (" + fqcn + ") h.ctx().input()"),
+ "Expected _p cast to TCPAccessLogEntry but got: " + source);
+ assertTrue(source.contains("_p.getCommonProperties()"),
+ "Expected _p.getCommonProperties() but got: " + source);
+ compileAndAssert(dsl);
+ }
+
+ @Test
+ void effectiveInputTypeIsNullWhenParserPresent() throws Exception {
+ // A json/yaml/text parser reads the parsed map, not proto getters, so
+ // the effective input type must be null even when inputType is set —
+ // the rule then runs against any input (e.g. network-profiling json).
+ generator.setInputType(
+ io.envoyproxy.envoy.data.accesslog.v3.HTTPAccessLogEntry.class);
+ compileAndAssert("filter {\n json {}\n sink {}\n}");
+ assertNull(generator.getEffectiveInputType(),
+ "A json/yaml/text parser must null out the effective input type.");
+ }
+
// ==================== Output field assignment ====================
@Test
diff --git
a/oap-server/analyzer/log-analyzer/src/test/java/org/apache/skywalking/oap/log/analyzer/v2/provider/log/listener/LogFilterListenerRoutingTest.java
b/oap-server/analyzer/log-analyzer/src/test/java/org/apache/skywalking/oap/log/analyzer/v2/provider/log/listener/LogFilterListenerRoutingTest.java
new file mode 100644
index 0000000000..d079595702
--- /dev/null
+++
b/oap-server/analyzer/log-analyzer/src/test/java/org/apache/skywalking/oap/log/analyzer/v2/provider/log/listener/LogFilterListenerRoutingTest.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.skywalking.oap.log.analyzer.v2.provider.log.listener;
+
+import io.envoyproxy.envoy.data.accesslog.v3.HTTPAccessLogEntry;
+import io.envoyproxy.envoy.data.accesslog.v3.TCPAccessLogEntry;
+import java.util.Arrays;
+import java.util.Collections;
+import org.apache.skywalking.oap.log.analyzer.v2.dsl.DSL;
+import org.apache.skywalking.oap.server.core.source.LogMetadata;
+import org.junit.jupiter.api.Test;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+/**
+ * Routing tests for {@link LogFilterListener#parse}: a rule that declares a
+ * typed proto input only applies to logs of that type. Envoy HTTP and TCP
+ * access logs share {@code Layer.MESH}, so the listener must dispatch each
+ * entry to the rule whose input type matches and skip the others — otherwise
+ * the mismatched rule throws {@code ClassCastException} on its generated proto
+ * cast. Rules with a {@code null} input type (parser-based / untyped) run
+ * against any input.
+ *
+ * <p>{@link DSL} is mocked so the assertions observe exactly which rules the
+ * listener evaluated, independent of DSL compilation.
+ */
+class LogFilterListenerRoutingTest {
+
+ private static LogMetadata meshMetadata() {
+ return LogMetadata.builder().service("svc").layer("MESH").build();
+ }
+
+ private static DSL ruleWithEffectiveInputType(final Class<?>
effectiveInputType) {
+ final DSL dsl = mock(DSL.class);
+ // doReturn avoids the Class<?> wildcard-capture mismatch that
+ // when(...).thenReturn(Class<?>) triggers on getEffectiveInputType().
+ doReturn(effectiveInputType).when(dsl).getEffectiveInputType();
+ return dsl;
+ }
+
+ @Test
+ void tcpEntryReachesOnlyTcpAndParserRules() {
+ // Mirrors the MESH bucket: envoy-als (HTTP), envoy-als-tcp (TCP), and
+ // network-profiling-slow-trace (json parser, null inputType).
+ final DSL httpRule =
ruleWithEffectiveInputType(HTTPAccessLogEntry.class);
+ final DSL tcpRule =
ruleWithEffectiveInputType(TCPAccessLogEntry.class);
+ final DSL parserRule = ruleWithEffectiveInputType(null);
+
+ final LogFilterListener listener = new LogFilterListener(
+ Arrays.asList(httpRule, tcpRule, parserRule), false, null);
+
+ listener.parse(meshMetadata(), TCPAccessLogEntry.newBuilder().build());
+ listener.build();
+
+ verify(tcpRule).evaluate(any());
+ verify(parserRule).evaluate(any());
+ verify(httpRule, never()).evaluate(any());
+ }
+
+ @Test
+ void httpEntryReachesOnlyHttpAndParserRules() {
+ final DSL httpRule =
ruleWithEffectiveInputType(HTTPAccessLogEntry.class);
+ final DSL tcpRule =
ruleWithEffectiveInputType(TCPAccessLogEntry.class);
+ final DSL parserRule = ruleWithEffectiveInputType(null);
+
+ final LogFilterListener listener = new LogFilterListener(
+ Arrays.asList(httpRule, tcpRule, parserRule), false, null);
+
+ listener.parse(meshMetadata(),
HTTPAccessLogEntry.newBuilder().build());
+ listener.build();
+
+ verify(httpRule).evaluate(any());
+ verify(parserRule).evaluate(any());
+ verify(tcpRule, never()).evaluate(any());
+ }
+
+ @Test
+ void untypedRuleRunsForAnyInput() {
+ final DSL untyped = ruleWithEffectiveInputType(null);
+
+ final LogFilterListener listener = new LogFilterListener(
+ Collections.singletonList(untyped), false, null);
+
+ listener.parse(meshMetadata(), TCPAccessLogEntry.newBuilder().build());
+ listener.build();
+
+ verify(untyped).evaluate(any());
+ }
+}
diff --git
a/oap-server/analyzer/log-analyzer/src/test/resources/scripts/lal/test-lal/oap-cases/envoy-als.data.yaml
b/oap-server/analyzer/log-analyzer/src/test/resources/scripts/lal/test-lal/oap-cases/envoy-als.data.yaml
index 1b644ec757..ba4c2201f8 100644
---
a/oap-server/analyzer/log-analyzer/src/test/resources/scripts/lal/test-lal/oap-cases/envoy-als.data.yaml
+++
b/oap-server/analyzer/log-analyzer/src/test/resources/scripts/lal/test-lal/oap-cases/envoy-als.data.yaml
@@ -47,6 +47,29 @@ envoy-als:
abort: false
tag.response.flag: "upstream_connection_failure: true\n"
+# The envoy-als-tcp rule processes protobuf TCPAccessLogEntry as extraLog.
+# TCP entries have no HTTP status code; the rule filters on
+# commonProperties.responseFlags and tags it as response.flag.
+envoy-als-tcp:
+ - service: test-mesh-tcp-svc
+ body-type: none
+ extra-log:
+ proto-class: io.envoyproxy.envoy.data.accesslog.v3.TCPAccessLogEntry
+ proto-json:
'{"commonProperties":{"responseFlags":{"upstreamConnectionFailure":true}}}'
+ expect:
+ save: true
+ abort: false
+ tag.response.flag: "upstream_connection_failure: true\n"
+
+ - service: test-mesh-tcp-svc-abort
+ body-type: none
+ extra-log:
+ proto-class: io.envoyproxy.envoy.data.accesslog.v3.TCPAccessLogEntry
+ proto-json:
'{"commonProperties":{"upstreamCluster":"outbound|80||backend.default.svc"}}'
+ expect:
+ save: true
+ abort: true
+
network-profiling-slow-trace:
body-type: json
body:
'{"latency":800,"uri":"/mesh/api","reason":"SLOW","service":"envoy-mesh-svc","serviceInstance":"envoy-inst-1","client_process":{"process_id":"proc-c1","local":false,"address":"10.0.0.5:8080"},"server_process":{"process_id":"","local":true,"address":""},"detect_point":"SERVER","component":"http","ssl":false}'
diff --git
a/oap-server/analyzer/log-analyzer/src/test/resources/scripts/lal/test-lal/oap-cases/envoy-als.yaml
b/oap-server/analyzer/log-analyzer/src/test/resources/scripts/lal/test-lal/oap-cases/envoy-als.yaml
index ae23160841..92d865e6b7 100644
---
a/oap-server/analyzer/log-analyzer/src/test/resources/scripts/lal/test-lal/oap-cases/envoy-als.yaml
+++
b/oap-server/analyzer/log-analyzer/src/test/resources/scripts/lal/test-lal/oap-cases/envoy-als.yaml
@@ -51,6 +51,33 @@ rules:
}
}
}
+ # The TCP counterpart of envoy-als. HTTP and TCP access logs share
+ # Layer.MESH; the runtime routes each entry to the rule whose inputType
+ # matches (see LogFilterListener#parse), so this rule only ever sees
+ # TCPAccessLogEntry and the HTTP rule above only sees HTTPAccessLogEntry.
+ - name: envoy-als-tcp
+ layer: MESH
+ inputType: io.envoyproxy.envoy.data.accesslog.v3.TCPAccessLogEntry
+ dsl: |
+ filter {
+ // TCP access logs have no HTTP status code; only collect abnormal
+ // connections (commonProperties?.responseFlags is not empty).
+ if (!parsed?.commonProperties?.responseFlags?.toString()?.trim()) {
+ abort {}
+ }
+ extractor {
+ tag 'response.flag': parsed?.commonProperties?.responseFlags
+ }
+ sink {
+ sampler {
+ // use service:responseFlags as sampler id so that each
+ // service:responseFlags has its own sampler.
+
rateLimit("${log.service}:${parsed?.commonProperties?.responseFlags?.toString()}")
{
+ rpm 6000
+ }
+ }
+ }
+ }
- name: network-profiling-slow-trace
layer: MESH
outputType: SampledTrace
diff --git a/oap-server/server-starter/src/main/resources/lal/envoy-als.yaml
b/oap-server/server-starter/src/main/resources/lal/envoy-als.yaml
index ae23160841..92d865e6b7 100644
--- a/oap-server/server-starter/src/main/resources/lal/envoy-als.yaml
+++ b/oap-server/server-starter/src/main/resources/lal/envoy-als.yaml
@@ -51,6 +51,33 @@ rules:
}
}
}
+ # The TCP counterpart of envoy-als. HTTP and TCP access logs share
+ # Layer.MESH; the runtime routes each entry to the rule whose inputType
+ # matches (see LogFilterListener#parse), so this rule only ever sees
+ # TCPAccessLogEntry and the HTTP rule above only sees HTTPAccessLogEntry.
+ - name: envoy-als-tcp
+ layer: MESH
+ inputType: io.envoyproxy.envoy.data.accesslog.v3.TCPAccessLogEntry
+ dsl: |
+ filter {
+ // TCP access logs have no HTTP status code; only collect abnormal
+ // connections (commonProperties?.responseFlags is not empty).
+ if (!parsed?.commonProperties?.responseFlags?.toString()?.trim()) {
+ abort {}
+ }
+ extractor {
+ tag 'response.flag': parsed?.commonProperties?.responseFlags
+ }
+ sink {
+ sampler {
+ // use service:responseFlags as sampler id so that each
+ // service:responseFlags has its own sampler.
+
rateLimit("${log.service}:${parsed?.commonProperties?.responseFlags?.toString()}")
{
+ rpm 6000
+ }
+ }
+ }
+ }
- name: network-profiling-slow-trace
layer: MESH
outputType: SampledTrace