Как программно войти в числовые поля в 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;
}