/*
* Copyright 2013-2017 the original author or authors.
*
* 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 org.cloudfoundry.reactor.util;
import org.cloudfoundry.util.TimeUtils;
import org.reactivestreams.Subscription;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.publisher.Mono;
import reactor.ipc.netty.http.client.HttpClientResponse;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
public final class NetworkLogging {
static final Logger RESPONSE_LOGGER = LoggerFactory.getLogger("cloudfoundry-client.response");
private static final String CF_WARNINGS = "X-Cf-Warnings";
private static final Logger REQUEST_LOGGER = LoggerFactory.getLogger("cloudfoundry-client.request");
private NetworkLogging() {
}
public static Consumer<Subscription> delete(String uri) {
return s -> REQUEST_LOGGER.debug("DELETE {}", uri);
}
public static Consumer<Subscription> get(String uri) {
return s -> REQUEST_LOGGER.debug("GET {}", uri);
}
public static Consumer<Subscription> patch(String uri) {
return s -> REQUEST_LOGGER.debug("PATCH {}", uri);
}
public static Consumer<Subscription> post(String uri) {
return s -> REQUEST_LOGGER.debug("POST {}", uri);
}
public static Consumer<Subscription> put(String uri) {
return s -> REQUEST_LOGGER.debug("PUT {}", uri);
}
public static Function<Mono<HttpClientResponse>, Mono<HttpClientResponse>> response(String uri) {
if (!RESPONSE_LOGGER.isDebugEnabled()) {
return inbound -> inbound;
}
AtomicLong startTimeHolder = new AtomicLong();
AtomicReference<HttpClientResponse> responseHolder = new AtomicReference<>();
return inbound -> inbound
.doOnSubscribe(s -> startTimeHolder.set(System.currentTimeMillis()))
.doOnNext(responseHolder::set)
.doFinally(signalType -> {
String elapsed = TimeUtils.asTime(System.currentTimeMillis() - startTimeHolder.get());
Optional.ofNullable(responseHolder.get())
.ifPresent(response -> {
List<String> warnings = response.responseHeaders().getAll(CF_WARNINGS);
if (warnings.isEmpty()) {
RESPONSE_LOGGER.debug("{} {} ({})", response.status().code(), uri, elapsed);
} else {
RESPONSE_LOGGER.warn("{} {} ({}) [{}]", response.status().code(), uri, elapsed, warnings.stream().collect(Collectors.joining(", ")));
}
});
});
}
public static Consumer<Subscription> ws(String uri) {
return s -> REQUEST_LOGGER.debug("WS {}", uri);
}
}