Pregunta

Estoy trabajando en una aplicación que consta de un planificador basado en Quartz y " CycledJob " ejecutar usando CronTriggers. El propósito de la aplicación es procesar entradas de diferentes bandejas de entrada de correo electrónico según el país de origen.

Según el país del que proviene (es decir, EE. UU., Reino Unido, Francia, etc.), la aplicación activa un subproceso de trabajo para ejecutar el ciclo de procesamiento de cada país, por lo que habría un subproceso de Trabajador del Reino Unido, uno para EE. UU., Francia , etc. Al formatear la salida a log4j, estoy usando el parámetro thread, por lo que emite [ApplicationName_Worker-1], [ApplicationName_Worker-2] etc. Intento como podría, no puedo encontrar una manera de nombrar los hilos desde que fueron sacados de las piscinas de hilos de cuarzo. Aunque podría llegar a extender Quartz, me gustaría encontrar una solución diferente en lugar de jugar con la biblioteca estándar.

Aquí está el problema: cuando uso log4j, me gustaría tener todos los elementos de registro desde la salida de subprocesos de EE. UU. a un archivo exclusivo de EE. UU., del mismo modo para cada uno de los subprocesos del país. No me importa si permanecen en un ConsoleAppender unificado, la división FileAppender es lo que busco aquí. Ya sé cómo especificar múltiples agregadores de archivos y tal, mi problema es que no puedo diferenciar según el país. Hay más de 20 clases dentro de la aplicación que pueden estar en la cadena de ejecución, muy pocas de las cuales quiero cargar con el conocimiento de pasar un & Quot; context & Quot; parámetro a través de CADA método ... He considerado un patrón de estrategia que extiende una clase de contenedor log4j, pero a menos que pueda dejar que cada clase en la cadena sepa en qué hilo está para parametrizar la llamada del registrador, eso parece imposible. Sin poder nombrar el hilo también crea un desafío (¡o de lo contrario esto sería fácil!).

Entonces, esta es la pregunta: ¿Cuál sería un enfoque sugerido para permitir que muchas clases subordinadas en una aplicación que se utilizan para cada subproceso diferente procesen la entrada y sepan que están dentro del contexto de un subproceso de país en particular cuando inician sesión ?

¡Buena suerte entendiendo, y por favor haga preguntas aclaratorias! Espero que alguien pueda ayudarme a encontrar una forma decente de abordar esto. Todas las sugerencias son bienvenidas.

¿Fue útil?

Solución

En la parte superior del hilo de procesamiento de cada país, coloque el código del país en el contexto de diagnóstico mapeado (MDC) de Log4j. Esto utiliza una variable ThreadLocal para que no tenga que pasar el país hacia arriba y hacia abajo de la pila de llamadas explícitamente. Luego, cree un filtro personalizado que mire el MDC y filtre los eventos que no contengan el código de país del adjunto actual.

En su 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);
  }
}
...

Escriba un Filter :

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

}

En su 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> 

Otros consejos

Ojalá pudiera ser un poco más útil que esto, pero ¿puedes investigar usando algunos filtros? ¿Quizás su registro podría generar el código de país y podría coincidir con su filtro en función de eso?

Un StringMatchFilter probablemente debería poder emparejarlo por usted.

No se pudo obtener la dirección siguiente para que funcione correctamente como un enlace, pero si la observa, tiene algunas cosas sobre el registro de archivos por separado utilizando filtros.

http: //mail-archives.apache. org / mod_mbox / logging-log4j-user / 200512.mbox / < 1CC26C83B6E5AA49A9540FAC8D35158B01E2968E@pune.kaleconsultants.com > (solo quite el espacio antes de >)

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

¿Por qué no simplemente llamar a Thread.setName () cuando su trabajo comienza a establecer el nombre de Thread? Si hay un problema de acceso, configure Quartz para usar su propio grupo de subprocesos.

Puede que esté completamente fuera de mi base de mi comprensión de lo que está tratando de lograr, pero voy a probar la solución. Parece que desea un archivo de registro separado para cada país para el que está procesando correo electrónico. En base a ese entendimiento, aquí hay una posible solución:

  1. Configure un apéndice en su configuración de log4j para cada país en el que desee iniciar sesión por separado (se proporciona un ejemplo de EE. UU.):

    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. Cree un registrador para cada país y diríjalo al appender apropiado (se proporciona un ejemplo de EE. UU.):

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

  3. En su código, cree su Logger según el país para el que se procesa el correo electrónico:

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

  4. Determine cómo logrará el paso 3 para las siguientes llamadas de método. Puede repetir el paso 3 en cada clase / método; o puede modificar las firmas del método para aceptar un registrador como entrada; o podría usar ThreadLocal pasar el registrador entre métodos.

Información adicional: si no desea que las declaraciones de registro vayan a los registradores principales (por ejemplo, el rootLogger), puede establecer sus indicadores de aditividad en falso (se proporciona un ejemplo de EE. UU.):

log4j.additivity.my-us-logger=false
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top