diff --git a/.artifacts b/.artifacts index 8e3789b5bb..be912a56f7 100644 --- a/.artifacts +++ b/.artifacts @@ -65,6 +65,7 @@ dubbo-metrics-metadata dubbo-metrics-prometheus dubbo-metrics-registry dubbo-metrics-config-center +dubbo-metrics-netty dubbo-monitor dubbo-monitor-api dubbo-monitor-common diff --git a/.asf.yaml b/.asf.yaml index 7b00d47b06..cb1d0d1037 100644 --- a/.asf.yaml +++ b/.asf.yaml @@ -25,6 +25,7 @@ notifications: github: homepage: https://dubbo.apache.org/ + description: "The java implementation of Apache Dubbo. An RPC and microservice framework." features: # Enable wiki for documentation wiki: true @@ -44,9 +45,13 @@ github: foo: bar labels: - java + - rpc - microservices - framework - restful - distributed-systems - - rpc - dubbo + - service-mesh + - http + - grpc + - web diff --git a/CHANGES.md b/CHANGES.md index 625906f3b8..2c282afdf6 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -184,7 +184,7 @@ check 2.7.5 milestone for details. - Add a script to check dependencies license. [#3840](https://github.com/apache/dubbo/issues/3840) - Change DynamicConfiguration definition to better adapt to Apollo's namespace storage model.[#3266](https://github.com/apache/dubbo/issues/3266) - use equal explicit class to replace anonymous class [#4027](https://github.com/apache/dubbo/issues/4027) -- Seperate Constants.java into some SubConstants Class [#3137](https://github.com/apache/dubbo/issues/3137) +- Separate Constants.java into some SubConstants Class [#3137](https://github.com/apache/dubbo/issues/3137) - Need to enhance DecodeableRpcResult error message [#3994](https://github.com/apache/dubbo/issues/3994) - Provide more meaningful binary releases. [#2491](https://github.com/apache/dubbo/issues/2491) - remove useless module-dubbo-test-integration [#3573](https://github.com/apache/dubbo/issues/3573) @@ -211,7 +211,7 @@ check 2.7.5 milestone for details. - Fix consumer will generate wrong stackTrace. [#4137](https://github.com/apache/dubbo/issues/4137) - nacos registry serviceName may conflict. [#4111](https://github.com/apache/dubbo/issues/4111) - The client loses the listener when the network is reconnected. [#4115](https://github.com/apache/dubbo/issues/4115) -- fix registery urls increase forever when recreate reference proxy. [#4109](https://github.com/apache/dubbo/issues/4109) +- fix registry urls increase forever when recreate reference proxy. [#4109](https://github.com/apache/dubbo/issues/4109) - In dubbo 2.7.1,the watcher processor of zookeeper client throw Nullpointexception. [#3866](https://github.com/apache/dubbo/issues/3866) - ReferenceConfig initialized not changed to false once subscribe throws exception [#4068](https://github.com/apache/dubbo/issues/4068) - dubbo registry extension compatibility with dubbo 2.6.x. [#3882](https://github.com/apache/dubbo/issues/3882) @@ -400,7 +400,7 @@ Enhancement / New feature: * tag route. #3065 * Use Netty4 as default Netty version. #3029 * upporting Java 8 Date/Time type when serializing with Kryo #3519 -* supoort config telnet #3511 +* support config telnet #3511 * add annotation driven in MethodConfig and ArgumentConfig #2603 * add nacos-registry module #3296 * add `protocol` attribute in `@Rerefence` #3555 @@ -416,7 +416,7 @@ BugFix: * SPI entires dup by 3 times #3315 * fix Consumer throws RpcException after RegistryDirectory notify in high QPS #2016 * fix NPE in @Reference when using Junit to test dubbo service #3429 -* fix consuer always catch java.lang.reflect.UndeclaredThrowableException for any exception throws in provider #3386 +* fix consumer always catch java.lang.reflect.UndeclaredThrowableException for any exception throws in provider #3386 * fix the priority of `DubboConfigConfigurationSelector ` #2897 * fix `@Rerefence#parameters()` not work #2301 diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md index e924748243..acc7d007d8 100644 --- a/PULL_REQUEST_TEMPLATE.md +++ b/PULL_REQUEST_TEMPLATE.md @@ -1,21 +1,8 @@ -## What is the purpose of the change +## What is the purpose of the change? - -## Brief changelog - - -## Verifying this change - - - - ## Checklist -- [x] Make sure there is a [GitHub_issue](https://github.com/apache/dubbo/issues) field for the change (usually before you start working on it). Trivial changes like typos do not require a GitHub issue. Your pull request should address just this issue, without pulling in other changes - one PR resolves one issue. -- [ ] Each commit in the pull request should have a meaningful subject line and body. -- [ ] Write a pull request description that is detailed enough to understand what the pull request does, how, and why. -- [ ] Check if is necessary to patch to Dubbo 3 if you are work on Dubbo 2.7 -- [ ] Write necessary unit-test to verify your logic correction, more mock a little better when cross module dependency exist. If the new feature or significant change is committed, please remember to add sample in [dubbo samples](https://github.com/apache/dubbo-samples) project. -- [ ] Add some description to [dubbo-website](https://github.com/apache/dubbo-website) project if you are requesting to add a feature. -- [ ] GitHub Actions works fine on your own branch. -- [ ] If this contribution is large, please follow the [Software Donation Guide](https://github.com/apache/dubbo/wiki/Software-donation-guide). +- [x] Make sure there is a [GitHub_issue](https://github.com/apache/dubbo/issues) field for the change. +- [x] Write a pull request description that is detailed enough to understand what the pull request does, how, and why. +- [x] Write necessary unit-test to verify your logic correction. If the new feature or significant change is committed, please remember to add sample in [dubbo samples](https://github.com/apache/dubbo-samples) project. +- [x] Make sure gitHub actions can pass. [Why the workflow is failing and how to fix it?](./CONTRIBUTING.md) diff --git a/README.md b/README.md index e34ee20894..504b42f014 100644 --- a/README.md +++ b/README.md @@ -10,236 +10,69 @@ [![Twitter Follow](https://img.shields.io/twitter/follow/ApacheDubbo.svg?label=Follow&style=social&logoWidth=0)](https://twitter.com/intent/follow?screen_name=ApacheDubbo) [![Gitter](https://badges.gitter.im/alibaba/dubbo.svg)](https://gitter.im/alibaba/dubbo?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) -Apache Dubbo is a high-performance, Java-based open-source RPC framework. Please visit the [official site](http://dubbo.apache.org) for the quick start guide and documentation, as well as the [wiki](https://github.com/apache/dubbo/wiki) for news, FAQ, and release notes. +Apache Dubbo is an easy-to-use Web and RPC framework that provides multiple +language implementations(Java, [Go](https://github.com/apache/dubbo-go), [Rust](https://github.com/apache/dubbo-rust), [Node.js](https://github.com/apache/dubbo-js), [Web](https://github.com/apache/dubbo-js)) for communication, service discovery, traffic management, +observability, security, tools, and best practices for building enterprise-ready microservices. -We are now collecting Dubbo user info to help us to improve Dubbo further. Kindly support us by providing your usage information on [issue#9436: Wanted: who's using dubbo](https://github.com/apache/dubbo/issues/9436), thanks :) +Visit [the official website](https://dubbo.apache.org/) for more information. ## Architecture - ![Architecture](https://dubbo.apache.org/imgs/architecture.png) -## Features - -* Transparent interface based RPC -* Intelligent load balancing -* Automatic service registration and discovery -* High extensibility -* Runtime traffic routing -* Visualized service governance +* Consumer and provider communicate with each other using RPC protocol like triple, tcp, rest, etc. +* Consumers automatically trace provider instances registered in registries(Zookeeper, Nacos) and distribute traffic among them by following traffic strategies. +* Rich features for monitoring and managing the cluster with dynamic configuration, metrics, tracing, security, and visualized console. ## Getting started +Follow the instructions below to learn how to: -The following code snippet comes from [Dubbo Samples](https://github.com/apache/dubbo-samples.git). You may clone the sample project and step into the `dubbo-samples-api` subdirectory before proceeding. +### Programming with lightweight RPC API +[5 minutes step-by-step guide](https://dubbo.apache.org/zh-cn/overview/quickstart/rpc/java) -```bash -git clone https://github.com/apache/dubbo-samples.git -cd dubbo-samples/1-basic/dubbo-samples-api -``` - -There's a [README](https://github.com/apache/dubbo-samples/blob/389cd612f1ea57ee6e575005b32f195c442c35a2/1-basic/dubbo-samples-api/README.md) file under `dubbo-samples-api` directory. We recommend referencing the samples in that directory by following the below-mentioned instructions: - -### Maven dependency - -```xml - - 3.0.10 - - - - - org.apache.dubbo - dubbo - ${dubbo.version} - - - org.apache.dubbo - dubbo-dependencies-zookeeper - ${dubbo.version} - pom - - -``` - -### Define service interfaces - -```java -package org.apache.dubbo.samples.api; - -public interface GreetingsService { - String sayHi(String name); -} -``` - -*See [api/GreetingsService.java](https://github.com/apache/dubbo-samples/blob/389cd612f1ea57ee6e575005b32f195c442c35a2/1-basic/dubbo-samples-api/src/main/java/org/apache/dubbo/samples/api/GreetingsService.java) on GitHub.* - -### Implement service interface for the provider - -```java -package org.apache.dubbo.samples.provider; - -import org.apache.dubbo.samples.api.GreetingsService; - -public class GreetingsServiceImpl implements GreetingsService { - @Override - public String sayHi(String name) { - return "hi, " + name; - } -} -``` - -*See [provider/GreetingsServiceImpl.java](https://github.com/apache/dubbo-samples/blob/389cd612f1ea57ee6e575005b32f195c442c35a2/1-basic/dubbo-samples-api/src/main/java/org/apache/dubbo/samples/provider/GreetingsServiceImpl.java) on GitHub.* - -### Start service provider - -```java -package org.apache.dubbo.samples.provider; +Dubbo supports building RPC services with only a few lines of code while depending only on a lightweight SDK (<10MB). The protocol on the wire can be [Triple](https://dubbo.apache.org/zh-cn/overview/reference/protocols/triple/)(fully gRPC compatible and HTTP-friendly), Dubbo2(TCP), REST, or any protocol of your choice. -import org.apache.dubbo.config.ApplicationConfig; -import org.apache.dubbo.config.RegistryConfig; -import org.apache.dubbo.config.ServiceConfig; -import org.apache.dubbo.samples.api.GreetingsService; +### Building a microservice application with Spring Boot +[5 minutes step-by-step guide](https://dubbo.apache.org/zh-cn/overview/quickstart/microservice) -import java.util.concurrent.CountDownLatch; +It's highly recommended to start your microservice application with the Spring Boot Starter `dubbo-spring-boot-starter` provided by Dubbo. With only a single dependency and yaml file, and optionally a bunch of other useful spring boot starters, you can enable all of the Dubo features like service discovery, observability, tracing, etc. -public class Application { - private static String zookeeperHost = System.getProperty("zookeeper.address", "127.0.0.1"); +Next, learn how to [deploy](https://dubbo.apache.org/zh-cn/overview/tasks/deploy/), [monitor](https://dubbo.apache.org/zh-cn/overview/tasks/observability/), and [manage the traffic](https://dubbo.apache.org/zh-cn/overview/tasks/traffic-management/) of your Dubbo application and cluster. - public static void main(String[] args) throws Exception { - ServiceConfig service = new ServiceConfig<>(); - service.setApplication(new ApplicationConfig("first-dubbo-provider")); - service.setRegistry(new RegistryConfig("zookeeper://" + zookeeperHost + ":2181")); - service.setInterface(GreetingsService.class); - service.setRef(new GreetingsServiceImpl()); - service.export(); +## More Features +Get more details by visiting the links below to get your hands dirty with some well-designed tasks on our website. - System.out.println("dubbo service started"); - new CountDownLatch(1).await(); - } -} -``` +* [Launch a Dubbo project](https://dubbo.apache.org/zh-cn/overview/tasks/develop/template/) +* [RPC protocols](https://dubbo.apache.org/zh-cn/overview/core-features/protocols/) +* [Traffic management](https://dubbo.apache.org/zh-cn/overview/core-features/traffic/) +* [Service discovery](https://dubbo.apache.org/zh-cn/overview/core-features/service-discovery/) +* [Observability](https://dubbo.apache.org/zh-cn/overview/core-features/observability/) +* [Extensibility](https://dubbo.apache.org/zh-cn/overview/core-features/extensibility/) +* [Security](https://dubbo.apache.org/zh-cn/overview/core-features/security/) +* [Visualized console and control plane](https://dubbo.apache.org/zh-cn/overview/reference/admin/) +* [Kubernetes and Service mesh](https://dubbo.apache.org/zh-cn/overview/core-features/service-mesh/) -*See [provider/Application.java](https://github.com/apache/dubbo-samples/blob/389cd612f1ea57ee6e575005b32f195c442c35a2/1-basic/dubbo-samples-spring-xml/src/main/java/org/apache/dubbo/samples/provider/Application.java) on GitHub.* +## Which Dubbo version should I use? +| **Dubbo3** | **JDK** | **Dependencies** | **Description** | +| --- | --- | --- | --- | +| 3.3.0-beta| 1.8 ~ 17 | [dependency list](https://github.com/apache/dubbo/blob/3.3/dubbo-dependencies-bom/pom.xml#L94) | **- Unstable version**
**- Features**
   - Triple - gRPC and cURL compatible.
   - Rest-style programming support.
   - Spring Boot Starters. | +| 3.2.5 | 1.8 ~ 17 | [dependency list](https://github.com/apache/dubbo/blob/dubbo-3.2.5/dubbo-dependencies-bom/pom.xml#L94) | **- Stable version (active)**
**- Features**
  - Out-of-box metrics and tracing support.
  - Threadpool Isolation
  - 30% performance
  - Native Image| +| 3.1.11 | 1.8 ~ 11 | [dependency list](https://github.com/apache/dubbo/blob/dubbo-3.2.11/dubbo-dependencies-bom/pom.xml#L94) | **Stable version (not active)** | -### Build and run the provider - -```bash -mvn clean package -mvn -Djava.net.preferIPv4Stack=true -Dexec.mainClass=org.apache.dubbo.samples.provider.Application exec:java -``` - -### Call remote service in the consumer - -```java -package org.apache.dubbo.samples.client; - - -import org.apache.dubbo.config.ApplicationConfig; -import org.apache.dubbo.config.ReferenceConfig; -import org.apache.dubbo.config.RegistryConfig; -import org.apache.dubbo.samples.api.GreetingsService; - -public class Application { - private static String zookeeperHost = System.getProperty("zookeeper.address", "127.0.0.1"); - - public static void main(String[] args) { - ReferenceConfig reference = new ReferenceConfig<>(); - reference.setApplication(new ApplicationConfig("first-dubbo-consumer")); - reference.setRegistry(new RegistryConfig("zookeeper://" + zookeeperHost + ":2181")); - reference.setInterface(GreetingsService.class); - GreetingsService service = reference.get(); - String message = service.sayHi("dubbo"); - System.out.println(message); - } -} -``` -*See [client/Application.java](https://github.com/apache/dubbo-samples/blob/389cd612f1ea57ee6e575005b32f195c442c35a2/1-basic/dubbo-samples-api/src/main/java/org/apache/dubbo/samples/client/Application.java) on GitHub.* - -### Build and run the consumer - -```bash -mvn clean package -mvn -Djava.net.preferIPv4Stack=true -Dexec.mainClass=org.apache.dubbo.samples.client.Application exec:java -``` - -The consumer will print out `hi, dubbo` on the screen. - - -### Next steps - -* [Your first Dubbo application](https://dubbo.apache.org/en/blog/2018/08/07/dubbo-101/) - A 101 tutorial to reveal more details, with the same code above. -* [Dubbo user manual](https://dubbo.apache.org/en/overview/what/) - How to use Dubbo and all its features. -* [Dubbo developer guide](https://dubbo.apache.org/en/docs3-v2/java-sdk/) - How to involve in Dubbo development. -* [Dubbo admin manual](https://dubbo.apache.org/en/docs/v2.7/admin/ops/) - How to admin and manage Dubbo services. - -## Building - -If you want to try out the cutting-edge features, you can build with the following commands. (Java 1.8 is needed to build the master branch) - -``` - mvn clean install -``` - -## Recommended Test Environment -To avoid intermittent test failures (i.e., flaky tests), it is recommended to have a machine or virtual machine with the following specifications: - -* Minumum of 2CPUs. -* Minimum of 2Gb of RAM. - -## Contact - -* Mailing list: - * dev list: for dev/user discussion. [subscribe](mailto:dev-subscribe@dubbo.apache.org), [unsubscribe](mailto:dev-unsubscribe@dubbo.apache.org), [archive](https://lists.apache.org/list.html?dev@dubbo.apache.org), [guide](https://github.com/apache/dubbo/wiki/Mailing-list-subscription-guide) - -* Bugs: [Issues](https://github.com/apache/dubbo/issues/new?template=dubbo-issue-report-template.md) -* Gitter: [Gitter channel](https://gitter.im/alibaba/dubbo) -* Twitter: [@ApacheDubbo](https://twitter.com/ApacheDubbo) +| **Dubbo2** | **JDK** | **Dependencies** | **Description** | +| --- | --- | --- | --- | +| 2.7.23 | 1.8 | [dependency list](https://github.com/apache/dubbo/blob/dubbo-2.7.23/dubbo-dependencies-bom/pom.xml#L92) | EOL | +| 2.6.x, 2.5.x | 1.6 ~ 1.7 | | EOL | ## Contributing +See [CONTRIBUTING](https://github.com/apache/dubbo/blob/master/CONTRIBUTING.md) for details on submitting patches and the contribution workflow. -See [CONTRIBUTING](https://github.com/apache/dubbo/blob/master/CONTRIBUTING.md) for details on submitting patches and the contribution workflow. - -### How can I contribute? - -* Take a look at issues with tags marked [`Good first issue`](https://github.com/apache/dubbo/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) or [`Help wanted`](https://github.com/apache/dubbo/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22). -* Join the discussion on the mailing list, subscription [guide](https://github.com/apache/dubbo/wiki/Mailing-list-subscription-guide). -* Answer questions on [issues](https://github.com/apache/dubbo/issues). -* Fix bugs reported on [issues](https://github.com/apache/dubbo/issues), and send us a pull request. -* Review the existing [pull request](https://github.com/apache/dubbo/pulls). -* Improve the [website](https://github.com/apache/dubbo-website), typically we need - * blog post - * translation on documentation - * use cases around the integration of Dubbo in enterprise systems. -* Improve the [dubbo-admin/dubbo-monitor](https://github.com/apache/dubbo-admin). -* Contribute to the projects listed in [ecosystem](https://github.com/dubbo). -* Other forms of contribution not explicitly enumerated above. -* If you would like to contribute, please send an email to dev@dubbo.apache.org to let us know! - -## Reporting bugs - -Please follow the [template](https://github.com/apache/dubbo/issues/new?template=dubbo-issue-report-template.md) for reporting any issues. - -## Reporting a security vulnerability - -Please report security vulnerabilities to [us](mailto:security@dubbo.apache.org) privately. - -## Dubbo ecosystem - -* [Dubbo Ecosystem Entry](https://github.com/apache?utf8=%E2%9C%93&q=dubbo&type=&language=) - A GitHub group `dubbo` to gather all Dubbo relevant projects not appropriate in [apache](https://github.com/apache) group yet -* [Dubbo Website](https://github.com/apache/dubbo-website) - Apache Dubbo official website -* [Dubbo Samples](https://github.com/apache/dubbo-samples) - samples for Apache Dubbo -* [Dubbo Spring Boot](https://github.com/apache/dubbo-spring-boot-project) - Spring Boot Project for Dubbo -* [Dubbo Admin](https://github.com/apache/dubbo-admin) - The reference implementation for Dubbo admin -* [Dubbo Awesome](https://github.com/apache/dubbo-awesome) - Dubbo's slides and video links in Meetup - -#### Language - -* [Go](https://github.com/dubbo/dubbo-go) (recommended) -* [Node.js](https://github.com/apache/dubbo-js) -* [Python](https://github.com/dubbo/py-client-for-apache-dubbo) -* [PHP](https://github.com/apache/dubbo-php-framework) -* [Erlang](https://github.com/apache/dubbo-erlang) +## Contact +* WeChat: apachedubbo +* DingTalk group: 37290003945 +* Mailing list: [guide](https://dubbo.apache.org/zh-cn/contact/) +* Twitter: [@ApacheDubbo](https://twitter.com/ApacheDubbo) +* Security issues: please mail to [us](mailto:security@dubbo.apache.org) privately. ## License - -Apache Dubbo software is licenced under the Apache License Version 2.0. See the [LICENSE](https://github.com/apache/dubbo/blob/master/LICENSE) file for details. +Apache Dubbo is licensed under the Apache License Version 2.0. See the [LICENSE](https://github.com/apache/dubbo/blob/master/LICENSE) file for details. diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/AbstractDirectory.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/AbstractDirectory.java index 3583b15f1c..4ffe016d12 100644 --- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/AbstractDirectory.java +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/AbstractDirectory.java @@ -352,7 +352,7 @@ public abstract class AbstractDirectory implements Directory { } }, reconnectTaskPeriod, TimeUnit.MILLISECONDS); } - MetricsEventBus.publish(RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary())); + MetricsEventBus.publish(RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary(), getDirectoryMeta())); } /** @@ -366,7 +366,11 @@ public abstract class AbstractDirectory implements Directory { if (invokersInitialized) { refreshInvokerInternal(); } - MetricsEventBus.publish(RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary())); + MetricsEventBus.publish(RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary(), getDirectoryMeta())); + } + + protected Map getDirectoryMeta() { + return Collections.emptyMap(); } private synchronized void refreshInvokerInternal() { @@ -395,7 +399,7 @@ public abstract class AbstractDirectory implements Directory { removeValidInvoker(invoker); logger.info("Disable service address: " + invoker.getUrl() + "."); } - MetricsEventBus.publish(RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary())); + MetricsEventBus.publish(RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary(), getDirectoryMeta())); } @Override @@ -408,7 +412,7 @@ public abstract class AbstractDirectory implements Directory { } } - MetricsEventBus.publish(RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary())); + MetricsEventBus.publish(RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary(), getDirectoryMeta())); } protected final void refreshRouter(BitList> newlyInvokers, Runnable switchAction) { @@ -465,7 +469,7 @@ public abstract class AbstractDirectory implements Directory { refreshInvokerInternal(); this.invokersInitialized = true; - MetricsEventBus.publish(RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary())); + MetricsEventBus.publish(RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary(), getDirectoryMeta())); } protected void destroyInvokers() { @@ -480,7 +484,7 @@ public abstract class AbstractDirectory implements Directory { synchronized (this.validInvokers) { result = this.validInvokers.add(invoker); } - MetricsEventBus.publish(RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary())); + MetricsEventBus.publish(RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary(), getDirectoryMeta())); return result; } @@ -489,7 +493,7 @@ public abstract class AbstractDirectory implements Directory { synchronized (this.validInvokers) { result = this.validInvokers.remove(invoker); } - MetricsEventBus.publish(RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary())); + MetricsEventBus.publish(RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary(), getDirectoryMeta())); return result; } @@ -519,18 +523,7 @@ public abstract class AbstractDirectory implements Directory { } private Map groupByServiceKey(Collection> invokers) { - - Map serviceNumMap = new HashMap<>(); - for (Invoker invoker : invokers) { - if (invoker.getClass().getSimpleName().contains("Mockito")) { - return serviceNumMap; - } - } - if (invokers.size() > 0) { - serviceNumMap = invokers.stream().filter(invoker -> invoker.getInterface() != null).collect(Collectors.groupingBy(invoker -> invoker.getInterface().getName(), Collectors.reducing(0, e -> 1, Integer::sum))); - } - - return serviceNumMap; + return Collections.singletonMap(getConsumerUrl().getServiceKey(), invokers.size()); } @Override diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/StaticDirectory.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/StaticDirectory.java index 36e3d3eb59..d5ec1e512b 100644 --- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/StaticDirectory.java +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/StaticDirectory.java @@ -27,9 +27,12 @@ import org.apache.dubbo.rpc.cluster.RouterChain; import org.apache.dubbo.rpc.cluster.SingleRouterChain; import org.apache.dubbo.rpc.cluster.router.state.BitList; +import java.util.Collections; import java.util.List; +import java.util.Map; import static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_FAILED_SITE_SELECTION; +import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_KEY; /** * StaticDirectory @@ -125,4 +128,8 @@ public class StaticDirectory extends AbstractDirectory { return invokers; } + @Override + protected Map getDirectoryMeta() { + return Collections.singletonMap(REGISTRY_KEY, "static"); + } } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java index b768ee0f9e..fcf113302f 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java @@ -33,6 +33,8 @@ public interface CommonConstants { String CONSUMER = "consumer"; + String CALLBACK = "callback"; + String APPLICATION_KEY = "application"; String APPLICATION_VERSION_KEY = "application.version"; @@ -241,6 +243,8 @@ public interface CommonConstants { String INTERFACE_REGISTER_MODE = "interface"; + String INSTANCE_REGISTER_MODE = "instance"; + String DEFAULT_REGISTER_MODE = "all"; String GENERIC_KEY = "generic"; @@ -637,8 +641,7 @@ public interface CommonConstants { String REST_SERVICE_DEPLOYER_URL_ATTRIBUTE_KEY = "restServiceDeployerAttributeKey"; - String SERVICE_DEPLOYER_ATTRIBUTE_KEY = "serviceDeployer"; - String RESTEASY_NETTY_HTTP_REQUEST_ATTRIBUTE_KEY = "resteasyNettyHttpRequest"; + String SERVICE_DEPLOYER_ATTRIBUTE_KEY = "serviceDeployer"; String RESTEASY_NETTY_HTTP_REQUEST_ATTRIBUTE_KEY = "resteasyNettyHttpRequest"; String DUBBO_MANUAL_REGISTER_KEY = "dubbo.application.manual-register"; } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/MetricsConstants.java b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/MetricsConstants.java index e7805eaa32..49bd9665c7 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/MetricsConstants.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/MetricsConstants.java @@ -47,6 +47,8 @@ public interface MetricsConstants { String TAG_CHANGE_TYPE = "change.type"; + String TAG_ERROR_CODE = "error"; + String ENABLE_JVM_METRICS_KEY = "enable.jvm"; String AGGREGATION_COLLECTOR_KEY = "aggregation"; diff --git a/dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/exporter/TraceExporter.java b/dubbo-common/src/main/java/org/apache/dubbo/common/logger/ListenableLogger.java similarity index 71% rename from dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/exporter/TraceExporter.java rename to dubbo-common/src/main/java/org/apache/dubbo/common/logger/ListenableLogger.java index 9b8f12ee4b..e0d3c76cae 100644 --- a/dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/exporter/TraceExporter.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/logger/ListenableLogger.java @@ -14,24 +14,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.tracing.exporter; -import brave.handler.SpanHandler; -import io.opentelemetry.sdk.trace.export.SpanExporter; +package org.apache.dubbo.common.logger; -public interface TraceExporter { +/** + * Loggers that can register to listen to log messages. + */ +public interface ListenableLogger extends ErrorTypeAwareLogger{ /** - * for otel + * Register a listener to this logger,and get notified when a log happens. * - * @return + * @param listener log listener */ - SpanExporter getSpanExporter(); + void registerListen(LogListener listener); - /** - * for brave - * - * @return - */ - SpanHandler getSpanHandler(); } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/logger/LogListener.java b/dubbo-common/src/main/java/org/apache/dubbo/common/logger/LogListener.java new file mode 100644 index 0000000000..c0308e8a41 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/logger/LogListener.java @@ -0,0 +1,27 @@ +/* + * 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.dubbo.common.logger; + +/** + * Log Listener, can registered to an {@link ListenableLogger}. + */ +public interface LogListener { + + void onMessage(String code, String msg); + +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/logger/support/FailsafeErrorTypeAwareLogger.java b/dubbo-common/src/main/java/org/apache/dubbo/common/logger/support/FailsafeErrorTypeAwareLogger.java index 8438c0ebfd..f5b7d5ef5a 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/logger/support/FailsafeErrorTypeAwareLogger.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/logger/support/FailsafeErrorTypeAwareLogger.java @@ -18,16 +18,22 @@ package org.apache.dubbo.common.logger.support; import org.apache.dubbo.common.Version; -import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; +import org.apache.dubbo.common.logger.ListenableLogger; +import org.apache.dubbo.common.logger.LogListener; import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.utils.NetUtils; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicReference; import java.util.regex.Pattern; /** * A fail-safe (ignoring exception thrown by logger) wrapper of error type aware logger. */ -public class FailsafeErrorTypeAwareLogger extends FailsafeLogger implements ErrorTypeAwareLogger { +public class FailsafeErrorTypeAwareLogger extends FailsafeLogger implements ListenableLogger { /** * Template address for formatting. @@ -36,6 +42,16 @@ public class FailsafeErrorTypeAwareLogger extends FailsafeLogger implements Erro private static final Pattern ERROR_CODE_PATTERN = Pattern.compile("\\d+-\\d+"); + /** + * Listeners that listened to all Loggers. + */ + private static final List GLOBAL_LISTENERS = Collections.synchronizedList(new ArrayList<>()); + + /** + * Listeners that listened to this listener. + */ + private final AtomicReference> listeners = new AtomicReference<>(); + public FailsafeErrorTypeAwareLogger(Logger logger) { super(logger); } @@ -80,6 +96,7 @@ public class FailsafeErrorTypeAwareLogger extends FailsafeLogger implements Erro } try { + onEvent(code, msg); getLogger().warn(appendContextMessageWithInstructions(code, cause, extendedInformation, msg)); } catch (Throwable t) { // ignored. @@ -93,6 +110,7 @@ public class FailsafeErrorTypeAwareLogger extends FailsafeLogger implements Erro } try { + onEvent(code, msg); getLogger().warn(appendContextMessageWithInstructions(code, cause, extendedInformation, msg), e); } catch (Throwable t) { // ignored. @@ -106,6 +124,7 @@ public class FailsafeErrorTypeAwareLogger extends FailsafeLogger implements Erro } try { + onEvent(code, msg); getLogger().error(appendContextMessageWithInstructions(code, cause, extendedInformation, msg)); } catch (Throwable t) { // ignored. @@ -119,9 +138,45 @@ public class FailsafeErrorTypeAwareLogger extends FailsafeLogger implements Erro } try { + onEvent(code, msg); getLogger().error(appendContextMessageWithInstructions(code, cause, extendedInformation, msg), e); } catch (Throwable t) { // ignored. } } + + public static void registerGlobalListen(LogListener listener) { + GLOBAL_LISTENERS.add(listener); + } + + @Override + public void registerListen(LogListener listener) { + listeners.getAndUpdate(logListeners -> { + if (logListeners == null) { + logListeners = Collections.synchronizedList(new ArrayList<>()); + } + logListeners.add(listener); + return logListeners; + }); + } + + private void onEvent(String code, String msg) { + Optional.ofNullable(listeners.get()).ifPresent( + logListeners -> logListeners.forEach(logListener -> { + try { + logListener.onMessage(code, msg); + } catch (Exception e) { + // ignored. + } + })); + + GLOBAL_LISTENERS.forEach(logListener -> { + try { + logListener.onMessage(code, msg); + } catch (Exception e) { + // ignored. + } + }); + } + } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/DefaultSerializeClassChecker.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/DefaultSerializeClassChecker.java index 093cad8a96..9c863d717e 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/DefaultSerializeClassChecker.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/DefaultSerializeClassChecker.java @@ -159,7 +159,7 @@ public class DefaultSerializeClassChecker implements AllowClassNotifyListener { "Current mode is `WARN`, will disallow to deserialize it by default. " + "Please add it into security/serialize.allowlist or follow FAQ to configure it."; if (serializeSecurityManager.getWarnedClasses().add(className)) { - logger.error(PROTOCOL_UNTRUSTED_SERIALIZE_CLASS, "", "", msg); + logger.warn(PROTOCOL_UNTRUSTED_SERIALIZE_CLASS, "", "", msg); } throw new IllegalArgumentException(msg); @@ -180,7 +180,7 @@ public class DefaultSerializeClassChecker implements AllowClassNotifyListener { "Current mode is `WARN`, will disallow to deserialize it by default. " + "Please add it into security/serialize.allowlist or follow FAQ to configure it."; if (serializeSecurityManager.getWarnedClasses().add(className)) { - logger.error(PROTOCOL_UNTRUSTED_SERIALIZE_CLASS, "", "", msg); + logger.warn(PROTOCOL_UNTRUSTED_SERIALIZE_CLASS, "", "", msg); } throw new IllegalArgumentException(msg); @@ -189,7 +189,7 @@ public class DefaultSerializeClassChecker implements AllowClassNotifyListener { Class clazz = ClassUtils.forName(className, classLoader); if (serializeSecurityManager.getWarnedClasses().add(className)) { - logger.error(PROTOCOL_UNTRUSTED_SERIALIZE_CLASS, "", "", + logger.warn(PROTOCOL_UNTRUSTED_SERIALIZE_CLASS, "", "", "[Serialization Security] Serialized class " + className + " is not in allow list. " + "Current mode is `WARN`, will allow to deserialize it by default. " + "Dubbo will set to `STRICT` mode by default in the future. " + diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/StringUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/StringUtils.java index 31372ca8a3..34fa8b5403 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/StringUtils.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/StringUtils.java @@ -856,6 +856,23 @@ public final class StringUtils { return sb.toString(); } + public static String join(final Object[] array, final char delimiter, final int startIndex, final int endIndex) { + if (ArrayUtils.isEmpty(array)) { + return EMPTY_STRING; + } + if (endIndex - startIndex <= 0) { + return EMPTY_STRING; + } + StringBuilder sb = new StringBuilder(); + for (int i = startIndex; i < endIndex; i++) { + if (i > 0) { + sb.append(delimiter); + } + sb.append(array[i]); + } + return sb.toString(); + } + /** * parse key-value pair. * diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/MetricsConfig.java b/dubbo-common/src/main/java/org/apache/dubbo/config/MetricsConfig.java index 067833b2b0..37cd727f4c 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/config/MetricsConfig.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/config/MetricsConfig.java @@ -61,6 +61,11 @@ public class MetricsConfig extends AbstractConfig { */ private Boolean exportMetricsService; + /** + * Enable netty metrics. + */ + private Boolean enableNetty; + /** * @deprecated After metrics config is refactored. * This parameter should no longer use and will be deleted in the future. @@ -223,4 +228,12 @@ public class MetricsConfig extends AbstractConfig { public void setEnableRpc(Boolean enableRpc) { this.enableRpc = enableRpc; } + + public Boolean getEnableNetty() { + return enableNetty; + } + + public void setEnableNetty(Boolean enableNetty) { + this.enableNetty = enableNetty; + } } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ModelConstants.java b/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ModelConstants.java index 447c798c5f..c25031da51 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ModelConstants.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ModelConstants.java @@ -24,4 +24,6 @@ public interface ModelConstants { * Keep Dubbo running when spring is stopped */ String KEEP_RUNNING_ON_SPRING_CLOSED = "keepRunningOnSpringClosed"; + + String KEEP_RUNNING_ON_SPRING_CLOSED_KEY = "dubbo.module.keepRunningOnSpringClosed"; } diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/StringUtilsTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/StringUtilsTest.java index 5d46c2ad18..2ac7ccc411 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/StringUtilsTest.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/StringUtilsTest.java @@ -227,6 +227,10 @@ class StringUtilsTest { assertEquals(StringUtils.join(s), "123"); assertEquals(StringUtils.join(s, ','), "1,2,3"); assertEquals(StringUtils.join(s, ","), "1,2,3"); + assertEquals(StringUtils.join(s, ',', 0, 1), "1"); + assertEquals(StringUtils.join(s, ',', 0, 2), "1,2"); + assertEquals(StringUtils.join(s, ',', 0, 3), "1,2,3"); + assertEquals("", StringUtils.join(s, ',', 2, 0), "1,2"); } @Test @@ -502,4 +506,4 @@ class StringUtilsTest { assertTrue(startsWithIgnoreCase("Dubbo.application.name", "dubbo.application.")); } -} \ No newline at end of file +} diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java index 73dec83e01..c11f9c3f62 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java @@ -463,7 +463,7 @@ public class ReferenceConfig extends ReferenceConfigBase { if (logger.isInfoEnabled()) { logger.info("Referred dubbo service: [" + referenceParameters.get(INTERFACE_KEY) + "]." + - (Boolean.parseBoolean(referenceParameters.get(GENERIC_KEY)) ? + (ProtocolUtils.isGeneric(referenceParameters.get(GENERIC_KEY)) ? " it's GenericService reference" : " it's not GenericService reference")); } diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java index 8061f7c28d..3e6b767b52 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java @@ -38,8 +38,6 @@ import org.apache.dubbo.config.invoker.DelegateProviderMetaDataInvoker; import org.apache.dubbo.config.support.Parameter; import org.apache.dubbo.config.utils.ConfigValidationUtils; import org.apache.dubbo.metadata.ServiceNameMapping; -import org.apache.dubbo.metrics.event.MetricsEventBus; -import org.apache.dubbo.metrics.registry.event.RegistryEvent; import org.apache.dubbo.registry.client.metadata.MetadataUtils; import org.apache.dubbo.rpc.Exporter; import org.apache.dubbo.rpc.Invoker; @@ -193,7 +191,7 @@ public class ServiceConfig extends ServiceConfigBase { } @Override - public void unexport() { + public synchronized void unexport() { if (!exported) { return; } @@ -517,21 +515,17 @@ public class ServiceConfig extends ServiceConfigBase { List registryURLs = !Boolean.FALSE.equals(isRegister()) ? ConfigValidationUtils.loadRegistries(this, true) : Collections.emptyList(); - MetricsEventBus.post(RegistryEvent.toRsEvent(getApplicationModel(), getUniqueServiceName(), protocols.size() * registryURLs.size()), () -> { - for (ProtocolConfig protocolConfig : protocols) { - String pathKey = URL.buildKey(getContextPath(protocolConfig) - .map(p -> p + "/" + path) - .orElse(path), group, version); - // stub service will use generated service name - if (!serverService) { - // In case user specified path, registerImmediately service one more time to map it to path. - repository.registerService(pathKey, interfaceClass); - } - doExportUrlsFor1Protocol(protocolConfig, registryURLs, registerType); - } - return null; + for (ProtocolConfig protocolConfig : protocols) { + String pathKey = URL.buildKey(getContextPath(protocolConfig) + .map(p -> p + "/" + path) + .orElse(path), group, version); + // stub service will use generated service name + if (!serverService) { + // In case user specified path, register service one more time to map it to path. + repository.registerService(pathKey, interfaceClass); } - ); + doExportUrlsFor1Protocol(protocolConfig, registryURLs, registerType); + } providerModel.setServiceUrls(urls); } diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/DefaultApplicationDeployer.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/DefaultApplicationDeployer.java index 6302ee6eb3..d4a3da0cee 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/DefaultApplicationDeployer.java +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/DefaultApplicationDeployer.java @@ -55,7 +55,6 @@ import org.apache.dubbo.metadata.report.MetadataReportInstance; import org.apache.dubbo.metrics.collector.DefaultMetricsCollector; import org.apache.dubbo.metrics.config.event.ConfigCenterEvent; import org.apache.dubbo.metrics.event.MetricsEventBus; -import org.apache.dubbo.metrics.registry.event.RegistryEvent; import org.apache.dubbo.metrics.report.DefaultMetricsReporterFactory; import org.apache.dubbo.metrics.report.MetricsReporter; import org.apache.dubbo.metrics.report.MetricsReporterFactory; @@ -914,16 +913,12 @@ public class DefaultApplicationDeployer extends AbstractDeployer { + ServiceInstanceMetadataUtils.registerMetadataAndInstance(applicationModel); - return null; - } - ); + } catch (Exception e) { logger.error(CONFIG_REGISTER_INSTANCE_ERROR, "configuration server disconnected", "", "Register instance error.", e); } - if (registered) { // scheduled task for updating Metadata and ServiceInstance asyncMetadataFuture = frameworkExecutorRepository.getSharedScheduledExecutor().scheduleWithFixedDelay(() -> { diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/DefaultModuleDeployer.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/DefaultModuleDeployer.java index 9ddd1646da..5694c890dc 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/DefaultModuleDeployer.java +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/DefaultModuleDeployer.java @@ -335,6 +335,13 @@ public class DefaultModuleDeployer extends AbstractDeployer impleme private void onModuleFailed(String msg, Throwable ex) { try { + try { + // un-export all services if start failure + unexportServices(); + } catch (Throwable t) { + logger.info("Failed to un-export services after module failed.", t); + } + setFailed(ex); logger.error(CONFIG_FAILED_START_MODEL, "", "", "Model start failed: " + msg, ex); applicationDeployer.notifyModuleChanged(moduleModel, DeployState.FAILED); @@ -450,8 +457,8 @@ public class DefaultModuleDeployer extends AbstractDeployer impleme try { configManager.removeConfig(sc); sc.unexport(); - } catch (Exception ignored) { - // ignored + } catch (Throwable t) { + logger.info("Failed to un-export service. Service Key: " + sc.getUniqueServiceName(), t); } }); exportedServices.clear(); diff --git a/dubbo-config/dubbo-config-spring/pom.xml b/dubbo-config/dubbo-config-spring/pom.xml index c335d50632..9526d791e7 100644 --- a/dubbo-config/dubbo-config-spring/pom.xml +++ b/dubbo-config/dubbo-config-spring/pom.xml @@ -73,7 +73,7 @@ org.aspectj aspectjweaver - 1.9.19 + 1.9.20 test diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboDeployApplicationListener.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboDeployApplicationListener.java index 2f61fa22d6..73c07c5b29 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboDeployApplicationListener.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/DubboDeployApplicationListener.java @@ -16,6 +16,7 @@ */ package org.apache.dubbo.config.spring.context; +import org.apache.dubbo.common.config.ConfigurationUtils; import org.apache.dubbo.common.deploy.DeployListenerAdapter; import org.apache.dubbo.common.deploy.DeployState; import org.apache.dubbo.common.deploy.ModuleDeployer; @@ -169,6 +170,9 @@ public class DubboDeployApplicationListener implements ApplicationListener entry : contextMap.entrySet()) { DubboSpringInitContext initContext = entry.getValue(); if (initContext.getApplicationContext() == springContext || - initContext.getBeanFactory() == springContext.getAutowireCapableBeanFactory() || - initContext.getRegistry() == springContext.getAutowireCapableBeanFactory() + initContext.getBeanFactory() == autowireCapableBeanFactory || + initContext.getRegistry() == autowireCapableBeanFactory ) { DubboSpringInitContext context = contextMap.remove(entry.getKey()); logger.info("Unbind " + safeGetModelDesc(context.getModuleModel()) + " from spring container: " + @@ -89,8 +91,7 @@ public class DubboSpringInitializer { } static DubboSpringInitContext findBySpringContext(ApplicationContext applicationContext) { - for (Map.Entry entry : contextMap.entrySet()) { - DubboSpringInitContext initContext = entry.getValue(); + for (DubboSpringInitContext initContext : contextMap.values()) { if (initContext.getApplicationContext() == applicationContext) { return initContext; } @@ -113,25 +114,26 @@ public class DubboSpringInitializer { if (findContextForApplication(ApplicationModel.defaultModel()) == null) { // first spring context use default application instance applicationModel = ApplicationModel.defaultModel(); - logger.info("Use default application: " + safeGetModelDesc(applicationModel)); + logger.info("Use default application: " + applicationModel.getDesc()); } else { // create a new application instance for later spring context applicationModel = FrameworkModel.defaultModel().newApplication(); - logger.info("Create new application: " + safeGetModelDesc(applicationModel)); + logger.info("Create new application: " + applicationModel.getDesc()); } // init ModuleModel moduleModel = applicationModel.getDefaultModule(); context.setModuleModel(moduleModel); - logger.info("Use default module model of target application: " + safeGetModelDesc(moduleModel)); + logger.info("Use default module model of target application: " + moduleModel.getDesc()); } else { - logger.info("Use module model from customizer: " + safeGetModelDesc(moduleModel)); + logger.info("Use module model from customizer: " + moduleModel.getDesc()); } - logger.info("Bind " + safeGetModelDesc(moduleModel) + " to spring container: " + ObjectUtils.identityToString(registry)); + logger.info("Bind " + moduleModel.getDesc() + " to spring container: " + ObjectUtils.identityToString(registry)); // set module attributes - if (context.getModuleAttributes().size() > 0) { - context.getModuleModel().getAttributes().putAll(context.getModuleAttributes()); + Map moduleAttributes = context.getModuleAttributes(); + if (moduleAttributes.size() > 0) { + moduleModel.getAttributes().putAll(moduleAttributes); } // bind dubbo initialization context to spring context @@ -207,7 +209,6 @@ public class DubboSpringInitializer { customizer.customize(context); } customizerHolder.clearCustomizers(); - } } diff --git a/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo.xsd b/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo.xsd index a2bcbee0bd..ea3e643132 100644 --- a/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo.xsd +++ b/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo.xsd @@ -1092,6 +1092,12 @@ + + + + + + diff --git a/dubbo-demo/dubbo-demo-native/dubbo-demo-native-consumer/pom.xml b/dubbo-demo/dubbo-demo-native/dubbo-demo-native-consumer/pom.xml index ef128333bd..22708014b8 100644 --- a/dubbo-demo/dubbo-demo-native/dubbo-demo-native-consumer/pom.xml +++ b/dubbo-demo/dubbo-demo-native/dubbo-demo-native-consumer/pom.xml @@ -224,7 +224,7 @@ org.graalvm.buildtools native-maven-plugin - 0.9.23 + 0.9.24 ${project.build.outputDirectory} diff --git a/dubbo-demo/dubbo-demo-native/dubbo-demo-native-provider/pom.xml b/dubbo-demo/dubbo-demo-native/dubbo-demo-native-provider/pom.xml index 1f2fc06b5b..0ad39765b5 100644 --- a/dubbo-demo/dubbo-demo-native/dubbo-demo-native-provider/pom.xml +++ b/dubbo-demo/dubbo-demo-native/dubbo-demo-native-provider/pom.xml @@ -222,7 +222,7 @@ org.graalvm.buildtools native-maven-plugin - 0.9.23 + 0.9.24 ${project.build.outputDirectory} diff --git a/dubbo-demo/dubbo-demo-spring-boot/pom.xml b/dubbo-demo/dubbo-demo-spring-boot/pom.xml index 9170101e54..d1d011fd79 100644 --- a/dubbo-demo/dubbo-demo-spring-boot/pom.xml +++ b/dubbo-demo/dubbo-demo-spring-boot/pom.xml @@ -38,7 +38,7 @@ true 2.7.14 2.7.14 - 1.11.2 + 1.11.3 diff --git a/dubbo-dependencies-bom/pom.xml b/dubbo-dependencies-bom/pom.xml index 57e598fcdd..37cec6bf9e 100644 --- a/dubbo-dependencies-bom/pom.xml +++ b/dubbo-dependencies-bom/pom.xml @@ -94,7 +94,7 @@ 5.3.25 5.8.5 3.29.2-GA - 1.14.5 + 1.14.6 3.2.10.Final 4.1.95.Final 2.2.1 @@ -102,7 +102,7 @@ 4.5.14 4.4.16 1.2.83 - 2.0.35 + 2.0.39 3.4.14 4.3.0 2.12.0 @@ -114,7 +114,7 @@ 3.5.5 0.18.1 4.0.66 - 3.23.4 + 3.24.1 1.3.2 3.1.0 9.4.51.v20230217 @@ -129,18 +129,18 @@ 2.57 1.11.1 2.1.0 - 2.0 + 2.1 3.12.0 1.8.0 0.1.35 - 1.11.2 + 1.11.3 1.26.0 2.16.4 - 1.1.3 + 1.1.4 3.3 0.16.0 1.0.4 - 3.5.8 + 3.5.9 2.2.21 3.14.9 @@ -152,7 +152,7 @@ 2.2.4 1.8.6 1.6.1 - 1.56.1 + 1.57.2 0.8.1 1.2.2 @@ -170,7 +170,7 @@ 1.10.18 - 6.6.2 + 6.8.1 1.0.11 diff --git a/dubbo-distribution/dubbo-all/pom.xml b/dubbo-distribution/dubbo-all/pom.xml index 3011ed31a8..d0ff531c7e 100644 --- a/dubbo-distribution/dubbo-all/pom.xml +++ b/dubbo-distribution/dubbo-all/pom.xml @@ -232,6 +232,13 @@ compile true + + org.apache.dubbo + dubbo-metrics-netty + ${project.version} + compile + true + @@ -695,6 +702,7 @@ org.apache.dubbo:dubbo-metrics-registry org.apache.dubbo:dubbo-metrics-metadata org.apache.dubbo:dubbo-metrics-config-center + org.apache.dubbo:dubbo-metrics-netty org.apache.dubbo:dubbo-metrics-prometheus org.apache.dubbo:dubbo-tracing org.apache.dubbo:dubbo-monitor-api diff --git a/dubbo-distribution/dubbo-bom/pom.xml b/dubbo-distribution/dubbo-bom/pom.xml index 1ce62e76e6..9757c56352 100644 --- a/dubbo-distribution/dubbo-bom/pom.xml +++ b/dubbo-distribution/dubbo-bom/pom.xml @@ -276,6 +276,11 @@ dubbo-metrics-config-center ${project.version} + + org.apache.dubbo + dubbo-metrics-netty + ${project.version} + diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/identifier/MetadataIdentifier.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/identifier/MetadataIdentifier.java index 9ce637f2ad..1e5b8919f0 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/identifier/MetadataIdentifier.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/identifier/MetadataIdentifier.java @@ -101,4 +101,14 @@ public class MetadataIdentifier extends BaseServiceMetadataIdentifier implements return serviceInterface != null ? URL.buildKey(serviceInterface, getGroup(), getVersion()) : null; } + @Override + public String toString() { + return "MetadataIdentifier{" + + "application='" + application + '\'' + + ", serviceInterface='" + serviceInterface + '\'' + + ", version='" + version + '\'' + + ", group='" + group + '\'' + + ", side='" + side + '\'' + + '}'; + } } diff --git a/dubbo-metadata/dubbo-metadata-rest/src/main/java/org/apache/dubbo/metadata/rest/AbstractServiceRestMetadataResolver.java b/dubbo-metadata/dubbo-metadata-rest/src/main/java/org/apache/dubbo/metadata/rest/AbstractServiceRestMetadataResolver.java index 7efb70a145..d0062f74cd 100644 --- a/dubbo-metadata/dubbo-metadata-rest/src/main/java/org/apache/dubbo/metadata/rest/AbstractServiceRestMetadataResolver.java +++ b/dubbo-metadata/dubbo-metadata-rest/src/main/java/org/apache/dubbo/metadata/rest/AbstractServiceRestMetadataResolver.java @@ -40,6 +40,7 @@ import static java.util.Collections.emptyList; import static java.util.Collections.sort; import static java.util.Collections.unmodifiableMap; import static org.apache.dubbo.common.function.ThrowableFunction.execute; +import static org.apache.dubbo.common.utils.AnnotationUtils.isAnnotationPresent; import static org.apache.dubbo.common.utils.AnnotationUtils.isAnyAnnotationPresent; import static org.apache.dubbo.common.utils.ClassUtils.forName; import static org.apache.dubbo.common.utils.ClassUtils.getAllInterfaces; @@ -197,8 +198,9 @@ public abstract class AbstractServiceRestMetadataResolver implements ServiceRest for (Method serviceMethod : serviceMethods) { if (overrides(serviceMethod, declaredServiceMethod)) { serviceMethodsMap.put(serviceMethod, declaredServiceMethod); - // once method match ,break for decrease loop times - break; + // override method count > 1 +// // once method match ,break for decrease loop times +// break; } } } @@ -421,4 +423,16 @@ public abstract class AbstractServiceRestMetadataResolver implements ServiceRest return supportedExtensionInstances; } + + public static boolean isServiceMethodAnnotationPresent(Class serviceImpl, String annotationClass) { + List allMethods = getAllMethods(serviceImpl, excludedDeclaredClass(Object.class)); + + for (Method method : allMethods) { + if (isAnnotationPresent(method, annotationClass)) { + return true; + } + } + + return false; + } } diff --git a/dubbo-metadata/dubbo-metadata-rest/src/main/java/org/apache/dubbo/metadata/rest/PathMatcher.java b/dubbo-metadata/dubbo-metadata-rest/src/main/java/org/apache/dubbo/metadata/rest/PathMatcher.java index 7abefcf71e..e08e0733b2 100644 --- a/dubbo-metadata/dubbo-metadata-rest/src/main/java/org/apache/dubbo/metadata/rest/PathMatcher.java +++ b/dubbo-metadata/dubbo-metadata-rest/src/main/java/org/apache/dubbo/metadata/rest/PathMatcher.java @@ -110,13 +110,17 @@ public class PathMatcher { } public static PathMatcher getInvokeCreatePathMatcher(String path, String version, String group, Integer port, String method) { - return new PathMatcher(path, version, group, port, method).noNeedHttpMethodCompare(); + return new PathMatcher(path, version, group, port, method).compareHttpMethod(false); } public static PathMatcher getInvokeCreatePathMatcher(Method serviceMethod) { return new PathMatcher(serviceMethod).setNeedCompareServiceMethod(true); } + public static PathMatcher convertPathMatcher(PathMatcher pathMatcher) { + return getInvokeCreatePathMatcher(pathMatcher.path, pathMatcher.version, pathMatcher.group, pathMatcher.port, pathMatcher.httpMethod); + } + public boolean hasPathVariable() { return hasPathVariable; } @@ -134,8 +138,8 @@ public class PathMatcher { return this; } - private PathMatcher noNeedHttpMethodCompare() { - this.needCompareHttpMethod = false; + public PathMatcher compareHttpMethod(boolean needCompareHttpMethod) { + this.needCompareHttpMethod = needCompareHttpMethod; return this; } @@ -176,7 +180,7 @@ public class PathMatcher { * @return */ private boolean httpMethodMatch(PathMatcher that) { - return !that.needCompareHttpMethod || !this.needCompareHttpMethod ? true: Objects.equals(this.httpMethod, that.httpMethod); + return !that.needCompareHttpMethod || !this.needCompareHttpMethod ? true : Objects.equals(this.httpMethod, that.httpMethod); } private boolean serviceMethodEqual(PathMatcher thatPathMatcher, PathMatcher thisPathMatcher) { diff --git a/dubbo-metadata/dubbo-metadata-rest/src/main/java/org/apache/dubbo/metadata/rest/jaxrs/JAXRSServiceRestMetadataResolver.java b/dubbo-metadata/dubbo-metadata-rest/src/main/java/org/apache/dubbo/metadata/rest/jaxrs/JAXRSServiceRestMetadataResolver.java index fc74647232..0acd60b7db 100644 --- a/dubbo-metadata/dubbo-metadata-rest/src/main/java/org/apache/dubbo/metadata/rest/jaxrs/JAXRSServiceRestMetadataResolver.java +++ b/dubbo-metadata/dubbo-metadata-rest/src/main/java/org/apache/dubbo/metadata/rest/jaxrs/JAXRSServiceRestMetadataResolver.java @@ -49,7 +49,9 @@ public class JAXRSServiceRestMetadataResolver extends AbstractServiceRestMetadat @Override protected boolean supports0(Class serviceType) { - return isAnnotationPresent(serviceType, PATH_ANNOTATION_CLASS_NAME); + return isAnnotationPresent(serviceType, PATH_ANNOTATION_CLASS_NAME) + // method @Path + || isServiceMethodAnnotationPresent(serviceType,PATH_ANNOTATION_CLASS_NAME); } @Override diff --git a/dubbo-metadata/dubbo-metadata-rest/src/main/java/org/apache/dubbo/metadata/rest/springmvc/SpringMvcServiceRestMetadataResolver.java b/dubbo-metadata/dubbo-metadata-rest/src/main/java/org/apache/dubbo/metadata/rest/springmvc/SpringMvcServiceRestMetadataResolver.java index da8035915c..84a21aa76b 100644 --- a/dubbo-metadata/dubbo-metadata-rest/src/main/java/org/apache/dubbo/metadata/rest/springmvc/SpringMvcServiceRestMetadataResolver.java +++ b/dubbo-metadata/dubbo-metadata-rest/src/main/java/org/apache/dubbo/metadata/rest/springmvc/SpringMvcServiceRestMetadataResolver.java @@ -41,6 +41,7 @@ import static org.apache.dubbo.metadata.rest.RestMetadataConstants.SPRING_MVC.AN import static org.apache.dubbo.metadata.rest.RestMetadataConstants.SPRING_MVC.CONTROLLER_ANNOTATION_CLASS; import static org.apache.dubbo.metadata.rest.RestMetadataConstants.SPRING_MVC.FEIGN_CLIENT_CLASS; import static org.apache.dubbo.metadata.rest.RestMetadataConstants.SPRING_MVC.REQUEST_MAPPING_ANNOTATION_CLASS; +import static org.apache.dubbo.metadata.rest.RestMetadataConstants.SPRING_MVC.REQUEST_MAPPING_ANNOTATION_CLASS_NAME; /** * {@link ServiceRestMetadataResolver} @@ -61,7 +62,8 @@ public class SpringMvcServiceRestMetadataResolver extends AbstractServiceRestMet // class @Controller or @RequestMapping return isAnnotationPresent(serviceType, CONTROLLER_ANNOTATION_CLASS) || isAnnotationPresent(serviceType, FEIGN_CLIENT_CLASS) - || isAnnotationPresent(serviceType, REQUEST_MAPPING_ANNOTATION_CLASS); + || isAnnotationPresent(serviceType, REQUEST_MAPPING_ANNOTATION_CLASS)// method @RequestMapping + || isServiceMethodAnnotationPresent(serviceType, REQUEST_MAPPING_ANNOTATION_CLASS_NAME); } @Override diff --git a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/MetricsConstants.java b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/MetricsConstants.java index a99e4c6657..b03a63dddc 100644 --- a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/MetricsConstants.java +++ b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/MetricsConstants.java @@ -22,8 +22,8 @@ public interface MetricsConstants { String INVOCATION = "metric_filter_invocation"; String METHOD_METRICS = "metric_filter_method_metrics"; String INVOCATION_METRICS_COUNTER = "metric_filter_invocation_counter"; - String INVOCATION_SIDE = "metric_filter_side"; + String INVOCATION_REQUEST_ERROR = "metric_request_error"; String ATTACHMENT_KEY_SERVICE = "serviceKey"; String ATTACHMENT_KEY_SIZE = "size"; @@ -32,4 +32,6 @@ public interface MetricsConstants { int SELF_INCREMENT_SIZE = 1; + String NETTY_METRICS_MAP = "nettyMetricsMap"; + } diff --git a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/aggregate/DubboMergingDigest.java b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/aggregate/DubboMergingDigest.java index 24bdfe1c74..b4bfe34b74 100644 --- a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/aggregate/DubboMergingDigest.java +++ b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/aggregate/DubboMergingDigest.java @@ -18,11 +18,12 @@ package org.apache.dubbo.metrics.aggregate; +import org.apache.dubbo.metrics.exception.MetricsNeverHappenException; + import com.tdunning.math.stats.Centroid; import com.tdunning.math.stats.ScaleFunction; import com.tdunning.math.stats.Sort; import com.tdunning.math.stats.TDigest; -import org.apache.dubbo.metrics.exception.MetricsNeverHappenException; import java.nio.ByteBuffer; import java.util.AbstractCollection; @@ -285,16 +286,17 @@ public class DubboMergingDigest extends DubboAbstractTDigest { throw new IllegalArgumentException("Cannot add NaN to t-digest"); } + int where; synchronized (this) { // There is a small probability of entering here if (tempUsed.get() >= tempWeight.length - lastUsedCell.get() - 1) { mergeNewValues(); } + where = tempUsed.getAndIncrement(); + tempWeight[where] = w; + tempMean[where] = x; + unmergedWeight.addAndGet(w); } - int where = tempUsed.getAndIncrement(); - tempWeight[where] = w; - tempMean[where] = x; - unmergedWeight.addAndGet(w); if (x < min) { min = x; } diff --git a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/collector/CombMetricsCollector.java b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/collector/CombMetricsCollector.java index 81ae03eb40..02657a293f 100644 --- a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/collector/CombMetricsCollector.java +++ b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/collector/CombMetricsCollector.java @@ -34,7 +34,7 @@ import static org.apache.dubbo.metrics.MetricsConstants.SELF_INCREMENT_SIZE; public abstract class CombMetricsCollector extends AbstractMetricsListener implements ApplicationMetricsCollector, ServiceMetricsCollector, MethodMetricsCollector { - private final BaseStatComposite stats; + protected final BaseStatComposite stats; private MetricsEventMulticaster eventMulticaster; @@ -80,6 +80,10 @@ public abstract class CombMetricsCollector extends A stats.calcMethodKeyRt(invocation, registryOpType, responseTime); } + public void setAppNum(MetricsKey metricsKey,Long num) { + stats.setAppKey(metricsKey, num); + } + @Override public void increment(MethodMetric methodMetric, MetricsKeyWrapper wrapper, int size) { this.stats.incrementMethodKey(wrapper, methodMetric, size); @@ -108,5 +112,9 @@ public abstract class CombMetricsCollector extends A public void onEventError(TimeCounterEvent event) { eventMulticaster.publishErrorEvent(event); } + + protected BaseStatComposite getStats() { + return stats; + } } diff --git a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/data/ApplicationStatComposite.java b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/data/ApplicationStatComposite.java index 47a432e480..0d539095a6 100644 --- a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/data/ApplicationStatComposite.java +++ b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/data/ApplicationStatComposite.java @@ -60,6 +60,12 @@ public class ApplicationStatComposite extends AbstractMetricsExport { applicationNumStats.get(metricsKey).getAndAdd(size); } + public void setAppKey(MetricsKey metricsKey, Long num){ + if (!applicationNumStats.containsKey(metricsKey)) { + return; + } + applicationNumStats.get(metricsKey).set(num); + } public List export(MetricsCategory category) { List list = new ArrayList<>(); diff --git a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/data/BaseStatComposite.java b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/data/BaseStatComposite.java index c7ddd9dee0..75e5ed4904 100644 --- a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/data/BaseStatComposite.java +++ b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/data/BaseStatComposite.java @@ -18,8 +18,10 @@ package org.apache.dubbo.metrics.data; import org.apache.dubbo.metrics.collector.MetricsCollector; +import org.apache.dubbo.metrics.model.ApplicationMetric; import org.apache.dubbo.metrics.model.MethodMetric; import org.apache.dubbo.metrics.model.MetricsCategory; +import org.apache.dubbo.metrics.model.ServiceKeyMetric; import org.apache.dubbo.metrics.model.key.MetricsKey; import org.apache.dubbo.metrics.model.key.MetricsKeyWrapper; import org.apache.dubbo.metrics.model.sample.MetricSample; @@ -29,6 +31,7 @@ import org.apache.dubbo.rpc.model.ApplicationModel; import java.util.ArrayList; import java.util.List; +import java.util.Map; /** @@ -70,11 +73,11 @@ public abstract class BaseStatComposite implements MetricsExport { } public void calcApplicationRt(String registryOpType, Long responseTime) { - rtStatComposite.calcApplicationRt(registryOpType, responseTime); + rtStatComposite.calcServiceKeyRt(registryOpType, responseTime, new ApplicationMetric(rtStatComposite.getApplicationModel())); } public void calcServiceKeyRt(String serviceKey, String registryOpType, Long responseTime) { - rtStatComposite.calcServiceKeyRt(serviceKey, registryOpType, responseTime); + rtStatComposite.calcServiceKeyRt(registryOpType, responseTime, new ServiceKeyMetric(rtStatComposite.getApplicationModel(), serviceKey)); } public void calcServiceKeyRt(Invocation invocation, String registryOpType, Long responseTime) { @@ -89,6 +92,10 @@ public abstract class BaseStatComposite implements MetricsExport { serviceStatComposite.setServiceKey(metricsKey, serviceKey, num); } + public void setServiceKey(MetricsKeyWrapper metricsKey, String serviceKey, int num, Map extra) { + serviceStatComposite.setExtraServiceKey(metricsKey, serviceKey, num, extra); + } + public void incrementApp(MetricsKey metricsKey, int size) { applicationStatComposite.incrementSize(metricsKey, size); } @@ -97,6 +104,10 @@ public abstract class BaseStatComposite implements MetricsExport { serviceStatComposite.incrementServiceKey(metricsKeyWrapper, attServiceKey, size); } + public void incrementServiceKey(MetricsKeyWrapper metricsKeyWrapper, String attServiceKey, Map extra, int size) { + serviceStatComposite.incrementExtraServiceKey(metricsKeyWrapper, attServiceKey, extra, size); + } + public void incrementMethodKey(MetricsKeyWrapper metricsKeyWrapper, MethodMetric methodMetric, int size) { methodStatComposite.incrementMethodKey(metricsKeyWrapper, methodMetric, size); } @@ -118,4 +129,8 @@ public abstract class BaseStatComposite implements MetricsExport { public RtStatComposite getRtStatComposite() { return rtStatComposite; } + + public void setAppKey(MetricsKey metricsKey, Long num) { + applicationStatComposite.setAppKey(metricsKey, num); + } } diff --git a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/data/RtStatComposite.java b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/data/RtStatComposite.java index 5a3d96c9b3..e6d0bae6e7 100644 --- a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/data/RtStatComposite.java +++ b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/data/RtStatComposite.java @@ -17,7 +17,6 @@ package org.apache.dubbo.metrics.data; -import org.apache.dubbo.metrics.model.ApplicationMetric; import org.apache.dubbo.metrics.model.MethodMetric; import org.apache.dubbo.metrics.model.Metric; import org.apache.dubbo.metrics.model.MetricsCategory; @@ -89,20 +88,7 @@ public class RtStatComposite extends AbstractMetricsExport { return singleRtStats; } - public void calcApplicationRt(String registryOpType, Long responseTime) { - ApplicationMetric key = new ApplicationMetric(getApplicationModel()); - for (LongContainer container : rtStats.get(registryOpType)) { - Number current = (Number) container.get(key); - if (current == null) { - container.putIfAbsent(key, container.getInitFunc().apply(key)); - current = (Number) container.get(key); - } - container.getConsumerFunc().accept(responseTime, current); - } - } - - public void calcServiceKeyRt(String serviceKey, String registryOpType, Long responseTime) { - ServiceKeyMetric key = new ServiceKeyMetric(getApplicationModel(), serviceKey); + public void calcServiceKeyRt(String registryOpType, Long responseTime, Metric key) { for (LongContainer container : rtStats.get(registryOpType)) { Number current = (Number) container.get(key); if (current == null) { diff --git a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/data/ServiceStatComposite.java b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/data/ServiceStatComposite.java index 3399541c42..afedd71641 100644 --- a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/data/ServiceStatComposite.java +++ b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/data/ServiceStatComposite.java @@ -53,21 +53,37 @@ public class ServiceStatComposite extends AbstractMetricsExport { } public void incrementServiceKey(MetricsKeyWrapper wrapper, String serviceKey, int size) { + incrementExtraServiceKey(wrapper, serviceKey, null, size); + } + + public void incrementExtraServiceKey(MetricsKeyWrapper wrapper, String serviceKey, Map extra, int size) { if (!serviceWrapperNumStats.containsKey(wrapper)) { return; } - serviceWrapperNumStats.get(wrapper).computeIfAbsent(new ServiceKeyMetric(getApplicationModel(), serviceKey), k -> new AtomicLong(0L)).getAndAdd(size); + ServiceKeyMetric serviceKeyMetric = new ServiceKeyMetric(getApplicationModel(), serviceKey); + if (extra != null) { + serviceKeyMetric.setExtraInfo(extra); + } + serviceWrapperNumStats.get(wrapper).computeIfAbsent(serviceKeyMetric, k -> new AtomicLong(0L)).getAndAdd(size); // MetricsSupport.fillZero(serviceWrapperNumStats); } public void setServiceKey(MetricsKeyWrapper wrapper, String serviceKey, int num) { + setExtraServiceKey(wrapper, serviceKey, num, null); + } + + public void setExtraServiceKey(MetricsKeyWrapper wrapper, String serviceKey, int num, Map extra) { if (!serviceWrapperNumStats.containsKey(wrapper)) { return; } - serviceWrapperNumStats.get(wrapper).computeIfAbsent(new ServiceKeyMetric(getApplicationModel(), serviceKey), k -> new AtomicLong(0L)).set(num); -// MetricsSupport.fillZero(serviceWrapperNumStats); + ServiceKeyMetric serviceKeyMetric = new ServiceKeyMetric(getApplicationModel(), serviceKey); + if (extra != null) { + serviceKeyMetric.setExtraInfo(extra); + } + serviceWrapperNumStats.get(wrapper).computeIfAbsent(serviceKeyMetric, k -> new AtomicLong(0L)).set(num); } + @Override public List export(MetricsCategory category) { List list = new ArrayList<>(); for (MetricsKeyWrapper wrapper : serviceWrapperNumStats.keySet()) { diff --git a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/event/MetricsEvent.java b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/event/MetricsEvent.java index 4203d81a63..3b22dfa818 100644 --- a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/event/MetricsEvent.java +++ b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/event/MetricsEvent.java @@ -23,6 +23,7 @@ import org.apache.dubbo.metrics.model.MethodMetric; import org.apache.dubbo.metrics.model.key.TypeWrapper; import org.apache.dubbo.rpc.model.ApplicationModel; +import java.util.Collections; import java.util.IdentityHashMap; import java.util.Map; @@ -40,7 +41,7 @@ public abstract class MetricsEvent { private final String appName; private final MetricsDispatcher metricsDispatcher; - private final Map attachment = new IdentityHashMap<>(8); + private final Map attachments = new IdentityHashMap<>(8); public MetricsEvent(ApplicationModel source, TypeWrapper typeWrapper) { this(source, null, null, typeWrapper); @@ -82,11 +83,19 @@ public abstract class MetricsEvent { if (key == null) { throw new MetricsNeverHappenException("Attachment key is null"); } - return (T) attachment.get(key); + return (T) attachments.get(key); + } + + public Map getAttachments() { + return Collections.unmodifiableMap(attachments); } public void putAttachment(String key, Object value) { - attachment.put(key, value); + attachments.put(key, value); + } + + public void putAttachments(Map attachments) { + this.attachments.putAll(attachments); } public void setAvailable(boolean available) { diff --git a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/event/MetricsEventBus.java b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/event/MetricsEventBus.java index 6c514bafda..74ef55e4c7 100644 --- a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/event/MetricsEventBus.java +++ b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/event/MetricsEventBus.java @@ -17,15 +17,22 @@ package org.apache.dubbo.metrics.event; +import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; +import org.apache.dubbo.common.logger.LoggerFactory; + import java.util.Optional; import java.util.function.Function; import java.util.function.Supplier; +import static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_METRICS_COLLECTOR_EXCEPTION; + /** * Dispatches events to listeners, and provides ways for listeners to register themselves. */ public class MetricsEventBus { + private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(MetricsEventBus.class); + /** * Posts an event to all registered subscribers and only once. * @@ -36,7 +43,9 @@ public class MetricsEventBus { return; } MetricsDispatcher dispatcher = event.getMetricsDispatcher(); - Optional.ofNullable(dispatcher).ifPresent(d -> d.publishEvent(event)); + Optional.ofNullable(dispatcher).ifPresent(d -> { + tryInvoke(() -> d.publishEvent(event)); + }); } /** @@ -63,27 +72,35 @@ public class MetricsEventBus { */ public static T post(MetricsEvent event, Supplier targetSupplier, Function trFunction) { T result; - before(event); + tryInvoke(() -> before(event)); if (trFunction == null) { try { result = targetSupplier.get(); } catch (Throwable e) { - error(event); + tryInvoke(() -> error(event)); throw e; } - after(event, result); + tryInvoke(() -> after(event, result)); } else { // Custom failure status result = targetSupplier.get(); if (trFunction.apply(result)) { - after(event, result); + tryInvoke(() -> after(event, result)); } else { - error(event); + tryInvoke(() -> error(event)); } } return result; } + public static void tryInvoke(Runnable runnable) { + try { + runnable.run(); + } catch (Throwable e) { + logger.warn(COMMON_METRICS_COLLECTOR_EXCEPTION, "", "", "invoke metric event error" + e.getMessage()); + } + } + /** * Applicable to the scene where execution and return are separated, * eventSaveRunner saves the event, so that the calculation rt is introverted @@ -91,20 +108,22 @@ public class MetricsEventBus { public static void before(MetricsEvent event) { MetricsDispatcher dispatcher = validate(event); if (dispatcher == null) return; - dispatcher.publishEvent(event); + tryInvoke(() -> dispatcher.publishEvent(event)); } public static void after(MetricsEvent event, Object result) { MetricsDispatcher dispatcher = validate(event); if (dispatcher == null) return; - event.customAfterPost(result); - dispatcher.publishFinishEvent((TimeCounterEvent) event); + tryInvoke(() -> { + event.customAfterPost(result); + dispatcher.publishFinishEvent((TimeCounterEvent) event); + }); } public static void error(MetricsEvent event) { MetricsDispatcher dispatcher = validate(event); if (dispatcher == null) return; - dispatcher.publishErrorEvent((TimeCounterEvent) event); + tryInvoke(() -> dispatcher.publishErrorEvent((TimeCounterEvent) event)); } private static MetricsDispatcher validate(MetricsEvent event) { diff --git a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/listener/AbstractMetricsKeyListener.java b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/listener/AbstractMetricsKeyListener.java index 04c18f5263..2ba791e0e1 100644 --- a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/listener/AbstractMetricsKeyListener.java +++ b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/listener/AbstractMetricsKeyListener.java @@ -27,6 +27,7 @@ import java.util.function.Consumer; /** * According to the event template of {@link MetricsEventBus}, * build a consistent static method for general and custom monitoring consume methods + * */ public abstract class AbstractMetricsKeyListener extends AbstractMetricsListener implements MetricsLifeListener { diff --git a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/listener/AbstractMetricsListener.java b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/listener/AbstractMetricsListener.java index 63ac20b877..0a3b9e65f9 100644 --- a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/listener/AbstractMetricsListener.java +++ b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/listener/AbstractMetricsListener.java @@ -28,7 +28,7 @@ public abstract class AbstractMetricsListener implements private final Map eventMatchCache = new ConcurrentHashMap<>(); /** - * Whether to support the general determination of event points depends on the event type + * Only interested in events of the current listener's generic parameter type */ public boolean isSupport(MetricsEvent event) { Boolean eventMatch = eventMatchCache.get(System.identityHashCode(event.getClass())); diff --git a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/listener/MetricsApplicationListener.java b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/listener/MetricsApplicationListener.java index 57d52ccb29..96891e6bb0 100644 --- a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/listener/MetricsApplicationListener.java +++ b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/listener/MetricsApplicationListener.java @@ -21,19 +21,37 @@ import org.apache.dubbo.metrics.collector.CombMetricsCollector; import org.apache.dubbo.metrics.model.key.MetricsKey; import org.apache.dubbo.metrics.model.key.MetricsPlaceValue; +/** + * App-level listener type, in most cases, can use the static method + * to produce an anonymous listener for general monitoring + */ public class MetricsApplicationListener extends AbstractMetricsKeyListener { public MetricsApplicationListener(MetricsKey metricsKey) { super(metricsKey); } - public static AbstractMetricsKeyListener onPostEventBuild(MetricsKey metricsKey, CombMetricsCollector collector) { + /** + * Perform auto-increment on the monitored key, + * Can use a custom listener instead of this generic operation + * + * @param metricsKey Monitor key + * @param collector Corresponding collector + */ + public static AbstractMetricsKeyListener onPostEventBuild(MetricsKey metricsKey, CombMetricsCollector collector) { return AbstractMetricsKeyListener.onEvent(metricsKey, - event -> collector.increment(metricsKey) + event -> collector.increment(metricsKey) ); } - public static AbstractMetricsKeyListener onFinishEventBuild(MetricsKey metricsKey, MetricsPlaceValue placeType, CombMetricsCollector collector) { + /** + * To end the monitoring normally, in addition to increasing the number of corresponding indicators, + * use the introspection method to calculate the relevant rt indicators + * + * @param metricsKey Monitor key + * @param collector Corresponding collector + */ + public static AbstractMetricsKeyListener onFinishEventBuild(MetricsKey metricsKey, MetricsPlaceValue placeType, CombMetricsCollector collector) { return AbstractMetricsKeyListener.onFinish(metricsKey, event -> { collector.increment(metricsKey); @@ -42,7 +60,10 @@ public class MetricsApplicationListener extends AbstractMetricsKeyListener { ); } - public static AbstractMetricsKeyListener onErrorEventBuild(MetricsKey metricsKey, MetricsPlaceValue placeType, CombMetricsCollector collector) { + /** + * Similar to onFinishEventBuild + */ + public static AbstractMetricsKeyListener onErrorEventBuild(MetricsKey metricsKey, MetricsPlaceValue placeType, CombMetricsCollector collector) { return AbstractMetricsKeyListener.onError(metricsKey, event -> { collector.increment(metricsKey); diff --git a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/listener/MetricsServiceListener.java b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/listener/MetricsServiceListener.java index 18989d78b4..40f27b18ca 100644 --- a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/listener/MetricsServiceListener.java +++ b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/listener/MetricsServiceListener.java @@ -23,6 +23,11 @@ import org.apache.dubbo.metrics.model.MetricsSupport; import org.apache.dubbo.metrics.model.key.MetricsKey; import org.apache.dubbo.metrics.model.key.MetricsPlaceValue; +/** + * Service-level listener type, in most cases, can use the static method + * to produce an anonymous listener for general monitoring. + * Similar to App-level + */ public class MetricsServiceListener extends AbstractMetricsKeyListener { public MetricsServiceListener(MetricsKey metricsKey) { diff --git a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/ApplicationMetric.java b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/ApplicationMetric.java index 6752139e89..20d03ca523 100644 --- a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/ApplicationMetric.java +++ b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/ApplicationMetric.java @@ -17,25 +17,14 @@ package org.apache.dubbo.metrics.model; -import org.apache.dubbo.common.Version; -import org.apache.dubbo.metrics.model.key.MetricsKey; import org.apache.dubbo.rpc.model.ApplicationModel; -import java.util.HashMap; import java.util.Map; import java.util.Objects; -import static org.apache.dubbo.common.constants.MetricsConstants.TAG_APPLICATION_NAME; -import static org.apache.dubbo.common.constants.MetricsConstants.TAG_APPLICATION_VERSION_KEY; -import static org.apache.dubbo.common.constants.MetricsConstants.TAG_HOSTNAME; -import static org.apache.dubbo.common.constants.MetricsConstants.TAG_IP; -import static org.apache.dubbo.common.utils.NetUtils.getLocalHost; -import static org.apache.dubbo.common.utils.NetUtils.getLocalHostName; - public class ApplicationMetric implements Metric { private final ApplicationModel applicationModel; - private static final String version = Version.getVersion(); - private static final String commitId = Version.getLastCommitId(); + protected Map extraInfo; public ApplicationMetric(ApplicationModel applicationModel) { this.applicationModel = applicationModel; @@ -49,27 +38,29 @@ public class ApplicationMetric implements Metric { return getApplicationModel().getApplicationName(); } - public String getData() { - return version; - } - @Override public Map getTags() { - Map tags = new HashMap<>(); - tags.put(TAG_IP, getLocalHost()); - tags.put(TAG_HOSTNAME, getLocalHostName()); - tags.put(TAG_APPLICATION_NAME, getApplicationName()); - tags.put(TAG_APPLICATION_VERSION_KEY, version); - tags.put(MetricsKey.METADATA_GIT_COMMITID_METRIC.getName(), commitId); - return tags; + return MetricsSupport.applicationTags(applicationModel, getExtraInfo()); + } + + public Map getExtraInfo() { + return extraInfo; + } + + public void setExtraInfo(Map extraInfo) { + this.extraInfo = extraInfo; } @Override public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof ApplicationMetric)) return false; + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } ApplicationMetric that = (ApplicationMetric) o; - return Objects.equals(getApplicationName(), that.applicationModel.getApplicationName()); + return getApplicationName().equals(that.applicationModel.getApplicationName()) && Objects.equals(extraInfo, that.extraInfo); } private volatile int hashCode; @@ -77,8 +68,9 @@ public class ApplicationMetric implements Metric { @Override public int hashCode() { if (hashCode == 0) { - hashCode = Objects.hash(getApplicationName()); + hashCode = Objects.hash(getApplicationName(), extraInfo); } return hashCode; } + } diff --git a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/ErrorCodeMetric.java b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/ErrorCodeMetric.java new file mode 100644 index 0000000000..6553761783 --- /dev/null +++ b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/ErrorCodeMetric.java @@ -0,0 +1,51 @@ +/* + * 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.dubbo.metrics.model; + +import java.util.HashMap; +import java.util.Map; + +import static org.apache.dubbo.common.constants.MetricsConstants.TAG_APPLICATION_NAME; +import static org.apache.dubbo.common.constants.MetricsConstants.TAG_ERROR_CODE; + +/** + * ErrorCodeMetric. Provide tags for error code metrics. + */ +public class ErrorCodeMetric implements Metric { + + private final String errorCode; + + private final String applicationName; + + public ErrorCodeMetric(String applicationName, String errorCode) { + this.errorCode = errorCode; + this.applicationName = applicationName; + } + + @Override + public Map getTags() { + Map tags = new HashMap<>(); + tags.put(TAG_ERROR_CODE, errorCode); + tags.put(TAG_APPLICATION_NAME, applicationName); + return tags; + } + + public String getErrorCode() { + return errorCode; + } +} diff --git a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/MetricsCategory.java b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/MetricsCategory.java index 0eecdda807..66d5d8b492 100644 --- a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/MetricsCategory.java +++ b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/MetricsCategory.java @@ -29,4 +29,6 @@ public enum MetricsCategory { REGISTRY, METADATA, THREAD_POOL, + ERROR_CODE, + NETTY, } diff --git a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/MetricsSupport.java b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/MetricsSupport.java index 034bcbea02..404018dfb5 100644 --- a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/MetricsSupport.java +++ b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/MetricsSupport.java @@ -18,12 +18,12 @@ package org.apache.dubbo.metrics.model; import org.apache.dubbo.common.Version; +import org.apache.dubbo.common.lang.Nullable; import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.metrics.collector.MethodMetricsCollector; import org.apache.dubbo.metrics.collector.ServiceMetricsCollector; import org.apache.dubbo.metrics.event.MetricsEvent; import org.apache.dubbo.metrics.event.TimeCounterEvent; -import org.apache.dubbo.metrics.exception.MetricsNeverHappenException; import org.apache.dubbo.metrics.model.key.MetricsKey; import org.apache.dubbo.metrics.model.key.MetricsKeyWrapper; import org.apache.dubbo.metrics.model.key.MetricsPlaceValue; @@ -62,6 +62,10 @@ public class MetricsSupport { private static final String commitId = Version.getLastCommitId(); public static Map applicationTags(ApplicationModel applicationModel) { + return applicationTags(applicationModel, null); + } + + public static Map applicationTags(ApplicationModel applicationModel, @Nullable Map extraInfo) { Map tags = new HashMap<>(); tags.put(TAG_IP, getLocalHost()); tags.put(TAG_HOSTNAME, getLocalHostName()); @@ -69,23 +73,18 @@ public class MetricsSupport { tags.put(TAG_APPLICATION_MODULE, applicationModel.getInternalId()); tags.put(TAG_APPLICATION_VERSION_KEY, version); tags.put(MetricsKey.METADATA_GIT_COMMITID_METRIC.getName(), commitId); + if (CollectionUtils.isNotEmptyMap(extraInfo)) { + tags.putAll(extraInfo); + } return tags; } - public static Map serviceTags(ApplicationModel applicationModel, String serviceKey) { - Map tags = applicationTags(applicationModel); + public static Map serviceTags(ApplicationModel applicationModel, String serviceKey, Map extraInfo) { + Map tags = applicationTags(applicationModel, extraInfo); tags.put(TAG_INTERFACE_KEY, serviceKey); return tags; } - public static Map methodTags(ApplicationModel applicationModel, String names) { - String[] keys = names.split("_"); - if (keys.length != 2) { - throw new MetricsNeverHappenException("Error names: " + names); - } - return methodTags(applicationModel, keys[0], keys[1]); - } - public static Map methodTags(ApplicationModel applicationModel, String serviceKey, String methodName) { Map tags = applicationTags(applicationModel); tags.put(TAG_INTERFACE_KEY, serviceKey); @@ -211,7 +210,6 @@ public class MetricsSupport { Invocation invocation = event.getAttachmentValue(INVOCATION); if (invocation != null) { collector.addServiceRt(invocation, placeType.getType(), event.getTimePair().calc()); - return; } else { collector.addServiceRt((String) event.getAttachmentValue(ATTACHMENT_KEY_SERVICE), placeType.getType(), event.getTimePair().calc()); } @@ -240,9 +238,9 @@ public class MetricsSupport { } /** - * Generate a complete indicator item for an interface/method + * Generate a complete indicator item for an interface/method */ - public static void fillZero(Map> data) { + public static void fillZero(Map> data) { if (CollectionUtils.isEmptyMap(data)) { return; } diff --git a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/ServiceKeyMetric.java b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/ServiceKeyMetric.java index 1b1d220cea..361fd9f06e 100644 --- a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/ServiceKeyMetric.java +++ b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/ServiceKeyMetric.java @@ -35,7 +35,7 @@ public class ServiceKeyMetric extends ApplicationMetric { @Override public Map getTags() { - return MetricsSupport.serviceTags(getApplicationModel(), serviceKey); + return MetricsSupport.serviceTags(getApplicationModel(), serviceKey, getExtraInfo()); } public String getServiceKey() { @@ -47,16 +47,11 @@ public class ServiceKeyMetric extends ApplicationMetric { if (this == o) { return true; } - if (o == null || getClass() != o.getClass()) { + if (!(o instanceof ServiceKeyMetric)) { return false; } - ServiceKeyMetric that = (ServiceKeyMetric) o; - - if (!getApplicationName().equals(that.getApplicationName())) { - return false; - } - return serviceKey.equals(that.serviceKey); + return serviceKey.equals(that.serviceKey) && Objects.equals(extraInfo, that.extraInfo); } @@ -65,7 +60,7 @@ public class ServiceKeyMetric extends ApplicationMetric { @Override public int hashCode() { if (hashCode == 0) { - hashCode = Objects.hash(getApplicationName(), serviceKey); + hashCode = Objects.hash(getApplicationName(), serviceKey, extraInfo); } return hashCode; } diff --git a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/ThreadPoolMetric.java b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/ThreadPoolMetric.java index 002653359b..c45815f106 100644 --- a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/ThreadPoolMetric.java +++ b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/ThreadPoolMetric.java @@ -85,6 +85,7 @@ public class ThreadPoolMetric implements Metric{ return Objects.hash(applicationName, threadPoolName); } + @Override public Map getTags() { Map tags = new HashMap<>(); tags.put(TAG_IP, getLocalHost()); diff --git a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/ThreadPoolRejectMetric.java b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/ThreadPoolRejectMetric.java index 8706070847..c2daf4b5a9 100644 --- a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/ThreadPoolRejectMetric.java +++ b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/ThreadPoolRejectMetric.java @@ -30,6 +30,7 @@ import static org.apache.dubbo.common.constants.MetricsConstants.TAG_HOSTNAME; import static org.apache.dubbo.common.constants.MetricsConstants.TAG_IP; public class ThreadPoolRejectMetric implements Metric{ + private String applicationName; private String threadPoolName; @@ -69,6 +70,7 @@ public class ThreadPoolRejectMetric implements Metric{ return Objects.hash(applicationName, threadPoolName); } + @Override public Map getTags() { Map tags = new HashMap<>(); tags.put(TAG_IP, getLocalHost()); diff --git a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/key/MetricsCat.java b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/key/MetricsCat.java index cf1c813419..d085aa7ee9 100644 --- a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/key/MetricsCat.java +++ b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/key/MetricsCat.java @@ -43,7 +43,7 @@ public class MetricsCat { } /** - * @param tpFunc Ternary function, corresponding to finish and error events, because an additional record rt is required, and the type type of metricsKey is required + * @param tpFunc Ternary function, corresponding to finish and error events, because an additional record rt is required, and the type of metricsKey is required */ public MetricsCat(MetricsKey metricsKey, TpFunction tpFunc) { this.eventFunc = collector -> tpFunc.apply(metricsKey, placeType, collector); diff --git a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/key/MetricsKey.java b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/key/MetricsKey.java index 6b5329edc2..300c6f4dc4 100644 --- a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/key/MetricsKey.java +++ b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/key/MetricsKey.java @@ -17,131 +17,160 @@ package org.apache.dubbo.metrics.model.key; +/** + * Please follow a unified naming format as follows: + * dubbo_type_action_unit_otherfun + */ public enum MetricsKey { - APPLICATION_METRIC_INFO("dubbo.application.info.total", "Total Application Info"), + APPLICATION_METRIC_INFO("application.info.total", "Total Application Info"), - CONFIGCENTER_METRIC_TOTAL("dubbo.configcenter.total", "Config Changed Total"), + CONFIGCENTER_METRIC_TOTAL("configcenter.total", "Config Changed Total"), // provider metrics key - METRIC_REQUESTS("dubbo.%s.requests.total", "Total Requests"), - METRIC_REQUESTS_SUCCEED("dubbo.%s.requests.succeed.total", "Total Succeed Requests"), - METRIC_REQUEST_BUSINESS_FAILED("dubbo.%s.requests.business.failed.total", "Total Failed Business Requests"), + METRIC_REQUESTS("requests.total", "Total Requests"), + METRIC_REQUESTS_SUCCEED("requests.succeed.total", "Total Succeed Requests"), + METRIC_REQUEST_BUSINESS_FAILED("requests.business.failed.total", "Total Failed Business Requests"), - METRIC_REQUESTS_PROCESSING("dubbo.%s.requests.processing.total", "Processing Requests"), - METRIC_REQUESTS_TIMEOUT("dubbo.%s.requests.timeout.total", "Total Timeout Failed Requests"), - METRIC_REQUESTS_LIMIT("dubbo.%s.requests.limit.total", "Total Limit Failed Requests"), - METRIC_REQUESTS_FAILED("dubbo.%s.requests.unknown.failed.total", "Total Unknown Failed Requests"), - METRIC_REQUESTS_TOTAL_FAILED("dubbo.%s.requests.failed.total", "Total Failed Requests"), - METRIC_REQUESTS_NETWORK_FAILED("dubbo.%s.requests.failed.network.total", "Total network Failed Requests"), - METRIC_REQUESTS_SERVICE_UNAVAILABLE_FAILED("dubbo.%s.requests.failed.service.unavailable.total", "Total Service Unavailable Failed Requests"), - METRIC_REQUESTS_CODEC_FAILED("dubbo.%s.requests.failed.codec.total", "Total Codec Failed Requests"), + METRIC_REQUESTS_PROCESSING("requests.processing.total", "Processing Requests"), + METRIC_REQUESTS_TIMEOUT("requests.timeout.total", "Total Timeout Failed Requests"), + METRIC_REQUESTS_LIMIT("requests.limit.total", "Total Limit Failed Requests"), + METRIC_REQUESTS_FAILED("requests.unknown.failed.total", "Total Unknown Failed Requests"), + METRIC_REQUESTS_TOTAL_FAILED("requests.failed.total", "Total Failed Requests"), + METRIC_REQUESTS_NETWORK_FAILED("requests.failed.network.total", "Total network Failed Requests"), + METRIC_REQUESTS_SERVICE_UNAVAILABLE_FAILED("requests.failed.service.unavailable.total", "Total Service Unavailable Failed Requests"), + METRIC_REQUESTS_CODEC_FAILED("requests.failed.codec.total", "Total Codec Failed Requests"), - METRIC_REQUESTS_TOTAL_AGG("dubbo.%s.requests.total.aggregate", "Aggregated Total Requests"), - METRIC_REQUESTS_SUCCEED_AGG("dubbo.%s.requests.succeed.aggregate", "Aggregated Succeed Requests"), - METRIC_REQUESTS_FAILED_AGG("dubbo.%s.requests.failed.aggregate", "Aggregated Failed Requests"), - METRIC_REQUEST_BUSINESS_FAILED_AGG("dubbo.%s.requests.business.failed.aggregate", "Aggregated Business Failed Requests"), - METRIC_REQUESTS_TIMEOUT_AGG("dubbo.%s.requests.timeout.failed.aggregate", "Aggregated timeout Failed Requests"), - METRIC_REQUESTS_LIMIT_AGG("dubbo.%s.requests.limit.aggregate", "Aggregated limit Requests"), - METRIC_REQUESTS_TOTAL_FAILED_AGG("dubbo.%s.requests.failed.total.aggregate", "Aggregated failed total Requests"), - METRIC_REQUESTS_NETWORK_FAILED_AGG("dubbo.%s.requests.failed.network.total.aggregate", "Aggregated failed network total Requests"), - METRIC_REQUESTS_CODEC_FAILED_AGG("dubbo.%s.requests.failed.codec.total.aggregate", "Aggregated failed codec total Requests"), - METRIC_REQUESTS_TOTAL_SERVICE_UNAVAILABLE_FAILED_AGG("dubbo.%s.requests.failed.service.unavailable.total.aggregate", "Aggregated failed codec total Requests"), + METRIC_REQUESTS_TOTAL_AGG("requests.total.aggregate", "Aggregated Total Requests"), + METRIC_REQUESTS_SUCCEED_AGG("requests.succeed.aggregate", "Aggregated Succeed Requests"), + METRIC_REQUESTS_FAILED_AGG("requests.failed.aggregate", "Aggregated Failed Requests"), + METRIC_REQUEST_BUSINESS_FAILED_AGG("requests.business.failed.aggregate", "Aggregated Business Failed Requests"), + METRIC_REQUESTS_TIMEOUT_AGG("requests.timeout.failed.aggregate", "Aggregated timeout Failed Requests"), + METRIC_REQUESTS_LIMIT_AGG("requests.limit.aggregate", "Aggregated limit Requests"), + METRIC_REQUESTS_TOTAL_FAILED_AGG("requests.failed.total.aggregate", "Aggregated failed total Requests"), + METRIC_REQUESTS_NETWORK_FAILED_AGG("requests.failed.network.total.aggregate", "Aggregated failed network total Requests"), + METRIC_REQUESTS_CODEC_FAILED_AGG("requests.failed.codec.total.aggregate", "Aggregated failed codec total Requests"), + METRIC_REQUESTS_TOTAL_SERVICE_UNAVAILABLE_FAILED_AGG("requests.failed.service.unavailable.total.aggregate", "Aggregated failed codec total Requests"), - METRIC_QPS("dubbo.%s.qps.total", "Query Per Seconds"), - METRIC_RT_LAST("dubbo.%s.rt.milliseconds.last", "Last Response Time"), - METRIC_RT_MIN("dubbo.%s.rt.milliseconds.min", "Min Response Time"), - METRIC_RT_MAX("dubbo.%s.rt.milliseconds.max", "Max Response Time"), - METRIC_RT_SUM("dubbo.%s.rt.milliseconds.sum", "Sum Response Time"), - METRIC_RT_AVG("dubbo.%s.rt.milliseconds.avg", "Average Response Time"), - METRIC_RT_P99("dubbo.%s.rt.milliseconds.p99", "Response Time P99"), - METRIC_RT_P95("dubbo.%s.rt.milliseconds.p95", "Response Time P95"), - METRIC_RT_P90("dubbo.%s.rt.milliseconds.p90", "Response Time P90"), - METRIC_RT_P50("dubbo.%s.rt.milliseconds.p50", "Response Time P50"), - METRIC_RT_MIN_AGG("dubbo.%s.rt.min.milliseconds.aggregate", "Aggregated Min Response"), - METRIC_RT_MAX_AGG("dubbo.%s.rt.max.milliseconds.aggregate", "Aggregated Max Response"), - METRIC_RT_AVG_AGG("dubbo.%s.rt.avg.milliseconds.aggregate", "Aggregated Avg Response"), + METRIC_QPS("qps.total", "Query Per Seconds"), + METRIC_RT_LAST("rt.milliseconds.last", "Last Response Time"), + METRIC_RT_MIN("rt.milliseconds.min", "Min Response Time"), + METRIC_RT_MAX("rt.milliseconds.max", "Max Response Time"), + METRIC_RT_SUM("rt.milliseconds.sum", "Sum Response Time"), + METRIC_RT_AVG("rt.milliseconds.avg", "Average Response Time"), + METRIC_RT_P99("rt.milliseconds.p99", "Response Time P99"), + METRIC_RT_P95("rt.milliseconds.p95", "Response Time P95"), + METRIC_RT_P90("rt.milliseconds.p90", "Response Time P90"), + METRIC_RT_P50("rt.milliseconds.p50", "Response Time P50"), + METRIC_RT_MIN_AGG("rt.milliseconds.min.aggregate", "Aggregated Min Response"), + METRIC_RT_MAX_AGG("rt.milliseconds.max.aggregate", "Aggregated Max Response"), + METRIC_RT_AVG_AGG("rt.milliseconds.avg.aggregate", "Aggregated Avg Response"), // register metrics key - REGISTER_METRIC_REQUESTS("dubbo.registry.register.requests.total", "Total Register Requests"), - REGISTER_METRIC_REQUESTS_SUCCEED("dubbo.registry.register.requests.succeed.total", "Succeed Register Requests"), - REGISTER_METRIC_REQUESTS_FAILED("dubbo.registry.register.requests.failed.total", "Failed Register Requests"), - METRIC_RT_HISTOGRAM("dubbo.%s.rt.milliseconds.histogram", "Response Time Histogram"), + REGISTER_METRIC_REQUESTS("registry.register.requests.total", "Total Register Requests"), + REGISTER_METRIC_REQUESTS_SUCCEED("registry.register.requests.succeed.total", "Succeed Register Requests"), + REGISTER_METRIC_REQUESTS_FAILED("registry.register.requests.failed.total", "Failed Register Requests"), + METRIC_RT_HISTOGRAM("rt.milliseconds.histogram", "Response Time Histogram"), - GENERIC_METRIC_REQUESTS("dubbo.%s.requests.total", "Total %s Requests"), - GENERIC_METRIC_REQUESTS_SUCCEED("dubbo.%s.requests.succeed.total", "Succeed %s Requests"), - GENERIC_METRIC_REQUESTS_FAILED("dubbo.%s.requests.failed.total", "Failed %s Requests"), + GENERIC_METRIC_REQUESTS("requests.total", "Total %s Requests"), + GENERIC_METRIC_REQUESTS_SUCCEED("requests.succeed.total", "Succeed %s Requests"), + GENERIC_METRIC_REQUESTS_FAILED("requests.failed.total", "Failed %s Requests"), // subscribe metrics key - SUBSCRIBE_METRIC_NUM("dubbo.registry.subscribe.num.total", "Total Subscribe Num"), - SUBSCRIBE_METRIC_NUM_SUCCEED("dubbo.registry.subscribe.num.succeed.total", "Succeed Subscribe Num"), - SUBSCRIBE_METRIC_NUM_FAILED("dubbo.registry.subscribe.num.failed.total", "Failed Subscribe Num"), + SUBSCRIBE_METRIC_NUM("registry.subscribe.num.total", "Total Subscribe Num"), + SUBSCRIBE_METRIC_NUM_SUCCEED("registry.subscribe.num.succeed.total", "Succeed Subscribe Num"), + SUBSCRIBE_METRIC_NUM_FAILED("registry.subscribe.num.failed.total", "Failed Subscribe Num"), // directory metrics key - DIRECTORY_METRIC_NUM_ALL("dubbo.registry.directory.num.all", "All Directory Urls"), - DIRECTORY_METRIC_NUM_VALID("dubbo.registry.directory.num.valid.total", "Valid Directory Urls"), - DIRECTORY_METRIC_NUM_TO_RECONNECT("dubbo.registry.directory.num.to_reconnect.total", "ToReconnect Directory Urls"), - DIRECTORY_METRIC_NUM_DISABLE("dubbo.registry.directory.num.disable.total", "Disable Directory Urls"), + DIRECTORY_METRIC_NUM_ALL("registry.directory.num.all", "All Directory Urls"), + DIRECTORY_METRIC_NUM_VALID("registry.directory.num.valid.total", "Valid Directory Urls"), + DIRECTORY_METRIC_NUM_TO_RECONNECT("registry.directory.num.to_reconnect.total", "ToReconnect Directory Urls"), + DIRECTORY_METRIC_NUM_DISABLE("registry.directory.num.disable.total", "Disable Directory Urls"), - NOTIFY_METRIC_REQUESTS("dubbo.registry.notify.requests.total", "Total Notify Requests"), - NOTIFY_METRIC_NUM_LAST("dubbo.registry.notify.num.last", "Last Notify Nums"), + NOTIFY_METRIC_REQUESTS("registry.notify.requests.total", "Total Notify Requests"), + NOTIFY_METRIC_NUM_LAST("registry.notify.num.last", "Last Notify Nums"), - THREAD_POOL_CORE_SIZE("dubbo.thread.pool.core.size", "Thread Pool Core Size"), - THREAD_POOL_LARGEST_SIZE("dubbo.thread.pool.largest.size", "Thread Pool Largest Size"), - THREAD_POOL_MAX_SIZE("dubbo.thread.pool.max.size", "Thread Pool Max Size"), - THREAD_POOL_ACTIVE_SIZE("dubbo.thread.pool.active.size", "Thread Pool Active Size"), - THREAD_POOL_THREAD_COUNT("dubbo.thread.pool.thread.count", "Thread Pool Thread Count"), - THREAD_POOL_QUEUE_SIZE("dubbo.thread.pool.queue.size", "Thread Pool Queue Size"), - THREAD_POOL_THREAD_REJECT_COUNT("dubbo.thread.pool.reject.thread.count", "Thread Pool Reject Thread Count"), + THREAD_POOL_CORE_SIZE("thread.pool.core.size", "Thread Pool Core Size"), + THREAD_POOL_LARGEST_SIZE("thread.pool.largest.size", "Thread Pool Largest Size"), + THREAD_POOL_MAX_SIZE("thread.pool.max.size", "Thread Pool Max Size"), + THREAD_POOL_ACTIVE_SIZE("thread.pool.active.size", "Thread Pool Active Size"), + THREAD_POOL_THREAD_COUNT("thread.pool.thread.count", "Thread Pool Thread Count"), + THREAD_POOL_QUEUE_SIZE("thread.pool.queue.size", "Thread Pool Queue Size"), + THREAD_POOL_THREAD_REJECT_COUNT("thread.pool.reject.thread.count", "Thread Pool Reject Thread Count"), // metadata push metrics key - METADATA_PUSH_METRIC_NUM("dubbo.metadata.push.num.total", "Total Push Num"), - METADATA_PUSH_METRIC_NUM_SUCCEED("dubbo.metadata.push.num.succeed.total", "Succeed Push Num"), - METADATA_PUSH_METRIC_NUM_FAILED("dubbo.metadata.push.num.failed.total", "Failed Push Num"), + METADATA_PUSH_METRIC_NUM("metadata.push.num.total", "Total Push Num"), + METADATA_PUSH_METRIC_NUM_SUCCEED("metadata.push.num.succeed.total", "Succeed Push Num"), + METADATA_PUSH_METRIC_NUM_FAILED("metadata.push.num.failed.total", "Failed Push Num"), // metadata subscribe metrics key - METADATA_SUBSCRIBE_METRIC_NUM("dubbo.metadata.subscribe.num.total", "Total Metadata Subscribe Num"), - METADATA_SUBSCRIBE_METRIC_NUM_SUCCEED("dubbo.metadata.subscribe.num.succeed.total", "Succeed Metadata Subscribe Num"), - METADATA_SUBSCRIBE_METRIC_NUM_FAILED("dubbo.metadata.subscribe.num.failed.total", "Failed Metadata Subscribe Num"), + METADATA_SUBSCRIBE_METRIC_NUM("metadata.subscribe.num.total", "Total Metadata Subscribe Num"), + METADATA_SUBSCRIBE_METRIC_NUM_SUCCEED("metadata.subscribe.num.succeed.total", "Succeed Metadata Subscribe Num"), + METADATA_SUBSCRIBE_METRIC_NUM_FAILED("metadata.subscribe.num.failed.total", "Failed Metadata Subscribe Num"), // register service metrics key - SERVICE_REGISTER_METRIC_REQUESTS("dubbo.registry.register.service.total", "Total Service-Level Register Requests"), - SERVICE_REGISTER_METRIC_REQUESTS_SUCCEED("dubbo.registry.register.service.succeed.total", "Succeed Service-Level Register Requests"), - SERVICE_REGISTER_METRIC_REQUESTS_FAILED("dubbo.registry.register.service.failed.total", "Failed Service-Level Register Requests"), + SERVICE_REGISTER_METRIC_REQUESTS("registry.total", "Total Service-Level Register Requests"), + SERVICE_REGISTER_METRIC_REQUESTS_SUCCEED("registry.succeed.total", "Succeed Service-Level Register Requests"), + SERVICE_REGISTER_METRIC_REQUESTS_FAILED("registry.failed.total", "Failed Service-Level Register Requests"), // subscribe metrics key - SERVICE_SUBSCRIBE_METRIC_NUM("dubbo.registry.subscribe.service.num.total", "Total Service-Level Subscribe Num"), - SERVICE_SUBSCRIBE_METRIC_NUM_SUCCEED("dubbo.registry.subscribe.service.num.succeed.total", "Succeed Service-Level Num"), - SERVICE_SUBSCRIBE_METRIC_NUM_FAILED("dubbo.registry.subscribe.service.num.failed.total", "Failed Service-Level Num"), + SERVICE_SUBSCRIBE_METRIC_NUM("registry.subscribe.service.num.total", "Total Service-Level Subscribe Num"), + SERVICE_SUBSCRIBE_METRIC_NUM_SUCCEED("registry.subscribe.service.num.succeed.total", "Succeed Service-Level Num"), + SERVICE_SUBSCRIBE_METRIC_NUM_FAILED("registry.subscribe.service.num.failed.total", "Failed Service-Level Num"), // store provider metadata service key - STORE_PROVIDER_METADATA("dubbo.metadata.store.provider.total", "Store Provider Metadata"), + STORE_PROVIDER_METADATA("metadata.store.provider.total", "Store Provider Metadata"), - STORE_PROVIDER_METADATA_SUCCEED("dubbo.metadata.store.provider.succeed.total", "Succeed Store Provider Metadata"), + STORE_PROVIDER_METADATA_SUCCEED("metadata.store.provider.succeed.total", "Succeed Store Provider Metadata"), - STORE_PROVIDER_METADATA_FAILED("dubbo.metadata.store.provider.failed.total", "Failed Store Provider Metadata"), + STORE_PROVIDER_METADATA_FAILED("metadata.store.provider.failed.total", "Failed Store Provider Metadata"), METADATA_GIT_COMMITID_METRIC("git.commit.id", "Git Commit Id Metrics"), // consumer metrics key - INVOKER_NO_AVAILABLE_COUNT("dubbo.consumer.invoker.no.available.count", "Request Throw No Invoker Available Exception Count"), + INVOKER_NO_AVAILABLE_COUNT("consumer.invoker.no.available.count", "Request Throw No Invoker Available Exception Count"), + + // count the number of occurrences of each error code + ERROR_CODE_COUNT("dubbo.error.code.count","The Count Of Occurrences for Each Error Code"), + + // netty metrics key + NETTY_ALLOCATOR_HEAP_MEMORY_USED("netty.allocator.memory.used", "Netty Allocator Memory Used"), + NETTY_ALLOCATOR_DIRECT_MEMORY_USED("netty.allocator.direct.memory.used", "Netty Allocator Direct Memory Used"), + NETTY_ALLOCATOR_PINNED_DIRECT_MEMORY("netty.allocator.pinned.direct.memory", "Netty Allocator Pinned Direct Memory"), + NETTY_ALLOCATOR_PINNED_HEAP_MEMORY("netty.allocator.pinned.heap.memory", "Netty Allocator Pinned Heap Memory"), + NETTY_ALLOCATOR_HEAP_ARENAS_NUM("netty.allocator.heap.arenas.num", "Netty Allocator Heap Arenas Num"), + NETTY_ALLOCATOR_DIRECT_ARENAS_NUM("netty.allocator.direct.arenas.num", "Netty Allocator Direct Arenas Num"), + NETTY_ALLOCATOR_NORMAL_CACHE_SIZE("netty.allocator.normal.cache.size", "Netty Allocator Normal Cache Size"), + NETTY_ALLOCATOR_SMALL_CACHE_SIZE("netty.allocator.small.cache.size", "Netty Allocator Small Cache Size"), + NETTY_ALLOCATOR_THREAD_LOCAL_CACHES_NUM("netty.allocator.thread.local.caches.num", "Netty Allocator Thread Local Caches Num"), + NETTY_ALLOCATOR_CHUNK_SIZE("netty.allocator.chunk.size", "Netty Allocator Chunk Size"), ; - private String name; + private String nameSuffix; private String description; public final String getName() { - return this.name; + return "dubbo." + nameSuffix; } public final String getNameByType(String type) { - return String.format(name, type); + return "dubbo." + type + "." + nameSuffix; + } + + public static MetricsKey getMetricsByName(String name){ + for (MetricsKey metricsKey : MetricsKey.values()) { + if (metricsKey.getName().equals(name)) { + return metricsKey; + } + } + return null; } public final String getDescription() { return this.description; } - MetricsKey(String name, String description) { - this.name = name; + + MetricsKey(String nameSuffix, String description) { + this.nameSuffix = nameSuffix; this.description = description; } } diff --git a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/key/MetricsKeyWrapper.java b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/key/MetricsKeyWrapper.java index 21bb7648e9..042bfd0e3c 100644 --- a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/key/MetricsKeyWrapper.java +++ b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/key/MetricsKeyWrapper.java @@ -18,11 +18,8 @@ package org.apache.dubbo.metrics.model.key; import io.micrometer.common.lang.Nullable; -import org.apache.dubbo.metrics.model.MetricsSupport; import org.apache.dubbo.metrics.model.sample.MetricSample; -import org.apache.dubbo.rpc.model.ApplicationModel; -import java.util.Map; import java.util.Objects; /** @@ -88,7 +85,7 @@ public class MetricsKeyWrapper { return metricsKey.getName(); } try { - return String.format(metricsKey.getName(), getType()); + return metricsKey.getNameByType(getType()); } catch (Exception ignore) { return metricsKey.getName(); } @@ -105,19 +102,6 @@ public class MetricsKeyWrapper { } } - public Map tagName(ApplicationModel applicationModel, String key) { - MetricsLevel level = getLevel(); - switch (level) { - case APP: - return MetricsSupport.applicationTags(applicationModel); - case SERVICE: - return MetricsSupport.serviceTags(applicationModel, key); - case METHOD: - return MetricsSupport.methodTags(applicationModel, key); - } - return MetricsSupport.applicationTags(applicationModel); - } - public static MetricsKeyWrapper wrapper(MetricsKey metricsKey) { return new MetricsKeyWrapper(metricsKey, null); } diff --git a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/key/MetricsLevel.java b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/key/MetricsLevel.java index 783de99948..9a81e17ef8 100644 --- a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/key/MetricsLevel.java +++ b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/model/key/MetricsLevel.java @@ -18,5 +18,5 @@ package org.apache.dubbo.metrics.model.key; public enum MetricsLevel { - APP, SERVICE, METHOD, CONFIG + APP, SERVICE, METHOD, CONFIG, REGISTRY } diff --git a/dubbo-metrics/dubbo-metrics-api/src/test/java/org/apache/dubbo/metrics/aggregate/TimeWindowQuantileTest.java b/dubbo-metrics/dubbo-metrics-api/src/test/java/org/apache/dubbo/metrics/aggregate/TimeWindowQuantileTest.java index 4d2aa21baa..170efd61f9 100644 --- a/dubbo-metrics/dubbo-metrics-api/src/test/java/org/apache/dubbo/metrics/aggregate/TimeWindowQuantileTest.java +++ b/dubbo-metrics/dubbo-metrics-api/src/test/java/org/apache/dubbo/metrics/aggregate/TimeWindowQuantileTest.java @@ -18,6 +18,7 @@ package org.apache.dubbo.metrics.aggregate; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.RepeatedTest; import org.junit.jupiter.api.Test; import java.util.concurrent.ExecutorService; @@ -37,6 +38,7 @@ class TimeWindowQuantileTest { } @Test + @RepeatedTest(100) void testMulti() { ExecutorService executorService = Executors.newFixedThreadPool(200); @@ -51,12 +53,14 @@ class TimeWindowQuantileTest { quantile.add(finalI)); } index++; - try { - Thread.sleep(100); - } catch (InterruptedException e) { - e.printStackTrace(); - } +// try { +// Thread.sleep(1); +// } catch (InterruptedException e) { +// e.printStackTrace(); +// } } + + executorService.shutdown(); } } diff --git a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/DefaultMetricsCollector.java b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/DefaultMetricsCollector.java index c4c3ef9ec0..39376d344f 100644 --- a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/DefaultMetricsCollector.java +++ b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/DefaultMetricsCollector.java @@ -20,16 +20,16 @@ package org.apache.dubbo.metrics.collector; import org.apache.dubbo.common.constants.CommonConstants; import org.apache.dubbo.common.extension.Activate; import org.apache.dubbo.metrics.DefaultConstants; -import org.apache.dubbo.metrics.collector.sample.MetricsCountSampleConfigurer; +import org.apache.dubbo.metrics.collector.sample.ErrorCodeSampler; import org.apache.dubbo.metrics.collector.sample.MetricsSampler; import org.apache.dubbo.metrics.collector.sample.SimpleMetricsCountSampler; import org.apache.dubbo.metrics.collector.sample.ThreadPoolMetricsSampler; +import org.apache.dubbo.metrics.collector.sample.MetricsCountSampleConfigurer; import org.apache.dubbo.metrics.data.BaseStatComposite; import org.apache.dubbo.metrics.data.MethodStatComposite; import org.apache.dubbo.metrics.data.RtStatComposite; import org.apache.dubbo.metrics.event.DefaultSubDispatcher; import org.apache.dubbo.metrics.event.MetricsEvent; -import org.apache.dubbo.metrics.event.RequestBeforeEvent; import org.apache.dubbo.metrics.event.RequestEvent; import org.apache.dubbo.metrics.model.ApplicationMetric; import org.apache.dubbo.metrics.model.MetricsCategory; @@ -54,9 +54,15 @@ public class DefaultMetricsCollector extends CombMetricsCollector private boolean collectEnabled = false; private volatile boolean threadpoolCollectEnabled = false; + private final ThreadPoolMetricsSampler threadPoolSampler = new ThreadPoolMetricsSampler(this); + + private final ErrorCodeSampler errorCodeSampler; + private String applicationName; + private final ApplicationModel applicationModel; + private final List samplers = new ArrayList<>(); public DefaultMetricsCollector(ApplicationModel applicationModel) { @@ -75,8 +81,9 @@ public class DefaultMetricsCollector extends CombMetricsCollector } }); super.setEventMulticaster(new DefaultSubDispatcher(this)); - samplers.add(applicationSampler); - samplers.add(threadPoolSampler); + this.samplers.add(applicationSampler); + this.samplers.add(threadPoolSampler); + this.errorCodeSampler = new ErrorCodeSampler(this); this.applicationModel = applicationModel; } @@ -100,6 +107,7 @@ public class DefaultMetricsCollector extends CombMetricsCollector this.collectEnabled = collectEnabled; } + @Override public boolean isCollectEnabled() { return collectEnabled; } @@ -138,7 +146,7 @@ public class DefaultMetricsCollector extends CombMetricsCollector @Override public boolean isSupport(MetricsEvent event) { - return event instanceof RequestEvent || event instanceof RequestBeforeEvent; + return event instanceof RequestEvent; } public SimpleMetricsCountSampler applicationSampler = new SimpleMetricsCountSampler() { diff --git a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/sample/ErrorCodeMetricsListenRegister.java b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/sample/ErrorCodeMetricsListenRegister.java new file mode 100644 index 0000000000..82860dab51 --- /dev/null +++ b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/sample/ErrorCodeMetricsListenRegister.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.dubbo.metrics.collector.sample; + +import org.apache.dubbo.common.logger.LogListener; +import org.apache.dubbo.common.logger.support.FailsafeErrorTypeAwareLogger; +import org.apache.dubbo.metrics.model.key.MetricsKey; + +/** + * Listen the log of all {@link FailsafeErrorTypeAwareLogger} instances, and add error code count to {@link ErrorCodeSampler}. + */ +public class ErrorCodeMetricsListenRegister implements LogListener { + + private final ErrorCodeSampler errorCodeSampler; + + public ErrorCodeMetricsListenRegister(ErrorCodeSampler errorCodeSampler){ + FailsafeErrorTypeAwareLogger.registerGlobalListen(this); + this.errorCodeSampler = errorCodeSampler; + this.errorCodeSampler.addMetricName(MetricsKey.ERROR_CODE_COUNT.getName()); + } + + @Override + public void onMessage(String code, String msg) { + errorCodeSampler.inc(code, MetricsKey.ERROR_CODE_COUNT.getName()); + } +} diff --git a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/sample/ErrorCodeSampler.java b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/sample/ErrorCodeSampler.java new file mode 100644 index 0000000000..86fdf79237 --- /dev/null +++ b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/sample/ErrorCodeSampler.java @@ -0,0 +1,74 @@ +/* + * 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.dubbo.metrics.collector.sample; + +import org.apache.dubbo.metrics.collector.DefaultMetricsCollector; +import org.apache.dubbo.metrics.model.ErrorCodeMetric; +import org.apache.dubbo.metrics.model.MetricsCategory; +import org.apache.dubbo.metrics.model.key.MetricsKey; +import org.apache.dubbo.metrics.model.sample.CounterMetricSample; +import org.apache.dubbo.metrics.model.sample.MetricSample; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicLong; + +/** + * This sampler is used to count the number of occurrences of each error code. + */ +public class ErrorCodeSampler extends MetricsNameCountSampler { + + private final ErrorCodeMetricsListenRegister register; + + /** + * Map + */ + private final Map errorCodeMetrics; + + public ErrorCodeSampler(DefaultMetricsCollector collector) { + super(collector, MetricsCategory.ERROR_CODE, MetricsKey.ERROR_CODE_COUNT); + this.register = new ErrorCodeMetricsListenRegister(this); + this.errorCodeMetrics = new ConcurrentHashMap<>(); + } + + @Override + protected MetricSample provideMetricsSample(ErrorCodeMetric metric, AtomicLong count, MetricsKey metricsKey, MetricsCategory metricsCategory) { + return new CounterMetricSample<>( + metricsKey.getNameByType(metric.getErrorCode()), + metricsKey.getDescription(), + metric.getTags(), + metricsCategory, + count + ); + } + + @Override + protected void countConfigure(MetricsCountSampleConfigurer sampleConfigure) { + sampleConfigure.configureMetrics(configure -> { + + String errorCode = configure.getSource(); + ErrorCodeMetric metric = errorCodeMetrics.get(errorCode); + + if (metric == null) { + metric = new ErrorCodeMetric(collector.getApplicationModel().getApplicationName(), errorCode); + errorCodeMetrics.put(errorCode, metric); + } + return metric; + }); + } +} diff --git a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/sample/MetricsNameCountSampler.java b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/sample/MetricsNameCountSampler.java new file mode 100644 index 0000000000..ebf7e437ce --- /dev/null +++ b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/sample/MetricsNameCountSampler.java @@ -0,0 +1,69 @@ +/* + * 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.dubbo.metrics.collector.sample; + +import org.apache.dubbo.common.utils.ConcurrentHashSet; +import org.apache.dubbo.metrics.collector.DefaultMetricsCollector; +import org.apache.dubbo.metrics.model.Metric; +import org.apache.dubbo.metrics.model.MetricsCategory; +import org.apache.dubbo.metrics.model.key.MetricsKey; +import org.apache.dubbo.metrics.model.sample.MetricSample; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.concurrent.atomic.AtomicLong; + +public abstract class MetricsNameCountSampler extends SimpleMetricsCountSampler { + + protected final DefaultMetricsCollector collector; + + protected final Set metricNames = new ConcurrentHashSet<>(); + + protected final MetricsCategory metricsCategory; + + protected final MetricsKey metricsKey; + + public MetricsNameCountSampler(DefaultMetricsCollector collector,MetricsCategory metricsCategory,MetricsKey metricsKey) { + this.metricsCategory = metricsCategory; + this.metricsKey = metricsKey; + this.collector = collector; + this.collector.addSampler(this); + } + + public void addMetricName(K name) { + this.metricNames.add(name); + } + + @Override + public List sample() { + List metricSamples = new ArrayList<>(); + metricNames.forEach(name -> collect(metricSamples, name)); + return metricSamples; + } + + private void collect(List samples, K metricName) { + getCount(metricName) + .filter(e -> !e.isEmpty()) + .ifPresent(map -> map.forEach((k, v) -> + samples.add(provideMetricsSample(k,v,metricsKey,metricsCategory)))); + } + + protected abstract MetricSample provideMetricsSample(M metric,AtomicLong count,MetricsKey metricsKey,MetricsCategory metricsCategory); + +} diff --git a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/sample/SimpleMetricsCountSampler.java b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/sample/SimpleMetricsCountSampler.java index 9c31973740..666af13f30 100644 --- a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/sample/SimpleMetricsCountSampler.java +++ b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/sample/SimpleMetricsCountSampler.java @@ -36,6 +36,7 @@ public abstract class SimpleMetricsCountSampler implements MetricsCountSampler { private final ConcurrentMap EMPTY_COUNT = new ConcurrentHashMap<>(); + private final Map> metricCounter = new ConcurrentHashMap<>(); @Override diff --git a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/sample/ThreadRejectMetricsCountSampler.java b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/sample/ThreadRejectMetricsCountSampler.java index e9e55f9448..2638777574 100644 --- a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/sample/ThreadRejectMetricsCountSampler.java +++ b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/collector/sample/ThreadRejectMetricsCountSampler.java @@ -16,65 +16,33 @@ */ package org.apache.dubbo.metrics.collector.sample; -import org.apache.dubbo.common.utils.ConcurrentHashSet; + import org.apache.dubbo.metrics.collector.DefaultMetricsCollector; -import org.apache.dubbo.metrics.model.Metric; import org.apache.dubbo.metrics.model.MetricsCategory; -import org.apache.dubbo.metrics.model.key.MetricsKey; import org.apache.dubbo.metrics.model.ThreadPoolRejectMetric; +import org.apache.dubbo.metrics.model.key.MetricsKey; import org.apache.dubbo.metrics.model.sample.GaugeMetricSample; import org.apache.dubbo.metrics.model.sample.MetricSample; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; + import java.util.concurrent.atomic.AtomicLong; -import java.util.function.ToDoubleFunction; + import static org.apache.dubbo.metrics.model.MetricsCategory.THREAD_POOL; -public class ThreadRejectMetricsCountSampler extends SimpleMetricsCountSampler { +public class ThreadRejectMetricsCountSampler extends MetricsNameCountSampler { - private final DefaultMetricsCollector collector; - - private final Set metricNames = new ConcurrentHashSet<>(); public ThreadRejectMetricsCountSampler(DefaultMetricsCollector collector) { - this.collector = collector; - this.collector.addSampler(this); - } - - public void addMetricName(String name){ - this.metricNames.add(name); + super(collector, THREAD_POOL,MetricsKey.THREAD_POOL_THREAD_REJECT_COUNT); } @Override - public List sample() { - List metricSamples = new ArrayList<>(); - metricNames.stream().forEach(name->collect(metricSamples,name)); - return metricSamples; - } - - - private void collect(List list, String metricName) { - count(list, metricName, MetricsKey.THREAD_POOL_THREAD_REJECT_COUNT); - } - - private void count(List list, String metricName, MetricsKey metricsKey) { - getCount(metricName).filter(e -> !e.isEmpty()) - .ifPresent(map -> map.forEach((k, v) -> - list.add(getGaugeMetricSample(metricsKey, k, THREAD_POOL, v, AtomicLong::get)))); - } - - private GaugeMetricSample getGaugeMetricSample(MetricsKey metricsKey, - ThreadPoolRejectMetric methodMetric, - MetricsCategory metricsCategory, - T value, - ToDoubleFunction apply) { + protected MetricSample provideMetricsSample(ThreadPoolRejectMetric metric, AtomicLong count, MetricsKey metricsKey, MetricsCategory metricsCategory) { return new GaugeMetricSample<>( - metricsKey.getNameByType(methodMetric.getThreadPoolName()), + metricsKey.getNameByType(metric.getThreadPoolName()), metricsKey.getDescription(), - methodMetric.getTags(), + metric.getTags(), metricsCategory, - value, - apply); + count, + AtomicLong::get); } @Override diff --git a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/event/DefaultSubDispatcher.java b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/event/DefaultSubDispatcher.java index 9894c67d11..d9a88c466d 100644 --- a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/event/DefaultSubDispatcher.java +++ b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/event/DefaultSubDispatcher.java @@ -43,17 +43,16 @@ public final class DefaultSubDispatcher extends SimpleMetricsEventMulticaster { super.addListener(categoryOverall.getFinish().getEventFunc().apply(collector)); super.addListener(categoryOverall.getError().getEventFunc().apply(collector)); - super.addListener(new MetricsListener() { + super.addListener(new MetricsListener() { @Override public boolean isSupport(MetricsEvent event) { - return event instanceof RequestBeforeEvent; + return event instanceof RequestEvent && ((RequestEvent) event).isRequestErrorEvent(); } - private final MetricsPlaceValue dynamicPlaceType = MetricsPlaceValue.of(CommonConstants.CONSUMER, MetricsLevel.METHOD); @Override - public void onEvent(RequestBeforeEvent event) { + public void onEvent(RequestEvent event) { MetricsSupport.increment(METRIC_REQUESTS_SERVICE_UNAVAILABLE_FAILED, dynamicPlaceType, (MethodMetricsCollector) collector, event); } }); @@ -97,6 +96,7 @@ public final class DefaultSubDispatcher extends SimpleMetricsEventMulticaster { MetricsSupport.incrAndAddRt(targetKey, dynamicPlaceType, (MethodMetricsCollector) collector, event); } ))); + } } diff --git a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/event/RequestBeforeEvent.java b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/event/RequestBeforeEvent.java deleted file mode 100644 index 5b7d7c64da..0000000000 --- a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/event/RequestBeforeEvent.java +++ /dev/null @@ -1,51 +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. - */ - -package org.apache.dubbo.metrics.event; - -import org.apache.dubbo.metrics.MetricsConstants; -import org.apache.dubbo.metrics.model.MethodMetric; -import org.apache.dubbo.metrics.model.MetricsSupport; -import org.apache.dubbo.metrics.model.key.MetricsKey; -import org.apache.dubbo.metrics.model.key.MetricsLevel; -import org.apache.dubbo.metrics.model.key.TypeWrapper; -import org.apache.dubbo.rpc.Invocation; -import org.apache.dubbo.rpc.model.ApplicationModel; - -import static org.apache.dubbo.metrics.MetricsConstants.ATTACHMENT_KEY_SERVICE; - -/** - * Acts on MetricsClusterFilter to monitor exceptions that occur before request execution - */ -public class RequestBeforeEvent extends TimeCounterEvent { - - public RequestBeforeEvent(ApplicationModel source, String appName, MetricsDispatcher metricsDispatcher, TypeWrapper typeWrapper) { - super(source, appName, metricsDispatcher, typeWrapper); - - } - - private static final TypeWrapper REQUEST_BEFORE_EVENT = new TypeWrapper(MetricsLevel.METHOD, MetricsKey.METRIC_REQUESTS); - public static RequestBeforeEvent toEvent(ApplicationModel applicationModel, String appName, MetricsDispatcher metricsDispatcher, Invocation invocation, String side) { - RequestBeforeEvent event = new RequestBeforeEvent(applicationModel, appName, metricsDispatcher, REQUEST_BEFORE_EVENT); - event.putAttachment(ATTACHMENT_KEY_SERVICE, MetricsSupport.getInterfaceName(invocation)); - event.putAttachment(MetricsConstants.INVOCATION_SIDE, side); - event.putAttachment(MetricsConstants.INVOCATION, invocation); - event.putAttachment(MetricsConstants.METHOD_METRICS, new MethodMetric(applicationModel, invocation)); - return event; - } - -} diff --git a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/event/RequestEvent.java b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/event/RequestEvent.java index acb0aad159..93ad680df1 100644 --- a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/event/RequestEvent.java +++ b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/event/RequestEvent.java @@ -23,6 +23,7 @@ import org.apache.dubbo.metrics.collector.DefaultMetricsCollector; import org.apache.dubbo.metrics.exception.MetricsNeverHappenException; import org.apache.dubbo.metrics.model.MethodMetric; import org.apache.dubbo.metrics.model.MetricsSupport; +import org.apache.dubbo.metrics.model.key.MetricsKey; import org.apache.dubbo.metrics.model.key.MetricsLevel; import org.apache.dubbo.metrics.model.key.TypeWrapper; import org.apache.dubbo.rpc.Invocation; @@ -39,7 +40,8 @@ import static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_REQUEST_BUSIN * Request related events */ public class RequestEvent extends TimeCounterEvent { - private static final TypeWrapper TYPE_WRAPPER = new TypeWrapper(MetricsLevel.SERVICE, METRIC_REQUESTS, METRIC_REQUESTS_SUCCEED, METRIC_REQUEST_BUSINESS_FAILED); + private static final TypeWrapper REQUEST_EVENT = new TypeWrapper(MetricsLevel.SERVICE, METRIC_REQUESTS, METRIC_REQUESTS_SUCCEED, METRIC_REQUEST_BUSINESS_FAILED); + private static final TypeWrapper REQUEST_ERROR_EVENT = new TypeWrapper(MetricsLevel.METHOD, MetricsKey.METRIC_REQUESTS); public RequestEvent(ApplicationModel applicationModel, String appName, MetricsDispatcher metricsDispatcher, DefaultMetricsCollector collector, TypeWrapper TYPE_WRAPPER) { super(applicationModel, appName, metricsDispatcher, TYPE_WRAPPER); @@ -56,7 +58,7 @@ public class RequestEvent extends TimeCounterEvent { MetricsDispatcher metricsDispatcher, DefaultMetricsCollector collector, Invocation invocation, String side) { MethodMetric methodMetric = new MethodMetric(applicationModel, invocation); - RequestEvent requestEvent = new RequestEvent(applicationModel, appName, metricsDispatcher, collector, TYPE_WRAPPER); + RequestEvent requestEvent = new RequestEvent(applicationModel, appName, metricsDispatcher, collector, REQUEST_EVENT); requestEvent.putAttachment(MetricsConstants.INVOCATION, invocation); requestEvent.putAttachment(MetricsConstants.METHOD_METRICS, methodMetric); requestEvent.putAttachment(ATTACHMENT_KEY_SERVICE, MetricsSupport.getInterfaceName(invocation)); @@ -74,4 +76,21 @@ public class RequestEvent extends TimeCounterEvent { } super.putAttachment(METRIC_THROWABLE, ((Result) postResult).getException()); } + + /** + * Acts on MetricsClusterFilter to monitor exceptions that occur before request execution + */ + public static RequestEvent toRequestErrorEvent(ApplicationModel applicationModel, String appName, MetricsDispatcher metricsDispatcher, Invocation invocation, String side, int code) { + RequestEvent event = new RequestEvent(applicationModel, appName, metricsDispatcher, null, REQUEST_ERROR_EVENT); + event.putAttachment(ATTACHMENT_KEY_SERVICE, MetricsSupport.getInterfaceName(invocation)); + event.putAttachment(MetricsConstants.INVOCATION_SIDE, side); + event.putAttachment(MetricsConstants.INVOCATION, invocation); + event.putAttachment(MetricsConstants.INVOCATION_REQUEST_ERROR, code); + event.putAttachment(MetricsConstants.METHOD_METRICS, new MethodMetric(applicationModel, invocation)); + return event; + } + + public boolean isRequestErrorEvent(){ + return super.getAttachmentValue(MetricsConstants.INVOCATION_REQUEST_ERROR) != null; + } } diff --git a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/report/AbstractMetricsReporter.java b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/report/AbstractMetricsReporter.java index 3dfed9b466..c6eb309b36 100644 --- a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/report/AbstractMetricsReporter.java +++ b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/report/AbstractMetricsReporter.java @@ -21,7 +21,6 @@ import io.micrometer.core.instrument.FunctionCounter; import io.micrometer.core.instrument.binder.MeterBinder; import org.apache.dubbo.common.URL; import org.apache.dubbo.common.beans.factory.ScopeBeanFactory; -import org.apache.dubbo.common.constants.MetricsConstants; import org.apache.dubbo.common.lang.ShutdownHookCallbacks; import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; import org.apache.dubbo.common.logger.LoggerFactory; @@ -38,7 +37,6 @@ import org.apache.dubbo.rpc.model.ApplicationModel; import io.micrometer.core.instrument.Gauge; import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.Tag; -import io.micrometer.core.instrument.Tags; import io.micrometer.core.instrument.binder.jvm.ClassLoaderMetrics; import io.micrometer.core.instrument.binder.jvm.JvmGcMetrics; import io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics; @@ -49,7 +47,6 @@ import io.micrometer.core.instrument.composite.CompositeMeterRegistry; import java.util.ArrayList; import java.util.List; -import java.util.Optional; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @@ -112,21 +109,19 @@ public abstract class AbstractMetricsReporter implements MetricsReporter { private void addJvmMetrics() { boolean enableJvmMetrics = url.getParameter(ENABLE_JVM_METRICS_KEY, false); if (enableJvmMetrics) { - Tags extraTags = Tags.of(MetricsConstants.TAG_APPLICATION_NAME, - Optional.ofNullable(applicationModel.getApplicationName()).orElse("")); - new ClassLoaderMetrics(extraTags).bindTo(compositeRegistry); - new JvmMemoryMetrics(extraTags).bindTo(compositeRegistry); + new ClassLoaderMetrics().bindTo(compositeRegistry); + new JvmMemoryMetrics().bindTo(compositeRegistry); @SuppressWarnings("java:S2095") // Do not change JvmGcMetrics to try-with-resources as the JvmGcMetrics will not be available after (auto-)closing. // See https://github.com/micrometer-metrics/micrometer/issues/1492 - JvmGcMetrics jvmGcMetrics = new JvmGcMetrics(extraTags); + JvmGcMetrics jvmGcMetrics = new JvmGcMetrics(); jvmGcMetrics.bindTo(compositeRegistry); Runtime.getRuntime().addShutdownHook(new Thread(jvmGcMetrics::close)); - bindTo(new ProcessorMetrics(extraTags)); - new JvmThreadMetrics(extraTags).bindTo(compositeRegistry); - bindTo(new UptimeMetrics(extraTags)); + bindTo(new ProcessorMetrics()); + new JvmThreadMetrics().bindTo(compositeRegistry); + bindTo(new UptimeMetrics()); } } diff --git a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/rpc/cluster/filter/support/MetricsClusterFilter.java b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/rpc/cluster/filter/support/MetricsClusterFilter.java index 03c9018517..5634202384 100644 --- a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/rpc/cluster/filter/support/MetricsClusterFilter.java +++ b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/rpc/cluster/filter/support/MetricsClusterFilter.java @@ -22,7 +22,7 @@ import org.apache.dubbo.common.extension.Activate; import org.apache.dubbo.metrics.collector.DefaultMetricsCollector; import org.apache.dubbo.metrics.event.MetricsDispatcher; import org.apache.dubbo.metrics.event.MetricsEventBus; -import org.apache.dubbo.metrics.event.RequestBeforeEvent; +import org.apache.dubbo.metrics.event.RequestEvent; import org.apache.dubbo.rpc.BaseFilter; import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invoker; @@ -73,7 +73,7 @@ public class MetricsClusterFilter implements ClusterFilter, BaseFilter.Listener, if (t instanceof RpcException) { RpcException e = (RpcException) t; if (e.isForbidden()) { - MetricsEventBus.publish(RequestBeforeEvent.toEvent(applicationModel, appName, metricsDispatcher, invocation, CONSUMER_SIDE)); + MetricsEventBus.publish(RequestEvent.toRequestErrorEvent(applicationModel, appName, metricsDispatcher, invocation, CONSUMER_SIDE, e.getCode())); } } } diff --git a/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/AggregateMetricsCollectorTest.java b/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/AggregateMetricsCollectorTest.java index a99be4735d..652d335ab8 100644 --- a/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/AggregateMetricsCollectorTest.java +++ b/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/AggregateMetricsCollectorTest.java @@ -31,7 +31,6 @@ import org.apache.dubbo.metrics.TestMetricsInvoker; import org.apache.dubbo.metrics.aggregate.TimeWindowCounter; import org.apache.dubbo.metrics.event.MetricsDispatcher; import org.apache.dubbo.metrics.event.MetricsEventBus; -import org.apache.dubbo.metrics.event.RequestBeforeEvent; import org.apache.dubbo.metrics.event.RequestEvent; import org.apache.dubbo.metrics.filter.MetricsFilter; import org.apache.dubbo.metrics.listener.MetricsListener; @@ -143,9 +142,10 @@ class AggregateMetricsCollectorTest { void testListener() { AggregateMetricsCollector metricsCollector = new AggregateMetricsCollector(applicationModel); RequestEvent event = RequestEvent.toRequestEvent(applicationModel, null, null, null, invocation, MetricsSupport.getSide(invocation)); - RequestBeforeEvent beforeEvent = new RequestBeforeEvent(applicationModel, null, null, new TypeWrapper(MetricsLevel.METHOD, MetricsKey.METRIC_REQUESTS)); + RequestEvent beforeEvent = RequestEvent.toRequestErrorEvent(applicationModel, null, null, invocation, MetricsSupport.getSide(invocation), RpcException.FORBIDDEN_EXCEPTION); + Assertions.assertTrue(metricsCollector.isSupport(event)); - Assertions.assertFalse(metricsCollector.isSupport(beforeEvent)); + Assertions.assertTrue(metricsCollector.isSupport(beforeEvent)); } @AfterEach diff --git a/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/DefaultCollectorTest.java b/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/DefaultCollectorTest.java index 6113908990..450da8a7c6 100644 --- a/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/DefaultCollectorTest.java +++ b/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/DefaultCollectorTest.java @@ -22,7 +22,6 @@ import org.apache.dubbo.common.constants.CommonConstants; import org.apache.dubbo.config.ApplicationConfig; import org.apache.dubbo.metrics.TestMetricsInvoker; import org.apache.dubbo.metrics.event.MetricsDispatcher; -import org.apache.dubbo.metrics.event.RequestBeforeEvent; import org.apache.dubbo.metrics.event.RequestEvent; import org.apache.dubbo.metrics.filter.MetricsFilter; import org.apache.dubbo.metrics.model.MetricsSupport; @@ -114,7 +113,8 @@ class DefaultCollectorTest { void testListener() { DefaultMetricsCollector metricsCollector = new DefaultMetricsCollector(applicationModel); RequestEvent event = RequestEvent.toRequestEvent(applicationModel, null, null, null, invocation, MetricsSupport.getSide(invocation)); - RequestBeforeEvent beforeEvent = new RequestBeforeEvent(applicationModel, null, null, new TypeWrapper(MetricsLevel.METHOD, MetricsKey.METRIC_REQUESTS)); + RequestEvent beforeEvent = RequestEvent.toRequestErrorEvent(applicationModel, null, null, invocation, MetricsSupport.getSide(invocation), RpcException.FORBIDDEN_EXCEPTION); + Assertions.assertTrue(metricsCollector.isSupport(event)); Assertions.assertTrue(metricsCollector.isSupport(beforeEvent)); } diff --git a/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/metrics/model/sample/ErrorCodeSampleTest.java b/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/metrics/model/sample/ErrorCodeSampleTest.java new file mode 100644 index 0000000000..89b2ca5fa3 --- /dev/null +++ b/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/metrics/model/sample/ErrorCodeSampleTest.java @@ -0,0 +1,70 @@ +/* + * 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.dubbo.metrics.metrics.model.sample; + +import org.apache.dubbo.common.utils.Assert; +import org.apache.dubbo.common.utils.ReflectionUtils; +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.metrics.collector.DefaultMetricsCollector; +import org.apache.dubbo.metrics.collector.sample.ErrorCodeMetricsListenRegister; +import org.apache.dubbo.metrics.collector.sample.ErrorCodeSampler; +import org.apache.dubbo.metrics.model.sample.CounterMetricSample; +import org.apache.dubbo.metrics.model.sample.MetricSample; +import org.apache.dubbo.rpc.model.ApplicationModel; +import org.apache.dubbo.rpc.model.FrameworkModel; +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.concurrent.atomic.AtomicLong; + +public class ErrorCodeSampleTest { + + @Test + void testErrorCodeMetric() { + FrameworkModel frameworkModel = FrameworkModel.defaultModel(); + ApplicationModel applicationModel = frameworkModel.newApplication(); + + ApplicationConfig applicationConfig = new ApplicationConfig(); + applicationConfig.setName("MyApplication1"); + + applicationModel.getApplicationConfigManager().setApplication(applicationConfig); + + DefaultMetricsCollector defaultMetricsCollector = new DefaultMetricsCollector(applicationModel); + defaultMetricsCollector.setCollectEnabled(true); + + ErrorCodeSampler sampler = (ErrorCodeSampler) ReflectionUtils.getField(defaultMetricsCollector, "errorCodeSampler"); + + ErrorCodeMetricsListenRegister register = (ErrorCodeMetricsListenRegister) ReflectionUtils.getField(sampler, "register"); + + register.onMessage("0-1", null); + register.onMessage("0-1", null); + register.onMessage("0-2", null); + register.onMessage("0-2", null); + register.onMessage("1-2", null); + register.onMessage("1-2", null); + register.onMessage("1-3", null); + register.onMessage("1-3", null); + + List samples = defaultMetricsCollector.collect(); + + Assert.assertTrue(samples.size() == 4,"Wrong number of samples."); + samples.forEach(metricSample -> Assert.assertTrue(((AtomicLong)((CounterMetricSample)metricSample).getValue()).get() == 2L,"Sample count error.")); + + System.out.println(samples); + } +} diff --git a/dubbo-metrics/dubbo-metrics-netty/pom.xml b/dubbo-metrics/dubbo-metrics-netty/pom.xml new file mode 100644 index 0000000000..95067ef1b0 --- /dev/null +++ b/dubbo-metrics/dubbo-metrics-netty/pom.xml @@ -0,0 +1,40 @@ + + + 4.0.0 + + org.apache.dubbo + dubbo-metrics + ${revision} + ../pom.xml + + dubbo-metrics-netty + jar + ${project.artifactId} + The metrics module of dubbo project + + false + + + + org.apache.dubbo + dubbo-metrics-api + ${project.parent.version} + + + diff --git a/dubbo-metrics/dubbo-metrics-netty/src/main/java/org/apache/dubbo/metrics/registry/NettyMetricsConstants.java b/dubbo-metrics/dubbo-metrics-netty/src/main/java/org/apache/dubbo/metrics/registry/NettyMetricsConstants.java new file mode 100644 index 0000000000..236ba2d254 --- /dev/null +++ b/dubbo-metrics/dubbo-metrics-netty/src/main/java/org/apache/dubbo/metrics/registry/NettyMetricsConstants.java @@ -0,0 +1,44 @@ +/* + * 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.dubbo.metrics.registry; + +import org.apache.dubbo.metrics.model.key.MetricsKey; + +import java.util.Arrays; +import java.util.List; + +import static org.apache.dubbo.metrics.model.key.MetricsKey.NETTY_ALLOCATOR_CHUNK_SIZE; +import static org.apache.dubbo.metrics.model.key.MetricsKey.NETTY_ALLOCATOR_DIRECT_ARENAS_NUM; +import static org.apache.dubbo.metrics.model.key.MetricsKey.NETTY_ALLOCATOR_DIRECT_MEMORY_USED; +import static org.apache.dubbo.metrics.model.key.MetricsKey.NETTY_ALLOCATOR_HEAP_ARENAS_NUM; +import static org.apache.dubbo.metrics.model.key.MetricsKey.NETTY_ALLOCATOR_HEAP_MEMORY_USED; +import static org.apache.dubbo.metrics.model.key.MetricsKey.NETTY_ALLOCATOR_NORMAL_CACHE_SIZE; +import static org.apache.dubbo.metrics.model.key.MetricsKey.NETTY_ALLOCATOR_PINNED_DIRECT_MEMORY; +import static org.apache.dubbo.metrics.model.key.MetricsKey.NETTY_ALLOCATOR_PINNED_HEAP_MEMORY; +import static org.apache.dubbo.metrics.model.key.MetricsKey.NETTY_ALLOCATOR_SMALL_CACHE_SIZE; +import static org.apache.dubbo.metrics.model.key.MetricsKey.NETTY_ALLOCATOR_THREAD_LOCAL_CACHES_NUM; + +public interface NettyMetricsConstants { + + // App-level + List APP_LEVEL_KEYS = Arrays.asList(NETTY_ALLOCATOR_HEAP_MEMORY_USED,NETTY_ALLOCATOR_DIRECT_MEMORY_USED + ,NETTY_ALLOCATOR_PINNED_DIRECT_MEMORY,NETTY_ALLOCATOR_PINNED_HEAP_MEMORY,NETTY_ALLOCATOR_HEAP_ARENAS_NUM + ,NETTY_ALLOCATOR_DIRECT_ARENAS_NUM,NETTY_ALLOCATOR_NORMAL_CACHE_SIZE,NETTY_ALLOCATOR_SMALL_CACHE_SIZE,NETTY_ALLOCATOR_THREAD_LOCAL_CACHES_NUM + ,NETTY_ALLOCATOR_CHUNK_SIZE); + +} diff --git a/dubbo-metrics/dubbo-metrics-netty/src/main/java/org/apache/dubbo/metrics/registry/collector/NettyMetricsCollector.java b/dubbo-metrics/dubbo-metrics-netty/src/main/java/org/apache/dubbo/metrics/registry/collector/NettyMetricsCollector.java new file mode 100644 index 0000000000..e6d871c8db --- /dev/null +++ b/dubbo-metrics/dubbo-metrics-netty/src/main/java/org/apache/dubbo/metrics/registry/collector/NettyMetricsCollector.java @@ -0,0 +1,97 @@ +/* + * 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.dubbo.metrics.registry.collector; + +import org.apache.dubbo.common.extension.Activate; +import org.apache.dubbo.config.context.ConfigManager; +import org.apache.dubbo.metrics.collector.CombMetricsCollector; +import org.apache.dubbo.metrics.collector.MetricsCollector; +import org.apache.dubbo.metrics.data.ApplicationStatComposite; +import org.apache.dubbo.metrics.data.BaseStatComposite; +import org.apache.dubbo.metrics.data.RtStatComposite; +import org.apache.dubbo.metrics.data.ServiceStatComposite; +import org.apache.dubbo.metrics.model.MetricsCategory; +import org.apache.dubbo.metrics.model.sample.MetricSample; +import org.apache.dubbo.metrics.registry.NettyMetricsConstants; +import org.apache.dubbo.metrics.registry.event.NettyEvent; +import org.apache.dubbo.metrics.registry.event.NettySubDispatcher; +import org.apache.dubbo.rpc.model.ApplicationModel; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + + +/** + * Netty implementation of {@link MetricsCollector} + */ +@Activate +public class NettyMetricsCollector extends CombMetricsCollector { + + private Boolean collectEnabled = null; + private final ApplicationModel applicationModel; + + public NettyMetricsCollector(ApplicationModel applicationModel) { + super(new BaseStatComposite(applicationModel) { + @Override + protected void init(ApplicationStatComposite applicationStatComposite) { + super.init(applicationStatComposite); + applicationStatComposite.init(NettyMetricsConstants.APP_LEVEL_KEYS); + } + + @Override + protected void init(ServiceStatComposite serviceStatComposite) { + super.init(serviceStatComposite); + } + + @Override + protected void init(RtStatComposite rtStatComposite) { + super.init(rtStatComposite); + } + }); + super.setEventMulticaster(new NettySubDispatcher(this)); + this.applicationModel = applicationModel; + } + + public void setCollectEnabled(Boolean collectEnabled) { + if (collectEnabled != null) { + this.collectEnabled = collectEnabled; + } + } + + @Override + public boolean isCollectEnabled() { + if (collectEnabled == null) { + ConfigManager configManager = applicationModel.getApplicationConfigManager(); + configManager.getMetrics().ifPresent(metricsConfig -> setCollectEnabled(metricsConfig.getEnableNetty())); + } + return Optional.ofNullable(collectEnabled).orElse(true); + } + + + @Override + public List collect() { + List list = new ArrayList<>(); + if (!isCollectEnabled()) { + return list; + } + list.addAll(super.export(MetricsCategory.NETTY)); + return list; + } + +} diff --git a/dubbo-metrics/dubbo-metrics-netty/src/main/java/org/apache/dubbo/metrics/registry/event/NettyEvent.java b/dubbo-metrics/dubbo-metrics-netty/src/main/java/org/apache/dubbo/metrics/registry/event/NettyEvent.java new file mode 100644 index 0000000000..72c8aff56f --- /dev/null +++ b/dubbo-metrics/dubbo-metrics-netty/src/main/java/org/apache/dubbo/metrics/registry/event/NettyEvent.java @@ -0,0 +1,54 @@ +/* + * 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.dubbo.metrics.registry.event; + +import org.apache.dubbo.common.beans.factory.ScopeBeanFactory; +import org.apache.dubbo.metrics.event.TimeCounterEvent; +import org.apache.dubbo.metrics.model.key.MetricsLevel; +import org.apache.dubbo.metrics.model.key.TypeWrapper; +import org.apache.dubbo.metrics.registry.collector.NettyMetricsCollector; +import org.apache.dubbo.rpc.model.ApplicationModel; + +import static org.apache.dubbo.metrics.MetricsConstants.NETTY_METRICS_MAP; + + +/** + * Netty related events + */ +public class NettyEvent extends TimeCounterEvent { + public NettyEvent(ApplicationModel applicationModel, TypeWrapper typeWrapper) { + super(applicationModel,typeWrapper); + ScopeBeanFactory beanFactory = getSource().getBeanFactory(); + NettyMetricsCollector collector; + if (!beanFactory.isDestroyed()) { + collector = beanFactory.getBean(NettyMetricsCollector.class); + super.setAvailable(collector != null && collector.isCollectEnabled()); + } + } + + public static NettyEvent toNettyEvent(ApplicationModel applicationModel) { + return new NettyEvent(applicationModel, new TypeWrapper(MetricsLevel.APP, null,null, null)) { + @Override + public void customAfterPost(Object postResult) { + super.putAttachment(NETTY_METRICS_MAP, postResult); + } + }; + } + + +} diff --git a/dubbo-metrics/dubbo-metrics-netty/src/main/java/org/apache/dubbo/metrics/registry/event/NettySubDispatcher.java b/dubbo-metrics/dubbo-metrics-netty/src/main/java/org/apache/dubbo/metrics/registry/event/NettySubDispatcher.java new file mode 100644 index 0000000000..040014c3f2 --- /dev/null +++ b/dubbo-metrics/dubbo-metrics-netty/src/main/java/org/apache/dubbo/metrics/registry/event/NettySubDispatcher.java @@ -0,0 +1,53 @@ +/* + * 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.dubbo.metrics.registry.event; + +import org.apache.dubbo.metrics.event.MetricsEvent; +import org.apache.dubbo.metrics.event.SimpleMetricsEventMulticaster; +import org.apache.dubbo.metrics.event.TimeCounterEvent; +import org.apache.dubbo.metrics.listener.AbstractMetricsKeyListener; +import org.apache.dubbo.metrics.model.key.MetricsKey; +import org.apache.dubbo.metrics.registry.collector.NettyMetricsCollector; + +import java.util.Collections; + +import java.util.Map; + +import static org.apache.dubbo.metrics.MetricsConstants.NETTY_METRICS_MAP; + +public final class NettySubDispatcher extends SimpleMetricsEventMulticaster { + + public NettySubDispatcher(NettyMetricsCollector collector) { + super.addListener(new AbstractMetricsKeyListener(null) { + @Override + public boolean isSupport(MetricsEvent event) { + return true; + } + + @Override + public void onEventFinish(TimeCounterEvent event) { + Map lastNumMap = Collections.unmodifiableMap(event.getAttachmentValue(NETTY_METRICS_MAP)); + lastNumMap.forEach( + (k, v) -> { + MetricsKey metricsKey = MetricsKey.getMetricsByName(k); + collector.setAppNum(metricsKey, v); + }); + } + }); + } +} diff --git a/dubbo-metrics/dubbo-metrics-netty/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metrics.collector.MetricsCollector b/dubbo-metrics/dubbo-metrics-netty/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metrics.collector.MetricsCollector new file mode 100644 index 0000000000..29c24de5ad --- /dev/null +++ b/dubbo-metrics/dubbo-metrics-netty/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.metrics.collector.MetricsCollector @@ -0,0 +1 @@ +org.apache.dubbo.metrics.registry.collector.NettyMetricsCollector diff --git a/dubbo-metrics/dubbo-metrics-prometheus/src/test/java/org/apache/dubbo/metrics/prometheus/PrometheusMetricsReporterTest.java b/dubbo-metrics/dubbo-metrics-prometheus/src/test/java/org/apache/dubbo/metrics/prometheus/PrometheusMetricsReporterTest.java index e6aae6745d..6b4122753e 100644 --- a/dubbo-metrics/dubbo-metrics-prometheus/src/test/java/org/apache/dubbo/metrics/prometheus/PrometheusMetricsReporterTest.java +++ b/dubbo-metrics/dubbo-metrics-prometheus/src/test/java/org/apache/dubbo/metrics/prometheus/PrometheusMetricsReporterTest.java @@ -80,7 +80,7 @@ class PrometheusMetricsReporterTest { Double d2 = prometheusRegistry.getPrometheusRegistry().getSampleValue("jvm_gc_memory_promoted_bytes_total", new String[]{"application_name"}, new String[]{name}); Assertions.assertNull(d1); - Assertions.assertNotNull(d2); + Assertions.assertNull(d2); } @Test diff --git a/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/RegistryMetricsConstants.java b/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/RegistryMetricsConstants.java index e7adbc9622..18dac35bc6 100644 --- a/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/RegistryMetricsConstants.java +++ b/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/RegistryMetricsConstants.java @@ -23,6 +23,7 @@ import org.apache.dubbo.metrics.model.key.MetricsLevel; import org.apache.dubbo.metrics.model.key.MetricsPlaceValue; import java.util.Arrays; +import java.util.Collections; import java.util.List; import static org.apache.dubbo.metrics.model.key.MetricsKey.DIRECTORY_METRIC_NUM_ALL; @@ -46,17 +47,23 @@ import static org.apache.dubbo.metrics.model.key.MetricsKey.SUBSCRIBE_METRIC_NUM public interface RegistryMetricsConstants { + String ATTACHMENT_REGISTRY_KEY = "registryKey"; + String ATTACHMENT_REGISTRY_SINGLE_KEY = "registrySingleKey"; + MetricsPlaceValue OP_TYPE_REGISTER = MetricsPlaceValue.of("register", MetricsLevel.APP); MetricsPlaceValue OP_TYPE_SUBSCRIBE = MetricsPlaceValue.of("subscribe", MetricsLevel.APP); MetricsPlaceValue OP_TYPE_NOTIFY = MetricsPlaceValue.of("notify", MetricsLevel.APP); MetricsPlaceValue OP_TYPE_DIRECTORY = MetricsPlaceValue.of("directory", MetricsLevel.APP); - MetricsPlaceValue OP_TYPE_REGISTER_SERVICE = MetricsPlaceValue.of("register.service", MetricsLevel.SERVICE); + MetricsPlaceValue OP_TYPE_REGISTER_SERVICE = MetricsPlaceValue.of("register.service", MetricsLevel.REGISTRY); MetricsPlaceValue OP_TYPE_SUBSCRIBE_SERVICE = MetricsPlaceValue.of("subscribe.service", MetricsLevel.SERVICE); // App-level - List APP_LEVEL_KEYS = Arrays.asList(REGISTER_METRIC_REQUESTS, REGISTER_METRIC_REQUESTS_SUCCEED, REGISTER_METRIC_REQUESTS_FAILED, - SUBSCRIBE_METRIC_NUM, SUBSCRIBE_METRIC_NUM_SUCCEED, SUBSCRIBE_METRIC_NUM_FAILED, - NOTIFY_METRIC_REQUESTS); + List APP_LEVEL_KEYS = Collections.singletonList(NOTIFY_METRIC_REQUESTS); + + // Registry-level + List REGISTER_LEVEL_KEYS = Arrays.asList(REGISTER_METRIC_REQUESTS, REGISTER_METRIC_REQUESTS_SUCCEED, REGISTER_METRIC_REQUESTS_FAILED, + SUBSCRIBE_METRIC_NUM, SUBSCRIBE_METRIC_NUM_SUCCEED, SUBSCRIBE_METRIC_NUM_FAILED + ); // Service-level List SERVICE_LEVEL_KEYS = Arrays.asList( diff --git a/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/collector/RegistryMetricsCollector.java b/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/collector/RegistryMetricsCollector.java index b18ed313f7..b510ed541b 100644 --- a/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/collector/RegistryMetricsCollector.java +++ b/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/collector/RegistryMetricsCollector.java @@ -17,6 +17,7 @@ package org.apache.dubbo.metrics.registry.collector; +import org.apache.dubbo.common.constants.RegistryConstants; import org.apache.dubbo.common.extension.Activate; import org.apache.dubbo.config.context.ConfigManager; import org.apache.dubbo.metrics.collector.CombMetricsCollector; @@ -25,7 +26,11 @@ import org.apache.dubbo.metrics.data.ApplicationStatComposite; import org.apache.dubbo.metrics.data.BaseStatComposite; import org.apache.dubbo.metrics.data.RtStatComposite; import org.apache.dubbo.metrics.data.ServiceStatComposite; +import org.apache.dubbo.metrics.model.ApplicationMetric; import org.apache.dubbo.metrics.model.MetricsCategory; +import org.apache.dubbo.metrics.model.ServiceKeyMetric; +import org.apache.dubbo.metrics.model.key.MetricsKey; +import org.apache.dubbo.metrics.model.key.MetricsKeyWrapper; import org.apache.dubbo.metrics.model.sample.MetricSample; import org.apache.dubbo.metrics.registry.RegistryMetricsConstants; import org.apache.dubbo.metrics.registry.event.RegistryEvent; @@ -33,7 +38,9 @@ import org.apache.dubbo.metrics.registry.event.RegistrySubDispatcher; import org.apache.dubbo.rpc.model.ApplicationModel; import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.Optional; import static org.apache.dubbo.metrics.registry.RegistryMetricsConstants.OP_TYPE_NOTIFY; @@ -51,6 +58,7 @@ public class RegistryMetricsCollector extends CombMetricsCollector registryClusterNames) { + registryClusterNames.forEach(name -> internalStat.incrMetricsNum(metricsKey, name)); + } + + public void incrRegisterFinishNum(MetricsKey metricsKey, String registryOpType, List registryClusterNames, Long responseTime) { + registryClusterNames.forEach(name -> + { + ApplicationMetric applicationMetric = new ApplicationMetric(applicationModel); + applicationMetric.setExtraInfo(Collections.singletonMap(RegistryConstants.REGISTRY_CLUSTER_KEY.toLowerCase(), name)); + internalStat.incrMetricsNum(metricsKey, name); + getStats().getRtStatComposite().calcServiceKeyRt(registryOpType, responseTime, applicationMetric); + }); + + } + + public void incrServiceRegisterNum(MetricsKeyWrapper wrapper, String serviceKey, List registryClusterNames, int size) { + registryClusterNames.forEach(name -> + stats.incrementServiceKey(wrapper, serviceKey, Collections.singletonMap(RegistryConstants.REGISTRY_CLUSTER_KEY.toLowerCase(), name), size) + ); + } + + public void incrServiceRegisterFinishNum(MetricsKeyWrapper wrapper, String serviceKey, List registryClusterNames, int size, Long responseTime) { + registryClusterNames.forEach(name -> + { + Map extraInfo = Collections.singletonMap(RegistryConstants.REGISTRY_CLUSTER_KEY.toLowerCase(), name); + ServiceKeyMetric serviceKeyMetric = new ServiceKeyMetric(applicationModel, serviceKey); + serviceKeyMetric.setExtraInfo(extraInfo); + stats.incrementServiceKey(wrapper, serviceKey, extraInfo, size); + getStats().getRtStatComposite().calcServiceKeyRt(wrapper.getType(), responseTime, serviceKeyMetric); + } + ); + } + + public void setNum(MetricsKeyWrapper metricsKey, String serviceKey, int num, Map attachments) { + this.stats.setServiceKey(metricsKey, serviceKey, num, attachments); + } + } diff --git a/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/collector/RegistryStatComposite.java b/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/collector/RegistryStatComposite.java new file mode 100644 index 0000000000..a60c5c4b49 --- /dev/null +++ b/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/collector/RegistryStatComposite.java @@ -0,0 +1,81 @@ +/* + * 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.dubbo.metrics.registry.collector; + +import org.apache.dubbo.common.constants.RegistryConstants; +import org.apache.dubbo.common.utils.CollectionUtils; +import org.apache.dubbo.metrics.model.ApplicationMetric; +import org.apache.dubbo.metrics.model.MetricsCategory; +import org.apache.dubbo.metrics.model.MetricsSupport; +import org.apache.dubbo.metrics.model.key.MetricsKey; +import org.apache.dubbo.metrics.model.sample.GaugeMetricSample; +import org.apache.dubbo.metrics.model.sample.MetricSample; +import org.apache.dubbo.metrics.registry.RegistryMetricsConstants; +import org.apache.dubbo.metrics.report.AbstractMetricsExport; +import org.apache.dubbo.rpc.model.ApplicationModel; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicLong; + +import static org.apache.dubbo.metrics.MetricsConstants.SELF_INCREMENT_SIZE; + +public class RegistryStatComposite extends AbstractMetricsExport { + + private final Map> appStats = new ConcurrentHashMap<>(); + + public RegistryStatComposite(ApplicationModel applicationModel) { + super(applicationModel); + init(RegistryMetricsConstants.REGISTER_LEVEL_KEYS); + } + + public void init(List appKeys) { + if (CollectionUtils.isEmpty(appKeys)) { + return; + } + appKeys.forEach(appKey -> appStats.put(appKey, new ConcurrentHashMap<>())); + } + + @Override + public List export(MetricsCategory category) { + List list = new ArrayList<>(); + for (MetricsKey metricsKey : appStats.keySet()) { + Map stringAtomicLongMap = appStats.get(metricsKey); + for (ApplicationMetric registerKeyMetric : stringAtomicLongMap.keySet()) { + list.add(new GaugeMetricSample<>(metricsKey, registerKeyMetric.getTags(), category, stringAtomicLongMap, value -> value.get(registerKeyMetric).get())); + } + } + return list; + } + + public void incrMetricsNum(MetricsKey metricsKey, String name) { + if (!appStats.containsKey(metricsKey)) { + return; + } + ApplicationMetric applicationMetric = new ApplicationMetric(getApplicationModel()); + applicationMetric.setExtraInfo(Collections.singletonMap(RegistryConstants.REGISTRY_CLUSTER_KEY.toLowerCase(), name)); + appStats.get(metricsKey).computeIfAbsent(applicationMetric, k -> new AtomicLong(0L)).getAndAdd(SELF_INCREMENT_SIZE); + MetricsSupport.fillZero(appStats); + } + + public Map> getAppStats() { + return appStats; + } +} diff --git a/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/RegistryEvent.java b/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/RegistryEvent.java index 5ed721c695..97b9bac1ac 100644 --- a/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/RegistryEvent.java +++ b/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/RegistryEvent.java @@ -22,9 +22,12 @@ import org.apache.dubbo.metrics.event.TimeCounterEvent; import org.apache.dubbo.metrics.model.key.MetricsKey; import org.apache.dubbo.metrics.model.key.MetricsLevel; import org.apache.dubbo.metrics.model.key.TypeWrapper; +import org.apache.dubbo.metrics.registry.RegistryMetricsConstants; import org.apache.dubbo.metrics.registry.collector.RegistryMetricsCollector; import org.apache.dubbo.rpc.model.ApplicationModel; +import java.util.Collections; +import java.util.List; import java.util.Map; import static org.apache.dubbo.metrics.MetricsConstants.ATTACHMENT_DIRECTORY_MAP; @@ -48,18 +51,25 @@ public class RegistryEvent extends TimeCounterEvent { } private static final TypeWrapper REGISTER_EVENT = new TypeWrapper(MetricsLevel.APP, MetricsKey.REGISTER_METRIC_REQUESTS, MetricsKey.REGISTER_METRIC_REQUESTS_SUCCEED, MetricsKey.REGISTER_METRIC_REQUESTS_FAILED); - public static RegistryEvent toRegisterEvent(ApplicationModel applicationModel) { - return new RegistryEvent(applicationModel, REGISTER_EVENT); + + public static RegistryEvent toRegisterEvent(ApplicationModel applicationModel, List registryClusterNames) { + RegistryEvent registryEvent = new RegistryEvent(applicationModel, REGISTER_EVENT); + registryEvent.putAttachment(RegistryMetricsConstants.ATTACHMENT_REGISTRY_KEY, registryClusterNames); + return registryEvent; } private static final TypeWrapper SUBSCRIBE_EVENT = new TypeWrapper(MetricsLevel.APP, MetricsKey.SUBSCRIBE_METRIC_NUM, MetricsKey.SUBSCRIBE_METRIC_NUM_SUCCEED, MetricsKey.SUBSCRIBE_METRIC_NUM_FAILED); - public static RegistryEvent toSubscribeEvent(ApplicationModel applicationModel) { - return new RegistryEvent(applicationModel, SUBSCRIBE_EVENT); + + public static RegistryEvent toSubscribeEvent(ApplicationModel applicationModel, String registryClusterName) { + RegistryEvent ddEvent = new RegistryEvent(applicationModel, SUBSCRIBE_EVENT); + ddEvent.putAttachment(RegistryMetricsConstants.ATTACHMENT_REGISTRY_KEY, Collections.singletonList(registryClusterName)); + return ddEvent; } private static final TypeWrapper NOTIFY_EVENT = new TypeWrapper(MetricsLevel.APP, MetricsKey.NOTIFY_METRIC_REQUESTS, MetricsKey.NOTIFY_METRIC_NUM_LAST, (MetricsKey) null); + public static RegistryEvent toNotifyEvent(ApplicationModel applicationModel) { return new RegistryEvent(applicationModel, NOTIFY_EVENT) { @Override @@ -70,24 +80,31 @@ public class RegistryEvent extends TimeCounterEvent { } private static final TypeWrapper RS_EVENT = new TypeWrapper(MetricsLevel.SERVICE, MetricsKey.SERVICE_REGISTER_METRIC_REQUESTS, MetricsKey.SERVICE_REGISTER_METRIC_REQUESTS_SUCCEED, MetricsKey.SERVICE_REGISTER_METRIC_REQUESTS_FAILED); - public static RegistryEvent toRsEvent(ApplicationModel applicationModel, String serviceKey, int size) { + + public static RegistryEvent toRsEvent(ApplicationModel applicationModel, String serviceKey, int size, List serviceDiscoveryNames) { RegistryEvent ddEvent = new RegistryEvent(applicationModel, RS_EVENT); ddEvent.putAttachment(ATTACHMENT_KEY_SERVICE, serviceKey); ddEvent.putAttachment(ATTACHMENT_KEY_SIZE, size); + ddEvent.putAttachment(RegistryMetricsConstants.ATTACHMENT_REGISTRY_KEY, serviceDiscoveryNames); return ddEvent; } private static final TypeWrapper SS_EVENT = new TypeWrapper(MetricsLevel.SERVICE, MetricsKey.SERVICE_SUBSCRIBE_METRIC_NUM, MetricsKey.SERVICE_SUBSCRIBE_METRIC_NUM_SUCCEED, MetricsKey.SERVICE_SUBSCRIBE_METRIC_NUM_FAILED); - public static RegistryEvent toSsEvent(ApplicationModel applicationModel, String serviceKey) { + + public static RegistryEvent toSsEvent(ApplicationModel applicationModel, String serviceKey, List serviceDiscoveryNames) { RegistryEvent ddEvent = new RegistryEvent(applicationModel, SS_EVENT); ddEvent.putAttachment(ATTACHMENT_KEY_SERVICE, serviceKey); + ddEvent.putAttachment(ATTACHMENT_KEY_SIZE, 1); + ddEvent.putAttachment(RegistryMetricsConstants.ATTACHMENT_REGISTRY_KEY, serviceDiscoveryNames); return ddEvent; } private static final TypeWrapper DIRECTORY_EVENT = new TypeWrapper(MetricsLevel.APP, MetricsKey.DIRECTORY_METRIC_NUM_VALID, null, null); - public static RegistryEvent refreshDirectoryEvent(ApplicationModel applicationModel, Map> summaryMap) { + + public static RegistryEvent refreshDirectoryEvent(ApplicationModel applicationModel, Map> summaryMap, Map attachments) { RegistryEvent registryEvent = new RegistryEvent(applicationModel, DIRECTORY_EVENT); registryEvent.putAttachment(ATTACHMENT_DIRECTORY_MAP, summaryMap); + registryEvent.putAttachments(attachments); return registryEvent; } diff --git a/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/RegistrySpecListener.java b/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/RegistrySpecListener.java new file mode 100644 index 0000000000..6e44fea1b1 --- /dev/null +++ b/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/RegistrySpecListener.java @@ -0,0 +1,154 @@ +/* + * 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.dubbo.metrics.registry.event; + +import org.apache.dubbo.common.utils.CollectionUtils; +import org.apache.dubbo.metrics.collector.CombMetricsCollector; +import org.apache.dubbo.metrics.event.MetricsEvent; +import org.apache.dubbo.metrics.listener.AbstractMetricsKeyListener; +import org.apache.dubbo.metrics.listener.MetricsApplicationListener; +import org.apache.dubbo.metrics.model.key.MetricsKey; +import org.apache.dubbo.metrics.model.key.MetricsKeyWrapper; +import org.apache.dubbo.metrics.model.key.MetricsPlaceValue; +import org.apache.dubbo.metrics.registry.RegistryMetricsConstants; +import org.apache.dubbo.metrics.registry.collector.RegistryMetricsCollector; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import static org.apache.dubbo.metrics.MetricsConstants.ATTACHMENT_DIRECTORY_MAP; +import static org.apache.dubbo.metrics.MetricsConstants.ATTACHMENT_KEY_LAST_NUM_MAP; +import static org.apache.dubbo.metrics.MetricsConstants.ATTACHMENT_KEY_SERVICE; +import static org.apache.dubbo.metrics.MetricsConstants.ATTACHMENT_KEY_SIZE; +import static org.apache.dubbo.metrics.registry.RegistryMetricsConstants.OP_TYPE_DIRECTORY; +import static org.apache.dubbo.metrics.registry.RegistryMetricsConstants.OP_TYPE_NOTIFY; +import static org.apache.dubbo.metrics.registry.RegistryMetricsConstants.OP_TYPE_REGISTER; + +/** + * Different from the general-purpose listener constructor {@link MetricsApplicationListener} , + * it provides registry custom listeners + */ +public class RegistrySpecListener { + + /** + * Perform auto-increment on the monitored key, + * Can use a custom listener instead of this generic operation + */ + public static AbstractMetricsKeyListener onPost(MetricsKey metricsKey, CombMetricsCollector collector) { + return AbstractMetricsKeyListener.onEvent(metricsKey, + event -> ((RegistryMetricsCollector) collector).incrMetricsNum(metricsKey, getRgs(event)) + ); + } + + public static AbstractMetricsKeyListener onFinish(MetricsKey metricsKey, CombMetricsCollector collector) { + return AbstractMetricsKeyListener.onFinish(metricsKey, + event -> ((RegistryMetricsCollector) collector).incrRegisterFinishNum(metricsKey, OP_TYPE_REGISTER.getType(), getRgs(event), event.getTimePair().calc()) + ); + } + + public static AbstractMetricsKeyListener onError(MetricsKey metricsKey, CombMetricsCollector collector) { + return AbstractMetricsKeyListener.onError(metricsKey, + event -> ((RegistryMetricsCollector) collector).incrRegisterFinishNum(metricsKey, OP_TYPE_REGISTER.getType(), getRgs(event), event.getTimePair().calc()) + ); + } + + public static AbstractMetricsKeyListener onPostOfService(MetricsKey metricsKey, MetricsPlaceValue placeType, CombMetricsCollector collector) { + return AbstractMetricsKeyListener.onEvent(metricsKey, + event -> ((RegistryMetricsCollector) collector).incrServiceRegisterNum(new MetricsKeyWrapper(metricsKey, placeType), getServiceKey(event), getRgs(event), getSize(event)) + ); + } + + public static AbstractMetricsKeyListener onFinishOfService(MetricsKey metricsKey, MetricsPlaceValue placeType, CombMetricsCollector collector) { + return AbstractMetricsKeyListener.onFinish(metricsKey, + event -> ((RegistryMetricsCollector) collector).incrServiceRegisterFinishNum(new MetricsKeyWrapper(metricsKey, placeType), getServiceKey(event), getRgs(event), getSize(event), event.getTimePair().calc()) + ); + } + + public static AbstractMetricsKeyListener onErrorOfService(MetricsKey metricsKey, MetricsPlaceValue placeType, CombMetricsCollector collector) { + return AbstractMetricsKeyListener.onError(metricsKey, + event -> ((RegistryMetricsCollector) collector).incrServiceRegisterFinishNum(new MetricsKeyWrapper(metricsKey, placeType), getServiceKey(event), getRgs(event), getSize(event), event.getTimePair().calc()) + ); + } + + /** + * Every time an event is triggered, multiple serviceKey related to notify are increment + */ + public static AbstractMetricsKeyListener onFinishOfNotify(MetricsKey metricsKey, MetricsPlaceValue placeType, CombMetricsCollector collector) { + return AbstractMetricsKeyListener.onFinish(metricsKey, + event -> + { + collector.addServiceRt(event.appName(), placeType.getType(), event.getTimePair().calc()); + Map lastNumMap = Collections.unmodifiableMap(event.getAttachmentValue(ATTACHMENT_KEY_LAST_NUM_MAP)); + lastNumMap.forEach( + (k, v) -> collector.setNum(new MetricsKeyWrapper(metricsKey, OP_TYPE_NOTIFY), k, v)); + } + ); + } + + /** + * Every time an event is triggered, multiple fixed key related to directory are increment, which has nothing to do with the monitored key + */ + public static AbstractMetricsKeyListener onPostOfDirectory(MetricsKey metricsKey, CombMetricsCollector collector) { + return AbstractMetricsKeyListener.onEvent(metricsKey, + event -> { + Map> summaryMap = event.getAttachmentValue(ATTACHMENT_DIRECTORY_MAP); + Map otherAttachments = new HashMap<>(); + for (Map.Entry entry : event.getAttachments().entrySet()) { + if (entry.getValue() instanceof String) { + otherAttachments.put(entry.getKey().toLowerCase(Locale.ROOT), (String) entry.getValue()); + } + } + summaryMap.forEach((summaryKey, map) -> + map.forEach( + (k, v) -> + { + if (CollectionUtils.isEmptyMap(otherAttachments)) { + collector.setNum(new MetricsKeyWrapper(summaryKey, OP_TYPE_DIRECTORY), k, v); + } else { + ((RegistryMetricsCollector) collector).setNum(new MetricsKeyWrapper(summaryKey, OP_TYPE_DIRECTORY), k, v, otherAttachments); + } + } + + )); + + } + ); + } + + + /** + * Get the number of multiple registries + */ + public static List getRgs(MetricsEvent event) { + return event.getAttachmentValue(RegistryMetricsConstants.ATTACHMENT_REGISTRY_KEY); + } + + /** + * Get the exposed number of the protocol + */ + public static int getSize(MetricsEvent event) { + return event.getAttachmentValue(ATTACHMENT_KEY_SIZE); + } + + public static String getServiceKey(MetricsEvent event) { + return event.getAttachmentValue(ATTACHMENT_KEY_SERVICE); + } + +} diff --git a/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/RegistrySubDispatcher.java b/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/RegistrySubDispatcher.java index fd314443db..27cbcb4f61 100644 --- a/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/RegistrySubDispatcher.java +++ b/dubbo-metrics/dubbo-metrics-registry/src/main/java/org/apache/dubbo/metrics/registry/event/RegistrySubDispatcher.java @@ -18,22 +18,15 @@ package org.apache.dubbo.metrics.registry.event; import org.apache.dubbo.metrics.event.SimpleMetricsEventMulticaster; -import org.apache.dubbo.metrics.listener.AbstractMetricsKeyListener; import org.apache.dubbo.metrics.listener.MetricsApplicationListener; -import org.apache.dubbo.metrics.listener.MetricsServiceListener; import org.apache.dubbo.metrics.model.key.CategoryOverall; import org.apache.dubbo.metrics.model.key.MetricsCat; import org.apache.dubbo.metrics.model.key.MetricsKey; -import org.apache.dubbo.metrics.model.key.MetricsKeyWrapper; import org.apache.dubbo.metrics.registry.collector.RegistryMetricsCollector; import java.util.Arrays; -import java.util.Collections; import java.util.List; -import java.util.Map; -import static org.apache.dubbo.metrics.MetricsConstants.ATTACHMENT_DIRECTORY_MAP; -import static org.apache.dubbo.metrics.MetricsConstants.ATTACHMENT_KEY_LAST_NUM_MAP; import static org.apache.dubbo.metrics.registry.RegistryMetricsConstants.OP_TYPE_DIRECTORY; import static org.apache.dubbo.metrics.registry.RegistryMetricsConstants.OP_TYPE_NOTIFY; import static org.apache.dubbo.metrics.registry.RegistryMetricsConstants.OP_TYPE_REGISTER; @@ -74,55 +67,37 @@ public final class RegistrySubDispatcher extends SimpleMetricsEventMulticaster { /** - * {@link MetricsCat} MetricsCat collection, for better classification processing - * Except for a few custom functions, most of them can build standard event listening functions through the static methods of MetricsApplicationListener + * {@link MetricsCat} MetricsCat collection, for better classification processing + * Except for a few custom functions, most of them can build standard event listening functions through the static methods of MetricsApplicationListener */ interface MCat { // MetricsRegisterListener - MetricsCat APPLICATION_REGISTER_POST = new MetricsCat(MetricsKey.REGISTER_METRIC_REQUESTS, MetricsApplicationListener::onPostEventBuild); - MetricsCat APPLICATION_REGISTER_FINISH = new MetricsCat(MetricsKey.REGISTER_METRIC_REQUESTS_SUCCEED, MetricsApplicationListener::onFinishEventBuild); - MetricsCat APPLICATION_REGISTER_ERROR = new MetricsCat(MetricsKey.REGISTER_METRIC_REQUESTS_FAILED, MetricsApplicationListener::onErrorEventBuild); + MetricsCat APPLICATION_REGISTER_POST = new MetricsCat(MetricsKey.REGISTER_METRIC_REQUESTS, RegistrySpecListener::onPost); + MetricsCat APPLICATION_REGISTER_FINISH = new MetricsCat(MetricsKey.REGISTER_METRIC_REQUESTS_SUCCEED, RegistrySpecListener::onFinish); + MetricsCat APPLICATION_REGISTER_ERROR = new MetricsCat(MetricsKey.REGISTER_METRIC_REQUESTS_FAILED, RegistrySpecListener::onError); // MetricsSubscribeListener - MetricsCat APPLICATION_SUBSCRIBE_POST = new MetricsCat(MetricsKey.SUBSCRIBE_METRIC_NUM, MetricsApplicationListener::onPostEventBuild); - MetricsCat APPLICATION_SUBSCRIBE_FINISH = new MetricsCat(MetricsKey.SUBSCRIBE_METRIC_NUM_SUCCEED, MetricsApplicationListener::onFinishEventBuild); - MetricsCat APPLICATION_SUBSCRIBE_ERROR = new MetricsCat(MetricsKey.SUBSCRIBE_METRIC_NUM_FAILED, MetricsApplicationListener::onErrorEventBuild); + MetricsCat APPLICATION_SUBSCRIBE_POST = new MetricsCat(MetricsKey.SUBSCRIBE_METRIC_NUM, RegistrySpecListener::onPost); + MetricsCat APPLICATION_SUBSCRIBE_FINISH = new MetricsCat(MetricsKey.SUBSCRIBE_METRIC_NUM_SUCCEED, RegistrySpecListener::onFinish); + MetricsCat APPLICATION_SUBSCRIBE_ERROR = new MetricsCat(MetricsKey.SUBSCRIBE_METRIC_NUM_FAILED, RegistrySpecListener::onError); // MetricsNotifyListener MetricsCat APPLICATION_NOTIFY_POST = new MetricsCat(MetricsKey.NOTIFY_METRIC_REQUESTS, MetricsApplicationListener::onPostEventBuild); - MetricsCat APPLICATION_NOTIFY_FINISH = new MetricsCat(MetricsKey.NOTIFY_METRIC_NUM_LAST, - (key, placeType, collector) -> AbstractMetricsKeyListener.onFinish(key, - event -> { - collector.addServiceRt(event.appName(), placeType.getType(), event.getTimePair().calc()); - Map lastNumMap = Collections.unmodifiableMap(event.getAttachmentValue(ATTACHMENT_KEY_LAST_NUM_MAP)); - lastNumMap.forEach( - (k, v) -> collector.setNum(new MetricsKeyWrapper(key, OP_TYPE_NOTIFY), k, v)); + MetricsCat APPLICATION_NOTIFY_FINISH = new MetricsCat(MetricsKey.NOTIFY_METRIC_NUM_LAST, RegistrySpecListener::onFinishOfNotify); - } - )); - - - MetricsCat APPLICATION_DIRECTORY_POST = new MetricsCat(MetricsKey.DIRECTORY_METRIC_NUM_VALID, (key, placeType, collector) -> AbstractMetricsKeyListener.onEvent(key, - event -> - { - Map> summaryMap = event.getAttachmentValue(ATTACHMENT_DIRECTORY_MAP); - summaryMap.forEach((metricsKey, map) -> - map.forEach( - (k, v) -> collector.setNum(new MetricsKeyWrapper(metricsKey, OP_TYPE_DIRECTORY), k, v))); - } - )); + MetricsCat APPLICATION_DIRECTORY_POST = new MetricsCat(MetricsKey.DIRECTORY_METRIC_NUM_VALID, RegistrySpecListener::onPostOfDirectory); // MetricsServiceRegisterListener - MetricsCat SERVICE_REGISTER_POST = new MetricsCat(MetricsKey.SERVICE_REGISTER_METRIC_REQUESTS, MetricsServiceListener::onPostEventBuild); - MetricsCat SERVICE_REGISTER_FINISH = new MetricsCat(MetricsKey.SERVICE_REGISTER_METRIC_REQUESTS_SUCCEED, MetricsServiceListener::onFinishEventBuild); - MetricsCat SERVICE_REGISTER_ERROR = new MetricsCat(MetricsKey.SERVICE_REGISTER_METRIC_REQUESTS_FAILED, MetricsServiceListener::onErrorEventBuild); + MetricsCat SERVICE_REGISTER_POST = new MetricsCat(MetricsKey.SERVICE_REGISTER_METRIC_REQUESTS, RegistrySpecListener::onPostOfService); + MetricsCat SERVICE_REGISTER_FINISH = new MetricsCat(MetricsKey.SERVICE_REGISTER_METRIC_REQUESTS_SUCCEED, RegistrySpecListener::onFinishOfService); + MetricsCat SERVICE_REGISTER_ERROR = new MetricsCat(MetricsKey.SERVICE_REGISTER_METRIC_REQUESTS_FAILED, RegistrySpecListener::onErrorOfService); // MetricsServiceSubscribeListener - MetricsCat SERVICE_SUBSCRIBE_POST = new MetricsCat(MetricsKey.SERVICE_SUBSCRIBE_METRIC_NUM, MetricsServiceListener::onPostEventBuild); - MetricsCat SERVICE_SUBSCRIBE_FINISH = new MetricsCat(MetricsKey.SERVICE_SUBSCRIBE_METRIC_NUM_SUCCEED, MetricsServiceListener::onFinishEventBuild); - MetricsCat SERVICE_SUBSCRIBE_ERROR = new MetricsCat(MetricsKey.SERVICE_SUBSCRIBE_METRIC_NUM_FAILED, MetricsServiceListener::onErrorEventBuild); + MetricsCat SERVICE_SUBSCRIBE_POST = new MetricsCat(MetricsKey.SERVICE_SUBSCRIBE_METRIC_NUM, RegistrySpecListener::onPostOfService); + MetricsCat SERVICE_SUBSCRIBE_FINISH = new MetricsCat(MetricsKey.SERVICE_SUBSCRIBE_METRIC_NUM_SUCCEED, RegistrySpecListener::onFinishOfService); + MetricsCat SERVICE_SUBSCRIBE_ERROR = new MetricsCat(MetricsKey.SERVICE_SUBSCRIBE_METRIC_NUM_FAILED, RegistrySpecListener::onErrorOfService); } diff --git a/dubbo-metrics/dubbo-metrics-registry/src/test/java/org/apache/dubbo/metrics/registry/metrics/collector/RegistryMetricsCollectorTest.java b/dubbo-metrics/dubbo-metrics-registry/src/test/java/org/apache/dubbo/metrics/registry/metrics/collector/RegistryMetricsCollectorTest.java index 00352ecf2a..ff289caca3 100644 --- a/dubbo-metrics/dubbo-metrics-registry/src/test/java/org/apache/dubbo/metrics/registry/metrics/collector/RegistryMetricsCollectorTest.java +++ b/dubbo-metrics/dubbo-metrics-registry/src/test/java/org/apache/dubbo/metrics/registry/metrics/collector/RegistryMetricsCollectorTest.java @@ -17,6 +17,7 @@ package org.apache.dubbo.metrics.registry.metrics.collector; +import com.google.common.collect.Lists; import org.apache.dubbo.config.ApplicationConfig; import org.apache.dubbo.metrics.event.MetricsDispatcher; import org.apache.dubbo.metrics.event.MetricsEventBus; @@ -30,12 +31,12 @@ import org.apache.dubbo.metrics.registry.collector.RegistryMetricsCollector; import org.apache.dubbo.metrics.registry.event.RegistryEvent; import org.apache.dubbo.rpc.model.ApplicationModel; import org.apache.dubbo.rpc.model.FrameworkModel; - import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -43,9 +44,11 @@ import java.util.Objects; import java.util.stream.Collectors; import static org.apache.dubbo.common.constants.MetricsConstants.TAG_APPLICATION_NAME; +import static org.apache.dubbo.metrics.registry.RegistryMetricsConstants.APP_LEVEL_KEYS; import static org.apache.dubbo.metrics.registry.RegistryMetricsConstants.OP_TYPE_REGISTER; import static org.apache.dubbo.metrics.registry.RegistryMetricsConstants.OP_TYPE_REGISTER_SERVICE; import static org.apache.dubbo.metrics.registry.RegistryMetricsConstants.OP_TYPE_SUBSCRIBE_SERVICE; +import static org.apache.dubbo.metrics.registry.RegistryMetricsConstants.REGISTER_LEVEL_KEYS; class RegistryMetricsCollectorTest { @@ -74,12 +77,12 @@ class RegistryMetricsCollectorTest { @Test void testRegisterMetrics() { - RegistryEvent registryEvent = RegistryEvent.toRegisterEvent(applicationModel); + RegistryEvent registryEvent = RegistryEvent.toRegisterEvent(applicationModel, Lists.newArrayList("reg1")); MetricsEventBus.post(registryEvent, () -> { List metricSamples = collector.collect(); - // push success +1 -> other default 0 = RegistryMetricsConstants.APP_LEVEL_KEYS.size() - Assertions.assertEquals(RegistryMetricsConstants.APP_LEVEL_KEYS.size(), metricSamples.size()); + // push success +1 -> other default 0 = APP_LEVEL_KEYS.size() + Assertions.assertEquals(APP_LEVEL_KEYS.size() + REGISTER_LEVEL_KEYS.size(), metricSamples.size()); Assertions.assertTrue(metricSamples.stream().allMatch(metricSample -> metricSample instanceof GaugeMetricSample)); Assertions.assertTrue(metricSamples.stream().anyMatch(metricSample -> ((GaugeMetricSample) metricSample).applyAsDouble() == 1)); return null; @@ -88,12 +91,12 @@ class RegistryMetricsCollectorTest { // push finish rt +1 List metricSamples = collector.collect(); - // RegistryMetricsConstants.APP_LEVEL_KEYS.size() + rt(5) = 12 - Assertions.assertEquals(RegistryMetricsConstants.APP_LEVEL_KEYS.size() + 5, metricSamples.size()); + // APP_LEVEL_KEYS.size() + rt(5) = 12 + Assertions.assertEquals(APP_LEVEL_KEYS.size() + REGISTER_LEVEL_KEYS.size() + 5, metricSamples.size()); long c1 = registryEvent.getTimePair().calc(); - registryEvent = RegistryEvent.toRegisterEvent(applicationModel); + registryEvent = RegistryEvent.toRegisterEvent(applicationModel, Lists.newArrayList("reg1")); TimePair lastTimePair = registryEvent.getTimePair(); MetricsEventBus.post(registryEvent, () -> { @@ -111,7 +114,7 @@ class RegistryMetricsCollectorTest { metricSamples = collector.collect(); // num(total+success+error) + rt(5) - Assertions.assertEquals(RegistryMetricsConstants.APP_LEVEL_KEYS.size() + 5, metricSamples.size()); + Assertions.assertEquals(APP_LEVEL_KEYS.size() + REGISTER_LEVEL_KEYS.size() + 5, metricSamples.size()); // calc rt for (MetricSample sample : metricSamples) { @@ -134,8 +137,9 @@ class RegistryMetricsCollectorTest { void testServicePushMetrics() { String serviceName = "demo.gameService"; + List rcNames = Lists.newArrayList("demo1"); - RegistryEvent registryEvent = RegistryEvent.toRsEvent(applicationModel, serviceName, 2); + RegistryEvent registryEvent = RegistryEvent.toRsEvent(applicationModel, serviceName, 2, rcNames); MetricsEventBus.post(registryEvent, () -> { List metricSamples = collector.collect(); @@ -154,7 +158,7 @@ class RegistryMetricsCollectorTest { Assertions.assertEquals(RegistryMetricsConstants.APP_LEVEL_KEYS.size() + 5 + 2, metricSamples.size()); long c1 = registryEvent.getTimePair().calc(); - registryEvent = RegistryEvent.toRsEvent(applicationModel, serviceName, 2); + registryEvent = RegistryEvent.toRsEvent(applicationModel, serviceName, 2, rcNames); TimePair lastTimePair = registryEvent.getTimePair(); MetricsEventBus.post(registryEvent, () -> { @@ -196,7 +200,7 @@ class RegistryMetricsCollectorTest { String serviceName = "demo.gameService"; - RegistryEvent subscribeEvent = RegistryEvent.toSsEvent(applicationModel, serviceName); + RegistryEvent subscribeEvent = RegistryEvent.toSsEvent(applicationModel, serviceName, Collections.singletonList("demo1")); MetricsEventBus.post(subscribeEvent, () -> { List metricSamples = collector.collect(); @@ -216,7 +220,7 @@ class RegistryMetricsCollectorTest { Assertions.assertEquals(RegistryMetricsConstants.APP_LEVEL_KEYS.size() + 5 + 2, metricSamples.size()); long c1 = subscribeEvent.getTimePair().calc(); - subscribeEvent = RegistryEvent.toSsEvent(applicationModel, serviceName); + subscribeEvent = RegistryEvent.toSsEvent(applicationModel, serviceName, Collections.singletonList("demo1")); TimePair lastTimePair = subscribeEvent.getTimePair(); MetricsEventBus.post(subscribeEvent, () -> { diff --git a/dubbo-metrics/dubbo-metrics-registry/src/test/java/org/apache/dubbo/metrics/registry/metrics/collector/RegistryMetricsTest.java b/dubbo-metrics/dubbo-metrics-registry/src/test/java/org/apache/dubbo/metrics/registry/metrics/collector/RegistryMetricsTest.java index 0e1bf07346..3187161fad 100644 --- a/dubbo-metrics/dubbo-metrics-registry/src/test/java/org/apache/dubbo/metrics/registry/metrics/collector/RegistryMetricsTest.java +++ b/dubbo-metrics/dubbo-metrics-registry/src/test/java/org/apache/dubbo/metrics/registry/metrics/collector/RegistryMetricsTest.java @@ -17,6 +17,7 @@ package org.apache.dubbo.metrics.registry.metrics.collector; +import com.google.common.collect.Lists; import org.apache.dubbo.config.ApplicationConfig; import org.apache.dubbo.config.MetricsConfig; import org.apache.dubbo.config.context.ConfigManager; @@ -24,11 +25,11 @@ import org.apache.dubbo.config.nested.AggregationConfig; import org.apache.dubbo.metrics.model.key.MetricsKey; import org.apache.dubbo.metrics.model.sample.GaugeMetricSample; import org.apache.dubbo.metrics.model.sample.MetricSample; +import org.apache.dubbo.metrics.registry.RegistryMetricsConstants; import org.apache.dubbo.metrics.registry.collector.RegistryMetricsCollector; import org.apache.dubbo.metrics.registry.event.RegistryEvent; import org.apache.dubbo.rpc.model.ApplicationModel; import org.apache.dubbo.rpc.model.FrameworkModel; - import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -221,9 +222,9 @@ public class RegistryMetricsTest { } List samples = collector.collect(); - GaugeMetricSample succeedRequests = getSample(MetricsKey.SERVICE_REGISTER_METRIC_REQUESTS_SUCCEED.getName(), samples); - GaugeMetricSample failedRequests = getSample(MetricsKey.SERVICE_REGISTER_METRIC_REQUESTS_FAILED.getName(), samples); - GaugeMetricSample totalRequests = getSample(MetricsKey.SERVICE_REGISTER_METRIC_REQUESTS.getName(), samples); + GaugeMetricSample succeedRequests = getSample(MetricsKey.SERVICE_REGISTER_METRIC_REQUESTS_SUCCEED.getNameByType(RegistryMetricsConstants.OP_TYPE_REGISTER_SERVICE.getType()), samples); + GaugeMetricSample failedRequests = getSample(MetricsKey.SERVICE_REGISTER_METRIC_REQUESTS_FAILED.getNameByType(RegistryMetricsConstants.OP_TYPE_REGISTER_SERVICE.getType()), samples); + GaugeMetricSample totalRequests = getSample(MetricsKey.SERVICE_REGISTER_METRIC_REQUESTS.getNameByType(RegistryMetricsConstants.OP_TYPE_REGISTER_SERVICE.getType()), samples); Assertions.assertEquals(5L, succeedRequests.applyAsLong()); Assertions.assertEquals(5L, failedRequests.applyAsLong()); @@ -289,19 +290,20 @@ public class RegistryMetricsTest { } RegistryEvent registerEvent() { - RegistryEvent event = RegistryEvent.toRegisterEvent(applicationModel); + RegistryEvent event = RegistryEvent.toRegisterEvent(applicationModel, Lists.newArrayList("reg1")); event.setAvailable(true); return event; } RegistryEvent rsEvent() { - RegistryEvent event = RegistryEvent.toRsEvent(applicationModel, "TestServiceInterface1", 1); + List rcNames = Lists.newArrayList("demo1"); + RegistryEvent event = RegistryEvent.toRsEvent(applicationModel, "TestServiceInterface1", 1, rcNames); event.setAvailable(true); return event; } RegistryEvent subscribeEvent() { - RegistryEvent event = RegistryEvent.toSubscribeEvent(applicationModel); + RegistryEvent event = RegistryEvent.toSubscribeEvent(applicationModel, "registryClusterName_test"); event.setAvailable(true); return event; } diff --git a/dubbo-metrics/dubbo-metrics-registry/src/test/java/org/apache/dubbo/metrics/registry/metrics/collector/RegistryStatCompositeTest.java b/dubbo-metrics/dubbo-metrics-registry/src/test/java/org/apache/dubbo/metrics/registry/metrics/collector/RegistryStatCompositeTest.java index 5ce44d04ad..3c0d00826e 100644 --- a/dubbo-metrics/dubbo-metrics-registry/src/test/java/org/apache/dubbo/metrics/registry/metrics/collector/RegistryStatCompositeTest.java +++ b/dubbo-metrics/dubbo-metrics-registry/src/test/java/org/apache/dubbo/metrics/registry/metrics/collector/RegistryStatCompositeTest.java @@ -17,6 +17,7 @@ package org.apache.dubbo.metrics.registry.metrics.collector; +import org.apache.dubbo.common.constants.RegistryConstants; import org.apache.dubbo.config.ApplicationConfig; import org.apache.dubbo.metrics.data.ApplicationStatComposite; import org.apache.dubbo.metrics.data.BaseStatComposite; @@ -29,12 +30,15 @@ import org.apache.dubbo.metrics.model.container.LongContainer; import org.apache.dubbo.metrics.model.sample.GaugeMetricSample; import org.apache.dubbo.metrics.model.sample.MetricSample; import org.apache.dubbo.metrics.registry.RegistryMetricsConstants; +import org.apache.dubbo.metrics.registry.collector.RegistryStatComposite; import org.apache.dubbo.rpc.model.ApplicationModel; import org.apache.dubbo.rpc.model.FrameworkModel; + import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Optional; @@ -55,6 +59,7 @@ public class RegistryStatCompositeTest { private ApplicationModel applicationModel; private String applicationName; private BaseStatComposite statComposite; + private RegistryStatComposite regStatComposite; @BeforeEach public void setup() { @@ -83,6 +88,7 @@ public class RegistryStatCompositeTest { rtStatComposite.init(OP_TYPE_REGISTER, OP_TYPE_SUBSCRIBE, OP_TYPE_NOTIFY, OP_TYPE_REGISTER_SERVICE, OP_TYPE_SUBSCRIBE_SERVICE); } }; + regStatComposite = new RegistryStatComposite(applicationModel); } @Test @@ -102,8 +108,10 @@ public class RegistryStatCompositeTest { @Test void testIncrement() { - statComposite.incrementApp(REGISTER_METRIC_REQUESTS, 1); - Assertions.assertEquals(1L, statComposite.getApplicationStatComposite().getApplicationNumStats().get(REGISTER_METRIC_REQUESTS).get()); + regStatComposite.incrMetricsNum(REGISTER_METRIC_REQUESTS, "beijing"); + ApplicationMetric applicationMetric = new ApplicationMetric(applicationModel); + applicationMetric.setExtraInfo(Collections.singletonMap(RegistryConstants.REGISTRY_CLUSTER_KEY.toLowerCase(), "beijing")); + Assertions.assertEquals(1L, regStatComposite.getAppStats().get(REGISTER_METRIC_REQUESTS).get(applicationMetric).get()); } @Test diff --git a/dubbo-metrics/dubbo-tracing/pom.xml b/dubbo-metrics/dubbo-tracing/pom.xml index e50dae23bd..f6e26215d9 100644 --- a/dubbo-metrics/dubbo-tracing/pom.xml +++ b/dubbo-metrics/dubbo-tracing/pom.xml @@ -107,5 +107,12 @@ zipkin-reporter-brave true + + + + io.zipkin.reporter2 + zipkin-sender-urlconnection + true + \ No newline at end of file diff --git a/dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/exporter/TraceExporterFactory.java b/dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/exporter/TraceExporterFactory.java deleted file mode 100644 index 7327cf038e..0000000000 --- a/dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/exporter/TraceExporterFactory.java +++ /dev/null @@ -1,66 +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. - */ -package org.apache.dubbo.tracing.exporter; - -import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; -import org.apache.dubbo.common.logger.LoggerFactory; -import org.apache.dubbo.common.utils.StringUtils; -import org.apache.dubbo.config.nested.ExporterConfig; -import org.apache.dubbo.rpc.model.ApplicationModel; -import org.apache.dubbo.tracing.exporter.otlp.OTlpExporter; -import org.apache.dubbo.tracing.exporter.zipkin.ZipkinExporter; - -import brave.handler.SpanHandler; -import io.opentelemetry.sdk.trace.export.SpanExporter; - -import java.util.ArrayList; -import java.util.List; - -public class TraceExporterFactory { - - private final static ErrorTypeAwareLogger LOGGER = LoggerFactory.getErrorTypeAwareLogger(TraceExporterFactory.class); - - /** - * for OTel - */ - public static List getSpanExporters(ApplicationModel applicationModel, ExporterConfig exporterConfig) { - ExporterConfig.ZipkinConfig zipkinConfig = exporterConfig.getZipkinConfig(); - ExporterConfig.OtlpConfig otlpConfig = exporterConfig.getOtlpConfig(); - List res = new ArrayList<>(); - if (zipkinConfig != null && StringUtils.isNotEmpty(zipkinConfig.getEndpoint())) { - ZipkinExporter zipkinExporter = new ZipkinExporter(applicationModel, zipkinConfig); - LOGGER.info("Create zipkin span exporter."); - res.add(zipkinExporter.getSpanExporter()); - } - if (otlpConfig != null && StringUtils.isNotEmpty(otlpConfig.getEndpoint())) { - OTlpExporter otlpExporter = new OTlpExporter(applicationModel, otlpConfig); - LOGGER.info("Create OTlp span exporter."); - res.add(otlpExporter.getSpanExporter()); - } - - return res; - } - - /** - * for Brave - */ - public static List getSpanHandlers(ApplicationModel applicationModel, ExporterConfig exporterConfig) { - List res = new ArrayList<>(); - // TODO brave SpanHandler impl - return res; - } -} diff --git a/dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/exporter/otlp/OTlpExporter.java b/dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/exporter/otlp/OTlpSpanExporter.java similarity index 77% rename from dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/exporter/otlp/OTlpExporter.java rename to dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/exporter/otlp/OTlpSpanExporter.java index 72da78a795..2f2a4acd9f 100644 --- a/dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/exporter/otlp/OTlpExporter.java +++ b/dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/exporter/otlp/OTlpSpanExporter.java @@ -18,9 +18,7 @@ package org.apache.dubbo.tracing.exporter.otlp; import org.apache.dubbo.config.nested.ExporterConfig; import org.apache.dubbo.rpc.model.ApplicationModel; -import org.apache.dubbo.tracing.exporter.TraceExporter; -import brave.handler.SpanHandler; import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter; import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter; import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporterBuilder; @@ -28,18 +26,12 @@ import io.opentelemetry.sdk.trace.export.SpanExporter; import java.util.Map; -public class OTlpExporter implements TraceExporter { +/** + * OTlp span exporter for OTel. + */ +public class OTlpSpanExporter { - private final ApplicationModel applicationModel; - private final ExporterConfig.OtlpConfig otlpConfig; - - public OTlpExporter(ApplicationModel applicationModel, ExporterConfig.OtlpConfig otlpConfig) { - this.applicationModel = applicationModel; - this.otlpConfig = otlpConfig; - } - - @Override - public SpanExporter getSpanExporter() { + public static SpanExporter getSpanExporter(ApplicationModel applicationModel, ExporterConfig.OtlpConfig otlpConfig) { OtlpGrpcSpanExporter externalOTlpGrpcSpanExporter = applicationModel.getBeanFactory().getBean(OtlpGrpcSpanExporter.class); if (externalOTlpGrpcSpanExporter != null) { return externalOTlpGrpcSpanExporter; @@ -57,10 +49,4 @@ public class OTlpExporter implements TraceExporter { } return builder.build(); } - - @Override - public SpanHandler getSpanHandler() { - // OTlp is only belong to OTel. - return null; - } } diff --git a/dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/exporter/zipkin/ZipkinExporter.java b/dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/exporter/zipkin/ZipkinSpanExporter.java similarity index 54% rename from dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/exporter/zipkin/ZipkinExporter.java rename to dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/exporter/zipkin/ZipkinSpanExporter.java index c0c00c6fa8..e8a7a9f3d1 100644 --- a/dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/exporter/zipkin/ZipkinExporter.java +++ b/dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/exporter/zipkin/ZipkinSpanExporter.java @@ -18,43 +18,26 @@ package org.apache.dubbo.tracing.exporter.zipkin; import org.apache.dubbo.config.nested.ExporterConfig; import org.apache.dubbo.rpc.model.ApplicationModel; -import org.apache.dubbo.tracing.exporter.TraceExporter; -import brave.handler.SpanHandler; -import io.opentelemetry.exporter.zipkin.ZipkinSpanExporter; -import io.opentelemetry.sdk.trace.export.SpanExporter; import zipkin2.Span; import zipkin2.codec.BytesEncoder; import zipkin2.codec.SpanBytesEncoder; -public class ZipkinExporter implements TraceExporter { +/** + * Zipkin span exporter for OTel. + */ +public class ZipkinSpanExporter { - private final ApplicationModel applicationModel; - private final ExporterConfig.ZipkinConfig zipkinConfig; - - public ZipkinExporter(ApplicationModel applicationModel, ExporterConfig.ZipkinConfig zipkinConfig) { - this.applicationModel = applicationModel; - this.zipkinConfig = zipkinConfig; - } - - @Override - public SpanExporter getSpanExporter() { - BytesEncoder encoder = getSpanBytesEncoder(); - return ZipkinSpanExporter.builder() - .setEncoder(encoder) + public static io.opentelemetry.sdk.trace.export.SpanExporter getSpanExporter(ApplicationModel applicationModel, ExporterConfig.ZipkinConfig zipkinConfig) { + return io.opentelemetry.exporter.zipkin.ZipkinSpanExporter.builder() + .setEncoder(getSpanBytesEncoder(applicationModel)) .setEndpoint(zipkinConfig.getEndpoint()) .setReadTimeout(zipkinConfig.getReadTimeout()) .build(); } - @Override - public SpanHandler getSpanHandler() { - // TODO SpanHandler of Brave impl - return null; - } - - private BytesEncoder getSpanBytesEncoder() { - BytesEncoder encoder = applicationModel.getBeanFactory().getBean(BytesEncoder.class); + private static BytesEncoder getSpanBytesEncoder(ApplicationModel applicationModel) { + BytesEncoder encoder = applicationModel.getBeanFactory().getBean(BytesEncoder.class); return encoder == null ? SpanBytesEncoder.JSON_V2 : encoder; } } diff --git a/dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/exporter/zipkin/ZipkinSpanHandler.java b/dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/exporter/zipkin/ZipkinSpanHandler.java new file mode 100644 index 0000000000..f56173a8ad --- /dev/null +++ b/dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/exporter/zipkin/ZipkinSpanHandler.java @@ -0,0 +1,53 @@ +/* + * 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.dubbo.tracing.exporter.zipkin; + +import org.apache.dubbo.config.nested.ExporterConfig; +import org.apache.dubbo.rpc.model.ApplicationModel; + +import brave.handler.SpanHandler; +import zipkin2.Span; +import zipkin2.codec.BytesEncoder; +import zipkin2.codec.SpanBytesEncoder; +import zipkin2.reporter.AsyncReporter; +import zipkin2.reporter.urlconnection.URLConnectionSender; + +/** + * Zipkin span handler for Brave. + */ +public class ZipkinSpanHandler { + + public static SpanHandler getSpanHandler(ApplicationModel applicationModel, ExporterConfig.ZipkinConfig zipkinConfig) { + URLConnectionSender sender = applicationModel.getBeanFactory().getBean(URLConnectionSender.class); + if (sender == null) { + URLConnectionSender.Builder builder = URLConnectionSender.newBuilder(); + builder.connectTimeout((int) zipkinConfig.getConnectTimeout().toMillis()); + builder.readTimeout((int) zipkinConfig.getReadTimeout().toMillis()); + builder.endpoint(zipkinConfig.getEndpoint()); + + sender = builder.build(); + } + + AsyncReporter spanReporter = AsyncReporter.builder(sender).build(getSpanBytesEncoder(applicationModel)); + return zipkin2.reporter.brave.ZipkinSpanHandler.newBuilder(spanReporter).build(); + } + + private static BytesEncoder getSpanBytesEncoder(ApplicationModel applicationModel) { + BytesEncoder encoder = applicationModel.getBeanFactory().getBean(BytesEncoder.class); + return encoder == null ? SpanBytesEncoder.JSON_V2 : encoder; + } +} diff --git a/dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/tracer/brave/BravePropagatorProvider.java b/dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/tracer/brave/BravePropagatorProvider.java index 8560a5b149..56e23d3670 100644 --- a/dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/tracer/brave/BravePropagatorProvider.java +++ b/dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/tracer/brave/BravePropagatorProvider.java @@ -18,14 +18,20 @@ package org.apache.dubbo.tracing.tracer.brave; import org.apache.dubbo.tracing.tracer.PropagatorProvider; +import io.micrometer.tracing.brave.bridge.BravePropagator; import io.micrometer.tracing.propagation.Propagator; public class BravePropagatorProvider implements PropagatorProvider { + private static Propagator propagator; + @Override public Propagator getPropagator() { - // TODO impl - return null; + return propagator; + } + + protected static void createMicrometerPropagator(brave.Tracing tracing) { + propagator = new BravePropagator(tracing); } } diff --git a/dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/tracer/brave/BraveProvider.java b/dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/tracer/brave/BraveProvider.java index 9ab8172b02..9f178f400b 100644 --- a/dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/tracer/brave/BraveProvider.java +++ b/dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/tracer/brave/BraveProvider.java @@ -16,15 +16,40 @@ */ package org.apache.dubbo.tracing.tracer.brave; +import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; +import org.apache.dubbo.common.logger.LoggerFactory; +import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.config.ApplicationConfig; import org.apache.dubbo.config.TracingConfig; +import org.apache.dubbo.config.nested.BaggageConfig; +import org.apache.dubbo.config.nested.ExporterConfig; import org.apache.dubbo.rpc.model.ApplicationModel; +import org.apache.dubbo.tracing.exporter.zipkin.ZipkinSpanHandler; import org.apache.dubbo.tracing.tracer.TracerProvider; +import org.apache.dubbo.tracing.utils.PropagationType; +import io.micrometer.tracing.CurrentTraceContext; import io.micrometer.tracing.Tracer; +import io.micrometer.tracing.brave.bridge.BraveBaggageManager; +import io.micrometer.tracing.brave.bridge.BraveCurrentTraceContext; +import io.micrometer.tracing.brave.bridge.BraveTracer; +import io.micrometer.tracing.brave.bridge.W3CPropagation; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +import static org.apache.dubbo.tracing.utils.ObservationConstants.DEFAULT_APPLICATION_NAME; +import static org.apache.dubbo.tracing.utils.ObservationSupportUtil.isSupportBraveURLSender; public class BraveProvider implements TracerProvider { + private final static ErrorTypeAwareLogger LOGGER = LoggerFactory.getErrorTypeAwareLogger(BraveProvider.class); + + private static final BraveBaggageManager BRAVE_BAGGAGE_MANAGER = new BraveBaggageManager(); + private final ApplicationModel applicationModel; private final TracingConfig tracingConfig; @@ -35,7 +60,139 @@ public class BraveProvider implements TracerProvider { @Override public Tracer getTracer() { - // TODO impl - return null; + // [Brave component] SpanHandler is a component that gets called when a span is finished. + List spanHandlerList = getSpanHandlers(); + + String applicationName = applicationModel.getApplicationConfigManager().getApplication() + .map(ApplicationConfig::getName) + .orElse(DEFAULT_APPLICATION_NAME); + + // [Brave component] CurrentTraceContext is a Brave component that allows you to + // retrieve the current TraceContext. + brave.propagation.ThreadLocalCurrentTraceContext braveCurrentTraceContext = brave.propagation.ThreadLocalCurrentTraceContext.newBuilder() + .addScopeDecorator(correlationScopeDecorator()) // Brave's automatic MDC setup + .build(); + + // [Micrometer Tracing component] A Micrometer Tracing wrapper for Brave's CurrentTraceContext + CurrentTraceContext bridgeContext = new BraveCurrentTraceContext(braveCurrentTraceContext); + + + // [Brave component] Tracing is the root component that allows to configure the + // tracer, handlers, context propagation etc. + brave.Tracing.Builder builder = brave.Tracing.newBuilder() + .currentTraceContext(braveCurrentTraceContext) + .supportsJoin(false) + .traceId128Bit(true) + .localServiceName(applicationName) + // For Baggage to work you need to provide a list of fields to propagate + .propagationFactory(PropagatorFactory.getPropagationFactory(tracingConfig)) + .sampler(getSampler()); + spanHandlerList.forEach(builder::addSpanHandler); + + brave.Tracing tracing = builder.build(); + + BravePropagatorProvider.createMicrometerPropagator(tracing); + + // [Brave component] Tracer is a component that handles the life-cycle of a span + brave.Tracer braveTracer = tracing.tracer(); + + // [Micrometer Tracing component] A Micrometer Tracing wrapper for Brave's Tracer + return new BraveTracer(braveTracer, bridgeContext, BRAVE_BAGGAGE_MANAGER); + } + + private List getSpanHandlers() { + ExporterConfig exporterConfig = tracingConfig.getTracingExporter(); + List res = new ArrayList<>(); + if (!isSupportBraveURLSender()) { + return res; + } + ExporterConfig.ZipkinConfig zipkinConfig = exporterConfig.getZipkinConfig(); + if (zipkinConfig != null && StringUtils.isNotEmpty(zipkinConfig.getEndpoint())) { + LOGGER.info("Create zipkin span handler."); + res.add(ZipkinSpanHandler.getSpanHandler(applicationModel, zipkinConfig)); + } + return res; + } + + private brave.sampler.Sampler getSampler() { + return brave.sampler.Sampler.create(tracingConfig.getSampling().getProbability()); + } + + private Optional correlationFieldsCorrelationScopeCustomizer() { + BaggageConfig.Correlation correlation = tracingConfig.getBaggage().getCorrelation(); + boolean enabled = correlation.isEnabled(); + if (!enabled) { + return Optional.empty(); + } + return Optional.of((builder) -> { + List correlationFields = correlation.getFields(); + for (String field : correlationFields) { + builder.add(brave.baggage.CorrelationScopeConfig.SingleCorrelationField.newBuilder(brave.baggage.BaggageField.create(field)) + .flushOnUpdate().build()); + } + }); + } + + private brave.propagation.CurrentTraceContext.ScopeDecorator correlationScopeDecorator() { + brave.baggage.CorrelationScopeDecorator.Builder builder = brave.context.slf4j.MDCScopeDecorator.newBuilder(); + correlationFieldsCorrelationScopeCustomizer().ifPresent((customizer) -> customizer.customize(builder)); + return builder.build(); + } + + static class PropagatorFactory { + + public static brave.propagation.Propagation.Factory getPropagationFactory(TracingConfig tracingConfig) { + BaggageConfig baggageConfig = tracingConfig.getBaggage(); + if (baggageConfig == null || !baggageConfig.getEnabled()) { + return getPropagationFactoryWithoutBaggage(tracingConfig); + } + return getPropagationFactoryWithBaggage(tracingConfig); + } + + private static brave.propagation.Propagation.Factory getPropagationFactoryWithoutBaggage(TracingConfig tracingConfig) { + PropagationType propagationType = PropagationType.forValue(tracingConfig.getPropagation().getType()); + if (PropagationType.W3C == propagationType) { + return new io.micrometer.tracing.brave.bridge.W3CPropagation(); + } else { + // Brave default propagation is B3 + return brave.propagation.B3Propagation.newFactoryBuilder().injectFormat(brave.propagation.B3Propagation.Format.SINGLE_NO_PARENT).build(); + } + } + + private static brave.propagation.Propagation.Factory getPropagationFactoryWithBaggage(TracingConfig tracingConfig) { + PropagationType propagationType = PropagationType.forValue(tracingConfig.getPropagation().getType()); + brave.propagation.Propagation.Factory delegate; + if (PropagationType.W3C == propagationType) { + delegate = new W3CPropagation(BRAVE_BAGGAGE_MANAGER, Collections.emptyList()); + } else { + // Brave default propagation is B3 + delegate = brave.propagation.B3Propagation.newFactoryBuilder().injectFormat(brave.propagation.B3Propagation.Format.SINGLE_NO_PARENT).build(); + } + return getBaggageFactoryBuilder(delegate, tracingConfig).build(); + } + + private static brave.baggage.BaggagePropagation.FactoryBuilder getBaggageFactoryBuilder(brave.propagation.Propagation.Factory delegate, TracingConfig tracingConfig) { + brave.baggage.BaggagePropagation.FactoryBuilder builder = brave.baggage.BaggagePropagation.newFactoryBuilder(delegate); + + getBaggagePropagationCustomizers(tracingConfig).forEach((customizer) -> customizer.customize(builder)); + return builder; + } + + private static List getBaggagePropagationCustomizers(TracingConfig tracingConfig) { + List res = new ArrayList<>(); + if (tracingConfig.getBaggage().getCorrelation().isEnabled()) { + res.add(remoteFieldsBaggagePropagationCustomizer(tracingConfig)); + } + return res; + } + + private static brave.baggage.BaggagePropagationCustomizer remoteFieldsBaggagePropagationCustomizer(TracingConfig tracingConfig) { + return (builder) -> { + List remoteFields = tracingConfig.getBaggage().getRemoteFields(); + for (String fieldName : remoteFields) { + builder.add(brave.baggage.BaggagePropagationConfig.SingleBaggageField.remote(brave.baggage.BaggageField.create(fieldName))); + } + }; + } } } diff --git a/dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/tracer/otel/OpenTelemetryProvider.java b/dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/tracer/otel/OpenTelemetryProvider.java index 36b3c3f191..bf00771b99 100644 --- a/dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/tracer/otel/OpenTelemetryProvider.java +++ b/dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/tracer/otel/OpenTelemetryProvider.java @@ -18,13 +18,19 @@ package org.apache.dubbo.tracing.tracer.otel; import org.apache.dubbo.common.Version; import org.apache.dubbo.common.lang.Nullable; +import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; +import org.apache.dubbo.common.logger.LoggerFactory; +import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.config.ApplicationConfig; import org.apache.dubbo.config.TracingConfig; import org.apache.dubbo.config.nested.BaggageConfig; +import org.apache.dubbo.config.nested.ExporterConfig; import org.apache.dubbo.config.nested.PropagationConfig; import org.apache.dubbo.rpc.model.ApplicationModel; -import org.apache.dubbo.tracing.exporter.TraceExporterFactory; +import org.apache.dubbo.tracing.exporter.otlp.OTlpSpanExporter; +import org.apache.dubbo.tracing.exporter.zipkin.ZipkinSpanExporter; import org.apache.dubbo.tracing.tracer.TracerProvider; +import org.apache.dubbo.tracing.utils.PropagationType; import io.micrometer.tracing.Tracer; import io.micrometer.tracing.otel.bridge.CompositeSpanExporter; @@ -36,28 +42,17 @@ import io.micrometer.tracing.otel.bridge.OtelTracer; import io.micrometer.tracing.otel.bridge.Slf4JBaggageEventListener; import io.micrometer.tracing.otel.bridge.Slf4JEventListener; import io.micrometer.tracing.otel.propagation.BaggageTextMapPropagator; -import io.opentelemetry.api.baggage.propagation.W3CBaggagePropagator; -import io.opentelemetry.api.common.Attributes; -import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; -import io.opentelemetry.context.ContextStorage; -import io.opentelemetry.context.propagation.ContextPropagators; -import io.opentelemetry.context.propagation.TextMapPropagator; -import io.opentelemetry.extension.trace.propagation.B3Propagator; -import io.opentelemetry.sdk.OpenTelemetrySdk; -import io.opentelemetry.sdk.resources.Resource; -import io.opentelemetry.sdk.trace.SdkTracerProvider; -import io.opentelemetry.sdk.trace.export.BatchSpanProcessor; -import io.opentelemetry.sdk.trace.export.SpanExporter; -import io.opentelemetry.sdk.trace.samplers.Sampler; -import io.opentelemetry.semconv.resource.attributes.ResourceAttributes; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import static org.apache.dubbo.tracing.utils.ObservationConstants.DEFAULT_APPLICATION_NAME; + public class OpenTelemetryProvider implements TracerProvider { - private static final String DEFAULT_APPLICATION_NAME = "dubbo-application"; + private final static ErrorTypeAwareLogger LOGGER = LoggerFactory.getErrorTypeAwareLogger(OpenTelemetryProvider.class); + private final ApplicationModel applicationModel; private final TracingConfig tracingConfig; @@ -72,7 +67,7 @@ public class OpenTelemetryProvider implements TracerProvider { @Override public Tracer getTracer() { // [OTel component] SpanExporter is a component that gets called when a span is finished. - List spanExporters = TraceExporterFactory.getSpanExporters(applicationModel, tracingConfig.getTracingExporter()); + List spanExporters = getSpanExporters(); String applicationName = applicationModel.getApplicationConfigManager().getApplication() .map(ApplicationConfig::getName) @@ -84,18 +79,18 @@ public class OpenTelemetryProvider implements TracerProvider { this.otelCurrentTraceContext = createCurrentTraceContext(); // [OTel component] SdkTracerProvider is an SDK implementation for TracerProvider - SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder() + io.opentelemetry.sdk.trace.SdkTracerProvider sdkTracerProvider = io.opentelemetry.sdk.trace.SdkTracerProvider.builder() .setSampler(getSampler()) - .setResource(Resource.create(Attributes.of(ResourceAttributes.SERVICE_NAME, applicationName))) - .addSpanProcessor(BatchSpanProcessor + .setResource(io.opentelemetry.sdk.resources.Resource.create(io.opentelemetry.api.common.Attributes.of(io.opentelemetry.semconv.resource.attributes.ResourceAttributes.SERVICE_NAME, applicationName))) + .addSpanProcessor(io.opentelemetry.sdk.trace.export.BatchSpanProcessor .builder(new CompositeSpanExporter(spanExporters, null, null, null)) .build()) .build(); - ContextPropagators otelContextPropagators = createOtelContextPropagators(); + io.opentelemetry.context.propagation.ContextPropagators otelContextPropagators = createOtelContextPropagators(); // [OTel component] The SDK implementation of OpenTelemetry - OpenTelemetrySdk openTelemetrySdk = OpenTelemetrySdk.builder() + io.opentelemetry.sdk.OpenTelemetrySdk openTelemetrySdk = io.opentelemetry.sdk.OpenTelemetrySdk.builder() .setTracerProvider(sdkTracerProvider) .setPropagators(otelContextPropagators) .build(); @@ -113,14 +108,31 @@ public class OpenTelemetryProvider implements TracerProvider { Collections.emptyList())); } + private List getSpanExporters() { + ExporterConfig exporterConfig = tracingConfig.getTracingExporter(); + ExporterConfig.ZipkinConfig zipkinConfig = exporterConfig.getZipkinConfig(); + ExporterConfig.OtlpConfig otlpConfig = exporterConfig.getOtlpConfig(); + List res = new ArrayList<>(); + if (zipkinConfig != null && StringUtils.isNotEmpty(zipkinConfig.getEndpoint())) { + LOGGER.info("Create zipkin span exporter."); + res.add(ZipkinSpanExporter.getSpanExporter(applicationModel, zipkinConfig)); + } + if (otlpConfig != null && StringUtils.isNotEmpty(otlpConfig.getEndpoint())) { + LOGGER.info("Create OTlp span exporter."); + res.add(OTlpSpanExporter.getSpanExporter(applicationModel, otlpConfig)); + } + + return res; + } + /** * sampler with probability * * @return sampler */ - private Sampler getSampler() { - Sampler rootSampler = Sampler.traceIdRatioBased(tracingConfig.getSampling().getProbability()); - return Sampler.parentBased(rootSampler); + private io.opentelemetry.sdk.trace.samplers.Sampler getSampler() { + io.opentelemetry.sdk.trace.samplers.Sampler rootSampler = io.opentelemetry.sdk.trace.samplers.Sampler.traceIdRatioBased(tracingConfig.getSampling().getProbability()); + return io.opentelemetry.sdk.trace.samplers.Sampler.parentBased(rootSampler); } private List getEventListeners() { @@ -141,13 +153,13 @@ public class OpenTelemetryProvider implements TracerProvider { } private OtelCurrentTraceContext createCurrentTraceContext() { - ContextStorage.addWrapper(new EventPublishingContextWrapper(publisher)); + io.opentelemetry.context.ContextStorage.addWrapper(new EventPublishingContextWrapper(publisher)); return new OtelCurrentTraceContext(); } - private ContextPropagators createOtelContextPropagators() { - return ContextPropagators.create( - TextMapPropagator.composite( + private io.opentelemetry.context.propagation.ContextPropagators createOtelContextPropagators() { + return io.opentelemetry.context.propagation.ContextPropagators.create( + io.opentelemetry.context.propagation.TextMapPropagator.composite( PropagatorFactory.getPropagator(tracingConfig.getPropagation(), tracingConfig.getBaggage(), otelCurrentTraceContext @@ -172,41 +184,44 @@ public class OpenTelemetryProvider implements TracerProvider { static class PropagatorFactory { - public static TextMapPropagator getPropagator(PropagationConfig propagationConfig, - @Nullable BaggageConfig baggageConfig, - @Nullable OtelCurrentTraceContext currentTraceContext) { + public static io.opentelemetry.context.propagation.TextMapPropagator getPropagator(PropagationConfig propagationConfig, + @Nullable BaggageConfig baggageConfig, + @Nullable OtelCurrentTraceContext currentTraceContext) { if (baggageConfig == null || !baggageConfig.getEnabled()) { return getPropagatorWithoutBaggage(propagationConfig); } return getPropagatorWithBaggage(propagationConfig, baggageConfig, currentTraceContext); } - private static TextMapPropagator getPropagatorWithoutBaggage(PropagationConfig propagationConfig) { + private static io.opentelemetry.context.propagation.TextMapPropagator getPropagatorWithoutBaggage(PropagationConfig propagationConfig) { String type = propagationConfig.getType(); - if ("B3".equals(type)) { - return B3Propagator.injectingSingleHeader(); - } else if ("W3C".equals(type)) { - return W3CTraceContextPropagator.getInstance(); + PropagationType propagationType = PropagationType.forValue(type); + + if (PropagationType.B3 == propagationType) { + return io.opentelemetry.extension.trace.propagation.B3Propagator.injectingSingleHeader(); + } else if (PropagationType.W3C == propagationType) { + return io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator.getInstance(); } - return TextMapPropagator.noop(); + return io.opentelemetry.context.propagation.TextMapPropagator.noop(); } - private static TextMapPropagator getPropagatorWithBaggage(PropagationConfig propagationConfig, - BaggageConfig baggageConfig, - OtelCurrentTraceContext currentTraceContext) { + private static io.opentelemetry.context.propagation.TextMapPropagator getPropagatorWithBaggage(PropagationConfig propagationConfig, + BaggageConfig baggageConfig, + OtelCurrentTraceContext currentTraceContext) { String type = propagationConfig.getType(); - if ("B3".equals(type)) { + PropagationType propagationType = PropagationType.forValue(type); + if (PropagationType.B3 == propagationType) { List remoteFields = baggageConfig.getRemoteFields(); - return TextMapPropagator.composite(B3Propagator.injectingSingleHeader(), + return io.opentelemetry.context.propagation.TextMapPropagator.composite(io.opentelemetry.extension.trace.propagation.B3Propagator.injectingSingleHeader(), new BaggageTextMapPropagator(remoteFields, new OtelBaggageManager(currentTraceContext, remoteFields, Collections.emptyList()))); - } else if ("W3C".equals(type)) { + } else if (PropagationType.W3C == propagationType) { List remoteFields = baggageConfig.getRemoteFields(); - return TextMapPropagator.composite(W3CTraceContextPropagator.getInstance(), - W3CBaggagePropagator.getInstance(), new BaggageTextMapPropagator(remoteFields, + return io.opentelemetry.context.propagation.TextMapPropagator.composite(io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator.getInstance(), + io.opentelemetry.api.baggage.propagation.W3CBaggagePropagator.getInstance(), new BaggageTextMapPropagator(remoteFields, new OtelBaggageManager(currentTraceContext, remoteFields, Collections.emptyList()))); } - return TextMapPropagator.noop(); + return io.opentelemetry.context.propagation.TextMapPropagator.noop(); } } } diff --git a/dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/utils/ObservationConstants.java b/dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/utils/ObservationConstants.java new file mode 100644 index 0000000000..819e6ac44b --- /dev/null +++ b/dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/utils/ObservationConstants.java @@ -0,0 +1,23 @@ +/* + * 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.dubbo.tracing.utils; + +public class ObservationConstants { + + public static final String DEFAULT_APPLICATION_NAME = "dubbo-application"; +} diff --git a/dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/utils/ObservationSupportUtil.java b/dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/utils/ObservationSupportUtil.java index 4cf8e05edf..72a77556eb 100644 --- a/dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/utils/ObservationSupportUtil.java +++ b/dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/utils/ObservationSupportUtil.java @@ -43,6 +43,10 @@ public class ObservationSupportUtil { && isClassPresent("brave.Tracing"); } + public static boolean isSupportBraveURLSender() { + return isClassPresent("zipkin2.reporter.urlconnection.URLConnectionSender"); + } + private static boolean isClassPresent(String className) { return ClassUtils.isPresent(className, ObservationSupportUtil.class.getClassLoader()); } diff --git a/dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/utils/PropagationType.java b/dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/utils/PropagationType.java new file mode 100644 index 0000000000..8ed5c56135 --- /dev/null +++ b/dubbo-metrics/dubbo-tracing/src/main/java/org/apache/dubbo/tracing/utils/PropagationType.java @@ -0,0 +1,44 @@ +/* + * 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.dubbo.tracing.utils; + +public enum PropagationType { + + W3C("W3C"), + B3("B3"); + + private final String value; + + PropagationType(String type) { + this.value = type; + } + + public String getValue() { + return value; + } + + public static PropagationType forValue(String value) { + PropagationType[] values = values(); + for (PropagationType type : values) { + if (type.getValue().equals(value)) { + return type; + } + } + return null; + } +} diff --git a/dubbo-metrics/dubbo-tracing/src/test/java/org/apache/dubbo/tracing/exporter/otlp/OTlpSpanExporterTest.java b/dubbo-metrics/dubbo-tracing/src/test/java/org/apache/dubbo/tracing/exporter/otlp/OTlpSpanExporterTest.java new file mode 100644 index 0000000000..a57933ea2e --- /dev/null +++ b/dubbo-metrics/dubbo-tracing/src/test/java/org/apache/dubbo/tracing/exporter/otlp/OTlpSpanExporterTest.java @@ -0,0 +1,43 @@ +/* + * 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.dubbo.tracing.exporter.otlp; + +import org.apache.dubbo.config.nested.ExporterConfig; +import org.apache.dubbo.rpc.model.ApplicationModel; + +import io.opentelemetry.sdk.trace.export.SpanExporter; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.time.Duration; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class OTlpSpanExporterTest { + + @Test + void getSpanExporter() { + ExporterConfig.OtlpConfig otlpConfig = mock(ExporterConfig.OtlpConfig.class); + when(otlpConfig.getEndpoint()).thenReturn("http://localhost:9411/api/v2/spans"); + when(otlpConfig.getTimeout()).thenReturn(Duration.ofSeconds(5)); + when(otlpConfig.getCompressionMethod()).thenReturn("gzip"); + + SpanExporter spanExporter = OTlpSpanExporter.getSpanExporter(ApplicationModel.defaultModel(), otlpConfig); + Assertions.assertNotNull(spanExporter); + } +} \ No newline at end of file diff --git a/dubbo-metrics/dubbo-tracing/src/test/java/org/apache/dubbo/tracing/exporter/zipkin/ZipkinSpanExporterTest.java b/dubbo-metrics/dubbo-tracing/src/test/java/org/apache/dubbo/tracing/exporter/zipkin/ZipkinSpanExporterTest.java new file mode 100644 index 0000000000..c6bd0922e0 --- /dev/null +++ b/dubbo-metrics/dubbo-tracing/src/test/java/org/apache/dubbo/tracing/exporter/zipkin/ZipkinSpanExporterTest.java @@ -0,0 +1,44 @@ +/* + * 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.dubbo.tracing.exporter.zipkin; + +import org.apache.dubbo.config.nested.ExporterConfig; +import org.apache.dubbo.rpc.model.ApplicationModel; + +import io.opentelemetry.sdk.trace.export.SpanExporter; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.time.Duration; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + + +class ZipkinSpanExporterTest { + + @Test + void getSpanExporter() { + ExporterConfig.ZipkinConfig zipkinConfig = mock(ExporterConfig.ZipkinConfig.class); + when(zipkinConfig.getEndpoint()).thenReturn("http://localhost:9411/api/v2/spans"); + when(zipkinConfig.getConnectTimeout()).thenReturn(Duration.ofSeconds(5)); + when(zipkinConfig.getReadTimeout()).thenReturn(Duration.ofSeconds(5)); + + SpanExporter spanExporter = ZipkinSpanExporter.getSpanExporter(ApplicationModel.defaultModel(), zipkinConfig); + Assertions.assertNotNull(spanExporter); + } +} \ No newline at end of file diff --git a/dubbo-metrics/dubbo-tracing/src/test/java/org/apache/dubbo/tracing/exporter/zipkin/ZipkinSpanHandlerTest.java b/dubbo-metrics/dubbo-tracing/src/test/java/org/apache/dubbo/tracing/exporter/zipkin/ZipkinSpanHandlerTest.java new file mode 100644 index 0000000000..b30b2a8f04 --- /dev/null +++ b/dubbo-metrics/dubbo-tracing/src/test/java/org/apache/dubbo/tracing/exporter/zipkin/ZipkinSpanHandlerTest.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.dubbo.tracing.exporter.zipkin; + +import org.apache.dubbo.config.nested.ExporterConfig; +import org.apache.dubbo.rpc.model.ApplicationModel; + +import brave.handler.SpanHandler; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.time.Duration; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class ZipkinSpanHandlerTest { + + @Test + void getSpanHandler() { + ExporterConfig.ZipkinConfig zipkinConfig = mock(ExporterConfig.ZipkinConfig.class); + when(zipkinConfig.getEndpoint()).thenReturn("http://localhost:9411/api/v2/spans"); + when(zipkinConfig.getConnectTimeout()).thenReturn(Duration.ofSeconds(5)); + + SpanHandler spanHandler = ZipkinSpanHandler.getSpanHandler(ApplicationModel.defaultModel(), zipkinConfig); + Assertions.assertNotNull(spanHandler); + } +} \ No newline at end of file diff --git a/dubbo-metrics/dubbo-tracing/src/test/java/org/apache/dubbo/tracing/tracer/brave/BravePropagatorProviderTest.java b/dubbo-metrics/dubbo-tracing/src/test/java/org/apache/dubbo/tracing/tracer/brave/BravePropagatorProviderTest.java new file mode 100644 index 0000000000..b9c6c32489 --- /dev/null +++ b/dubbo-metrics/dubbo-tracing/src/test/java/org/apache/dubbo/tracing/tracer/brave/BravePropagatorProviderTest.java @@ -0,0 +1,38 @@ +/* + * 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.dubbo.tracing.tracer.brave; + +import org.apache.dubbo.common.utils.Assert; + +import brave.Tracing; +import io.micrometer.tracing.propagation.Propagator; +import org.junit.jupiter.api.Test; + +import static org.mockito.Mockito.mock; + +class BravePropagatorProviderTest { + + @Test + void testBravePropagatorProvider() { + Tracing tracing = mock(Tracing.class); + BravePropagatorProvider.createMicrometerPropagator(tracing); + + BravePropagatorProvider bravePropagatorProvider = new BravePropagatorProvider(); + Propagator propagator = bravePropagatorProvider.getPropagator(); + Assert.notNull(propagator, "Propagator don't be null."); + } +} \ No newline at end of file diff --git a/dubbo-metrics/dubbo-tracing/src/test/java/org/apache/dubbo/tracing/tracer/brave/BraveProviderTest.java b/dubbo-metrics/dubbo-tracing/src/test/java/org/apache/dubbo/tracing/tracer/brave/BraveProviderTest.java new file mode 100644 index 0000000000..a622a3c6a1 --- /dev/null +++ b/dubbo-metrics/dubbo-tracing/src/test/java/org/apache/dubbo/tracing/tracer/brave/BraveProviderTest.java @@ -0,0 +1,86 @@ +/* + * 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.dubbo.tracing.tracer.brave; + +import org.apache.dubbo.common.utils.Assert; +import org.apache.dubbo.config.TracingConfig; +import org.apache.dubbo.config.nested.BaggageConfig; +import org.apache.dubbo.config.nested.ExporterConfig; +import org.apache.dubbo.config.nested.PropagationConfig; +import org.apache.dubbo.rpc.model.ApplicationModel; +import org.apache.dubbo.tracing.utils.PropagationType; + +import brave.propagation.Propagation; +import io.micrometer.tracing.Tracer; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class BraveProviderTest { + + @Test + void testGetTracer() { + TracingConfig tracingConfig = new TracingConfig(); + tracingConfig.setEnabled(true); + ExporterConfig exporterConfig = new ExporterConfig(); + exporterConfig.setZipkinConfig(new ExporterConfig.ZipkinConfig("")); + tracingConfig.setTracingExporter(exporterConfig); + + BraveProvider braveProvider = new BraveProvider(ApplicationModel.defaultModel(), tracingConfig); + Tracer tracer = braveProvider.getTracer(); + Assert.notNull(tracer, "Tracer should not be null."); + assertEquals(io.micrometer.tracing.brave.bridge.BraveTracer.class, tracer.getClass()); + } + + @Test + void testGetPropagator() { + TracingConfig tracingConfig = mock(TracingConfig.class); + PropagationConfig propagationConfig = mock(PropagationConfig.class); + when(tracingConfig.getPropagation()).thenReturn(propagationConfig); + BaggageConfig baggageConfig = mock(BaggageConfig.class); + when(tracingConfig.getBaggage()).thenReturn(baggageConfig); + + // no baggage + when(baggageConfig.getEnabled()).thenReturn(Boolean.FALSE); + + when(propagationConfig.getType()).thenReturn(PropagationType.W3C.getValue()); + Propagation.Factory w3cPropagationFactoryWithoutBaggage = BraveProvider.PropagatorFactory.getPropagationFactory(tracingConfig); + assertEquals(io.micrometer.tracing.brave.bridge.W3CPropagation.class, w3cPropagationFactoryWithoutBaggage.getClass()); + + when(propagationConfig.getType()).thenReturn(PropagationType.B3.getValue()); + Propagation.Factory b3PropagationFactoryWithoutBaggage = BraveProvider.PropagatorFactory.getPropagationFactory(tracingConfig); + Assert.notNull(b3PropagationFactoryWithoutBaggage, "b3PropagationFactoryWithoutBaggage should not be null."); + + // with baggage + when(baggageConfig.getEnabled()).thenReturn(Boolean.TRUE); + BaggageConfig.Correlation correlation = mock(BaggageConfig.Correlation.class); + when(correlation.isEnabled()).thenReturn(Boolean.TRUE); + when(baggageConfig.getCorrelation()).thenReturn(correlation); + List remoteFields = new ArrayList<>(); + for (int i = 0; i < 10; i++) { + remoteFields.add("test-hd-" + i); + } + when(baggageConfig.getRemoteFields()).thenReturn(remoteFields); + Propagation.Factory propagationFactoryWithBaggage = BraveProvider.PropagatorFactory.getPropagationFactory(tracingConfig); + Assert.notNull(propagationFactoryWithBaggage, "propagationFactoryWithBaggage should not be null."); + } +} \ No newline at end of file diff --git a/dubbo-metrics/dubbo-tracing/src/test/java/org/apache/dubbo/tracing/tracer/otel/OTelPropagatorProviderTest.java b/dubbo-metrics/dubbo-tracing/src/test/java/org/apache/dubbo/tracing/tracer/otel/OTelPropagatorProviderTest.java index 83f2cd2df0..24b1e3f11d 100644 --- a/dubbo-metrics/dubbo-tracing/src/test/java/org/apache/dubbo/tracing/tracer/otel/OTelPropagatorProviderTest.java +++ b/dubbo-metrics/dubbo-tracing/src/test/java/org/apache/dubbo/tracing/tracer/otel/OTelPropagatorProviderTest.java @@ -23,6 +23,7 @@ import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.context.propagation.ContextPropagators; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; class OTelPropagatorProviderTest { diff --git a/dubbo-metrics/dubbo-tracing/src/test/java/org/apache/dubbo/tracing/tracer/otel/OpenTelemetryProviderTest.java b/dubbo-metrics/dubbo-tracing/src/test/java/org/apache/dubbo/tracing/tracer/otel/OpenTelemetryProviderTest.java index 0374912c3a..b48c624cd8 100644 --- a/dubbo-metrics/dubbo-tracing/src/test/java/org/apache/dubbo/tracing/tracer/otel/OpenTelemetryProviderTest.java +++ b/dubbo-metrics/dubbo-tracing/src/test/java/org/apache/dubbo/tracing/tracer/otel/OpenTelemetryProviderTest.java @@ -20,15 +20,23 @@ import org.apache.dubbo.common.utils.Assert; import org.apache.dubbo.config.TracingConfig; import org.apache.dubbo.config.nested.BaggageConfig; import org.apache.dubbo.config.nested.ExporterConfig; +import org.apache.dubbo.config.nested.PropagationConfig; import org.apache.dubbo.rpc.model.ApplicationModel; import org.apache.dubbo.tracing.tracer.TracerProvider; import org.apache.dubbo.tracing.tracer.TracerProviderFactory; +import org.apache.dubbo.tracing.utils.PropagationType; import io.micrometer.tracing.Tracer; +import io.micrometer.tracing.otel.bridge.OtelCurrentTraceContext; import io.micrometer.tracing.otel.bridge.OtelTracer; +import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; +import io.opentelemetry.context.propagation.TextMapPropagator; +import io.opentelemetry.extension.trace.propagation.B3Propagator; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; class OpenTelemetryProviderTest { @@ -50,4 +58,28 @@ class OpenTelemetryProviderTest { Tracer tracer2 = tracerProvider2.getTracer(); assertEquals(OtelTracer.class, tracer2.getClass()); } + + @Test + void testGetPropagator() { + PropagationConfig propagationConfig = mock(PropagationConfig.class); + BaggageConfig baggageConfig = mock(BaggageConfig.class); + OtelCurrentTraceContext otelCurrentTraceContext = mock(OtelCurrentTraceContext.class); + + when(baggageConfig.getEnabled()).thenReturn(Boolean.FALSE); + + when(propagationConfig.getType()).thenReturn(PropagationType.B3.getValue()); + TextMapPropagator b3PropagatorWithoutBaggage = OpenTelemetryProvider.PropagatorFactory.getPropagator(propagationConfig, baggageConfig, otelCurrentTraceContext); + assertEquals(B3Propagator.class, b3PropagatorWithoutBaggage.getClass()); + + when(propagationConfig.getType()).thenReturn(PropagationType.W3C.getValue()); + TextMapPropagator w3cPropagatorWithoutBaggage = OpenTelemetryProvider.PropagatorFactory.getPropagator(propagationConfig, baggageConfig, otelCurrentTraceContext); + assertEquals(W3CTraceContextPropagator.class, w3cPropagatorWithoutBaggage.getClass()); + + + when(baggageConfig.getEnabled()).thenReturn(Boolean.TRUE); + TextMapPropagator propagatorWithBaggage = OpenTelemetryProvider.PropagatorFactory.getPropagator(propagationConfig, baggageConfig, otelCurrentTraceContext); + Assert.notNull(propagatorWithBaggage, "PropagatorWithBaggage should not be null"); + } + + } \ No newline at end of file diff --git a/dubbo-metrics/dubbo-tracing/src/test/java/org/apache/dubbo/tracing/utils/PropagationTypeTest.java b/dubbo-metrics/dubbo-tracing/src/test/java/org/apache/dubbo/tracing/utils/PropagationTypeTest.java new file mode 100644 index 0000000000..857c7a84f3 --- /dev/null +++ b/dubbo-metrics/dubbo-tracing/src/test/java/org/apache/dubbo/tracing/utils/PropagationTypeTest.java @@ -0,0 +1,37 @@ +/* + * 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.dubbo.tracing.utils; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +class PropagationTypeTest { + + @Test + void forValue() { + PropagationType propagationType1 = PropagationType.forValue("W3C"); + assertEquals(PropagationType.W3C, propagationType1); + + PropagationType propagationType2 = PropagationType.forValue("B3"); + assertEquals(PropagationType.B3, propagationType2); + + PropagationType propagationType3 = PropagationType.forValue("B33"); + assertNull(propagationType3); + } +} \ No newline at end of file diff --git a/dubbo-metrics/pom.xml b/dubbo-metrics/pom.xml index c10defb8d6..014632df63 100644 --- a/dubbo-metrics/pom.xml +++ b/dubbo-metrics/pom.xml @@ -25,6 +25,7 @@ dubbo-metrics-prometheus dubbo-metrics-config-center dubbo-tracing + dubbo-metrics-netty org.apache.dubbo diff --git a/dubbo-plugin/dubbo-plugin-context/src/main/java/org/apache/dubbo/rpc/cluster/filter/support/CallbackConsumerContextFilter.java b/dubbo-plugin/dubbo-plugin-context/src/main/java/org/apache/dubbo/rpc/cluster/filter/support/CallbackConsumerContextFilter.java new file mode 100644 index 0000000000..8e2a128d23 --- /dev/null +++ b/dubbo-plugin/dubbo-plugin-context/src/main/java/org/apache/dubbo/rpc/cluster/filter/support/CallbackConsumerContextFilter.java @@ -0,0 +1,36 @@ +/* + * 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.dubbo.rpc.cluster.filter.support; + +import org.apache.dubbo.common.extension.Activate; +import org.apache.dubbo.rpc.Filter; +import org.apache.dubbo.rpc.model.ApplicationModel; + +import static org.apache.dubbo.common.constants.CommonConstants.CALLBACK; + +/** + * CallbackConsumerContextFilter set current RpcContext with invoker,invocation, local host, remote host and port + * for consumer callback invoker.It does it to make the requires info available to execution thread's RpcContext. + * @see ConsumerContextFilter + */ +@Activate(group = CALLBACK, order = Integer.MIN_VALUE) +public class CallbackConsumerContextFilter extends ConsumerContextFilter implements Filter { + + public CallbackConsumerContextFilter(ApplicationModel applicationModel) { + super(applicationModel); + } +} diff --git a/dubbo-plugin/dubbo-plugin-context/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.Filter b/dubbo-plugin/dubbo-plugin-context/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.Filter index 4b7f067695..542659af8d 100644 --- a/dubbo-plugin/dubbo-plugin-context/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.Filter +++ b/dubbo-plugin/dubbo-plugin-context/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.Filter @@ -1 +1,2 @@ context=org.apache.dubbo.rpc.filter.ContextFilter +callback-consumer-context=org.apache.dubbo.rpc.cluster.filter.support.CallbackConsumerContextFilter diff --git a/dubbo-plugin/dubbo-plugin-generic-invoke/src/main/java/org/apache/dubbo/rpc/filter/GenericFilter.java b/dubbo-plugin/dubbo-plugin-generic-invoke/src/main/java/org/apache/dubbo/rpc/filter/GenericFilter.java index 5c260fbf4c..1d83f35aa3 100644 --- a/dubbo-plugin/dubbo-plugin-generic-invoke/src/main/java/org/apache/dubbo/rpc/filter/GenericFilter.java +++ b/dubbo-plugin/dubbo-plugin-generic-invoke/src/main/java/org/apache/dubbo/rpc/filter/GenericFilter.java @@ -208,6 +208,9 @@ public class GenericFilter implements Filter, Filter.Listener, ScopeModelAware { private Object[] getGsonGenericArgs(final Object[] args, Type[] types) { return IntStream.range(0, args.length).mapToObj(i -> { + if (args[i] == null) { + return null; + } if (!(args[i] instanceof String)) { throw new RpcException("When using GSON to deserialize generic dubbo request arguments, the arguments must be of type String"); } diff --git a/dubbo-plugin/dubbo-plugin-router-tag/src/main/java/org/apache/dubbo/rpc/cluster/router/tag/TagStateRouter.java b/dubbo-plugin/dubbo-plugin-router-tag/src/main/java/org/apache/dubbo/rpc/cluster/router/tag/TagStateRouter.java index c3470776b2..f6e7d9dc33 100644 --- a/dubbo-plugin/dubbo-plugin-router-tag/src/main/java/org/apache/dubbo/rpc/cluster/router/tag/TagStateRouter.java +++ b/dubbo-plugin/dubbo-plugin-router-tag/src/main/java/org/apache/dubbo/rpc/cluster/router/tag/TagStateRouter.java @@ -36,6 +36,7 @@ import org.apache.dubbo.rpc.cluster.router.state.BitList; import org.apache.dubbo.rpc.cluster.router.tag.model.TagRouterRule; import org.apache.dubbo.rpc.cluster.router.tag.model.TagRuleParser; +import java.util.Map; import java.util.Set; import java.util.function.Predicate; @@ -52,6 +53,7 @@ public class TagStateRouter extends AbstractStateRouter implements Configu public static final String NAME = "TAG_ROUTER"; private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(TagStateRouter.class); private static final String RULE_SUFFIX = ".tag-router"; + public static final char TAG_SEPERATOR = '|'; private volatile TagRouterRule tagRouterRule; private String application; @@ -106,7 +108,8 @@ public class TagStateRouter extends AbstractStateRouter implements Configu // if we are requesting for a Provider with a specific tag if (StringUtils.isNotEmpty(tag)) { - Set addresses = tagRouterRuleCopy.getTagnameToAddresses().get(tag); + Map> tagnameToAddresses = tagRouterRuleCopy.getTagnameToAddresses(); + Set addresses = selectAddressByTagLevel(tagnameToAddresses, tag, isForceUseTag(invocation)); // filter by dynamic tag group first if (addresses != null) { // null means tag not set result = filterInvoker(invokers, invoker -> addressMatches(invoker.getUrl(), addresses)); @@ -306,4 +309,34 @@ public class TagStateRouter extends AbstractStateRouter implements Configu public void setTagRouterRule(TagRouterRule tagRouterRule) { this.tagRouterRule = tagRouterRule; } + + /** + * select addresses by tag with level + *

+ * example: + * selector=beta|team1|partner1 + * step1.select tagAddresses with selector=beta|team1|partner1, if result is empty, then run step2 + * step2.select tagAddresses with selector=beta|team1, if result is empty, then run step3 + * step3.select tagAddresses with selector=beta, if result is empty, result is null + *

+ * + * @param tagAddresses + * @param tagSelector eg: beta|team1|partner1 + * @return + */ + public static Set selectAddressByTagLevel(Map> tagAddresses, String tagSelector, boolean isForce) { + if (isForce || StringUtils.isNotContains(tagSelector, TAG_SEPERATOR)) { + return tagAddresses.get(tagSelector); + } + String[] selectors = StringUtils.split(tagSelector, TAG_SEPERATOR); + for (int i = selectors.length; i > 0; i--) { + String selectorTmp = StringUtils.join(selectors, TAG_SEPERATOR, 0, i); + Set addresses = tagAddresses.get(selectorTmp); + if (CollectionUtils.isNotEmpty(addresses)) { + return addresses; + } + } + return null; + } + } diff --git a/dubbo-plugin/dubbo-plugin-router-tag/src/test/java/org/apache/dubbo/rpc/cluster/router/tag/TagStateRouterTest.java b/dubbo-plugin/dubbo-plugin-router-tag/src/test/java/org/apache/dubbo/rpc/cluster/router/tag/TagStateRouterTest.java index 228a667eef..6477c09b6c 100644 --- a/dubbo-plugin/dubbo-plugin-router-tag/src/test/java/org/apache/dubbo/rpc/cluster/router/tag/TagStateRouterTest.java +++ b/dubbo-plugin/dubbo-plugin-router-tag/src/test/java/org/apache/dubbo/rpc/cluster/router/tag/TagStateRouterTest.java @@ -24,7 +24,6 @@ import org.apache.dubbo.common.utils.Holder; import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.RpcInvocation; import org.apache.dubbo.rpc.cluster.router.MockInvoker; -//import org.apache.dubbo.rpc.cluster.router.mesh.util.TracingContextProvider; import org.apache.dubbo.rpc.cluster.router.state.BitList; import org.apache.dubbo.rpc.cluster.router.state.StateRouter; import org.apache.dubbo.rpc.cluster.router.tag.model.TagRouterRule; @@ -32,13 +31,17 @@ import org.apache.dubbo.rpc.cluster.router.tag.model.TagRuleParser; import org.apache.dubbo.rpc.model.ApplicationModel; import org.apache.dubbo.rpc.model.ModuleModel; +import com.google.common.collect.Sets; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mockito; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.Set; import static org.apache.dubbo.common.constants.CommonConstants.TAG_KEY; import static org.mockito.Mockito.when; @@ -256,4 +259,47 @@ class TagStateRouterTest { TagRouterRule tagRouterRule = TagRuleParser.parse(tagRouterRuleConfig); return tagRouterRule; } + + @Test + public void tagMultiLevelTest() { + String tagSelector = "beta|team1|partner1"; + Set address1 = Sets.newHashSet("192.168.5.1:20880"); + Map> tagAddresses = new HashMap<>(); + tagAddresses.put("beta", address1); + Assertions.assertEquals(address1, TagStateRouter.selectAddressByTagLevel(tagAddresses, tagSelector, false)); + + Set address2 = Sets.newHashSet("192.168.5.2:20880"); + tagAddresses.put("beta|team1", address2); + Assertions.assertEquals(address2, TagStateRouter.selectAddressByTagLevel(tagAddresses, tagSelector, false)); + + Set address3 = Sets.newHashSet("192.168.5.3:20880"); + tagAddresses.put("beta|team1|partner1", address3); + Assertions.assertEquals(address3, TagStateRouter.selectAddressByTagLevel(tagAddresses, tagSelector, false)); + + tagSelector = "beta"; + Assertions.assertEquals(address1, TagStateRouter.selectAddressByTagLevel(tagAddresses, tagSelector, false)); + tagSelector = "beta|team1"; + Assertions.assertEquals(address2, TagStateRouter.selectAddressByTagLevel(tagAddresses, tagSelector, false)); + tagSelector = "beta|team1|partner1"; + Assertions.assertEquals(address3, TagStateRouter.selectAddressByTagLevel(tagAddresses, tagSelector, false)); + + tagSelector = "beta2"; + Assertions.assertNull(TagStateRouter.selectAddressByTagLevel(tagAddresses, tagSelector, false)); + tagSelector = "beta|team2"; + Assertions.assertEquals(address1, TagStateRouter.selectAddressByTagLevel(tagAddresses, tagSelector, false)); + tagSelector = "beta|team1|partner2"; + Assertions.assertEquals(address2, TagStateRouter.selectAddressByTagLevel(tagAddresses, tagSelector, false)); + + + } + + @Test + public void tagLevelForceTest() { + Set addresses = Sets.newHashSet("192.168.1.223:20880"); + Map> tagAddresses = new HashMap<>(); + tagAddresses.put("beta", addresses); + Set selectedAddresses = TagStateRouter.selectAddressByTagLevel(tagAddresses, "beta", true); + Assertions.assertEquals(addresses, selectedAddresses); + } + } diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/BaseOffline.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/BaseOffline.java index 1832d0b55d..0e21d2c429 100644 --- a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/BaseOffline.java +++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/BaseOffline.java @@ -19,6 +19,7 @@ package org.apache.dubbo.qos.command.impl; import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.utils.ArrayUtils; +import org.apache.dubbo.common.utils.NamedThreadFactory; import org.apache.dubbo.qos.api.BaseCommand; import org.apache.dubbo.qos.api.CommandContext; import org.apache.dubbo.registry.Registry; @@ -29,7 +30,12 @@ import org.apache.dubbo.rpc.model.ProviderModel; import org.apache.dubbo.rpc.model.ServiceMetadata; import java.util.Collection; +import java.util.LinkedList; import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; public class BaseOffline implements BaseCommand { private static final Logger logger = LoggerFactory.getLogger(BaseOffline.class); @@ -63,18 +69,31 @@ public class BaseOffline implements BaseCommand { public boolean offline(String servicePattern) { boolean hasService = false; - Collection providerModelList = serviceRepository.allProviderModels(); - for (ProviderModel providerModel : providerModelList) { - ServiceMetadata metadata = providerModel.getServiceMetadata(); - if (metadata.getServiceKey().matches(servicePattern) || metadata.getDisplayServiceKey().matches(servicePattern)) { - hasService = true; - List statedUrls = providerModel.getStatedUrl(); - for (ProviderModel.RegisterStatedURL statedURL : statedUrls) { - if (statedURL.isRegistered()) { - doUnexport(statedURL); + ExecutorService executorService = Executors.newFixedThreadPool(Math.min(Runtime.getRuntime().availableProcessors(), 4), new NamedThreadFactory("Dubbo-Offline")); + try { + List> futures = new LinkedList<>(); + Collection providerModelList = serviceRepository.allProviderModels(); + for (ProviderModel providerModel : providerModelList) { + ServiceMetadata metadata = providerModel.getServiceMetadata(); + if (metadata.getServiceKey().matches(servicePattern) || metadata.getDisplayServiceKey().matches(servicePattern)) { + hasService = true; + List statedUrls = providerModel.getStatedUrl(); + for (ProviderModel.RegisterStatedURL statedURL : statedUrls) { + if (statedURL.isRegistered()) { + futures.add(CompletableFuture.runAsync(() -> { + doUnexport(statedURL); + }, executorService)); + } } } } + for (CompletableFuture future : futures) { + future.get(); + } + } catch (ExecutionException | InterruptedException e) { + throw new RuntimeException(e); + } finally { + executorService.shutdown(); } return hasService; diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/GracefulShutdown.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/GracefulShutdown.java index c4fa69557d..f21e6473f8 100644 --- a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/GracefulShutdown.java +++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/GracefulShutdown.java @@ -37,11 +37,11 @@ public class GracefulShutdown implements BaseCommand { @Override public String execute(CommandContext commandContext, String[] args) { - offline.execute(commandContext, new String[0]); for (org.apache.dubbo.rpc.GracefulShutdown gracefulShutdown : org.apache.dubbo.rpc.GracefulShutdown.getGracefulShutdowns(frameworkModel)) { gracefulShutdown.readonly(); } + offline.execute(commandContext, new String[0]); return "OK"; } } diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistry.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistry.java index 9c6eb314de..95a196466e 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistry.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistry.java @@ -17,6 +17,7 @@ package org.apache.dubbo.registry.client; import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.constants.RegistryConstants; import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.utils.CollectionUtils; @@ -33,6 +34,7 @@ import org.apache.dubbo.registry.client.event.listener.ServiceInstancesChangedLi import org.apache.dubbo.registry.support.FailbackRegistry; import org.apache.dubbo.rpc.model.ApplicationModel; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; @@ -328,7 +330,9 @@ public class ServiceDiscoveryRegistry extends FailbackRegistry { serviceInstancesChangedListener.addListenerAndNotify(url, listener); ServiceInstancesChangedListener finalServiceInstancesChangedListener = serviceInstancesChangedListener; - MetricsEventBus.post(RegistryEvent.toSsEvent(url.getApplicationModel(), serviceKey), + String serviceDiscoveryName = url.getParameter(RegistryConstants.REGISTRY_CLUSTER_KEY, url.getProtocol()); + + MetricsEventBus.post(RegistryEvent.toSsEvent(url.getApplicationModel(), serviceKey, Collections.singletonList(serviceDiscoveryName)), () -> { serviceDiscovery.addServiceInstancesChangedListener(finalServiceInstancesChangedListener); return null; diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistryDirectory.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistryDirectory.java index baec948745..d5168aaf7c 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistryDirectory.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/ServiceDiscoveryRegistryDirectory.java @@ -21,6 +21,7 @@ import org.apache.dubbo.common.URL; import org.apache.dubbo.common.URLBuilder; import org.apache.dubbo.common.config.configcenter.DynamicConfiguration; import org.apache.dubbo.common.constants.CommonConstants; +import org.apache.dubbo.common.constants.RegistryConstants; import org.apache.dubbo.common.extension.ExtensionLoader; import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; import org.apache.dubbo.common.logger.LoggerFactory; @@ -34,6 +35,7 @@ import org.apache.dubbo.metadata.MetadataInfo; import org.apache.dubbo.registry.AddressListener; import org.apache.dubbo.registry.Constants; import org.apache.dubbo.registry.ProviderFirstParams; +import org.apache.dubbo.registry.Registry; import org.apache.dubbo.registry.integration.AbstractConfiguratorListener; import org.apache.dubbo.registry.integration.DynamicDirectory; import org.apache.dubbo.rpc.Invocation; @@ -58,6 +60,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -66,6 +69,7 @@ import java.util.stream.Collectors; import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY; import static org.apache.dubbo.common.constants.CommonConstants.DISABLED_KEY; import static org.apache.dubbo.common.constants.CommonConstants.ENABLED_KEY; +import static org.apache.dubbo.common.constants.CommonConstants.INSTANCE_REGISTER_MODE; import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY; import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY; import static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_FAILED_DESTROY_INVOKER; @@ -73,6 +77,8 @@ import static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_FAI import static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_UNSUPPORTED; import static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_HASHMAP_LOAD_FACTOR; import static org.apache.dubbo.common.constants.RegistryConstants.EMPTY_PROTOCOL; +import static org.apache.dubbo.common.constants.RegistryConstants.REGISTER_MODE_KEY; +import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_KEY; import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_TYPE_KEY; import static org.apache.dubbo.common.constants.RegistryConstants.SERVICE_REGISTRY_TYPE; import static org.apache.dubbo.registry.Constants.CONFIGURATORS_SUFFIX; @@ -498,6 +504,18 @@ public class ServiceDiscoveryRegistryDirectory extends DynamicDirectory { this.destroyInvokers(); } + @Override + protected Map getDirectoryMeta() { + String registryKey = Optional.ofNullable(getRegistry()) + .map(Registry::getUrl) + .map(url -> url.getParameter(RegistryConstants.REGISTRY_CLUSTER_KEY, url.getParameter(RegistryConstants.REGISTRY_KEY, url.getProtocol()))) + .orElse("unknown"); + Map metas = new HashMap<>(); + metas.put(REGISTRY_KEY, registryKey); + metas.put(REGISTER_MODE_KEY, INSTANCE_REGISTER_MODE); + return metas; + } + /** * Check whether the invoker in the cache needs to be destroyed * If set attribute of url: refer.autodestroy=false, the invokers will only increase without decreasing,there may be a refer leak diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/ServiceInstanceMetadataUtils.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/ServiceInstanceMetadataUtils.java index 13434ceabc..fbb858aac0 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/ServiceInstanceMetadataUtils.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/ServiceInstanceMetadataUtils.java @@ -17,6 +17,7 @@ package org.apache.dubbo.registry.client.metadata; import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.constants.RegistryConstants; import org.apache.dubbo.common.extension.ExtensionLoader; import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; import org.apache.dubbo.common.logger.LoggerFactory; @@ -24,6 +25,8 @@ import org.apache.dubbo.common.utils.JsonUtils; import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.metadata.MetadataInfo; import org.apache.dubbo.metadata.MetadataService; +import org.apache.dubbo.metrics.event.MetricsEventBus; +import org.apache.dubbo.metrics.registry.event.RegistryEvent; import org.apache.dubbo.registry.client.DefaultServiceInstance; import org.apache.dubbo.registry.client.DefaultServiceInstance.Endpoint; import org.apache.dubbo.registry.client.ServiceDiscovery; @@ -33,6 +36,7 @@ import org.apache.dubbo.registry.support.RegistryManager; import org.apache.dubbo.rpc.model.ApplicationModel; import java.util.ArrayList; +import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -44,6 +48,7 @@ import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY; import static org.apache.dubbo.common.constants.CommonConstants.PORT_KEY; import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY; import static org.apache.dubbo.common.constants.CommonConstants.TIMESTAMP_KEY; +import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_KEY; import static org.apache.dubbo.common.utils.StringUtils.isBlank; import static org.apache.dubbo.registry.integration.InterfaceCompatibleRegistryProtocol.DEFAULT_REGISTER_PROVIDER_KEYS; import static org.apache.dubbo.rpc.Constants.DEPRECATED_KEY; @@ -201,7 +206,22 @@ public class ServiceInstanceMetadataUtils { LOGGER.info("Start registering instance address to registry."); RegistryManager registryManager = applicationModel.getBeanFactory().getBean(RegistryManager.class); // register service instance - registryManager.getServiceDiscoveries().forEach(ServiceDiscovery::register); + List serviceDiscoveries = registryManager.getServiceDiscoveries(); + for (ServiceDiscovery serviceDiscovery : serviceDiscoveries) { + MetricsEventBus.post(RegistryEvent.toRegisterEvent(applicationModel, + Collections.singletonList(getServiceDiscoveryName(serviceDiscovery))), + () -> { + // register service instance + serviceDiscoveries.forEach(ServiceDiscovery::register); + return null; + } + ); + } + } + + private static String getServiceDiscoveryName(ServiceDiscovery serviceDiscovery) { + return serviceDiscovery.getUrl().getParameter(RegistryConstants.REGISTRY_CLUSTER_KEY, + serviceDiscovery.getUrl().getParameter(REGISTRY_KEY)); } public static void refreshMetadataAndInstance(ApplicationModel applicationModel) { diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryDirectory.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryDirectory.java index a484453322..cf33c533f1 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryDirectory.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryDirectory.java @@ -19,6 +19,7 @@ package org.apache.dubbo.registry.integration; import org.apache.dubbo.common.URL; import org.apache.dubbo.common.URLBuilder; import org.apache.dubbo.common.config.configcenter.DynamicConfiguration; +import org.apache.dubbo.common.constants.RegistryConstants; import org.apache.dubbo.common.extension.ExtensionLoader; import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; import org.apache.dubbo.common.logger.LoggerFactory; @@ -33,6 +34,7 @@ import org.apache.dubbo.common.utils.UrlUtils; import org.apache.dubbo.metrics.event.MetricsEventBus; import org.apache.dubbo.metrics.registry.event.RegistryEvent; import org.apache.dubbo.registry.AddressListener; +import org.apache.dubbo.registry.Registry; import org.apache.dubbo.remoting.Constants; import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Protocol; @@ -62,6 +64,7 @@ import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY; import static org.apache.dubbo.common.constants.CommonConstants.DISABLED_KEY; import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL; import static org.apache.dubbo.common.constants.CommonConstants.ENABLED_KEY; +import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_REGISTER_MODE; import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY; import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY; import static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_FAILED_INIT_SERIALIZATION_OPTIMIZER; @@ -79,6 +82,8 @@ import static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_HASHMA import static org.apache.dubbo.common.constants.RegistryConstants.DYNAMIC_CONFIGURATORS_CATEGORY; import static org.apache.dubbo.common.constants.RegistryConstants.EMPTY_PROTOCOL; import static org.apache.dubbo.common.constants.RegistryConstants.PROVIDERS_CATEGORY; +import static org.apache.dubbo.common.constants.RegistryConstants.REGISTER_MODE_KEY; +import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_KEY; import static org.apache.dubbo.common.constants.RegistryConstants.ROUTERS_CATEGORY; import static org.apache.dubbo.common.constants.RegistryConstants.ROUTE_PROTOCOL; import static org.apache.dubbo.registry.Constants.CONFIGURATORS_SUFFIX; @@ -130,7 +135,8 @@ public class RegistryDirectory extends DynamicDirectory { } ApplicationModel applicationModel = url.getApplicationModel(); - MetricsEventBus.post(RegistryEvent.toSubscribeEvent(applicationModel), () -> + String registryClusterName = registry.getUrl().getParameter(RegistryConstants.REGISTRY_CLUSTER_KEY, registry.getUrl().getParameter(PROTOCOL_KEY)); + MetricsEventBus.post(RegistryEvent.toSubscribeEvent(applicationModel,registryClusterName), () -> { super.subscribe(url); return null; @@ -644,6 +650,18 @@ public class RegistryDirectory extends DynamicDirectory { return false; } + @Override + protected Map getDirectoryMeta() { + String registryKey = Optional.ofNullable(getRegistry()) + .map(Registry::getUrl) + .map(url -> url.getParameter(RegistryConstants.REGISTRY_CLUSTER_KEY, url.getProtocol())) + .orElse("unknown"); + Map metas = new HashMap<>(); + metas.put(REGISTRY_KEY, registryKey); + metas.put(REGISTER_MODE_KEY, INTERFACE_REGISTER_MODE); + return metas; + } + private boolean isNotCompatibleFor26x(URL url) { return StringUtils.isEmpty(url.getParameter(COMPATIBLE_CONFIG_KEY)); } diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryProtocol.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryProtocol.java index f2818b7721..f8d3f72e77 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryProtocol.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryProtocol.java @@ -18,6 +18,7 @@ package org.apache.dubbo.registry.integration; import org.apache.dubbo.common.URL; import org.apache.dubbo.common.config.configcenter.DynamicConfiguration; +import org.apache.dubbo.common.constants.RegistryConstants; import org.apache.dubbo.common.deploy.ApplicationDeployer; import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; import org.apache.dubbo.common.logger.LoggerFactory; @@ -29,6 +30,8 @@ import org.apache.dubbo.common.utils.ConcurrentHashSet; import org.apache.dubbo.common.utils.NamedThreadFactory; import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.common.utils.UrlUtils; +import org.apache.dubbo.metrics.event.MetricsEventBus; +import org.apache.dubbo.metrics.registry.event.RegistryEvent; import org.apache.dubbo.registry.NotifyListener; import org.apache.dubbo.registry.Registry; import org.apache.dubbo.registry.RegistryFactory; @@ -60,9 +63,11 @@ import org.apache.dubbo.rpc.protocol.InvokerWrapper; import org.apache.dubbo.rpc.support.ProtocolUtils; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -224,7 +229,16 @@ public class RegistryProtocol implements Protocol, ScopeModelAware { ApplicationDeployer deployer = registeredProviderUrl.getOrDefaultApplicationModel().getDeployer(); try { deployer.increaseServiceRefreshCount(); - registry.register(registeredProviderUrl); + String registryName = Optional.ofNullable(registry.getUrl()) + .map(u -> u.getParameter(RegistryConstants.REGISTRY_CLUSTER_KEY, + UrlUtils.isServiceDiscoveryURL(u) ? u.getParameter(REGISTRY_KEY) : u.getProtocol())) + .filter(StringUtils::isNotEmpty) + .orElse("unknown"); + MetricsEventBus.post(RegistryEvent.toRsEvent(registeredProviderUrl.getApplicationModel(), registeredProviderUrl.getServiceKey(), 1, Collections.singletonList(registryName)), + () -> { + registry.register(registeredProviderUrl); + return null; + }); } finally { deployer.decreaseServiceRefreshCount(); } @@ -1001,12 +1015,26 @@ public class RegistryProtocol implements Protocol, ScopeModelAware { @Override public synchronized void unregister() { if (registered.compareAndSet(true, false)) { - Registry registry = RegistryProtocol.this.getRegistry(getRegistryUrl(originInvoker)); - try { - registry.unregister(registerUrl); - } catch (Throwable t) { - logger.warn(INTERNAL_ERROR, "unknown error in registry module", "", t.getMessage(), t); + URL registryUrl = getRegistryUrl(originInvoker); + Registry registry = RegistryProtocol.this.getRegistry(registryUrl); + + ProviderModel providerModel = frameworkModel.getServiceRepository() + .lookupExportedService(getRegisterUrl().getServiceKey()); + + List statedURLs = + providerModel.getStatedUrl() + .stream() + .filter(u -> u.getRegistryUrl().equals(registryUrl) + && u.getProviderUrl().getProtocol().equals(getRegisterUrl().getProtocol())) + .collect(Collectors.toList()); + if (statedURLs.isEmpty() || statedURLs.stream().anyMatch(ProviderModel.RegisterStatedURL::isRegistered)) { + try { + registry.unregister(registerUrl); + } catch (Throwable t) { + logger.warn(INTERNAL_ERROR, "unknown error in registry module", "", t.getMessage(), t); + } } + try { if (subscribeUrl != null) { Map> overrideListeners = getProviderConfigurationListener(subscribeUrl).getOverrideListeners(); diff --git a/dubbo-remoting/dubbo-remoting-netty4/pom.xml b/dubbo-remoting/dubbo-remoting-netty4/pom.xml index 447da39ef6..f94dce6bf3 100644 --- a/dubbo-remoting/dubbo-remoting-netty4/pom.xml +++ b/dubbo-remoting/dubbo-remoting-netty4/pom.xml @@ -40,7 +40,16 @@ dubbo-remoting-api ${project.parent.version} - + + org.apache.dubbo + dubbo-metrics-api + ${project.parent.version} + + + org.apache.dubbo + dubbo-metrics-netty + ${project.parent.version} + io.netty netty-handler-proxy diff --git a/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyServer.java b/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyServer.java index 8511370b5d..6acf226391 100644 --- a/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyServer.java +++ b/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyServer.java @@ -20,8 +20,12 @@ import org.apache.dubbo.common.URL; import org.apache.dubbo.common.config.ConfigurationUtils; import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; import org.apache.dubbo.common.logger.LoggerFactory; +import org.apache.dubbo.common.utils.ClassUtils; import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.common.utils.NetUtils; +import org.apache.dubbo.metrics.event.MetricsEventBus; +import org.apache.dubbo.metrics.model.key.MetricsKey; +import org.apache.dubbo.metrics.registry.event.NettyEvent; import org.apache.dubbo.remoting.Channel; import org.apache.dubbo.remoting.ChannelHandler; import org.apache.dubbo.remoting.Constants; @@ -30,6 +34,7 @@ import org.apache.dubbo.remoting.transport.AbstractServer; import org.apache.dubbo.remoting.transport.dispatcher.ChannelHandlers; import org.apache.dubbo.remoting.transport.netty4.ssl.SslServerTlsHandler; import org.apache.dubbo.remoting.utils.UrlUtils; +import org.apache.dubbo.rpc.model.ApplicationModel; import io.netty.bootstrap.ServerBootstrap; import io.netty.buffer.PooledByteBufAllocator; @@ -44,6 +49,7 @@ import io.netty.util.concurrent.Future; import java.net.InetSocketAddress; import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; import java.util.Map; import static java.util.concurrent.TimeUnit.MILLISECONDS; @@ -109,6 +115,26 @@ public class NettyServer extends AbstractServer { channelFuture.syncUninterruptibly(); channel = channelFuture.channel(); + // metrics + if (isSupportMetrics()) { + ApplicationModel applicationModel = ApplicationModel.defaultModel(); + MetricsEventBus.post(NettyEvent.toNettyEvent(applicationModel), () -> { + Map dataMap = new HashMap<>(); + dataMap.put(MetricsKey.NETTY_ALLOCATOR_HEAP_MEMORY_USED.getName(), PooledByteBufAllocator.DEFAULT.metric().usedHeapMemory()); + dataMap.put(MetricsKey.NETTY_ALLOCATOR_DIRECT_MEMORY_USED.getName(), PooledByteBufAllocator.DEFAULT.metric().usedDirectMemory()); + dataMap.put(MetricsKey.NETTY_ALLOCATOR_HEAP_ARENAS_NUM.getName(), (long) PooledByteBufAllocator.DEFAULT.numHeapArenas()); + dataMap.put(MetricsKey.NETTY_ALLOCATOR_DIRECT_ARENAS_NUM.getName(), (long) PooledByteBufAllocator.DEFAULT.numDirectArenas()); + dataMap.put(MetricsKey.NETTY_ALLOCATOR_NORMAL_CACHE_SIZE.getName(), (long) PooledByteBufAllocator.DEFAULT.normalCacheSize()); + dataMap.put(MetricsKey.NETTY_ALLOCATOR_SMALL_CACHE_SIZE.getName(), (long) PooledByteBufAllocator.DEFAULT.smallCacheSize()); + dataMap.put(MetricsKey.NETTY_ALLOCATOR_THREAD_LOCAL_CACHES_NUM.getName(), (long) PooledByteBufAllocator.DEFAULT.numThreadLocalCaches()); + dataMap.put(MetricsKey.NETTY_ALLOCATOR_CHUNK_SIZE.getName(), (long) PooledByteBufAllocator.DEFAULT.chunkSize()); + return dataMap; + }); + } + } + + private boolean isSupportMetrics() { + return ClassUtils.isPresent("io.netty.buffer.PooledByteBufAllocatorMetric", NettyServer.class.getClassLoader()); } protected EventLoopGroup createBossGroup() { diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/CallbackServiceCodec.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/CallbackServiceCodec.java index 2bc90887fb..7c15e8a26e 100644 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/CallbackServiceCodec.java +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/CallbackServiceCodec.java @@ -18,6 +18,7 @@ package org.apache.dubbo.rpc.protocol.dubbo; import org.apache.dubbo.common.BaseServiceMetadata; import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.constants.CommonConstants; import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.url.component.ServiceConfigURL; @@ -33,10 +34,12 @@ import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Protocol; import org.apache.dubbo.rpc.ProxyFactory; import org.apache.dubbo.rpc.RpcInvocation; +import org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder; import org.apache.dubbo.rpc.model.ApplicationModel; import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.model.ModuleModel; import org.apache.dubbo.rpc.model.ProviderModel; +import org.apache.dubbo.rpc.model.ScopeModelUtil; import org.apache.dubbo.rpc.model.ServiceDescriptor; import org.apache.dubbo.rpc.model.ServiceMetadata; import org.apache.dubbo.rpc.support.RpcUtils; @@ -47,11 +50,14 @@ import java.util.Map; import java.util.Set; import static org.apache.dubbo.common.constants.CommonConstants.CALLBACK_INSTANCES_LIMIT_KEY; +import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SIDE; import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_CALLBACK_INSTANCES; import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL; import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY; import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY; import static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY; +import static org.apache.dubbo.common.constants.CommonConstants.REFERENCE_FILTER_KEY; +import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY; import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY; import static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_PROPERTY_TYPE_MISMATCH; import static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_FAILED_DESTROY_INVOKER; @@ -202,11 +208,16 @@ public class CallbackServiceCodec { if (isRefer) { if (proxy == null) { URL referurl = URL.valueOf("callback://" + url.getAddress() + "/" + clazz.getName() + "?" + INTERFACE_KEY + "=" + clazz.getName()); - referurl = referurl.addParametersIfAbsent(url.getParameters()).removeParameter(METHODS_KEY); + referurl = referurl.addParametersIfAbsent(url.getParameters()).removeParameter(METHODS_KEY).addParameter(SIDE_KEY, CONSUMER_SIDE); if (!isInstancesOverLimit(channel, referurl, clazz.getName(), instid, true)) { url.getOrDefaultApplicationModel().getDefaultModule().getServiceRepository().registerService(clazz); @SuppressWarnings("rawtypes") Invoker invoker = new ChannelWrappedInvoker(clazz, channel, referurl, String.valueOf(instid)); + + FilterChainBuilder builder = getFilterChainBuilder(url); + invoker = builder.buildInvokerChain(invoker, REFERENCE_FILTER_KEY, CommonConstants.CONSUMER); + invoker = builder.buildInvokerChain(invoker, REFERENCE_FILTER_KEY, CommonConstants.CALLBACK); + proxy = proxyFactory.getProxy(invoker); channel.setAttribute(proxyCacheKey, proxy); channel.setAttribute(invokerCacheKey, invoker); @@ -244,6 +255,10 @@ public class CallbackServiceCodec { return proxy; } + private FilterChainBuilder getFilterChainBuilder(URL url) { + return ScopeModelUtil.getExtensionLoader(FilterChainBuilder.class, url.getScopeModel()).getDefaultExtension(); + } + private static String getClientSideCallbackServiceCacheKey(int instid) { return CALLBACK_SERVICE_KEY + "." + instid; } diff --git a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/Constants.java b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/Constants.java index c2918062f4..c7d49dd316 100644 --- a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/Constants.java +++ b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/Constants.java @@ -31,10 +31,4 @@ public interface Constants { String NETTY_HTTP = "netty_http"; - // exception mapper - String EXCEPTION_MAPPER_KEY = "exception.mapper"; - - - - } diff --git a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/PathAndInvokerMapper.java b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/PathAndInvokerMapper.java index d04b652958..c9fea955ec 100644 --- a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/PathAndInvokerMapper.java +++ b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/PathAndInvokerMapper.java @@ -24,7 +24,10 @@ import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.protocol.rest.exception.DoublePathCheckException; import org.apache.dubbo.rpc.protocol.rest.pair.InvokerAndRestMethodMetadataPair; +import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; /** @@ -36,6 +39,8 @@ public class PathAndInvokerMapper { private final Map pathToServiceMapContainPathVariable = new ConcurrentHashMap<>(); private final Map pathToServiceMapNoPathVariable = new ConcurrentHashMap<>(); + // for http method compare 405 + private final Map> pathMatcherToHttpMethodMap = new HashMap<>(); /** * deploy path metadata @@ -105,7 +110,7 @@ public class PathAndInvokerMapper { InvokerAndRestMethodMetadataPair beforeMetadata = pathMatcherPairMap.get(pathMatcher); // true when reExport - if (!invokerRestMethodMetadataPair.compareServiceMethod(beforeMetadata)){ + if (!invokerRestMethodMetadataPair.compareServiceMethod(beforeMetadata)) { throw new DoublePathCheckException( "dubbo rest double path check error, current path is: " + pathMatcher + " ,and service method is: " + invokerRestMethodMetadataPair.getRestMethodMetadata().getReflectMethod() @@ -116,8 +121,57 @@ public class PathAndInvokerMapper { pathMatcherPairMap.put(pathMatcher, invokerRestMethodMetadataPair); + addPathMatcherToHttpMethodsMap(pathMatcher); + logger.info("dubbo rest deploy pathMatcher:" + pathMatcher + ", and service method is :" + invokerRestMethodMetadataPair.getRestMethodMetadata().getReflectMethod()); } + private void addPathMatcherToHttpMethodsMap(PathMatcher pathMatcher) { + + PathMatcher newPathMatcher = PathMatcher.convertPathMatcher(pathMatcher); + + if (!pathMatcherToHttpMethodMap.containsKey(newPathMatcher)) { + HashSet httpMethods = new HashSet<>(); + + httpMethods.add(pathMatcher.getHttpMethod()); + + pathMatcherToHttpMethodMap.put(newPathMatcher, httpMethods); + + } + + Set httpMethods = pathMatcherToHttpMethodMap.get(newPathMatcher); + + httpMethods.add(newPathMatcher.getHttpMethod()); + + } + + public boolean isHttpMethodAllowed(PathMatcher pathMatcher) { + + PathMatcher newPathMatcher = PathMatcher.convertPathMatcher(pathMatcher); + if (!pathMatcherToHttpMethodMap.containsKey(newPathMatcher)) { + return false; + } + + + Set httpMethods = pathMatcherToHttpMethodMap.get(newPathMatcher); + + return httpMethods.contains(newPathMatcher.getHttpMethod()); + + } + + public String pathHttpMethods(PathMatcher pathMatcher) { + + PathMatcher newPathMatcher = PathMatcher.convertPathMatcher(pathMatcher); + if (!pathMatcherToHttpMethodMap.containsKey(newPathMatcher)) { + return null; + } + + + Set httpMethods = pathMatcherToHttpMethodMap.get(newPathMatcher); + + return httpMethods.toString(); + + } + } diff --git a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/RestRPCInvocationUtil.java b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/RestRPCInvocationUtil.java index 5acfc98998..b3205d55ec 100644 --- a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/RestRPCInvocationUtil.java +++ b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/RestRPCInvocationUtil.java @@ -23,7 +23,6 @@ import org.apache.dubbo.metadata.rest.ArgInfo; import org.apache.dubbo.metadata.rest.PathMatcher; import org.apache.dubbo.metadata.rest.RestMethodMetadata; import org.apache.dubbo.rpc.Invoker; -import org.apache.dubbo.rpc.RpcContext; import org.apache.dubbo.rpc.RpcInvocation; import org.apache.dubbo.rpc.protocol.rest.annotation.ParamParserManager; import org.apache.dubbo.rpc.protocol.rest.annotation.param.parse.provider.ProviderParseContext; @@ -39,9 +38,6 @@ import java.lang.reflect.Method; import java.util.Arrays; import java.util.List; -import static org.apache.dubbo.common.constants.CommonConstants.SERVICE_DEPLOYER_ATTRIBUTE_KEY; - - public class RestRPCInvocationUtil { private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(RestRPCInvocationUtil.class); @@ -142,13 +138,8 @@ public class RestRPCInvocationUtil { * @param pathMatcher * @return */ - public static InvokerAndRestMethodMetadataPair getRestMethodMetadataAndInvokerPair(PathMatcher pathMatcher) { + public static InvokerAndRestMethodMetadataPair getRestMethodMetadataAndInvokerPair(PathMatcher pathMatcher, ServiceDeployer serviceDeployer) { - ServiceDeployer serviceDeployer = (ServiceDeployer) RpcContext.getServiceContext().getObjectAttachment(SERVICE_DEPLOYER_ATTRIBUTE_KEY); - - if (serviceDeployer == null) { - return null; - } return serviceDeployer.getPathAndInvokerMapper().getRestMethodMetadata(pathMatcher); } @@ -164,7 +155,7 @@ public class RestRPCInvocationUtil { PathMatcher pathMather = createPathMatcher(request); - return getRestMethodMetadataAndInvokerPair(pathMather); + return getRestMethodMetadataAndInvokerPair(pathMather, request.getServiceDeployer()); } @@ -179,20 +170,20 @@ public class RestRPCInvocationUtil { PathMatcher pathMatcher = createPathMatcher(request); - return getInvoker(pathMatcher); + return getInvoker(pathMatcher, request.getServiceDeployer()); } /** * get invoker by service method - * + *

* compare method`s name,param types * * @param serviceMethod * @return */ - public static Invoker getInvokerByServiceInvokeMethod(Method serviceMethod) { + public static Invoker getInvokerByServiceInvokeMethod(Method serviceMethod, ServiceDeployer serviceDeployer) { if (serviceMethod == null) { return null; @@ -200,7 +191,7 @@ public class RestRPCInvocationUtil { PathMatcher pathMatcher = PathMatcher.getInvokeCreatePathMatcher(serviceMethod); - InvokerAndRestMethodMetadataPair pair = getRestMethodMetadataAndInvokerPair(pathMatcher); + InvokerAndRestMethodMetadataPair pair = getRestMethodMetadataAndInvokerPair(pathMatcher, serviceDeployer); if (pair == null) { return null; @@ -215,8 +206,8 @@ public class RestRPCInvocationUtil { * @param pathMatcher * @return */ - public static Invoker getInvoker(PathMatcher pathMatcher) { - InvokerAndRestMethodMetadataPair pair = getRestMethodMetadataAndInvokerPair(pathMatcher); + public static Invoker getInvoker(PathMatcher pathMatcher, ServiceDeployer serviceDeployer) { + InvokerAndRestMethodMetadataPair pair = getRestMethodMetadataAndInvokerPair(pathMatcher, serviceDeployer); if (pair == null) { return null; diff --git a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/deploy/ServiceDeployer.java b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/deploy/ServiceDeployer.java index 0c75ba5bfb..1830dc2e86 100644 --- a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/deploy/ServiceDeployer.java +++ b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/deploy/ServiceDeployer.java @@ -144,4 +144,15 @@ public class ServiceDeployer { } + public boolean isMethodAllowed(PathMatcher pathMatcher) { + return pathAndInvokerMapper.isHttpMethodAllowed(pathMatcher); + } + + public boolean hashRestMethod(PathMatcher pathMatcher) { + return pathAndInvokerMapper.getRestMethodMetadata(pathMatcher) != null; + } + + public String pathHttpMethods(PathMatcher pathMatcher) { + return pathAndInvokerMapper.pathHttpMethods(pathMatcher); + } } diff --git a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/extension/resteasy/filter/DubboBuiltResponse.java b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/extension/resteasy/filter/DubboBuiltResponse.java new file mode 100644 index 0000000000..1a034c2891 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/extension/resteasy/filter/DubboBuiltResponse.java @@ -0,0 +1,54 @@ +/* + * 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.dubbo.rpc.protocol.rest.extension.resteasy.filter; + +import org.jboss.resteasy.specimpl.BuiltResponse; + +/** + * wrapper resteasy BuiltResponse + */ +public class DubboBuiltResponse extends BuiltResponse { + + // user reset entity + private boolean resetEntity; + + public DubboBuiltResponse(Object entity, int status, Class entityClass) { + + this.entity = entity; + this.entityClass = entityClass; + this.status = status; + } + + + @Override + public void setEntity(Object entity) { + if (entity == null) { + return; + } + + if (entity.equals(this.entity)) { + return; + } + // reset entity true + this.resetEntity = true; + super.setEntity(entity); + } + + public boolean isResetEntity() { + return resetEntity; + } +} diff --git a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/extension/resteasy/filter/ResteasyResponseContainerFilterAdapter.java b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/extension/resteasy/filter/ResteasyResponseContainerFilterAdapter.java index bdee7cd9b2..c6af847ece 100644 --- a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/extension/resteasy/filter/ResteasyResponseContainerFilterAdapter.java +++ b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/extension/resteasy/filter/ResteasyResponseContainerFilterAdapter.java @@ -24,7 +24,6 @@ import org.apache.dubbo.rpc.protocol.rest.filter.RestResponseFilter; import org.apache.dubbo.rpc.protocol.rest.filter.context.RestFilterContext; import org.apache.dubbo.rpc.protocol.rest.netty.NettyHttpResponse; import org.apache.dubbo.rpc.protocol.rest.request.RequestFacade; -import org.jboss.resteasy.specimpl.BuiltResponse; import org.jboss.resteasy.spi.HttpResponse; import javax.ws.rs.container.ContainerResponseFilter; @@ -50,16 +49,18 @@ public class ResteasyResponseContainerFilterAdapter implements RestResponseFilte // response filter entity first - // empty jaxrsResponse - BuiltResponse jaxrsResponse = new BuiltResponse(); + // build jaxrsResponse from rest netty response + DubboBuiltResponse dubboBuiltResponse = new DubboBuiltResponse(response.getResponseBody(), response.getStatus(), response.getEntityClass()); // NettyHttpResponse wrapper HttpResponse httpResponse = new ResteasyNettyHttpResponse(response); - DubboContainerResponseContextImpl containerResponseContext = createContainerResponseContext(requestFacade, httpResponse, jaxrsResponse, containerRequestFilters.toArray(new ContainerResponseFilter[0])); + DubboContainerResponseContextImpl containerResponseContext = createContainerResponseContext(requestFacade, httpResponse, dubboBuiltResponse, containerRequestFilters.toArray(new ContainerResponseFilter[0])); containerResponseContext.filter(); - if (jaxrsResponse.getEntity() != null) { + + // user reset entity + if (dubboBuiltResponse.hasEntity() && dubboBuiltResponse.isResetEntity()) { // clean output stream data restOutputStream(response); - writeResteasyResponse(url, requestFacade, response, jaxrsResponse); + writeResteasyResponse(url, requestFacade, response, dubboBuiltResponse); } addResponseHeaders(response, httpResponse.getOutputHeaders()); diff --git a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/filter/ServiceInvokeRestFilter.java b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/filter/ServiceInvokeRestFilter.java index 0381b911bd..404f8edd5a 100644 --- a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/filter/ServiceInvokeRestFilter.java +++ b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/filter/ServiceInvokeRestFilter.java @@ -22,6 +22,7 @@ import org.apache.dubbo.common.URL; import org.apache.dubbo.common.extension.Activate; import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; import org.apache.dubbo.common.logger.LoggerFactory; +import org.apache.dubbo.metadata.rest.PathMatcher; import org.apache.dubbo.metadata.rest.RestMethodMetadata; import org.apache.dubbo.metadata.rest.media.MediaType; import org.apache.dubbo.rpc.Invoker; @@ -72,26 +73,28 @@ public class ServiceInvokeRestFilter implements RestRequestFilter { RequestFacade request, URL url, ServiceDeployer serviceDeployer) throws Exception { - // acquire metadata by request - InvokerAndRestMethodMetadataPair restMethodMetadataPair = RestRPCInvocationUtil.getRestMethodMetadataAndInvokerPair(request); + PathMatcher pathMatcher = RestRPCInvocationUtil.createPathMatcher(request); // path NoFound 404 - if (restMethodMetadataPair == null) { - throw new PathNoFoundException("rest service Path no found, current path info:" + RestRPCInvocationUtil.createPathMatcher(request)); + if (!serviceDeployer.hashRestMethod(pathMatcher)) { + throw new PathNoFoundException("rest service Path no found, current path info:" + pathMatcher); } - Invoker invoker = restMethodMetadataPair.getInvoker(); - - RestMethodMetadata restMethodMetadata = restMethodMetadataPair.getRestMethodMetadata(); // method disallowed - if (!restMethodMetadata.getRequest().methodAllowed(request.getMethod())) { + if (!serviceDeployer.isMethodAllowed(pathMatcher)) { nettyHttpResponse.sendError(405, "service require request method is : " - + restMethodMetadata.getRequest().getMethod() + + serviceDeployer.pathHttpMethods(pathMatcher) + ", but current request method is: " + request.getMethod() ); return; } + // compare http method and acquire metadata by request + InvokerAndRestMethodMetadataPair restMethodMetadataPair = RestRPCInvocationUtil.getRestMethodMetadataAndInvokerPair(pathMatcher.compareHttpMethod(true), serviceDeployer); + + Invoker invoker = restMethodMetadataPair.getInvoker(); + + RestMethodMetadata restMethodMetadata = restMethodMetadataPair.getRestMethodMetadata(); // content-type support judge,throw unSupportException @@ -106,6 +109,9 @@ public class ServiceInvokeRestFilter implements RestRequestFilter { // execute business method invoke Result result = invoker.invoke(rpcInvocation); + // set raw response + nettyHttpResponse.setResponseBody(result.getValue()); + if (result.hasException()) { Throwable exception = result.getException(); logger.error("", exception.getMessage(), "", "dubbo rest protocol provider Invoker invoke error", exception); @@ -150,7 +156,8 @@ public class ServiceInvokeRestFilter implements RestRequestFilter { public static void writeResult(NettyHttpResponse nettyHttpResponse, URL url, Object value, Class returnType, MediaType mediaType) throws Exception { MessageCodecResultPair booleanMediaTypePair = HttpMessageCodecManager.httpMessageEncode(nettyHttpResponse.getOutputStream(), value, url, mediaType, returnType); - + // reset raw response result + nettyHttpResponse.setResponseBody(value); nettyHttpResponse.addOutputHeaders(RestHeaderEnum.CONTENT_TYPE.getHeader(), booleanMediaTypePair.getMediaType().value); } diff --git a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/handler/NettyHttpHandler.java b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/handler/NettyHttpHandler.java index b179cc939e..e24207b792 100644 --- a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/handler/NettyHttpHandler.java +++ b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/handler/NettyHttpHandler.java @@ -38,8 +38,6 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; -import static org.apache.dubbo.common.constants.CommonConstants.SERVICE_DEPLOYER_ATTRIBUTE_KEY; - /** * netty http request handler @@ -76,8 +74,6 @@ public class NettyHttpHandler implements HttpHandler restFilters) throws Exception { RestFilterContext restFilterContext = new RestFilterContext(url, requestFacade, nettyHttpResponse, serviceDeployer); - for (RestFilter restResponseFilter : restFilters) { - restResponseFilter.filter(restFilterContext); + for (RestFilter restFilter : restFilters) { + restFilter.filter(restFilterContext); if (restFilterContext.complete()) { break; } diff --git a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/netty/ChunkOutputStream.java b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/netty/ChunkOutputStream.java index 53db275b7d..0e9d9bb904 100644 --- a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/netty/ChunkOutputStream.java +++ b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/netty/ChunkOutputStream.java @@ -21,6 +21,7 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.http.DefaultHttpContent; +import org.apache.dubbo.remoting.transport.ExceedPayloadLimitException; import java.io.IOException; import java.io.OutputStream; @@ -29,27 +30,32 @@ public class ChunkOutputStream extends OutputStream { final ByteBuf buffer; final ChannelHandlerContext ctx; final NettyHttpResponse response; + int chunkSize = 0; - ChunkOutputStream(final NettyHttpResponse response, final ChannelHandlerContext ctx, final int chunksize) { + ChunkOutputStream(final NettyHttpResponse response, final ChannelHandlerContext ctx, final int chunkSize) { this.response = response; - if (chunksize < 1) { + if (chunkSize < 1) { throw new IllegalArgumentException(); } - // TODO buffer pool - this.buffer = Unpooled.buffer(0, chunksize); + this.buffer = Unpooled.buffer(0, chunkSize); + this.chunkSize = chunkSize; this.ctx = ctx; } @Override public void write(int b) throws IOException { if (buffer.maxWritableBytes() < 1) { - flush(); + throwExceedPayloadLimitException(buffer.readableBytes() + 1); } buffer.writeByte(b); } - public void reset() - { + private void throwExceedPayloadLimitException(int dataSize) throws ExceedPayloadLimitException { + throw new ExceedPayloadLimitException( + "Data length too large: " + dataSize + ", max payload: " + chunkSize); + } + + public void reset() { if (response.isCommitted()) throw new IllegalStateException(); buffer.clear(); } @@ -65,16 +71,10 @@ public class ChunkOutputStream extends OutputStream { public void write(byte[] b, int off, int len) throws IOException { int dataLengthLeftToWrite = len; int dataToWriteOffset = off; - int spaceLeftInCurrentChunk; - while ((spaceLeftInCurrentChunk = buffer.maxWritableBytes()) < dataLengthLeftToWrite) { - buffer.writeBytes(b, dataToWriteOffset, spaceLeftInCurrentChunk); - dataToWriteOffset = dataToWriteOffset + spaceLeftInCurrentChunk; - dataLengthLeftToWrite = dataLengthLeftToWrite - spaceLeftInCurrentChunk; - flush(); - } - if (dataLengthLeftToWrite > 0) { - buffer.writeBytes(b, dataToWriteOffset, dataLengthLeftToWrite); + if (buffer.maxWritableBytes() < dataLengthLeftToWrite) { + throwExceedPayloadLimitException(buffer.readableBytes() + len); } + buffer.writeBytes(b, dataToWriteOffset, dataLengthLeftToWrite); } @Override diff --git a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/netty/NettyHttpResponse.java b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/netty/NettyHttpResponse.java index c092907f3f..4ed2c5525b 100644 --- a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/netty/NettyHttpResponse.java +++ b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/netty/NettyHttpResponse.java @@ -27,7 +27,9 @@ import io.netty.handler.codec.http.HttpHeaders.Names; import io.netty.handler.codec.http.HttpMethod; import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.handler.codec.http.LastHttpContent; +import org.apache.dubbo.common.URL; import org.apache.dubbo.metadata.rest.media.MediaType; +import org.apache.dubbo.remoting.Constants; import org.apache.dubbo.rpc.protocol.rest.RestHeaderEnum; @@ -54,16 +56,19 @@ public class NettyHttpResponse implements HttpResponse { private boolean committed; private boolean keepAlive; private HttpMethod method; + // raw response body + private Object responseBody; + // raw response class + private Class entityClass; - public NettyHttpResponse(final ChannelHandlerContext ctx, final boolean keepAlive) { - this(ctx, keepAlive, null); + public NettyHttpResponse(final ChannelHandlerContext ctx, final boolean keepAlive, URL url) { + this(ctx, keepAlive, null, url); } - public NettyHttpResponse(final ChannelHandlerContext ctx, final boolean keepAlive, final HttpMethod method) { + public NettyHttpResponse(final ChannelHandlerContext ctx, final boolean keepAlive, HttpMethod method, URL url) { outputHeaders = new HashMap<>(); this.method = method; - // TODO chunk size to config - os = new ChunkOutputStream(this, ctx, 1000); + os = new ChunkOutputStream(this, ctx, url.getParameter(Constants.PAYLOAD_KEY, Constants.DEFAULT_PAYLOAD)); this.ctx = ctx; this.keepAlive = keepAlive; } @@ -105,6 +110,7 @@ public class NettyHttpResponse implements HttpResponse { @Override public void sendError(int status, String message) throws IOException { setStatus(status); + setResponseBody(message); if (message != null) { getOutputStream().write(message.getBytes(StandardCharsets.UTF_8)); } @@ -211,4 +217,21 @@ public class NettyHttpResponse implements HttpResponse { } } + + public Object getResponseBody() { + return responseBody; + } + + public void setResponseBody(Object responseBody) { + + this.responseBody = responseBody; + + if (responseBody != null) { + this.entityClass = responseBody.getClass(); + } + } + + public Class getEntityClass() { + return entityClass; + } } diff --git a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/netty/RestHttpRequestDecoder.java b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/netty/RestHttpRequestDecoder.java index 311beaa451..d5233c3e10 100644 --- a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/netty/RestHttpRequestDecoder.java +++ b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/netty/RestHttpRequestDecoder.java @@ -28,12 +28,15 @@ import io.netty.handler.codec.http.HttpHeaders; import org.apache.dubbo.common.URL; import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; import org.apache.dubbo.common.logger.LoggerFactory; -import org.apache.dubbo.common.threadpool.ThreadPool; +import org.apache.dubbo.common.threadpool.manager.ExecutorRepository; +import org.apache.dubbo.common.utils.ExecutorUtil; import org.apache.dubbo.rpc.protocol.rest.RestHeaderEnum; import org.apache.dubbo.rpc.protocol.rest.deploy.ServiceDeployer; import org.apache.dubbo.rpc.protocol.rest.handler.NettyHttpHandler; import org.apache.dubbo.rpc.protocol.rest.request.NettyRequestFacade; +import static org.apache.dubbo.config.Constants.SERVER_THREAD_POOL_NAME; + public class RestHttpRequestDecoder extends MessageToMessageDecoder { private final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(getClass()); @@ -48,7 +51,7 @@ public class RestHttpRequestDecoder extends MessageToMessageDecoder out) throws Exception { boolean keepAlive = HttpHeaders.isKeepAlive(request); - NettyHttpResponse nettyHttpResponse = new NettyHttpResponse(ctx, keepAlive); - NettyRequestFacade requestFacade = new NettyRequestFacade(request, ctx); + NettyHttpResponse nettyHttpResponse = new NettyHttpResponse(ctx, keepAlive,url); + NettyRequestFacade requestFacade = new NettyRequestFacade(request, ctx,serviceDeployer); executor.execute(() -> { diff --git a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/request/NettyRequestFacade.java b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/request/NettyRequestFacade.java index 3c24717048..006b404766 100644 --- a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/request/NettyRequestFacade.java +++ b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/request/NettyRequestFacade.java @@ -23,6 +23,7 @@ import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.HttpContent; import org.apache.dubbo.common.utils.IOUtils; +import org.apache.dubbo.rpc.protocol.rest.deploy.ServiceDeployer; import java.io.IOException; import java.util.ArrayList; @@ -48,6 +49,12 @@ public class NettyRequestFacade extends RequestFacade { } + public NettyRequestFacade(Object request, ChannelHandlerContext context, ServiceDeployer serviceDeployer) { + super((FullHttpRequest) request, serviceDeployer); + this.context = context; + + } + protected void initHeaders() { for (Map.Entry header : request.headers()) { diff --git a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/request/RequestFacade.java b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/request/RequestFacade.java index 8d95ac60cb..ab0dcbf484 100644 --- a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/request/RequestFacade.java +++ b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/request/RequestFacade.java @@ -18,6 +18,7 @@ package org.apache.dubbo.rpc.protocol.rest.request; import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.rpc.protocol.rest.deploy.ServiceDeployer; import java.io.IOException; import java.util.ArrayList; @@ -37,6 +38,7 @@ public abstract class RequestFacade { protected String path; protected T request; protected byte[] body = new byte[0]; + protected ServiceDeployer serviceDeployer; public RequestFacade(T request) { this.request = request; @@ -45,6 +47,11 @@ public abstract class RequestFacade { parseBody(); } + public RequestFacade(T request, ServiceDeployer serviceDeployer) { + this(request); + this.serviceDeployer = serviceDeployer; + } + protected void initHeaders() { } @@ -131,5 +138,7 @@ public abstract class RequestFacade { protected abstract void parseBody(); - + public ServiceDeployer getServiceDeployer() { + return serviceDeployer; + } } diff --git a/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/JaxrsRestProtocolTest.java b/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/JaxrsRestProtocolTest.java index 8248b0246f..b20734cd44 100644 --- a/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/JaxrsRestProtocolTest.java +++ b/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/JaxrsRestProtocolTest.java @@ -63,6 +63,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import static org.apache.dubbo.remoting.Constants.SERVER_KEY; @@ -745,6 +746,35 @@ class JaxrsRestProtocolTest { exporter.unexport(); } + @Test + void testBody() { + + + Assertions.assertThrowsExactly(RpcException.class, () -> { + DemoService server = new DemoServiceImpl(); + + URL url = this.registerProvider(exportUrl, server, DemoService.class); + + URL nettyUrl = url.addParameter(org.apache.dubbo.remoting.Constants.PAYLOAD_KEY, 1024); + + Exporter exporter = protocol.export(proxy.getInvoker(server, DemoService.class, nettyUrl)); + + + DemoService demoService = this.proxy.getProxy(protocol.refer(DemoService.class, nettyUrl)); + + List users = new ArrayList<>(); + for (int i = 0; i < 10000; i++) { + users.add(User.getInstance()); + + } + + demoService.list(users); + + exporter.unexport(); + }); + + } + private URL registerProvider(URL url, Object impl, Class interfaceClass) { ServiceDescriptor serviceDescriptor = repository.registerService(interfaceClass); ProviderModel providerModel = new ProviderModel( diff --git a/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/rest/TestGetInvokerServiceImpl.java b/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/rest/TestGetInvokerServiceImpl.java index b61f4afdfa..ed66a1e3f8 100644 --- a/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/rest/TestGetInvokerServiceImpl.java +++ b/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/rest/TestGetInvokerServiceImpl.java @@ -31,6 +31,7 @@ public class TestGetInvokerServiceImpl implements TestGetInvokerService { @Override public String getInvoker() { Object request = RpcContext.getServiceContext().getRequest(); + RequestFacade requestFacade = (RequestFacade) request; Invoker invokerByRequest = RestRPCInvocationUtil.getInvokerByRequest((RequestFacade) request); @@ -44,9 +45,9 @@ public class TestGetInvokerServiceImpl implements TestGetInvokerService { } - Invoker invokerByServiceInvokeMethod = RestRPCInvocationUtil.getInvokerByServiceInvokeMethod(hello); + Invoker invokerByServiceInvokeMethod = RestRPCInvocationUtil.getInvokerByServiceInvokeMethod(hello,requestFacade.getServiceDeployer()); - Invoker invoker = RestRPCInvocationUtil.getInvokerByServiceInvokeMethod(hashcode); + Invoker invoker = RestRPCInvocationUtil.getInvokerByServiceInvokeMethod(hashcode,requestFacade.getServiceDeployer()); Assertions.assertEquals(invokerByRequest, invokerByServiceInvokeMethod); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleInvoker.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleInvoker.java index c5ba56b1db..61c6870c50 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleInvoker.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleInvoker.java @@ -25,6 +25,7 @@ import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.stream.StreamObserver; import org.apache.dubbo.common.threadpool.ThreadlessExecutor; +import org.apache.dubbo.common.utils.ReflectUtils; import org.apache.dubbo.remoting.api.connection.AbstractConnectionClient; import org.apache.dubbo.rpc.AppResponse; import org.apache.dubbo.rpc.AsyncRpcResult; @@ -55,6 +56,7 @@ import org.apache.dubbo.rpc.protocol.tri.compressor.Compressor; import org.apache.dubbo.rpc.protocol.tri.compressor.Identity; import org.apache.dubbo.rpc.protocol.tri.observer.ClientCallToObserverAdapter; import org.apache.dubbo.rpc.protocol.tri.transport.TripleWriteQueue; +import org.apache.dubbo.rpc.service.ServiceDescriptorInternalCache; import org.apache.dubbo.rpc.support.RpcUtils; import io.netty.util.AsciiString; @@ -65,6 +67,7 @@ import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; import java.util.concurrent.locks.ReentrantLock; +import java.util.stream.Collectors; import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY; import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PACKABLE_METHOD_FACTORY; @@ -131,9 +134,13 @@ public class TripleInvoker extends AbstractInvoker { ConsumerModel consumerModel = (ConsumerModel) (invocation.getServiceModel() != null ? invocation.getServiceModel() : getUrl().getServiceModel()); ServiceDescriptor serviceDescriptor = consumerModel.getServiceModel(); - final MethodDescriptor methodDescriptor = serviceDescriptor.getMethod( - invocation.getMethodName(), - invocation.getParameterTypes()); + final MethodDescriptor methodDescriptor; + boolean genericCall = RpcUtils.isGenericCall(ReflectUtils.getDesc(invocation.getParameterTypes()), invocation.getMethodName()); + if (!genericCall) { + methodDescriptor = serviceDescriptor.getMethod(invocation.getMethodName(), invocation.getParameterTypes()); + } else { + methodDescriptor = ServiceDescriptorInternalCache.genericService().getMethod(invocation.getMethodName(), invocation.getParameterTypes()); + } ExecutorService callbackExecutor = isSync(methodDescriptor, invocation) ? new ThreadlessExecutor() : streamExecutor; ClientCall call = new TripleClientCall(connectionClient, callbackExecutor, getUrl().getOrDefaultFrameworkModel(), writeQueue); @@ -239,7 +246,15 @@ public class TripleInvoker extends AbstractInvoker { if (methodDescriptor instanceof StubMethodDescriptor) { pureArgument = invocation.getArguments()[0]; } else { - pureArgument = invocation.getArguments(); + if (methodDescriptor.isGeneric()) { + Object[] args = new Object[3]; + args[0] = RpcUtils.getMethodName(invocation); + args[1] = Arrays.stream(RpcUtils.getParameterTypes(invocation)).map(Class::getName).collect(Collectors.toList()); + args[2] = RpcUtils.getArguments(invocation); + pureArgument = args; + } else { + pureArgument = invocation.getArguments(); + } } result = new AsyncRpcResult(future, invocation); if (setFutureWhenSync || ((RpcInvocation) invocation).getInvokeMode() != InvokeMode.SYNC) { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/call/TripleClientCall.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/call/TripleClientCall.java index 4ba712e843..3673bd5e83 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/call/TripleClientCall.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/call/TripleClientCall.java @@ -188,7 +188,7 @@ public class TripleClientCall implements ClientCall, ClientStream.Listener { } catch (Throwable t) { LOGGER.error(PROTOCOL_FAILED_SERIALIZE_TRIPLE, "", "", String.format("Serialize triple request failed, service=%s method=%s", requestMetadata.service, - requestMetadata.method), t); + requestMetadata.method.getMethodName()), t); cancelByLocal(t); listener.onClose(TriRpcStatus.INTERNAL.withDescription("Serialize request failed") .withCause(t), null, false); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/frame/TriDecoder.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/frame/TriDecoder.java index e2fbbcfb16..5fcfda427d 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/frame/TriDecoder.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/frame/TriDecoder.java @@ -17,12 +17,11 @@ package org.apache.dubbo.rpc.protocol.tri.frame; -import org.apache.dubbo.rpc.RpcException; -import org.apache.dubbo.rpc.protocol.tri.compressor.DeCompressor; - import io.netty.buffer.ByteBuf; import io.netty.buffer.CompositeByteBuf; import io.netty.buffer.Unpooled; +import org.apache.dubbo.rpc.RpcException; +import org.apache.dubbo.rpc.protocol.tri.compressor.DeCompressor; public class TriDecoder implements Deframer { @@ -152,6 +151,7 @@ public class TriDecoder implements Deframer { private byte[] getUncompressedBody() { byte[] data = new byte[requiredLength]; accumulate.readBytes(data); + accumulate.discardReadComponents(); return data; } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/stream/TripleClientStreamTest.java b/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/stream/TripleClientStreamTest.java index a95718b3ca..0ab866e6cc 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/stream/TripleClientStreamTest.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/test/java/org/apache/dubbo/rpc/protocol/tri/stream/TripleClientStreamTest.java @@ -17,8 +17,15 @@ package org.apache.dubbo.rpc.protocol.tri.stream; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.embedded.EmbeddedChannel; import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.netty.handler.codec.http.HttpScheme; +import io.netty.handler.codec.http2.DefaultHttp2Headers; import io.netty.handler.codec.http2.Http2StreamChannel; +import io.netty.util.concurrent.ImmediateEventExecutor; import org.apache.dubbo.common.URL; import org.apache.dubbo.rpc.TriRpcStatus; import org.apache.dubbo.rpc.model.ApplicationModel; @@ -38,21 +45,12 @@ import org.apache.dubbo.rpc.protocol.tri.compressor.Compressor; import org.apache.dubbo.rpc.protocol.tri.support.IGreeter; import org.apache.dubbo.rpc.protocol.tri.transport.H2TransportListener; import org.apache.dubbo.rpc.protocol.tri.transport.TripleWriteQueue; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.embedded.EmbeddedChannel; -import io.netty.handler.codec.http.HttpResponseStatus; -import io.netty.handler.codec.http.HttpScheme; -import io.netty.handler.codec.http2.DefaultHttp2Headers; -import io.netty.util.concurrent.ImmediateEventExecutor; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import java.util.concurrent.Executor; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -121,7 +119,6 @@ class TripleClientStreamTest { byte[] data = new byte[]{0, 0, 0, 0, 1, 1}; final ByteBuf buf = Unpooled.wrappedBuffer(data); transportListener.onData(buf, false); - buf.release(); Assertions.assertEquals(1, listener.message.length); } } diff --git a/dubbo-serialization/dubbo-serialization-fastjson2/src/main/java/org/apache/dubbo/common/serialize/fastjson2/Fastjson2SecurityManager.java b/dubbo-serialization/dubbo-serialization-fastjson2/src/main/java/org/apache/dubbo/common/serialize/fastjson2/Fastjson2SecurityManager.java index 32e477b2e3..1c1258af55 100644 --- a/dubbo-serialization/dubbo-serialization-fastjson2/src/main/java/org/apache/dubbo/common/serialize/fastjson2/Fastjson2SecurityManager.java +++ b/dubbo-serialization/dubbo-serialization-fastjson2/src/main/java/org/apache/dubbo/common/serialize/fastjson2/Fastjson2SecurityManager.java @@ -16,10 +16,6 @@ */ package org.apache.dubbo.common.serialize.fastjson2; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.utils.AllowClassNotifyListener; @@ -31,6 +27,10 @@ import org.apache.dubbo.rpc.model.FrameworkModel; import com.alibaba.fastjson2.filter.ContextAutoTypeBeforeHandler; import com.alibaba.fastjson2.util.TypeUtils; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + import static com.alibaba.fastjson2.util.TypeUtils.loadClass; import static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_UNTRUSTED_SERIALIZE_CLASS; import static org.apache.dubbo.common.utils.SerializeCheckStatus.STRICT; @@ -115,14 +115,14 @@ public class Fastjson2SecurityManager implements AllowClassNotifyListener { logger.error(PROTOCOL_UNTRUSTED_SERIALIZE_CLASS, "", "", msg); } - return null; + throw new IllegalArgumentException(msg); } // 3. try load Class localClass = loadClassDirectly(typeName); if (localClass != null) { if (status == SerializeCheckStatus.WARN && serializeSecurityManager.getWarnedClasses().add(typeName)) { - logger.error(PROTOCOL_UNTRUSTED_SERIALIZE_CLASS, "", "", + logger.warn(PROTOCOL_UNTRUSTED_SERIALIZE_CLASS, "", "", "[Serialization Security] Serialized class " + localClass.getName() + " is not in allow list. " + "Current mode is `WARN`, will allow to deserialize it by default. " + "Dubbo will set to `STRICT` mode by default in the future. " + @@ -152,7 +152,7 @@ public class Fastjson2SecurityManager implements AllowClassNotifyListener { "Current mode is `WARN`, will disallow to deserialize it by default. " + "Please add it into security/serialize.allowlist or follow FAQ to configure it."; if (serializeSecurityManager.getWarnedClasses().add(typeName)) { - logger.error(PROTOCOL_UNTRUSTED_SERIALIZE_CLASS, "", "", msg); + logger.warn(PROTOCOL_UNTRUSTED_SERIALIZE_CLASS, "", "", msg); } } diff --git a/dubbo-spring-boot/dubbo-spring-boot-actuator/README.md b/dubbo-spring-boot/dubbo-spring-boot-actuator/README.md index 8b2f0805c7..b0f22c027c 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-actuator/README.md +++ b/dubbo-spring-boot/dubbo-spring-boot-actuator/README.md @@ -473,7 +473,7 @@ management.health.dubbo.status.extras = load,threadpool `management.health.dubbo.enabled` is a enabled configuration to turn on or off health checks feature, its' default is `true`. - If you'd like to disable health checks , you chould apply `management.health.dubbo.enabled` to be `false`: + If you'd like to disable health checks , you could apply `management.health.dubbo.enabled` to be `false`: ```properties management.health.dubbo.enabled = false diff --git a/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/README.md b/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/README.md index 0e0dd0f0f0..c43f119627 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/README.md +++ b/dubbo-spring-boot/dubbo-spring-boot-autoconfigure/README.md @@ -48,7 +48,7 @@ If your project failed to resolve the dependency, try to add the following repos ## Auto Configuration -Since `2.5.7` , Dubbo totally supports Annotation-Driven , core Dubbo's components that are registered and initialized in Spring application context , including exterialized configuration features. However , those features need to trigger in manual configuration , e.g `@DubboComponentScan` , `@EnableDubboConfig` or `@EnableDubbo`. +Since `2.5.7` , Dubbo totally supports Annotation-Driven , core Dubbo's components that are registered and initialized in Spring application context , including externalized configuration features. However , those features need to trigger in manual configuration , e.g `@DubboComponentScan` , `@EnableDubboConfig` or `@EnableDubbo`. > If you'd like to learn more , please read [Dubbo Annotation-Driven (Chinese)](http://dubbo.apache.org/zh-cn/blog/dubbo-annotation-driven.html) @@ -76,7 +76,7 @@ dubbo.application.owner = bar dubbo.registry.address = 10.20.153.10:9090 ``` -There are two Spring Beans will be initialized when Spring `ApplicatonContext` is ready, their Bean types are `ApplicationConfig` and `RegistryConfig`. +There are two Spring Beans will be initialized when Spring `ApplicationContext` is ready, their Bean types are `ApplicationConfig` and `RegistryConfig`. @@ -181,7 +181,7 @@ The whole Properties Mapping of "Multiple Dubbo Config Bean Bindings" lists belo There is a different way to identify Multiple Dubbo Config Bean , the configuration pattern is like this : -`${config-property-prefix}.${config-bean-id}.${property-name} = some value` , let's explain those placehoders : +`${config-property-prefix}.${config-bean-id}.${property-name} = some value` , let's explain those placeholders : - `${config-property-prefix}` : The The prefix of property name for Multiple Bindings , e.g. `dubbo.protocols`, `dubbo.applications` and so on. - `${config-bean-id}` : The bean id of Dubbo's `*Config` @@ -217,7 +217,7 @@ If you used advanced IDE tools , for instance [Jetbrains IDEA Ultimate](https:// -#### Case 2 - Mutiple Bindings +#### Case 2 - Multiple Bindings ![](mconfig-popup-window.png) diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/env/DubboDefaultPropertiesEnvironmentPostProcessor.java b/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/env/DubboDefaultPropertiesEnvironmentPostProcessor.java index 44a0ae59de..adeb94b1f6 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/env/DubboDefaultPropertiesEnvironmentPostProcessor.java +++ b/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/main/java/org/apache/dubbo/spring/boot/env/DubboDefaultPropertiesEnvironmentPostProcessor.java @@ -33,7 +33,6 @@ import java.util.Map; import java.util.Properties; import static org.apache.dubbo.spring.boot.util.DubboUtils.DUBBO_APPLICATION_NAME_PROPERTY; -import static org.apache.dubbo.spring.boot.util.DubboUtils.DUBBO_APPLICATION_QOS_ENABLE_PROPERTY; import static org.apache.dubbo.spring.boot.util.DubboUtils.DUBBO_CONFIG_MULTIPLE_PROPERTY; import static org.apache.dubbo.spring.boot.util.DubboUtils.SPRING_APPLICATION_NAME_PROPERTY; @@ -73,8 +72,6 @@ public class DubboDefaultPropertiesEnvironmentPostProcessor implements Environme Map defaultProperties = new HashMap<>(); setDubboApplicationNameProperty(environment, defaultProperties); setDubboConfigMultipleProperty(defaultProperties); - setDubboApplicationQosEnableProperty(defaultProperties); - //setAllowBeanDefinitionOverriding(defaultProperties); return defaultProperties; } @@ -90,9 +87,7 @@ public class DubboDefaultPropertiesEnvironmentPostProcessor implements Environme defaultProperties.put(DUBBO_CONFIG_MULTIPLE_PROPERTY, Boolean.TRUE.toString()); } - private void setDubboApplicationQosEnableProperty(Map defaultProperties) { - defaultProperties.put(DUBBO_APPLICATION_QOS_ENABLE_PROPERTY, Boolean.TRUE.toString()); - } + /** * Set {@link #ALLOW_BEAN_DEFINITION_OVERRIDING_PROPERTY "spring.main.allow-bean-definition-overriding"} to be diff --git a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/env/DubboDefaultPropertiesEnvironmentPostProcessorTest.java b/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/env/DubboDefaultPropertiesEnvironmentPostProcessorTest.java index bde4c383a7..56642875d2 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/env/DubboDefaultPropertiesEnvironmentPostProcessorTest.java +++ b/dubbo-spring-boot/dubbo-spring-boot-compatible/autoconfigure/src/test/java/org/apache/dubbo/spring/boot/env/DubboDefaultPropertiesEnvironmentPostProcessorTest.java @@ -53,7 +53,7 @@ public class DubboDefaultPropertiesEnvironmentPostProcessorTest { PropertySource defaultPropertySource = propertySources.get("defaultProperties"); Assert.assertNotNull(defaultPropertySource); Assert.assertEquals("true", defaultPropertySource.getProperty("dubbo.config.multiple")); - Assert.assertEquals("true", defaultPropertySource.getProperty("dubbo.application.qos-enable")); + // Assert.assertEquals("true", defaultPropertySource.getProperty("dubbo.application.qos-enable")); // Case 2 : Only set property "spring.application.name" environment.setProperty("spring.application.name", "demo-dubbo-application"); diff --git a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/pom.xml b/dubbo-spring-boot/dubbo-spring-boot-starters/observability/pom.xml index dbd3c6c903..1ed28d1b5a 100644 --- a/dubbo-spring-boot/dubbo-spring-boot-starters/observability/pom.xml +++ b/dubbo-spring-boot/dubbo-spring-boot-starters/observability/pom.xml @@ -38,9 +38,9 @@ - 1.11.2 - 1.1.3 - 1.28.0 + 1.11.3 + 1.1.4 + 1.29.0 2.16.4 0.16.0 diff --git a/dubbo-test/dubbo-dependencies-all/pom.xml b/dubbo-test/dubbo-dependencies-all/pom.xml index 9f407a4dbb..0216003790 100644 --- a/dubbo-test/dubbo-dependencies-all/pom.xml +++ b/dubbo-test/dubbo-dependencies-all/pom.xml @@ -203,6 +203,13 @@ dubbo-metrics-config-center ${project.version} + + + org.apache.dubbo + dubbo-metrics-netty + ${project.version} + + org.apache.dubbo dubbo-metrics-prometheus