Шаблон за заместващ знак за RoutingAppender на Log4j2

Опитвам се да използвам новия RoutingAppender на Log4j2, за да маршрутизирам различните регистрационни файлове въз основа на MDC (ThreadContext в Log4j2). Това, което искам да направя е следното:

  • Ако MDC картата има $contextId -> Добавяне към $contextId appender (конкретен журнал)
  • Ако MDC няма $contextId -> Добавяне към главния appender (общ дневник)

Искам да постигна това, като използвам шаблон със заместващ знак в маркера и след това филтрирам, като използвам ключовия параметър в for contextId (${ctx:contextId}) и използвам стандартния (без ключов параметър) за главния добавъчен елемент, но не го правя знаете коя стойност е този заместващ знак.

Всяка помощ се оценява, може би подхождам към това от грешен път. Четох за филтрите, но изглежда не работят както искам.

Благодаря!


person hveiga    schedule 16.08.2013    source източник


Отговори (4)


Това отговаря ли на въпроса ви? https://issues.apache.org/jira/browse/LOG4J2-326

Ремко

person Remko Popma    schedule 17.08.2013

Не бях доволен от решението за дефиниране на резервния маршрут с трика, описан в https://issues.apache.org/jira/browse/LOG4J2-326 и http://logging.apache.org/log4j/2.x/faq.html#separate_log_files, защото това ме принуждава да дублирам конфигурацията на appender, съдържаща се в маршрутите. Не се нуждая от различна конфигурация на appender за маршрута по подразбиране, а само от правилно име на файл за общия дневник.

Като се има предвид, че картата на свойствата по подразбиране се търси за свойство, което е недефинирано в неговия контекст, вижте https://logging.apache.org/log4j/2.x/manual/configuration.html#PropertySubstitution, мисля, че най-простият начин е просто да дефинирате стойността по подразбиране, напр.

<Properties>
    <Property name="fruits">any_fruit</Property>
</Properties>

и в случай че контекстът на нишката няма ${ctx:fruits}, се взема "any_fruit".

person Torsten Küpper    schedule 14.09.2016

Благодаря за връзката Remko, намерих временно решение, докато тази функция не бъде подобрена от момчетата от Log4j2. Решението използва както RoutingAppender, така и Filters. Ето как изглежда моята конфигурация log4j2 (имам дефинирани свойства, но не ги показвам тук):

<appenders>
    <appender name="applicationAppender" type="RollingFile" fileName="${logFileName}" filePattern="${logFileNamePattern}" bufferedIO="true" immediateFlush="true" append="true">
        <layout type="PatternLayout" pattern="${logPattern}" />
        <Policies>
            <TimeBasedTriggeringPolicy />
            <SizeBasedTriggeringPolicy size="${logFileSize}" />
        </Policies>
        <DefaultRolloverStrategy max="${logFileCount}" />
    </appender>

    <Routing name="contextSpecificAppender">
        <Routes pattern="$${ctx:contextId}">
            <Route>
                <appender name="Rolling-${ctx:contextId}" type="RollingFile" fileName="logs/${ctx:contextId}.log" filePattern="${logFileNamePattern}" bufferedIO="true" immediateFlush="true" append="true">
                    <layout type="PatternLayout" pattern="${logPattern}" />
                    <Policies>
                        <TimeBasedTriggeringPolicy />
                        <SizeBasedTriggeringPolicy size="${logFileSize}" />
                    </Policies>
                    <DefaultRolloverStrategy max="${logFileCount}" />
                </appender>
            </Route>
        </Routes>
    </Routing>
</appenders>

<loggers>
    <root level="info">
        <appender-ref ref="contextSpecificAppender">
            <ThreadContextMapFilter onMatch="DENY" onMismatch="ACCEPT">
                <KeyValuePair key="contextId" value="" />
            </ThreadContextMapFilter>
        </appender-ref>
        <appender-ref ref="applicationAppender">
            <ThreadContextMapFilter onMatch="ACCEPT" onMismatch="DENY">
                <KeyValuePair key="contextId" value="" />
            </ThreadContextMapFilter>
        </appender-ref>
    </root>
</loggers>

Това, което правя, е да извикам ThreadContext.put("contextId", "") или ThreadContext.put("contextId", "something") в зависимост от това какъв appender искам да регистрирам. Надявам се функцията wildward да бъде внедрена скоро, но междувременно това решение ми е достатъчно.

Благодаря!

person hveiga    schedule 19.08.2013
comment
Намерих решение, така че да не се налага да използвате филтъра заедно с превключването на ключа ThreadContext от попълнен на празен), като използвате два маршрута. Като този пример обяснява logging.apache.org/log4j/2.x/ faq.html#separate_log_files Можете да използвате атрибута ключ на маршрут, за да създадете маршрут, който е избран, ако ThreadContext няма стойност за ключа. След това използвам този маршрут, за да реферирам към основния си appender. Ако настроите този втори маршрут, изобщо не трябва да използвате ThreadContextMapFilter. Освен това ще ви трябва само един appender-ref във вашия root регистратор. - person Alex; 14.06.2014

Благодаря, hveiga, че проследи и публикува решението си, беше полезно. Исках да кажа, че можете да избегнете вашето филтърно решение, като добавите втори „маршрут“, който маршрутизира всички съобщения без стойност за вашия ключ за маршрутизиране, както е обяснено тук: http://logging.apache.org/log4j/2.x/faq.html#separate_log_files

Така че вашата актуализирана конфигурация на log4j ще изглежда така.

<appenders>
    <appender name="applicationAppender" type="RollingFile" fileName="${logFileName}" filePattern="${logFileNamePattern}" bufferedIO="true" immediateFlush="true" append="true">
        <layout type="PatternLayout" pattern="${logPattern}" />
        <Policies>
            <TimeBasedTriggeringPolicy />
            <SizeBasedTriggeringPolicy size="${logFileSize}" />
        </Policies>
        <DefaultRolloverStrategy max="${logFileCount}" />
    </appender>

    <Routing name="contextSpecificAppender">
        <Routes pattern="$${ctx:contextId}">
            <Route>
                <appender name="Rolling-${ctx:contextId}" type="RollingFile" fileName="logs/${ctx:contextId}.log" filePattern="${logFileNamePattern}" bufferedIO="true" immediateFlush="true" append="true">
                    <layout type="PatternLayout" pattern="${logPattern}" />
                    <Policies>
                        <TimeBasedTriggeringPolicy />
                        <SizeBasedTriggeringPolicy size="${logFileSize}" />
                    </Policies>
                    <DefaultRolloverStrategy max="${logFileCount}" />
                </appender>
            </Route>
            <Route ref="applicationAppender" key="$${ctx:contextId}">
            </Route>
        </Routes>
    </Routing>
</appenders>

<loggers>
    <root level="info">
        <appender-ref ref="contextSpecificAppender"/>
    </root>
</loggers>

И във вашето приложение можете просто да зададете ThreadContext, като извикате ThreadContext.put("contextId", "something") и да го изчистите, когато сте готови, като извикате ThreadContext.clear() ИЛИ ThreadContext.remove("contextId")

Накрая използвах

<RollingFile>

елемент (като примерите, свързани по-горе), вместо

<appender type="RollingFile"> 

елемент, който сте използвали. Вярвам, че това е предпочитано, когато мигрирате към log4j2 от log4j.

person Alex    schedule 13.06.2014