【问题标题】:Logback appender to post message as HTTP messageLogback appender 将消息作为 HTTP 消息发布
【发布时间】:2016-07-08 16:19:57
【问题描述】:

根据我的要求,我只想将 HTTP 消息发布到由org.slf4j.LoggerFactory.getLogger() 记录的另一端。

以下 JSON 字符串记录在 INFO level

{
  "studentName": "My Name",
  "Deratment": "Computer Science",
  "address": {
     "Address Line1": "My Address Line1",
     "Address Line2": "My Address Line2",
     "Address Line3": "My Address Line3"
  }
}

注意事项,

  1. Http 消息应该使用 MIME 类型application/json 发布

  2. 应该只处理INFO 级别的特定日志而不是全部。

Logback 中是否有任何内置的 appender 来实现这一点?

如果没有,最好的方法是什么?

【问题讨论】:

    标签: json log4j logback slf4j


    【解决方案1】:

    我认为发布 json 消息的最佳方式是使用 org.apache.logging.log4j。

    第一步:添加maven依赖

    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>2.11.1</version>
    </dependency>
    

    以及任何构造json的依赖,比如

    <dependency>
         <groupId>com.google.code.gson</groupId>
         <artifactId>gson</artifactId>
         <version>2.8.5</version>
    </dependency>
    

    第 2 步:编写自定义布局以创建您的 json

    @Plugin(name = "CustomJsonLayout", category = Node.CATEGORY, elementType = Layout.ELEMENT_TYPE)
    public class CustomJsonLayout extends AbstractStringLayout {
        private static final Gson gson = new Gson();
    
        public CustomJsonLayout(Configuration config, Charset aCharset, Serializer headerSerializer, Serializer footerSerializer) {
            super(config, aCharset, headerSerializer, footerSerializer);
        }
    
        @PluginFactory
        public static CustomJsonLayout createLayout(@PluginConfiguration final Configuration config,
                                                    @PluginAttribute(value = "charset", defaultString = "US-ASCII") final Charset charset) {
            return new CustomJsonLayout(config, charset, null, null);
        }
    
        @Override
        public String toSerializable(LogEvent event) {
            JsonObject jsonObject = new JsonObject();
    
            // as example
            jsonObject.addProperty("application_name", "MyApp");
            jsonObject.addProperty("timestamp", "" + System.currentTimeMillis());
    
            // some log Information
            jsonObject.addProperty("level", event.getLevel().name());
            jsonObject.addProperty("thread", event.getThreadName());
            jsonObject.addProperty("thread_id", event.getThreadId());
            jsonObject.addProperty("logger_name", event.getLoggerName());
    
            // extra information
            final StackTraceElement source = event.getSource();
            JsonObject sourceObject = new JsonObject();
            sourceObject.addProperty("class", source.getClassName());
            sourceObject.addProperty("method", source.getMethodName());
            sourceObject.addProperty("file", source.getFileName());
            sourceObject.addProperty("line", source.getLineNumber());
            jsonObject.add("source", sourceObject);
    
            // your log message
            jsonObject.addProperty("message", event.getMessage().getFormattedMessage());
    
            // Exceptions
            if (event.getThrownProxy() != null) {
                final ThrowableProxy thrownProxy = event.getThrownProxy();
                final Throwable throwable = thrownProxy.getThrowable();
    
                final String exceptionsClass = throwable.getClass().getCanonicalName();
                if (exceptionsClass != null) {
                    jsonObject.addProperty("exception", exceptionsClass);
                }
    
                final String exceptionsMessage = throwable.getMessage();
                if (exceptionsMessage != null) {
                    jsonObject.addProperty("cause", exceptionsMessage);
                }
    
                final String stackTrace = thrownProxy.getExtendedStackTraceAsString("");
                if (stackTrace != null) {
                    jsonObject.addProperty("stacktrace", stackTrace);
                }
            }
    
            return gson.toJson(jsonObject).concat("\r\n");
        }
    
    }
    

    第 3 步:配置 log4j2.xml where yourUrl - 如果您使用 Spring Boot,则从 application.properties 定位 url (yourUrl=http://....)

    <?xml version="1.0" encoding="UTF-8"?>
    <Configuration status="WARN">
        <Properties>
            <Property name="urlProp">${bundle:application:yourUrl}</Property>
        </Properties>
        <Appenders>
            <Console name="Console" target="SYSTEM_OUT">
                <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
            </Console>
            <Http name="Http" url="${urlProp}">
                <Property name="X-Java-Runtime" value="$${java:runtime}" />
                <CustomJsonLayout/>
            </Http>
            <File name="LogToFile" fileName="logs/app.log">
                <PatternLayout>
                    <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
                </PatternLayout>
                <Policies>
                    <TimeBasedTriggeringPolicy/>
                    <SizeBasedTriggeringPolicy size="100 MB"/>
                </Policies>
                <DefaultRolloverStrategy max="10"/>
            </File>
        </Appenders>
        <Loggers>
            <Root level="info">
                <AppenderRef ref="Http"/>
                <AppenderRef ref="Console"/>
                <AppenderRef ref="LogToFile"/>
            </Root>
        </Loggers>
    </Configuration>
    

    第 4 步:最后,您可以在任何类中使用您的记录器

    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;
    
    private static final Logger logger = LogManager.getLogger(App.class);
    
    logger.info("Application started");
    

    【讨论】:

      【解决方案2】:

      Logback 与 logstash 配合得非常好:https://github.com/logstash/logstash-logback-encoder

      第一步是配置 logback 到 logstash 连接。

      <?xml version="1.0" encoding="UTF-8"?>
      <configuration>
        <appender name="stash" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
            <destination>127.0.0.1:4560</destination>
      
            <!-- encoder is required -->
            <encoder class="net.logstash.logback.encoder.LogstashEncoder" />
        </appender>
      
        <root level="DEBUG">
            <appender-ref ref="stash" />
        </root>
      </configuration>
      

      完成后,您需要创建一个从 tcp 输入到 http 输出插件的管道,如下所示

      input {
          tcp {
                  port => 4560
                  codec => json_lines
              }
      }
      
      output {
          http {
              http_method => ...
              url => ...
          }
      }
      

      (见https://www.elastic.co/guide/en/logstash/current/plugins-outputs-http.html

      【讨论】:

      • 这不是 HTTP,只有 TCP。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-22
      • 2015-10-21
      相关资源
      最近更新 更多