提交 70ba55da 编写于 作者: P peng-yongsheng

Merge branch 'feature/collector-modelization' of...

Merge branch 'feature/collector-modelization' of https://github.com/OpenSkywalking/skywalking into feature/collector-modelization
......@@ -56,13 +56,5 @@
</includes>
<outputDirectory>/config</outputDirectory>
</fileSet>
<fileSet>
<directory>${project.build.directory}</directory>
<outputDirectory>/libs</outputDirectory>
<includes>
<include>${build.finalName}.jar</include>
</includes>
</fileSet>
</fileSets>
</assembly>
......@@ -31,7 +31,7 @@ import java.util.ServiceLoader;
*/
public class ModuleManager {
private Map<String, Module> loadedModules = new HashMap<>();
private boolean isServiceInstrument = false;
private boolean isServiceInstrument = true;
/**
* Init the given modules
......
......@@ -96,7 +96,7 @@ public abstract class ModuleProvider {
Service service) throws ServiceNotProvidedException {
if (serviceType.isInstance(service)) {
if (manager.isServiceInstrument()) {
service = ServiceInstrumentation.INSTANCE.buildServiceUnderMonitor(service);
service = ServiceInstrumentation.INSTANCE.buildServiceUnderMonitor(module.name(), name(), service);
}
this.services.put(serviceType, service);
} else {
......
/*
* Copyright 2017, OpenSkywalking Organization All rights reserved.
*
* Licensed 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.
*
* Project repository: https://github.com/OpenSkywalking/skywalking
*/
package org.skywalking.apm.collector.core.module.instrument;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The <code>MetricCollector</code> collects the service metrics by Module/Provider/Service structure.
*/
public enum MetricCollector implements Runnable {
INSTANCE;
private final Logger logger = LoggerFactory.getLogger(MetricCollector.class);
private HashMap<String, ModuleMetric> modules = new HashMap<>();
MetricCollector() {
ScheduledExecutorService service = Executors
.newSingleThreadScheduledExecutor();
service.scheduleAtFixedRate(this, 10, 60, TimeUnit.SECONDS);
}
@Override
public void run() {
if (!logger.isDebugEnabled()) {
return;
}
StringBuilder report = new StringBuilder();
report.append("\n");
report.append("##################################################################################################################\n");
report.append("# Collector Service Report #\n");
report.append("##################################################################################################################\n");
modules.forEach((moduleName, moduleMetric) -> {
report.append(moduleName).append(":\n");
moduleMetric.providers.forEach((providerName, providerMetric) -> {
report.append("\t").append(providerName).append(":\n");
providerMetric.services.forEach((serviceName, serviceMetric) -> {
serviceMetric.methodMetrics.forEach((method, metric) -> {
report.append("\t\t").append(method).append(":\n");
report.append("\t\t\t").append(metric).append("\n");
serviceMetric.methodMetrics.put(method, new ServiceMethodMetric());
});
});
});
});
logger.debug(report.toString());
}
ServiceMetric registerService(String module, String provider, String service) {
return initIfAbsent(module).initIfAbsent(provider).initIfAbsent(service);
}
private ModuleMetric initIfAbsent(String moduleName) {
if (!modules.containsKey(moduleName)) {
ModuleMetric metric = new ModuleMetric(moduleName);
modules.put(moduleName, metric);
return metric;
}
return modules.get(moduleName);
}
private class ModuleMetric {
private String moduleName;
private HashMap<String, ProviderMetric> providers = new HashMap<>();
public ModuleMetric(String moduleName) {
this.moduleName = moduleName;
}
private ProviderMetric initIfAbsent(String providerName) {
if (!providers.containsKey(providerName)) {
ProviderMetric metric = new ProviderMetric(providerName);
providers.put(providerName, metric);
return metric;
}
return providers.get(providerName);
}
}
private class ProviderMetric {
private String providerName;
private HashMap<String, ServiceMetric> services = new HashMap<>();
public ProviderMetric(String providerName) {
this.providerName = providerName;
}
private ServiceMetric initIfAbsent(String serviceName) {
if (!services.containsKey(serviceName)) {
ServiceMetric metric = new ServiceMetric(serviceName);
services.put(serviceName, metric);
return metric;
}
return services.get(serviceName);
}
}
class ServiceMetric {
private String serviceName;
private ConcurrentHashMap<Method, ServiceMethodMetric> methodMetrics = new ConcurrentHashMap<>();
public ServiceMetric(String serviceName) {
this.serviceName = serviceName;
}
void trace(Method method, long nano, boolean occurException) {
if (logger.isDebugEnabled()) {
ServiceMethodMetric metric = methodMetrics.get(method);
if (metric == null) {
ServiceMethodMetric methodMetric = new ServiceMethodMetric();
methodMetrics.putIfAbsent(method, methodMetric);
metric = methodMetrics.get(method);
}
metric.add(nano, occurException);
}
}
}
private class ServiceMethodMetric {
private AtomicLong totalTimeNano;
private AtomicLong counter;
private AtomicLong errorCounter;
public ServiceMethodMetric() {
totalTimeNano = new AtomicLong(0);
counter = new AtomicLong(0);
errorCounter = new AtomicLong(0);
}
private void add(long nano, boolean occurException) {
totalTimeNano.addAndGet(nano);
counter.incrementAndGet();
if (occurException)
errorCounter.incrementAndGet();
}
@Override public String toString() {
if (counter.longValue() == 0) {
return "Avg=N/A";
}
return "Avg=" + (totalTimeNano.longValue() / counter.longValue()) + " (nano)" +
", Success Rate=" + (counter.longValue() - errorCounter.longValue()) * 100 / counter.longValue() +
"%";
}
}
}
......@@ -31,6 +31,9 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.not;
/**
* The <code>ServiceInstrumentation</code> create the dynamic service implementations based on the provider
* implementation. So the new implementation will report performance metric to {@link MetricCollector}.
*
* @author wu-sheng
*/
public enum ServiceInstrumentation {
......@@ -39,8 +42,8 @@ public enum ServiceInstrumentation {
private final Logger logger = LoggerFactory.getLogger(ServiceInstrumentation.class);
private ElementMatcher<? super MethodDescription> excludeObjectMethodsMatcher;
public Service buildServiceUnderMonitor(Service implementation) {
if (TracedService.class.isInstance(implementation)) {
public Service buildServiceUnderMonitor(String moduleName, String providerName, Service implementation) {
if (implementation instanceof TracedService) {
// Duplicate service instrument, ignore.
return implementation;
}
......@@ -48,7 +51,7 @@ public enum ServiceInstrumentation {
return new ByteBuddy().subclass(implementation.getClass())
.implement(TracedService.class)
.method(getDefaultMatcher()).intercept(
MethodDelegation.withDefaultConfiguration().to(new ServiceMetricCollector())
MethodDelegation.withDefaultConfiguration().to(new ServiceMetricTracing(moduleName, providerName, implementation.getClass().getName()))
).make().load(getClass().getClassLoader()
).getLoaded().newInstance();
} catch (InstantiationException e) {
......
......@@ -29,7 +29,12 @@ import net.bytebuddy.implementation.bind.annotation.This;
/**
* @author wu-sheng
*/
public class ServiceMetricCollector {
public class ServiceMetricTracing {
private MetricCollector.ServiceMetric serviceMetric;
public ServiceMetricTracing(String module, String provider, String service) {
serviceMetric = MetricCollector.INSTANCE.registerService(module, provider, service);
}
@RuntimeType
public Object intercept(@This Object obj,
......@@ -37,6 +42,17 @@ public class ServiceMetricCollector {
@SuperCall Callable<?> zuper,
@Origin Method method
) throws Throwable {
return zuper.call();
boolean occurError = false;
long startNano = System.nanoTime();
long endNano;
try {
return zuper.call();
} catch (Throwable t) {
occurError = true;
throw t;
} finally {
endNano = System.nanoTime();
serviceMetric.trace(method, endNano - startNano, occurError);
}
}
}
/*
* Copyright 2017, OpenSkywalking Organization All rights reserved.
*
* Licensed 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.
*
* Project repository: https://github.com/OpenSkywalking/skywalking
*/
package org.skywalking.apm.collector.core.module;
/**
* @author wu-sheng
*/
public class ModuleABusiness1Impl implements BaseModuleA.ServiceABusiness1 {
@Override public void print() {
}
}
/*
* Copyright 2017, OpenSkywalking Organization All rights reserved.
*
* Licensed 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.
*
* Project repository: https://github.com/OpenSkywalking/skywalking
*/
package org.skywalking.apm.collector.core.module;
/**
* @author wu-sheng
*/
public class ModuleABusiness2Impl implements BaseModuleA.ServiceABusiness2 {
}
......@@ -33,11 +33,11 @@ public class ModuleAProvider extends ModuleProvider {
}
@Override public void prepare(Properties config) throws ServiceNotProvidedException {
this.registerServiceImplementation(BaseModuleA.ServiceABusiness1.class, new Business1());
this.registerServiceImplementation(BaseModuleA.ServiceABusiness1.class, new ModuleABusiness1Impl());
}
@Override public void start(Properties config) throws ServiceNotProvidedException {
this.registerServiceImplementation(BaseModuleA.ServiceABusiness2.class, new Business2());
this.registerServiceImplementation(BaseModuleA.ServiceABusiness2.class, new ModuleABusiness2Impl());
}
@Override public void notifyAfterCompleted() throws ServiceNotProvidedException {
......@@ -47,14 +47,4 @@ public class ModuleAProvider extends ModuleProvider {
@Override public String[] requiredModules() {
return new String[0];
}
public class Business1 implements BaseModuleA.ServiceABusiness1 {
@Override public void print() {
}
}
public class Business2 implements BaseModuleA.ServiceABusiness2 {
}
}
/*
* Copyright 2017, OpenSkywalking Organization All rights reserved.
*
* Licensed 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.
*
* Project repository: https://github.com/OpenSkywalking/skywalking
*/
package org.skywalking.apm.collector.core.module;
/**
* @author wu-sheng
*/
public class ModuleBBusiness1Impl implements BaseModuleB.ServiceBBusiness1 {
}
/*
* Copyright 2017, OpenSkywalking Organization All rights reserved.
*
* Licensed 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.
*
* Project repository: https://github.com/OpenSkywalking/skywalking
*/
package org.skywalking.apm.collector.core.module;
/**
* @author wu-sheng
*/
public class ModuleBBusiness2Impl implements BaseModuleB.ServiceBBusiness2 {
}
......@@ -33,11 +33,11 @@ public class ModuleBProvider extends ModuleProvider {
}
@Override public void prepare(Properties config) throws ServiceNotProvidedException {
this.registerServiceImplementation(BaseModuleB.ServiceBBusiness1.class, new Business1());
this.registerServiceImplementation(BaseModuleB.ServiceBBusiness1.class, new ModuleBBusiness1Impl());
}
@Override public void start(Properties config) throws ServiceNotProvidedException {
this.registerServiceImplementation(BaseModuleB.ServiceBBusiness2.class, new Business2());
this.registerServiceImplementation(BaseModuleB.ServiceBBusiness2.class, new ModuleBBusiness2Impl());
}
@Override public void notifyAfterCompleted() throws ServiceNotProvidedException {
......@@ -47,12 +47,4 @@ public class ModuleBProvider extends ModuleProvider {
@Override public String[] requiredModules() {
return new String[0];
}
public class Business1 implements BaseModuleB.ServiceBBusiness1 {
}
public class Business2 implements BaseModuleB.ServiceBBusiness2 {
}
}
......@@ -30,30 +30,47 @@ public class ModuleManagerTest {
public void testInit() throws ServiceNotProvidedException, ModuleNotFoundException, ProviderNotFoundException, DuplicateProviderException {
ApplicationConfiguration configuration = new ApplicationConfiguration();
configuration.addModule("Test").addProviderConfiguration("TestModule-Provider", null);
configuration.addModule("BaseA").addProviderConfiguration("P-A",null);
configuration.addModule("BaseB").addProviderConfiguration("P-B",null);
configuration.addModule("BaseA").addProviderConfiguration("P-A", null);
configuration.addModule("BaseB").addProviderConfiguration("P-B", null);
ModuleManager manager = new ModuleManager();
manager.init(configuration);
BaseModuleA.ServiceABusiness1 serviceABusiness1 = manager.find("BaseA").provider().getService(BaseModuleA.ServiceABusiness1.class);
serviceABusiness1.print();
Assert.assertTrue(serviceABusiness1 != null);
}
//@Test
@Test
public void testInstrument() throws ServiceNotProvidedException, ModuleNotFoundException, ProviderNotFoundException, DuplicateProviderException {
ApplicationConfiguration configuration = new ApplicationConfiguration();
configuration.addModule("Test").addProviderConfiguration("TestModule-Provider", null);
configuration.addModule("BaseA").addProviderConfiguration("P-A",null);
configuration.addModule("BaseB").addProviderConfiguration("P-B",null);
configuration.addModule("BaseA").addProviderConfiguration("P-A", null);
configuration.addModule("BaseB").addProviderConfiguration("P-B", null);
ModuleManager manager = new ModuleManager();
manager.setServiceInstrument(true);
manager.init(configuration);
BaseModuleA.ServiceABusiness1 serviceABusiness1 = manager.find("BaseA").provider().getService(BaseModuleA.ServiceABusiness1.class);
serviceABusiness1.print();
BaseModuleA.ServiceABusiness1 serviceABusiness1 = manager.find("BaseA").getService(BaseModuleA.ServiceABusiness1.class);
Assert.assertTrue(serviceABusiness1 instanceof TracedService);
// for (int i = 0; i < 10000; i++)
// serviceABusiness1.print();
//
// try {
// Thread.sleep(60 * 1000L);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
//
// for (int i = 0; i < 10000; i++)
// serviceABusiness1.print();
//
// try {
// Thread.sleep(120 * 1000L);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
}
}
......@@ -29,27 +29,27 @@ public class CMSCollectorModule extends MemoryPoolModule {
super(beans);
}
@Override protected String getPermName() {
return "CMS Perm Gen";
@Override protected String[] getPermNames() {
return new String[] {"CMS Perm Gen"};
}
@Override protected String getCodeCacheName() {
return "Code Cache";
@Override protected String[] getCodeCacheNames() {
return new String[] {"Code Cache"};
}
@Override protected String getEdenName() {
return "Par Eden Space";
@Override protected String[] getEdenNames() {
return new String[] {"Par Eden Space"};
}
@Override protected String getOldName() {
return "CMS Old Gen";
@Override protected String[] getOldNames() {
return new String[] {"CMS Old Gen"};
}
@Override protected String getSurvivorName() {
return "Par Survivor Space";
@Override protected String[] getSurvivorNames() {
return new String[] {"Par Survivor Space"};
}
@Override protected String getMetaspaceName() {
return "Metaspace";
@Override protected String[] getMetaspaceNames() {
return new String[] {"Metaspace"};
}
}
......@@ -29,27 +29,27 @@ public class G1CollectorModule extends MemoryPoolModule {
super(beans);
}
@Override protected String getPermName() {
return "G1 Perm Gen";
@Override protected String[] getPermNames() {
return new String[] {"G1 Perm Gen"};
}
@Override protected String getCodeCacheName() {
return "Code Cache";
@Override protected String[] getCodeCacheNames() {
return new String[] {"Code Cache"};
}
@Override protected String getEdenName() {
return "G1 Eden Space";
@Override protected String[] getEdenNames() {
return new String[] {"G1 Eden Space"};
}
@Override protected String getOldName() {
return "G1 Old Gen";
@Override protected String[] getOldNames() {
return new String[] {"G1 Old Gen"};
}
@Override protected String getSurvivorName() {
return "G1 Survivor Space";
@Override protected String[] getSurvivorNames() {
return new String[] {"G1 Survivor Space"};
}
@Override protected String getMetaspaceName() {
return "Metaspace";
@Override protected String[] getMetaspaceNames() {
return new String[] {"Metaspace"};
}
}
......@@ -40,18 +40,18 @@ public abstract class MemoryPoolModule implements MemoryPoolMetricAccessor {
List<MemoryPool> poolList = new LinkedList<MemoryPool>();
for (MemoryPoolMXBean bean : beans) {
String name = bean.getName();
PoolType type = null;
if (name.equals(getCodeCacheName())) {
PoolType type;
if (contains(getCodeCacheNames(), name)) {
type = PoolType.CODE_CACHE_USAGE;
} else if (name.equals(getEdenName())) {
} else if (contains(getEdenNames(), name)) {
type = PoolType.NEWGEN_USAGE;
} else if (name.equals(getOldName())) {
} else if (contains(getOldNames(), name)) {
type = PoolType.OLDGEN_USAGE;
} else if (name.equals(getSurvivorName())) {
} else if (contains(getSurvivorNames(), name)) {
type = PoolType.SURVIVOR_USAGE;
} else if (name.equals(getMetaspaceName())) {
} else if (contains(getMetaspaceNames(), name)) {
type = PoolType.METASPACE_USAGE;
} else if (name.equals(getPermName())) {
} else if (contains(getPermNames(), name)) {
type = PoolType.PERMGEN_USAGE;
} else {
continue;
......@@ -68,15 +68,24 @@ public abstract class MemoryPoolModule implements MemoryPoolMetricAccessor {
return poolList;
}
protected abstract String getPermName();
private boolean contains(String[] possibleNames, String name) {
for (String possibleName : possibleNames) {
if (name.equals(possibleName)) {
return true;
}
}
return false;
}
protected abstract String[] getPermNames();
protected abstract String getCodeCacheName();
protected abstract String[] getCodeCacheNames();
protected abstract String getEdenName();
protected abstract String[] getEdenNames();
protected abstract String getOldName();
protected abstract String[] getOldNames();
protected abstract String getSurvivorName();
protected abstract String[] getSurvivorNames();
protected abstract String getMetaspaceName();
protected abstract String[] getMetaspaceNames();
}
......@@ -30,27 +30,27 @@ public class ParallelCollectorModule extends MemoryPoolModule {
super(beans);
}
@Override protected String getPermName() {
return "PS Perm Gen";
@Override protected String[] getPermNames() {
return new String[] {"PS Perm Gen", "Compressed Class Space"};
}
@Override protected String getCodeCacheName() {
return "Code Cache";
@Override protected String[] getCodeCacheNames() {
return new String[] {"Code Cache"};
}
@Override protected String getEdenName() {
return "PS Eden Space";
@Override protected String[] getEdenNames() {
return new String[] {"PS Eden Space"};
}
@Override protected String getOldName() {
return "PS Old Gen";
@Override protected String[] getOldNames() {
return new String[] {"PS Old Gen"};
}
@Override protected String getSurvivorName() {
return "PS Survivor Space";
@Override protected String[] getSurvivorNames() {
return new String[] {"PS Survivor Space"};
}
@Override protected String getMetaspaceName() {
return "Metaspace";
@Override protected String[] getMetaspaceNames() {
return new String[] {"Metaspace"};
}
}
......@@ -29,27 +29,27 @@ public class SerialCollectorModule extends MemoryPoolModule {
super(beans);
}
@Override protected String getPermName() {
return "Perm Gen";
@Override protected String[] getPermNames() {
return new String[] {"Perm Gen"};
}
@Override protected String getCodeCacheName() {
return "Code Cache";
@Override protected String[] getCodeCacheNames() {
return new String[] {"Code Cache"};
}
@Override protected String getEdenName() {
return "Eden Space";
@Override protected String[] getEdenNames() {
return new String[] {"Eden Space"};
}
@Override protected String getOldName() {
return "Tenured Gen";
@Override protected String[] getOldNames() {
return new String[] {"Tenured Gen"};
}
@Override protected String getSurvivorName() {
return "Survivor Space";
@Override protected String[] getSurvivorNames() {
return new String[] {"Survivor Space"};
}
@Override protected String getMetaspaceName() {
return "Metaspace";
@Override protected String[] getMetaspaceNames() {
return new String[] {"Metaspace"};
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册