Question

Je travaille sur une application composée d'un planificateur global basé sur Quartz et de & "CycledJob &"; exécuter en utilisant CronTriggers. Le but de l'application est de traiter les entrées de différentes boîtes de réception en fonction du pays source.

En fonction du pays d'origine (États-Unis, Royaume-Uni, France, etc.), l'application déclenche un thread de travail pour exécuter le cycle de traitement de chaque pays. Il existe donc un thread de travail britannique, un pour les États-Unis et la France. , etc. Lors du formatage de la sortie en log4j, j'utilise le paramètre thread, qui émet donc [NomApplication_Worker-1], [NomApplication_Worker-2], etc. Malgré mes efforts, je ne parviens pas à nommer les threads. puisqu’ils sont sortis des Thread Pools de Quartz. Bien que je puisse éventuellement aller jusqu’à étendre Quartz, j’aimerais élaborer une solution différente au lieu de jouer avec la bibliothèque standard.

Voici le problème: lors de l’utilisation de log4j, j'aimerais que tous les éléments de journal du fil de discussion américain soient exportés dans un fichier contenant uniquement des fichiers américains, de même que pour chacun des threads de pays. Peu m'importe qu'ils restent dans un seul ConsoleAppender unifié, la division FileAppender est ce que je recherche ici. Je sais déjà comment spécifier plusieurs appender de fichiers, par exemple, mon problème est que je ne peux pas différencier en fonction du pays. Il existe plus de 20 classes dans l'application qui peuvent figurer dans la chaîne d'exécution, mais je ne souhaite en charger que très peu de connaissances sur la nécessité de passer un & «Contexte &» Supplémentaire. paramètre par CHAQUE MÉTHODE ... J'ai envisagé un modèle de stratégie étendant une classe d'encapsuleur log4j, mais si je ne peux pas laisser chaque classe de la chaîne savoir sur quel thread il est en train de paramétrer l'appel du consignateur, cela semble impossible. Sans pouvoir nommer le fil, cela crée également un défi (sinon ce serait facile!).

Alors voici la question: quelle serait une approche suggérée pour permettre à de nombreuses classes subordonnées dans une application qui sont utilisées chacune pour chaque thread différent de traiter l'entrée, sachant qu'elles se trouvent dans le contexte d'un thread de pays particulier lors de la journalisation ?

Bonne compréhension, et posez des questions de clarification! J'espère que quelqu'un pourra m'aider à trouver un moyen décent de s'y attaquer. Toutes les suggestions sont les bienvenues.

Était-ce utile?

La solution

En haut du fil de traitement de chaque pays, placez le code de pays dans le contexte de diagnostic mappé (MDC) de Log4j. Ceci utilise une variable ThreadLocal afin que vous n'ayez pas à passer le pays de haut en bas de la pile d'appels explicitement. Créez ensuite un filtre personnalisé qui examine le MDC et élimine tous les événements ne contenant pas le code de pays de l'appender actuel.

Dans votre 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);
  }
}
...

Ecrivez un Filtre :

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; }

}

Dans votre 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> 

Autres conseils

Je souhaiterais pouvoir être un peu plus utile que cela, mais vous voudrez peut-être examiner certains filtres? Peut-être que votre journalisation pourrait générer l’indicatif du pays et que votre filtre corresponde à celui-ci?

Un StringMatchFilter devrait probablement pouvoir vous correspondre.

Impossible que l'adresse ci-dessous fonctionne correctement en tant que lien, mais si vous la regardez, elle contient des informations sur la journalisation séparée des fichiers à l'aide de filtres.

http: //mail-archives.apache. org / mod_mbox / logging-log4j-user / 200512.mbox / < 1CC26C83B6E5AA49A9540FAC8D35158B01E2968E@pune.kaleconsultants.com > (il suffit de supprimer l'espace avant le >)

http: //logging.apache .org / log4j / 1.2 / apidocs / org / apache / log4j / spi / Filter.html

Pourquoi ne pas simplement appeler Thread.setName () lorsque votre travail commence à définir le nom Thread? En cas de problème d’accès, configurez quartz pour utiliser votre propre pool de threads.

Je comprends peut-être parfaitement ce que vous essayez d'accomplir, mais je vais essayer de trouver une solution. Il semble que vous souhaitiez un fichier journal distinct pour chaque pays pour lequel vous traitez un courrier électronique. Sur la base de cette compréhension, voici une solution possible:

  1. Configurez un générateur d'appels dans votre configuration log4j pour chaque pays pour lequel vous souhaitez vous connecter séparément (exemple américain fourni):

    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. Créez un enregistreur pour chaque pays et dirigez-le vers l'appendeur approprié (exemple américain fourni):

    log4j.logger.my-us-logger = debug, fichier_fichier

  3. Dans votre code, créez votre enregistreur en fonction du pays pour lequel l'e-mail est en cours de traitement:

    Logger logger = Logger.getLogger (& "Mon-us-logger &";);

  4. Déterminez comment vous réaliserez l'étape 3 pour les appels de méthode suivants. Vous pouvez répéter l’étape 3 dans chaque classe / méthode; ou vous pouvez modifier les signatures de méthode pour accepter un enregistreur en tant qu'entrée; ou vous pouvez éventuellement utiliser ThreadLocal . passer l'enregistreur entre les méthodes.

Informations supplémentaires: si vous ne souhaitez pas que les instructions de journal soient envoyées aux enregistreurs parents (par exemple, le rootLogger), vous pouvez définir leurs indicateurs d'additivité sur false (exemple américain fourni):

log4j.additivity.my-us-logger=false
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top