Separation log4j Quartz Workflow Exit

I am working on an application that consists of a general Quartz-based scheduler and "CycledJob" using CronTriggers. The purpose of the application is to process data from different email mailboxes based on the source country.

Depending on the country from which it comes (for example, USA, UK, FR, etc.), the application launches one task chain to start the processing cycle of each country, so there will be a worker flow from the UK, one for the USA, France, etc. .d. When formatting the output in log4j, I use the stream parameter, so it emits [ApplicationName_Worker-1], [ApplicationName_Worker-2], etc. Try as I could, I can’t find a way to name the threads since they are derived from the Quartz Thread pools. Although I could go so far as to expand Quartz, I would like to develop a different solution instead of messing with the standard library.

Here's the problem: when using log4j, I would like all of the log entries from the US US stream to a file for the US only, also for each of the country flows. I don’t care if they stay in the same combined ConsoleAppender, the split FileAppender is what I am here. I already know how to specify several file applications, etc. My problem is that I can not differentiate by country. There are 20 classes in the application that can be in the execution chain, very few of which I want to burden with knowledge about passing an additional "context" parameter through the EVERY method ... I examined a strategy template that extends log4j, but if I cannot allow each class in the chain to know which thread he turned on to parameterize the log call, this seems impossible. Without the ability to name the stream also poses a problem (otherwise it would be easy!).

So, the question arises: what will be the proposed approach, allowing many subclasses in the application, which each of them is used for each thread, to process the input data, know that they are in the context of a particular country ceiling when they register

Good luck, and please ask clarifying questions! I hope someone can help me find a decent way to handle this. All suggestions are welcome.

+4
source share
4 answers

At the top of each processing flow for each country, enter the country code in the diagnostic context (MDC) specified in Log4j. This uses the ThreadLocal variable, so you do not need to explicitly skip the country up and down the call stack. Then create a custom filter that looks at the MDC and filters out any events that do not contain the current recipient country code.

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

Write a custom 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; } } 

In your 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> 
+5
source

I would like to be a little more useful than that, but can you explore some filters? Perhaps your journal can output the country code, and you can match your filter based on this?

Probably StringMatchFilter will be able to match it for you.

It was not possible to get this address to work correctly as a link, but if you look at it, it has something in separate journaling using filters.

http://mail-archives.apache.org/mod_mbox/logging-log4j-user/200512.mbox/ < 1CC26C83B6E5AA49A9540FAC8D35158B01E2968E@pune.kaleconsultants.co m> (just remove the space before>)

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

+2
source

I can completely abandon my understanding of what you are trying to accomplish, but I will go to solve the problem. It looks like you need a separate log file for each country for which you are processing email. Based on this understanding, here is a possible solution:

  • Configure the application in your log4j configuration for each country for which you want to register separately (example in the USA):

    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

  • Create a registrar for each country and direct each of them to the corresponding application (example in the USA):

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

  • In your code, create your Logger based on the country for which the email is being processed:

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

  • Determine how you complete step 3 for subsequent method calls. You can repeat step 3 in each class / method; or you can change the method signatures to accept Logger as input; or you can use ThreadLocal to pass Logger between methods.

Additional Information. If you do not want the log statements sent to the parent registrars (for example, rootLogger), you can set their additivity flags to false (example in the USA):

 log4j.additivity.my-us-logger=false 
+1
source

Why not just call Thread.setName () when your job starts setting the name Thread? If there is a problem with access, configure quartz to use your own thread pool.

+1
source

Source: https://habr.com/ru/post/1277246/


All Articles