简体   繁体   中英

How can I find which Quartz job a thread is running in java?

I am using a discriminator for logging in different file. Based on the thread name. It usually give good result, except for the quartz job that are all logger in file with name like:

org.springframework.scheduling.quartz.SchedulerFactoryBean#0_Worker-1.log

I would like to have a file that is the name of the quartz job (on something base on it) to be able to quickly find which file contains the logs for a job. Is there a way ask quartz if the current thread is associated with a job?

Thanks

Your approach implies you have to change code for all job classes (or inherit from base job class). However, there is alternative approach which is compatible with jobs whose code is not available for changing.

You can create job listener which changes thread name during execution (as at my example below) or sets MDC (as at your example) and register it via Scheduler.addJobListener() or configure via Spring.

public class RenameThreadWhenJobRunning extends JobListenerSupport {
    /**
     * Must provide two groups - for name and for number
     */
    private String parsingPattern = "^(.+)_Worker-(\\d+)$";

    /**
     * {0} - Original full name (e.q. XXX_Worker-NN)
     * {1} - XXX - original thread name
     * {2} - NN - original worker number
     * {3} - Job key (e.g. JobGroup.JobName)
     * {4} - Job group
     * {5} - Job name
     */
    private String format = "{5}-Qz{2}";

    public void setParsingPattern(String parsingPattern) {
        this.parsingPattern = parsingPattern;
    }

    public void setFormat(String format) {
        this.format = format;
    }

    @Override
    public String getName() {
        return RenameThreadWhenJobRunning.class.getSimpleName();
    }

    @Override
    public void jobToBeExecuted(JobExecutionContext context) {
        final String originalThreadName = currentThread().getName();
        final Matcher matcher = Pattern.compile(parsingPattern).matcher(originalThreadName);
        if (matcher.matches()) {
            final JobKey key = context.getJobDetail().getKey();
            currentThread().setName(format(format,
                originalThreadName,
                matcher.group(1),
                matcher.group(2),
                key.toString(),
                key.getGroup(),
                key.getName()
            ));
            context.put(getOriginalThreadNameContextParameter(), originalThreadName);
        }
    }

    @Override
    public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) {
        Object originalThreadName = context.get(getOriginalThreadNameContextParameter());
        if (originalThreadName instanceof String) {
            currentThread().setName((String)originalThreadName);
        }
    }

    String getOriginalThreadNameContextParameter() {
        return getName()+".originalThreadName";
    }

}

Alexander Pavlov's answer works for me (although I tweaked it to make it into a Groovy file). What was missing for me was the registration of the JobListener to the scheduler.

I registered a singleton instance of the Alexander's RenameThreadWhenJobRunning class as the bean 'renameThreadJobListener'. The 'quartzScheduler' bean already existed in my application context.

Since I'm using Grails, here is the block from my resources.groovy, which can be ported into an XML configuration or Annotation-based approach:

quartzSchedulerInitializer(QuartzSchedulerInitializer) { bean ->
    bean.dependsOn = ['quartzScheduler', 'renameThreadJobListener'] as String[]
    quartzScheduler = ref('quartzScheduler')
    renameThreadJobListener = ref('renameThreadJobListener')
}

renameThreadJobListener(RenameThreadWhenJobRunning)

Then I created the following Groovy class:

import org.quartz.impl.matchers.EverythingMatcher
import org.springframework.beans.factory.InitializingBean

/**
 * At application startup, register job listeners on the QuartzScheduler bean.
 */
class QuartzSchedulerInitializer implements InitializingBean {

    def quartzScheduler
    def renameThreadJobListener

    @Override
    void afterPropertiesSet() throws Exception {
        def matcher = EverythingMatcher.allJobs()
        quartzScheduler.listenerManager.addJobListener(renameThreadJobListener, matcher)
    }
}

Outcome is my Worker thread names now look like "com.example.MyJob-Qz1"!

Finally, I resolve it by manually indicating with slf4j MDC

at the beginning of the task, I do

try {
    MDC.put(MDC_KEY, getTaskName());

and at the end

    }
    finally {
        MDC.remove(MDC_KEY);
    }

So I just need to check the key in MDC to know if I am inside a task.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM