Как управлять переключением файла журнала через пользовательское событие в Spring? - PullRequest
0 голосов
/ 14 января 2020

Предположим, мы используем Logback для ведения журнала.

Требуется изменять путь к файлу журнала каждый раз, когда происходит определенное событие (т.е. вызов функции).

Например, где-то мы вызываем функцию.

startNewLogSegment("A")

После этого события регистратор должен начать запись в файл logs/mySegment_A.log. Затем снова выполняется вызов:

startNewLogSegment("B")

После этого события регистратор должен завершить sh запись в предыдущий файл и начать запись в файл logs/mySegment_B.log.

Давайте предположим, что состояние, измененное на startNewLogSegment, должно быть видно во всем приложении (все потоки).


Я попытался применить подход с MD C:

logback. xml

...
<appender name="SIFTING_BY_ID" class="ch.qos.logback.classic.sift.SiftingAppender">
    <discriminator>
        <key>id</key>
        <defaultValue>initial</defaultValue>
    </discriminator>

    <sift>
        <appender name="FULL-${id}" class="ch.qos.logback.core.FileAppender">
            <file>logs/mySegment_${id}.log</file>
            <append>false</append>
            <encoder >
                <pattern>%d{dd-MM-yyyy HH:mm:ss.SSS} [%thread] [%-5level] %logger{36}.%M - %msg%n</pattern>
            </encoder>
        </appender>
    </sift>
</appender>
...

и вызов MDC.put("id", "A"), когда появляется пользовательское событие.

Но оно работает не так, как мне нужно.

Известно, что MD C управляет контекстной информацией для каждого потока , поэтому, по крайней мере, нам нужно контроль над созданием потоков для достижения sh цели, описанной выше .

Интересно, можно ли использовать этот подход с Spring и, в частности, с асинхронными c операциями, выполняемыми Spring Reactor. Я не нашел информации об использовании пользовательского пула потоков для внутренних операций Spring.

Возможно, я надеюсь, что есть более простой способ настроить ведение журнала таким образом, не используя внутренние ресурсы Spring.

1 Ответ

0 голосов
/ 28 января 2020

Я получил специальную реализацию дискриминатора AbstractDiscriminator<ILoggingEvent>, позволяющего использовать глобально видимые значения.

GV C. java

/**
 * Global values context.
 * Allows to sift log files globally independent from a thread calling log operation.
 * <p>
 * Used API analogous to standard {@link org.slf4j.MDC}.
 */
public final class GVC {

    private static Map<String, String> STORED = new HashMap<>();

    private GVC() {
    }

    public static synchronized void put(String key, String value) {
        STORED.put(key, value);
    }

    public static synchronized String get(String key) {
        return STORED.get(key);
    }
}

GVCBasedDiscriminator. java

/**
 * Customized analogue of MDCBasedDiscriminator.
 * <p>
 * GVCBasedDiscriminator essentially returns the value mapped to an GVC key.
 * If the value is null, then a default value is returned.
 * <p>
 * Both Key and the DefaultValue are user specified properties.
 */
public class GVCBasedDiscriminator extends AbstractDiscriminator<ILoggingEvent> {

    private String key;
    private String defaultValue;

    public String getDiscriminatingValue(ILoggingEvent event) {
        String value = GVC.get(key);

        if (value == null) {
            return defaultValue;
        } else {
            return value;
        }
    }

    @Override
    public String getKey() {
        return key;
    }

    @Override
    public void start() {
        int errors = 0;
        if (OptionHelper.isEmpty(key)) {
            errors++;
            addError("The \"Key\" property must be set");
        }
        if (OptionHelper.isEmpty(defaultValue)) {
            errors++;
            addError("The \"DefaultValue\" property must be set");
        }
        if (errors == 0) {
            started = true;
        }
    }

    /**
     * Key for this discriminator instance
     *
     * @param key
     */
    public void setKey(String key) {
        this.key = key;
    }

    /**
     * The default GVC value in case the GVC is not set for
     * {@link #setKey(String) mdcKey}.
     * <p/>
     * <p> For example, if {@link #setKey(String) Key} is set to the value
     * "someKey", and the MDC is not set for "someKey", then this appender will
     * use the default value, which you can set with the help of this method.
     *
     * @param defaultValue
     */
    public void setDefaultValue(String defaultValue) {
        this.defaultValue = defaultValue;
    }
}

logback. xml

<appender name="TRACES_PER_SESSION_FILE" class="ch.qos.logback.classic.sift.SiftingAppender">
  <!-- here the custom discriminator implementation is applied -->
  <discriminator class="internal.paxport.misc.logging.GVCBasedDiscriminator">             
    <key>id</key>
    <defaultValue>initial</defaultValue>
  </discriminator>

  <sift>
    <appender name="FULL-${id}" class="ch.qos.logback.core.FileAppender">
      <file>logs/mySegment_${id}.log</file>
      <append>false</append>
      <encoder>
        <pattern>%d{dd-MM-yyyy HH:mm:ss.SSS} [%thread] [%-5level] %logger{36}.%M - %msg%n</pattern>
      </encoder>
    </appender>
  </sift>
</appender>
...