You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@skywalking.apache.org by wu...@apache.org on 2018/01/05 09:11:32 UTC

[incubator-skywalking] branch collector/instrument created (now bd9d400)

This is an automated email from the ASF dual-hosted git repository.

wusheng pushed a change to branch collector/instrument
in repository https://gitbox.apache.org/repos/asf/incubator-skywalking.git.


      at bd9d400  Collector instrument agent.

This branch includes the following new commits:

     new bd9d400  Collector instrument agent.

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


-- 
To stop receiving notification emails like this one, please contact
['"commits@skywalking.apache.org" <co...@skywalking.apache.org>'].

[incubator-skywalking] 01/01: Collector instrument agent.

Posted by wu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

wusheng pushed a commit to branch collector/instrument
in repository https://gitbox.apache.org/repos/asf/incubator-skywalking.git

commit bd9d400b26dd9cdc37927f96363fabd969655b4f
Author: wu-sheng <wu...@foxmail.com>
AuthorDate: Fri Jan 5 17:11:00 2018 +0800

    Collector instrument agent.
---
 apm-collector/apm-collector-instrument/pom.xml     |  41 +++++++
 .../instrument/CollectorInstrumentAgent.java       |  98 ++++++++++++++++
 .../apm/collector/instrument/MetricCollector.java  | 130 ++++++++++-----------
 .../instrument/ServiceInstrumentation.java         |  73 ------------
 .../collector/instrument/ServiceMetricTracing.java |  15 +--
 5 files changed, 204 insertions(+), 153 deletions(-)

diff --git a/apm-collector/apm-collector-instrument/pom.xml b/apm-collector/apm-collector-instrument/pom.xml
index 928de89..346a79a 100644
--- a/apm-collector/apm-collector-instrument/pom.xml
+++ b/apm-collector/apm-collector-instrument/pom.xml
@@ -34,6 +34,7 @@
             <groupId>org.apache.skywalking</groupId>
             <artifactId>apm-collector-core</artifactId>
             <version>${project.version}</version>
+            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>net.bytebuddy</groupId>
@@ -41,4 +42,44 @@
             <version>1.7.8</version>
         </dependency>
     </dependencies>
+
+    <build>
+        <finalName>collector-instrument-agent</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-shade-plugin</artifactId>
+                <version>2.4.1</version>
+                <executions>
+                    <execution>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>shade</goal>
+                        </goals>
+                        <configuration>
+                            <shadedArtifactAttached>false</shadedArtifactAttached>
+                            <createDependencyReducedPom>true</createDependencyReducedPom>
+                            <createSourcesJar>true</createSourcesJar>
+                            <shadeSourcesContent>true</shadeSourcesContent>
+                            <transformers>
+                                <transformer
+                                    implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
+                                    <manifestEntries>
+                                        <Premain-Class>org.apache.skywalking.apm.collector.instrument.CollectorInstrumentAgent</Premain-Class>
+                                    </manifestEntries>
+                                </transformer>
+                            </transformers>
+                            <artifactSet>
+                                <excludes>
+                                    <exclude>com.*:*</exclude>
+                                    <exclude>org.slf4j:*</exclude>
+                                    <exclude>org.apache.logging.log4j:*</exclude>
+                                </excludes>
+                            </artifactSet>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
 </project>
