Как отправить журналы весенней загрузки на удаленный сервер через GELF?

Для наших весенних загрузочных приложений мы используем logback + GELF для отправки журналов приложений на наш центральный сервер журналов, где мы можем их анализировать. Можно ли сделать то же самое с журналом доступа весенней загрузки?

А если нет, то есть ли другие предложения или рекомендации по сбору журналов доступа из нескольких приложений весенней загрузки на центральном сервере?

1 ответ

Решение

ОК, я узнал после некоторых исследований. Вам нужно добавить пользовательский клапан в 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. Поэтому вам нужно добавить эту зависимость в ваш 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;
    }
}
Другие вопросы по тегам