You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by wu...@apache.org on 2020/12/08 02:04:32 UTC

[skywalking] branch master updated: Change the operation name of quartz-scheduler plugin (#5934)

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

wusheng pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/skywalking.git


The following commit(s) were added to refs/heads/master by this push:
     new fbf49b2  Change the operation name of quartz-scheduler plugin (#5934)
fbf49b2 is described below

commit fbf49b2cc61a42305b0a44a3518e6058154f47f7
Author: hailin0 <ha...@foxmail.com>
AuthorDate: Tue Dec 8 10:04:14 2020 +0800

    Change the operation name of quartz-scheduler plugin (#5934)
---
 CHANGES.md                                         |  1 +
 ....java => JobExecuteStateMethodInterceptor.java} | 51 +++++-----------------
 .../quartz/JobRunShellMethodInterceptor.java       |  6 ++-
 .../JobRunShellInterceptorInstrumentation.java     | 32 +++++++++++---
 docs/en/setup/service-agent/java-agent/README.md   |  2 +-
 .../config/expectedData.yaml                       | 32 ++++++++++++--
 .../testcase/quartzscheduler/job/ExceptionJob.java | 32 ++++++++++++++
 .../testcase/quartzscheduler/job/QuartzConfig.java | 21 ++++++++-
 8 files changed, 126 insertions(+), 51 deletions(-)

diff --git a/CHANGES.md b/CHANGES.md
index 228bf47..1d2ce2a 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -8,6 +8,7 @@ Release Notes.
 * Chore: adapt `create_source_release.sh` to make it runnable on Linux.
 
 #### Java Agent
+* The operation name of quartz-scheduler plugin, has been changed as the `quartz-scheduler/${className}` format.
 * Fix jdk-http and okhttp-3.x plugin did not overwrite the old trace header.
 
 #### OAP-Backend
diff --git a/apm-sniffer/optional-plugins/quartz-scheduler-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/quartz/JobRunShellMethodInterceptor.java b/apm-sniffer/optional-plugins/quartz-scheduler-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/quartz/JobExecuteStateMethodInterceptor.java
similarity index 51%
copy from apm-sniffer/optional-plugins/quartz-scheduler-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/quartz/JobRunShellMethodInterceptor.java
copy to apm-sniffer/optional-plugins/quartz-scheduler-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/quartz/JobExecuteStateMethodInterceptor.java
index 465a7fe..e42c45a 100644
--- a/apm-sniffer/optional-plugins/quartz-scheduler-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/quartz/JobRunShellMethodInterceptor.java
+++ b/apm-sniffer/optional-plugins/quartz-scheduler-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/quartz/JobExecuteStateMethodInterceptor.java
@@ -19,65 +19,38 @@
 package org.apache.skywalking.apm.plugin.quartz;
 
 import org.apache.skywalking.apm.agent.core.context.ContextManager;
-import org.apache.skywalking.apm.agent.core.context.tag.AbstractTag;
-import org.apache.skywalking.apm.agent.core.context.tag.Tags;
 import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
 import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
 import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
 import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
-import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
-import org.quartz.JobDataMap;
-import org.quartz.JobDetail;
+import org.quartz.JobExecutionException;
+import org.quartz.core.JobRunShell;
 
 import java.lang.reflect.Method;
-import java.util.Collections;
-import java.util.Map;
 
 /**
- * Intercept method of {@link org.quartz.core.JobRunShell#run()}.
- * record the quartz job local span.
+ * Intercept method of {@link JobRunShell#notifyJobListenersComplete(org.quartz.JobExecutionContext, org.quartz.JobExecutionException)}.
+ * record the quartz job execute exception.
  */
-public class JobRunShellMethodInterceptor implements InstanceMethodsAroundInterceptor {
-
-    private static final AbstractTag JOB_GROUP = Tags.ofKey("jobGroup");
-    private static final AbstractTag JOB_DATA_MAP = Tags.ofKey("jobDataMap");
-
-    private static final String EMPTY_JOB_DATA_MAP_STRING = Collections.emptyMap().toString();
+public class JobExecuteStateMethodInterceptor implements InstanceMethodsAroundInterceptor {
 
     @Override
     public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
-        JobDetail jobDetail = (JobDetail) objInst.getSkyWalkingDynamicField();
-
-        String jobName = jobDetail.getKey().getName();
-        String jobGroup = jobDetail.getKey().getGroup();
-        String operationName = ComponentsDefine.QUARTZ_SCHEDULER.getName() + "/" + jobName;
-
-        AbstractSpan span = ContextManager.createLocalSpan(operationName);
-        span.setComponent(ComponentsDefine.QUARTZ_SCHEDULER);
-        Tags.LOGIC_ENDPOINT.set(span, Tags.VAL_LOCAL_SPAN_AS_LOGIC_ENDPOINT);
-        span.tag(JOB_GROUP, jobGroup == null ? "" : jobGroup);
-        span.tag(JOB_DATA_MAP, getJobDataMapString(jobDetail));
+        if (ContextManager.isActive()) {
+            JobExecutionException exception = (JobExecutionException) allArguments[1];
+            if (exception != null) {
+                AbstractSpan span = ContextManager.activeSpan();
+                span.log(exception);
+            }
+        }
     }
 
     @Override
     public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Object ret) throws Throwable {
-        ContextManager.stopSpan();
         return ret;
     }
 
     @Override
     public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Throwable t) {
-        ContextManager.activeSpan().log(t);
-    }
-
-    private static String getJobDataMapString(JobDetail jobDetail) {
-        JobDataMap jobDataMap = jobDetail.getJobDataMap();
-        if (jobDataMap != null) {
-            Map wrappedMap = jobDataMap.getWrappedMap();
-            if (wrappedMap != null) {
-                return wrappedMap.toString();
-            }
-        }
-        return EMPTY_JOB_DATA_MAP_STRING;
     }
 }
diff --git a/apm-sniffer/optional-plugins/quartz-scheduler-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/quartz/JobRunShellMethodInterceptor.java b/apm-sniffer/optional-plugins/quartz-scheduler-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/quartz/JobRunShellMethodInterceptor.java
index 465a7fe..213c93c 100644
--- a/apm-sniffer/optional-plugins/quartz-scheduler-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/quartz/JobRunShellMethodInterceptor.java
+++ b/apm-sniffer/optional-plugins/quartz-scheduler-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/quartz/JobRunShellMethodInterceptor.java
@@ -40,6 +40,7 @@ import java.util.Map;
 public class JobRunShellMethodInterceptor implements InstanceMethodsAroundInterceptor {
 
     private static final AbstractTag JOB_GROUP = Tags.ofKey("jobGroup");
+    private static final AbstractTag JOB_NAME = Tags.ofKey("jobName");
     private static final AbstractTag JOB_DATA_MAP = Tags.ofKey("jobDataMap");
 
     private static final String EMPTY_JOB_DATA_MAP_STRING = Collections.emptyMap().toString();
@@ -48,14 +49,15 @@ public class JobRunShellMethodInterceptor implements InstanceMethodsAroundInterc
     public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
         JobDetail jobDetail = (JobDetail) objInst.getSkyWalkingDynamicField();
 
-        String jobName = jobDetail.getKey().getName();
         String jobGroup = jobDetail.getKey().getGroup();
-        String operationName = ComponentsDefine.QUARTZ_SCHEDULER.getName() + "/" + jobName;
+        String jobName = jobDetail.getKey().getName();
+        String operationName = ComponentsDefine.QUARTZ_SCHEDULER.getName() + "/" + jobDetail.getJobClass().getName();
 
         AbstractSpan span = ContextManager.createLocalSpan(operationName);
         span.setComponent(ComponentsDefine.QUARTZ_SCHEDULER);
         Tags.LOGIC_ENDPOINT.set(span, Tags.VAL_LOCAL_SPAN_AS_LOGIC_ENDPOINT);
         span.tag(JOB_GROUP, jobGroup == null ? "" : jobGroup);
+        span.tag(JOB_NAME, jobName == null ? "" : jobName);
         span.tag(JOB_DATA_MAP, getJobDataMapString(jobDetail));
     }
 