diff --git a/apm-collector/apm-collector-instrument/src/main/java/org/apache/skywalking/apm/collector/instrument/CollectorInstrumentAgent.java b/apm-collector/apm-collector-instrument/src/main/java/org/apache/skywalking/apm/collector/instrument/CollectorInstrumentAgent.java
new file mode 100644
index 0000000..dc7ccf2
--- /dev/null
+++ b/apm-collector/apm-collector-instrument/src/main/java/org/apache/skywalking/apm/collector/instrument/CollectorInstrumentAgent.java
@@ -0,0 +1,98 @@
+/*
+ * 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.instrument;
+
+import java.lang.instrument.Instrumentation;
+import net.bytebuddy.agent.builder.AgentBuilder;
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.description.type.TypeDescription;
+import net.bytebuddy.dynamic.DynamicType;
+import net.bytebuddy.implementation.MethodDelegation;
+import net.bytebuddy.matcher.ElementMatcher;
+import net.bytebuddy.utility.JavaModule;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static net.bytebuddy.matcher.ElementMatchers.hasSuperType;
+import static net.bytebuddy.matcher.ElementMatchers.isStatic;
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static net.bytebuddy.matcher.ElementMatchers.not;
+
+/**
+ * There are a lot of monitoring requirements in collector side.
+ * The agent way is easy, pluggable, and match the target services/graph-nodes automatically.
+ *
+ * This agent is designed and expected running in the same class loader of the collector application,
+ * so I will keep all class loader issue out of concern,
+ * in order to keep the trace and monitor codes as simple as possible.
+ *
+ * @author wu-sheng
+ */
+public class CollectorInstrumentAgent {
+    private final static Logger logger = LoggerFactory.getLogger(CollectorInstrumentAgent.class);
+    private static ElementMatcher<? super MethodDescription> EXCLUDE_OBJECT_DEFAULT_METHODS;
+
+    public static void premain(String agentArgs, Instrumentation instrumentation) {
+        new AgentBuilder.Default().type(hasSuperType(named("org.apache.skywalking.apm.collector.core.module.Service"))).transform(new AgentBuilder.Transformer() {
+            @Override
+            public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription,
+                ClassLoader classLoader, JavaModule module) {
+                builder = builder.method(excludeDefaultMethodsMatcher())
+                    .intercept(MethodDelegation.withDefaultConfiguration()
+                        .to(new ServiceMetricTracing(typeDescription.getActualName())));
+                return builder;
+            }
+        }).with(new AgentBuilder.Listener() {
+            @Override
+            public void onDiscovery(String typeName, ClassLoader classLoader, JavaModule module, boolean loaded) {
+
+            }
+
+            @Override
+            public void onTransformation(TypeDescription typeDescription, ClassLoader classLoader, JavaModule module,
+                boolean loaded, DynamicType dynamicType) {
+
+            }
+
+            @Override
+            public void onIgnored(TypeDescription typeDescription, ClassLoader classLoader, JavaModule module,
+                boolean loaded) {
+
+            }
+
+            @Override public void onError(String typeName, ClassLoader classLoader, JavaModule module, boolean loaded,
+                Throwable throwable) {
+                logger.error("Enhance service " + typeName + " error.", throwable);
+            }
+
+            @Override
+            public void onComplete(String typeName, ClassLoader classLoader, JavaModule module, boolean loaded) {
+
+            }
+        }).installOn(instrumentation);
+    }
+
+    private static ElementMatcher<? super MethodDescription> excludeDefaultMethodsMatcher() {
+        if (EXCLUDE_OBJECT_DEFAULT_METHODS == null) {
+            EXCLUDE_OBJECT_DEFAULT_METHODS = 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 EXCLUDE_OBJECT_DEFAULT_METHODS;
+    }
+}
diff --git a/apm-collector/apm-collector-instrument/src/main/java/org/apache/skywalking/apm/collector/instrument/MetricCollector.java b/apm-collector/apm-collector-instrument/src/main/java/org/apache/skywalking/apm/collector/instrument/MetricCollector.java
index 9715914..5b8b62d 100644
--- a/apm-collector/apm-collector-instrument/src/main/java/org/apache/skywalking/apm/collector/instrument/MetricCollector.java
+++ b/apm-collector/apm-collector-instrument/src/main/java/org/apache/skywalking/apm/collector/instrument/MetricCollector.java
@@ -16,11 +16,9 @@
  *
  */
 
-
 package org.apache.skywalking.apm.collector.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;
@@ -36,7 +34,9 @@ public enum MetricCollector implements Runnable {
     INSTANCE;
 
     private final Logger logger = LoggerFactory.getLogger(MetricCollector.class);
-    private HashMap<String, ModuleMetric> modules = new HashMap<>();
+    private ConcurrentHashMap<String, ServiceMetric> serviceMetricsA = new ConcurrentHashMap<>();
+    private ConcurrentHashMap<String, ServiceMetric> serviceMetricsB = new ConcurrentHashMap<>();
+    private volatile boolean isA = true;
 
     MetricCollector() {
         ScheduledExecutorService service = Executors
@@ -46,99 +46,77 @@ public enum MetricCollector implements Runnable {
 
     @Override
     public void run() {
-        if (!logger.isDebugEnabled()) {
-            return;
+        ConcurrentHashMap<String, ServiceMetric> now;
+        if (isA) {
+            now = serviceMetricsA;
+            isA = false;
+        } else {
+            now = serviceMetricsB;
+            isA = true;
+        }
+        try {
+            // Wait the A/B switch completed.
+            Thread.sleep(1000L);
+        } catch (InterruptedException e) {
+
         }
+
         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());
-                    });
-                });
+        now.forEach((serviceName, serviceMetric) -> {
+            report.append(serviceName).append(":\n");
+            serviceMetric.methodMetrics.forEach((method, metric) -> {
+                if (metric.isExecuted()) {
+                    report.append(method).append(":\n");
+                    report.append("\t").append(metric).append("\n");
+                    metric.clear();
+                }
             });
+            serviceMetric.reset();
         });
 
-        logger.debug(report.toString());
-
-    }
+        /**
+         * The reason of outputing in warn info, is to make sure this logs aren't blocked in performance test.(debug/info log level off)
+         */
+        logger.warn(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);
+    void registerService(String service) {
+        serviceMetricsA.put(service, new ServiceMetric(service));
+        serviceMetricsB.put(service, new ServiceMetric(service));
     }
 
