如何通过GELF将Spring Boot访问日志发送到远程服务器?

巴斯蒂安·沃格特

对于我们的Spring Boot应用程序,我们使用logback + GELF将应用程序日志发送到我们的中央日志服务器,在此我们可以对其进行分析。Spring Boot的访问日志是否可以做同样的事情?

如果不是,是否还有其他建议或最佳实践,用于从中央服务器上的多个spring boot应用程序收集访问日志?

巴斯蒂安·沃格特

好的,我经过研究后才发现。您需要向tomcat添加自定义阀门:

@Bean
public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() {
    TomcatEmbeddedServletContainerFactory factory 
        = new TomcatEmbeddedServletContainerFactory();
    GelfAccessLogValve gelfAccessLogValve = new GelfAccessLogValve();
    gelfAccessLogValve.setPattern("%h %m %U %I %l %u %t "%r" %s %b");
    factory.addContextValves(gelfAccessLogValve);
    return factory;
}

我编写的阀门基于paluch.biz的阀门,但不同之处在于它仅取决于Graylog的gelf客户。因此,您需要将此依赖项添加到pom中:

<dependency>
    <groupId>org.graylog2</groupId>
    <artifactId>gelfclient</artifactId>
    <version>1.4.0</version>
</dependency>

这是阀门代码:

public class GelfAccessLogValve extends AccessLogValve {

    private final static Map<Class, String> names = Collections.unmodifiableMap(new HashMap<Class, String>() {
        {
            put(HeaderElement.class, "Header");
            put(CookieElement.class, "Cookie");
            put(ResponseHeaderElement.class, "ResponseHeader");
            put(SessionAttributeElement.class, "SessionAttribute");
            put(RemoteAddrElement.class, "RemoteAddr");
            put(LocalAddrElement.class, "LocalAddr");
            put(ByteSentElement.class, "ByteSent");
            put(ElapsedTimeElement.class, "ElapsedTime");
            put(HostElement.class, "Host");
            put(ProtocolElement.class, "Protocol");
            put(MethodElement.class, "Method");
            put(PortElement.class, "LocalPort");
            put(QueryElement.class, "Query");
            put(RequestElement.class, "Request");
            put(FirstByteTimeElement.class, "FirstByteTime");
            put(HttpStatusCodeElement.class, "HttpStatusCode");
            put(SessionIdElement.class, "SessionId");
            put(DateAndTimeElement.class, "DateAndTime");
            put(UserElement.class, "User");
            put(RequestURIElement.class, "RequestURI");
            put(LocalServerNameElement.class, "LocalServerName");
            put(ThreadNameElement.class, "ThreadName");
        }
    });

    private String host = "localhost";
    private int port = 1234;
    private GelfTransport gelfSender;

    @Override
    public void log(Request request, Response response, long time) {

        if (gelfSender == null || !getState().isAvailable() || !getEnabled() || logElements == null || condition != null
                && null != request.getRequest().getAttribute(condition) || conditionIf != null
                && null == request.getRequest().getAttribute(conditionIf)) {
            return;
        }

        /**
         * XXX This is a bit silly, but we want to have start and stop time and duration consistent. It would be better to keep
         * start and stop simply in the request and/or response object and remove time (duration) from the interface.
         */
        long start = request.getCoyoteRequest().getStartTime();
        Date date = new Date(start + time);

        GelfMessage message = new GelfMessage(request.getMethod() + " " + request.getRequestURI());
        message.addAdditionalField("facility", getClass().getSimpleName());
        message.setFullMessage(request.getMethod() + " " + request.getRequestURI());
        message.setTimestamp(start + time);
        message.setLevel(GelfMessageLevel.INFO);

        for (int i = 0; i < logElements.length; i++) {

            String name = names.get(logElements[i].getClass());
            if (name == null) {
                continue;
            }

            CharArrayWriter result = new CharArrayWriter(128);
            logElements[i].addElement(result, date, request, response, time);
            message.addAdditionalField(name, result.toString());
        }

        try {
            gelfSender.send(message);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    private void createSender() {
        GelfConfiguration configuration = new GelfConfiguration(host, port);
        gelfSender = GelfTransports.create(configuration);
    }

    @Override
    protected synchronized void startInternal() throws LifecycleException {
        createSender();

        super.startInternal();
    }

    @Override
    protected synchronized void stopInternal() throws LifecycleException {
        if (gelfSender != null) {
            gelfSender.stop();
            gelfSender = null;
        }
        super.stopInternal();
    }

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何将日志条目发送到运行日记(系统)的远程服务器

如何配置rsyslog将日志从特定程序发送到远程syslog服务器?

如何将Android应用日志发送到远程服务器?

将Logstash日志发送到Kibana远程服务器

如何获取SSH日志并发送到macOS中的远程syslog服务器?

定期将动态公共IP发送到Web服务器以允许远程SSH访问

将文件发送到远程 FTP 服务器

Apache NiFi 可以配置 logback.xml 文件以通过 UDP 将日志发送到远程服务器吗?

如何通过ssh将本地变量发送到远程服务器

通过WCF将NLog日志发送到服务器

将日志发送到多个系统日志服务器

远程Internet服务器如何将数据包发送到本地IP?

如何使用iterm2将tmux前缀发送到远程服务器

如何将SWFT消息发送到远程服务器上的MQ?

Rails:如何将文件从S3发送到远程服务器

如何使用C#将JSon文件发送到远程Web服务器

如何将weblogic服务器日志发送到graylog?

如何将日志信息从Android应用发送到服务器?

如何将日志从本地服务器发送到AWS Cloudwatch?

Kafka-无法使用Java将消息发送到远程服务器

将文件/目录从本地 unix 机器发送到远程 unix 服务器

使用PSFTP将文件发送到远程服务器

使用套接字将数据发送到远程服务器

使用jsonp将数据发送到远程服务器

Python脚本未从crontab将数据库日志发送到服务器

如何使用 NativeScript 3 捕获图像并发送到远程服务器

如何使用libCurl将访问令牌发送到服务器API

将POST请求发送到服务器,服务器的响应为空,Angular-Spring-boot

如何自动将图像发送到服务器?