Domanda

Sto lavorando ad un'applicazione che consiste in un programmatore generale basato su Quartz e " CycleJob " eseguito utilizzando CronTriggers. Lo scopo dell'applicazione è quello di elaborare input da diverse caselle di posta elettronica in base al paese di origine.

In base al Paese di provenienza (ad es. USA, Regno Unito, Francia, ecc.) l'applicazione attiva un thread di lavoro per eseguire il ciclo di elaborazione di ciascun Paese, quindi ci sarebbe un thread di lavoro nel Regno Unito, uno per Stati Uniti, Francia , ecc. Quando si formatta l'output su log4j, sto usando il parametro thread, quindi emette [ApplicationName_Worker-1], [ApplicationName_Worker-2] ecc. Prova come potrei, non riesco a trovare un modo per nominare i thread dal momento che sono stati estratti dai pool di thread di Quartz. Sebbene sia possibile arrivare al punto di estendere Quartz, mi piacerebbe trovare una soluzione diversa invece di fare casino con la libreria standard.

Ecco il problema: quando utilizzo log4j, vorrei avere tutti gli elementi di registro dall'output del thread USA in un file solo USA, allo stesso modo per ciascuno dei thread del paese. Non mi importa se rimangono in un ConsoleAppender unificato, la divisione FileAppender è ciò che sto cercando qui. So già come specificare più appendici di file e simili, il mio problema è che non riesco a differenziare in base al paese. Ci sono più di 20 classi all'interno dell'applicazione che possono trovarsi nella catena di esecuzione, pochissime delle quali voglio caricare con la conoscenza di passare un & Quot; contesto & Quot; parametro attraverso OGNI metodo ... Ho considerato un modello di strategia che estende una classe wrapper log4j, ma a meno che non sia in grado di far sapere a ogni classe della catena su quale thread si trova per parametrizzare la chiamata del logger, questo sembra impossibile. Senza essere in grado di nominare il thread crea anche una sfida (altrimenti sarebbe facile!).

Quindi, ecco la domanda: quale sarebbe un approccio suggerito per consentire a molte classi subordinate in un'applicazione che sono usate ciascuna per ogni thread diverso per elaborare l'input, sapere che si trovano nel contesto di un thread di un determinato paese durante la registrazione ?

Buona fortuna, e per favore fai domande chiarificanti! Spero che qualcuno sia in grado di aiutarmi a trovare un modo decente per affrontarlo. Tutti i suggerimenti sono benvenuti.

È stato utile?

Soluzione

Nella parte superiore del thread di elaborazione di ciascun paese, inserire il codice paese nel contesto diagnostico mappato (MDC) di Log4j. Questo utilizza una variabile ThreadLocal in modo da non dover passare esplicitamente il paese su e giù dallo stack di chiamate. Quindi crea un filtro personalizzato che esamina l'MDC e filtra tutti gli eventi che non contengono il codice paese dell'appender corrente.

Nel tuo Job:

...
public static final String MDC_COUNTRY = "com.y.foo.Country";
public void execute(JobExecutionContext context)
  /* Just guessing that you have the country in your JobContext. */
  MDC.put(MDC_COUNTRY, context.get(MDC_COUNTRY));
  try {
    /* Perform your job here. */
    ...
  } finally {
    MDC.remove(MDC_COUNTRY);
  }
}
...

Scrivi un personalizzato :

package com.y.log4j;

import org.apache.log4j.spi.LoggingEvent;

/**
 * This is a general purpose filter. If its "value" property is null, 
 * it requires only that the specified key be set in the MDC. If its 
 * value is not null, it further requires that the value in the MDC 
 * is equal.
 */
public final class ContextFilter extends org.apache.log4j.spi.Filter {

  public int decide(LoggingEvent event) {
    Object ctx = event.getMDC(key);
    if (value == null)
      return (ctx != null) ? NEUTRAL : DENY;
    else
      return value.equals(ctx) ? NEUTRAL : DENY;
  }

  private String key;
  private String value;

  public void setContextKey(String key) { this.key = key; }
  public String getContextKey() { return key; }
  public void setValue(String value) { this.value = value; }
  public String getValue() { return value; }

}

Nel tuo log4j.xml:

<appender name="fr" class="org.apache.log4j.FileAppender">
  <param name="file" value="france.log"/>
  ...
  <filter class="com.y.log4j.ContextFilter">
    <param name="key" value="com.y.foo.Country" />
    <param name="value" value="fr" />
  </filter>
</appender> 

Altri suggerimenti

Perché non chiamare semplicemente Thread.setName () quando il lavoro inizia a impostare il nome Thread? Se si verifica un problema di accesso, configurare quartz per utilizzare il proprio pool di thread.

Potrei essere completamente off-base sulla mia comprensione di ciò che stai tentando di realizzare, ma mi prenderò cura della soluzione. Sembra che tu voglia un file di registro separato per ogni paese per il quale stai elaborando la posta elettronica. Sulla base di tale comprensione, ecco una possibile soluzione:

  1. Imposta un appender nella configurazione di log4j per ogni Paese per il quale desideri effettuare il login separatamente (esempio USA fornito):

    log4j.appender.usfile = org.apache.log4j.FileAppender

    log4j.appender.usfile.File = us.log

    log4j.appender.usfile.layout = org.apache.log4j.PatternLayout

    log4j.appender.usfile.layout.ConversionPattern =% m% n

  2. Crea un logger per ciascun paese e indirizza ciascuno di essi all'appender appropriato (esempio USA fornito):

    log4j.logger.my-us-logger = di debug, usfile

  3. Nel tuo codice, crea il tuo Logger in base al paese per cui viene elaborata l'email:

    Logger logger = Logger.getLogger (" my-us-logger ");

  4. Determina come eseguirai il passaggio 3 per le successive chiamate al metodo. Puoi ripetere il passaggio 3 in ogni classe / metodo; oppure è possibile modificare le firme del metodo per accettare un Logger come input; oppure potresti usare ThreadLocal per passare il Logger tra i metodi.

Informazioni aggiuntive: se non si desidera che le istruzioni del registro vengano indirizzate ai logger principali (ad es. rootLogger), è possibile impostare i flag di additività su false (esempio USA fornito):

log4j.additivity.my-us-logger=false
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top