When I switch to Spring Boot 3.x + Micrometer, the quartz jobs Observability stop working.
Here is a simple example, how my Job looks like:
import org.quartz.DisallowConcurrentExecution;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
@DisallowConcurrentExecution
public class QueueJob implements Job {
private final QueueService queueService;
@Override
public void execute(JobExecutionContext context) {
queueService.fetchAndSaveQueues();
}
}
There was TracingJobListener.java in Spring Sleuth. According to this class I have written my own:
import io.micrometer.tracing.Span;
import io.micrometer.tracing.Tracer;
import io.micrometer.tracing.propagation.Propagator;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobListener;
import org.quartz.Trigger;
import org.quartz.Trigger.CompletedExecutionInstruction;
import org.quartz.TriggerListener;
public class TracingJobListener implements JobListener, TriggerListener {
static final String TRIGGER_TAG_KEY = "quartz.trigger";
static final String CONTEXT_SPAN_KEY = Span.class.getName();
static final String CONTEXT_SPAN_IN_SCOPE_KEY = Tracer.SpanInScope.class.getName();
private static final Propagator.Getter<JobDataMap> GETTER = (carrier, key) -> {
Object value = carrier.get(key);
if (value instanceof String) {
return (String) value;
}
return null;
};
private final Tracer tracer;
private final Propagator propagator;
public TracingJobListener(Tracer tracer, Propagator propagator) {
this.tracer = tracer;
this.propagator = propagator;
}
@Override
public String getName() {
return getClass().getName();
}
@Override
public void triggerFired(Trigger trigger, JobExecutionContext context) {
Span nextSpan = propagator.extract(context.getMergedJobDataMap(), GETTER).start();
Span span = nextSpan.name(context.getTrigger().getJobKey().toString()).tag(TRIGGER_TAG_KEY,
context.getTrigger().getKey().toString());
context.put(CONTEXT_SPAN_KEY, span);
context.put(CONTEXT_SPAN_IN_SCOPE_KEY, tracer.withSpan(span.start()));
}
@Override
public boolean vetoJobExecution(Trigger trigger, JobExecutionContext context) {
return false;
}
@Override
public void triggerMisfired(Trigger trigger) {
}
@Override
public void triggerComplete(Trigger trigger, JobExecutionContext context,
CompletedExecutionInstruction triggerInstructionCode) {
closeTrace(context);
}
@Override
public void jobToBeExecuted(JobExecutionContext context) {
}
@Override
public void jobExecutionVetoed(JobExecutionContext context) {
closeTrace(context);
}
@Override
public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) {
}
private void closeTrace(JobExecutionContext context) {
Object spanInScope = context.get(CONTEXT_SPAN_IN_SCOPE_KEY);
Object span = context.get(CONTEXT_SPAN_KEY);
if (spanInScope instanceof Tracer.SpanInScope) {
((Tracer.SpanInScope) spanInScope).close();
}
if (span instanceof Span) {
((Span) span).end();
}
}
}
@bclozel what do you think is it worth a PR or does somebody is working on a same thing yet?
Comment From: bclozel
@jmecsei I think this would be a generally useful addition for all quartz users, not just Spring Framework. In fact, the class you've shared doesn't have any dependency on Spring Framework.
I think this could be reworked to only depend on the Observation
API (so only the io.micrometer:micrometer-observation
module) and contributed to the quartz project. In my opinion, the right approach is to contribute the observability instrumentation as close as possible to the actual project, where the experts are.
What do you think?
Comment From: jmecsei
Yes I think so, it should be in the quartz project, but as I see the quartz's github pages it is fairly dead project. This is why I think we can put it to the Spring Framework, thus nobody miss functionality what is existed in previously.
Comment From: bclozel
Spring Framework's Quartz support is itself stale at the moment. I'm not sure we want to invest there given the situation. Let me discuss this with the team.
Comment From: bclozel
Declining for the reasons listed above.