All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.netflix.netty.common.accesslog.AccessLogPublisher Maven / Gradle / Ivy

There is a newer version: 2.5.13
Show newest version
/*
 * Copyright 2018 Netflix, Inc.
 *
 *      Licensed under the Apache License, Version 2.0 (the "License");
 *      you may not use this file except in compliance with the License.
 *      You may obtain a copy of the License at
 *
 *          http://www.apache.org/licenses/LICENSE-2.0
 *
 *      Unless required by applicable law or agreed to in writing, software
 *      distributed under the License is distributed on an "AS IS" BASIS,
 *      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *      See the License for the specific language governing permissions and
 *      limitations under the License.
 */

package com.netflix.netty.common.accesslog;

import com.netflix.config.DynamicIntProperty;
import com.netflix.config.DynamicStringListProperty;
import io.netty.channel.Channel;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponse;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.function.BiFunction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class AccessLogPublisher {
    private static final char DELIM = '\t';
    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ISO_LOCAL_DATE_TIME;

    private static final List LOG_REQ_HEADERS = new DynamicStringListProperty(
                    "zuul.access.log.requestheaders",
                    "host,x-forwarded-for,x-forwarded-proto,x-forwarded-host,x-forwarded-port,user-agent")
            .get();
    private static final List LOG_RESP_HEADERS =
            new DynamicStringListProperty("zuul.access.log.responseheaders", "server,via,content-type").get();
    private static final DynamicIntProperty URI_LENGTH_LIMIT =
            new DynamicIntProperty("zuul.access.log.uri.length.limit", Integer.MAX_VALUE);

    private final Logger logger;
    private final BiFunction requestIdProvider;

    private static final Logger LOG = LoggerFactory.getLogger(AccessLogPublisher.class);

    public AccessLogPublisher(String loggerName, BiFunction requestIdProvider) {
        this.logger = LoggerFactory.getLogger(loggerName);
        this.requestIdProvider = requestIdProvider;
    }

    public void log(
            Channel channel,
            HttpRequest request,
            HttpResponse response,
            LocalDateTime dateTime,
            Integer localPort,
            String remoteIp,
            Long durationNs,
            Integer requestBodySize,
            Integer responseBodySize) {
        StringBuilder sb = new StringBuilder();

        String dateTimeStr = dateTime != null ? dateTime.format(DATE_TIME_FORMATTER) : "-----T-:-:-";
        String remoteIpStr = (remoteIp != null && !remoteIp.isEmpty()) ? remoteIp : "-";
        String port = localPort != null ? localPort.toString() : "-";
        String method = request != null ? request.method().toString().toUpperCase() : "-";
        String uri = request != null ? request.uri() : "-";
        if (uri.length() > URI_LENGTH_LIMIT.get()) {
            uri = uri.substring(0, URI_LENGTH_LIMIT.get());
        }
        String status = response != null ? String.valueOf(response.status().code()) : "-";

        String requestId = null;
        try {
            requestId = requestIdProvider.apply(channel, request);
        } catch (Exception ex) {
            LOG.error(
                    "requestIdProvider failed in AccessLogPublisher method={}, uri={}, status={}", method, uri, status);
        }
        requestId = requestId != null ? requestId : "-";

        // Convert duration to microseconds.
        String durationStr = (durationNs != null && durationNs > 0) ? String.valueOf(durationNs / 1000) : "-";

        String requestBodySizeStr = (requestBodySize != null && requestBodySize > 0) ? requestBodySize.toString() : "-";
        String responseBodySizeStr =
                (responseBodySize != null && responseBodySize > 0) ? responseBodySize.toString() : "-";

        // Build the line.
        sb.append(dateTimeStr)
                .append(DELIM)
                .append(remoteIpStr)
                .append(DELIM)
                .append(port)
                .append(DELIM)
                .append(method)
                .append(DELIM)
                .append(uri)
                .append(DELIM)
                .append(status)
                .append(DELIM)
                .append(durationStr)
                .append(DELIM)
                .append(responseBodySizeStr)
                .append(DELIM)
                .append(requestId)
                .append(DELIM)
                .append(requestBodySizeStr);

        if (request != null && request.headers() != null) {
            includeMatchingHeaders(sb, LOG_REQ_HEADERS, request.headers());
        }

        if (response != null && response.headers() != null) {
            includeMatchingHeaders(sb, LOG_RESP_HEADERS, response.headers());
        }

        // Write to logger.
        final String access = sb.toString();
        logger.info(access);
        LOG.debug(access);
    }

    void includeMatchingHeaders(StringBuilder builder, List requiredHeaders, HttpHeaders headers) {
        for (String headerName : requiredHeaders) {
            String value = headerAsString(headers, headerName);
            builder.append(DELIM).append('\"').append(value).append('\"');
        }
    }

    String headerAsString(HttpHeaders headers, String headerName) {
        List values = headers.getAll(headerName);
        return (values.size() == 0) ? "-" : String.join(",", values);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy