From 833611a450763af9b149adf4e68ef20ff35de63e Mon Sep 17 00:00:00 2001 From: Jerry Duffy Date: Wed, 6 Mar 2024 10:10:47 -0500 Subject: [PATCH] v4 and v5 spring batch modules --- instrumentation/spring-batch-4.0.0/README.md | 32 ++++++++++++++ .../spring-batch-4.0.0/build.gradle | 27 ++++++++++++ .../batch/core/Job_Instrumentation.java | 42 +++++++++++++++++++ .../batch/core/Step_Instrumentation.java | 26 ++++++++++++ .../item/ItemWriter_Instrumentation.java | 22 ++++++++++ instrumentation/spring-batch-5.0.0/README.md | 32 ++++++++++++++ .../spring-batch-5.0.0/build.gradle | 33 +++++++++++++++ .../batch/core/Job_Instrumentation.java | 42 +++++++++++++++++++ .../batch/core/Step_Instrumentation.java | 26 ++++++++++++ .../item/ItemWriter_Instrumentation.java | 23 ++++++++++ settings.gradle | 2 + 11 files changed, 307 insertions(+) create mode 100644 instrumentation/spring-batch-4.0.0/README.md create mode 100644 instrumentation/spring-batch-4.0.0/build.gradle create mode 100644 instrumentation/spring-batch-4.0.0/src/main/java/org/springframework/batch/core/Job_Instrumentation.java create mode 100644 instrumentation/spring-batch-4.0.0/src/main/java/org/springframework/batch/core/Step_Instrumentation.java create mode 100644 instrumentation/spring-batch-4.0.0/src/main/java/org/springframework/batch/item/ItemWriter_Instrumentation.java create mode 100644 instrumentation/spring-batch-5.0.0/README.md create mode 100644 instrumentation/spring-batch-5.0.0/build.gradle create mode 100644 instrumentation/spring-batch-5.0.0/src/main/java/org/springframework/batch/core/Job_Instrumentation.java create mode 100644 instrumentation/spring-batch-5.0.0/src/main/java/org/springframework/batch/core/Step_Instrumentation.java create mode 100644 instrumentation/spring-batch-5.0.0/src/main/java/org/springframework/batch/item/ItemWriter_Instrumentation.java diff --git a/instrumentation/spring-batch-4.0.0/README.md b/instrumentation/spring-batch-4.0.0/README.md new file mode 100644 index 0000000000..e14ff0229a --- /dev/null +++ b/instrumentation/spring-batch-4.0.0/README.md @@ -0,0 +1,32 @@ +# spring-batch-4.0.0 Instrumentation Module + +This module provides instrumentation for the Spring Batch 4 framework (up to, but not including version 5). + +Only single process, single threaded jobs are supported. Single process, multi-threaded and +multi-process jobs are not supported. + +### Details +The instrumentation will weave the following classes: + +- `org.springframework.batch.core.Job`: In Spring Batch, the Job class wraps the steps and processors that make a up a complete batch job implementation. +The execute() method will be the transaction dispatcher. The transaction name will be `OtherTransaction/SpringBatch/Job/{jobName}` + +- `org.springframework.batch.core.Step`: The Step class represents a single step of the target batch job. The execute() method will be instrumented in order +to track the total execution time of a job step. The timing of a Step task will include the time to read the data +from the defined data source, the processing of the data and the time to write the data to the target data source. + +- `org.springframework.batch.item.ItemWriter`: The ItemWriter class is used to write the processed/transformed items to a data store. There will be the same number +of ItemWriter segments as Step segments, since there is one write operation per Step. + +The ItemReader and ItemProcessor classes will not be instrumented since these are each called once per data item, +which would cause the Transaction traces to be inflated unnecessarily. The timings for these calls are included +in the Step instrumentation timing. + +### Metrics +The following metrics will be reported: + +- `SpringBatch/Job/{jobName}/Step/{stepName}/read` +- `SpringBatch/Job/{jobName}/Step/{stepName}/write` +- `SpringBatch/Job/{jobName}/Step/{stepName}/skipped` + +These metrics represent the total number of items read, written and skipped for a particular step for a completed job. diff --git a/instrumentation/spring-batch-4.0.0/build.gradle b/instrumentation/spring-batch-4.0.0/build.gradle new file mode 100644 index 0000000000..b28ae34549 --- /dev/null +++ b/instrumentation/spring-batch-4.0.0/build.gradle @@ -0,0 +1,27 @@ +plugins { + id "org.jetbrains.kotlin.jvm" +} + +dependencies { + implementation(project(":agent-bridge")) + implementation("org.springframework.batch:spring-batch-core:4.0.0.RELEASE") + implementation("org.springframework.batch:spring-batch-infrastructure:4.0.0.RELEASE") + testImplementation("org.jetbrains.kotlin:kotlin-stdlib:1.8.21") +} + +jar { + manifest { attributes 'Implementation-Title': 'com.newrelic.instrumentation.spring-batch-4.0.0', + 'Implementation-Title-Alias': 'spring_batch' } +} + +verifyInstrumentation { + passesOnly 'org.springframework.batch:spring-batch-core:[4.0.0.RELEASE,5.0.0.RELEASE)' + + excludeRegex 'org.springframework.batch:spring-batch-core:.*(RC|SEC|M)[0-9]*$' + exclude 'org.springframework.batch:spring-batch-core:[1.0.0.FINAL,4.0.0.RELEASE)' +} + +site { + title 'Spring' + type 'Framework' +} \ No newline at end of file diff --git a/instrumentation/spring-batch-4.0.0/src/main/java/org/springframework/batch/core/Job_Instrumentation.java b/instrumentation/spring-batch-4.0.0/src/main/java/org/springframework/batch/core/Job_Instrumentation.java new file mode 100644 index 0000000000..701b724d2e --- /dev/null +++ b/instrumentation/spring-batch-4.0.0/src/main/java/org/springframework/batch/core/Job_Instrumentation.java @@ -0,0 +1,42 @@ +/* + * + * * Copyright 2024 New Relic Corporation. All rights reserved. + * * SPDX-License-Identifier: Apache-2.0 + * + */ +package org.springframework.batch.core; + +import com.newrelic.agent.bridge.AgentBridge; +import com.newrelic.agent.bridge.Transaction; +import com.newrelic.agent.bridge.TransactionNamePriority; +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +@Weave(type = MatchType.Interface, originalName = "org.springframework.batch.core.Job") +public class Job_Instrumentation { + @Trace(dispatcher = true) + public void execute(JobExecution jobExecution) { + Weaver.callOriginal(); + + Transaction transaction = AgentBridge.getAgent().getTransaction(false); + if (transaction != null) { + String jobName = jobExecution.getJobInstance().getJobName(); + transaction.setTransactionName(TransactionNamePriority.FRAMEWORK_HIGH, false, "SpringBatch", "Job", jobName); + + String status = jobExecution.getExitStatus().getExitCode(); + if ("COMPLETED".equals(status) || "FAILED".equals(status)) { + NewRelic.incrementCounter("SpringBatch/Job/" + jobName + "/" + status); + } + + for (StepExecution stepExecution : jobExecution.getStepExecutions()) { + String metricName = "SpringBatch/Job/" + jobName + "/Step/" + stepExecution.getStepName(); + NewRelic.incrementCounter(metricName + "/read", stepExecution.getReadCount()); + NewRelic.incrementCounter(metricName + "/write", stepExecution.getWriteCount()); + NewRelic.incrementCounter(metricName + "/skip", stepExecution.getSkipCount()); + } + } + } +} diff --git a/instrumentation/spring-batch-4.0.0/src/main/java/org/springframework/batch/core/Step_Instrumentation.java b/instrumentation/spring-batch-4.0.0/src/main/java/org/springframework/batch/core/Step_Instrumentation.java new file mode 100644 index 0000000000..01b4dbfb90 --- /dev/null +++ b/instrumentation/spring-batch-4.0.0/src/main/java/org/springframework/batch/core/Step_Instrumentation.java @@ -0,0 +1,26 @@ +/* + * + * * Copyright 2024 New Relic Corporation. All rights reserved. + * * SPDX-License-Identifier: Apache-2.0 + * + */ +package org.springframework.batch.core; + +import com.newrelic.agent.bridge.AgentBridge; +import com.newrelic.agent.bridge.Transaction; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +@Weave(type = MatchType.Interface, originalName = "org.springframework.batch.core.Step") +public class Step_Instrumentation { + @Trace + public void execute(StepExecution stepExecution) throws JobInterruptedException { + Weaver.callOriginal(); + Transaction transaction = AgentBridge.getAgent().getTransaction(false); + if (transaction != null) { + transaction.getTracedMethod().setMetricName("SpringBatch", "Step", "execute", stepExecution.getStepName()); + } + } +} diff --git a/instrumentation/spring-batch-4.0.0/src/main/java/org/springframework/batch/item/ItemWriter_Instrumentation.java b/instrumentation/spring-batch-4.0.0/src/main/java/org/springframework/batch/item/ItemWriter_Instrumentation.java new file mode 100644 index 0000000000..d3913afbb0 --- /dev/null +++ b/instrumentation/spring-batch-4.0.0/src/main/java/org/springframework/batch/item/ItemWriter_Instrumentation.java @@ -0,0 +1,22 @@ +/* + * + * * Copyright 2024 New Relic Corporation. All rights reserved. + * * SPDX-License-Identifier: Apache-2.0 + * + */ +package org.springframework.batch.item; + +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +import java.util.List; + +@Weave(type = MatchType.Interface, originalName = "org.springframework.batch.item.ItemWriter") +public class ItemWriter_Instrumentation { + @Trace + public void write(List items) throws Exception { + Weaver.callOriginal(); + } +} diff --git a/instrumentation/spring-batch-5.0.0/README.md b/instrumentation/spring-batch-5.0.0/README.md new file mode 100644 index 0000000000..d88448130e --- /dev/null +++ b/instrumentation/spring-batch-5.0.0/README.md @@ -0,0 +1,32 @@ +# spring-batch-5.0.0 Instrumentation Module + +This module provides instrumentation for the Spring Batch v5 framework. + +Only single process, single threaded jobs are supported. Single process, multi-threaded and +multi-process jobs are not supported. + +### Details +The instrumentation will weave the following classes: + +- `org.springframework.batch.core.Job`: In Spring Batch, the Job class wraps the steps and processors that make a up a complete batch job implementation. +The execute() method will be the transaction dispatcher. The transaction name will be `OtherTransaction/SpringBatch/Job/{jobName}` + +- `org.springframework.batch.core.Step`: The Step class represents a single step of the target batch job. The execute() method will be instrumented in order +to track the total execution time of a job step. The timing of a Step task will include the time to read the data +from the defined data source, the processing of the data and the time to write the data to the target data source. + +- `org.springframework.batch.item.ItemWriter`: The ItemWriter class is used to write the processed/transformed items to a data store. There will be the same number +of ItemWriter segments as Step segments, since there is one write operation per Step. + +The ItemReader and ItemProcessor classes will not be instrumented since these are each called once per data item, +which would cause the Transaction traces to be inflated unnecessarily. The timings for these calls are included +in the Step instrumentation timing. + +### Metrics +The following metrics will be reported: + +- `SpringBatch/Job/{jobName}/Step/{stepName}/read` +- `SpringBatch/Job/{jobName}/Step/{stepName}/write` +- `SpringBatch/Job/{jobName}/Step/{stepName}/skipped` + +These metrics represent the total number of items read, written and skipped for a particular step for a completed job. diff --git a/instrumentation/spring-batch-5.0.0/build.gradle b/instrumentation/spring-batch-5.0.0/build.gradle new file mode 100644 index 0000000000..7b47264b15 --- /dev/null +++ b/instrumentation/spring-batch-5.0.0/build.gradle @@ -0,0 +1,33 @@ +plugins { + id "org.jetbrains.kotlin.jvm" +} + +dependencies { + implementation(project(":agent-bridge")) + implementation("org.springframework.batch:spring-batch-core:5.0.0") + implementation("org.springframework.batch:spring-batch-infrastructure:5.0.0") + testImplementation("org.jetbrains.kotlin:kotlin-stdlib:1.8.21") +} + +jar { + manifest { attributes 'Implementation-Title': 'com.newrelic.instrumentation.spring-batch-5.0.0', + 'Implementation-Title-Alias': 'spring_batch' } +} + +verifyInstrumentation { + passesOnly 'org.springframework.batch:spring-batch-core:[5.0.0,)' + + excludeRegex 'org.springframework.batch:spring-batch-core:.*(RC|SEC|M)[0-9]*$' + exclude 'org.springframework.batch:spring-batch-core:[1.0.0.FINAL,4.0.0.RELEASE)' +} + +site { + title 'Spring' + type 'Framework' +} + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(17)) + } +} \ No newline at end of file diff --git a/instrumentation/spring-batch-5.0.0/src/main/java/org/springframework/batch/core/Job_Instrumentation.java b/instrumentation/spring-batch-5.0.0/src/main/java/org/springframework/batch/core/Job_Instrumentation.java new file mode 100644 index 0000000000..28e39a82a3 --- /dev/null +++ b/instrumentation/spring-batch-5.0.0/src/main/java/org/springframework/batch/core/Job_Instrumentation.java @@ -0,0 +1,42 @@ +/* + * + * * Copyright 2024 New Relic Corporation. All rights reserved. + * * SPDX-License-Identifier: Apache-2.0 + * + */ +package org.springframework.batch.core; + +import com.newrelic.agent.bridge.AgentBridge; +import com.newrelic.agent.bridge.Transaction; +import com.newrelic.agent.bridge.TransactionNamePriority; +import com.newrelic.api.agent.NewRelic; +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +@Weave(type = MatchType.Interface, originalName = "org.springframework.batch.core.Job") +public class Job_Instrumentation { + @Trace(dispatcher = true) + public void execute(JobExecution jobExecution) { + Weaver.callOriginal(); + + Transaction transaction = AgentBridge.getAgent().getTransaction(false); + if (transaction != null) { + String jobName = jobExecution.getJobInstance().getJobName(); + transaction.setTransactionName(TransactionNamePriority.FRAMEWORK_HIGH, false, "SpringBatch", "Job", jobName); + + String status = jobExecution.getExitStatus().getExitCode(); + if ("COMPLETED".equals(status) || "FAILED".equals(status)) { + NewRelic.incrementCounter("SpringBatch/Job/" + jobName + "/" + status); + } + + for (StepExecution stepExecution : jobExecution.getStepExecutions()) { + String metricName = "SpringBatch/Job/" + jobName + "/Step/" + stepExecution.getStepName(); + NewRelic.incrementCounter(metricName + "/read", (int)stepExecution.getReadCount()); + NewRelic.incrementCounter(metricName + "/write", (int)stepExecution.getWriteCount()); + NewRelic.incrementCounter(metricName + "/skip", (int)stepExecution.getSkipCount()); + } + } + } +} diff --git a/instrumentation/spring-batch-5.0.0/src/main/java/org/springframework/batch/core/Step_Instrumentation.java b/instrumentation/spring-batch-5.0.0/src/main/java/org/springframework/batch/core/Step_Instrumentation.java new file mode 100644 index 0000000000..01b4dbfb90 --- /dev/null +++ b/instrumentation/spring-batch-5.0.0/src/main/java/org/springframework/batch/core/Step_Instrumentation.java @@ -0,0 +1,26 @@ +/* + * + * * Copyright 2024 New Relic Corporation. All rights reserved. + * * SPDX-License-Identifier: Apache-2.0 + * + */ +package org.springframework.batch.core; + +import com.newrelic.agent.bridge.AgentBridge; +import com.newrelic.agent.bridge.Transaction; +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; + +@Weave(type = MatchType.Interface, originalName = "org.springframework.batch.core.Step") +public class Step_Instrumentation { + @Trace + public void execute(StepExecution stepExecution) throws JobInterruptedException { + Weaver.callOriginal(); + Transaction transaction = AgentBridge.getAgent().getTransaction(false); + if (transaction != null) { + transaction.getTracedMethod().setMetricName("SpringBatch", "Step", "execute", stepExecution.getStepName()); + } + } +} diff --git a/instrumentation/spring-batch-5.0.0/src/main/java/org/springframework/batch/item/ItemWriter_Instrumentation.java b/instrumentation/spring-batch-5.0.0/src/main/java/org/springframework/batch/item/ItemWriter_Instrumentation.java new file mode 100644 index 0000000000..a33db4245d --- /dev/null +++ b/instrumentation/spring-batch-5.0.0/src/main/java/org/springframework/batch/item/ItemWriter_Instrumentation.java @@ -0,0 +1,23 @@ +/* + * + * * Copyright 2024 New Relic Corporation. All rights reserved. + * * SPDX-License-Identifier: Apache-2.0 + * + */ +package org.springframework.batch.item; + +import com.newrelic.api.agent.weaver.MatchType; +import com.newrelic.api.agent.Trace; +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import org.springframework.lang.NonNull; + +import java.util.List; + +@Weave(type = MatchType.Interface, originalName = "org.springframework.batch.item.ItemWriter") +public class ItemWriter_Instrumentation { + @Trace + public void write(@NonNull Chunk chunk) throws Exception { + Weaver.callOriginal(); + } +} diff --git a/settings.gradle b/settings.gradle index 1250c5e486..a3cdeb8915 100644 --- a/settings.gradle +++ b/settings.gradle @@ -334,6 +334,8 @@ include 'instrumentation:spring-4.2.0' include 'instrumentation:spring-4.3.0' include 'instrumentation:spring-6.0.0' include 'instrumentation:spring-aop-2' +include 'instrumentation:spring-batch-4.0.0' +include 'instrumentation:spring-batch-5.0.0' include 'instrumentation:spring-cache-3.1.0' include 'instrumentation:spring-jms-2' include 'instrumentation:spring-jms-3'