diff --git a/apm-sniffer/optional-plugins/quartz-scheduler-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/quartz/define/JobRunShellInterceptorInstrumentation.java b/apm-sniffer/optional-plugins/quartz-scheduler-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/quartz/define/JobRunShellInterceptorInstrumentation.java
index 6cfad92..6a098df 100644
--- a/apm-sniffer/optional-plugins/quartz-scheduler-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/quartz/define/JobRunShellInterceptorInstrumentation.java
+++ b/apm-sniffer/optional-plugins/quartz-scheduler-2.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/quartz/define/JobRunShellInterceptorInstrumentation.java
@@ -26,22 +26,25 @@ import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInst
 import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
 
 import static net.bytebuddy.matcher.ElementMatchers.named;
-import static net.bytebuddy.matcher.ElementMatchers.isPublic;
 import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
 import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
+import static net.bytebuddy.matcher.ElementMatchers.isPublic;
+import static net.bytebuddy.matcher.ElementMatchers.isPrivate;
 import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
 
 /**
- * Enhance {@link org.quartz.core.JobRunShell} instance and intercept {@link org.quartz.core.JobRunShell#run()} method,
- * this method is a unified entrance of execute schedule job.
+ * Enhance {@link org.quartz.core.JobRunShell} instance and intercept {@link org.quartz.core.JobRunShell#run()},{@link org.quartz.core.JobRunShell#notifyJobListenersComplete(org.quartz.JobExecutionContext, org.quartz.JobExecutionException)} methods,
+ * this class is a unified entrance of execute schedule job.
  *
  * @see org.apache.skywalking.apm.plugin.quartz.JobRunShellConstructorInterceptor
  * @see org.apache.skywalking.apm.plugin.quartz.JobRunShellMethodInterceptor
+ * @see org.apache.skywalking.apm.plugin.quartz.JobExecuteStateMethodInterceptor
  */
 public class JobRunShellInterceptorInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
 
     public static final String CONSTRUCTOR_INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.quartz.JobRunShellConstructorInterceptor";
-    public static final String METHOD_INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.quartz.JobRunShellMethodInterceptor";
+    public static final String JOB_EXECUTE_METHOD_INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.quartz.JobRunShellMethodInterceptor";
+    public static final String JOB_EXECUTE_STATE_METHOD_INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.quartz.JobExecuteStateMethodInterceptor";
     public static final String ENHANC_CLASS = "org.quartz.core.JobRunShell";
 
     @Override
