@Override
    public String formatRequest(RequestOnlyLog log) {
        requireNonNull(log, "log");

        final int flags = log.availabilityStamp();
        final RequestContext ctx = log.context();
        if (!RequestLogProperty.REQUEST_START_TIME.isAvailable(flags)) {
            if (includeContext) {
                return ctx + " Request: {}";
            } else {
                return "Request: {}";
            }
        }

        String requestCauseString = null;
        if (RequestLogProperty.REQUEST_CAUSE.isAvailable(flags)) {
            final Throwable cause = log.requestCause();
            if (cause != null) {
                requestCauseString = cause.toString();
            }
        }

        final String sanitizedHeaders;
        if (RequestLogProperty.REQUEST_HEADERS.isAvailable(flags)) {
            sanitizedHeaders = requestHeadersSanitizer.apply(ctx, log.requestHeaders());
        } else {
            sanitizedHeaders = null;
        }

        String sanitizedPreview = null;
        if (RequestLogProperty.REQUEST_CONTENT_PREVIEW.isAvailable(flags)) {
            final String contentPreview = log.requestContentPreview();
            if (contentPreview != null) {
                sanitizedPreview = requestContentSanitizer.apply(ctx, contentPreview);
            }
        }
        String sanitizedContent = null;
        if (RequestLogProperty.REQUEST_CONTENT.isAvailable(flags)) {
            final Object content = log.requestContent();
            if (content != null) {
                sanitizedContent = requestContentSanitizer.apply(ctx, content);
            }
        }

        final String sanitizedTrailers;
        if (RequestLogProperty.REQUEST_TRAILERS.isAvailable(flags) &&
            !log.requestTrailers().isEmpty()) {
            sanitizedTrailers = requestTrailersSanitizer.apply(ctx, log.requestTrailers());
        } else {
            sanitizedTrailers = null;
        }

        final String ctxString;
        if (includeContext) {
            // ctx internally uses TemporaryThreadLocals, so we should call ctx.toString() outside of acquire().
            ctxString = ctx.toString() + ' ';
        } else {
            ctxString = null;
        }

        try (TemporaryThreadLocals tempThreadLocals = TemporaryThreadLocals.acquire()) {
            final StringBuilder buf = tempThreadLocals.stringBuilder();
            if (ctxString != null) {
                buf.append(ctxString);
            }
            buf.append("Request: {startTime=");
            TextFormatter.appendEpochMicros(buf, log.requestStartTimeMicros());

            if (RequestLogProperty.SESSION.isAvailable(flags)) {
                maybeAppendConnectionTimings(log.connectionTimings(), buf);
            }

            if (RequestLogProperty.REQUEST_LENGTH.isAvailable(flags)) {
                buf.append(", length=");
                TextFormatter.appendSize(buf, log.requestLength());
            }

            if (RequestLogProperty.REQUEST_END_TIME.isAvailable(flags)) {
                buf.append(", duration=");
                TextFormatter.appendElapsed(buf, log.requestDurationNanos());
            }

            if (requestCauseString != null) {
                buf.append(", cause=").append(requestCauseString);
            }

            buf.append(", scheme=");
            if (RequestLogProperty.SCHEME.isAvailable(flags)) {
                buf.append(log.scheme().uriText());
            } else if (RequestLogProperty.SESSION.isAvailable(flags)) {
                buf.append(SerializationFormat.UNKNOWN.uriText())
                   .append('+')
                   .append(log.sessionProtocol());
            } else {
                buf.append(SerializationFormat.UNKNOWN.uriText())
                   .append('+')
                   .append("unknown");
            }

            if (RequestLogProperty.NAME.isAvailable(flags)) {
                buf.append(", name=").append(log.name());
            }

            if (sanitizedHeaders != null) {
                buf.append(", headers=").append(sanitizedHeaders);
            }

            if (sanitizedPreview != null) {
                buf.append(", preview=").append(sanitizedPreview);
            }

            if (sanitizedContent != null) {
                buf.append(", content=").append(sanitizedContent);
            }

            if (sanitizedTrailers != null) {
                buf.append(", trailers=").append(sanitizedTrailers);
            }

            final int currentAttempt = log.currentAttempt();
            if (currentAttempt > 0) {
                buf.append(", currentAttempt=").append(currentAttempt);
            }
            buf.append('}');
            return buf.toString();
        }
    }
A formatter that converts {@link RequestOnlyLog} or {@link RequestLog} into text message.
core/src/main/java/com/linecorp/armeria/common/logging/TextLogFormatter.java