diff --git a/apm-collector/apm-collector-core/pom.xml b/apm-collector/apm-collector-core/pom.xml
index 4d35a3a00..5c19df2da 100644
--- a/apm-collector/apm-collector-core/pom.xml
+++ b/apm-collector/apm-collector-core/pom.xml
@@ -23,5 +23,10 @@
gson
2.8.1
+
+ net.bytebuddy
+ byte-buddy
+ 1.7.8
+
\ No newline at end of file
diff --git a/apm-collector/apm-collector-core/src/main/java/org/skywalking/apm/collector/core/module/ModuleManager.java b/apm-collector/apm-collector-core/src/main/java/org/skywalking/apm/collector/core/module/ModuleManager.java
index 2cde24246..838b564e5 100644
--- a/apm-collector/apm-collector-core/src/main/java/org/skywalking/apm/collector/core/module/ModuleManager.java
+++ b/apm-collector/apm-collector-core/src/main/java/org/skywalking/apm/collector/core/module/ModuleManager.java
@@ -31,6 +31,7 @@ import java.util.ServiceLoader;
*/
public class ModuleManager {
private Map loadedModules = new HashMap<>();
+ private boolean isServiceInstrument = false;
/**
* Init the given modules
@@ -83,4 +84,12 @@ public class ModuleManager {
return module;
throw new ModuleNotFoundException(moduleName + " missing.");
}
+
+ public boolean isServiceInstrument() {
+ return isServiceInstrument;
+ }
+
+ public void setServiceInstrument(boolean serviceInstrument) {
+ isServiceInstrument = serviceInstrument;
+ }
}
diff --git a/apm-collector/apm-collector-core/src/main/java/org/skywalking/apm/collector/core/module/ModuleProvider.java b/apm-collector/apm-collector-core/src/main/java/org/skywalking/apm/collector/core/module/ModuleProvider.java
index 7c693de2c..05d498879 100644
--- a/apm-collector/apm-collector-core/src/main/java/org/skywalking/apm/collector/core/module/ModuleProvider.java
+++ b/apm-collector/apm-collector-core/src/main/java/org/skywalking/apm/collector/core/module/ModuleProvider.java
@@ -21,6 +21,7 @@ package org.skywalking.apm.collector.core.module;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
+import org.skywalking.apm.collector.core.module.instrument.ServiceInstrumentation;
/**
* The ModuleProvider is an implementation of a {@link Module}.
@@ -90,6 +91,9 @@ public abstract class ModuleProvider {
protected final void registerServiceImplementation(Class extends Service> serviceType,
Service service) throws ServiceNotProvidedException {
if (serviceType.isInstance(service)) {
+ if (manager.isServiceInstrument()) {
+ service = ServiceInstrumentation.INSTANCE.buildServiceUnderMonitor(service);
+ }
this.services.put(serviceType, service);
} else {
throw new ServiceNotProvidedException(serviceType + " is not implemented by " + service);
diff --git a/apm-collector/apm-collector-core/src/main/java/org/skywalking/apm/collector/core/module/instrument/ServiceInstrumentation.java b/apm-collector/apm-collector-core/src/main/java/org/skywalking/apm/collector/core/module/instrument/ServiceInstrumentation.java
new file mode 100644
index 000000000..1b85a8b6c
--- /dev/null
+++ b/apm-collector/apm-collector-core/src/main/java/org/skywalking/apm/collector/core/module/instrument/ServiceInstrumentation.java
@@ -0,0 +1,69 @@
+/*
+ * 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 net.bytebuddy.ByteBuddy;
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.implementation.MethodDelegation;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.skywalking.apm.collector.core.module.Service;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static net.bytebuddy.matcher.ElementMatchers.isStatic;
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static net.bytebuddy.matcher.ElementMatchers.not;
+
+/**
+ * @author wu-sheng
+ */
+public enum ServiceInstrumentation {
+ INSTANCE;
+
+ private final Logger logger = LoggerFactory.getLogger(ServiceInstrumentation.class);
+ private ElementMatcher super MethodDescription> excludeObjectMethodsMatcher;
+
+ public Service buildServiceUnderMonitor(Service implementation) {
+ if (TracedService.class.isInstance(implementation)) {
+ // Duplicate service instrument, ignore.
+ return implementation;
+ }
+ try {
+ return new ByteBuddy().subclass(implementation.getClass())
+ .implement(TracedService.class)
+ .method(getDefaultMatcher()).intercept(
+ MethodDelegation.withDefaultConfiguration().to(new ServiceMetricCollector())
+ ).make().load(getClass().getClassLoader()
+ ).getLoaded().newInstance();
+ } catch (InstantiationException e) {
+ logger.error("Create instrumented service " + implementation.getClass() + " fail.", e);
+ } catch (IllegalAccessException e) {
+ logger.error("Create instrumented service " + implementation.getClass() + " fail.", e);
+ }
+ return implementation;
+ }
+
+ private ElementMatcher super MethodDescription> getDefaultMatcher() {
+ if (excludeObjectMethodsMatcher == null) {
+ excludeObjectMethodsMatcher = not(isStatic().or(named("getClass")).or(named("hashCode")).or(named("equals")).or(named("clone"))
+ .or(named("toString")).or(named("notify")).or(named("notifyAll")).or(named("wait")).or(named("finalize")));
+ }
+ return excludeObjectMethodsMatcher;
+ }
+}
diff --git a/apm-collector/apm-collector-core/src/main/java/org/skywalking/apm/collector/core/module/instrument/ServiceMetricCollector.java b/apm-collector/apm-collector-core/src/main/java/org/skywalking/apm/collector/core/module/instrument/ServiceMetricCollector.java
new file mode 100644
index 000000000..2da824857
--- /dev/null
+++ b/apm-collector/apm-collector-core/src/main/java/org/skywalking/apm/collector/core/module/instrument/ServiceMetricCollector.java
@@ -0,0 +1,42 @@
+/*
+ * 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.concurrent.Callable;
+import net.bytebuddy.implementation.bind.annotation.AllArguments;
+import net.bytebuddy.implementation.bind.annotation.Origin;
+import net.bytebuddy.implementation.bind.annotation.RuntimeType;
+import net.bytebuddy.implementation.bind.annotation.SuperCall;
+import net.bytebuddy.implementation.bind.annotation.This;
+
+/**
+ * @author wu-sheng
+ */
+public class ServiceMetricCollector {
+
+ @RuntimeType
+ public Object intercept(@This Object obj,
+ @AllArguments Object[] allArguments,
+ @SuperCall Callable> zuper,
+ @Origin Method method
+ ) throws Throwable {
+ return zuper.call();
+ }
+}
diff --git a/apm-collector/apm-collector-core/src/main/java/org/skywalking/apm/collector/core/module/instrument/TracedService.java b/apm-collector/apm-collector-core/src/main/java/org/skywalking/apm/collector/core/module/instrument/TracedService.java
new file mode 100644
index 000000000..7cec836ca
--- /dev/null
+++ b/apm-collector/apm-collector-core/src/main/java/org/skywalking/apm/collector/core/module/instrument/TracedService.java
@@ -0,0 +1,32 @@
+/*
+ * 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 org.skywalking.apm.collector.core.module.ModuleManager;
+
+/**
+ * The TracedService implementation are dynamic class, generated by {@link ServiceInstrumentation}, when
+ * {@link ModuleManager#isServiceInstrument} is true.
+ *
+ * By that, all the services metrics are collected, and report in the certain cycle through console.
+ *
+ * @author wu-sheng
+ */
+public interface TracedService {
+}
diff --git a/apm-collector/apm-collector-core/src/test/java/org/skywalking/apm/collector/core/module/ModuleBProvider.java b/apm-collector/apm-collector-core/src/test/java/org/skywalking/apm/collector/core/module/ModuleBProvider.java
index d84602857..e5de9fd65 100644
--- a/apm-collector/apm-collector-core/src/test/java/org/skywalking/apm/collector/core/module/ModuleBProvider.java
+++ b/apm-collector/apm-collector-core/src/test/java/org/skywalking/apm/collector/core/module/ModuleBProvider.java
@@ -19,6 +19,17 @@
package org.skywalking.apm.collector.core.module;
import java.util.Properties;
+import net.bytebuddy.ByteBuddy;
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.implementation.MethodDelegation;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.junit.Test;
+import org.skywalking.apm.collector.core.module.instrument.ServiceMetricCollector;
+import org.skywalking.apm.collector.core.module.instrument.TracedService;
+
+import static net.bytebuddy.matcher.ElementMatchers.isStatic;
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static net.bytebuddy.matcher.ElementMatchers.not;
/**
* @author wu-sheng
diff --git a/apm-collector/apm-collector-core/src/test/java/org/skywalking/apm/collector/core/module/ModuleManagerTest.java b/apm-collector/apm-collector-core/src/test/java/org/skywalking/apm/collector/core/module/ModuleManagerTest.java
index fda8a4f34..0874c9569 100644
--- a/apm-collector/apm-collector-core/src/test/java/org/skywalking/apm/collector/core/module/ModuleManagerTest.java
+++ b/apm-collector/apm-collector-core/src/test/java/org/skywalking/apm/collector/core/module/ModuleManagerTest.java
@@ -18,7 +18,9 @@
package org.skywalking.apm.collector.core.module;
+import org.junit.Assert;
import org.junit.Test;
+import org.skywalking.apm.collector.core.module.instrument.TracedService;
/**
* @author wu-sheng
@@ -37,4 +39,21 @@ public class ModuleManagerTest {
BaseModuleA.ServiceABusiness1 serviceABusiness1 = manager.find("BaseA").provider().getService(BaseModuleA.ServiceABusiness1.class);
serviceABusiness1.print();
}
+
+ //@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);
+
+ ModuleManager manager = new ModuleManager();
+ manager.setServiceInstrument(true);
+ manager.init(configuration);
+
+ BaseModuleA.ServiceABusiness1 serviceABusiness1 = manager.find("BaseA").provider().getService(BaseModuleA.ServiceABusiness1.class);
+ serviceABusiness1.print();
+
+ Assert.assertTrue(serviceABusiness1 instanceof TracedService);
+ }
}