@@ -81,7 +84,26 @@ public class JobRunShellInterceptorInstrumentation extends ClassInstanceMethodsE
 
                     @Override
                     public String getMethodsInterceptor() {
-                        return METHOD_INTERCEPTOR_CLASS;
+                        return JOB_EXECUTE_METHOD_INTERCEPTOR_CLASS;
+                    }
+
+                    @Override
+                    public boolean isOverrideArgs() {
+                        return false;
+                    }
+                },
+                new InstanceMethodsInterceptPoint() {
+                    @Override
+                    public ElementMatcher<MethodDescription> getMethodsMatcher() {
+                        return named("notifyJobListenersComplete")
+                                .and(isPrivate())
+                                .and(takesArguments(2))
+                                .and(takesArgument(1, named("org.quartz.JobExecutionException")));
+                    }
+
+                    @Override
+                    public String getMethodsInterceptor() {
+                        return JOB_EXECUTE_STATE_METHOD_INTERCEPTOR_CLASS;
                     }
 
                     @Override
diff --git a/docs/en/setup/service-agent/java-agent/README.md b/docs/en/setup/service-agent/java-agent/README.md
index 144fee3..db886c5 100755
--- a/docs/en/setup/service-agent/java-agent/README.md
+++ b/docs/en/setup/service-agent/java-agent/README.md
@@ -192,7 +192,7 @@ The following logic endpoints are added automatically by plugins.
 1. Spring's ScheduledMethodRunnable jobs are logic endpoints. The name format is `SpringScheduled`/`${className}`/`${methodName}`.
 1. Apache ShardingSphere ElasticJob's jobs are logic endpoints. The name format is `ElasticJob`/`${jobName}`.
 1. XXLJob's jobs are logic endpoints. The name formats include `xxl-job`/`MethodJob`/`${className}`.`${methodName}`, `xxl-job`/`ScriptJob`/`${GlueType}`/`id`/`${jobId}`, and `xxl-job`/`SimpleJob`/`${className}`.
-1. Quartz(optional plugin)'s jobs are logic endpoints. the name format is `quartz-scheduler`/`${jobName}`.
+1. Quartz(optional plugin)'s jobs are logic endpoints. the name format is `quartz-scheduler`/`${className}`.
 
 User could use the SkyWalking's application toolkits to add the tag into the local span to label the span as a logic endpoint in the analysis stage.
 The tag is, key=`x-le` and value = `{"logic-span":true}`.
diff --git a/test/plugin/scenarios/quartz-scheduler-2.x-scenario/config/expectedData.yaml b/test/plugin/scenarios/quartz-scheduler-2.x-scenario/config/expectedData.yaml
index ae649d7..7deb74c 100644
--- a/test/plugin/scenarios/quartz-scheduler-2.x-scenario/config/expectedData.yaml
+++ b/test/plugin/scenarios/quartz-scheduler-2.x-scenario/config/expectedData.yaml
@@ -35,7 +35,7 @@ segmentItems:
       - {key: url, value: 'http://localhost:8080/quartz-scheduler-2.x-scenario/case/call'}
       - {key: http.method, value: GET}
       refs:
-      - {parentEndpoint: quartz-scheduler/DemoJob, networkAddress: 'localhost:8080', refType: CrossProcess, parentSpanId: 1, parentTraceSegmentId: not null, parentServiceInstance: not null, parentService: not null, traceId: not null}
+      - {parentEndpoint: quartz-scheduler/org.apache.skywalking.apm.testcase.quartzscheduler.job.DemoJob, networkAddress: 'localhost:8080', refType: CrossProcess, parentSpanId: 1, parentTraceSegmentId: not null, parentServiceInstance: not null, parentService: not null, traceId: not null}
   - segmentId: not null
     spans:
     - operationName: /quartz-scheduler-2.x-scenario/case/call
@@ -53,7 +53,7 @@ segmentItems:
       tags:
       - {key: http.method, value: GET}
       - {key: url, value: 'http://localhost:8080/quartz-scheduler-2.x-scenario/case/call'}
-    - operationName: quartz-scheduler/DemoJob
+    - operationName: quartz-scheduler/org.apache.skywalking.apm.testcase.quartzscheduler.job.DemoJob
       operationId: 0
       parentSpanId: -1
       spanId: 0
@@ -68,4 +68,30 @@ segmentItems:
       tags:
       - {key: x-le, value: '{"logic-span":true}'}
       - {key: jobGroup, value: 'DemoJobGroup'}
-      - {key: jobDataMap, value: '{param1=test}'}
\ No newline at end of file
+      - {key: jobName, value: 'DemoJob'}
+      - {key: jobDataMap, value: '{param1=test}'}
+  - segmentId: not null
+    spans:
+    - operationName: quartz-scheduler/org.apache.skywalking.apm.testcase.quartzscheduler.job.ExceptionJob
+      operationId: 0
+      parentSpanId: -1
+      spanId: 0
+      spanLayer: Unknown
+      startTime: not null
+      endTime: not null
+      componentId: 97
+      isError: true
+      spanType: Local
+      peer: ''
+      skipAnalysis: false
+      tags:
+      - {key: x-le, value: '{"logic-span":true}'}
+      - {key: jobGroup, value: 'ExceptionJobGroup'}
+      - {key: jobName, value: 'ExceptionJob'}
+      - {key: jobDataMap, value: '{param1=test}'}
+      logs:
+      - logEvent:
+        - {key: event, value: error}
+        - {key: error.kind, value: org.quartz.JobExecutionException}
+        - {key: message, value: not null}
+        - {key: stack, value: not null}
\ No newline at end of file
diff --git a/test/plugin/scenarios/quartz-scheduler-2.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/quartzscheduler/job/ExceptionJob.java b/test/plugin/scenarios/quartz-scheduler-2.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/quartzscheduler/job/ExceptionJob.java
new file mode 100644
index 0000000..6cb29c3
--- /dev/null
+++ b/test/plugin/scenarios/quartz-scheduler-2.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/quartzscheduler/job/ExceptionJob.java
@@ -0,0 +1,32 @@
+/*
+ * 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.testcase.quartzscheduler.job;
+
+import lombok.extern.slf4j.Slf4j;
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+
+@Slf4j
+public class ExceptionJob implements Job {
+
+    @Override
+    public void execute(JobExecutionContext jobExecutionContext) {
+        throw new RuntimeException("execute job exception");
+    }
+}
diff --git a/test/plugin/scenarios/quartz-scheduler-2.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/quartzscheduler/job/QuartzConfig.java b/test/plugin/scenarios/quartz-scheduler-2.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/quartzscheduler/job/QuartzConfig.java
index e4d2e48..4ca979e 100644
--- a/test/plugin/scenarios/quartz-scheduler-2.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/quartzscheduler/job/QuartzConfig.java
+++ b/test/plugin/scenarios/quartz-scheduler-2.x-scenario/src/main/java/org/apache/skywalking/apm/testcase/quartzscheduler/job/QuartzConfig.java
@@ -38,12 +38,15 @@ public class QuartzConfig {
         Map.Entry<JobDetail, Trigger> demoJobConfig = demoJobConfig();
         scheduler.scheduleJob(demoJobConfig.getKey(), demoJobConfig.getValue());
 
+        Map.Entry<JobDetail, Trigger> exceptionJobConfig = exceptionJobConfig();
+        scheduler.scheduleJob(exceptionJobConfig.getKey(), exceptionJobConfig.getValue());
+
         return scheduler;
     }
 
     private Map.Entry<JobDetail, Trigger> demoJobConfig() throws ParseException {
         JobDetail demoJobDetail = JobBuilder.newJob(DemoJob.class)
-                .withIdentity("DemoJob","DemoJobGroup")
+                .withIdentity("DemoJob", "DemoJobGroup")
                 .usingJobData("param1", "test")
                 .storeDurably()
                 .build();
@@ -56,4 +59,20 @@ public class QuartzConfig {
 
         return new AbstractMap.SimpleEntry(demoJobDetail, demoJobTrigger);
     }
+
+    private Map.Entry<JobDetail, Trigger> exceptionJobConfig() throws ParseException {
+        JobDetail exceptionJobDetail = JobBuilder.newJob(ExceptionJob.class)
+                .withIdentity("ExceptionJob", "ExceptionJobGroup")
+                .usingJobData("param1", "test")
+                .storeDurably()
+                .build();
+
+        Trigger exceptionJobTrigger = TriggerBuilder.newTrigger()
+                .forJob(exceptionJobDetail)
+                .startNow()
+                .withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * * * ?"))
+                .build();
+
+        return new AbstractMap.SimpleEntry(exceptionJobDetail, exceptionJobTrigger);
+    }
 }
\ No newline at end of file