-    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);
-        }
+    void trace(String service, Method method, long nano, boolean occurException) {
+        ConcurrentHashMap<String, ServiceMetric> now = isA ? serviceMetricsA : serviceMetricsB;
+        now.get(service).trace(method, nano, occurException);
     }
 
     class ServiceMetric {
         private String serviceName;
         private ConcurrentHashMap<Method, ServiceMethodMetric> methodMetrics = new ConcurrentHashMap<>();
+        private volatile boolean isExecuted = false;
 
         public ServiceMetric(String serviceName) {
             this.serviceName = serviceName;
         }
 
+        private void reset() {
+            isExecuted = false;
+        }
+
         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);
+            isExecuted = true;
+            ServiceMethodMetric metric = methodMetrics.get(method);
+            if (metric == null) {
+                ServiceMethodMetric methodMetric = new ServiceMethodMetric();
+                methodMetrics.putIfAbsent(method, methodMetric);
+                metric = methodMetrics.get(method);
             }
+            metric.add(nano, occurException);
         }
     }
 
@@ -153,6 +131,10 @@ public enum MetricCollector implements Runnable {
             errorCounter = new AtomicLong(0);
         }
 
+        private boolean isExecuted() {
+            return counter.get() > 0;
+        }
+
         private void add(long nano, boolean occurException) {
             totalTimeNano.addAndGet(nano);
             counter.incrementAndGet();
@@ -160,13 +142,19 @@ public enum MetricCollector implements Runnable {
                 errorCounter.incrementAndGet();
         }
 
+        private void clear() {
+            totalTimeNano.set(0);
+            counter.set(0);
+            errorCounter.set(0);
+        }
+
         @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() +
-                "%";
+                "%, Calls=" + counter.longValue();
         }
     }
 }
diff --git a/apm-collector/apm-collector-instrument/src/main/java/org/apache/skywalking/apm/collector/instrument/ServiceInstrumentation.java b/apm-collector/apm-collector-instrument/src/main/java/org/apache/skywalking/apm/collector/instrument/ServiceInstrumentation.java
deleted file mode 100644
index d73dacd..0000000
--- a/apm-collector/apm-collector-instrument/src/main/java/org/apache/skywalking/apm/collector/instrument/ServiceInstrumentation.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-
-package org.apache.skywalking.apm.collector.instrument;
-
-import net.bytebuddy.ByteBuddy;
-import net.bytebuddy.description.method.MethodDescription;
-import net.bytebuddy.implementation.MethodDelegation;
-import net.bytebuddy.matcher.ElementMatcher;
-import org.apache.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;
-
-/**
- * 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 {
-    INSTANCE;
-
-    private final Logger logger = LoggerFactory.getLogger(ServiceInstrumentation.class);
-    private ElementMatcher<? super MethodDescription> excludeObjectMethodsMatcher;
-
-    public Service buildServiceUnderMonitor(String moduleName, String providerName, Service implementation) {
-        if (implementation instanceof TracedService) {
-            // Duplicate service instrument, ignore.
-            return implementation;
-        }
-        try {
-            return new ByteBuddy().subclass(implementation.getClass())
-                .implement(TracedService.class)
-                .method(getDefaultMatcher()).intercept(
-                    MethodDelegation.withDefaultConfiguration().to(new ServiceMetricTracing(moduleName, providerName, implementation.getClass().getName()))
-                ).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-instrument/src/main/java/org/apache/skywalking/apm/collector/instrument/ServiceMetricTracing.java b/apm-collector/apm-collector-instrument/src/main/java/org/apache/skywalking/apm/collector/instrument/ServiceMetricTracing.java
index 715ec8e..3c47e1d 100644
--- a/apm-collector/apm-collector-instrument/src/main/java/org/apache/skywalking/apm/collector/instrument/ServiceMetricTracing.java
+++ b/apm-collector/apm-collector-instrument/src/main/java/org/apache/skywalking/apm/collector/instrument/ServiceMetricTracing.java
@@ -16,30 +16,27 @@
  *
  */
 
-
 package org.apache.skywalking.apm.collector.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 ServiceMetricTracing {
-    private MetricCollector.ServiceMetric serviceMetric;
+    private String serviceName;
 
-    public ServiceMetricTracing(String module, String provider, String service) {
-        serviceMetric = MetricCollector.INSTANCE.registerService(module, provider, service);
+    public ServiceMetricTracing(String service) {
+        this.serviceName = service;
+        MetricCollector.INSTANCE.registerService(service);
     }
 
     @RuntimeType
-    public Object intercept(@This Object obj,
-        @AllArguments Object[] allArguments,
+    public Object intercept(
         @SuperCall Callable<?> zuper,
         @Origin Method method
     ) throws Throwable {
@@ -53,7 +50,7 @@ public class ServiceMetricTracing {
             throw t;
         } finally {
             endNano = System.nanoTime();
-            serviceMetric.trace(method, endNano - startNano, occurError);
+            MetricCollector.INSTANCE.trace(serviceName, method, endNano - startNano, occurError);
         }
     }
 }

-- 
To stop receiving notification emails like this one, please contact
"commits@skywalking.apache.org" <co...@skywalking.apache.org>.