package de.codecentric.batch.metrics;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.boot.actuate.metrics.GaugeService;
import org.springframework.util.ClassUtils;
import org.springframework.util.StopWatch;

import de.codecentric.batch.listener.LoggingListener;

/**
 * Central aspect-configuration to profile Spring Batch Jobs with AspectJ and Spring Boot Metrics.
 * 
 * @author Dennis Schulte
 */
@Aspect
public class BatchMetricsAspects {

	private static final Logger LOG = LoggerFactory.getLogger(BatchMetricsAspects.class);

	private GaugeService gaugeService;

	public BatchMetricsAspects(GaugeService gaugeService) {
		this.gaugeService = gaugeService;
	}
	
	@Around("execution(* org.springframework.batch.core.step.item.ChunkOrientedTasklet.execute(..))")
	public Object profileChunk(ProceedingJoinPoint pjp) throws Throwable {
		StopWatch stopWatch = startStopWatch();
		try {
			return pjp.proceed();
		} finally {
			gaugeService.submit(MetricsListener.GAUGE_PREFIX + getJobIdentifier() + "." + ClassUtils.getShortName(pjp.getTarget().getClass())+ ".execute",
					getTotalTimeMillis(stopWatch));
		}
	}

	@Around("execution(* org.springframework.batch.item.ItemReader.read(..))")
	public Object profileReadMethods(ProceedingJoinPoint pjp) throws Throwable {
		StopWatch stopWatch = startStopWatch();
		try {
			return pjp.proceed();
		} finally {
			gaugeService.submit(MetricsListener.GAUGE_PREFIX + getJobIdentifier() + "." + ClassUtils.getShortName(pjp.getTarget().getClass())+ ".read",
					getTotalTimeMillis(stopWatch));
		}
	}

	@Around("execution(* org.springframework.batch.item.ItemProcessor.process(..))")
	public Object profileProcessMethods(ProceedingJoinPoint pjp) throws Throwable {
		StopWatch stopWatch = startStopWatch();
		try {
			return pjp.proceed();
		} finally {
			gaugeService.submit(MetricsListener.GAUGE_PREFIX + getJobIdentifier() + "." + ClassUtils.getShortName(pjp.getTarget().getClass())+ ".process",
					getTotalTimeMillis(stopWatch));
		}
	}

	@Around("execution(* org.springframework.batch.item.ItemWriter.write(..))")
	public Object profileWriteMethods(ProceedingJoinPoint pjp) throws Throwable {
		StopWatch stopWatch = startStopWatch();
		try {
			return pjp.proceed();
		} finally {
			gaugeService.submit(MetricsListener.GAUGE_PREFIX + getJobIdentifier() + "." + ClassUtils.getShortName(pjp.getTarget().getClass())+ ".write",
					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 getJobIdentifier() {
		String jobName = MDC.get(LoggingListener.JOB_EXECUTION_IDENTIFIER);
		if (jobName == null) {
			LOG.warn("Jobname could not be read from MDC.");
			jobName = "unknown";
		}
		return jobName;
	}
}
@@ -881,471 +881,8 @@
 %0A%09%7D%0D
-%0A%09%0D%0A%09@Around(%22execution(* org.springframework.batch.core.step.item.ChunkOrientedTasklet.execute(..))%22)%0D%0A%09public Object profileChunk(ProceedingJoinPoint pjp) throws Throwable %7B%0D%0A%09%09StopWatch stopWatch = startStopWatch();%0D%0A%09%09try %7B%0D%0A%09%09%09return pjp.proceed();%0D%0A%09%09%7D finally %7B%0D%0A%09%09%09gaugeService.submit(MetricsListener.GAUGE_PREFIX + getJobIdentifier() + %22.%22 + ClassUtils.getShortName(pjp.getTarget().getClass())+ %22.execute%22,%0D%0A%09%09%09%09%09getTotalTimeMillis(stopWatch));%0D%0A%09%09%7D%0D%0A%09%7D%0D
 %0A%0D%0A%09

Remove chunk aspect because it's not a bean.