【问题标题】:How can I programmatically log numeric fields into Graylog?如何以编程方式将数字字段记录到 Graylog 中?
【发布时间】:2017-06-08 14:16:03
【问题描述】:

情况

我编写库以针对计算服务器工作。 我正在记录计算时间(例如,作业的开始和停止)。 我想独立于客户端应用程序的日志框架配置来记录这些值。我通过以编程方式使用 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.moocarorg.graylog2.log 都没有给我想要的结果;使用后者,我可以更轻松地将附加程序附加到记录器。

更新

me.moocar 似乎仅限于 String 作为附加字段的类型。所以如果我想要数字字段,我必须选择其他选项。

【问题讨论】:

    标签: java graylog gelf


    【解决方案1】:

    您需要根据数据类型发送值。有区别

    {'cpuTime':'42'}
    

    {'cpuTime':42}
    

    我不知道 Graylog 中是否有可用的转换器(您可以通过 filters 处理 logstash 中的字段转换)。如果您想在记录器级别解决问题,请查看http://logging.paluch.biz/examples/logback.html,特别是additionalFieldTypes

    【讨论】:

    • 非常感谢。我以为我在沙漠里说话。我明天第一件事就试试看。
    • 不。没有帮助:org.apache.log4j.MDC.put("id_numeric_field", 222222); 也以字符串形式出现。 me.moocar.logbackgelf.GelfAppender.setStaticAdditionalFields(Map&lt;String, String&gt; staticAdditionalFields) 不允许我输入除字符串以外的任何内容。
    • 最后但并非最不重要的一点是,尝试将附加字段添加为"'cpuTime': '42'" 成功将字段cpuTime 设置为字符串值"42",但"'cpuTime':42" 抛出Exception in thread "main" java.lang.ClassCastException: java.lang.Long cannot be cast to java.lang.String .所以,它期待一个String
    • Moocar 的 Logback appender 仅限于 String。你试过biz.paluch.logging:logstash-gelf 吗?
    • 天哪!当然。这就是我第一个尝试的想法。好吧,事实证明,我将GraylogHost 设置为正确的主机,但我将Host 设置为原始主机之后...现在我成功试用了。这很可能会“取消暂停”这个任务!非常感谢。
    【解决方案2】:

    我遇到了同样的问题,并发现最新版本的 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>false</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;
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-30
      • 1970-01-01
      相关资源
      最近更新 更多