提交 4b96bc0d 编写于 作者: 彭勇升 pengys 提交者: wu-sheng

The implementation of getThermodynamic in overview page. (#1107)

上级 1e57d48d
...@@ -26,6 +26,8 @@ import org.apache.skywalking.apm.collector.analysis.segment.parser.define.listen ...@@ -26,6 +26,8 @@ import org.apache.skywalking.apm.collector.analysis.segment.parser.define.listen
import org.apache.skywalking.apm.collector.analysis.segment.parser.define.listener.LocalSpanListener; import org.apache.skywalking.apm.collector.analysis.segment.parser.define.listener.LocalSpanListener;
import org.apache.skywalking.apm.collector.analysis.segment.parser.define.listener.SpanListener; import org.apache.skywalking.apm.collector.analysis.segment.parser.define.listener.SpanListener;
import org.apache.skywalking.apm.collector.analysis.segment.parser.define.listener.SpanListenerFactory; import org.apache.skywalking.apm.collector.analysis.segment.parser.define.listener.SpanListenerFactory;
import org.apache.skywalking.apm.collector.configuration.ConfigurationModule;
import org.apache.skywalking.apm.collector.configuration.service.IResponseTimeDistributionConfigService;
import org.apache.skywalking.apm.collector.core.annotations.trace.GraphComputingMetric; import org.apache.skywalking.apm.collector.core.annotations.trace.GraphComputingMetric;
import org.apache.skywalking.apm.collector.core.graph.Graph; import org.apache.skywalking.apm.collector.core.graph.Graph;
import org.apache.skywalking.apm.collector.core.graph.GraphManager; import org.apache.skywalking.apm.collector.core.graph.GraphManager;
...@@ -47,6 +49,11 @@ public class ResponseTimeDistributionSpanListener implements FirstSpanListener, ...@@ -47,6 +49,11 @@ public class ResponseTimeDistributionSpanListener implements FirstSpanListener,
private boolean isError = false; private boolean isError = false;
private int entrySpanDuration = 0; private int entrySpanDuration = 0;
private int firstSpanDuration = 0; private int firstSpanDuration = 0;
private final IResponseTimeDistributionConfigService configService;
ResponseTimeDistributionSpanListener(ModuleManager moduleManager) {
this.configService = moduleManager.find(ConfigurationModule.NAME).getService(IResponseTimeDistributionConfigService.class);
}
@Override public boolean containsPoint(Point point) { @Override public boolean containsPoint(Point point) {
return Point.First.equals(point) || Point.Entry.equals(point) || Point.Exit.equals(point) || Point.Local.equals(point); return Point.First.equals(point) || Point.Entry.equals(point) || Point.Exit.equals(point) || Point.Local.equals(point);
...@@ -101,8 +108,8 @@ public class ResponseTimeDistributionSpanListener implements FirstSpanListener, ...@@ -101,8 +108,8 @@ public class ResponseTimeDistributionSpanListener implements FirstSpanListener,
} }
int getStep() { int getStep() {
int abovePoint = 3000; int responseTimeMaxStep = configService.getResponseTimeStep() * configService.getResponseTimeMaxStep();
int interval = 50; int responseTimeStep = configService.getResponseTimeStep();
int duration; int duration;
if (entrySpanDuration == 0) { if (entrySpanDuration == 0) {
...@@ -111,12 +118,12 @@ public class ResponseTimeDistributionSpanListener implements FirstSpanListener, ...@@ -111,12 +118,12 @@ public class ResponseTimeDistributionSpanListener implements FirstSpanListener,
duration = entrySpanDuration; duration = entrySpanDuration;
} }
if (duration > abovePoint) { if (duration > responseTimeMaxStep) {
return abovePoint / interval; return responseTimeMaxStep / responseTimeStep;
} else if (duration <= interval) { } else if (duration <= responseTimeStep) {
return 0; return 0;
} else { } else {
return (int)Math.ceil((double)duration / (double)interval) - 1; return (int)Math.ceil((double)duration / (double)responseTimeStep) - 1;
} }
} }
...@@ -124,7 +131,7 @@ public class ResponseTimeDistributionSpanListener implements FirstSpanListener, ...@@ -124,7 +131,7 @@ public class ResponseTimeDistributionSpanListener implements FirstSpanListener,
@GraphComputingMetric(name = "/segment/parse/createSpanListeners/responseTimeDistributionSpanListener") @GraphComputingMetric(name = "/segment/parse/createSpanListeners/responseTimeDistributionSpanListener")
@Override public SpanListener create(ModuleManager moduleManager) { @Override public SpanListener create(ModuleManager moduleManager) {
return new ResponseTimeDistributionSpanListener(); return new ResponseTimeDistributionSpanListener(moduleManager);
} }
} }
} }
...@@ -18,8 +18,15 @@ ...@@ -18,8 +18,15 @@
package org.apache.skywalking.apm.collector.analysis.metric.provider.worker.global.std; package org.apache.skywalking.apm.collector.analysis.metric.provider.worker.global.std;
import java.util.LinkedList;
import org.apache.skywalking.apm.collector.configuration.ConfigurationModule;
import org.apache.skywalking.apm.collector.configuration.service.IResponseTimeDistributionConfigService;
import org.apache.skywalking.apm.collector.core.module.Module;
import org.apache.skywalking.apm.collector.core.module.ModuleManager;
import org.apache.skywalking.apm.collector.core.module.ModuleProvider;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.mockito.Mockito;
import org.powermock.reflect.Whitebox; import org.powermock.reflect.Whitebox;
/** /**
...@@ -29,7 +36,22 @@ public class ResponseTimeDistributionSpanListenerTestCase { ...@@ -29,7 +36,22 @@ public class ResponseTimeDistributionSpanListenerTestCase {
@Test @Test
public void testStep() { public void testStep() {
ResponseTimeDistributionSpanListener listener = new ResponseTimeDistributionSpanListener(); ModuleProvider moduleProvider = Mockito.mock(ModuleProvider.class);
LinkedList<ModuleProvider> loadedProviders = new LinkedList<>();
loadedProviders.add(moduleProvider);
IResponseTimeDistributionConfigService service = Mockito.mock(IResponseTimeDistributionConfigService.class);
Mockito.when(service.getResponseTimeStep()).thenReturn(50);
Mockito.when(service.getResponseTimeMaxStep()).thenReturn(40);
Module module = Mockito.mock(Module.class);
Whitebox.setInternalState(module, "loadedProviders", loadedProviders);
Mockito.when(module.getService(IResponseTimeDistributionConfigService.class)).thenReturn(service);
ModuleManager moduleManager = Mockito.mock(ModuleManager.class);
Mockito.when(moduleManager.find(ConfigurationModule.NAME)).thenReturn(module);
ResponseTimeDistributionSpanListener listener = new ResponseTimeDistributionSpanListener(moduleManager);
Whitebox.setInternalState(listener, "entrySpanDuration", 0); Whitebox.setInternalState(listener, "entrySpanDuration", 0);
Whitebox.setInternalState(listener, "firstSpanDuration", 200); Whitebox.setInternalState(listener, "firstSpanDuration", 200);
...@@ -42,6 +64,6 @@ public class ResponseTimeDistributionSpanListenerTestCase { ...@@ -42,6 +64,6 @@ public class ResponseTimeDistributionSpanListenerTestCase {
Assert.assertEquals(1, listener.getStep()); Assert.assertEquals(1, listener.getStep());
Whitebox.setInternalState(listener, "entrySpanDuration", 3100); Whitebox.setInternalState(listener, "entrySpanDuration", 3100);
Assert.assertEquals(60, listener.getStep()); Assert.assertEquals(40, listener.getStep());
} }
} }
...@@ -25,6 +25,7 @@ import org.apache.skywalking.apm.collector.configuration.service.ICollectorConfi ...@@ -25,6 +25,7 @@ import org.apache.skywalking.apm.collector.configuration.service.ICollectorConfi
import org.apache.skywalking.apm.collector.configuration.service.IComponentLibraryCatalogService; import org.apache.skywalking.apm.collector.configuration.service.IComponentLibraryCatalogService;
import org.apache.skywalking.apm.collector.configuration.service.IInstanceAlarmRuleConfig; import org.apache.skywalking.apm.collector.configuration.service.IInstanceAlarmRuleConfig;
import org.apache.skywalking.apm.collector.configuration.service.IInstanceReferenceAlarmRuleConfig; import org.apache.skywalking.apm.collector.configuration.service.IInstanceReferenceAlarmRuleConfig;
import org.apache.skywalking.apm.collector.configuration.service.IResponseTimeDistributionConfigService;
import org.apache.skywalking.apm.collector.configuration.service.IServiceAlarmRuleConfig; import org.apache.skywalking.apm.collector.configuration.service.IServiceAlarmRuleConfig;
import org.apache.skywalking.apm.collector.configuration.service.IServiceReferenceAlarmRuleConfig; import org.apache.skywalking.apm.collector.configuration.service.IServiceReferenceAlarmRuleConfig;
import org.apache.skywalking.apm.collector.core.module.Module; import org.apache.skywalking.apm.collector.core.module.Module;
...@@ -46,6 +47,6 @@ public class ConfigurationModule extends Module { ...@@ -46,6 +47,6 @@ public class ConfigurationModule extends Module {
IApdexThresholdService.class, IApdexThresholdService.class,
IServiceAlarmRuleConfig.class, IInstanceAlarmRuleConfig.class, IApplicationAlarmRuleConfig.class, IServiceAlarmRuleConfig.class, IInstanceAlarmRuleConfig.class, IApplicationAlarmRuleConfig.class,
IServiceReferenceAlarmRuleConfig.class, IInstanceReferenceAlarmRuleConfig.class, IApplicationReferenceAlarmRuleConfig.class, IServiceReferenceAlarmRuleConfig.class, IInstanceReferenceAlarmRuleConfig.class, IApplicationReferenceAlarmRuleConfig.class,
IComponentLibraryCatalogService.class}; IComponentLibraryCatalogService.class, IResponseTimeDistributionConfigService.class};
} }
} }
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.collector.configuration.service;
import org.apache.skywalking.apm.collector.core.module.Service;
/**
* @author peng-yongsheng
*/
public interface IResponseTimeDistributionConfigService extends Service {
int getResponseTimeStep();
int getResponseTimeMaxStep();
}
...@@ -33,6 +33,8 @@ class ConfigurationModuleConfig extends ModuleConfig { ...@@ -33,6 +33,8 @@ class ConfigurationModuleConfig extends ModuleConfig {
private int instanceAverageResponseTimeThreshold; private int instanceAverageResponseTimeThreshold;
private double applicationErrorRateThreshold; private double applicationErrorRateThreshold;
private int applicationAverageResponseTimeThreshold; private int applicationAverageResponseTimeThreshold;
private int responseTimeDistributionDuration;
private int responseTimeDistributionMaxDurationns;
public String getNamespace() { public String getNamespace() {
return namespace; return namespace;
...@@ -97,4 +99,20 @@ class ConfigurationModuleConfig extends ModuleConfig { ...@@ -97,4 +99,20 @@ class ConfigurationModuleConfig extends ModuleConfig {
public void setApplicationAverageResponseTimeThreshold(int applicationAverageResponseTimeThreshold) { public void setApplicationAverageResponseTimeThreshold(int applicationAverageResponseTimeThreshold) {
this.applicationAverageResponseTimeThreshold = applicationAverageResponseTimeThreshold; this.applicationAverageResponseTimeThreshold = applicationAverageResponseTimeThreshold;
} }
public int getResponseTimeDistributionDuration() {
return responseTimeDistributionDuration;
}
public void setResponseTimeDistributionDuration(int responseTimeDistributionDuration) {
this.responseTimeDistributionDuration = responseTimeDistributionDuration;
}
public int getResponseTimeDistributionMaxDurationns() {
return responseTimeDistributionMaxDurationns;
}
public void setResponseTimeDistributionMaxDurationns(int responseTimeDistributionMaxDurationns) {
this.responseTimeDistributionMaxDurationns = responseTimeDistributionMaxDurationns;
}
} }
...@@ -30,10 +30,12 @@ import org.apache.skywalking.apm.collector.configuration.service.ICollectorConfi ...@@ -30,10 +30,12 @@ import org.apache.skywalking.apm.collector.configuration.service.ICollectorConfi
import org.apache.skywalking.apm.collector.configuration.service.IComponentLibraryCatalogService; import org.apache.skywalking.apm.collector.configuration.service.IComponentLibraryCatalogService;
import org.apache.skywalking.apm.collector.configuration.service.IInstanceAlarmRuleConfig; import org.apache.skywalking.apm.collector.configuration.service.IInstanceAlarmRuleConfig;
import org.apache.skywalking.apm.collector.configuration.service.IInstanceReferenceAlarmRuleConfig; import org.apache.skywalking.apm.collector.configuration.service.IInstanceReferenceAlarmRuleConfig;
import org.apache.skywalking.apm.collector.configuration.service.IResponseTimeDistributionConfigService;
import org.apache.skywalking.apm.collector.configuration.service.IServiceAlarmRuleConfig; import org.apache.skywalking.apm.collector.configuration.service.IServiceAlarmRuleConfig;
import org.apache.skywalking.apm.collector.configuration.service.IServiceReferenceAlarmRuleConfig; import org.apache.skywalking.apm.collector.configuration.service.IServiceReferenceAlarmRuleConfig;
import org.apache.skywalking.apm.collector.configuration.service.InstanceAlarmRuleConfig; import org.apache.skywalking.apm.collector.configuration.service.InstanceAlarmRuleConfig;
import org.apache.skywalking.apm.collector.configuration.service.InstanceReferenceAlarmRuleConfig; import org.apache.skywalking.apm.collector.configuration.service.InstanceReferenceAlarmRuleConfig;
import org.apache.skywalking.apm.collector.configuration.service.ResponseTimeDistributionConfigService;
import org.apache.skywalking.apm.collector.configuration.service.ServiceAlarmRuleConfig; import org.apache.skywalking.apm.collector.configuration.service.ServiceAlarmRuleConfig;
import org.apache.skywalking.apm.collector.configuration.service.ServiceReferenceAlarmRuleConfig; import org.apache.skywalking.apm.collector.configuration.service.ServiceReferenceAlarmRuleConfig;
import org.apache.skywalking.apm.collector.core.module.Module; import org.apache.skywalking.apm.collector.core.module.Module;
...@@ -69,13 +71,16 @@ public class ConfigurationModuleProvider extends ModuleProvider { ...@@ -69,13 +71,16 @@ public class ConfigurationModuleProvider extends ModuleProvider {
@Override public void prepare() throws ServiceNotProvidedException { @Override public void prepare() throws ServiceNotProvidedException {
String namespace = StringUtils.isNotEmpty(config.getNamespace()) ? config.getNamespace() : Const.EMPTY_STRING; String namespace = StringUtils.isNotEmpty(config.getNamespace()) ? config.getNamespace() : Const.EMPTY_STRING;
Integer applicationApdexThreshold = config.getApplicationApdexThreshold() == 0 ? 2000 : config.getApplicationApdexThreshold(); int applicationApdexThreshold = config.getApplicationApdexThreshold() == 0 ? 2000 : config.getApplicationApdexThreshold();
Double serviceErrorRateThreshold = config.getServiceErrorRateThreshold() == 0 ? 10.00 : config.getServiceErrorRateThreshold(); double serviceErrorRateThreshold = config.getServiceErrorRateThreshold() == 0 ? 10.00 : config.getServiceErrorRateThreshold();
Integer serviceAverageResponseTimeThreshold = config.getServiceAverageResponseTimeThreshold() == 0 ? 2000 : config.getServiceAverageResponseTimeThreshold(); int serviceAverageResponseTimeThreshold = config.getServiceAverageResponseTimeThreshold() == 0 ? 2000 : config.getServiceAverageResponseTimeThreshold();
Double instanceErrorRateThreshold = config.getInstanceErrorRateThreshold() == 0 ? 10.00 : config.getInstanceErrorRateThreshold(); double instanceErrorRateThreshold = config.getInstanceErrorRateThreshold() == 0 ? 10.00 : config.getInstanceErrorRateThreshold();
Integer instanceAverageResponseTimeThreshold = config.getInstanceAverageResponseTimeThreshold() == 0 ? 2000 : config.getInstanceAverageResponseTimeThreshold(); int instanceAverageResponseTimeThreshold = config.getInstanceAverageResponseTimeThreshold() == 0 ? 2000 : config.getInstanceAverageResponseTimeThreshold();
Double applicationErrorRateThreshold = config.getApplicationErrorRateThreshold() == 0 ? 10.00 : config.getApplicationErrorRateThreshold(); double applicationErrorRateThreshold = config.getApplicationErrorRateThreshold() == 0 ? 10.00 : config.getApplicationErrorRateThreshold();
Integer applicationAverageResponseTimeThreshold = config.getApplicationAverageResponseTimeThreshold() == 0 ? 2000 : config.getApplicationAverageResponseTimeThreshold(); int applicationAverageResponseTimeThreshold = config.getApplicationAverageResponseTimeThreshold() == 0 ? 2000 : config.getApplicationAverageResponseTimeThreshold();
int responseTimeDistributionDuration = config.getResponseTimeDistributionDuration() == 0 ? 50 : config.getResponseTimeDistributionDuration();
int responseTimeDistributionMaxDurations = config.getResponseTimeDistributionMaxDurationns() == 0 ? 40 : config.getResponseTimeDistributionMaxDurationns();
this.registerServiceImplementation(ICollectorConfig.class, new CollectorConfigService(namespace)); this.registerServiceImplementation(ICollectorConfig.class, new CollectorConfigService(namespace));
this.registerServiceImplementation(IComponentLibraryCatalogService.class, new ComponentLibraryCatalogService()); this.registerServiceImplementation(IComponentLibraryCatalogService.class, new ComponentLibraryCatalogService());
...@@ -86,6 +91,7 @@ public class ConfigurationModuleProvider extends ModuleProvider { ...@@ -86,6 +91,7 @@ public class ConfigurationModuleProvider extends ModuleProvider {
this.registerServiceImplementation(IServiceReferenceAlarmRuleConfig.class, new ServiceReferenceAlarmRuleConfig(serviceErrorRateThreshold, serviceAverageResponseTimeThreshold)); this.registerServiceImplementation(IServiceReferenceAlarmRuleConfig.class, new ServiceReferenceAlarmRuleConfig(serviceErrorRateThreshold, serviceAverageResponseTimeThreshold));
this.registerServiceImplementation(IInstanceReferenceAlarmRuleConfig.class, new InstanceReferenceAlarmRuleConfig(instanceErrorRateThreshold, instanceAverageResponseTimeThreshold)); this.registerServiceImplementation(IInstanceReferenceAlarmRuleConfig.class, new InstanceReferenceAlarmRuleConfig(instanceErrorRateThreshold, instanceAverageResponseTimeThreshold));
this.registerServiceImplementation(IApplicationReferenceAlarmRuleConfig.class, new ApplicationReferenceAlarmRuleConfig(applicationErrorRateThreshold, applicationAverageResponseTimeThreshold)); this.registerServiceImplementation(IApplicationReferenceAlarmRuleConfig.class, new ApplicationReferenceAlarmRuleConfig(applicationErrorRateThreshold, applicationAverageResponseTimeThreshold));
this.registerServiceImplementation(IResponseTimeDistributionConfigService.class, new ResponseTimeDistributionConfigService(responseTimeDistributionDuration, responseTimeDistributionMaxDurations));
} }
@Override public void start() { @Override public void start() {
......
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.collector.configuration.service;
/**
* @author peng-yongsheng
*/
public class ResponseTimeDistributionConfigService implements IResponseTimeDistributionConfigService {
private final int responseTimeStep;
private final int responseTimeMaxStep;
public ResponseTimeDistributionConfigService(int responseTimeStep, int responseTimeMaxStep) {
this.responseTimeStep = responseTimeStep;
this.responseTimeMaxStep = responseTimeMaxStep + 1;
}
@Override public int getResponseTimeStep() {
return responseTimeStep;
}
@Override public int getResponseTimeMaxStep() {
return responseTimeMaxStep;
}
}
...@@ -123,6 +123,7 @@ import org.apache.skywalking.apm.collector.storage.dao.ui.IInstanceMetricUIDAO; ...@@ -123,6 +123,7 @@ import org.apache.skywalking.apm.collector.storage.dao.ui.IInstanceMetricUIDAO;
import org.apache.skywalking.apm.collector.storage.dao.ui.IInstanceUIDAO; import org.apache.skywalking.apm.collector.storage.dao.ui.IInstanceUIDAO;
import org.apache.skywalking.apm.collector.storage.dao.ui.IMemoryMetricUIDAO; import org.apache.skywalking.apm.collector.storage.dao.ui.IMemoryMetricUIDAO;
import org.apache.skywalking.apm.collector.storage.dao.ui.INetworkAddressUIDAO; import org.apache.skywalking.apm.collector.storage.dao.ui.INetworkAddressUIDAO;
import org.apache.skywalking.apm.collector.storage.dao.ui.IResponseTimeDistributionUIDAO;
import org.apache.skywalking.apm.collector.storage.dao.ui.ISegmentDurationUIDAO; import org.apache.skywalking.apm.collector.storage.dao.ui.ISegmentDurationUIDAO;
import org.apache.skywalking.apm.collector.storage.dao.ui.ISegmentUIDAO; import org.apache.skywalking.apm.collector.storage.dao.ui.ISegmentUIDAO;
import org.apache.skywalking.apm.collector.storage.dao.ui.IServiceAlarmUIDAO; import org.apache.skywalking.apm.collector.storage.dao.ui.IServiceAlarmUIDAO;
...@@ -260,6 +261,7 @@ public class StorageModule extends Module { ...@@ -260,6 +261,7 @@ public class StorageModule extends Module {
classes.add(IMemoryMetricUIDAO.class); classes.add(IMemoryMetricUIDAO.class);
classes.add(IGlobalTraceUIDAO.class); classes.add(IGlobalTraceUIDAO.class);
classes.add(IResponseTimeDistributionUIDAO.class);
classes.add(IInstanceMetricUIDAO.class); classes.add(IInstanceMetricUIDAO.class);
classes.add(IApplicationComponentUIDAO.class); classes.add(IApplicationComponentUIDAO.class);
classes.add(IApplicationMappingUIDAO.class); classes.add(IApplicationMappingUIDAO.class);
......
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.collector.storage.dao.ui;
import java.util.List;
import org.apache.skywalking.apm.collector.storage.base.dao.DAO;
import org.apache.skywalking.apm.collector.storage.ui.common.Step;
/**
* Interface to be implemented for execute database query operation
* from {@link org.apache.skywalking.apm.collector.storage.table.global.ResponseTimeDistributionTable#TABLE}.
*
* @author peng-yongsheng
* @see org.apache.skywalking.apm.collector.storage.table.global.ResponseTimeDistributionTable
* @see org.apache.skywalking.apm.collector.storage.StorageModule
*/
public interface IResponseTimeDistributionUIDAO extends DAO {
/**
* <p>SQL as: select CALLS, ERROR_CALLS, SUCCESS_CALLS from RESPONSE_TIME_DISTRIBUTION
* where ID in (${responseTimeSteps}),
*
* <p>Rule of ID generation is "${responseTimeStep.getDurationPoint}_${responseTimeStep.getStep}",
*
* <p>Every element in return list must match ResponseTimeStep list, which also means that,
* the two list must be in same size, and yAxis match.
*
* <p>If some element of the return list can't be found, the implementor must set 0 as
* default value.
*
* <p>Use {@link org.apache.skywalking.apm.collector.storage.utils.TimePyramidTableNameBuilder#build(Step, String)}
* to generate table name which mixed with step name.
*
* @param step the step which represent time formats
* @param responseTimeSteps the time points in the time span
* @see org.apache.skywalking.apm.collector.storage.ui.common.Step
*/
void loadMetrics(Step step, List<ResponseTimeStep> responseTimeSteps);
class ResponseTimeStep {
private final int step;
private final long durationPoint;
private final int yAxis;
private long calls;
private long errorCalls;
private long successCalls;
public ResponseTimeStep(long durationPoint, int yAxis, int step) {
this.step = step;
this.durationPoint = durationPoint;
this.yAxis = yAxis;
}
public int getStep() {
return step;
}
public long getDurationPoint() {
return durationPoint;
}
public int getyAxis() {
return yAxis;
}
public long getCalls() {
return calls;
}
public void setCalls(long calls) {
this.calls = calls;
}
public long getErrorCalls() {
return errorCalls;
}
public void setErrorCalls(long errorCalls) {
this.errorCalls = errorCalls;
}
public long getSuccessCalls() {
return successCalls;
}
public void setSuccessCalls(long successCalls) {
this.successCalls = successCalls;
}
}
}
...@@ -137,6 +137,7 @@ import org.apache.skywalking.apm.collector.storage.dao.ui.IInstanceMetricUIDAO; ...@@ -137,6 +137,7 @@ import org.apache.skywalking.apm.collector.storage.dao.ui.IInstanceMetricUIDAO;
import org.apache.skywalking.apm.collector.storage.dao.ui.IInstanceUIDAO; import org.apache.skywalking.apm.collector.storage.dao.ui.IInstanceUIDAO;
import org.apache.skywalking.apm.collector.storage.dao.ui.IMemoryMetricUIDAO; import org.apache.skywalking.apm.collector.storage.dao.ui.IMemoryMetricUIDAO;
import org.apache.skywalking.apm.collector.storage.dao.ui.INetworkAddressUIDAO; import org.apache.skywalking.apm.collector.storage.dao.ui.INetworkAddressUIDAO;
import org.apache.skywalking.apm.collector.storage.dao.ui.IResponseTimeDistributionUIDAO;
import org.apache.skywalking.apm.collector.storage.dao.ui.ISegmentDurationUIDAO; import org.apache.skywalking.apm.collector.storage.dao.ui.ISegmentDurationUIDAO;
import org.apache.skywalking.apm.collector.storage.dao.ui.ISegmentUIDAO; import org.apache.skywalking.apm.collector.storage.dao.ui.ISegmentUIDAO;
import org.apache.skywalking.apm.collector.storage.dao.ui.IServiceAlarmUIDAO; import org.apache.skywalking.apm.collector.storage.dao.ui.IServiceAlarmUIDAO;
...@@ -246,6 +247,7 @@ import org.apache.skywalking.apm.collector.storage.es.dao.ui.InstanceEsUIDAO; ...@@ -246,6 +247,7 @@ import org.apache.skywalking.apm.collector.storage.es.dao.ui.InstanceEsUIDAO;
import org.apache.skywalking.apm.collector.storage.es.dao.ui.InstanceMetricEsUIDAO; import org.apache.skywalking.apm.collector.storage.es.dao.ui.InstanceMetricEsUIDAO;
import org.apache.skywalking.apm.collector.storage.es.dao.ui.MemoryMetricEsUIDAO; import org.apache.skywalking.apm.collector.storage.es.dao.ui.MemoryMetricEsUIDAO;
import org.apache.skywalking.apm.collector.storage.es.dao.ui.NetworkAddressEsUIDAO; import org.apache.skywalking.apm.collector.storage.es.dao.ui.NetworkAddressEsUIDAO;
import org.apache.skywalking.apm.collector.storage.es.dao.ui.ResponseTimeDistributionEsUIDAO;
import org.apache.skywalking.apm.collector.storage.es.dao.ui.SegmentDurationEsUIDAO; import org.apache.skywalking.apm.collector.storage.es.dao.ui.SegmentDurationEsUIDAO;
import org.apache.skywalking.apm.collector.storage.es.dao.ui.SegmentEsUIDAO; import org.apache.skywalking.apm.collector.storage.es.dao.ui.SegmentEsUIDAO;
import org.apache.skywalking.apm.collector.storage.es.dao.ui.ServiceAlarmEsUIDAO; import org.apache.skywalking.apm.collector.storage.es.dao.ui.ServiceAlarmEsUIDAO;
...@@ -450,6 +452,7 @@ public class StorageModuleEsProvider extends ModuleProvider { ...@@ -450,6 +452,7 @@ public class StorageModuleEsProvider extends ModuleProvider {
this.registerServiceImplementation(IServiceAlarmUIDAO.class, new ServiceAlarmEsUIDAO(elasticSearchClient)); this.registerServiceImplementation(IServiceAlarmUIDAO.class, new ServiceAlarmEsUIDAO(elasticSearchClient));
this.registerServiceImplementation(IApplicationAlarmListUIDAO.class, new ApplicationAlarmListEsUIDAO(elasticSearchClient)); this.registerServiceImplementation(IApplicationAlarmListUIDAO.class, new ApplicationAlarmListEsUIDAO(elasticSearchClient));
this.registerServiceImplementation(IResponseTimeDistributionUIDAO.class, new ResponseTimeDistributionEsUIDAO(elasticSearchClient));
} }
private void registerAlarmDAO() throws ServiceNotProvidedException { private void registerAlarmDAO() throws ServiceNotProvidedException {
......
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.collector.storage.es.dao.ui;
import java.util.List;
import org.apache.skywalking.apm.collector.client.elasticsearch.ElasticSearchClient;
import org.apache.skywalking.apm.collector.core.util.Const;
import org.apache.skywalking.apm.collector.storage.dao.ui.IResponseTimeDistributionUIDAO;
import org.apache.skywalking.apm.collector.storage.es.base.dao.EsDAO;
import org.apache.skywalking.apm.collector.storage.table.global.ResponseTimeDistributionTable;
import org.apache.skywalking.apm.collector.storage.ui.common.Step;
import org.apache.skywalking.apm.collector.storage.utils.TimePyramidTableNameBuilder;
import org.elasticsearch.action.get.MultiGetItemResponse;
import org.elasticsearch.action.get.MultiGetRequestBuilder;
import org.elasticsearch.action.get.MultiGetResponse;
/**
* @author peng-yongsheng
*/
public class ResponseTimeDistributionEsUIDAO extends EsDAO implements IResponseTimeDistributionUIDAO {
public ResponseTimeDistributionEsUIDAO(ElasticSearchClient client) {
super(client);
}
@Override
public void loadMetrics(Step step, List<ResponseTimeStep> responseTimeSteps) {
String tableName = TimePyramidTableNameBuilder.build(step, ResponseTimeDistributionTable.TABLE);
MultiGetRequestBuilder prepareMultiGet = getClient().prepareMultiGet(responseTimeSteps, new ElasticSearchClient.MultiGetRowHandler<ResponseTimeStep>() {
@Override
public void accept(ResponseTimeStep responseTimeStep) {
String id = String.valueOf(responseTimeStep.getDurationPoint()) + Const.ID_SPLIT + String.valueOf(responseTimeStep.getStep());
this.add(tableName, ResponseTimeDistributionTable.TABLE_TYPE, id);
}
});
MultiGetResponse multiGetResponse = prepareMultiGet.get();
for (int i = 0; i < multiGetResponse.getResponses().length; i++) {
MultiGetItemResponse response = multiGetResponse.getResponses()[i];
if (response.getResponse().isExists()) {
long calls = ((Number)response.getResponse().getSource().get(ResponseTimeDistributionTable.CALLS.getName())).longValue();
long errorCalls = ((Number)response.getResponse().getSource().get(ResponseTimeDistributionTable.ERROR_CALLS.getName())).longValue();
long successCalls = ((Number)response.getResponse().getSource().get(ResponseTimeDistributionTable.SUCCESS_CALLS.getName())).longValue();
responseTimeSteps.get(i).setCalls(calls);
responseTimeSteps.get(i).setErrorCalls(errorCalls);
responseTimeSteps.get(i).setSuccessCalls(successCalls);
} else {
responseTimeSteps.get(i).setCalls(0);
responseTimeSteps.get(i).setErrorCalls(0);
responseTimeSteps.get(i).setSuccessCalls(0);
}
}
}
}
...@@ -20,6 +20,8 @@ package org.apache.skywalking.apm.collector.storage.h2; ...@@ -20,6 +20,8 @@ package org.apache.skywalking.apm.collector.storage.h2;
import org.apache.skywalking.apm.collector.client.h2.H2Client; import org.apache.skywalking.apm.collector.client.h2.H2Client;
import org.apache.skywalking.apm.collector.client.h2.H2ClientException; import org.apache.skywalking.apm.collector.client.h2.H2ClientException;
import org.apache.skywalking.apm.collector.cluster.ClusterModule;
import org.apache.skywalking.apm.collector.configuration.ConfigurationModule;
import org.apache.skywalking.apm.collector.core.module.Module; import org.apache.skywalking.apm.collector.core.module.Module;
import org.apache.skywalking.apm.collector.core.module.ModuleConfig; import org.apache.skywalking.apm.collector.core.module.ModuleConfig;
import org.apache.skywalking.apm.collector.core.module.ModuleProvider; import org.apache.skywalking.apm.collector.core.module.ModuleProvider;
...@@ -129,6 +131,7 @@ import org.apache.skywalking.apm.collector.storage.dao.ui.IInstanceMetricUIDAO; ...@@ -129,6 +131,7 @@ import org.apache.skywalking.apm.collector.storage.dao.ui.IInstanceMetricUIDAO;
import org.apache.skywalking.apm.collector.storage.dao.ui.IInstanceUIDAO; import org.apache.skywalking.apm.collector.storage.dao.ui.IInstanceUIDAO;
import org.apache.skywalking.apm.collector.storage.dao.ui.IMemoryMetricUIDAO; import org.apache.skywalking.apm.collector.storage.dao.ui.IMemoryMetricUIDAO;
import org.apache.skywalking.apm.collector.storage.dao.ui.INetworkAddressUIDAO; import org.apache.skywalking.apm.collector.storage.dao.ui.INetworkAddressUIDAO;
import org.apache.skywalking.apm.collector.storage.dao.ui.IResponseTimeDistributionUIDAO;
import org.apache.skywalking.apm.collector.storage.dao.ui.ISegmentDurationUIDAO; import org.apache.skywalking.apm.collector.storage.dao.ui.ISegmentDurationUIDAO;
import org.apache.skywalking.apm.collector.storage.dao.ui.ISegmentUIDAO; import org.apache.skywalking.apm.collector.storage.dao.ui.ISegmentUIDAO;
import org.apache.skywalking.apm.collector.storage.dao.ui.IServiceAlarmUIDAO; import org.apache.skywalking.apm.collector.storage.dao.ui.IServiceAlarmUIDAO;
...@@ -238,6 +241,7 @@ import org.apache.skywalking.apm.collector.storage.h2.dao.ui.InstanceH2UIDAO; ...@@ -238,6 +241,7 @@ import org.apache.skywalking.apm.collector.storage.h2.dao.ui.InstanceH2UIDAO;
import org.apache.skywalking.apm.collector.storage.h2.dao.ui.InstanceMetricH2UIDAO; import org.apache.skywalking.apm.collector.storage.h2.dao.ui.InstanceMetricH2UIDAO;
import org.apache.skywalking.apm.collector.storage.h2.dao.ui.MemoryMetricH2UIDAO; import org.apache.skywalking.apm.collector.storage.h2.dao.ui.MemoryMetricH2UIDAO;
import org.apache.skywalking.apm.collector.storage.h2.dao.ui.NetworkAddressH2UIDAO; import org.apache.skywalking.apm.collector.storage.h2.dao.ui.NetworkAddressH2UIDAO;
import org.apache.skywalking.apm.collector.storage.h2.dao.ui.ResponseTimeDistributionH2UIDAO;
import org.apache.skywalking.apm.collector.storage.h2.dao.ui.SegmentDurationH2UIDAO; import org.apache.skywalking.apm.collector.storage.h2.dao.ui.SegmentDurationH2UIDAO;
import org.apache.skywalking.apm.collector.storage.h2.dao.ui.SegmentH2UIDAO; import org.apache.skywalking.apm.collector.storage.h2.dao.ui.SegmentH2UIDAO;
import org.apache.skywalking.apm.collector.storage.h2.dao.ui.ServiceAlarmH2UIDAO; import org.apache.skywalking.apm.collector.storage.h2.dao.ui.ServiceAlarmH2UIDAO;
...@@ -299,7 +303,7 @@ public class StorageModuleH2Provider extends ModuleProvider { ...@@ -299,7 +303,7 @@ public class StorageModuleH2Provider extends ModuleProvider {
} }
@Override public String[] requiredModules() { @Override public String[] requiredModules() {
return new String[] {RemoteModule.NAME}; return new String[] {ClusterModule.NAME, ConfigurationModule.NAME, RemoteModule.NAME};
} }
private void registerCacheDAO() throws ServiceNotProvidedException { private void registerCacheDAO() throws ServiceNotProvidedException {
...@@ -423,6 +427,7 @@ public class StorageModuleH2Provider extends ModuleProvider { ...@@ -423,6 +427,7 @@ public class StorageModuleH2Provider extends ModuleProvider {
this.registerServiceImplementation(IServiceAlarmUIDAO.class, new ServiceAlarmH2UIDAO(h2Client)); this.registerServiceImplementation(IServiceAlarmUIDAO.class, new ServiceAlarmH2UIDAO(h2Client));
this.registerServiceImplementation(IApplicationAlarmListUIDAO.class, new ApplicationAlarmListH2UIDAO(h2Client)); this.registerServiceImplementation(IApplicationAlarmListUIDAO.class, new ApplicationAlarmListH2UIDAO(h2Client));
this.registerServiceImplementation(IResponseTimeDistributionUIDAO.class, new ResponseTimeDistributionH2UIDAO(h2Client));
} }
private void registerAlarmDAO() throws ServiceNotProvidedException { private void registerAlarmDAO() throws ServiceNotProvidedException {
......
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.collector.storage.h2.dao.ui;
import java.util.List;
import org.apache.skywalking.apm.collector.client.h2.H2Client;
import org.apache.skywalking.apm.collector.storage.dao.ui.IResponseTimeDistributionUIDAO;
import org.apache.skywalking.apm.collector.storage.h2.base.dao.H2DAO;
import org.apache.skywalking.apm.collector.storage.ui.common.Step;
/**
* @author peng-yongsheng
*/
public class ResponseTimeDistributionH2UIDAO extends H2DAO implements IResponseTimeDistributionUIDAO {
public ResponseTimeDistributionH2UIDAO(H2Client client) {
super(client);
}
@Override public void loadMetrics(Step step, List<ResponseTimeStep> responseTimeSteps) {
}
}
...@@ -45,6 +45,11 @@ ...@@ -45,6 +45,11 @@
<artifactId>client-component</artifactId> <artifactId>client-component</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>collector-configuration-define</artifactId>
<version>${project.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.apache.skywalking</groupId> <groupId>org.apache.skywalking</groupId>
<artifactId>collector-remote-define</artifactId> <artifactId>collector-remote-define</artifactId>
......
...@@ -35,6 +35,7 @@ import org.apache.skywalking.apm.collector.ui.service.AlarmService; ...@@ -35,6 +35,7 @@ import org.apache.skywalking.apm.collector.ui.service.AlarmService;
import org.apache.skywalking.apm.collector.ui.service.ApplicationService; import org.apache.skywalking.apm.collector.ui.service.ApplicationService;
import org.apache.skywalking.apm.collector.ui.service.ClusterTopologyService; import org.apache.skywalking.apm.collector.ui.service.ClusterTopologyService;
import org.apache.skywalking.apm.collector.ui.service.NetworkAddressService; import org.apache.skywalking.apm.collector.ui.service.NetworkAddressService;
import org.apache.skywalking.apm.collector.ui.service.ResponseTimeDistributionService;
import org.apache.skywalking.apm.collector.ui.service.ServiceNameService; import org.apache.skywalking.apm.collector.ui.service.ServiceNameService;
import org.apache.skywalking.apm.collector.ui.utils.DurationUtils; import org.apache.skywalking.apm.collector.ui.utils.DurationUtils;
...@@ -51,6 +52,7 @@ public class OverViewLayerQuery implements Query { ...@@ -51,6 +52,7 @@ public class OverViewLayerQuery implements Query {
private NetworkAddressService networkAddressService; private NetworkAddressService networkAddressService;
private ServiceNameService serviceNameService; private ServiceNameService serviceNameService;
private AlarmService alarmService; private AlarmService alarmService;
private ResponseTimeDistributionService timeDistributionService;
public OverViewLayerQuery(ModuleManager moduleManager) { public OverViewLayerQuery(ModuleManager moduleManager) {
this.moduleManager = moduleManager; this.moduleManager = moduleManager;
...@@ -91,6 +93,13 @@ public class OverViewLayerQuery implements Query { ...@@ -91,6 +93,13 @@ public class OverViewLayerQuery implements Query {
return alarmService; return alarmService;
} }
private ResponseTimeDistributionService getTimeDistributionService() {
if (isNull(timeDistributionService)) {
this.timeDistributionService = new ResponseTimeDistributionService(moduleManager);
}
return timeDistributionService;
}
public Topology getClusterTopology(Duration duration) throws ParseException { public Topology getClusterTopology(Duration duration) throws ParseException {
long startTimeBucket = DurationUtils.INSTANCE.exchangeToTimeBucket(duration.getStart()); long startTimeBucket = DurationUtils.INSTANCE.exchangeToTimeBucket(duration.getStart());
long endTimeBucket = DurationUtils.INSTANCE.exchangeToTimeBucket(duration.getEnd()); long endTimeBucket = DurationUtils.INSTANCE.exchangeToTimeBucket(duration.getEnd());
...@@ -150,6 +159,9 @@ public class OverViewLayerQuery implements Query { ...@@ -150,6 +159,9 @@ public class OverViewLayerQuery implements Query {
} }
public Thermodynamic getThermodynamic(Duration duration, ValueType type) throws ParseException { public Thermodynamic getThermodynamic(Duration duration, ValueType type) throws ParseException {
return new Thermodynamic(); long startTimeBucket = DurationUtils.INSTANCE.exchangeToTimeBucket(duration.getStart());
long endTimeBucket = DurationUtils.INSTANCE.exchangeToTimeBucket(duration.getEnd());
return getTimeDistributionService().getThermodynamic(duration.getStep(), startTimeBucket, endTimeBucket, type);
} }
} }
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.collector.ui.service;
import java.text.ParseException;
import java.util.LinkedList;
import java.util.List;
import org.apache.skywalking.apm.collector.configuration.ConfigurationModule;
import org.apache.skywalking.apm.collector.configuration.service.IResponseTimeDistributionConfigService;
import org.apache.skywalking.apm.collector.core.module.ModuleManager;
import org.apache.skywalking.apm.collector.storage.StorageModule;
import org.apache.skywalking.apm.collector.storage.dao.ui.IResponseTimeDistributionUIDAO;
import org.apache.skywalking.apm.collector.storage.ui.common.Step;
import org.apache.skywalking.apm.collector.storage.ui.common.ValueType;
import org.apache.skywalking.apm.collector.storage.ui.overview.Thermodynamic;
import org.apache.skywalking.apm.collector.storage.utils.DurationPoint;
import org.apache.skywalking.apm.collector.ui.utils.DurationUtils;
/**
* @author peng-yongsheng
*/
public class ResponseTimeDistributionService {
private final IResponseTimeDistributionConfigService responseTimeDistributionConfigService;
private final IResponseTimeDistributionUIDAO responseTimeDistributionUIDAO;
public ResponseTimeDistributionService(ModuleManager moduleManager) {
this.responseTimeDistributionConfigService = moduleManager.find(ConfigurationModule.NAME).getService(IResponseTimeDistributionConfigService.class);
this.responseTimeDistributionUIDAO = moduleManager.find(StorageModule.NAME).getService(IResponseTimeDistributionUIDAO.class);
}
public Thermodynamic getThermodynamic(Step step, long startTimeBucket, long endTimeBucket,
ValueType type) throws ParseException {
List<DurationPoint> durationPoints = DurationUtils.INSTANCE.getDurationPoints(step, startTimeBucket, endTimeBucket);
List<IResponseTimeDistributionUIDAO.ResponseTimeStep> responseTimeSteps = new LinkedList<>();
for (int i = 0; i < durationPoints.size(); i++) {
for (int j = 0; j < responseTimeDistributionConfigService.getResponseTimeMaxStep(); j++) {
responseTimeSteps.add(new IResponseTimeDistributionUIDAO.ResponseTimeStep(durationPoints.get(i).getPoint(), i, j));
}
}
responseTimeDistributionUIDAO.loadMetrics(step, responseTimeSteps);
Thermodynamic thermodynamic = new Thermodynamic();
thermodynamic.setResponseTimeStep(responseTimeDistributionConfigService.getResponseTimeStep());
responseTimeSteps.forEach(responseTimeStep -> {
long calls = 0;
switch (type) {
case ALL:
calls = responseTimeStep.getCalls();
break;
case RIGHT:
calls = responseTimeStep.getSuccessCalls();
break;
case WRONG:
calls = responseTimeStep.getErrorCalls();
break;
}
List<Long> metric = trans(responseTimeStep.getyAxis(), responseTimeStep.getStep(), calls);
thermodynamic.getNodes().add(metric);
});
return thermodynamic;
}
private List<Long> trans(long xAxis, long yAxis, long calls) {
List<Long> metric = new LinkedList<>();
metric.add(xAxis);
metric.add(yAxis);
metric.add(calls);
return metric;
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册