de.codecentric.batch.metrics.AbstractBatchMetricsAspect.java Source code

Java tutorial

Introduction

Here is the source code for de.codecentric.batch.metrics.AbstractBatchMetricsAspect.java

Source

/*
 * Copyright 2014 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package de.codecentric.batch.metrics;

import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.scope.context.StepContext;
import org.springframework.batch.core.scope.context.StepSynchronizationManager;
import org.springframework.boot.actuate.metrics.GaugeService;
import org.springframework.util.ClassUtils;
import org.springframework.util.StopWatch;

/**
 * This is a helper class for implementing method level profiling. See {@link ReaderProcessorWriterMetricsAspect} for an
 * aspect extending this class. All calls to an adviced method are tracked in a RichGauge, so you'll see average duration time,
 * maximum / minimum time, number of method calls and so on. For the name of the metric a special naming scheme is used so that
 * our {@link MetricsListener} picks up the gauge and writes it to the ExecutionContext of the StepExecution and to the log.
 * 
 * Job configurations need to enable auto-proxying so that aspects may be applied. In JavaConfig just add
 * {@code @EnableAspectJAutoProxy(proxyTargetClass=true)} as a class level annotation. In xml add
 * {@code <aop:aspectj-autoproxy proxy-target-class="true"/>} to the xml configuration file. This needs to be done because jobs reside
 * in child application contexts and don't inherit this kind of configuration from the parent. proxyTargetClass=true means using
 * CGLIB as proxy mechanism which allows us to proxy classes without interfaces.
 * 
 * @author Tobias Flohre
 */
public abstract class AbstractBatchMetricsAspect {

    private GaugeService gaugeService;

    public static final String TIMER_PREFIX = "timer.batch.";

    public AbstractBatchMetricsAspect(GaugeService gaugeService) {
        this.gaugeService = gaugeService;
    }

    protected Object profileMethod(ProceedingJoinPoint pjp) throws Throwable {
        StopWatch stopWatch = startStopWatch();
        try {
            return pjp.proceed();
        } finally {
            gaugeService.submit(TIMER_PREFIX + getStepIdentifier() + "."
                    + ClassUtils.getShortName(pjp.getTarget().getClass()) + "." + pjp.getSignature().getName(),
                    getTotalTimeMillis(stopWatch));
        }
    }

    private long getTotalTimeMillis(StopWatch stopWatch) {
        stopWatch.stop();
        long duration = stopWatch.getTotalTimeMillis();
        return duration;
    }

    private StopWatch startStopWatch() {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        return stopWatch;
    }

    private String getStepIdentifier() {
        StepContext stepContext = StepSynchronizationManager.getContext();
        StepExecution stepExecution = StepSynchronizationManager.getContext().getStepExecution();
        return stepContext.getJobName() + "." + stepExecution.getStepName();
    }

}