Как программно войти в числовые поля в Graylog?

Ситуация

Я пишу библиотеки для работы с вычислительным сервером. Я регистрирую время вычислений (например, запуск и остановку работы). Я хочу регистрировать эти значения независимо от конфигурации каркаса журнала клиентского приложения. Я достиг этого, используя Graylog программно. Поэтому я настраиваю и инициализирую свой регистратор из моей библиотеки, пока клиент не замечает.

Это мой код инициализации

import org.graylog2.log.GelfAppender;

void init() {
    final GelfAppender appender = new GelfAppender();

    appender.setName("MyServerAppender");
    appender.setGraylogHost("bigcpuserver");
    appender.setGraylogPort(2020);
    appender.setExtractStacktrace(true);
    appender.setAddExtendedInformation(true);
    appender.setAdditionalFields("{'environment': 'TEST',"
            + "'ip_address': '10.20.30.40',"
            + "'serverName': 'devPc',"
            + "'libVersion': '1.0.0',"
            + "'application': 'loggingTestApp',"
            + "'appversion': '2.0.7'}");
    appender.activateOptions();
    final org.apache.log4j.Logger myLog =
        org.apache.log4j.Logger.getLogger(MyHiddenLoggerClass.class);
    myLog.addAppender(appender);

}

Все идет нормально. Я могу отправлять журналы в Graylog из любой точки моего кода с помощью следующей строки:

org.apache.log4j.Logger.getLogger(MyHiddenLoggerClass.class).info("message");

Эта проблема

Я хочу добавить числовые поля в мои журналы, чтобы Graylog мог вести статистику по ним. Как, например, найти, какие задания заняли больше всего времени - может потребоваться оптимизация алгоритма - или самое короткое - может вообще не нуждаться в вычислительном сервере.

Я могу добавить поля в MDC следующим образом:

org.apache.log4j.MDC.put("cpuTime", startTimeMillis-endTimeMillis);

И с тех пор все журналы будут включать cpuTime поле с этим значением. Я удаляю его после отправки определенной записи журнала, чтобы предотвратить перенос его на следующие записи журнала:

org.apache.log4j.MDC.remove("cpuTime");

Но для Graylog это строки, поэтому он может только посчитать их и посмотреть, сколько их существует.

Вопрос

Как я могу сказать Graylog, что "cpuTime" всегда будет long?

Попытки пока

Я попытался настроить поля заранее, в init() время.

Для этого я протестировал и другие иерархии классов, например me.moocar, Например, я попробовал следующее:

    final me.moocar.logbackgelf.GelfAppender appender =
        new me.moocar.logbackgelf.GelfAppender();

    appender.setName("MyServerAppender");
    appender.setIncludeFullMDC(true);
    appender.setGraylog2ServerHost("bigcpuserver");
    appender.setGraylog2ServerPort(2020);
    final Map<String, String> additionalFields = new HashMap<String, String>();
    final Map<String, String> fieldTypes = new HashMap<String, String>();
    additionalFields.put("cpuTime", "42");
    fieldTypes.put("cpuTime", "long");
    appender.setAdditionalFields(additionalFields);
    appender.setFieldTypes(fieldTypes);
    appender.start();

    final ch.qos.logback.classic.LoggerContext logCtx =
            (LoggerContext) LoggerFactory.getILoggerFactory();
    appender.setContext(logCtx);

    ch.qos.logback.classic.Logger logToConfigure =
            logCtx.getLogger(MyHiddenLoggerClass.class);
    logToConfigure.addAppender(appender);

Так что я могу сделать следующее в моем тестовом коде:

    final ch.qos.logback.classic.Logger log =
             logCtx.getLogger(MyHiddenLoggerClass.class);
    MDC.put("cpuTime", totalTime);
    log.error("task finished.");

А в Graylog, журнал "задание выполнено". будет сопровождаться полем с именем "cpuTime" и содержит строку со значением totalTime в момент регистрации. Я просто хочу, чтобы содержащееся значение было числом. Кто-нибудь может мне помочь с этим?

Я могу изменить все на me.moocar иерархия, если это помогает вообще. Но пока ни me.moocar ни org.graylog2.log дали мне результат, который я хочу; и с последним я получаю более легкую задачу прикрепления appender к логгеру.

Обновить

me.moocar кажется, ограничивается String как тип дополнительных полей. Поэтому, если я хочу числовые поля, я должен выбрать другой вариант.

2 ответа

Решение

Вам необходимо отправить значения в соответствии с их типами данных. Есть разница в

{'cpuTime':'42'}

а также

{'cpuTime':42}

Я не знаю, есть ли в Graylog преобразователь (вы можете обрабатывать преобразования полей в logstash через filters). Если вы хотите решить проблему на уровне логгера, взгляните на http://logging.paluch.biz/examples/logback.html, в частности additionalFieldTypes,

Я столкнулся с той же проблемой и выяснил, что последняя версия https://mvnrepository.com/artifact/de.siegmar/logback-gelf/4.0.0 реализует функцию отправки числовых значений в виде чисел в Graylog.

По умолчанию он отключен, и вы можете включить его, установив флаг numbersAsString, например так в logback.xml

      <?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <include
        resource="org/springframework/boot/logging/logback/base.xml" />

    <appender name="GELF"
        class="de.siegmar.logbackgelf.GelfUdpAppender">
        <graylogHost>${graylog-host}</graylogHost>
        <graylogPort>${graylog-port></graylogPort>
        <encoder class="de.siegmar.logbackgelf.GelfEncoder">
            <numbersAsString>true</numbersAsString>
        </encoder>
    </appender>
    <root level="INFO">
        <appender-ref ref="CONSOLE" />
        <appender-ref ref="GELF" />
    </root>

</configuration>

С приведенной выше настройкой анализируемые значения отправляются в Graylog в виде чисел, он обрабатывается этим фрагментом кода в de.siegmar.logbackgelf.GelfEncoder - конвертирует String в BigDecimal

          private Object processValue(final String value) {
        if (!numbersAsString) {
            try {
                return new BigDecimal(value);
            } catch (final NumberFormatException e) {
                return value;
            }
        }
        return value;
    }

Позже это кодируется в Json как число в de.siegmar.logbackgelf.SimpleJsonEncoder

          SimpleJsonEncoder appendToJSON(final String key, final Object value) {
        if (closed) {
            throw new IllegalStateException("Encoder already closed");
        }
        if (value != null) {
            appendKey(key);
            if (value instanceof Number) {
                sb.append(value.toString());
            } else {
                sb.append(QUOTE).append(escapeString(value.toString())).append(QUOTE);
            }
        }
        return this;
    }
Другие вопросы по тегам