This is an automated email from the ASF dual-hosted git repository.

wusheng 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 d8b97f8e5b LAL: move service resolution into LALOutputBuilder, fix tag 
assignment restriction (#13741)
d8b97f8e5b is described below

commit d8b97f8e5b5e0766217490915f2871167491b8fb
Author: 吴晟 Wu Sheng <[email protected]>
AuthorDate: Thu Mar 12 15:48:44 2026 +0800

    LAL: move service resolution into LALOutputBuilder, fix tag assignment 
restriction (#13741)
    
      1. Refactor LALOutputBuilder.init() to take ModuleManager instead of
         NamingControl. Each builder (LogBuilder, DatabaseSlowStatementBuilder,
         SampledTraceBuilder, EnvoyAccessLogBuilder) now resolves its own
         services and caches them in static fields. RecordSinkListener no
         longer holds NamingControl, searchableTagKeys, or instanceof checks.
    
      2. Fix bug where LAL tag assignments were incorrectly restricted to
         LogBuilder via isAssignableFrom check, blocking any other output
         builder from defining addTag(String, String).
---
 .../listener/DatabaseSlowStatementBuilder.java     | 22 ++++++++---
 .../trace/parser/listener/SampledTraceBuilder.java | 24 +++++++++---
 oap-server/analyzer/log-analyzer/CLAUDE.md         |  7 +++-
 .../log/analyzer/v2/compiler/LALBlockCodegen.java  | 12 ------
 .../provider/log/listener/RecordSinkListener.java  | 33 ++++-------------
 .../oap/server/core/source/LALOutputBuilder.java   | 11 +++---
 .../oap/server/core/source/LogBuilder.java         | 39 ++++++++++++++------
 .../envoy/persistence/EnvoyAccessLogBuilder.java   |  6 +--
 .../persistence/EnvoyAccessLogBuilderTest.java     | 43 +++++++++++++++++++---
 .../envoy/persistence/EnvoyAlsLalTest.java         | 40 +++++++++++++++++---
 10 files changed, 154 insertions(+), 83 deletions(-)

diff --git 
a/oap-server/analyzer/agent-analyzer/src/main/java/org/apache/skywalking/oap/server/analyzer/provider/trace/parser/listener/DatabaseSlowStatementBuilder.java
 
b/oap-server/analyzer/agent-analyzer/src/main/java/org/apache/skywalking/oap/server/analyzer/provider/trace/parser/listener/DatabaseSlowStatementBuilder.java
index 1ab9d17204..db33d33e2f 100644
--- 
a/oap-server/analyzer/agent-analyzer/src/main/java/org/apache/skywalking/oap/server/analyzer/provider/trace/parser/listener/DatabaseSlowStatementBuilder.java
+++ 
b/oap-server/analyzer/agent-analyzer/src/main/java/org/apache/skywalking/oap/server/analyzer/provider/trace/parser/listener/DatabaseSlowStatementBuilder.java
@@ -23,6 +23,7 @@ import lombok.Getter;
 import lombok.Setter;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.skywalking.apm.network.logging.v3.LogData;
+import org.apache.skywalking.oap.server.core.CoreModule;
 import org.apache.skywalking.oap.server.core.analysis.DownSampling;
 import org.apache.skywalking.oap.server.core.analysis.IDManager;
 import org.apache.skywalking.oap.server.core.analysis.Layer;
@@ -31,12 +32,14 @@ import 
org.apache.skywalking.oap.server.core.config.NamingControl;
 import org.apache.skywalking.oap.server.core.source.DatabaseSlowStatement;
 import org.apache.skywalking.oap.server.core.source.LALOutputBuilder;
 import org.apache.skywalking.oap.server.core.source.SourceReceiver;
+import org.apache.skywalking.oap.server.library.module.ModuleManager;
 
 @Slf4j
 public class DatabaseSlowStatementBuilder implements LALOutputBuilder {
     public static final String NAME = "SlowSQL";
 
-    private NamingControl namingControl;
+    private static NamingControl NAMING_CONTROL;
+    private static boolean INITIALIZED;
 
     @Getter
     @Setter
@@ -66,8 +69,12 @@ public class DatabaseSlowStatementBuilder implements 
LALOutputBuilder {
     public DatabaseSlowStatementBuilder() {
     }
 
+    /**
+     * Constructor for v1 (Groovy) path which doesn't use {@link #init}.
+     */
     public DatabaseSlowStatementBuilder(final NamingControl namingControl) {
-        this.namingControl = namingControl;
+        NAMING_CONTROL = namingControl;
+        INITIALIZED = true;
     }
 
     @Override
@@ -77,8 +84,13 @@ public class DatabaseSlowStatementBuilder implements 
LALOutputBuilder {
 
     @Override
     public void init(final LogData logData, final Optional<Object> extraLog,
-                     final NamingControl namingControl) {
-        this.namingControl = namingControl;
+                     final ModuleManager moduleManager) {
+        if (!INITIALIZED) {
+            NAMING_CONTROL = moduleManager.find(CoreModule.NAME)
+                                          .provider()
+                                          .getService(NamingControl.class);
+            INITIALIZED = true;
+        }
         // Only populate fields not already set by the LAL extractor.
         if (this.serviceName == null) {
             this.serviceName = logData.getService();
@@ -114,7 +126,7 @@ public class DatabaseSlowStatementBuilder implements 
LALOutputBuilder {
     }
 
     public void prepare() {
-        this.serviceName = namingControl.formatServiceName(serviceName);
+        this.serviceName = NAMING_CONTROL.formatServiceName(serviceName);
     }
 
     public DatabaseSlowStatement toDatabaseSlowStatement() {
diff --git 
a/oap-server/analyzer/agent-analyzer/src/main/java/org/apache/skywalking/oap/server/analyzer/provider/trace/parser/listener/SampledTraceBuilder.java
 
b/oap-server/analyzer/agent-analyzer/src/main/java/org/apache/skywalking/oap/server/analyzer/provider/trace/parser/listener/SampledTraceBuilder.java
index 88997b63cb..1605a7ca10 100644
--- 
a/oap-server/analyzer/agent-analyzer/src/main/java/org/apache/skywalking/oap/server/analyzer/provider/trace/parser/listener/SampledTraceBuilder.java
+++ 
b/oap-server/analyzer/agent-analyzer/src/main/java/org/apache/skywalking/oap/server/analyzer/provider/trace/parser/listener/SampledTraceBuilder.java
@@ -34,6 +34,7 @@ import 
org.apache.skywalking.oap.server.core.analysis.manual.trace.SampledStatus
 import 
org.apache.skywalking.oap.server.core.analysis.manual.trace.SampledStatus5xxTraceRecord;
 import org.apache.skywalking.oap.server.core.analysis.record.Record;
 import 
org.apache.skywalking.oap.server.core.analysis.worker.RecordStreamProcessor;
+import org.apache.skywalking.oap.server.core.CoreModule;
 import org.apache.skywalking.oap.server.core.config.NamingControl;
 import org.apache.skywalking.oap.server.core.source.DefaultScopeDefine;
 import org.apache.skywalking.oap.server.core.source.DetectPoint;
@@ -41,12 +42,14 @@ import org.apache.skywalking.oap.server.core.source.ISource;
 import org.apache.skywalking.oap.server.core.source.LALOutputBuilder;
 import org.apache.skywalking.oap.server.core.source.ProcessRelation;
 import org.apache.skywalking.oap.server.core.source.SourceReceiver;
+import org.apache.skywalking.oap.server.library.module.ModuleManager;
 
 @Slf4j
 public class SampledTraceBuilder implements LALOutputBuilder {
     public static final String NAME = "SampledTrace";
 
-    private NamingControl namingControl;
+    private static NamingControl NAMING_CONTROL;
+    private static boolean INITIALIZED;
 
     @Setter
     @Getter
@@ -90,8 +93,12 @@ public class SampledTraceBuilder implements LALOutputBuilder 
{
     public SampledTraceBuilder() {
     }
 
+    /**
+     * Constructor for v1 (Groovy) path which doesn't use {@link #init}.
+     */
     public SampledTraceBuilder(final NamingControl namingControl) {
-        this.namingControl = namingControl;
+        NAMING_CONTROL = namingControl;
+        INITIALIZED = true;
     }
 
     @Override
@@ -101,8 +108,13 @@ public class SampledTraceBuilder implements 
LALOutputBuilder {
 
     @Override
     public void init(final LogData logData, final Optional<Object> extraLog,
-                     final NamingControl namingControl) {
-        this.namingControl = namingControl;
+                     final ModuleManager moduleManager) {
+        if (!INITIALIZED) {
+            NAMING_CONTROL = moduleManager.find(CoreModule.NAME)
+                                          .provider()
+                                          .getService(NamingControl.class);
+            INITIALIZED = true;
+        }
         // Only populate fields not already set by the LAL extractor.
         if (this.traceId == null) {
             this.traceId = logData.getTraceContext().getTraceId();
@@ -203,9 +215,9 @@ public class SampledTraceBuilder implements 
LALOutputBuilder {
 
     public ISource toEntity() {
         final ProcessRelation processRelation = new ProcessRelation();
-        final String serviceId = 
IDManager.ServiceID.buildId(namingControl.formatServiceName(serviceName),
+        final String serviceId = 
IDManager.ServiceID.buildId(NAMING_CONTROL.formatServiceName(serviceName),
             Layer.nameOf(layer).isNormal());
-        final String instanceId = 
IDManager.ServiceInstanceID.buildId(serviceId, 
namingControl.formatInstanceName(serviceInstanceName));
+        final String instanceId = 
IDManager.ServiceInstanceID.buildId(serviceId, 
NAMING_CONTROL.formatInstanceName(serviceInstanceName));
         processRelation.setInstanceId(instanceId);
         processRelation.setSourceProcessId(processId);
         processRelation.setDestProcessId(destProcessId);
diff --git a/oap-server/analyzer/log-analyzer/CLAUDE.md 
b/oap-server/analyzer/log-analyzer/CLAUDE.md
index a7adcee94d..3a0f6b0d13 100644
--- a/oap-server/analyzer/log-analyzer/CLAUDE.md
+++ b/oap-server/analyzer/log-analyzer/CLAUDE.md
@@ -237,8 +237,11 @@ validates that a matching setter exists on the output type 
class (e.g., `setStat
 If no setter is found, compilation fails with an `IllegalArgumentException` at 
boot.
 
 **Runtime dispatch**: `RecordSinkListener.parse()` reads the output object from
-`ExecutionContext.output()` (already populated by generated code), calls 
`init()` for
-builder mode, then `build()` dispatches via `complete()` or 
`sourceReceiver.receive()`.
+`ExecutionContext.output()` (already populated by generated code), calls
+`init(logData, extraLog, moduleManager)` to populate standard fields and 
resolve
+services (e.g., `NamingControl`, `ConfigService`) from `ModuleManager`, then 
`build()`
+dispatches via `complete(sourceReceiver)`. Each builder caches resolved 
services in
+static fields so `ModuleManager` lookups only happen once.
 
 Note: `slowSql {}` and `sampledTrace {}` sub-DSLs were removed. Custom output 
types use
 the `outputType` + output field mechanism instead of dedicated DSL blocks.
diff --git 
a/oap-server/analyzer/log-analyzer/src/main/java/org/apache/skywalking/oap/log/analyzer/v2/compiler/LALBlockCodegen.java
 
b/oap-server/analyzer/log-analyzer/src/main/java/org/apache/skywalking/oap/log/analyzer/v2/compiler/LALBlockCodegen.java
index d3f2647150..629edf7f4e 100644
--- 
a/oap-server/analyzer/log-analyzer/src/main/java/org/apache/skywalking/oap/log/analyzer/v2/compiler/LALBlockCodegen.java
+++ 
b/oap-server/analyzer/log-analyzer/src/main/java/org/apache/skywalking/oap/log/analyzer/v2/compiler/LALBlockCodegen.java
@@ -288,18 +288,6 @@ final class LALBlockCodegen {
     static void generateTagAssignment(final StringBuilder sb,
                                        final LALScriptModel.TagAssignment tag,
                                        final LALClassGenerator.GenCtx genCtx) {
-        // tag assignments are only supported on LogBuilder (the default 
output type).
-        // Other output types (e.g. SampledTraceBuilder, 
DatabaseSlowStatementBuilder)
-        // do not carry tags — fail at compile time instead of silently 
dropping them.
-        if (genCtx.outputType != null
-                && 
!org.apache.skywalking.oap.server.core.source.LogBuilder.class
-                        .isAssignableFrom(genCtx.outputType)) {
-            throw new IllegalArgumentException(
-                "LAL 'tag' assignments are only supported when outputType is 
LogBuilder"
-                    + " (or default), but the resolved outputType is "
-                    + genCtx.outputType.getName()
-                    + ". Remove the 'tag' statements or change the 
outputType.");
-        }
         for (final Map.Entry<String, LALScriptModel.TagValue> entry
                 : tag.getTags().entrySet()) {
             sb.append("  _o.addTag(\"")
diff --git 
a/oap-server/analyzer/log-analyzer/src/main/java/org/apache/skywalking/oap/log/analyzer/v2/provider/log/listener/RecordSinkListener.java
 
b/oap-server/analyzer/log-analyzer/src/main/java/org/apache/skywalking/oap/log/analyzer/v2/provider/log/listener/RecordSinkListener.java
index 2f7c16cb91..11e741db7d 100644
--- 
a/oap-server/analyzer/log-analyzer/src/main/java/org/apache/skywalking/oap/log/analyzer/v2/provider/log/listener/RecordSinkListener.java
+++ 
b/oap-server/analyzer/log-analyzer/src/main/java/org/apache/skywalking/oap/log/analyzer/v2/provider/log/listener/RecordSinkListener.java
@@ -17,20 +17,14 @@
 
 package org.apache.skywalking.oap.log.analyzer.v2.provider.log.listener;
 
-import java.util.Arrays;
-import java.util.List;
 import java.util.Optional;
 import lombok.SneakyThrows;
 import org.apache.skywalking.apm.network.logging.v3.LogData;
 
 import org.apache.skywalking.oap.log.analyzer.v2.dsl.ExecutionContext;
 import 
org.apache.skywalking.oap.log.analyzer.v2.provider.LogAnalyzerModuleConfig;
-import org.apache.skywalking.oap.server.core.Const;
 import org.apache.skywalking.oap.server.core.CoreModule;
-import org.apache.skywalking.oap.server.core.config.ConfigService;
-import org.apache.skywalking.oap.server.core.config.NamingControl;
 import org.apache.skywalking.oap.server.core.source.LALOutputBuilder;
-import org.apache.skywalking.oap.server.core.source.LogBuilder;
 import org.apache.skywalking.oap.server.core.source.SourceReceiver;
 import org.apache.skywalking.oap.server.library.module.ModuleManager;
 import org.slf4j.Logger;
@@ -46,17 +40,14 @@ import org.slf4j.LoggerFactory;
 public class RecordSinkListener implements LogSinkListener {
     private static final Logger LOGGER = 
LoggerFactory.getLogger(RecordSinkListener.class);
     private final SourceReceiver sourceReceiver;
-    private final NamingControl namingControl;
-    private final List<String> searchableTagKeys;
+    private final ModuleManager moduleManager;
 
     private LALOutputBuilder builder;
 
     RecordSinkListener(final SourceReceiver sourceReceiver,
-                       final NamingControl namingControl,
-                       final List<String> searchableTagKeys) {
+                       final ModuleManager moduleManager) {
         this.sourceReceiver = sourceReceiver;
-        this.namingControl = namingControl;
-        this.searchableTagKeys = searchableTagKeys;
+        this.moduleManager = moduleManager;
     }
 
     @Override
@@ -87,12 +78,9 @@ public class RecordSinkListener implements LogSinkListener {
             return this;
         }
         builder = ctx.outputAsBuilder();
-        if (builder instanceof LogBuilder) {
-            ((LogBuilder) builder).setSearchableTagKeys(searchableTagKeys);
-        }
         // Pass the input data matching the declared inputType:
         // extraLog (e.g., HTTPAccessLogEntry) when present, otherwise LogData.
-        builder.init(logData.build(), extraLog, namingControl);
+        builder.init(logData.build(), extraLog, moduleManager);
         return this;
     }
 
@@ -102,25 +90,18 @@ public class RecordSinkListener implements LogSinkListener 
{
 
     public static class Factory implements LogSinkListenerFactory {
         private final SourceReceiver sourceReceiver;
-        private final NamingControl namingControl;
-        private final List<String> searchableTagKeys;
+        private final ModuleManager moduleManager;
 
         public Factory(ModuleManager moduleManager, LogAnalyzerModuleConfig 
moduleConfig) {
             this.sourceReceiver = moduleManager.find(CoreModule.NAME)
                                                .provider()
                                                
.getService(SourceReceiver.class);
-            this.namingControl = moduleManager.find(CoreModule.NAME)
-                                              .provider()
-                                              .getService(NamingControl.class);
-            ConfigService configService = moduleManager.find(CoreModule.NAME)
-                                                       .provider()
-                                                       
.getService(ConfigService.class);
-            this.searchableTagKeys = 
Arrays.asList(configService.getSearchableLogsTags().split(Const.COMMA));
+            this.moduleManager = moduleManager;
         }
 
         @Override
         public RecordSinkListener create() {
-            return new RecordSinkListener(sourceReceiver, namingControl, 
searchableTagKeys);
+            return new RecordSinkListener(sourceReceiver, moduleManager);
         }
     }
 }
diff --git 
a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/LALOutputBuilder.java
 
b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/LALOutputBuilder.java
index 94c4ed4886..fad33dd9a8 100644
--- 
a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/LALOutputBuilder.java
+++ 
b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/LALOutputBuilder.java
@@ -20,7 +20,7 @@ package org.apache.skywalking.oap.server.core.source;
 
 import java.util.Optional;
 import org.apache.skywalking.apm.network.logging.v3.LogData;
-import org.apache.skywalking.oap.server.core.config.NamingControl;
+import org.apache.skywalking.oap.server.library.module.ModuleManager;
 
 /**
  * Interface for LAL output builders that produce {@link Source} objects from
@@ -54,11 +54,12 @@ public interface LALOutputBuilder {
      * Called once per log entry.
      *
      * @param logData  log metadata (service, layer, timestamp, trace context, 
etc.)
-     * @param extraLog optional extra input whose type matches
-     *                 {@code LALSourceTypeProvider#inputType()} for the layer
-     *                 (e.g., {@code HTTPAccessLogEntry} for envoy access logs)
+     * @param extraLog      optional extra input whose type matches
+     *                      {@code LALSourceTypeProvider#inputType()} for the 
layer
+     *                      (e.g., {@code HTTPAccessLogEntry} for envoy access 
logs)
+     * @param moduleManager module manager for resolving services (e.g., 
NamingControl)
      */
-    void init(LogData logData, Optional<Object> extraLog, NamingControl 
namingControl);
+    void init(LogData logData, Optional<Object> extraLog, ModuleManager 
moduleManager);
 
     /**
      * Validate the builder state and dispatch the final output source(s).
diff --git 
a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/LogBuilder.java
 
b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/LogBuilder.java
index a7d2cbdcbf..96f7f7a294 100644
--- 
a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/LogBuilder.java
+++ 
b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/source/LogBuilder.java
@@ -19,6 +19,7 @@
 package org.apache.skywalking.oap.server.core.source;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.List;
@@ -31,12 +32,16 @@ import lombok.extern.slf4j.Slf4j;
 import org.apache.skywalking.apm.network.logging.v3.LogData;
 import org.apache.skywalking.apm.network.logging.v3.LogDataBody;
 import org.apache.skywalking.apm.network.logging.v3.TraceContext;
+import org.apache.skywalking.oap.server.core.Const;
+import org.apache.skywalking.oap.server.core.CoreModule;
 import org.apache.skywalking.oap.server.core.analysis.IDManager;
 import org.apache.skywalking.oap.server.core.analysis.TimeBucket;
 import org.apache.skywalking.oap.server.core.analysis.manual.searchtag.Tag;
 import org.apache.skywalking.oap.server.core.analysis.manual.searchtag.TagType;
+import org.apache.skywalking.oap.server.core.config.ConfigService;
 import org.apache.skywalking.oap.server.core.config.NamingControl;
 import org.apache.skywalking.oap.server.core.query.type.ContentType;
+import org.apache.skywalking.oap.server.library.module.ModuleManager;
 import org.apache.skywalking.oap.server.library.util.StringUtil;
 
 /**
@@ -47,11 +52,11 @@ import 
org.apache.skywalking.oap.server.library.util.StringUtil;
 public class LogBuilder implements LALOutputBuilder {
     public static final String NAME = "Log";
 
-    private NamingControl namingControl;
-    private LogData logData;
+    private static NamingControl NAMING_CONTROL;
+    private static List<String> SEARCHABLE_TAG_KEYS;
+    private static boolean INITIALIZED;
 
-    @Setter
-    private List<String> searchableTagKeys;
+    private LogData logData;
 
     @Setter
     private String service;
@@ -91,8 +96,18 @@ public class LogBuilder implements LALOutputBuilder {
 
     @Override
     public void init(final LogData logData, final Optional<Object> extraLog,
-                     final NamingControl namingControl) {
-        this.namingControl = namingControl;
+                     final ModuleManager moduleManager) {
+        if (!INITIALIZED) {
+            NAMING_CONTROL = moduleManager.find(CoreModule.NAME)
+                                          .provider()
+                                          .getService(NamingControl.class);
+            final ConfigService configService = 
moduleManager.find(CoreModule.NAME)
+                                                             .provider()
+                                                             
.getService(ConfigService.class);
+            SEARCHABLE_TAG_KEYS = Arrays.asList(
+                configService.getSearchableLogsTags().split(Const.COMMA));
+            INITIALIZED = true;
+        }
         this.logData = logData;
         // Only populate fields that were NOT already set by the LAL extractor.
         // The extractor runs before init(), so extractor values take priority.
@@ -139,19 +154,19 @@ public class LogBuilder implements LALOutputBuilder {
         log.setTimeBucket(TimeBucket.getRecordTimeBucket(timestamp));
 
         // service
-        final String serviceName = namingControl.formatServiceName(service);
+        final String serviceName = NAMING_CONTROL.formatServiceName(service);
         final String serviceId = IDManager.ServiceID.buildId(serviceName, 
true);
         log.setServiceId(serviceId);
         // service instance
         if (StringUtil.isNotEmpty(serviceInstance)) {
             log.setServiceInstanceId(IDManager.ServiceInstanceID.buildId(
                 serviceId,
-                namingControl.formatInstanceName(serviceInstance)
+                NAMING_CONTROL.formatInstanceName(serviceInstance)
             ));
         }
         // endpoint
         if (StringUtil.isNotEmpty(endpoint)) {
-            final String endpointName = 
namingControl.formatEndpointName(serviceName, endpoint);
+            final String endpointName = 
NAMING_CONTROL.formatEndpointName(serviceName, endpoint);
             log.setEndpointId(IDManager.EndpointID.buildId(serviceId, 
endpointName));
         }
         // trace
@@ -188,16 +203,16 @@ public class LogBuilder implements LALOutputBuilder {
 
     private Collection<Tag> collectSearchableTags() {
         final HashSet<Tag> result = new HashSet<>();
-        if (searchableTagKeys != null) {
+        if (SEARCHABLE_TAG_KEYS != null) {
             // Tags from original LogData
             logData.getTags().getDataList().forEach(kv -> {
-                if (searchableTagKeys.contains(kv.getKey())) {
+                if (SEARCHABLE_TAG_KEYS.contains(kv.getKey())) {
                     addSearchableTag(result, kv.getKey(), kv.getValue());
                 }
             });
             // Tags added by LAL extractor
             for (final String[] kv : lalTags) {
-                if (searchableTagKeys.contains(kv[0])) {
+                if (SEARCHABLE_TAG_KEYS.contains(kv[0])) {
                     addSearchableTag(result, kv[0], kv[1]);
                 }
             }
diff --git 
a/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/envoy/persistence/EnvoyAccessLogBuilder.java
 
b/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/envoy/persistence/EnvoyAccessLogBuilder.java
index 69b0df6de7..60ba08618c 100644
--- 
a/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/envoy/persistence/EnvoyAccessLogBuilder.java
+++ 
b/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/envoy/persistence/EnvoyAccessLogBuilder.java
@@ -22,10 +22,10 @@ import com.google.protobuf.Message;
 import java.util.Optional;
 import lombok.SneakyThrows;
 import org.apache.skywalking.apm.network.logging.v3.LogData;
-import org.apache.skywalking.oap.server.core.config.NamingControl;
 import org.apache.skywalking.oap.server.core.query.type.ContentType;
 import org.apache.skywalking.oap.server.core.source.Log;
 import org.apache.skywalking.oap.server.core.source.LogBuilder;
+import org.apache.skywalking.oap.server.library.module.ModuleManager;
 import org.apache.skywalking.oap.server.library.util.ProtoBufJsonUtils;
 
 /**
@@ -51,9 +51,9 @@ public class EnvoyAccessLogBuilder extends LogBuilder {
 
     @Override
     public void init(final LogData logData, final Optional<Object> extraLog,
-                     final NamingControl namingControl) {
+                     final ModuleManager moduleManager) {
         extraLog.ifPresent(entry -> this.accessLogEntry = entry);
-        super.init(logData, extraLog, namingControl);
+        super.init(logData, extraLog, moduleManager);
     }
 
     @Override
diff --git 
a/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/test/java/org/apache/skywalking/oap/server/receiver/envoy/persistence/EnvoyAccessLogBuilderTest.java
 
b/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/test/java/org/apache/skywalking/oap/server/receiver/envoy/persistence/EnvoyAccessLogBuilderTest.java
index 9e257fd376..7bc3b0f89d 100644
--- 
a/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/test/java/org/apache/skywalking/oap/server/receiver/envoy/persistence/EnvoyAccessLogBuilderTest.java
+++ 
b/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/test/java/org/apache/skywalking/oap/server/receiver/envoy/persistence/EnvoyAccessLogBuilderTest.java
@@ -53,11 +53,26 @@ import static org.mockito.Mockito.when;
 
 class EnvoyAccessLogBuilderTest {
 
-    private NamingControl namingControl;
+    private ModuleManager moduleManager;
 
     @BeforeEach
     void setUp() {
-        namingControl = new NamingControl(512, 512, 512, new 
EndpointNameGrouping());
+        resetLogBuilderState();
+        moduleManager = buildModuleManager();
+    }
+
+    private static ModuleManager buildModuleManager() {
+        final ModuleManager manager = mock(ModuleManager.class);
+        final ModuleProviderHolder coreHolder = 
mock(ModuleProviderHolder.class);
+        final ModuleServiceHolder coreServices = 
mock(ModuleServiceHolder.class);
+        when(coreHolder.provider()).thenReturn(coreServices);
+        when(manager.find(CoreModule.NAME)).thenReturn(coreHolder);
+        when(coreServices.getService(NamingControl.class))
+            .thenReturn(new NamingControl(512, 512, 512, new 
EndpointNameGrouping()));
+        final ConfigService configService = mock(ConfigService.class);
+        when(configService.getSearchableLogsTags()).thenReturn("");
+        
when(coreServices.getService(ConfigService.class)).thenReturn(configService);
+        return manager;
     }
 
     @Test
@@ -76,7 +91,7 @@ class EnvoyAccessLogBuilderTest {
             .setService("test-svc")
             .setTimestamp(1609459200000L)
             .build();
-        builder.init(logData, Optional.of(entry), namingControl);
+        builder.init(logData, Optional.of(entry), moduleManager);
 
         final Log log = builder.toLog();
 
@@ -99,7 +114,7 @@ class EnvoyAccessLogBuilderTest {
             .setTimestamp(1609459200000L)
             .build();
         // Pass a default (empty) entry — no response code, so toLog() 
serializes empty JSON
-        builder.init(logData, 
Optional.of(HTTPAccessLogEntry.getDefaultInstance()), namingControl);
+        builder.init(logData, 
Optional.of(HTTPAccessLogEntry.getDefaultInstance()), moduleManager);
 
         final Log log = builder.toLog();
 
@@ -175,8 +190,13 @@ class EnvoyAccessLogBuilderTest {
         // Tags are stored in the output builder (via addTag), not in LogData.
         // To verify, call init + toLog and check the Log's searchable tags.
         final EnvoyAccessLogBuilder output = (EnvoyAccessLogBuilder) 
ctx.output();
-        output.setSearchableTagKeys(java.util.Arrays.asList("status.code", 
"svc"));
-        output.init(logData.build(), Optional.of(entry), namingControl);
+        // Build a moduleManager with searchable tag keys for this test
+        final ModuleManager testMm = buildModuleManager();
+        final ConfigService cs = 
testMm.find(CoreModule.NAME).provider().getService(ConfigService.class);
+        when(cs.getSearchableLogsTags()).thenReturn("status.code,svc");
+        // Reset static initialized flag so the new config takes effect
+        resetLogBuilderState();
+        output.init(logData.build(), Optional.of(entry), testMm);
         final Log log = output.toLog();
 
         assertTrue(log.getTags().stream().anyMatch(
@@ -225,6 +245,17 @@ class EnvoyAccessLogBuilderTest {
         return filterSpec;
     }
 
+    private static void resetLogBuilderState() {
+        try {
+            final java.lang.reflect.Field f = 
org.apache.skywalking.oap.server.core.source.LogBuilder.class
+                .getDeclaredField("INITIALIZED");
+            f.setAccessible(true);
+            f.set(null, false);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
     private static void assertTrue(final boolean condition, final String 
message) {
         org.junit.jupiter.api.Assertions.assertTrue(condition, message);
     }
diff --git 
a/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/test/java/org/apache/skywalking/oap/server/receiver/envoy/persistence/EnvoyAlsLalTest.java
 
b/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/test/java/org/apache/skywalking/oap/server/receiver/envoy/persistence/EnvoyAlsLalTest.java
index 974f4ff42b..9a9cb6a96e 100644
--- 
a/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/test/java/org/apache/skywalking/oap/server/receiver/envoy/persistence/EnvoyAlsLalTest.java
+++ 
b/oap-server/server-receiver-plugin/envoy-metrics-receiver-plugin/src/test/java/org/apache/skywalking/oap/server/receiver/envoy/persistence/EnvoyAlsLalTest.java
@@ -70,10 +70,11 @@ import static org.mockito.Mockito.when;
 class EnvoyAlsLalTest {
 
     private LALClassGenerator generator;
-    private NamingControl namingControl;
+    private ModuleManager moduleManager;
 
     @BeforeEach
     void setUp(final TestInfo testInfo) {
+        resetLogBuilderState();
         generator = new LALClassGenerator(new ClassPool(true));
         generator.setInputType(HTTPAccessLogEntry.class);
         generator.setOutputType(EnvoyAccessLogBuilder.class);
@@ -81,8 +82,32 @@ class EnvoyAlsLalTest {
         final String methodName = testInfo.getTestMethod()
             .map(m -> m.getName()).orElse("unknown");
         generator.setClassNameHint("EnvoyAlsLalTest_" + methodName);
-        namingControl = new NamingControl(
-            512, 512, 512, new EndpointNameGrouping());
+        moduleManager = buildCoreModuleManager("");
+    }
+
+    private static ModuleManager buildCoreModuleManager(final String 
searchableTags) {
+        final ModuleManager manager = mock(ModuleManager.class);
+        final ModuleProviderHolder coreHolder = 
mock(ModuleProviderHolder.class);
+        final ModuleServiceHolder coreServices = 
mock(ModuleServiceHolder.class);
+        when(coreHolder.provider()).thenReturn(coreServices);
+        when(manager.find(CoreModule.NAME)).thenReturn(coreHolder);
+        when(coreServices.getService(NamingControl.class))
+            .thenReturn(new NamingControl(512, 512, 512, new 
EndpointNameGrouping()));
+        final ConfigService configService = mock(ConfigService.class);
+        when(configService.getSearchableLogsTags()).thenReturn(searchableTags);
+        
when(coreServices.getService(ConfigService.class)).thenReturn(configService);
+        return manager;
+    }
+
+    private static void resetLogBuilderState() {
+        try {
+            final Field f = 
org.apache.skywalking.oap.server.core.source.LogBuilder.class
+                .getDeclaredField("INITIALIZED");
+            f.setAccessible(true);
+            f.set(null, false);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
     }
 
     // ==================== def + toJson: JWT from filter_metadata ===========
@@ -303,8 +328,11 @@ class EnvoyAlsLalTest {
         assertNotNull(ctx.output());
         final EnvoyAccessLogBuilder output =
             (EnvoyAccessLogBuilder) ctx.output();
-        
output.setSearchableTagKeys(java.util.Arrays.asList(searchableTagKeys));
-        output.init(ctx.log().build(), Optional.of(entry), namingControl);
+        // Reset and rebuild with the desired searchable tag keys
+        resetLogBuilderState();
+        final ModuleManager tagMm = buildCoreModuleManager(
+            String.join(",", searchableTagKeys));
+        output.init(ctx.log().build(), Optional.of(entry), tagMm);
         return output.toLog();
     }
 
@@ -347,7 +375,7 @@ class EnvoyAlsLalTest {
         when(coreServices.getService(SourceReceiver.class))
             .thenReturn(mock(SourceReceiver.class));
         when(coreServices.getService(NamingControl.class))
-            .thenReturn(namingControl);
+            .thenReturn(new NamingControl(512, 512, 512, new 
EndpointNameGrouping()));
         final ConfigService configService = mock(ConfigService.class);
         when(configService.getSearchableLogsTags()).thenReturn("");
         when(coreServices.getService(ConfigService.class))

Reply via email to