onFilter(Invocation invocation, FilterNode nextNode) {
+ LOGGER.info("It's my filter! \r\n");
+ return nextNode.onFilter(invocation);
+ }
+ }
```
- > ***NOTICE:*** can use a different name other than `cse.handler.xml`, e.g. `userDefined.hanlder.xml`
-
-3. Configure customized `MyHandler` in `microservice.yaml` file along with other handler together
+2. Configure customized `MyFilter` in `microservice.yaml` file along with other handler together.
```yaml
servicecomb:
- # other configurations omitted
- handler:
- chain:
- Consumer:
- default: bizkeeper-consumer,loadbalance, myhandler
+ # filters are enabled by default, configuration is optional
+ filter:
+ # Filter name
+ my-filter:
+ # Application name + Service name
+ chstest.chsClient.order: 10
+ chstest.chsClient.enabled: true
```
+ > Filters are enabled by default, configuration is optional.
+
## Precondition
see [Precondition](../../README.md)
@@ -56,7 +65,7 @@ see [Precondition](../../README.md)
servicecomb:
service:
registry:
- address: http://127.0.0.1:30100 #service center address
+ address: http://127.0.0.1:30100 #service center address
```
### Start the custom-handler-provider service
@@ -77,7 +86,7 @@ servicecomb:
### Start the custom-handler-consumer service
-Just like how to start custom-handler-provider service. But the main class of custom-handler-consumer service is `CustomHandlerCustomerMain`.
+Just like how to start custom-handler-provider service. But the main class of custom-handler-consumer service is `CustomHandlerCustomerMain`.
```bash
cd custom-handler-sample/custom-handler-consumer
diff --git a/java-chassis-samples/custom-handler-sample/custom-handler-consumer/pom.xml b/java-chassis-samples/custom-handler-sample/custom-handler-consumer/pom.xml
index 7cd62a11..590fefd8 100644
--- a/java-chassis-samples/custom-handler-sample/custom-handler-consumer/pom.xml
+++ b/java-chassis-samples/custom-handler-sample/custom-handler-consumer/pom.xml
@@ -26,21 +26,11 @@
custom-handler-consumer
Java Chassis::Samples::Custom Handler::Consumer
-
org.apache.servicecomb
- provider-pojo
+ solution-basic
-
-
- org.apache.servicecomb
- transport-rest-vertx
-
-
- org.apache.servicecomb
- handler-loadbalance
-
-
+
org.apache.logging.log4j
log4j-slf4j-impl
diff --git a/java-chassis-samples/custom-handler-sample/custom-handler-consumer/src/main/resources/microservice.yaml b/java-chassis-samples/custom-handler-sample/custom-handler-consumer/src/main/resources/microservice.yaml
index d080c789..62d2ae59 100644
--- a/java-chassis-samples/custom-handler-sample/custom-handler-consumer/src/main/resources/microservice.yaml
+++ b/java-chassis-samples/custom-handler-sample/custom-handler-consumer/src/main/resources/microservice.yaml
@@ -24,11 +24,11 @@ servicecomb:
registry:
sc:
address: http://127.0.0.1:30100
-# filter默认都是开启的,可以不用配置
+# # filters are enabled by default, configuration is optional
# filter:
-# # Filter名称
+# # Filter name
# my-filter:
-# # 应用名 + 服务名
+# # Application name + Service name
# chstest.chsClient.order: 10
# chstest.chsClient.enabled: true
references:
diff --git a/java-chassis-samples/custom-handler-sample/custom-handler-provider/pom.xml b/java-chassis-samples/custom-handler-sample/custom-handler-provider/pom.xml
index 257198fa..302d2239 100644
--- a/java-chassis-samples/custom-handler-sample/custom-handler-provider/pom.xml
+++ b/java-chassis-samples/custom-handler-sample/custom-handler-provider/pom.xml
@@ -26,26 +26,11 @@
custom-handler-provider
Java Chassis::Samples::Custom Handler::Provider
-
org.apache.servicecomb
- provider-pojo
+ solution-basic
-
-
- org.apache.servicecomb
- transport-rest-vertx
-
-
-
- org.apache.servicecomb
- handler-loadbalance
-
-
- org.apache.servicecomb
- handler-flowcontrol-qps
-
-
+
org.apache.logging.log4j
log4j-slf4j-impl
diff --git a/java-chassis-samples/custom-handler-sample/pom.xml b/java-chassis-samples/custom-handler-sample/pom.xml
index 7a38f0fb..996dc409 100644
--- a/java-chassis-samples/custom-handler-sample/pom.xml
+++ b/java-chassis-samples/custom-handler-sample/pom.xml
@@ -28,10 +28,6 @@
pom
-
- org.apache.servicecomb
- solution-basic
-
org.apache.servicecomb
registry-service-center
From 56919abc29b1d3bc1961f543a035f69f6798cf70 Mon Sep 17 00:00:00 2001
From: Aithusa <32020141+Aithosa@users.noreply.github.com>
Date: Wed, 21 Jan 2026 02:07:39 +0800
Subject: [PATCH 21/30] Update java version to 17 in pom files.
---
basic-tomcat/pom.xml | 5 +++--
bmi/pom.xml | 4 ++--
java-chassis-interoprability/pom.xml | 5 +++--
java-chassis-samples/pom.xml | 4 ++--
java-chassis-samples/use-log4j2-sample/pom.xml | 1 -
porter/pom.xml | 5 +++--
6 files changed, 13 insertions(+), 11 deletions(-)
diff --git a/basic-tomcat/pom.xml b/basic-tomcat/pom.xml
index ca64289f..94904531 100644
--- a/basic-tomcat/pom.xml
+++ b/basic-tomcat/pom.xml
@@ -26,6 +26,7 @@
pom
+ 17
UTF-8
3.2.4
3.1.3
@@ -116,8 +117,8 @@
${maven-compiler-plugin.version}
-parameters
- 17
- 17
+ ${java.version}
+ ${java.version}
diff --git a/bmi/pom.xml b/bmi/pom.xml
index 3d761cbe..4ba2025a 100644
--- a/bmi/pom.xml
+++ b/bmi/pom.xml
@@ -89,8 +89,8 @@
${maven-compiler-plugin.version}
-parameters
- 17
- 17
+ ${java.version}
+ ${java.version}
diff --git a/java-chassis-interoprability/pom.xml b/java-chassis-interoprability/pom.xml
index a541f134..59b2e4b0 100644
--- a/java-chassis-interoprability/pom.xml
+++ b/java-chassis-interoprability/pom.xml
@@ -26,6 +26,7 @@
pom
+ 17
UTF-8
3.11.0
3.1.3
@@ -46,8 +47,8 @@
${maven-compiler-plugin.version}
-parameters
- 17
- 17
+ ${java.version}
+ ${java.version}
diff --git a/java-chassis-samples/pom.xml b/java-chassis-samples/pom.xml
index 7ece0c4f..9e477096 100644
--- a/java-chassis-samples/pom.xml
+++ b/java-chassis-samples/pom.xml
@@ -79,8 +79,8 @@
maven-compiler-plugin
${maven-compiler-plugin.version}
- 17
- 17
+ ${java.version}
+ ${java.version}
diff --git a/java-chassis-samples/use-log4j2-sample/pom.xml b/java-chassis-samples/use-log4j2-sample/pom.xml
index 3c7bd69f..2ddf678a 100644
--- a/java-chassis-samples/use-log4j2-sample/pom.xml
+++ b/java-chassis-samples/use-log4j2-sample/pom.xml
@@ -31,7 +31,6 @@
UTF-8
UTF-8
- 17
diff --git a/porter/pom.xml b/porter/pom.xml
index 561d79af..3eb6bc3f 100644
--- a/porter/pom.xml
+++ b/porter/pom.xml
@@ -26,6 +26,7 @@
pom
+ 17
UTF-8
3.11.0
3.1.3
@@ -113,8 +114,8 @@
${maven-compiler-plugin.version}
-parameters
- 17
- 17
+ ${java.version}
+ ${java.version}
From b4dc3fc455e91e7dbef996bdfbb605cb02579f68 Mon Sep 17 00:00:00 2001
From: Aithusa <32020141+Aithosa@users.noreply.github.com>
Date: Wed, 21 Jan 2026 20:37:14 +0800
Subject: [PATCH 22/30] Remove redundant pom properties and adapt code for Java
17 compatibility
---
java-chassis-samples/apm-agent/pom.xml | 7 +---
.../servicecomb/samples/apm/AgentMain.java | 20 +++++++++
.../samples/apm/ApmBeanRegistrar.java | 41 +++++++++++++++++++
.../samples/apm/SCBClassFileTransformer.java | 7 ++++
4 files changed, 70 insertions(+), 5 deletions(-)
create mode 100644 java-chassis-samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/ApmBeanRegistrar.java
diff --git a/java-chassis-samples/apm-agent/pom.xml b/java-chassis-samples/apm-agent/pom.xml
index df9c3e10..b8573814 100644
--- a/java-chassis-samples/apm-agent/pom.xml
+++ b/java-chassis-samples/apm-agent/pom.xml
@@ -31,9 +31,6 @@
Java Chassis::Samples::apm-agent
- UTF-8
- 17
- -Dfile.encoding=UTF-8
3.1.0
org.apache.servicecomb.samples.apm.AgentMain
@@ -70,8 +67,8 @@
org.apache.maven.plugins
maven-compiler-plugin
- 17
- 17
+ ${java.version}
+ ${java.version}
-Werror
-Xlint:all
diff --git a/java-chassis-samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/AgentMain.java b/java-chassis-samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/AgentMain.java
index 213c7900..a411e92a 100644
--- a/java-chassis-samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/AgentMain.java
+++ b/java-chassis-samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/AgentMain.java
@@ -20,6 +20,26 @@
public class AgentMain {
public static void premain(String args, Instrumentation inst) {
+ // Register Spring ApplicationContextInitializer to make ApmBootListener a Spring Bean
+ // This must be set BEFORE Spring initializes
+ String existingInitializers = System.getProperty("context.initializer.classes", "");
+ String apmInitializer = "org.apache.servicecomb.samples.apm.ApmBeanRegistrar";
+
+ if (existingInitializers.isEmpty()) {
+ System.setProperty("context.initializer.classes", apmInitializer);
+ } else {
+ System.setProperty("context.initializer.classes", existingInitializers + "," + apmInitializer);
+ }
+
+ // Inject jar to System ClassLoader immediately for JDK 9+ compatibility
+ try {
+ java.util.jar.JarFile jarFile = new java.util.jar.JarFile(
+ new java.io.File(AgentMain.class.getProtectionDomain().getCodeSource().getLocation().toURI()));
+ inst.appendToSystemClassLoaderSearch(jarFile);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
// to support web container, we can not just only inject spiJar to system classloader
// in this sample, javaAgent jar equals ServiceComb plugin jar
inst.addTransformer(
diff --git a/java-chassis-samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/ApmBeanRegistrar.java b/java-chassis-samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/ApmBeanRegistrar.java
new file mode 100644
index 00000000..a352dec3
--- /dev/null
+++ b/java-chassis-samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/ApmBeanRegistrar.java
@@ -0,0 +1,41 @@
+/*
+ * 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.servicecomb.samples.apm;
+
+import org.apache.servicecomb.samples.apm.impl.ApmBootListener;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.support.BeanDefinitionRegistry;
+import org.springframework.context.ApplicationContextInitializer;
+import org.springframework.context.ConfigurableApplicationContext;
+
+/**
+ * Spring ApplicationContextInitializer to dynamically register ApmBootListener as a Spring Bean.
+ * This is necessary because ServiceComb uses @Autowired to inject BootListeners,
+ * not Java's ServiceLoader mechanism.
+ */
+public class ApmBeanRegistrar implements ApplicationContextInitializer {
+ @Override
+ public void initialize(ConfigurableApplicationContext applicationContext) {
+ BeanDefinitionRegistry registry = (BeanDefinitionRegistry) applicationContext.getBeanFactory();
+
+ BeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(ApmBootListener.class)
+ .getBeanDefinition();
+
+ registry.registerBeanDefinition("apmBootListener", beanDefinition);
+ }
+}
diff --git a/java-chassis-samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/SCBClassFileTransformer.java b/java-chassis-samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/SCBClassFileTransformer.java
index ae6d8cfb..7ccec757 100644
--- a/java-chassis-samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/SCBClassFileTransformer.java
+++ b/java-chassis-samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/SCBClassFileTransformer.java
@@ -49,7 +49,14 @@ private synchronized void injectSPI(ClassLoader loader) {
return;
}
+ // System ClassLoader injection is handled in premain for JDK 9+
+ if (ClassLoader.getSystemClassLoader() == loader) {
+ return;
+ }
+
try {
+ // Fallback for other classloaders (e.g. web containers) - keep legacy
+ // reflection just in case
Method addURLMethod = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
addURLMethod.setAccessible(true);
addURLMethod.invoke(loader, scbSpiJar);
From 6042f8b781baea500fbda83ec1c6960d7ca9cc9b Mon Sep 17 00:00:00 2001
From: Aithusa <32020141+Aithosa@users.noreply.github.com>
Date: Wed, 21 Jan 2026 22:54:56 +0800
Subject: [PATCH 23/30] Add APM Agent sample README
Introduces the APM Agent sample for ServiceComb, detailing its features, integration steps, output format, extension points, and references. Provides comprehensive instructions for building, running, and customizing the agent for performance monitoring in microservice applications.
---
java-chassis-samples/apm-agent/README.md | 269 +++++++++++++++++++++++
1 file changed, 269 insertions(+)
create mode 100644 java-chassis-samples/apm-agent/README.md
diff --git a/java-chassis-samples/apm-agent/README.md b/java-chassis-samples/apm-agent/README.md
new file mode 100644
index 00000000..08420efe
--- /dev/null
+++ b/java-chassis-samples/apm-agent/README.md
@@ -0,0 +1,269 @@
+# APM-Agent
+
+## Description
+
+This project is an APM (Application Performance Monitoring) sample based on Java Agent technology, demonstrating how to provide non-intrusive performance monitoring capabilities for ServiceComb microservice applications through the Java Instrumentation API.
+
+## APM Introduction
+
+APM (Application Performance Monitoring) is a practice method for monitoring and managing software application performance and availability. APM systems typically provide the following core features:
+
+- **Performance Metrics Collection**: Monitor key metrics such as response time, throughput, and error rate
+- **Distributed Tracing**: Track request call chains across multiple services in microservice architecture
+- **Business Metrics Monitoring**: Collect and analyze business-related performance data
+- **Anomaly Detection and Alerting**: Detect performance issues promptly and notify relevant personnel
+
+Common APM tools include: Zipkin, SkyWalking, Pinpoint, Jaeger, etc.
+
+## ServiceComb APM Support
+
+Apache ServiceComb provides flexible extension mechanisms to support APM integration:
+
+### 1. BootListener Mechanism
+
+ServiceComb provides extension points for application lifecycle through the `BootListener` interface, allowing custom logic to be injected at different stages of service startup:
+
+```java
+public interface BootListener {
+ void onBootEvent(BootEvent event);
+}
+```
+
+Supported event types include:
+
+- `BEFORE_FILTER`: Before filter initialization
+- `AFTER_TRANSPORT`: After transport layer initialization
+- `BEFORE_REGISTRY`: Before service registration
+- `AFTER_REGISTRY`: After service registration
+
+### 2. EventBus Event Mechanism
+
+ServiceComb uses Guava EventBus to publish various events during microservice invocation. APM components can collect performance data by subscribing to these events:
+
+- `InvocationStartEvent`: Invocation start event
+- `InvocationBusinessMethodStartEvent`: Business method execution start event
+- `InvocationBusinessMethodFinishEvent`: Business method execution finish event
+- `InvocationFinishEvent`: Invocation finish event (contains complete performance data)
+
+### 3. Invocation Context
+
+Each invocation has an independent context (`Invocation`) that supports storing local data, facilitating the transfer of APM-related information (such as TraceId, SpanId, etc.) across different stages of the invocation.
+
+## Implementation Overview
+
+### Core Components
+
+1. **AgentMain**: Java Agent entry class
+ - Injected before application startup through the `premain` method
+ - Registers Spring `ApplicationContextInitializer` to ensure APM listener is registered as a Spring Bean
+ - Uses bytecode enhancement technology to support Web container environments
+
+2. **ApmBeanRegistrar**: Spring Bean registrar
+ - Implements the `ApplicationContextInitializer` interface
+ - Dynamically registers `ApmBootListener` as a Bean during Spring container initialization
+ - Ensures ServiceComb can discover the APM listener through dependency injection
+
+3. **ApmBootListener**: APM core listener
+ - Implements ServiceComb's `BootListener` interface
+ - Subscribes to invocation-related events and collects performance metrics
+ - Generates and outputs performance monitoring reports
+
+4. **Output Generators**:
+ - `HeaderOutputGenerator`: Generates request header information
+ - `ConsumerOutputGenerator`: Generates consumer-side performance data
+ - `ProducerOutputGenerator`: Generates provider-side performance data
+ - `EdgeOutputGenerator`: Generates edge service performance data
+
+### Technical Features
+
+- **Non-intrusive**: Uses Java Agent technology, applications can integrate APM functionality without modifying any code
+- **Transparent Integration**: Automatic registration through Spring extension mechanism, completely transparent to the application
+- **Complete Call Chain**: Records timing data for each stage from request start to finish
+- **Multi-role Support**: Simultaneously supports monitoring for Consumer, Producer, Edge, and other roles
+
+## Usage
+
+### 1. Add Dependencies
+
+No dependencies need to be added to the microservice project using the APM Agent. The APM Agent is loaded as an independent JAR file through JVM parameters.
+
+### 2. Build APM Agent
+
+Execute in the `apm-agent` directory:
+
+```bash
+mvn clean install
+```
+
+After building, `apm-agent-3.0-SNAPSHOT.jar` will be generated in the `target` directory.
+
+### 3. Load Agent on Application Startup
+
+When starting a ServiceComb application, add the `-javaagent` JVM parameter:
+
+```bash
+java -javaagent:/path/to/apm-agent-3.0-SNAPSHOT.jar -jar your-application.jar
+```
+
+Or use with Maven:
+
+```bash
+mvn exec:java -Dexec.mainClass="your.main.Class" \
+ -Dexec.args="-javaagent:/path/to/apm-agent-3.0-SNAPSHOT.jar"
+```
+
+In JetBrains IDEA, you can add VM options in the run configuration:
+
+```bash
+-javaagent:/path/to/apm-agent-3.0-SNAPSHOT.jar
+```
+
+### 4. View Monitoring Output
+
+The APM Agent will output performance data for each request to the console in the following format:
+
+```text
+PROVIDER rest springmvchello.sayHi:
+ http method: GET
+ url : /springmvchello/sayhi
+ status code: 200
+ traceId : 696fe51656552b35
+ total : 9.375ms
+ prepare : 2.156ms
+ queue : 0.542ms
+ provider-decode : 0.321ms
+ provider-encode : 1.876ms
+ execute : 3.245ms
+```
+
+## Precondition
+
+See [Precondition](../../README.md)
+
+## Sample Quick Start
+
+This sample uses ServiceComb's basic example project to demonstrate APM Agent functionality.
+
+### Start the Service Center
+
+- [How to start Service Center](http://servicecomb.apache.org/docs/products/service-center/install/)
+- Make sure Service Center address is configured correctly in `microservice.yaml`
+
+```yaml
+servicecomb:
+ service:
+ registry:
+ address: http://127.0.0.1:30100 #service center address
+```
+
+### Run Sample with APM Agent
+
+Using other sample projects (such as `basic-application-sample`) as an example:
+
+1. **Build the project**
+
+ ```bash
+ # Execute in the project root directory
+ mvn clean install
+ ```
+
+2. **Start Provider service (with APM Agent)**
+
+ ```bash
+ cd java-chassis-samples/basic-application-sample/basic-provider/target
+ java -javaagent:../../../apm-agent/target/apm-agent-3.0-SNAPSHOT.jar -jar basic-provider-3.0-SNAPSHOT.jar
+ ```
+
+3. **Start Consumer service (normal startup, without APM Agent)**
+
+ ```bash
+ cd java-chassis-samples/basic-application-sample/basic-consumer/target
+ java -jar basic-consumer-3.0-SNAPSHOT.jar
+ ```
+
+### How to Verify
+
+After both Provider and Consumer services start successfully, you can see the following in the Provider's console:
+
+**Performance monitoring data**: Each service invocation will output detailed performance data, including:
+
+- HTTP method and URL
+- Response status code
+- TraceId (for distributed tracing)
+- Total time and time breakdown by stage
+
+## Output Data Description
+
+### Consumer Side Output
+
+```text
+CONSUMER rest provider.hello.sayHi:
+ http method: GET
+ url : /hello/sayhi
+ status code: 200
+ traceId : 696fe51656552b35
+ total : 17.857ms
+ prepare : 5.231ms
+ consumer-send : 8.456ms
+ consumer-decode : 2.124ms
+ consumer-after-decode : 1.046ms
+```
+
+### Provider Side Output
+
+```text
+PROVIDER rest provider.hello.sayHi:
+ http method: GET
+ url : /hello/sayhi
+ status code: 200
+ traceId : 696fe51656552b35
+ total : 9.375ms
+ prepare : 2.156ms
+ queue : 0.542ms
+ provider-decode : 0.321ms
+ provider-encode : 1.876ms
+ execute : 3.245ms
+```
+
+## Extension Development
+
+### Custom Output Format
+
+You can customize the output format by modifying or extending implementations of `AbstractOutputGenerator`:
+
+```java
+public class CustomOutputGenerator extends AbstractOutputGenerator {
+ @Override
+ public void generate(StringBuilder sb, InvocationFinishEvent event) {
+ // Custom output logic
+ }
+}
+```
+
+### Integration with External APM Systems
+
+You can add code in the `ApmBootListener.onInvocationFinish` method to send performance data to external APM systems (such as Zipkin, SkyWalking, etc.):
+
+```java
+@Subscribe
+public void onInvocationFinish(InvocationFinishEvent event) {
+ // Create Span data
+ Span span = createSpan(event);
+
+ // Send to external APM system
+ apmClient.sendSpan(span);
+}
+```
+
+## Notes
+
+1. **Performance Impact**: The APM Agent will have some impact on application performance. It is recommended to control the sampling rate in production environments
+2. **Log Output**: The current implementation outputs directly to the console. For production environments, it is recommended to use asynchronous output to files or message queues
+3. **Version Compatibility**: This sample is developed based on ServiceComb 3.0. Other versions may require adjustments
+4. **JDK Version**: Supports JDK 8 and above
+
+## References
+
+- [ServiceComb Java Chassis Official Documentation](http://servicecomb.apache.org/docs/)
+- [Java Agent Technical Documentation](https://docs.oracle.com/javase/8/docs/api/java/lang/instrument/package-summary.html)
+- [Project Implementation Details](docs/walkthrough.md)
From c513998f1b1ca7992f9f0c8dd6e4d72557422210 Mon Sep 17 00:00:00 2001
From: Aithusa <32020141+Aithosa@users.noreply.github.com>
Date: Thu, 22 Jan 2026 21:20:26 +0800
Subject: [PATCH 24/30] Update README with additional event types and
descriptions
Expanded the list of supported BootListener and EventBus event types in the APM agent README. Added new event types and clarified base event classes to provide more comprehensive documentation for developers integrating with the event system.
---
java-chassis-samples/apm-agent/README.md | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/java-chassis-samples/apm-agent/README.md b/java-chassis-samples/apm-agent/README.md
index 08420efe..8be6b5f3 100644
--- a/java-chassis-samples/apm-agent/README.md
+++ b/java-chassis-samples/apm-agent/README.md
@@ -32,18 +32,36 @@ public interface BootListener {
Supported event types include:
- `BEFORE_FILTER`: Before filter initialization
+- `AFTER_FILTER`: After filter initialization
+- `BEFORE_PRODUCER_PROVIDER`: Before Producer Provider initialization
+- `AFTER_PRODUCER_PROVIDER`: After Producer Provider initialization
+- `BEFORE_CONSUMER_PROVIDER`: Before Consumer Provider initialization
+- `AFTER_CONSUMER_PROVIDER`: After Consumer Provider initialization
+- `BEFORE_TRANSPORT`: Before transport layer initialization
- `AFTER_TRANSPORT`: After transport layer initialization
- `BEFORE_REGISTRY`: Before service registration
- `AFTER_REGISTRY`: After service registration
+- `BEFORE_CLOSE`: Before service shutdown
+- `AFTER_CLOSE`: After service shutdown
### 2. EventBus Event Mechanism
ServiceComb uses Guava EventBus to publish various events during microservice invocation. APM components can collect performance data by subscribing to these events:
- `InvocationStartEvent`: Invocation start event
+- `InvocationStartSendRequestEvent`: Start sending request event
- `InvocationBusinessMethodStartEvent`: Business method execution start event
- `InvocationBusinessMethodFinishEvent`: Business method execution finish event
+- `InvocationBusinessFinishEvent`: Business logic execution complete event
+- `InvocationEncodeResponseStartEvent`: Start encoding response event
- `InvocationFinishEvent`: Invocation finish event (contains complete performance data)
+- `InvocationTimeoutCheckEvent`: Invocation timeout check event
+- `ServerAccessLogEvent`: Server access log event
+
+**Base Event Types:**
+
+- `InvocationBaseEvent`: Base class for all invocation events
+- `InvocationWithResponseEvent`: Base class for invocation events that contain response information
### 3. Invocation Context
From f3ee3cbe6e709c45643f58f5731110e8d9b37481 Mon Sep 17 00:00:00 2001
From: Aithusa <32020141+Aithosa@users.noreply.github.com>
Date: Thu, 22 Jan 2026 21:37:52 +0800
Subject: [PATCH 25/30] Refactor APM output generators and remove BootListener
SPI
Updated timeline comments and ordering in ConsumerOutputGenerator and ProducerOutputGenerator for clarity and correctness. Removed redundant timeline output in HeaderOutputGenerator and super.generate call in EdgeOutputGenerator. Deleted the META-INF/services/org.apache.servicecomb.core.BootListener SPI registration file, indicating ApmBootListener is no longer registered as a BootListener.
---
.../impl/output/ConsumerOutputGenerator.java | 12 ++++++------
.../apm/impl/output/EdgeOutputGenerator.java | 2 --
.../apm/impl/output/HeaderOutputGenerator.java | 5 -----
.../impl/output/ProducerOutputGenerator.java | 12 ++++++------
.../org.apache.servicecomb.core.BootListener | 18 ------------------
5 files changed, 12 insertions(+), 37 deletions(-)
delete mode 100644 java-chassis-samples/apm-agent/src/main/resources/META-INF/services/org.apache.servicecomb.core.BootListener
diff --git a/java-chassis-samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/impl/output/ConsumerOutputGenerator.java b/java-chassis-samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/impl/output/ConsumerOutputGenerator.java
index 23d7583a..1022b22e 100644
--- a/java-chassis-samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/impl/output/ConsumerOutputGenerator.java
+++ b/java-chassis-samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/impl/output/ConsumerOutputGenerator.java
@@ -26,18 +26,18 @@ public void generate(StringBuilder sb, InvocationFinishEvent event) {
// 1. total: start create invocation -> all filters finished
appendTimeLine(sb, PAD4_TIME_FMT, InvocationStageTrace.STAGE_TOTAL, stageTrace.calcTotal());
- // 2. prepare: start create invocation -> finish create invocatio
+ // 2. prepare: start create invocation -> finish create invocation
appendTimeLine(sb, PAD4_TIME_FMT, InvocationStageTrace.STAGE_PREPARE, stageTrace.calcPrepare());
- // 4. connection: start get connection -> finish get connection
+ // 3. connection: start get connection -> finish get connection
appendTimeLine(sb, PAD4_TIME_FMT, InvocationStageTrace.STAGE_CONSUMER_CONNECTION, stageTrace.calcConnection());
- // 5. consumer-encode: start encode request -> finish encode request
+ // 4. consumer-encode: start encode request -> finish encode request
appendTimeLine(sb, PAD4_TIME_FMT, InvocationStageTrace.STAGE_CONSUMER_ENCODE_REQUEST,
stageTrace.calcConsumerEncodeRequest());
- // 6. consumer-decode: start decode response -> finish decode response
+ // 5. consumer-send: start send request -> finish send request
appendTimeLine(sb, PAD4_TIME_FMT, InvocationStageTrace.STAGE_CONSUMER_SEND, stageTrace.calcConsumerSendRequest());
- // 7. consumer-send: start send request -> finish send request
+ // 6. wait: finish send request -> start decode response
appendTimeLine(sb, PAD4_TIME_FMT, InvocationStageTrace.STAGE_CONSUMER_WAIT, stageTrace.calcWait());
- // 8. wait: finish send request -> start decode response
+ // 7. consumer-decode: start decode response -> finish decode response
appendTimeLine(sb, PAD4_TIME_FMT, InvocationStageTrace.STAGE_CONSUMER_DECODE_RESPONSE,
stageTrace.calcConsumerDecodeResponse());
}
diff --git a/java-chassis-samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/impl/output/EdgeOutputGenerator.java b/java-chassis-samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/impl/output/EdgeOutputGenerator.java
index b4eacbe9..541ad793 100644
--- a/java-chassis-samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/impl/output/EdgeOutputGenerator.java
+++ b/java-chassis-samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/impl/output/EdgeOutputGenerator.java
@@ -48,7 +48,5 @@ public void generate(StringBuilder sb, InvocationFinishEvent event) {
appendTimeLine(sb, PAD4_TIME_FMT, InvocationStageTrace.STAGE_PROVIDER_SEND, stageTrace.calcProviderSendResponse());
// 11. wait: finish send request -> start decode response
appendTimeLine(sb, PAD4_TIME_FMT, InvocationStageTrace.STAGE_CONSUMER_WAIT, stageTrace.calcWait());
- // 调用父类的generate方法获取其他相关信息
- super.generate(sb, event);
}
}
diff --git a/java-chassis-samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/impl/output/HeaderOutputGenerator.java b/java-chassis-samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/impl/output/HeaderOutputGenerator.java
index d57a8a51..a6973363 100644
--- a/java-chassis-samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/impl/output/HeaderOutputGenerator.java
+++ b/java-chassis-samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/impl/output/HeaderOutputGenerator.java
@@ -20,22 +20,17 @@
import org.apache.servicecomb.common.rest.definition.RestOperationMeta;
import org.apache.servicecomb.core.Invocation;
import org.apache.servicecomb.core.event.InvocationFinishEvent;
-import org.apache.servicecomb.core.invocation.InvocationStageTrace;
public class HeaderOutputGenerator extends AbstractOutputGenerator {
@Override
public void generate(StringBuilder sb, InvocationFinishEvent event) {
Invocation invocation = event.getInvocation();
RestOperationMeta restOperationMeta = invocation.getOperationMeta().getExtData(RestConst.SWAGGER_REST_OPERATION);
- InvocationStageTrace stageTrace = event.getInvocation().getInvocationStageTrace();
sb.append(invocation.getInvocationQualifiedName()).append(":\n");
appendLine(sb, PAD2_KEY11_FMT, "http method", restOperationMeta.getHttpMethod());
appendLine(sb, PAD2_KEY11_FMT, "url", restOperationMeta.getAbsolutePath());
appendLine(sb, PAD2_KEY11_FMT, "status code", event.getResponse().getStatusCode());
appendLine(sb, PAD2_KEY11_FMT, "traceId", invocation.getTraceId());
-
- appendTimeLine(sb, PAD2_TIME_FMT, InvocationStageTrace.STAGE_TOTAL, stageTrace.calcTotal());
- appendTimeLine(sb, PAD4_TIME_FMT, InvocationStageTrace.STAGE_PREPARE, stageTrace.calcPrepare());
}
}
diff --git a/java-chassis-samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/impl/output/ProducerOutputGenerator.java b/java-chassis-samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/impl/output/ProducerOutputGenerator.java
index 6542a609..2a4ee017 100644
--- a/java-chassis-samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/impl/output/ProducerOutputGenerator.java
+++ b/java-chassis-samples/apm-agent/src/main/java/org/apache/servicecomb/samples/apm/impl/output/ProducerOutputGenerator.java
@@ -30,18 +30,18 @@ public void generate(StringBuilder sb, InvocationFinishEvent event) {
appendTimeLine(sb, PAD4_TIME_FMT, InvocationStageTrace.STAGE_TOTAL, stageTrace.calcTotal());
// 2. prepare: start create invocation -> finish create invocation
appendTimeLine(sb, PAD4_TIME_FMT, InvocationStageTrace.STAGE_PREPARE, stageTrace.calcPrepare());
- // 4. queue: add in queue -> execute in thread
+ // 3. queue: add in queue -> execute in thread
appendTimeLine(sb, PAD4_TIME_FMT, InvocationStageTrace.STAGE_PROVIDER_QUEUE, stageTrace.calcQueue());
- // 5. provider-decode: start decode request -> finish decode request
+ // 4. provider-decode: start decode request -> finish decode request
appendTimeLine(sb, PAD4_TIME_FMT, InvocationStageTrace.STAGE_PROVIDER_DECODE_REQUEST,
stageTrace.calcProviderDecodeRequest());
+ // 5. execute: start business execute -> finish business execute
+ appendTimeLine(sb, PAD4_TIME_FMT, InvocationStageTrace.STAGE_PROVIDER_BUSINESS, stageTrace.calcBusinessExecute());
// 6. provider-encode: start encode response -> finish encode response
appendTimeLine(sb, PAD4_TIME_FMT, InvocationStageTrace.STAGE_PROVIDER_ENCODE_RESPONSE,
stageTrace.calcProviderEncodeResponse());
// 7. provider-send: start send response -> finish send response
- appendTimeLine(sb, PAD4_TIME_FMT, InvocationStageTrace.STAGE_PROVIDER_ENCODE_RESPONSE,
- stageTrace.calcProviderEncodeResponse());
- // 8. execute: start business execute -> finish business execute
- appendTimeLine(sb, PAD4_TIME_FMT, InvocationStageTrace.STAGE_PROVIDER_BUSINESS, stageTrace.calcBusinessExecute());
+ appendTimeLine(sb, PAD4_TIME_FMT, InvocationStageTrace.STAGE_PROVIDER_SEND,
+ stageTrace.calcProviderSendResponse());
}
}
diff --git a/java-chassis-samples/apm-agent/src/main/resources/META-INF/services/org.apache.servicecomb.core.BootListener b/java-chassis-samples/apm-agent/src/main/resources/META-INF/services/org.apache.servicecomb.core.BootListener
deleted file mode 100644
index e0efc733..00000000
--- a/java-chassis-samples/apm-agent/src/main/resources/META-INF/services/org.apache.servicecomb.core.BootListener
+++ /dev/null
@@ -1,18 +0,0 @@
-#
-# 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.
-#
-
-org.apache.servicecomb.samples.apm.impl.ApmBootListener
\ No newline at end of file
From 337a78506e68946660c484c0e605e38f0d5bc706 Mon Sep 17 00:00:00 2001
From: Aithusa <32020141+Aithosa@users.noreply.github.com>
Date: Thu, 22 Jan 2026 21:54:23 +0800
Subject: [PATCH 26/30] Update README and pom.xml for Java 17 and SLF4J 2.x
Enhanced the README with detailed build and deployment instructions for running the sample in an external Tomcat. Updated pom.xml to use Java 17 and explicitly override SLF4J to version 2.0.16, ensuring compatibility and consistency.
---
.../spring-boot-external-tomcat/README.md | 50 ++++++++++++++++++-
.../spring-boot-external-tomcat/pom.xml | 14 ++++--
2 files changed, 60 insertions(+), 4 deletions(-)
diff --git a/java-chassis-deployment-samples/spring-boot-external-tomcat/README.md b/java-chassis-deployment-samples/spring-boot-external-tomcat/README.md
index d2230b36..18192fbd 100644
--- a/java-chassis-deployment-samples/spring-boot-external-tomcat/README.md
+++ b/java-chassis-deployment-samples/spring-boot-external-tomcat/README.md
@@ -1,3 +1,7 @@
+# spring-boot-external-tomcat
+
+## Description
+
This project shows how to run java-chassis with spring boot in external web container.
Following are some useful articles to run spring boot in external web container.
@@ -11,4 +15,48 @@ For java-chassis using spring boot, check following articles.
* [Working with Spring Boot](https://docs.servicecomb.io/java-chassis/zh_CN/using-java-chassis-in-spring-boot/using-java-chassis-in-spring-boot/)
## Precondition
-see [Precondition](../../README.md)
\ No newline at end of file
+
+see [Precondition](../../README.md)
+
+## Usage
+
+### Build
+
+```bash
+mvn clean package
+```
+
+After building, you will find the `springBootExternalTomcat-0.0.1.war` file in the `target` directory.
+
+### Deploy to External Tomcat
+
+1. Download and install Apache Tomcat 9.x or higher
+2. Copy the generated WAR file to Tomcat's `webapps` directory:
+
+ ```bash
+ cp target/springBootExternalTomcat-0.0.1.war /webapps/
+ ```
+
+3. Start Tomcat:
+
+ ```bash
+ cd /bin
+ ./startup.sh # On Linux/Mac
+ startup.bat # On Windows
+ ```
+
+4. Tomcat will automatically deploy the WAR file
+
+### Test the Service
+
+Once deployed and started, you can test the service using curl:
+
+```bash
+curl "http://localhost:8080/springBootExternalTomcat-0.0.1/hello?name=World"
+```
+
+Expected response:
+
+```text
+World
+```
diff --git a/java-chassis-deployment-samples/spring-boot-external-tomcat/pom.xml b/java-chassis-deployment-samples/spring-boot-external-tomcat/pom.xml
index f79713fc..27a8ce39 100644
--- a/java-chassis-deployment-samples/spring-boot-external-tomcat/pom.xml
+++ b/java-chassis-deployment-samples/spring-boot-external-tomcat/pom.xml
@@ -21,11 +21,13 @@
UTF-8
- 1.8
+ 17
-Dfile.encoding=UTF-8
UTF-8
3.2.4
3.11.0
+
+ 2.0.16
@@ -37,6 +39,12 @@
pom
import
+
+
+ org.slf4j
+ slf4j-api
+ ${slf4j.version}
+
@@ -71,8 +79,8 @@
${maven-compiler-plugin.version}
-parameters
- 17
- 17
+ ${java.version}
+ ${java.version}
From 112bed42c333c07ff5cdbf970ea69a5a577bd752 Mon Sep 17 00:00:00 2001
From: Aithusa <32020141+Aithosa@users.noreply.github.com>
Date: Fri, 23 Jan 2026 00:45:54 +0800
Subject: [PATCH 27/30] Add legacy WAR sample with ServiceComb integration
Introduces a new sample project demonstrating how to integrate ServiceComb microservices into a traditional Java Web application deployed on external Tomcat. Adds legacy Servlet and Filter, JSP support, and updates pom.xml for Java 17, SLF4J 2.x, and ServiceComb 3.x compatibility. Updates web.xml for legacy component configuration and provides documentation in README.md.
---
.../war-external-tomcat/README.md | 62 +++++++++++++++++++
.../war-external-tomcat/pom.xml | 49 ++++++++++++++-
.../dependencyManagement/Application.java | 42 +++++++++++++
.../dependencyManagement/LegacyFilter.java | 50 +++++++++++++++
.../dependencyManagement/LegacyServlet.java | 40 ++++++++++++
.../src/main/webapp/WEB-INF/web.xml | 54 ++++++++--------
.../src/main/webapp/index.jsp | 59 ++++++++++++++++++
7 files changed, 324 insertions(+), 32 deletions(-)
create mode 100644 java-chassis-deployment-samples/war-external-tomcat/README.md
create mode 100644 java-chassis-deployment-samples/war-external-tomcat/src/main/java/org/apache/servicecomb/samples/dependencyManagement/Application.java
create mode 100644 java-chassis-deployment-samples/war-external-tomcat/src/main/java/org/apache/servicecomb/samples/dependencyManagement/LegacyFilter.java
create mode 100644 java-chassis-deployment-samples/war-external-tomcat/src/main/java/org/apache/servicecomb/samples/dependencyManagement/LegacyServlet.java
create mode 100644 java-chassis-deployment-samples/war-external-tomcat/src/main/webapp/index.jsp
diff --git a/java-chassis-deployment-samples/war-external-tomcat/README.md b/java-chassis-deployment-samples/war-external-tomcat/README.md
new file mode 100644
index 00000000..4e71f388
--- /dev/null
+++ b/java-chassis-deployment-samples/war-external-tomcat/README.md
@@ -0,0 +1,62 @@
+# war-external-tomcat
+
+This project demonstrates **how to integrate ServiceComb microservice framework into an existing traditional Java Web application** and deploy it to an external Tomcat.
+
+## Project Features (Differences from spring-boot-external-tomcat)
+
+This project demonstrates a **legacy system integration scenario**:
+
+- **Traditional Servlet/Filter coexist with ServiceComb** - Traditional components configured via web.xml
+- **JSP page support** - Retaining existing JSP pages
+- **ServiceComb microservices** - Modern microservices integrated through Spring Boot
+- **Unified deployment** - All components packaged into a single WAR and deployed to external Tomcat
+
+While the `spring-boot-external-tomcat` project is a **pure Spring Boot application** without legacy components.
+
+Note:
+
+- Integrating legacy code → Not a ServiceComb feature, but a Servlet standard capability
+- This sample → Only proves ServiceComb follows standards and doesn't break legacy systems
+- ServiceComb's value → Lies in microservice governance (service discovery, load balancing, fault tolerance, etc.), not "coexisting with legacy code"
+
+This sample demonstrates that introducing ServiceComb is safe and won't break existing systems, eliminating migration concerns.
+
+### Project Structure
+
+```text
+├── LegacyServlet.java # [Legacy] Traditional Servlet (configured via web.xml)
+├── LegacyFilter.java # [Legacy] Traditional Filter (configured via web.xml)
+├── HelloEndpoint.java # [New] ServiceComb microservice interface
+├── Application.java # [New] Spring Boot bootstrap class
+├── index.jsp # [Legacy] Traditional JSP page
+└── web.xml # [Legacy] Traditional Servlet container configuration
+```
+
+### Key Configurations
+
+1. **pom.xml**: Add `java-chassis-spring-boot-starter-servlet` dependency
+2. **Application.java**: Create a bootstrap class that extends `SpringBootServletInitializer`
+3. **web.xml**: ServiceComb is auto-configured by Spring Boot; traditional components are configured normally
+4. **microservice.yaml**: ServiceComb configuration file
+
+## Deployment Steps
+
+1. Build the project: `mvn clean package`
+2. Deploy the generated WAR package to Tomcat's webapps directory
+3. Start Tomcat
+4. Access the services, after deployment you can visit:
+
+ - **Traditional JSP**: `http://localhost:8080/warExternalTomcat-0.0.1/`
+ - **Traditional Servlet**: `http://localhost:8080/warExternalTomcat-0.0.1/legacy`
+ - **ServiceComb API**: `http://localhost:8080/warExternalTomcat-0.0.1/rest/hello?name=world`
+
+## ServiceComb 3.x Adaptation Notes
+
+`ServiceComb 3.x` adopts the Spring Boot approach and no longer uses the traditional `RestServletContextListener`. WAR deployment to external Tomcat is achieved through `java-chassis-spring-boot-starter-servlet` and `SpringBootServletInitializer`.
+
+Only:
+
+- `RestServlet.class` - Servlet implementation
+- `RestAsyncListener.class` - Async listener (not `ServletContextListener`)
+
+Therefore, `2.x` version samples cannot be upgraded to `3.x` version.
diff --git a/java-chassis-deployment-samples/war-external-tomcat/pom.xml b/java-chassis-deployment-samples/war-external-tomcat/pom.xml
index 46c32d1f..186b29ae 100644
--- a/java-chassis-deployment-samples/war-external-tomcat/pom.xml
+++ b/java-chassis-deployment-samples/war-external-tomcat/pom.xml
@@ -27,11 +27,14 @@
UTF-8
- 1.8
+ 17
-Dfile.encoding=UTF-8
UTF-8
3.2.4
3.11.0
+ 3.1.0
+
+ 2.0.16
@@ -43,6 +46,12 @@
pom
import
+
+
+ org.slf4j
+ slf4j-api
+ ${slf4j.version}
+
@@ -50,6 +59,32 @@
org.apache.servicecomb
solution-basic
+
+
+ org.apache.logging.log4j
+ *
+
+
+ org.slf4j
+ slf4j-api
+
+
+
+
+ org.apache.servicecomb
+ java-chassis-spring-boot-starter-servlet
+
+
+ org.springframework.boot
+ spring-boot-starter-tomcat
+
+
+
+
+
+ org.slf4j
+ slf4j-api
+ ${slf4j.version}
@@ -61,8 +96,16 @@
${maven-compiler-plugin.version}
-parameters
- 17
- 17
+ ${java.version}
+ ${java.version}
+
+
+
+ org.apache.maven.plugins
+ maven-war-plugin
+ ${maven-war-plugin.version}
+
+ false
diff --git a/java-chassis-deployment-samples/war-external-tomcat/src/main/java/org/apache/servicecomb/samples/dependencyManagement/Application.java b/java-chassis-deployment-samples/war-external-tomcat/src/main/java/org/apache/servicecomb/samples/dependencyManagement/Application.java
new file mode 100644
index 00000000..0395dfbf
--- /dev/null
+++ b/java-chassis-deployment-samples/war-external-tomcat/src/main/java/org/apache/servicecomb/samples/dependencyManagement/Application.java
@@ -0,0 +1,42 @@
+/*
+ * 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.servicecomb.samples.dependencyManagement;
+
+import org.springframework.boot.WebApplicationType;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
+
+@SpringBootApplication
+public class Application extends SpringBootServletInitializer {
+ public static void main(String[] args) throws Exception {
+ try {
+ new SpringApplicationBuilder()
+ .web(WebApplicationType.SERVLET)
+ .sources(Application.class)
+ .run(args);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
+ return application.sources(Application.class);
+ }
+}
diff --git a/java-chassis-deployment-samples/war-external-tomcat/src/main/java/org/apache/servicecomb/samples/dependencyManagement/LegacyFilter.java b/java-chassis-deployment-samples/war-external-tomcat/src/main/java/org/apache/servicecomb/samples/dependencyManagement/LegacyFilter.java
new file mode 100644
index 00000000..939c4948
--- /dev/null
+++ b/java-chassis-deployment-samples/war-external-tomcat/src/main/java/org/apache/servicecomb/samples/dependencyManagement/LegacyFilter.java
@@ -0,0 +1,50 @@
+/*
+ * 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.servicecomb.samples.dependencyManagement;
+
+import java.io.IOException;
+
+import jakarta.servlet.Filter;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.FilterConfig;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
+import jakarta.servlet.http.HttpServletRequest;
+
+public class LegacyFilter implements Filter {
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException {
+ System.out.println("LegacyFilter initialized");
+ }
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+ throws IOException, ServletException {
+ HttpServletRequest httpRequest = (HttpServletRequest) request;
+ System.out.println("LegacyFilter: Processing request to " + httpRequest.getRequestURI());
+
+ request.setAttribute("legacyFilterApplied", "true");
+ chain.doFilter(request, response);
+ }
+
+ @Override
+ public void destroy() {
+ System.out.println("LegacyFilter destroyed");
+ }
+}
diff --git a/java-chassis-deployment-samples/war-external-tomcat/src/main/java/org/apache/servicecomb/samples/dependencyManagement/LegacyServlet.java b/java-chassis-deployment-samples/war-external-tomcat/src/main/java/org/apache/servicecomb/samples/dependencyManagement/LegacyServlet.java
new file mode 100644
index 00000000..140c5c3e
--- /dev/null
+++ b/java-chassis-deployment-samples/war-external-tomcat/src/main/java/org/apache/servicecomb/samples/dependencyManagement/LegacyServlet.java
@@ -0,0 +1,40 @@
+/*
+ * 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.servicecomb.samples.dependencyManagement;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServlet;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+
+public class LegacyServlet extends HttpServlet {
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+ throws ServletException, IOException {
+ resp.setContentType("text/html;charset=UTF-8");
+ PrintWriter out = resp.getWriter();
+ out.println("");
+ out.println("Legacy Servlet Example
");
+ out.println("This is a traditional servlet coexisting with ServiceComb microservices.
");
+ out.println("Request URI: " + req.getRequestURI() + "
");
+ out.println("");
+ }
+}
diff --git a/java-chassis-deployment-samples/war-external-tomcat/src/main/webapp/WEB-INF/web.xml b/java-chassis-deployment-samples/war-external-tomcat/src/main/webapp/WEB-INF/web.xml
index cb2b22e5..966dc0a8 100644
--- a/java-chassis-deployment-samples/war-external-tomcat/src/main/webapp/WEB-INF/web.xml
+++ b/java-chassis-deployment-samples/war-external-tomcat/src/main/webapp/WEB-INF/web.xml
@@ -20,37 +20,33 @@
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
-
- contextConfigLocation
-
- classpath*:META-INF/spring/*.bean.xml
-
-
+
+
-
+
+
+ LegacyFilter
+ org.apache.servicecomb.samples.dependencyManagement.LegacyFilter
+
+
+ LegacyFilter
+ /legacy/*
+
-
-
- org.apache.servicecomb.transport.rest.servlet.RestServletContextListener
-
+
+
+ LegacyServlet
+ org.apache.servicecomb.samples.dependencyManagement.LegacyServlet
+ 2
+
+
+ LegacyServlet
+ /legacy
+
-
+
+
+ index.jsp
+
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/java-chassis-deployment-samples/war-external-tomcat/src/main/webapp/index.jsp b/java-chassis-deployment-samples/war-external-tomcat/src/main/webapp/index.jsp
new file mode 100644
index 00000000..0416181b
--- /dev/null
+++ b/java-chassis-deployment-samples/war-external-tomcat/src/main/webapp/index.jsp
@@ -0,0 +1,59 @@
+<%@ page contentType="text/html;charset=UTF-8" language="java" %>
+
+
+
+ Legacy WAR with ServiceComb
+
+
+
+ 传统 WAR 包集成 ServiceComb 示例
+
+
+
遗留系统组件(Legacy Components)
+
+ - 传统 Servlet - 通过 web.xml 配置的传统 Servlet
+ - 本页面 (index.jsp) - 传统 JSP 页面
+
+
+
+
+
ServiceComb 微服务(ServiceComb Microservices)
+
+
+
+
+
特点说明
+
本项目展示了如何在已有的传统 Java Web 应用中集成 ServiceComb 微服务框架:
+
+ - 传统 Servlet/Filter 与 ServiceComb 共存
+ - JSP 页面继续正常工作
+ - ServiceComb 微服务通过 Spring Boot 方式集成
+ - 统一部署到外部 Tomcat
+
+
+
+ 部署时间: <%= new java.util.Date() %>
+
+
From 74311ac2b2a2e7045e04363c505df543f2055adb Mon Sep 17 00:00:00 2001
From: Aithusa <32020141+Aithosa@users.noreply.github.com>
Date: Fri, 23 Jan 2026 23:03:05 +0800
Subject: [PATCH 28/30] Migrate metrics write-file sample to ServiceComb 3.x
Refactored the metrics-write-file sample to support ServiceComb 3.x and Micrometer, replacing Spectator and Java SPI with Spring Boot AutoConfiguration. Updated dependencies, removed SPI registration, added auto-configuration class, and revised CloudEyeFilePublisher for Micrometer and Spring integration. Enhanced README with detailed usage, migration notes, and troubleshooting.
---
.../metrics-write-file-sample/README.md | 324 +++++++++++++++++-
.../metrics-write-file/pom.xml | 27 +-
.../samples/mwf/CloudEyeFilePublisher.java | 65 ++--
.../MetricsWriteFileAutoConfiguration.java | 33 ++
...comb.foundation.metrics.MetricsInitializer | 18 -
...ot.autoconfigure.AutoConfiguration.imports | 18 +
.../metrics-write-file-sample/pom.xml | 2 +-
7 files changed, 419 insertions(+), 68 deletions(-)
create mode 100644 java-chassis-samples/metrics-write-file-sample/metrics-write-file/src/main/java/org/apache/servicecomb/samples/mwf/MetricsWriteFileAutoConfiguration.java
delete mode 100644 java-chassis-samples/metrics-write-file-sample/metrics-write-file/src/main/resources/META-INF/services/org.apache.servicecomb.foundation.metrics.MetricsInitializer
create mode 100644 java-chassis-samples/metrics-write-file-sample/metrics-write-file/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
diff --git a/java-chassis-samples/metrics-write-file-sample/README.md b/java-chassis-samples/metrics-write-file-sample/README.md
index 8a80e0cc..380bbd96 100644
--- a/java-chassis-samples/metrics-write-file-sample/README.md
+++ b/java-chassis-samples/metrics-write-file-sample/README.md
@@ -1,10 +1,322 @@
-# Write Metrics Data into Separate Text Files Sample
-## Purpose
-This sample show how direct get metrics data and write them into separate text files,then other monitor system can load this file in order to get run state of micro-service.
+# Metrics Write File Sample
-## What Contains
+## Description
-This module implements MetricsInitializer, to customize user defined output, see [documents](https://docs.servicecomb.io/java-chassis/zh_CN/general-development/metrics/)
+This project demonstrates how to export ServiceComb metrics data to separate text files, enabling external monitoring systems to collect runtime performance data by reading these files. It implements a custom metrics publisher that writes metrics in CloudEye-compatible JSON format to dynamically named files.
+
+## What is it for?
+
+- **Non-intrusive Monitoring**: Automatically collects and exports ServiceComb metrics without modifying application code
+- **External System Integration**: Provides a file-based interface for third-party monitoring tools (e.g., CloudEye, Prometheus exporters)
+- **Flexible Output**: Each metric is written to a separate file with dynamic naming based on metric properties
+- **Production Ready**: Uses industry-standard logging frameworks (Log4j2/Logback) for reliable file I/O
+
+## How it Works
+
+### Architecture Overview
+
+```text
+ServiceComb Application
+ ↓
+MeterRegistry (Micrometer)
+ ↓ periodic polling
+EventBus.post(PolledEvent)
+ ↓
+CloudEyeFilePublisher (@Subscribe)
+ ↓ extract metrics
+Log4j2 Routing Appender
+ ↓ dynamic file routing via MDC
+Individual .dat files
+```
+
+### Core Components
+
+1. **CloudEyeFilePublisher**: Implements `MetricsInitializer` interface
+ - Subscribes to `PolledEvent` from ServiceComb's EventBus
+ - Receives metrics snapshots periodically (controlled by `servicecomb.metrics.window_time`)
+ - Converts Micrometer meters to CloudEye JSON format
+ - Uses MDC (Mapped Diagnostic Context) for dynamic file routing
+
+2. **Log4j2 Routing Appender**: Dynamically creates log files
+ - Routes logs to different files based on `fileName` MDC variable
+ - Pattern: `${appId}.${serviceName}.${metricName}.dat`
+ - Each metric gets its own file for easy parsing by external systems
+
+3. **Spring Boot AutoConfiguration**: Zero-configuration integration
+ - Automatically registers `CloudEyeFilePublisher` as a Spring Bean
+ - Supports conditional loading via `servicecomb.metrics.write-file.enabled`
+ - Leverages Spring dependency injection for clean architecture
+
+### Output Format
+
+Each `.dat` file contains JSON lines in CloudEye format:
+
+```json
+{
+ "plugin_id": "myapp.myservice",
+ "metric": {
+ "node": "hostname",
+ "timestamp": 1706025600000,
+ "dynamicValue": { "metric.name": 123.45 }
+ }
+}
+```
+
+## Changes from ServiceComb 2.x to 3.x
+
+ServiceComb 3.x migrated from **Netflix Spectator** to **Micrometer** as its metrics API. This module has been adapted accordingly:
+
+### API Changes
+
+| Aspect | ServiceComb 2.x | ServiceComb 3.x | Status |
+| ------------------- | -------------------------- | ------------------------- | ----------- |
+| Metrics Library | Netflix Spectator | Micrometer | **Changed** |
+| Registry Type | `GlobalRegistry` | `MeterRegistry` | **Changed** |
+| Meter API | `meter.measure()` iterator | `meter.measure()` forEach | **Changed** |
+| Extension Interface | `MetricsInitializer` | `MetricsInitializer` | **Kept** |
+| Event Subscription | EventBus `@Subscribe` | EventBus `@Subscribe` | **Kept** |
+| Event Type | `PolledEvent` | `PolledEvent` | **Kept** |
+
+### Architecture Evolution
+
+| Aspect | ServiceComb 2.x | ServiceComb 3.x | Status |
+| -------------------- | ---------------------------- | ----------------------------- | ----------- |
+| Loading Mechanism | Java SPI (`ServiceLoader`) | Spring Boot AutoConfiguration | **Changed** |
+| Registration File | `META-INF/services/...` | `META-INF/spring/...imports` | **Changed** |
+| Dependency Injection | Manual `BeanUtils.getBean()` | Constructor injection | **Changed** |
+| Conditional Loading | Not supported | `@ConditionalOnProperty` | **Added** |
+| Spring Integration | Separate from Spring context | Native Spring Bean | **Changed** |
+
+### Key Improvements in 3.x
+
+✅ **Better Spring Integration**: `CloudEyeFilePublisher` is now a native Spring Bean with constructor injection
+✅ **Conditional Loading**: Can be disabled via configuration property
+✅ **Cleaner Code**: No need for `BeanUtils.getBean()` hacks
+✅ **Standard Mechanism**: Uses Spring Boot's AutoConfiguration instead of Java SPI
+
+## Usage
+
+### 1. Add Dependency
+
+Add the following dependency to your ServiceComb application's `pom.xml`:
+
+```xml
+
+ org.apache.servicecomb.samples
+ metrics-write-file
+ 3.0-SNAPSHOT
+
+```
+
+### 2. Configure Application
+
+In your `application.yml`, enable metrics collection:
+
+```yaml
+servicecomb:
+ service:
+ application: myapp
+ name: myservice
+ metrics:
+ window_time: 60000 # metrics collection interval in milliseconds, has default value
+```
+
+**Optional**: Disable this feature if needed:
+
+```yaml
+servicecomb:
+ metrics:
+ write-file:
+ enabled: false # Default is true
+```
+
+### 3. Configure Log4j2
+
+Add the Routing Appender to your application's `log4j2.xml`:
+
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+ %msg%n
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Note**: Reference `sample-log4j2.xml` in the `metrics-write-file` module for a complete example.
+
+### 4. Set Log Directory (Optional)
+
+By default, metrics files are written to `logs/` directory. You can customize it:
+
+```bash
+java -DcloudEye.logDir=/custom/path/to/metrics -jar your-application.jar
+```
+
+Or in `application.yml`:
+
+```yaml
+cloudEye:
+ logDir: /custom/path/to/metrics
+```
+
+## Testing
+
+Since this is a library module, it needs to be tested with an actual ServiceComb application.
+
+### Method 1: Quick Test with Sample Project
+
+Use the `metrics-extend-healthcheck` sample:
+
+```bash
+# 1. Build and install the metrics-write-file module
+cd java-chassis-samples/metrics-write-file-sample
+mvn clean install
+
+# 2. The dependency is already configured in metrics-extend-healthcheck
+cd ../metrics-extend-healthcheck
+
+# 3. Make sure log4j2.xml includes the cloudEyeRouting appender (already configured)
+
+# 4. Run the application
+mvn spring-boot:run
+```
+
+### Method 2: Integration Test
+
+1. Add dependency to your test project
+2. Ensure Service Center is running: `http://127.0.0.1:30100`
+3. Configure `application.yml` with `servicecomb.metrics.window_time`
+4. Start your application
+5. Trigger some requests to generate metrics
+
+## How to Verify
+
+### 1. Check Startup Logs
+
+You should see the following log on application startup:
+
+```
+INFO CloudEyeFilePublisher : CloudEyeFilePublisher init() called
+INFO CloudEyeFilePublisher : CloudEyeFilePublisher filePrefix set to: myapp.myservice
+```
+
+### 2. Check Periodic Metrics Collection
+
+Every 60 seconds (or your configured `window_time`), you should see:
+
+```
+INFO CloudEyeFilePublisher : CloudEyeFilePublisher onPolledEvent() called, meters count: 45
+```
+
+### 3. Verify Metrics Files
+
+Check the `logs/` directory (or your custom `cloudEye.logDir`):
+
+```bash
+ls -l logs/
+
+# Expected output (sample):
+myapp.myservice.jvm.memory.used.area.heap.id.PS-Eden-Space.dat
+myapp.myservice.jvm.threads.live.dat
+myapp.myservice.servicecomb.invocation.count.operation.sayHello.dat
+```
+
+### 4. Inspect File Content
+
+```bash
+cat logs/myapp.myservice.jvm.memory.used.area.heap.dat
+
+# Expected JSON output:
+{"plugin_id":"myapp.myservice","metric":{"node":"hostname","timestamp":1706025600000,"dynamicValue":{"jvm.memory.used.area.heap":134217728.0}}}
+```
+
+### 5. Trigger Metrics Collection
+
+If no files appear, trigger some service invocations:
+
+```bash
+# Example: call a REST endpoint
+curl http://localhost:7777/hello
+
+# Or health check endpoint
+curl http://localhost:7777/management/health
+```
+
+Wait for the next metrics collection cycle (60 seconds by default), and files should appear.
+
+## File Naming Convention
+
+Metrics files follow the pattern: `{appId}.{serviceName}.{metricName}.{tags}.dat`
+
+Examples:
+
+- `myapp.myservice.jvm.memory.used.area.heap.id.PS-Eden-Space.dat`
+- `myapp.myservice.servicecomb.invocation.count.operation.sayHello.role.CONSUMER.dat`
+- `myapp.myservice.jvm.threads.live.dat`
+
+## Troubleshooting
+
+### No metrics files generated
+
+1. **Check log4j2.xml**: Must include the `cloudEyeRouting` appender
+
+2. **Check feature enabled**: Verify not disabled in config
+
+ ```yaml
+ servicecomb:
+ metrics:
+ write-file:
+ enabled: true # Default is true
+ ```
+
+3. **Check startup logs**: Should see "CloudEyeFilePublisher init() called"
+
+### Files created but empty
+
+1. **Trigger some traffic**: Make service calls to generate metrics
+2. **Wait for collection cycle**: Default is 60 seconds
+3. **Check EventBus logs**: Should see "onPolledEvent() called"
+
+### Permission denied errors
+
+1. **Check directory permissions**: Ensure write access to `logs/` directory
+2. **Use absolute path**: Set `cloudEye.logDir` to an absolute path
+3. **Run with proper user**: Ensure application user has write permissions
## Precondition
-see [Precondition](../../README.md)
\ No newline at end of file
+
+See [Precondition](../../README.md)
+
+## References
+
+- [ServiceComb Metrics Documentation](https://servicecomb.apache.org/references/java-chassis/en_US/general-development/metrics/)
+- [Micrometer Documentation](https://micrometer.io/docs)
+- [Log4j2 Routing Appender](https://logging.apache.org/log4j/2.x/manual/appenders.html#RoutingAppender)
diff --git a/java-chassis-samples/metrics-write-file-sample/metrics-write-file/pom.xml b/java-chassis-samples/metrics-write-file-sample/metrics-write-file/pom.xml
index d34da9b4..5bca07d5 100644
--- a/java-chassis-samples/metrics-write-file-sample/metrics-write-file/pom.xml
+++ b/java-chassis-samples/metrics-write-file-sample/metrics-write-file/pom.xml
@@ -21,7 +21,7 @@
metrics-write-file-sample
org.apache.servicecomb.samples
- 2.6.0
+ 3.0-SNAPSHOT
4.0.0
@@ -31,22 +31,15 @@
org.apache.servicecomb
- metrics-core
+ foundation-metrics
+
+
+ io.micrometer
+ micrometer-core
+
+
+ org.apache.servicecomb
+ registry-lightweight
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/java-chassis-samples/metrics-write-file-sample/metrics-write-file/src/main/java/org/apache/servicecomb/samples/mwf/CloudEyeFilePublisher.java b/java-chassis-samples/metrics-write-file-sample/metrics-write-file/src/main/java/org/apache/servicecomb/samples/mwf/CloudEyeFilePublisher.java
index d6e6f31e..2601b6c0 100644
--- a/java-chassis-samples/metrics-write-file-sample/metrics-write-file/src/main/java/org/apache/servicecomb/samples/mwf/CloudEyeFilePublisher.java
+++ b/java-chassis-samples/metrics-write-file-sample/metrics-write-file/src/main/java/org/apache/servicecomb/samples/mwf/CloudEyeFilePublisher.java
@@ -23,9 +23,8 @@
import org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig;
import org.apache.servicecomb.foundation.metrics.MetricsInitializer;
import org.apache.servicecomb.foundation.metrics.PolledEvent;
-import org.apache.servicecomb.foundation.metrics.registry.GlobalRegistry;
import org.apache.servicecomb.registry.RegistrationManager;
-import org.apache.servicecomb.registry.api.registry.Microservice;
+import org.apache.servicecomb.registry.api.RegistrationInstance;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
@@ -33,10 +32,9 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
-import com.netflix.config.DynamicPropertyFactory;
-import com.netflix.spectator.api.Measurement;
-import com.netflix.spectator.api.Meter;
-import com.netflix.spectator.api.Tag;
+import io.micrometer.core.instrument.Meter;
+import io.micrometer.core.instrument.MeterRegistry;
+import io.micrometer.core.instrument.Tag;
/**
* a sample for cloud eye
@@ -51,48 +49,61 @@ public class CloudEyeFilePublisher implements MetricsInitializer {
private static final Logger CLOUD_EYE_LOGGER = LoggerFactory.getLogger("cloudEyeLogger");
+ private final RegistrationManager registrationManager;
+
private String filePrefix;
private String hostName;
+ public CloudEyeFilePublisher(RegistrationManager registrationManager) {
+ this.registrationManager = registrationManager;
+ }
+
@Override
- public void init(GlobalRegistry globalRegistry, EventBus eventBus, MetricsBootstrapConfig config) {
+ public void init(MeterRegistry meterRegistry, EventBus eventBus, MetricsBootstrapConfig config) {
+ LOGGER.info("CloudEyeFilePublisher init() called");
eventBus.register(this);
- Microservice microservice = RegistrationManager.INSTANCE.getMicroservice();
- filePrefix = microservice.getAppId() + "." + microservice.getServiceName();
+ RegistrationInstance microserviceInstance = registrationManager.getPrimaryRegistration().getMicroserviceInstance();
+ filePrefix = microserviceInstance.getApplication() + "." + microserviceInstance.getServiceName();
+ LOGGER.info("CloudEyeFilePublisher filePrefix set to: {}", filePrefix);
+// // Use system properties or config to get appId and serviceName
+// String appId = System.getProperty("APPLICATION_ID", "defaultApp");
+// String serviceName = System.getProperty("service.name", "defaultService");
+// filePrefix = appId + "." + serviceName;
hostName = NetUtils.getHostName();
if (StringUtils.isEmpty(hostName)) {
hostName = NetUtils.getHostAddress();
}
- System.setProperty("cloudEye.logDir",
- DynamicPropertyFactory
- .getInstance()
- .getStringProperty("cloudEye.logDir", "logs")
- .get());
+ // Set default log directory if not already configured
+ System.setProperty("cloudEye.logDir",
+ System.getProperty("cloudEye.logDir", "logs/metrics-write-file"));
}
@Subscribe
public void onPolledEvent(PolledEvent event) {
+ LOGGER.info("CloudEyeFilePublisher onPolledEvent() called, meters count: {}", event.getMeters().size());
long now = System.currentTimeMillis();
for (Meter meter : event.getMeters()) {
- for (Measurement measurement : meter.measure()) {
- logMeasurement(measurement, now);
- }
+ meter.measure().forEach(measurement -> {
+ logMeasurement(meter, measurement.getValue(), now);
+ });
}
}
- protected void logMeasurement(Measurement measurement, long now) {
- String metricKey = generateMetricKey(measurement);
-
- MDC.put("fileName", filePrefix + "." + metricKey + ".dat");
+ protected void logMeasurement(Meter meter, double value, long now) {
+ String metricKey = generateMetricKey(meter);
+ String fileName = filePrefix + "." + metricKey + ".dat";
+
+ LOGGER.debug("Writing metric to file: {}, value: {}", fileName, value);
+ MDC.put("fileName", fileName);
CloudEyeMetricModel metricModel = new CloudEyeMetricModel();
metricModel.setNode(hostName);
metricModel.setTimestamp(now);
- metricModel.getDynamicValue().put(metricKey, String.valueOf(measurement.value()));
+ metricModel.getDynamicValue().put(metricKey, String.valueOf(value));
CloudEyeModel model = new CloudEyeModel();
model.setPlugin_id(filePrefix);
@@ -102,14 +113,16 @@ protected void logMeasurement(Measurement measurement, long now) {
CLOUD_EYE_LOGGER.info(JsonUtils.writeValueAsString(model));
} catch (JsonProcessingException e) {
LOGGER.error("Failed to write cloud eye log.", e);
+ } finally {
+ MDC.remove("fileName");
}
}
- protected String generateMetricKey(Measurement measurement) {
+ protected String generateMetricKey(Meter meter) {
StringBuilder sb = new StringBuilder();
- sb.append(measurement.id().name());
- for (Tag tag : measurement.id().tags()) {
- sb.append('.').append(tag.value());
+ sb.append(meter.getId().getName());
+ for (Tag tag : meter.getId().getTags()) {
+ sb.append('.').append(tag.getValue());
}
return sb.toString();
}
diff --git a/java-chassis-samples/metrics-write-file-sample/metrics-write-file/src/main/java/org/apache/servicecomb/samples/mwf/MetricsWriteFileAutoConfiguration.java b/java-chassis-samples/metrics-write-file-sample/metrics-write-file/src/main/java/org/apache/servicecomb/samples/mwf/MetricsWriteFileAutoConfiguration.java
new file mode 100644
index 00000000..edc948b5
--- /dev/null
+++ b/java-chassis-samples/metrics-write-file-sample/metrics-write-file/src/main/java/org/apache/servicecomb/samples/mwf/MetricsWriteFileAutoConfiguration.java
@@ -0,0 +1,33 @@
+/*
+ * 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.servicecomb.samples.mwf;
+
+import org.apache.servicecomb.registry.RegistrationManager;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.annotation.Bean;
+
+@AutoConfiguration
+@ConditionalOnProperty(value = "servicecomb.metrics.write-file.enabled", havingValue = "true", matchIfMissing = true)
+public class MetricsWriteFileAutoConfiguration {
+
+ @Bean
+ public CloudEyeFilePublisher cloudEyeFilePublisher(RegistrationManager registrationManager) {
+ return new CloudEyeFilePublisher(registrationManager);
+ }
+}
diff --git a/java-chassis-samples/metrics-write-file-sample/metrics-write-file/src/main/resources/META-INF/services/org.apache.servicecomb.foundation.metrics.MetricsInitializer b/java-chassis-samples/metrics-write-file-sample/metrics-write-file/src/main/resources/META-INF/services/org.apache.servicecomb.foundation.metrics.MetricsInitializer
deleted file mode 100644
index 3a6ad61e..00000000
--- a/java-chassis-samples/metrics-write-file-sample/metrics-write-file/src/main/resources/META-INF/services/org.apache.servicecomb.foundation.metrics.MetricsInitializer
+++ /dev/null
@@ -1,18 +0,0 @@
-#
-# 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.
-#
-
-org.apache.servicecomb.samples.mwf.CloudEyeFilePublisher
\ No newline at end of file
diff --git a/java-chassis-samples/metrics-write-file-sample/metrics-write-file/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/java-chassis-samples/metrics-write-file-sample/metrics-write-file/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 00000000..684821f8
--- /dev/null
+++ b/java-chassis-samples/metrics-write-file-sample/metrics-write-file/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1,18 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+
+org.apache.servicecomb.samples.mwf.MetricsWriteFileAutoConfiguration
diff --git a/java-chassis-samples/metrics-write-file-sample/pom.xml b/java-chassis-samples/metrics-write-file-sample/pom.xml
index db5d1ceb..a6330b00 100644
--- a/java-chassis-samples/metrics-write-file-sample/pom.xml
+++ b/java-chassis-samples/metrics-write-file-sample/pom.xml
@@ -22,7 +22,7 @@
samples
org.apache.servicecomb.samples
- 2.6.0
+ 3.0-SNAPSHOT
4.0.0
From 62eb764582e77b9fa93f06c34a053ca7b5e8ddb0 Mon Sep 17 00:00:00 2001
From: Aithusa <32020141+Aithosa@users.noreply.github.com>
Date: Mon, 26 Jan 2026 21:17:29 +0800
Subject: [PATCH 29/30] Add rolling file appenders to log4j2 configs
Enhanced log4j2.xml for consumer, gateway, and provider modules by adding rolling file appenders for access, metrics, and slow logs. Introduced log file path properties and updated console log patterns for improved log management and organization.
---
.../consumer/src/main/resources/log4j2.xml | 48 +++++++++++++++++--
.../gateway/src/main/resources/log4j2.xml | 48 +++++++++++++++++--
.../provider/src/main/resources/log4j2.xml | 48 +++++++++++++++++--
3 files changed, 135 insertions(+), 9 deletions(-)
diff --git a/basic-tomcat/consumer/src/main/resources/log4j2.xml b/basic-tomcat/consumer/src/main/resources/log4j2.xml
index ea906df4..9553bce7 100644
--- a/basic-tomcat/consumer/src/main/resources/log4j2.xml
+++ b/basic-tomcat/consumer/src/main/resources/log4j2.xml
@@ -15,15 +15,57 @@
specific language governing permissions and limitations
under the License.
-->
-
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
diff --git a/basic-tomcat/gateway/src/main/resources/log4j2.xml b/basic-tomcat/gateway/src/main/resources/log4j2.xml
index ea906df4..67b65d20 100644
--- a/basic-tomcat/gateway/src/main/resources/log4j2.xml
+++ b/basic-tomcat/gateway/src/main/resources/log4j2.xml
@@ -15,15 +15,57 @@
specific language governing permissions and limitations
under the License.
-->
-
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
diff --git a/basic-tomcat/provider/src/main/resources/log4j2.xml b/basic-tomcat/provider/src/main/resources/log4j2.xml
index ea906df4..169e2df5 100644
--- a/basic-tomcat/provider/src/main/resources/log4j2.xml
+++ b/basic-tomcat/provider/src/main/resources/log4j2.xml
@@ -15,15 +15,57 @@
specific language governing permissions and limitations
under the License.
-->
-
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
From f3745ef674d6b9aa9683aeb230f650fa8b8bb1cc Mon Sep 17 00:00:00 2001
From: Aithusa <32020141+Aithosa@users.noreply.github.com>
Date: Mon, 26 Jan 2026 23:15:45 +0800
Subject: [PATCH 30/30] Upgrade servicecomb version to 3.3.0
---
ServiceComb-SpringMVC/pom.xml | 2 +-
basic-tomcat/pom.xml | 2 +-
basic/pom.xml | 7 ++++---
bmi/pom.xml | 2 +-
.../spring-boot-external-tomcat/pom.xml | 2 +-
.../war-external-tomcat/pom.xml | 2 +-
java-chassis-interoprability/java-chassis-3.0.x/pom.xml | 2 +-
java-chassis-samples/apm-agent/pom.xml | 7 +++++++
.../codefirst-sample/codefirst-consumer/build.gradle | 2 +-
.../codefirst-sample/codefirst-provider/build.gradle | 2 +-
java-chassis-samples/config-apollo-sample/pom.xml | 2 ++
.../local-service-registry/local-registry-server/pom.xml | 2 +-
java-chassis-samples/pojo-sample/pojo-consumer/pom.xml | 2 ++
java-chassis-samples/pojo-sample/pojo-provider/pom.xml | 2 ++
java-chassis-samples/pojo-sample/pom.xml | 1 +
java-chassis-samples/pom.xml | 2 +-
java-chassis-samples/springmvc-sample/pom.xml | 1 +
.../springmvc-sample/springmvc-consumer/pom.xml | 2 ++
.../springmvc-sample/springmvc-provider/pom.xml | 2 ++
java-chassis-samples/trust-sample/customer/pom.xml | 2 ++
java-chassis-samples/trust-sample/hacker/pom.xml | 2 ++
java-chassis-samples/trust-sample/pom.xml | 1 +
java-chassis-samples/trust-sample/store/pom.xml | 2 ++
java-chassis-samples/use-log4j2-sample/pom.xml | 1 +
porter/pom.xml | 2 +-
25 files changed, 42 insertions(+), 14 deletions(-)
diff --git a/ServiceComb-SpringMVC/pom.xml b/ServiceComb-SpringMVC/pom.xml
index 0ec9e28b..56f56895 100644
--- a/ServiceComb-SpringMVC/pom.xml
+++ b/ServiceComb-SpringMVC/pom.xml
@@ -28,7 +28,7 @@
servicecomb
http://maven.apache.org
- 3.2.4
+ 3.3.0
4.13.1
UTF-8
17
diff --git a/basic-tomcat/pom.xml b/basic-tomcat/pom.xml
index 94904531..eb2a39d0 100644
--- a/basic-tomcat/pom.xml
+++ b/basic-tomcat/pom.xml
@@ -28,7 +28,7 @@
17
UTF-8
- 3.2.4
+ 3.3.0
3.1.3
3.11.0
diff --git a/basic/pom.xml b/basic/pom.xml
index 11313ea1..068da838 100644
--- a/basic/pom.xml
+++ b/basic/pom.xml
@@ -26,8 +26,9 @@
pom
+ 17
UTF-8
- 3.2.4
+ 3.3.0
3.1.3
3.11.0
@@ -121,8 +122,8 @@
${maven-compiler-plugin.version}
-parameters
- 17
- 17
+ ${java.version}
+ ${java.version}
diff --git a/bmi/pom.xml b/bmi/pom.xml
index 4ba2025a..9bbff5bc 100644
--- a/bmi/pom.xml
+++ b/bmi/pom.xml
@@ -27,7 +27,7 @@
UTF-8
- 3.2.4
+ 3.3.0
3.1.3
3.11.0
17
diff --git a/java-chassis-deployment-samples/spring-boot-external-tomcat/pom.xml b/java-chassis-deployment-samples/spring-boot-external-tomcat/pom.xml
index 27a8ce39..e1e1f9ac 100644
--- a/java-chassis-deployment-samples/spring-boot-external-tomcat/pom.xml
+++ b/java-chassis-deployment-samples/spring-boot-external-tomcat/pom.xml
@@ -24,7 +24,7 @@
17
-Dfile.encoding=UTF-8
UTF-8
- 3.2.4
+ 3.3.0
3.11.0
2.0.16
diff --git a/java-chassis-deployment-samples/war-external-tomcat/pom.xml b/java-chassis-deployment-samples/war-external-tomcat/pom.xml
index 186b29ae..89e7993a 100644
--- a/java-chassis-deployment-samples/war-external-tomcat/pom.xml
+++ b/java-chassis-deployment-samples/war-external-tomcat/pom.xml
@@ -30,7 +30,7 @@
17
-Dfile.encoding=UTF-8
UTF-8
- 3.2.4
+ 3.3.0
3.11.0
3.1.0
diff --git a/java-chassis-interoprability/java-chassis-3.0.x/pom.xml b/java-chassis-interoprability/java-chassis-3.0.x/pom.xml
index a5f18220..b3db3f47 100644
--- a/java-chassis-interoprability/java-chassis-3.0.x/pom.xml
+++ b/java-chassis-interoprability/java-chassis-3.0.x/pom.xml
@@ -31,7 +31,7 @@
UTF-8
- 3.2.4
+ 3.3.0
diff --git a/java-chassis-samples/apm-agent/pom.xml b/java-chassis-samples/apm-agent/pom.xml
index b8573814..f67d2e96 100644
--- a/java-chassis-samples/apm-agent/pom.xml
+++ b/java-chassis-samples/apm-agent/pom.xml
@@ -32,6 +32,7 @@
3.1.0
+ 2.28.0
org.apache.servicecomb.samples.apm.AgentMain
@@ -41,6 +42,12 @@
provider-rest-common
provided