You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@skywalking.apache.org by pe...@apache.org on 2018/04/01 03:16:05 UTC
[incubator-skywalking] branch master updated: Support collector
service instrumentation (#730)
This is an automated email from the ASF dual-hosted git repository.
pengys pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-skywalking.git
The following commit(s) were added to refs/heads/master by this push:
new 049dc2f Support collector service instrumentation (#730)
049dc2f is described below
commit 049dc2fae8b83a6586821836a740491a4074128b
Author: 吴晟 Wu Sheng <wu...@foxmail.com>
AuthorDate: Sun Apr 1 11:16:01 2018 +0800
Support collector service instrumentation (#730)
* Collector instrument agent.
* Make the agent.jar output to the /agent folder in collector package.
* Try to add metric annotation.
* Change the instrument ways.
* Reformat.
* Finish the agent codes. Wait for @peng-yongsheng 's metric requirements.
* Debug new instrument.
* Fix a detect bug.
* Finish the instrument
* Fix compile issue.
---
.../parser/provider/parser/SegmentParse.java | 5 +
.../worker/model/base/LocalAsyncWorkerRef.java | 6 +-
apm-collector/apm-collector-boot/pom.xml | 8 +
.../src/main/assembly/assembly.xml | 7 +
.../core/annotations/trace/BatchParameter.java} | 16 +-
.../annotations/trace/GraphComputingMetric.java} | 18 ++-
.../annotations/trace/TracedGraphElement.java} | 21 ++-
apm-collector/apm-collector-instrument/pom.xml | 41 +++++
.../instrument/CollectorInstrumentAgent.java | 90 +++++++++++
.../apm/collector/instrument/MetricCollector.java | 172 ---------------------
.../apm/collector/instrument/MetricTree.java | 160 +++++++++++++++++++
.../{TracedService.java => ReportWriter.java} | 13 +-
.../instrument/ServiceInstrumentation.java | 73 ---------
.../apm/collector/instrument/ServiceMetric.java | 61 ++++++++
...dService.java => ServiceMetricBatchRecord.java} | 35 ++++-
.../collector/instrument/ServiceMetricRecord.java | 58 +++++++
.../collector/instrument/ServiceMetricTracing.java | 27 +++-
17 files changed, 526 insertions(+), 285 deletions(-)
diff --git a/apm-collector/apm-collector-analysis/analysis-segment-parser/segment-parser-provider/src/main/java/org/apache/skywalking/apm/collector/analysis/segment/parser/provider/parser/SegmentParse.java b/apm-collector/apm-collector-analysis/analysis-segment-parser/segment-parser-provider/src/main/java/org/apache/skywalking/apm/collector/analysis/segment/parser/provider/parser/SegmentParse.java
index 060bb88..b8094cb 100644
--- a/apm-collector/apm-collector-analysis/analysis-segment-parser/segment-parser-provider/src/main/java/org/apache/skywalking/apm/collector/analysis/segment/parser/provider/parser/SegmentParse.java
+++ b/apm-collector/apm-collector-analysis/analysis-segment-parser/segment-parser-provider/src/main/java/org/apache/skywalking/apm/collector/analysis/segment/parser/provider/parser/SegmentParse.java
@@ -36,6 +36,7 @@ import org.apache.skywalking.apm.collector.analysis.segment.parser.provider.pars
import org.apache.skywalking.apm.collector.analysis.segment.parser.provider.parser.standardization.SegmentStandardization;
import org.apache.skywalking.apm.collector.analysis.segment.parser.provider.parser.standardization.SpanIdExchanger;
import org.apache.skywalking.apm.collector.core.UnexpectedException;
+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.GraphManager;
import org.apache.skywalking.apm.collector.core.module.ModuleManager;
@@ -67,6 +68,7 @@ public class SegmentParse {
this.spanListeners = new LinkedList<>();
}
+ @GraphComputingMetric(name = "/segment/parse")
public boolean parse(UpstreamSegment segment, ISegmentParseService.Source source) {
createSpanListeners();
@@ -95,6 +97,7 @@ public class SegmentParse {
return false;
}
+ @GraphComputingMetric(name = "/segment/parse/preBuild")
private boolean preBuild(List<UniqueId> traceIds, SegmentDecorator segmentDecorator) {
StringBuilder segmentIdBuilder = new StringBuilder();
@@ -161,6 +164,7 @@ public class SegmentParse {
return true;
}
+ @GraphComputingMetric(name = "/segment/parse/buildSegment")
private void buildSegment(String id, byte[] dataBinary) {
Segment segment = new Segment();
segment.setId(id);
@@ -170,6 +174,7 @@ public class SegmentParse {
graph.start(segment);
}
+ @GraphComputingMetric(name = "/segment/parse/bufferFile/write")
private void writeToBufferFile(String id, UpstreamSegment upstreamSegment) {
logger.debug("push to segment buffer write worker, id: {}", id);
SegmentStandardization standardization = new SegmentStandardization(id);
diff --git a/apm-collector/apm-collector-analysis/analysis-worker-model/src/main/java/org/apache/skywalking/apm/collector/analysis/worker/model/base/LocalAsyncWorkerRef.java b/apm-collector/apm-collector-analysis/analysis-worker-model/src/main/java/org/apache/skywalking/apm/collector/analysis/worker/model/base/LocalAsyncWorkerRef.java
index da2e810..8d5e43c 100644
--- a/apm-collector/apm-collector-analysis/analysis-worker-model/src/main/java/org/apache/skywalking/apm/collector/analysis/worker/model/base/LocalAsyncWorkerRef.java
+++ b/apm-collector/apm-collector-analysis/analysis-worker-model/src/main/java/org/apache/skywalking/apm/collector/analysis/worker/model/base/LocalAsyncWorkerRef.java
@@ -20,6 +20,8 @@ package org.apache.skywalking.apm.collector.analysis.worker.model.base;
import java.util.Iterator;
import java.util.List;
+import org.apache.skywalking.apm.collector.core.annotations.trace.BatchParameter;
+import org.apache.skywalking.apm.collector.core.annotations.trace.GraphComputingMetric;
import org.apache.skywalking.apm.collector.core.data.QueueData;
import org.apache.skywalking.apm.collector.core.graph.NodeProcessor;
import org.apache.skywalking.apm.collector.core.queue.EndOfBatchContext;
@@ -45,7 +47,9 @@ public class LocalAsyncWorkerRef<INPUT extends QueueData, OUTPUT extends QueueDa
this.dataCarrier = dataCarrier;
}
- @Override public void consume(List<INPUT> data) {
+ @GraphComputingMetric(name = "/worker/async/consume")
+ @Override
+ public void consume(@BatchParameter List<INPUT> data) {
Iterator<INPUT> inputIterator = data.iterator();
int i = 0;
diff --git a/apm-collector/apm-collector-boot/pom.xml b/apm-collector/apm-collector-boot/pom.xml
index 74832f2..d3a2ac1 100644
--- a/apm-collector/apm-collector-boot/pom.xml
+++ b/apm-collector/apm-collector-boot/pom.xml
@@ -175,6 +175,14 @@
<version>${project.version}</version>
</dependency>
<!-- alarm provider -->
+
+ <!-- instrument provided dependency -->
+ <dependency>
+ <groupId>org.apache.skywalking</groupId>
+ <artifactId>apm-collector-instrument</artifactId>
+ <version>${project.version}</version>
+ <scope>provided</scope>
+ </dependency>
</dependencies>
<build>
diff --git a/apm-collector/apm-collector-boot/src/main/assembly/assembly.xml b/apm-collector/apm-collector-boot/src/main/assembly/assembly.xml
index ea2ee62..954e720 100644
--- a/apm-collector/apm-collector-boot/src/main/assembly/assembly.xml
+++ b/apm-collector/apm-collector-boot/src/main/assembly/assembly.xml
@@ -53,5 +53,12 @@
</includes>
<outputDirectory>/config</outputDirectory>
</fileSet>
+ <fileSet>
+ <directory>${project.basedir}/../apm-collector-instrument/target</directory>
+ <includes>
+ <include>collector-instrument-agent.jar</include>
+ </includes>
+ <outputDirectory>/agent</outputDirectory>
+ </fileSet>
</fileSets>
</assembly>
diff --git a/apm-collector/apm-collector-instrument/src/main/java/org/apache/skywalking/apm/collector/instrument/TracedService.java b/apm-collector/apm-collector-core/src/main/java/org/apache/skywalking/apm/collector/core/annotations/trace/BatchParameter.java
similarity index 70%
copy from apm-collector/apm-collector-instrument/src/main/java/org/apache/skywalking/apm/collector/instrument/TracedService.java
copy to apm-collector/apm-collector-core/src/main/java/org/apache/skywalking/apm/collector/core/annotations/trace/BatchParameter.java
index ffcbda4..e49570d 100644
--- a/apm-collector/apm-collector-instrument/src/main/java/org/apache/skywalking/apm/collector/instrument/TracedService.java
+++ b/apm-collector/apm-collector-core/src/main/java/org/apache/skywalking/apm/collector/core/annotations/trace/BatchParameter.java
@@ -16,15 +16,17 @@
*
*/
+package org.apache.skywalking.apm.collector.core.annotations.trace;
-package org.apache.skywalking.apm.collector.instrument;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
/**
- * The <code>TracedService</code> implementation are dynamic class, generated by {@link ServiceInstrumentation}.
- *
- * By that, all the services metrics are collected, and report in the certain cycle through console.
- *
- * @author wu-sheng
+ * @author wusheng
*/
-public interface TracedService {
+@Target(ElementType.PARAMETER)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface BatchParameter {
}
diff --git a/apm-collector/apm-collector-instrument/src/main/java/org/apache/skywalking/apm/collector/instrument/TracedService.java b/apm-collector/apm-collector-core/src/main/java/org/apache/skywalking/apm/collector/core/annotations/trace/GraphComputingMetric.java
similarity index 59%
copy from apm-collector/apm-collector-instrument/src/main/java/org/apache/skywalking/apm/collector/instrument/TracedService.java
copy to apm-collector/apm-collector-core/src/main/java/org/apache/skywalking/apm/collector/core/annotations/trace/GraphComputingMetric.java
index ffcbda4..d5dec9a 100644
--- a/apm-collector/apm-collector-instrument/src/main/java/org/apache/skywalking/apm/collector/instrument/TracedService.java
+++ b/apm-collector/apm-collector-core/src/main/java/org/apache/skywalking/apm/collector/core/annotations/trace/GraphComputingMetric.java
@@ -16,15 +16,23 @@
*
*/
+package org.apache.skywalking.apm.collector.core.annotations.trace;
-package org.apache.skywalking.apm.collector.instrument;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
/**
- * The <code>TracedService</code> implementation are dynamic class, generated by {@link ServiceInstrumentation}.
+ * The method with this annotation should be traced,
+ * and the metrics(avg response time, call count, success rate) could be collected by the instrument agent.
*
- * By that, all the services metrics are collected, and report in the certain cycle through console.
+ * This is an optional annotation.
*
- * @author wu-sheng
+ * @author wusheng
*/
-public interface TracedService {
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface GraphComputingMetric {
+ String name();
}
diff --git a/apm-collector/apm-collector-instrument/src/main/java/org/apache/skywalking/apm/collector/instrument/TracedService.java b/apm-collector/apm-collector-core/src/test/java/org/apache/skywalking/apm/collector/core/annotations/trace/TracedGraphElement.java
similarity index 61%
copy from apm-collector/apm-collector-instrument/src/main/java/org/apache/skywalking/apm/collector/instrument/TracedService.java
copy to apm-collector/apm-collector-core/src/test/java/org/apache/skywalking/apm/collector/core/annotations/trace/TracedGraphElement.java
index ffcbda4..cf95fa3 100644
--- a/apm-collector/apm-collector-instrument/src/main/java/org/apache/skywalking/apm/collector/instrument/TracedService.java
+++ b/apm-collector/apm-collector-core/src/test/java/org/apache/skywalking/apm/collector/core/annotations/trace/TracedGraphElement.java
@@ -16,15 +16,24 @@
*
*/
+package org.apache.skywalking.apm.collector.core.annotations.trace;
-package org.apache.skywalking.apm.collector.instrument;
+import java.util.List;
/**
- * The <code>TracedService</code> implementation are dynamic class, generated by {@link ServiceInstrumentation}.
+ * This is an example about how to use the tracing annotation in collector.
+ * These annotations effect only in `-instrument` mode active.
*
- * By that, all the services metrics are collected, and report in the certain cycle through console.
- *
- * @author wu-sheng
+ * @author wusheng
*/
-public interface TracedService {
+public class TracedGraphElement {
+ @GraphComputingMetric(name = "/traced/element/run")
+ public void run() {
+
+ }
+
+ @GraphComputingMetric(name = "/traced/element/runWithBatch")
+ public void runWithBatch(@BatchParameter List<Object> data) {
+
+ }
}
diff --git a/apm-collector/apm-collector-instrument/pom.xml b/apm-collector/apm-collector-instrument/pom.xml
index ffd5bb0..732c49d 100644
--- a/apm-collector/apm-collector-instrument/pom.xml
+++ b/apm-collector/apm-collector-instrument/pom.xml
@@ -32,6 +32,7 @@
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-collector-core</artifactId>
<version>${project.version}</version>
+ <scope>provided</scope>
</dependency>
<dependency>
<groupId>net.bytebuddy</groupId>
@@ -39,4 +40,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..53d1553
--- /dev/null
+++ b/apm-collector/apm-collector-instrument/src/main/java/org/apache/skywalking/apm/collector/instrument/CollectorInstrumentAgent.java
@@ -0,0 +1,90 @@
+/*
+ * 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.declaresMethod;
+import static net.bytebuddy.matcher.ElementMatchers.isAnnotatedWith;
+import static net.bytebuddy.matcher.ElementMatchers.named;
+
+/**
+ * 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);
+
+ public static void premain(String agentArgs, Instrumentation instrumentation) {
+ new AgentBuilder.Default().type(
+ declaresMethod(isAnnotationedMatch())
+ ).transform((builder, typeDescription, classLoader, module) -> {
+ builder = builder.method(isAnnotationedMatch())
+ .intercept(MethodDelegation.withDefaultConfiguration()
+ .to(new ServiceMetricTracing()));
+ 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> isAnnotationedMatch() {
+ return isAnnotatedWith(named("org.apache.skywalking.apm.collector.core.annotations.trace.GraphComputingMetric"));
+ }
+}
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
deleted file mode 100644
index 9715914..0000000
--- a/apm-collector/apm-collector-instrument/src/main/java/org/apache/skywalking/apm/collector/instrument/MetricCollector.java
+++ /dev/null
@@ -1,172 +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 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() +
- "%";
- }
- }
-}
diff --git a/apm-collector/apm-collector-instrument/src/main/java/org/apache/skywalking/apm/collector/instrument/MetricTree.java b/apm-collector/apm-collector-instrument/src/main/java/org/apache/skywalking/apm/collector/instrument/MetricTree.java
new file mode 100644
index 0000000..b0b5a77
--- /dev/null
+++ b/apm-collector/apm-collector-instrument/src/main/java/org/apache/skywalking/apm/collector/instrument/MetricTree.java
@@ -0,0 +1,160 @@
+/*
+ * 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.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+import org.apache.skywalking.apm.collector.core.annotations.trace.BatchParameter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author wusheng
+ */
+public enum MetricTree implements Runnable {
+ INSTANCE;
+ private final Logger logger = LoggerFactory.getLogger(MetricTree.class);
+
+ private ScheduledFuture<?> scheduledFuture;
+ private List<MetricNode> metrics = new LinkedList<>();
+ private String lineSeparator = System.getProperty("line.separator");
+
+ MetricTree() {
+ ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
+ scheduledFuture = service.scheduleAtFixedRate(this, 60, 60, TimeUnit.SECONDS);
+ }
+
+ synchronized MetricNode lookup(String metricName) {
+ MetricNode node = new MetricNode(metricName);
+ metrics.add(node);
+ return node;
+ }
+
+ @Override
+ public void run() {
+ try {
+ metrics.forEach((metric) -> {
+ metric.exchange();
+ });
+
+ try {
+ Thread.sleep(5 * 1000);
+ } catch (InterruptedException e) {
+
+ }
+
+ StringBuilder logBuffer = new StringBuilder();
+ logBuffer.append(lineSeparator);
+ logBuffer.append("##################################################################################################################").append(lineSeparator);
+ logBuffer.append("# Collector Service Report #").append(lineSeparator);
+ logBuffer.append("##################################################################################################################").append(lineSeparator);
+ metrics.forEach((metric) -> {
+ metric.toOutput(new ReportWriter() {
+
+ @Override public void writeMetricName(String name) {
+ logBuffer.append(name).append("").append(lineSeparator);
+ }
+
+ @Override public void writeMetric(String metrics) {
+ logBuffer.append("\t");
+ logBuffer.append(metrics).append("").append(lineSeparator);
+ }
+ });
+ });
+
+ logger.warn(logBuffer.toString());
+ } catch (Throwable e) {
+ logger.error(e.getMessage(), e);
+ }
+ }
+
+ class MetricNode {
+ private String metricName;
+ private volatile ServiceMetric metric;
+
+ public MetricNode(String metricName) {
+ this.metricName = metricName;
+ }
+
+ ServiceMetric getMetric(Method targetMethod, Object[] allArguments) {
+ if (metric == null) {
+ synchronized (metricName) {
+ if (metric == null) {
+ int detectedBatchIndex = -1;
+ String batchNodeNameSuffix = null;
+ if (targetMethod != null) {
+ Annotation[][] annotations = targetMethod.getParameterAnnotations();
+ if (annotations != null) {
+ int index = 0;
+ for (Annotation[] parameterAnnotation : annotations) {
+ if (parameterAnnotation != null) {
+ for (Annotation annotation : parameterAnnotation) {
+ if (annotation instanceof BatchParameter) {
+ detectedBatchIndex = index;
+ break;
+ }
+ }
+ }
+ if (detectedBatchIndex > -1) {
+ break;
+ }
+ index++;
+ }
+ if (detectedBatchIndex > -1) {
+ Object listArgs = allArguments[index];
+
+ if (listArgs instanceof List) {
+ List args = (List)listArgs;
+ batchNodeNameSuffix = "/" + args.get(0).getClass().getSimpleName();
+ metricName += batchNodeNameSuffix;
+ }
+ }
+ }
+ }
+ metric = new ServiceMetric(metricName, detectedBatchIndex);
+ if (batchNodeNameSuffix != null) {
+ this.metricName += batchNodeNameSuffix;
+ }
+ }
+ }
+ }
+ return metric;
+ }
+
+ void exchange() {
+ if (metric != null) {
+ metric.exchangeWindows();
+ }
+ }
+
+ void toOutput(ReportWriter writer) {
+ writer.writeMetricName(metricName);
+ if (metric != null) {
+ metric.toOutput(writer);
+ }
+
+ }
+ }
+}
diff --git a/apm-collector/apm-collector-instrument/src/main/java/org/apache/skywalking/apm/collector/instrument/TracedService.java b/apm-collector/apm-collector-instrument/src/main/java/org/apache/skywalking/apm/collector/instrument/ReportWriter.java
similarity index 76%
copy from apm-collector/apm-collector-instrument/src/main/java/org/apache/skywalking/apm/collector/instrument/TracedService.java
copy to apm-collector/apm-collector-instrument/src/main/java/org/apache/skywalking/apm/collector/instrument/ReportWriter.java
index ffcbda4..38f36eb 100644
--- a/apm-collector/apm-collector-instrument/src/main/java/org/apache/skywalking/apm/collector/instrument/TracedService.java
+++ b/apm-collector/apm-collector-instrument/src/main/java/org/apache/skywalking/apm/collector/instrument/ReportWriter.java
@@ -16,15 +16,14 @@
*
*/
-
package org.apache.skywalking.apm.collector.instrument;
/**
- * The <code>TracedService</code> implementation are dynamic class, generated by {@link ServiceInstrumentation}.
- *
- * By that, all the services metrics are collected, and report in the certain cycle through console.
- *
- * @author wu-sheng
+ * @author wusheng
*/
-public interface TracedService {
+public interface ReportWriter {
+ void writeMetricName(String name);
+
+ void writeMetric(String metrics);
+
}
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/ServiceMetric.java b/apm-collector/apm-collector-instrument/src/main/java/org/apache/skywalking/apm/collector/instrument/ServiceMetric.java
new file mode 100644
index 0000000..afd970a
--- /dev/null
+++ b/apm-collector/apm-collector-instrument/src/main/java/org/apache/skywalking/apm/collector/instrument/ServiceMetric.java
@@ -0,0 +1,61 @@
+/*
+ * 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.util.List;
+
+/**
+ * @author wusheng
+ */
+public class ServiceMetric {
+ private String metricName;
+ private ServiceMetricRecord winA;
+ private ServiceMetricRecord winB;
+ private volatile boolean isUsingWinA;
+ private volatile int detectedBatchIndex;
+
+ ServiceMetric(String metricName, int detectedBatchIndex) {
+ this.metricName = metricName;
+ winA = detectedBatchIndex > -1 ? new ServiceMetricBatchRecord() : new ServiceMetricRecord();
+ winB = detectedBatchIndex > -1 ? new ServiceMetricBatchRecord() : new ServiceMetricRecord();
+ isUsingWinA = true;
+ this.detectedBatchIndex = detectedBatchIndex;
+ }
+
+ public void trace(long nano, boolean occurException, Object[] allArguments) {
+ ServiceMetricRecord usingRecord = isUsingWinA ? winA : winB;
+ if (detectedBatchIndex > -1) {
+ List listArgs = (List)allArguments[detectedBatchIndex];
+ ((ServiceMetricBatchRecord)usingRecord).add(nano, occurException, listArgs == null ? 0 : listArgs.size());
+ } else {
+ usingRecord.add(nano, occurException);
+ }
+ }
+
+ void exchangeWindows() {
+ isUsingWinA = !isUsingWinA;
+ }
+
+ public void toOutput(ReportWriter writer) {
+ /**
+ * If using A, then B is available and free to output.
+ */
+ writer.writeMetric(isUsingWinA ? winB.toString() : winA.toString());
+ }
+}
diff --git a/apm-collector/apm-collector-instrument/src/main/java/org/apache/skywalking/apm/collector/instrument/TracedService.java b/apm-collector/apm-collector-instrument/src/main/java/org/apache/skywalking/apm/collector/instrument/ServiceMetricBatchRecord.java
similarity index 54%
rename from apm-collector/apm-collector-instrument/src/main/java/org/apache/skywalking/apm/collector/instrument/TracedService.java
rename to apm-collector/apm-collector-instrument/src/main/java/org/apache/skywalking/apm/collector/instrument/ServiceMetricBatchRecord.java
index ffcbda4..a9a0cbd 100644
--- a/apm-collector/apm-collector-instrument/src/main/java/org/apache/skywalking/apm/collector/instrument/TracedService.java
+++ b/apm-collector/apm-collector-instrument/src/main/java/org/apache/skywalking/apm/collector/instrument/ServiceMetricBatchRecord.java
@@ -16,15 +16,36 @@
*
*/
-
package org.apache.skywalking.apm.collector.instrument;
+import java.util.concurrent.atomic.AtomicLong;
+
/**
- * The <code>TracedService</code> implementation are dynamic class, generated by {@link ServiceInstrumentation}.
- *
- * By that, all the services metrics are collected, and report in the certain cycle through console.
- *
- * @author wu-sheng
+ * @author wusheng
*/
-public interface TracedService {
+public class ServiceMetricBatchRecord extends ServiceMetricRecord {
+ private AtomicLong batchRowSize;
+
+ public ServiceMetricBatchRecord() {
+ super();
+ batchRowSize = new AtomicLong(0);
+ }
+
+ void add(long nano, boolean occurException, int rowSize) {
+ super.add(nano, occurException);
+ batchRowSize.addAndGet(rowSize);
+ }
+
+ @Override void clear() {
+ super.clear();
+ batchRowSize.set(0);
+ }
+
+ @Override
+ public String toString() {
+ if (counter.longValue() == 0) {
+ return "Avg=N/A";
+ }
+ return super.toString() + " Rows per call = " + (batchRowSize.get() / counter.get());
+ }
}
diff --git a/apm-collector/apm-collector-instrument/src/main/java/org/apache/skywalking/apm/collector/instrument/ServiceMetricRecord.java b/apm-collector/apm-collector-instrument/src/main/java/org/apache/skywalking/apm/collector/instrument/ServiceMetricRecord.java
new file mode 100644
index 0000000..31ade89
--- /dev/null
+++ b/apm-collector/apm-collector-instrument/src/main/java/org/apache/skywalking/apm/collector/instrument/ServiceMetricRecord.java
@@ -0,0 +1,58 @@
+/*
+ * 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.util.concurrent.atomic.AtomicLong;
+
+/**
+ * @author wusheng
+ */
+public class ServiceMetricRecord {
+ private AtomicLong totalTimeNano;
+ protected AtomicLong counter;
+ private AtomicLong errorCounter;
+
+ public ServiceMetricRecord() {
+ totalTimeNano = new AtomicLong(0);
+ counter = new AtomicLong(0);
+ errorCounter = new AtomicLong(0);
+ }
+
+ void add(long nano, boolean occurException) {
+ totalTimeNano.addAndGet(nano);
+ counter.incrementAndGet();
+ if (occurException)
+ errorCounter.incrementAndGet();
+ }
+
+ 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/ServiceMetricTracing.java b/apm-collector/apm-collector-instrument/src/main/java/org/apache/skywalking/apm/collector/instrument/ServiceMetricTracing.java
index 715ec8e..9462961 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,33 +16,45 @@
*
*/
-
package org.apache.skywalking.apm.collector.instrument;
import java.lang.reflect.Method;
import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentHashMap;
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;
+import org.apache.skywalking.apm.collector.core.annotations.trace.GraphComputingMetric;
/**
* @author wu-sheng
*/
public class ServiceMetricTracing {
- private MetricCollector.ServiceMetric serviceMetric;
+ private volatile ConcurrentHashMap<Method, ServiceMetric> metrics = new ConcurrentHashMap<>();
- public ServiceMetricTracing(String module, String provider, String service) {
- serviceMetric = MetricCollector.INSTANCE.registerService(module, provider, service);
+ public ServiceMetricTracing() {
}
@RuntimeType
- public Object intercept(@This Object obj,
- @AllArguments Object[] allArguments,
+ public Object intercept(
+ @This Object inst,
@SuperCall Callable<?> zuper,
+ @AllArguments Object[] allArguments,
@Origin Method method
) throws Throwable {
+ ServiceMetric metric = this.metrics.get(method);
+ if (metric == null) {
+ GraphComputingMetric annotation = method.getAnnotation(GraphComputingMetric.class);
+ String metricName = annotation.name();
+ synchronized (inst) {
+ MetricTree.MetricNode metricNode = MetricTree.INSTANCE.lookup(metricName);
+ ServiceMetric serviceMetric = metricNode.getMetric(method, allArguments);
+ metrics.put(method, serviceMetric);
+ metric = serviceMetric;
+ }
+ }
boolean occurError = false;
long startNano = System.nanoTime();
long endNano;
@@ -53,7 +65,8 @@ public class ServiceMetricTracing {
throw t;
} finally {
endNano = System.nanoTime();
- serviceMetric.trace(method, endNano - startNano, occurError);
+
+ metric.trace(endNano - startNano, occurError, allArguments);
}
}
}
--
To stop receiving notification emails like this one, please contact
pengys@apache.org.