Subversion Repositories SmartDukaan

Rev

Rev 34563 | Rev 34578 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 34563 Rev 34567
Line 1... Line 1...
1
package com.smartdukaan.cron.monitored;
1
package com.smartdukaan.cron.monitored;
2
 
2
 
3
import java.util.Date;
3
import java.util.Date;
4
import java.util.Map;
4
import java.util.Map;
5
import java.util.concurrent.ConcurrentHashMap;
5
import java.util.concurrent.ConcurrentHashMap;
6
import java.util.concurrent.TimeUnit;
6
import java.util.concurrent.ConcurrentMap;
-
 
7
import java.util.concurrent.atomic.AtomicInteger;
7
 
8
 
8
import io.micrometer.core.instrument.Counter;
9
import io.micrometer.core.instrument.Counter;
-
 
10
import io.micrometer.core.instrument.Gauge;
-
 
11
import io.micrometer.core.instrument.Timer;
9
import org.aspectj.lang.ProceedingJoinPoint;
12
import org.aspectj.lang.ProceedingJoinPoint;
10
import org.aspectj.lang.annotation.Around;
13
import org.aspectj.lang.annotation.Around;
11
import org.aspectj.lang.annotation.Aspect;
14
import org.aspectj.lang.annotation.Aspect;
12
import org.springframework.beans.factory.annotation.Autowired;
15
import org.springframework.beans.factory.annotation.Autowired;
13
import org.springframework.stereotype.Component;
16
import org.springframework.stereotype.Component;
14
 
17
 
15
import io.micrometer.core.instrument.MeterRegistry;
18
import io.micrometer.core.instrument.MeterRegistry;
16
import org.slf4j.Logger;
19
import org.slf4j.Logger;
17
import org.slf4j.LoggerFactory;
20
import org.slf4j.LoggerFactory;
18
 
21
 
19
/**
-
 
20
 * Aspect to monitor execution of cron jobs via metrics and logging.
-
 
21
 */
-
 
22
@Aspect
22
@Aspect
23
@Component
23
@Component
24
public class CronJobMonitorAspect {
24
public class CronJobMonitorAspect {
25
 
25
 
26
    private static final Logger log = LoggerFactory.getLogger(CronJobMonitorAspect.class);
26
    private static final Logger log = LoggerFactory.getLogger(CronJobMonitorAspect.class);
27
 
27
 
28
    @Autowired
28
    @Autowired
29
    private MeterRegistry meterRegistry;
29
    private MeterRegistry meterRegistry;
30
 
30
 
31
    private final Map<String, Counter> failureCounters = new ConcurrentHashMap<>();
31
    private final ConcurrentMap<String, AtomicInteger> lastStatus = new ConcurrentHashMap<>();
32
 
32
 
33
 
-
 
34
    /**
-
 
35
     * Intercept any method annotated with @Scheduled (i.e. cron jobs).
-
 
36
     */
-
 
37
    @Around("@annotation(org.springframework.scheduling.annotation.Scheduled)")
33
    @Around("@annotation(org.springframework.scheduling.annotation.Scheduled)")
38
    public Object monitorCronJob(ProceedingJoinPoint joinPoint) throws Throwable {
34
    public Object monitorCronJob(ProceedingJoinPoint joinPoint) throws Throwable {
39
        String methodName = joinPoint.getSignature().toShortString();
35
        String methodName = joinPoint.getSignature().getName();
40
        log.info("Cron job {} started", methodName);
-
 
41
        long startTime = System.currentTimeMillis();
-
 
42
 
-
 
43
        try {
-
 
44
            // Proceed with the scheduled method
-
 
45
            Object result = joinPoint.proceed();
-
 
46
            long elapsed = System.currentTimeMillis() - startTime;
-
 
47
 
36
 
-
 
37
        lastStatus.computeIfAbsent(methodName, m -> {
-
 
38
            AtomicInteger gauge = new AtomicInteger(0);
48
            log.info("Cron job {} completed successfully in {} ms", methodName, elapsed);
39
            Gauge.builder("cron_job_last_status", gauge, AtomicInteger::get)
-
 
40
                    .description("1=success, 0=failure")
-
 
41
                    .tag("method", m)
-
 
42
                    .register(meterRegistry);
-
 
43
            return gauge;
-
 
44
        });
49
 
45
 
50
            try {
-
 
51
                meterRegistry.counter("custom.cron.success.count", "method", methodName, "status", "success")
-
 
52
                        .increment();
-
 
53
                meterRegistry.timer("custom.cron.execution.time", "method", methodName, "status", "success")
-
 
54
                        .record(elapsed, TimeUnit.MILLISECONDS);
-
 
55
            } catch (Exception e) {
46
        boolean success = false;
56
                log.warn("Failed to update success metrics for {}: {}", methodName, e.toString());
-
 
57
            }
-
 
58
 
47
 
-
 
48
        // Start a timer sample
-
 
49
        Timer.Sample sample = Timer.start(meterRegistry);
-
 
50
        try {
-
 
51
            Object result = joinPoint.proceed();
-
 
52
            success = true;
-
 
53
            // Record a success count
-
 
54
            meterRegistry.counter("cron_job_count_total", "method", methodName, "status", "success").increment();
59
            return result;
55
            return result;
60
        } catch (Throwable ex) {
56
        } catch (Throwable t) {
61
            long elapsed = System.currentTimeMillis() - startTime;
57
            String exceptionName = t.getClass().getSimpleName();
62
            log.error("Cron job {} failed in {} ms: {}", methodName, elapsed, ex.toString());
58
            // Record a failure count with exception type
63
 
-
 
64
            try {
59
            meterRegistry.counter(
65
                meterRegistry.counter("custom.cron.failure.count", "method", methodName, "status", "failure")
60
                    "cron_job_count_total", "method", methodName, "status", "failure", "exception", exceptionName).increment();
66
                        .increment();
61
            throw t;
67
                meterRegistry.timer("custom.cron.execution.time", "method", methodName, "status", "failure")
-
 
68
                        .record(elapsed, TimeUnit.MILLISECONDS);
-
 
69
            } catch (Exception e) {
62
        } finally {
70
                log.warn("Failed to update failure metrics for {}: {}", methodName, e.toString());
63
            sample.stop(Timer.builder("cron_job_duration_seconds")
71
            }
64
                    .tag("method", methodName)
72
            getFailureCounter(methodName).increment();
65
                    .register(meterRegistry));
73
            throw ex;
66
            lastStatus.get(methodName).set(success ? 1 : 0);
-
 
67
 
74
        }
68
        }
75
    }
69
    }
76
 
70
 
77
    private Counter getFailureCounter(String methodName) {
-
 
78
        return failureCounters.computeIfAbsent(methodName, name ->
-
 
79
                Counter.builder("cron_execution_failure_count_total")
-
 
80
                        .description("Number of failed executions of scheduled method")
-
 
81
                        .tag("method", name)
-
 
82
                        .register(meterRegistry)
-
 
83
        );
-
 
84
    }
-
 
85
}
71
}