elastic / elastic/apm-agent-java

Quartz job instrumentation - distributed tracing pass through JobDataMap

Aperta
#3,050 6 commenti 1 reazione 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

agent-java community enhancement
Lingua principale
Java
Stelle
593
Fork
337
Merge medio
1g 13h
PR unite (30g)
25

Descrizione

Is your feature request related to a problem?

We have some Quartz jobs immediately triggered by user requests. Both (job and user request) create transaction in APM, with no link between them: user request appears in "request" transactions, Quartz job appears in "scheduled" transaction, as per design I guess.
We would like to keep trace between user request and the triggered job (when jobs are immediately triggered, maybe not when they're scheduled).

Describe the solution you'd like

I think Quartz Job APM plugin could retrieve headers from JobDetailMap if any, thus keeping trace between parent and child transactions.

It could be done there:

https://github.com/elastic/apm-agent-java/blob/9c4e9351dd39b4413b2fb4990a73d91674201838/apm-agent-plugins/apm-quartz-job-plugin/quartz-common/src/main/java/co/elastic/apm/agent/quartzjob/AbstractJobTransactionNameInstrumentation.java#L117

We could start a child transaction with few modifications:

AbstractJobTransactionNameInstrumentation line 84:

if (transactionName != null) {
    transaction = createAndActivateTransaction(clazz, transactionName, jobExecutionContext, helper);
} else {
    logger.warn("Cannot correctly name transaction for method {} because JobExecutionContext is null or lacking job details", signature);
    transaction = createAndActivateTransaction(clazz, signature, jobExecutionContext, helper);
}

AbstractJobTransactionNameInstrumentation.java line 115:

@Nullable
private static <T> Transaction createAndActivateTransaction(Class<?> originClass, String name, T jobExecutionContext, JobExecutionContextHandler<T> helper) {
    Transaction transaction = GlobalTracer.get().startChildTransaction(helper.getJobDataMap(jobExecutionContext), key -> dataMap.getString(key), PrivilegedActionUtils.getClassLoader(originClass));
// ....

Add getJobDataMap to https://github.com/elastic/apm-agent-java/blob/main/apm-agent-plugins/apm-quartz-job-plugin/quartz-common/src/main/java/co/elastic/apm/agent/quartzjob/JobExecutionContextHandler.java:

@Nullable
JobDataMap getJobDataMap(T jobExecutionContext);

Describe alternatives you've considered

I've considered implementing it with APM Agent API like this:

Job scheduling:

Span span = ElasticApm.currentSpan();
if (span != null) {
  span.injectTraceHeaders((name, value) -> jobDetail.getJobDataMap().put(name, value));
}
/*
 this.scheduler.scheduleJob(jobDetail, trigger);
*/

Job execution:

Transaction transaction = ElasticApm.startTransactionWithRemoteParent((key) -> jobExecutionContext.getJobDetail().getJobDataMap().getString(key));
try (final Scope scope = transaction.activate()) {
  customRunJob(jobExecutionContext);
} catch (Exception e) {
  transaction.captureException(e);
  throw e;
} finally {
  transaction.end();
}

It does create a transaction, but interrupt transaction created by apm-quartz-job-plugin. I lose some spans (executed before I start the transaction), which appear in the plugin transaction. I think implementing distributed tracing between executor and job execution at plugin level would be more accurate.

Additional context

Guida per i contributori

Apri la guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Direzione di ricerca

Inizia con AbstractJobTransactionNameInstrumentation.java intorno alle righe 84 e 115, quindi esamina JobExecutionContextHandler.java. Traccia come viene ottenuto JobDataMap per l’esecuzione dei job Quartz e come viene creata la transazione esistente. Il lavoro è completato quando il plugin può usare gli header di trace da JobDetailMap per preservare il collegamento della transazione padre-figlio senza creare una seconda transazione o perdere gli span esistenti.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Valutazione

Stack tecnologico
java
Ambito
observability
Tipo di issue
Funzionalità
Difficoltà
4/5
Tempo stimato
3-5 giorni
Stato di attività
Ferma
Chiarezza
Abbastanza chiara
Idoneità per principianti
45/100

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.