From 855646f290b6f44c93139ca7168efb745759b10f Mon Sep 17 00:00:00 2001 From: ankitshokeen Date: Mon, 28 Jul 2025 01:43:17 +0530 Subject: [PATCH 01/10] [Enhancement] Add discovery-timeline QoS command for service discovery metadata --- .../src/main/resources/application.yml | 1 - .../org.apache.dubbo.qos.api.BaseCommand | 42 +++ dubbo-plugin/dubbo-qos/pom.xml | 103 +++++- .../impl/DiscoveryTimelineCommand.java | 313 ++++++++++++++++++ .../org.apache.dubbo.qos.api.BaseCommand | 1 + .../impl/DiscoveryTimelineCommandTest.java | 161 +++++++++ .../qos/command/util/CommandHelperTest.java | 2 + 7 files changed, 617 insertions(+), 6 deletions(-) create mode 100644 dubbo-plugin/dubbo-qos/META-INF/dubbo/internal/org.apache.dubbo.qos.api.BaseCommand create mode 100644 dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/DiscoveryTimelineCommand.java create mode 100644 dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/DiscoveryTimelineCommandTest.java diff --git a/dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-consumer/src/main/resources/application.yml b/dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-consumer/src/main/resources/application.yml index 9cbc17d4d882..86bb7cf40097 100644 --- a/dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-consumer/src/main/resources/application.yml +++ b/dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-consumer/src/main/resources/application.yml @@ -32,4 +32,3 @@ dubbo: metadata-report: address: zookeeper://127.0.0.1:2181 - diff --git a/dubbo-plugin/dubbo-qos/META-INF/dubbo/internal/org.apache.dubbo.qos.api.BaseCommand b/dubbo-plugin/dubbo-qos/META-INF/dubbo/internal/org.apache.dubbo.qos.api.BaseCommand new file mode 100644 index 000000000000..27ccb8adfe2f --- /dev/null +++ b/dubbo-plugin/dubbo-qos/META-INF/dubbo/internal/org.apache.dubbo.qos.api.BaseCommand @@ -0,0 +1,42 @@ +online=org.apache.dubbo.qos.command.impl.Online +onlineApp=org.apache.dubbo.qos.command.impl.OnlineApp +onlineInterface=org.apache.dubbo.qos.command.impl.OnlineInterface +help=org.apache.dubbo.qos.command.impl.Help +quit=org.apache.dubbo.qos.command.impl.Quit +ls=org.apache.dubbo.qos.command.impl.Ls +offline=org.apache.dubbo.qos.command.impl.Offline +offlineApp=org.apache.dubbo.qos.command.impl.OfflineApp +offlineInterface=org.apache.dubbo.qos.command.impl.OfflineInterface +ready=org.apache.dubbo.qos.command.impl.Ready +startup=org.apache.dubbo.qos.command.impl.Startup +live=org.apache.dubbo.qos.command.impl.Live +version=org.apache.dubbo.qos.command.impl.Version +publishMetadata=org.apache.dubbo.qos.command.impl.PublishMetadata +cd=org.apache.dubbo.qos.command.impl.ChangeTelnet +count=org.apache.dubbo.qos.command.impl.CountTelnet +pwd=org.apache.dubbo.qos.command.impl.PwdTelnet +invoke=org.apache.dubbo.qos.command.impl.InvokeTelnet +select=org.apache.dubbo.qos.command.impl.SelectTelnet +ps=org.apache.dubbo.qos.command.impl.PortTelnet +shutdown=org.apache.dubbo.qos.command.impl.ShutdownTelnet +enableDetailProfiler=org.apache.dubbo.qos.command.impl.EnableDetailProfiler +disableDetailProfiler=org.apache.dubbo.qos.command.impl.DisableDetailProfiler +enableSimpleProfiler=org.apache.dubbo.qos.command.impl.EnableSimpleProfiler +disableSimpleProfiler=org.apache.dubbo.qos.command.impl.DisableSimpleProfiler +setProfilerWarnPercent=org.apache.dubbo.qos.command.impl.SetProfilerWarnPercent +getRouterSnapshot=org.apache.dubbo.qos.command.impl.GetRouterSnapshot +getEnabledRouterSnapshot=org.apache.dubbo.qos.command.impl.GetEnabledRouterSnapshot +enableRouterSnapshot=org.apache.dubbo.qos.command.impl.EnableRouterSnapshot +disableRouterSnapshot=org.apache.dubbo.qos.command.impl.DisableRouterSnapshot +getRecentRouterSnapshot=org.apache.dubbo.qos.command.impl.GetRecentRouterSnapshot +loggerInfo=org.apache.dubbo.qos.command.impl.LoggerInfo +switchLogger=org.apache.dubbo.qos.command.impl.SwitchLogger +switchLogLevel=org.apache.dubbo.qos.command.impl.SwitchLogLevel +serializeCheckStatus=org.apache.dubbo.qos.command.impl.SerializeCheckStatus +serializeWarnedClasses=org.apache.dubbo.qos.command.impl.SerializeWarnedClasses +getConfig=org.apache.dubbo.qos.command.impl.GetConfig +getAddress=org.apache.dubbo.qos.command.impl.GetAddress +gracefulShutdown=org.apache.dubbo.qos.command.impl.GracefulShutdown +metrics_default=org.apache.dubbo.qos.command.impl.DefaultMetricsReporterCmd +getOpenAPI=org.apache.dubbo.qos.command.impl.GetOpenAPI +discovery-timeline=org.apache.dubbo.qos.command.impl.DiscoveryTimelineCommand diff --git a/dubbo-plugin/dubbo-qos/pom.xml b/dubbo-plugin/dubbo-qos/pom.xml index f65c454cb71d..7c6d300818e7 100644 --- a/dubbo-plugin/dubbo-qos/pom.xml +++ b/dubbo-plugin/dubbo-qos/pom.xml @@ -14,13 +14,13 @@ 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. - --> +--> 4.0.0 org.apache.dubbo dubbo-parent - ${revision} + 3.3.6-SNAPSHOT ../../pom.xml @@ -34,6 +34,18 @@ false + + + + org.apache.dubbo + dubbo-dependencies-bom + ${project.version} + pom + import + + + + org.apache.dubbo @@ -65,11 +77,10 @@ dubbo-serialization-hessian2 ${project.version} - org.apache.dubbo dubbo-serialization-fastjson2 - ${project.parent.version} + ${project.version} org.apache.dubbo @@ -79,7 +90,7 @@ org.apache.dubbo dubbo-native - ${project.parent.version} + ${project.version} org.apache.dubbo @@ -89,7 +100,89 @@ org.apache.logging.log4j log4j-slf4j-impl + 2.24.3 + test + + + org.junit.jupiter + junit-jupiter-api + 5.10.3 + test + + + org.junit.jupiter + junit-jupiter-engine + 5.10.3 + test + + + org.junit.platform + junit-platform-commons + 1.10.3 + test + + + org.junit.platform + junit-platform-engine + 1.10.3 + test + + + org.junit.platform + junit-platform-launcher + 1.10.3 + test + + + org.mockito + mockito-core + 4.11.0 + test + + + org.mockito + mockito-inline + 4.11.0 + test + + + org.hamcrest + hamcrest + 2.2 test + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.14.0 + + + org.apache.maven.plugins + maven-surefire-plugin + 3.5.3 + + + **/*Test.java + + + + + com.diffplug.spotless + spotless-maven-plugin + 2.44.4 + + + + check + + validate + + + + + diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/DiscoveryTimelineCommand.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/DiscoveryTimelineCommand.java new file mode 100644 index 000000000000..f5157fa094ea --- /dev/null +++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/DiscoveryTimelineCommand.java @@ -0,0 +1,313 @@ +/* + * 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.qos.command.impl; + +import org.apache.dubbo.common.logger.Logger; +import org.apache.dubbo.common.logger.LoggerFactory; +import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.qos.api.BaseCommand; +import org.apache.dubbo.qos.api.Cmd; +import org.apache.dubbo.qos.api.CommandContext; +import org.apache.dubbo.registry.client.ServiceDiscovery; +import org.apache.dubbo.registry.client.ServiceInstance; +import org.apache.dubbo.registry.client.event.ServiceInstancesChangedEvent; +import org.apache.dubbo.registry.client.event.listener.ServiceInstancesChangedListener; +import org.apache.dubbo.registry.support.RegistryManager; +import org.apache.dubbo.rpc.model.ApplicationModel; +import org.apache.dubbo.rpc.model.FrameworkModel; +import org.apache.dubbo.rpc.model.FrameworkServiceRepository; +import org.apache.dubbo.rpc.model.ProviderModel; + +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +@Cmd( + name = "discovery-timeline", + summary = "Show service discovery timeline", + example = { + "discovery-timeline", + "discovery-timeline service=com.example.Service", + "discovery-timeline registry=zookeeper://localhost:2181", + "discovery-timeline page=2", + "discovery-timeline limit=5" + }) +public class DiscoveryTimelineCommand implements BaseCommand { + + private static final Logger logger = LoggerFactory.getLogger(DiscoveryTimelineCommand.class); + private final FrameworkModel frameworkModel; + private static final int DEFAULT_LIMIT = 10; + private static final Map globalProviderRegistrationTimes = new HashMap<>(); + private static final String TIMESTAMP_KEY = "timestamp"; + + public DiscoveryTimelineCommand(FrameworkModel frameworkModel) { + this.frameworkModel = frameworkModel; + } + + @Override + public String execute(CommandContext commandContext, String[] args) { + logger.debug("DiscoveryTimelineCommand started"); + + try { + ApplicationModel applicationModel = frameworkModel.defaultApplication(); + if (applicationModel == null) { + throw new IllegalStateException("No ApplicationModel available"); + } + + RegistryManager registryManager = applicationModel.getBeanFactory().getBean(RegistryManager.class); + if (registryManager == null) { + logger.warn("RegistryManager not available"); + return "Error: RegistryManager not available. Check configuration."; + } + + List serviceDiscoveries = registryManager.getServiceDiscoveries(); + if (serviceDiscoveries == null || serviceDiscoveries.isEmpty()) { + logger.warn("No ServiceDiscovery found"); + return "Error: No ServiceDiscovery instances found."; + } + + String filterServiceName = null; + String filterRegistry = null; + int page = 1; + int limit = DEFAULT_LIMIT; + if (args != null && args.length > 0) { + for (String arg : args) { + if (arg == null) continue; + if (arg.startsWith("service=")) { + filterServiceName = arg.substring("service=".length()); + } else if (arg.startsWith("registry=")) { + filterRegistry = arg.substring("registry=".length()); + } else if (arg.startsWith("page=")) { + try { + page = Math.max(1, Integer.parseInt(arg.substring("page=".length()))); + } catch (NumberFormatException e) { + logger.warn("Invalid page number: {}", arg, e); + } + } else if (arg.startsWith("limit=")) { + try { + limit = Math.max(1, Integer.parseInt(arg.substring("limit=".length()))); + } catch (NumberFormatException e) { + logger.warn("Invalid limit number: {}", arg, e); + } + } + } + } + + final String finalFilterServiceName = filterServiceName; + + Map listeners = new HashMap<>(); + Map providerRegistrationTimes = new HashMap<>(globalProviderRegistrationTimes); + Map> registryServices = new HashMap<>(); + + FrameworkServiceRepository serviceRepository = frameworkModel.getServiceRepository(); + Set uniqueProviderModels = new HashSet<>(serviceRepository.allProviderModels()); + List providerModels = uniqueProviderModels.stream() + .filter(model -> { + String serviceName = model.getServiceKey(); + return serviceName != null && (finalFilterServiceName == null || serviceName.contains(finalFilterServiceName)); + }) + .sorted((m1, m2) -> { + String key1 = m1.getServiceKey(); + String key2 = m2.getServiceKey(); + String numStr1 = key1.replaceAll("[^0-9]", ""); + String numStr2 = key2.replaceAll("[^0-9]", ""); + if (StringUtils.isEmpty(numStr1) || StringUtils.isEmpty(numStr2)) { + return key1.compareTo(key2); + } + try { + int num1 = Integer.parseInt(numStr1); + int num2 = Integer.parseInt(numStr2); + return Integer.compare(num1, num2); + } catch (NumberFormatException e) { + logger.warn("Failed to parse numbers for sorting: {} vs {}", numStr1, numStr2, e); + return key1.compareTo(key2); + } + }) + .collect(Collectors.toList()); + logger.debug("Filtered and sorted provider models: {}", providerModels.stream() + .map(ProviderModel::getServiceKey) + .collect(Collectors.toList())); + + boolean hasServices = false; + for (ServiceDiscovery serviceDiscovery : serviceDiscoveries) { + if (filterRegistry != null && (serviceDiscovery.getUrl() == null || !serviceDiscovery.getUrl().getAddress().contains(filterRegistry))) { + continue; + } + + Set serviceNames = new HashSet<>(); + ServiceInstance instance = serviceDiscovery.getLocalInstance(); + if (instance == null) { + logger.warn("No local instance found for registry: {}", serviceDiscovery.getUrl()); + continue; + } + + Map metadata = instance.getMetadata(); + if (metadata == null || metadata.isEmpty()) { + logger.warn("No metadata found for instance in registry: {}", serviceDiscovery.getUrl()); + metadata = new HashMap<>(); + } + + for (ProviderModel providerModel : providerModels) { + String serviceName = providerModel.getServiceKey(); + if (serviceName != null) { + serviceNames.add(serviceName); + if (!providerRegistrationTimes.containsKey(serviceName)) { + String timestampStr = metadata.getOrDefault(TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis())); + try { + providerRegistrationTimes.put(serviceName, Long.parseLong(timestampStr)); + logger.debug("Set timestamp for {}: {}", serviceName, timestampStr); + } catch (NumberFormatException e) { + logger.warn("Invalid timestamp format for service: {}, timestamp: {}", serviceName, timestampStr, e); + providerRegistrationTimes.put(serviceName, System.currentTimeMillis()); + } + } + } + } + registryServices.put(serviceDiscovery, serviceNames); + CustomServiceInstancesChangedListener listener = + new CustomServiceInstancesChangedListener(serviceNames, serviceDiscovery, providerRegistrationTimes); + serviceDiscovery.addServiceInstancesChangedListener(listener); + listeners.put(serviceDiscovery, listener); + hasServices = true; + logger.debug("Registered services for discovery {}: {}", serviceDiscovery.getUrl(), serviceNames); + } + + for (Map.Entry entry : providerRegistrationTimes.entrySet()) { + globalProviderRegistrationTimes.putIfAbsent(entry.getKey(), entry.getValue()); + } + + if (!hasServices) { + return "Error: No services discovered."; + } + + StringBuilder timeline = new StringBuilder("Discovery Timeline\n"); + timeline.append("------------------------------------------------------------\n"); + timeline.append(String.format("%-30s|%-30s%n", "Registry", "Last Refresh")); + timeline.append("------------------------------------------------------------\n"); + + for (ServiceDiscovery sd : serviceDiscoveries) { + if (filterRegistry != null && (sd.getUrl() == null || !sd.getUrl().getAddress().contains(filterRegistry))) { + continue; + } + String refreshTimeStr = "Unknown"; + ServiceInstance instance = sd.getLocalInstance(); + if (instance != null && instance.getMetadata() != null && instance.getMetadata().containsKey(TIMESTAMP_KEY)) { + String timestampStr = instance.getMetadata().getOrDefault(TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis())); + try { + long registryTimestamp = Long.parseLong(timestampStr); + refreshTimeStr = new Date(registryTimestamp).toString(); + } catch (NumberFormatException e) { + logger.warn("Invalid timestamp format for registry: {}, timestamp: {}", sd.getUrl().getAddress(), timestampStr, e); + refreshTimeStr = new Date(System.currentTimeMillis()).toString(); + } + } + timeline.append(String.format("%-30s|%-30s%n", sd.getUrl().getAddress(), refreshTimeStr)); + } + + timeline.append("------------------------------------------------------------\n"); + timeline.append("Provider Services\n"); + + // Apply pagination + int providerStart = (page - 1) * limit; + int providerEnd = Math.min(providerStart + limit, providerModels.size()); + logger.debug("Pagination: page={}, limit={}, start={}, end={}, total providers={}", + page, limit, providerStart, providerEnd, providerModels.size()); + List paginatedProviders = providerModels.subList( + Math.min(providerStart, providerModels.size()), + Math.min(providerEnd, providerModels.size()) + ); + logger.debug("Paginated providers: {}", paginatedProviders.stream() + .map(ProviderModel::getServiceKey) + .collect(Collectors.toList())); + + for (ProviderModel providerModel : paginatedProviders) { + String serviceName = providerModel.getServiceKey(); + Long lastRegistrationTime = providerRegistrationTimes.get(serviceName); + String refreshTimeStr = lastRegistrationTime != null ? new Date(lastRegistrationTime).toString() : "Unknown"; + timeline.append(String.format("%-30s|%-30s%n", "Discovered: " + serviceName, refreshTimeStr)); + } + + timeline.append("------------------------------------------------------------\n"); + String result = timeline.toString(); + logger.debug("Final output:\n{}", result); + return result; + + } catch (Exception e) { + logger.error("Failed to generate discovery timeline", e); + return "Error: " + e.getMessage(); + } + } + + private static class CustomServiceInstancesChangedListener extends ServiceInstancesChangedListener { + private final Set serviceNames; + private final Map serviceRegistrationTimes; + private Set previousInstances = new HashSet<>(); + + public CustomServiceInstancesChangedListener( + Set serviceNames, ServiceDiscovery serviceDiscovery, Map serviceRegistrationTimes) { + super(serviceNames, serviceDiscovery); + this.serviceNames = serviceNames; + this.serviceRegistrationTimes = serviceRegistrationTimes; + initializeRegistrationTimes(); + } + + private void initializeRegistrationTimes() { + long currentTime = System.currentTimeMillis(); + for (String serviceName : serviceNames) { + if (!serviceRegistrationTimes.containsKey(serviceName)) { + serviceRegistrationTimes.put(serviceName, currentTime); + logger.debug("Initialized registration time for {}: {}", serviceName, new Date(currentTime).toString()); + } + } + } + + @Override + public void onEvent(ServiceInstancesChangedEvent event) { + super.onEvent(event); + String serviceName = event.getServiceName(); + Set currentInstances = event.getServiceInstances().stream() + .map(ServiceInstance::getServiceName) + .filter(name -> name != null) + .collect(Collectors.toSet()); + + if (previousInstances.isEmpty() || !previousInstances.equals(currentInstances)) { + serviceNames.add(serviceName); + for (ServiceInstance instance : event.getServiceInstances()) { + String timestampStr = instance.getMetadata() != null ? + instance.getMetadata().getOrDefault(TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis())) : + String.valueOf(System.currentTimeMillis()); + if (!serviceRegistrationTimes.containsKey(serviceName)) { + try { + serviceRegistrationTimes.put(serviceName, Long.parseLong(timestampStr)); + logger.debug("Updated timestamp for {}: {}", serviceName, new Date(Long.parseLong(timestampStr)).toString()); + } catch (NumberFormatException e) { + logger.warn("Invalid timestamp format for service: {}, timestamp: {}", serviceName, timestampStr, e); + serviceRegistrationTimes.put(serviceName, System.currentTimeMillis()); + } + } + } + previousInstances = new HashSet<>(currentInstances); + } + logger.debug("Event received for service: {}, current instances: {}, registration times: {}", + serviceName, currentInstances, serviceRegistrationTimes); + } + } +} diff --git a/dubbo-plugin/dubbo-qos/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.qos.api.BaseCommand b/dubbo-plugin/dubbo-qos/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.qos.api.BaseCommand index 9a336915e1ba..27ccb8adfe2f 100644 --- a/dubbo-plugin/dubbo-qos/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.qos.api.BaseCommand +++ b/dubbo-plugin/dubbo-qos/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.qos.api.BaseCommand @@ -39,3 +39,4 @@ getAddress=org.apache.dubbo.qos.command.impl.GetAddress gracefulShutdown=org.apache.dubbo.qos.command.impl.GracefulShutdown metrics_default=org.apache.dubbo.qos.command.impl.DefaultMetricsReporterCmd getOpenAPI=org.apache.dubbo.qos.command.impl.GetOpenAPI +discovery-timeline=org.apache.dubbo.qos.command.impl.DiscoveryTimelineCommand diff --git a/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/DiscoveryTimelineCommandTest.java b/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/DiscoveryTimelineCommandTest.java new file mode 100644 index 000000000000..42bc9a5e9c29 --- /dev/null +++ b/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/DiscoveryTimelineCommandTest.java @@ -0,0 +1,161 @@ +/* + * 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.qos.command.impl; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.beans.factory.ScopeBeanFactory; +import org.apache.dubbo.qos.api.CommandContext; +import org.apache.dubbo.registry.client.DefaultServiceInstance; +import org.apache.dubbo.registry.client.ServiceDiscovery; +import org.apache.dubbo.registry.support.RegistryManager; +import org.apache.dubbo.rpc.model.ApplicationModel; +import org.apache.dubbo.rpc.model.FrameworkModel; +import org.apache.dubbo.rpc.model.FrameworkServiceRepository; +import org.apache.dubbo.rpc.model.ProviderModel; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.util.*; +import java.util.stream.Collectors; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class DiscoveryTimelineCommandTest { + + private DiscoveryTimelineCommand command; + private FrameworkModel frameworkModel; + private ApplicationModel applicationModel; + private RegistryManager registryManager; + private ServiceDiscovery serviceDiscovery; + private DefaultServiceInstance serviceInstance; + private FrameworkServiceRepository serviceRepository; + private ScopeBeanFactory beanFactory; + + @BeforeEach + public void setUp() { + frameworkModel = Mockito.mock(FrameworkModel.class); + applicationModel = Mockito.mock(ApplicationModel.class); + registryManager = Mockito.mock(RegistryManager.class); + serviceDiscovery = Mockito.mock(ServiceDiscovery.class); + serviceInstance = Mockito.mock(DefaultServiceInstance.class); + serviceRepository = Mockito.mock(FrameworkServiceRepository.class); + beanFactory = Mockito.mock(ScopeBeanFactory.class); + + command = new DiscoveryTimelineCommand(frameworkModel); + + Mockito.when(frameworkModel.getServiceRepository()).thenReturn(serviceRepository); + Mockito.when(frameworkModel.defaultApplication()).thenReturn(applicationModel); + Mockito.when(applicationModel.getBeanFactory()).thenReturn(beanFactory); + Mockito.when(beanFactory.getBean(RegistryManager.class)).thenReturn(registryManager); + Mockito.when(registryManager.getServiceDiscoveries()).thenReturn(Collections.singletonList(serviceDiscovery)); + Mockito.when(serviceDiscovery.getLocalInstance()).thenReturn(serviceInstance); + Mockito.when(serviceDiscovery.getUrl()).thenReturn(URL.valueOf("zookeeper://127.0.0.1:2181")); + } + + @Test + void testExecuteWithTimestamps() { + ProviderModel providerModel = Mockito.mock(ProviderModel.class); + Mockito.when(providerModel.getServiceKey()).thenReturn("org.apache.dubbo.demo.DemoService"); + Mockito.when(serviceRepository.allProviderModels()).thenReturn(Collections.singletonList(providerModel)); + + long ts = LocalDateTime.of(2025, 7, 27, 17, 54, 0).toEpochSecond(ZoneOffset.ofHours(5)) * 1000L; + Map metadata = new HashMap<>(); + metadata.put("timestamp", String.valueOf(ts)); + Mockito.when(serviceInstance.getMetadata()).thenReturn(metadata); + + String output = command.execute(new CommandContext("discovery-timeline"), null); + System.out.println("testExecuteWithTimestamps Output:\n" + output); + + assertTrue(output.contains("Discovery Timeline")); + assertTrue(output.contains("127.0.0.1:2181")); + assertTrue(output.contains("Discovered: org.apache.dubbo.demo.DemoService")); + } + + @Test + void testExecuteWithoutMetadata() { + ProviderModel providerModel = Mockito.mock(ProviderModel.class); + Mockito.when(providerModel.getServiceKey()).thenReturn("org.apache.dubbo.demo.DemoService"); + Mockito.when(serviceRepository.allProviderModels()).thenReturn(Collections.singletonList(providerModel)); + + Mockito.when(serviceInstance.getMetadata()).thenReturn(null); + + String output = command.execute(new CommandContext("discovery-timeline"), null); + System.out.println("testExecuteWithoutMetadata Output:\n" + output); + + assertTrue(output.contains("Unknown")); + assertTrue(output.contains("Discovered: org.apache.dubbo.demo.DemoService")); + } + + @Test + void testExecuteWithPagination() { + List providers = new ArrayList<>(); + long ts = LocalDateTime.of(2025, 7, 27, 17, 54, 0).toEpochSecond(ZoneOffset.ofHours(5)) * 1000L; + for (int i = 1; i <= 15; i++) { + ProviderModel model = Mockito.mock(ProviderModel.class); + String serviceName = "Service" + i; + Mockito.when(model.getServiceKey()).thenReturn(serviceName); + providers.add(model); + } + Mockito.when(serviceRepository.allProviderModels()).thenReturn(providers); + Map metadata = new HashMap<>(); + metadata.put("timestamp", String.valueOf(ts)); + Mockito.when(serviceInstance.getMetadata()).thenReturn(metadata); + + String output = command.execute(new CommandContext("discovery-timeline"), new String[]{"limit=5", "page=2"}); + System.out.println("testExecuteWithPagination Output:\n" + output); + System.out.println("Providers mocked: " + providers.stream().map(ProviderModel::getServiceKey).collect(Collectors.toList())); + // Debug output character-by-character + System.out.println("Output characters:"); + for (int i = 0; i < output.length(); i++) { + System.out.printf("Index %d: %c (ASCII %d)%n", i, output.charAt(i), (int) output.charAt(i)); + } + + assertTrue(output.contains("Discovery Timeline")); + assertTrue(output.contains("Discovered: Service6")); + assertTrue(output.contains("Discovered: Service10")); + } + + @Test + void testExecuteWithServiceFilter() { + ProviderModel providerModel = Mockito.mock(ProviderModel.class); + Mockito.when(providerModel.getServiceKey()).thenReturn("org.apache.dubbo.MyService"); + Mockito.when(serviceRepository.allProviderModels()).thenReturn(Collections.singletonList(providerModel)); + Mockito.when(serviceInstance.getMetadata()).thenReturn(new HashMap<>()); + + String output = command.execute(new CommandContext("discovery-timeline"), new String[]{"service=MyService"}); + System.out.println("testExecuteWithServiceFilter Output:\n" + output); + + assertTrue(output.contains("Discovered: org.apache.dubbo.MyService")); + } + + @Test + void testExecuteWithRegistryFilterMismatch() { + ProviderModel providerModel = Mockito.mock(ProviderModel.class); + Mockito.when(providerModel.getServiceKey()).thenReturn("org.apache.dubbo.MyService"); + Mockito.when(serviceRepository.allProviderModels()).thenReturn(Collections.singletonList(providerModel)); + Mockito.when(serviceInstance.getMetadata()).thenReturn(new HashMap<>()); + + String output = command.execute(new CommandContext("discovery-timeline"), new String[]{"registry=nacos"}); + System.out.println("testExecuteWithRegistryFilterMismatch Output:\n" + output); + + assertTrue(output.contains("Error: No services discovered.")); + } +} diff --git a/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/util/CommandHelperTest.java b/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/util/CommandHelperTest.java index 238b1421dd07..26a232c9363f 100644 --- a/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/util/CommandHelperTest.java +++ b/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/util/CommandHelperTest.java @@ -23,6 +23,7 @@ import org.apache.dubbo.qos.command.impl.DisableDetailProfiler; import org.apache.dubbo.qos.command.impl.DisableRouterSnapshot; import org.apache.dubbo.qos.command.impl.DisableSimpleProfiler; +import org.apache.dubbo.qos.command.impl.DiscoveryTimelineCommand; import org.apache.dubbo.qos.command.impl.EnableDetailProfiler; import org.apache.dubbo.qos.command.impl.EnableRouterSnapshot; import org.apache.dubbo.qos.command.impl.EnableSimpleProfiler; @@ -129,6 +130,7 @@ void testGetAllCommandClass() { expectedClasses.add(GracefulShutdown.class); expectedClasses.add(DefaultMetricsReporterCmd.class); expectedClasses.add(GetOpenAPI.class); + expectedClasses.add(DiscoveryTimelineCommand.class); assertThat(classes, containsInAnyOrder(expectedClasses.toArray(new Class[0]))); } From f994f18e2aece49b374fc1622d1250e2f2333db1 Mon Sep 17 00:00:00 2001 From: ankitshokeen Date: Tue, 29 Jul 2025 01:46:15 +0530 Subject: [PATCH 02/10] fix/formatting --- dubbo-plugin/dubbo-qos/pom.xml | 103 +---------------- .../impl/DiscoveryTimelineCommand.java | 108 ++++++++++++------ .../impl/DiscoveryTimelineCommandTest.java | 17 +-- dubbo-plugin/dubbo-spring-security/pom.xml | 5 + 4 files changed, 91 insertions(+), 142 deletions(-) diff --git a/dubbo-plugin/dubbo-qos/pom.xml b/dubbo-plugin/dubbo-qos/pom.xml index 7c6d300818e7..f65c454cb71d 100644 --- a/dubbo-plugin/dubbo-qos/pom.xml +++ b/dubbo-plugin/dubbo-qos/pom.xml @@ -14,13 +14,13 @@ 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. ---> + --> 4.0.0 org.apache.dubbo dubbo-parent - 3.3.6-SNAPSHOT + ${revision} ../../pom.xml @@ -34,18 +34,6 @@ false - - - - org.apache.dubbo - dubbo-dependencies-bom - ${project.version} - pom - import - - - - org.apache.dubbo @@ -77,10 +65,11 @@ dubbo-serialization-hessian2 ${project.version} + org.apache.dubbo dubbo-serialization-fastjson2 - ${project.version} + ${project.parent.version} org.apache.dubbo @@ -90,7 +79,7 @@ org.apache.dubbo dubbo-native - ${project.version} + ${project.parent.version} org.apache.dubbo @@ -100,89 +89,7 @@ org.apache.logging.log4j log4j-slf4j-impl - 2.24.3 - test - - - org.junit.jupiter - junit-jupiter-api - 5.10.3 - test - - - org.junit.jupiter - junit-jupiter-engine - 5.10.3 - test - - - org.junit.platform - junit-platform-commons - 1.10.3 - test - - - org.junit.platform - junit-platform-engine - 1.10.3 - test - - - org.junit.platform - junit-platform-launcher - 1.10.3 - test - - - org.mockito - mockito-core - 4.11.0 - test - - - org.mockito - mockito-inline - 4.11.0 - test - - - org.hamcrest - hamcrest - 2.2 test - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.14.0 - - - org.apache.maven.plugins - maven-surefire-plugin - 3.5.3 - - - **/*Test.java - - - - - com.diffplug.spotless - spotless-maven-plugin - 2.44.4 - - - - check - - validate - - - - - diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/DiscoveryTimelineCommand.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/DiscoveryTimelineCommand.java index f5157fa094ea..6f78309500ad 100644 --- a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/DiscoveryTimelineCommand.java +++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/DiscoveryTimelineCommand.java @@ -44,11 +44,11 @@ name = "discovery-timeline", summary = "Show service discovery timeline", example = { - "discovery-timeline", - "discovery-timeline service=com.example.Service", - "discovery-timeline registry=zookeeper://localhost:2181", - "discovery-timeline page=2", - "discovery-timeline limit=5" + "discovery-timeline", + "discovery-timeline service=com.example.Service", + "discovery-timeline registry=zookeeper://localhost:2181", + "discovery-timeline page=2", + "discovery-timeline limit=5" }) public class DiscoveryTimelineCommand implements BaseCommand { @@ -122,7 +122,8 @@ public String execute(CommandContext commandContext, String[] args) { List providerModels = uniqueProviderModels.stream() .filter(model -> { String serviceName = model.getServiceKey(); - return serviceName != null && (finalFilterServiceName == null || serviceName.contains(finalFilterServiceName)); + return serviceName != null + && (finalFilterServiceName == null || serviceName.contains(finalFilterServiceName)); }) .sorted((m1, m2) -> { String key1 = m1.getServiceKey(); @@ -142,13 +143,15 @@ public String execute(CommandContext commandContext, String[] args) { } }) .collect(Collectors.toList()); - logger.debug("Filtered and sorted provider models: {}", providerModels.stream() - .map(ProviderModel::getServiceKey) - .collect(Collectors.toList())); + logger.debug( + "Filtered and sorted provider models: {}", + providerModels.stream().map(ProviderModel::getServiceKey).collect(Collectors.toList())); boolean hasServices = false; for (ServiceDiscovery serviceDiscovery : serviceDiscoveries) { - if (filterRegistry != null && (serviceDiscovery.getUrl() == null || !serviceDiscovery.getUrl().getAddress().contains(filterRegistry))) { + if (filterRegistry != null + && (serviceDiscovery.getUrl() == null + || !serviceDiscovery.getUrl().getAddress().contains(filterRegistry))) { continue; } @@ -170,20 +173,25 @@ public String execute(CommandContext commandContext, String[] args) { if (serviceName != null) { serviceNames.add(serviceName); if (!providerRegistrationTimes.containsKey(serviceName)) { - String timestampStr = metadata.getOrDefault(TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis())); + String timestampStr = + metadata.getOrDefault(TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis())); try { providerRegistrationTimes.put(serviceName, Long.parseLong(timestampStr)); logger.debug("Set timestamp for {}: {}", serviceName, timestampStr); } catch (NumberFormatException e) { - logger.warn("Invalid timestamp format for service: {}, timestamp: {}", serviceName, timestampStr, e); + logger.warn( + "Invalid timestamp format for service: {}, timestamp: {}", + serviceName, + timestampStr, + e); providerRegistrationTimes.put(serviceName, System.currentTimeMillis()); } } } } registryServices.put(serviceDiscovery, serviceNames); - CustomServiceInstancesChangedListener listener = - new CustomServiceInstancesChangedListener(serviceNames, serviceDiscovery, providerRegistrationTimes); + CustomServiceInstancesChangedListener listener = new CustomServiceInstancesChangedListener( + serviceNames, serviceDiscovery, providerRegistrationTimes); serviceDiscovery.addServiceInstancesChangedListener(listener); listeners.put(serviceDiscovery, listener); hasServices = true; @@ -204,18 +212,26 @@ public String execute(CommandContext commandContext, String[] args) { timeline.append("------------------------------------------------------------\n"); for (ServiceDiscovery sd : serviceDiscoveries) { - if (filterRegistry != null && (sd.getUrl() == null || !sd.getUrl().getAddress().contains(filterRegistry))) { + if (filterRegistry != null + && (sd.getUrl() == null || !sd.getUrl().getAddress().contains(filterRegistry))) { continue; } String refreshTimeStr = "Unknown"; ServiceInstance instance = sd.getLocalInstance(); - if (instance != null && instance.getMetadata() != null && instance.getMetadata().containsKey(TIMESTAMP_KEY)) { - String timestampStr = instance.getMetadata().getOrDefault(TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis())); + if (instance != null + && instance.getMetadata() != null + && instance.getMetadata().containsKey(TIMESTAMP_KEY)) { + String timestampStr = instance.getMetadata() + .getOrDefault(TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis())); try { long registryTimestamp = Long.parseLong(timestampStr); refreshTimeStr = new Date(registryTimestamp).toString(); } catch (NumberFormatException e) { - logger.warn("Invalid timestamp format for registry: {}, timestamp: {}", sd.getUrl().getAddress(), timestampStr, e); + logger.warn( + "Invalid timestamp format for registry: {}, timestamp: {}", + sd.getUrl().getAddress(), + timestampStr, + e); refreshTimeStr = new Date(System.currentTimeMillis()).toString(); } } @@ -228,20 +244,26 @@ public String execute(CommandContext commandContext, String[] args) { // Apply pagination int providerStart = (page - 1) * limit; int providerEnd = Math.min(providerStart + limit, providerModels.size()); - logger.debug("Pagination: page={}, limit={}, start={}, end={}, total providers={}", - page, limit, providerStart, providerEnd, providerModels.size()); + logger.debug( + "Pagination: page={}, limit={}, start={}, end={}, total providers={}", + page, + limit, + providerStart, + providerEnd, + providerModels.size()); List paginatedProviders = providerModels.subList( - Math.min(providerStart, providerModels.size()), - Math.min(providerEnd, providerModels.size()) - ); - logger.debug("Paginated providers: {}", paginatedProviders.stream() - .map(ProviderModel::getServiceKey) - .collect(Collectors.toList())); + Math.min(providerStart, providerModels.size()), Math.min(providerEnd, providerModels.size())); + logger.debug( + "Paginated providers: {}", + paginatedProviders.stream() + .map(ProviderModel::getServiceKey) + .collect(Collectors.toList())); for (ProviderModel providerModel : paginatedProviders) { String serviceName = providerModel.getServiceKey(); Long lastRegistrationTime = providerRegistrationTimes.get(serviceName); - String refreshTimeStr = lastRegistrationTime != null ? new Date(lastRegistrationTime).toString() : "Unknown"; + String refreshTimeStr = + lastRegistrationTime != null ? new Date(lastRegistrationTime).toString() : "Unknown"; timeline.append(String.format("%-30s|%-30s%n", "Discovered: " + serviceName, refreshTimeStr)); } @@ -262,7 +284,9 @@ private static class CustomServiceInstancesChangedListener extends ServiceInstan private Set previousInstances = new HashSet<>(); public CustomServiceInstancesChangedListener( - Set serviceNames, ServiceDiscovery serviceDiscovery, Map serviceRegistrationTimes) { + Set serviceNames, + ServiceDiscovery serviceDiscovery, + Map serviceRegistrationTimes) { super(serviceNames, serviceDiscovery); this.serviceNames = serviceNames; this.serviceRegistrationTimes = serviceRegistrationTimes; @@ -274,7 +298,8 @@ private void initializeRegistrationTimes() { for (String serviceName : serviceNames) { if (!serviceRegistrationTimes.containsKey(serviceName)) { serviceRegistrationTimes.put(serviceName, currentTime); - logger.debug("Initialized registration time for {}: {}", serviceName, new Date(currentTime).toString()); + logger.debug( + "Initialized registration time for {}: {}", serviceName, new Date(currentTime).toString()); } } } @@ -291,23 +316,34 @@ public void onEvent(ServiceInstancesChangedEvent event) { if (previousInstances.isEmpty() || !previousInstances.equals(currentInstances)) { serviceNames.add(serviceName); for (ServiceInstance instance : event.getServiceInstances()) { - String timestampStr = instance.getMetadata() != null ? - instance.getMetadata().getOrDefault(TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis())) : - String.valueOf(System.currentTimeMillis()); + String timestampStr = instance.getMetadata() != null + ? instance.getMetadata() + .getOrDefault(TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis())) + : String.valueOf(System.currentTimeMillis()); if (!serviceRegistrationTimes.containsKey(serviceName)) { try { serviceRegistrationTimes.put(serviceName, Long.parseLong(timestampStr)); - logger.debug("Updated timestamp for {}: {}", serviceName, new Date(Long.parseLong(timestampStr)).toString()); + logger.debug( + "Updated timestamp for {}: {}", + serviceName, + new Date(Long.parseLong(timestampStr)).toString()); } catch (NumberFormatException e) { - logger.warn("Invalid timestamp format for service: {}, timestamp: {}", serviceName, timestampStr, e); + logger.warn( + "Invalid timestamp format for service: {}, timestamp: {}", + serviceName, + timestampStr, + e); serviceRegistrationTimes.put(serviceName, System.currentTimeMillis()); } } } previousInstances = new HashSet<>(currentInstances); } - logger.debug("Event received for service: {}, current instances: {}, registration times: {}", - serviceName, currentInstances, serviceRegistrationTimes); + logger.debug( + "Event received for service: {}, current instances: {}, registration times: {}", + serviceName, + currentInstances, + serviceRegistrationTimes); } } } diff --git a/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/DiscoveryTimelineCommandTest.java b/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/DiscoveryTimelineCommandTest.java index 42bc9a5e9c29..f1c72e59fddf 100644 --- a/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/DiscoveryTimelineCommandTest.java +++ b/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/DiscoveryTimelineCommandTest.java @@ -27,15 +27,15 @@ import org.apache.dubbo.rpc.model.FrameworkServiceRepository; import org.apache.dubbo.rpc.model.ProviderModel; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; - import java.time.LocalDateTime; import java.time.ZoneOffset; import java.util.*; import java.util.stream.Collectors; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + import static org.junit.jupiter.api.Assertions.assertTrue; public class DiscoveryTimelineCommandTest { @@ -119,9 +119,10 @@ void testExecuteWithPagination() { metadata.put("timestamp", String.valueOf(ts)); Mockito.when(serviceInstance.getMetadata()).thenReturn(metadata); - String output = command.execute(new CommandContext("discovery-timeline"), new String[]{"limit=5", "page=2"}); + String output = command.execute(new CommandContext("discovery-timeline"), new String[] {"limit=5", "page=2"}); System.out.println("testExecuteWithPagination Output:\n" + output); - System.out.println("Providers mocked: " + providers.stream().map(ProviderModel::getServiceKey).collect(Collectors.toList())); + System.out.println("Providers mocked: " + + providers.stream().map(ProviderModel::getServiceKey).collect(Collectors.toList())); // Debug output character-by-character System.out.println("Output characters:"); for (int i = 0; i < output.length(); i++) { @@ -140,7 +141,7 @@ void testExecuteWithServiceFilter() { Mockito.when(serviceRepository.allProviderModels()).thenReturn(Collections.singletonList(providerModel)); Mockito.when(serviceInstance.getMetadata()).thenReturn(new HashMap<>()); - String output = command.execute(new CommandContext("discovery-timeline"), new String[]{"service=MyService"}); + String output = command.execute(new CommandContext("discovery-timeline"), new String[] {"service=MyService"}); System.out.println("testExecuteWithServiceFilter Output:\n" + output); assertTrue(output.contains("Discovered: org.apache.dubbo.MyService")); @@ -153,7 +154,7 @@ void testExecuteWithRegistryFilterMismatch() { Mockito.when(serviceRepository.allProviderModels()).thenReturn(Collections.singletonList(providerModel)); Mockito.when(serviceInstance.getMetadata()).thenReturn(new HashMap<>()); - String output = command.execute(new CommandContext("discovery-timeline"), new String[]{"registry=nacos"}); + String output = command.execute(new CommandContext("discovery-timeline"), new String[] {"registry=nacos"}); System.out.println("testExecuteWithRegistryFilterMismatch Output:\n" + output); assertTrue(output.contains("Error: No services discovered.")); diff --git a/dubbo-plugin/dubbo-spring-security/pom.xml b/dubbo-plugin/dubbo-spring-security/pom.xml index 68844fc816da..b7391cbc92d3 100644 --- a/dubbo-plugin/dubbo-spring-security/pom.xml +++ b/dubbo-plugin/dubbo-spring-security/pom.xml @@ -88,6 +88,11 @@ log4j-slf4j-impl test + + org.springframework.security + spring-security-core + 6.5.1 + From b9bfc4c0fa41a8762db9b9f4e162e258e2a3ed98 Mon Sep 17 00:00:00 2001 From: zrlw Date: Tue, 29 Jul 2025 11:45:25 +0800 Subject: [PATCH 03/10] Delete redundant configuration --- .../org.apache.dubbo.qos.api.BaseCommand | 42 ------------------- 1 file changed, 42 deletions(-) delete mode 100644 dubbo-plugin/dubbo-qos/META-INF/dubbo/internal/org.apache.dubbo.qos.api.BaseCommand diff --git a/dubbo-plugin/dubbo-qos/META-INF/dubbo/internal/org.apache.dubbo.qos.api.BaseCommand b/dubbo-plugin/dubbo-qos/META-INF/dubbo/internal/org.apache.dubbo.qos.api.BaseCommand deleted file mode 100644 index 27ccb8adfe2f..000000000000 --- a/dubbo-plugin/dubbo-qos/META-INF/dubbo/internal/org.apache.dubbo.qos.api.BaseCommand +++ /dev/null @@ -1,42 +0,0 @@ -online=org.apache.dubbo.qos.command.impl.Online -onlineApp=org.apache.dubbo.qos.command.impl.OnlineApp -onlineInterface=org.apache.dubbo.qos.command.impl.OnlineInterface -help=org.apache.dubbo.qos.command.impl.Help -quit=org.apache.dubbo.qos.command.impl.Quit -ls=org.apache.dubbo.qos.command.impl.Ls -offline=org.apache.dubbo.qos.command.impl.Offline -offlineApp=org.apache.dubbo.qos.command.impl.OfflineApp -offlineInterface=org.apache.dubbo.qos.command.impl.OfflineInterface -ready=org.apache.dubbo.qos.command.impl.Ready -startup=org.apache.dubbo.qos.command.impl.Startup -live=org.apache.dubbo.qos.command.impl.Live -version=org.apache.dubbo.qos.command.impl.Version -publishMetadata=org.apache.dubbo.qos.command.impl.PublishMetadata -cd=org.apache.dubbo.qos.command.impl.ChangeTelnet -count=org.apache.dubbo.qos.command.impl.CountTelnet -pwd=org.apache.dubbo.qos.command.impl.PwdTelnet -invoke=org.apache.dubbo.qos.command.impl.InvokeTelnet -select=org.apache.dubbo.qos.command.impl.SelectTelnet -ps=org.apache.dubbo.qos.command.impl.PortTelnet -shutdown=org.apache.dubbo.qos.command.impl.ShutdownTelnet -enableDetailProfiler=org.apache.dubbo.qos.command.impl.EnableDetailProfiler -disableDetailProfiler=org.apache.dubbo.qos.command.impl.DisableDetailProfiler -enableSimpleProfiler=org.apache.dubbo.qos.command.impl.EnableSimpleProfiler -disableSimpleProfiler=org.apache.dubbo.qos.command.impl.DisableSimpleProfiler -setProfilerWarnPercent=org.apache.dubbo.qos.command.impl.SetProfilerWarnPercent -getRouterSnapshot=org.apache.dubbo.qos.command.impl.GetRouterSnapshot -getEnabledRouterSnapshot=org.apache.dubbo.qos.command.impl.GetEnabledRouterSnapshot -enableRouterSnapshot=org.apache.dubbo.qos.command.impl.EnableRouterSnapshot -disableRouterSnapshot=org.apache.dubbo.qos.command.impl.DisableRouterSnapshot -getRecentRouterSnapshot=org.apache.dubbo.qos.command.impl.GetRecentRouterSnapshot -loggerInfo=org.apache.dubbo.qos.command.impl.LoggerInfo -switchLogger=org.apache.dubbo.qos.command.impl.SwitchLogger -switchLogLevel=org.apache.dubbo.qos.command.impl.SwitchLogLevel -serializeCheckStatus=org.apache.dubbo.qos.command.impl.SerializeCheckStatus -serializeWarnedClasses=org.apache.dubbo.qos.command.impl.SerializeWarnedClasses -getConfig=org.apache.dubbo.qos.command.impl.GetConfig -getAddress=org.apache.dubbo.qos.command.impl.GetAddress -gracefulShutdown=org.apache.dubbo.qos.command.impl.GracefulShutdown -metrics_default=org.apache.dubbo.qos.command.impl.DefaultMetricsReporterCmd -getOpenAPI=org.apache.dubbo.qos.command.impl.GetOpenAPI -discovery-timeline=org.apache.dubbo.qos.command.impl.DiscoveryTimelineCommand From 1f4a4eb5e83b63d54bc0c20c2a26ab9a6b2bfd01 Mon Sep 17 00:00:00 2001 From: zrlw Date: Tue, 29 Jul 2025 13:24:39 +0800 Subject: [PATCH 04/10] Update pom.xml --- dubbo-plugin/dubbo-spring-security/pom.xml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/dubbo-plugin/dubbo-spring-security/pom.xml b/dubbo-plugin/dubbo-spring-security/pom.xml index b7391cbc92d3..68844fc816da 100644 --- a/dubbo-plugin/dubbo-spring-security/pom.xml +++ b/dubbo-plugin/dubbo-spring-security/pom.xml @@ -88,11 +88,6 @@ log4j-slf4j-impl test - - org.springframework.security - spring-security-core - 6.5.1 - From 9743d31973716395274aa20b7e1c5b55b6e3f7cb Mon Sep 17 00:00:00 2001 From: ankitshokeen Date: Wed, 30 Jul 2025 03:07:11 +0530 Subject: [PATCH 05/10] fix(qos): add ASF license header and use proper logger codes in DiscoveryTimelineCommand --- dubbo-plugin/dubbo-qos/pom.xml | 5 -- .../impl/DiscoveryTimelineCommand.java | 64 +++++++++++++------ .../org.apache.dubbo.qos.api.BaseCommand | 15 +++++ .../impl/DiscoveryTimelineCommandTest.java | 1 - 4 files changed, 59 insertions(+), 26 deletions(-) diff --git a/dubbo-plugin/dubbo-qos/pom.xml b/dubbo-plugin/dubbo-qos/pom.xml index f65c454cb71d..7c7fcc5b3ad6 100644 --- a/dubbo-plugin/dubbo-qos/pom.xml +++ b/dubbo-plugin/dubbo-qos/pom.xml @@ -86,10 +86,5 @@ dubbo-metrics-default ${project.version} - - org.apache.logging.log4j - log4j-slf4j-impl - test - diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/DiscoveryTimelineCommand.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/DiscoveryTimelineCommand.java index 6f78309500ad..2c388be2063d 100644 --- a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/DiscoveryTimelineCommand.java +++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/DiscoveryTimelineCommand.java @@ -16,7 +16,7 @@ */ package org.apache.dubbo.qos.command.impl; -import org.apache.dubbo.common.logger.Logger; +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.qos.api.BaseCommand; @@ -40,6 +40,11 @@ import java.util.Set; import java.util.stream.Collectors; +import static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_PARAMETER_FORMAT_ERROR; +import static org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_ERROR; +import static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_FAILED_FETCH_INSTANCE; +import static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_FAILED_LOAD_METADATA; + @Cmd( name = "discovery-timeline", summary = "Show service discovery timeline", @@ -52,7 +57,8 @@ }) public class DiscoveryTimelineCommand implements BaseCommand { - private static final Logger logger = LoggerFactory.getLogger(DiscoveryTimelineCommand.class); + private static final ErrorTypeAwareLogger logger = + LoggerFactory.getErrorTypeAwareLogger(DiscoveryTimelineCommand.class); private final FrameworkModel frameworkModel; private static final int DEFAULT_LIMIT = 10; private static final Map globalProviderRegistrationTimes = new HashMap<>(); @@ -74,13 +80,13 @@ public String execute(CommandContext commandContext, String[] args) { RegistryManager registryManager = applicationModel.getBeanFactory().getBean(RegistryManager.class); if (registryManager == null) { - logger.warn("RegistryManager not available"); + logger.warn(REGISTRY_FAILED_FETCH_INSTANCE, "", "", "RegistryManager not available"); return "Error: RegistryManager not available. Check configuration."; } List serviceDiscoveries = registryManager.getServiceDiscoveries(); if (serviceDiscoveries == null || serviceDiscoveries.isEmpty()) { - logger.warn("No ServiceDiscovery found"); + logger.warn(REGISTRY_FAILED_LOAD_METADATA, "", "", "No ServiceDiscovery found"); return "Error: No ServiceDiscovery instances found."; } @@ -99,13 +105,13 @@ public String execute(CommandContext commandContext, String[] args) { try { page = Math.max(1, Integer.parseInt(arg.substring("page=".length()))); } catch (NumberFormatException e) { - logger.warn("Invalid page number: {}", arg, e); + logger.warn(CONFIG_PARAMETER_FORMAT_ERROR, "", "", "Invalid page number: " + arg, e); } } else if (arg.startsWith("limit=")) { try { limit = Math.max(1, Integer.parseInt(arg.substring("limit=".length()))); } catch (NumberFormatException e) { - logger.warn("Invalid limit number: {}", arg, e); + logger.warn(CONFIG_PARAMETER_FORMAT_ERROR, "", "", "Invalid limit number: " + arg, e); } } } @@ -138,7 +144,12 @@ public String execute(CommandContext commandContext, String[] args) { int num2 = Integer.parseInt(numStr2); return Integer.compare(num1, num2); } catch (NumberFormatException e) { - logger.warn("Failed to parse numbers for sorting: {} vs {}", numStr1, numStr2, e); + logger.warn( + CONFIG_PARAMETER_FORMAT_ERROR, + "", + "", + "Failed to parse numbers for sorting: " + numStr1 + " vs " + numStr2, + e); return key1.compareTo(key2); } }) @@ -158,13 +169,21 @@ public String execute(CommandContext commandContext, String[] args) { Set serviceNames = new HashSet<>(); ServiceInstance instance = serviceDiscovery.getLocalInstance(); if (instance == null) { - logger.warn("No local instance found for registry: {}", serviceDiscovery.getUrl()); + logger.warn( + REGISTRY_FAILED_FETCH_INSTANCE, + "", + "", + "No local instance found for registry: " + serviceDiscovery.getUrl()); continue; } Map metadata = instance.getMetadata(); if (metadata == null || metadata.isEmpty()) { - logger.warn("No metadata found for instance in registry: {}", serviceDiscovery.getUrl()); + logger.warn( + REGISTRY_FAILED_LOAD_METADATA, + "", + "", + "No metadata found for instance in registry: " + serviceDiscovery.getUrl()); metadata = new HashMap<>(); } @@ -180,9 +199,11 @@ public String execute(CommandContext commandContext, String[] args) { logger.debug("Set timestamp for {}: {}", serviceName, timestampStr); } catch (NumberFormatException e) { logger.warn( - "Invalid timestamp format for service: {}, timestamp: {}", - serviceName, - timestampStr, + CONFIG_PARAMETER_FORMAT_ERROR, + "", + "", + "Invalid timestamp format for service: " + serviceName + ", timestamp: " + + timestampStr, e); providerRegistrationTimes.put(serviceName, System.currentTimeMillis()); } @@ -228,9 +249,11 @@ public String execute(CommandContext commandContext, String[] args) { refreshTimeStr = new Date(registryTimestamp).toString(); } catch (NumberFormatException e) { logger.warn( - "Invalid timestamp format for registry: {}, timestamp: {}", - sd.getUrl().getAddress(), - timestampStr, + CONFIG_PARAMETER_FORMAT_ERROR, + "", + "", + "Invalid timestamp format for registry: " + + sd.getUrl().getAddress() + ", timestamp: " + timestampStr, e); refreshTimeStr = new Date(System.currentTimeMillis()).toString(); } @@ -241,7 +264,6 @@ public String execute(CommandContext commandContext, String[] args) { timeline.append("------------------------------------------------------------\n"); timeline.append("Provider Services\n"); - // Apply pagination int providerStart = (page - 1) * limit; int providerEnd = Math.min(providerStart + limit, providerModels.size()); logger.debug( @@ -273,7 +295,7 @@ public String execute(CommandContext commandContext, String[] args) { return result; } catch (Exception e) { - logger.error("Failed to generate discovery timeline", e); + logger.error(INTERNAL_ERROR, "", "", "Failed to generate discovery timeline", e); return "Error: " + e.getMessage(); } } @@ -329,9 +351,11 @@ public void onEvent(ServiceInstancesChangedEvent event) { new Date(Long.parseLong(timestampStr)).toString()); } catch (NumberFormatException e) { logger.warn( - "Invalid timestamp format for service: {}, timestamp: {}", - serviceName, - timestampStr, + CONFIG_PARAMETER_FORMAT_ERROR, + "", + "", + "Invalid timestamp format for service: " + serviceName + ", timestamp: " + + timestampStr, e); serviceRegistrationTimes.put(serviceName, System.currentTimeMillis()); } diff --git a/dubbo-plugin/dubbo-qos/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.qos.api.BaseCommand b/dubbo-plugin/dubbo-qos/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.qos.api.BaseCommand index 27ccb8adfe2f..4a527529a9fd 100644 --- a/dubbo-plugin/dubbo-qos/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.qos.api.BaseCommand +++ b/dubbo-plugin/dubbo-qos/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.qos.api.BaseCommand @@ -1,3 +1,18 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + online=org.apache.dubbo.qos.command.impl.Online onlineApp=org.apache.dubbo.qos.command.impl.OnlineApp onlineInterface=org.apache.dubbo.qos.command.impl.OnlineInterface diff --git a/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/DiscoveryTimelineCommandTest.java b/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/DiscoveryTimelineCommandTest.java index f1c72e59fddf..655afe1b8338 100644 --- a/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/DiscoveryTimelineCommandTest.java +++ b/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/DiscoveryTimelineCommandTest.java @@ -123,7 +123,6 @@ void testExecuteWithPagination() { System.out.println("testExecuteWithPagination Output:\n" + output); System.out.println("Providers mocked: " + providers.stream().map(ProviderModel::getServiceKey).collect(Collectors.toList())); - // Debug output character-by-character System.out.println("Output characters:"); for (int i = 0; i < output.length(); i++) { System.out.printf("Index %d: %c (ASCII %d)%n", i, output.charAt(i), (int) output.charAt(i)); From 6a995686193d834938e15cbe720d9d7973e552ec Mon Sep 17 00:00:00 2001 From: ankitshokeen Date: Wed, 30 Jul 2025 04:01:29 +0530 Subject: [PATCH 06/10] revert --- dubbo-plugin/dubbo-qos/pom.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dubbo-plugin/dubbo-qos/pom.xml b/dubbo-plugin/dubbo-qos/pom.xml index 7c7fcc5b3ad6..3ab3a6a018eb 100644 --- a/dubbo-plugin/dubbo-qos/pom.xml +++ b/dubbo-plugin/dubbo-qos/pom.xml @@ -86,5 +86,10 @@ dubbo-metrics-default ${project.version} + + org.slf4j + slf4j-api + test + From 6839f23f3856cd5d46f6a54d11a3f27c02d006e2 Mon Sep 17 00:00:00 2001 From: ankitshokeen Date: Thu, 31 Jul 2025 02:51:38 +0530 Subject: [PATCH 07/10] migrate to logger --- .../impl/DiscoveryTimelineCommandTest.java | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/DiscoveryTimelineCommandTest.java b/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/DiscoveryTimelineCommandTest.java index 655afe1b8338..41a030c42a9a 100644 --- a/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/DiscoveryTimelineCommandTest.java +++ b/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/DiscoveryTimelineCommandTest.java @@ -18,6 +18,8 @@ import org.apache.dubbo.common.URL; import org.apache.dubbo.common.beans.factory.ScopeBeanFactory; +import org.apache.dubbo.common.logger.Logger; +import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.qos.api.CommandContext; import org.apache.dubbo.registry.client.DefaultServiceInstance; import org.apache.dubbo.registry.client.ServiceDiscovery; @@ -40,6 +42,7 @@ public class DiscoveryTimelineCommandTest { + private static final Logger logger = LoggerFactory.getLogger(DiscoveryTimelineCommandTest.class); private DiscoveryTimelineCommand command; private FrameworkModel frameworkModel; private ApplicationModel applicationModel; @@ -82,7 +85,7 @@ void testExecuteWithTimestamps() { Mockito.when(serviceInstance.getMetadata()).thenReturn(metadata); String output = command.execute(new CommandContext("discovery-timeline"), null); - System.out.println("testExecuteWithTimestamps Output:\n" + output); + logger.info("testExecuteWithTimestamps Output:\n{}", output); assertTrue(output.contains("Discovery Timeline")); assertTrue(output.contains("127.0.0.1:2181")); @@ -98,7 +101,7 @@ void testExecuteWithoutMetadata() { Mockito.when(serviceInstance.getMetadata()).thenReturn(null); String output = command.execute(new CommandContext("discovery-timeline"), null); - System.out.println("testExecuteWithoutMetadata Output:\n" + output); + logger.info("testExecuteWithoutMetadata Output:\n{}", output); assertTrue(output.contains("Unknown")); assertTrue(output.contains("Discovered: org.apache.dubbo.demo.DemoService")); @@ -120,13 +123,13 @@ void testExecuteWithPagination() { Mockito.when(serviceInstance.getMetadata()).thenReturn(metadata); String output = command.execute(new CommandContext("discovery-timeline"), new String[] {"limit=5", "page=2"}); - System.out.println("testExecuteWithPagination Output:\n" + output); - System.out.println("Providers mocked: " - + providers.stream().map(ProviderModel::getServiceKey).collect(Collectors.toList())); - System.out.println("Output characters:"); + logger.info("testExecuteWithPagination Output:\n{}", output); + logger.info("Providers mocked: {}", providers.stream().map(ProviderModel::getServiceKey).collect(Collectors.toList())); + StringBuilder charLog = new StringBuilder("Output characters:\n"); for (int i = 0; i < output.length(); i++) { - System.out.printf("Index %d: %c (ASCII %d)%n", i, output.charAt(i), (int) output.charAt(i)); + charLog.append(String.format("Index %d: %c (ASCII %d)%n", i, output.charAt(i), (int) output.charAt(i))); } + logger.info("{}", charLog.toString()); assertTrue(output.contains("Discovery Timeline")); assertTrue(output.contains("Discovered: Service6")); @@ -141,7 +144,7 @@ void testExecuteWithServiceFilter() { Mockito.when(serviceInstance.getMetadata()).thenReturn(new HashMap<>()); String output = command.execute(new CommandContext("discovery-timeline"), new String[] {"service=MyService"}); - System.out.println("testExecuteWithServiceFilter Output:\n" + output); + logger.info("testExecuteWithServiceFilter Output:\n{}", output); assertTrue(output.contains("Discovered: org.apache.dubbo.MyService")); } @@ -154,7 +157,7 @@ void testExecuteWithRegistryFilterMismatch() { Mockito.when(serviceInstance.getMetadata()).thenReturn(new HashMap<>()); String output = command.execute(new CommandContext("discovery-timeline"), new String[] {"registry=nacos"}); - System.out.println("testExecuteWithRegistryFilterMismatch Output:\n" + output); + logger.info("testExecuteWithRegistryFilterMismatch Output:\n{}", output); assertTrue(output.contains("Error: No services discovered.")); } From b9b499598dade34ed4ae9b986fa4c38aee07a28a Mon Sep 17 00:00:00 2001 From: ankitshokeen Date: Thu, 31 Jul 2025 03:01:56 +0530 Subject: [PATCH 08/10] fix formatting issues --- .../dubbo/qos/command/impl/DiscoveryTimelineCommandTest.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/DiscoveryTimelineCommandTest.java b/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/DiscoveryTimelineCommandTest.java index 41a030c42a9a..810021c30316 100644 --- a/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/DiscoveryTimelineCommandTest.java +++ b/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/impl/DiscoveryTimelineCommandTest.java @@ -124,7 +124,9 @@ void testExecuteWithPagination() { String output = command.execute(new CommandContext("discovery-timeline"), new String[] {"limit=5", "page=2"}); logger.info("testExecuteWithPagination Output:\n{}", output); - logger.info("Providers mocked: {}", providers.stream().map(ProviderModel::getServiceKey).collect(Collectors.toList())); + logger.info( + "Providers mocked: {}", + providers.stream().map(ProviderModel::getServiceKey).collect(Collectors.toList())); StringBuilder charLog = new StringBuilder("Output characters:\n"); for (int i = 0; i < output.length(); i++) { charLog.append(String.format("Index %d: %c (ASCII %d)%n", i, output.charAt(i), (int) output.charAt(i))); From c4a89a1755f12429cd0f03f8a394e2380ba4b030 Mon Sep 17 00:00:00 2001 From: zrlw Date: Thu, 31 Jul 2025 11:57:59 +0800 Subject: [PATCH 09/10] Update org.apache.dubbo.qos.api.BaseCommand --- .../internal/org.apache.dubbo.qos.api.BaseCommand | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/dubbo-plugin/dubbo-qos/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.qos.api.BaseCommand b/dubbo-plugin/dubbo-qos/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.qos.api.BaseCommand index 4a527529a9fd..27ccb8adfe2f 100644 --- a/dubbo-plugin/dubbo-qos/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.qos.api.BaseCommand +++ b/dubbo-plugin/dubbo-qos/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.qos.api.BaseCommand @@ -1,18 +1,3 @@ -# 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. - online=org.apache.dubbo.qos.command.impl.Online onlineApp=org.apache.dubbo.qos.command.impl.OnlineApp onlineInterface=org.apache.dubbo.qos.command.impl.OnlineInterface From 04b7a9a54dfed24bcc9e260693f34b0343d1791e Mon Sep 17 00:00:00 2001 From: zrlw Date: Thu, 31 Jul 2025 12:09:52 +0800 Subject: [PATCH 10/10] Update pom.xml --- dubbo-plugin/dubbo-qos/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dubbo-plugin/dubbo-qos/pom.xml b/dubbo-plugin/dubbo-qos/pom.xml index 3ab3a6a018eb..f65c454cb71d 100644 --- a/dubbo-plugin/dubbo-qos/pom.xml +++ b/dubbo-plugin/dubbo-qos/pom.xml @@ -87,8 +87,8 @@ ${project.version} - org.slf4j - slf4j-api + org.apache.logging.log4j + log4j-slf4j-impl test