[go: nahoru, domu]

Skip to content

Commit

Permalink
logger refactored to use slf4j and lazy message constructing
Browse files Browse the repository at this point in the history
  • Loading branch information
skarpenko committed Mar 2, 2018
1 parent d4dee89 commit 56431fe
Show file tree
Hide file tree
Showing 9 changed files with 165 additions and 103 deletions.
23 changes: 10 additions & 13 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,16 @@
<version>${feign.version}</version>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>

<!-- Tests -->
<dependency>
<groupId>junit</groupId>
Expand Down Expand Up @@ -145,19 +155,6 @@
<scope>test</scope>
</dependency>

<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-slf4j</artifactId>
<version>${feign.version}</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j-log4j12.version}</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down
32 changes: 14 additions & 18 deletions src/main/java/feign/ReactiveFeign.java
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,10 @@ public <T> T newInstance(Target<T> target) {
public static final class Builder extends Feign.Builder {
private final List<RequestInterceptor> requestInterceptors =
new ArrayList<>();
private Logger.Level logLevel = Logger.Level.NONE;
private Contract contract =
new ReactiveDelegatingContract(new Contract.Default());
private WebClient webClient;
private ReactiveRetryer retryer = new ReactiveRetryer.Default();
private Logger logger = new Logger.NoOpLogger();
private Encoder encoder = new Encoder.Default();
private ErrorDecoder errorDecoder = new ErrorDecoder.Default();
private InvocationHandlerFactory invocationHandlerFactory =
Expand Down Expand Up @@ -122,8 +120,19 @@ public Builder webClient(final WebClient webClient) {
*/
@Override
public Builder logLevel(final Logger.Level logLevel) {
this.logLevel = logLevel;
return this;
throw new UnsupportedOperationException("Don't need it anymore");
}

/**
* Sets logger.
*
* @param logger logger
*
* @return this builder
*/
@Override
public Builder logger(final Logger logger) {
throw new UnsupportedOperationException("Don't need it anymore, slf4j used instead");
}

/**
Expand Down Expand Up @@ -157,19 +166,6 @@ public Builder retryer(final ReactiveRetryer retryer) {
return this;
}

/**
* Sets logger.
*
* @param logger logger
*
* @return this builder
*/
@Override
public Builder logger(final Logger logger) {
this.logger = logger;
return this;
}

/**
* Sets encoder.
*
Expand Down Expand Up @@ -312,7 +308,7 @@ public ReactiveFeign build() {

final ReactiveMethodHandler.Factory methodHandlerFactory =
new ReactiveMethodHandler.Factory(webClient, retryer,
requestInterceptors, logger, logLevel, decode404);
requestInterceptors, new feign.reactive.Logger(), decode404);
final ParseHandlersByName handlersByName = new ParseHandlersByName(
contract, encoder, errorDecoder,
methodHandlerFactory);
Expand Down
99 changes: 41 additions & 58 deletions src/main/java/feign/ReactiveMethodHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.Exceptions;
import reactor.core.publisher.Flux;
Expand All @@ -26,26 +25,25 @@
import static feign.Util.checkNotNull;
import static feign.Util.resolveLastTypeParameter;
import static org.springframework.http.HttpStatus.NOT_FOUND;
import static reactor.core.publisher.Mono.just;

/**
* Method handler for asynchronous HTTP requests via {@link WebClient}.
* Inspired by {@link SynchronousMethodHandler}.
*
* @author Sergii Karpenko
*/
class ReactiveMethodHandler
public class ReactiveMethodHandler
implements MethodHandler {

private final MethodMetadata metadata;
private final String methodTag;
private final Type returnPublisherType;
private final ParameterizedTypeReference<?> returnActualType;
private final Target<?> target;
private final WebClient client;
private final ReactiveRetryer retryer;
private final List<RequestInterceptor> requestInterceptors;
private final Logger logger;
private final Logger.Level logLevel;
private final feign.reactive.Logger logger;
private final Function<Object[], RequestTemplate> buildTemplateFromArgs;
private final ErrorDecoder errorDecoder;
private final boolean decode404;
Expand All @@ -55,8 +53,7 @@ private ReactiveMethodHandler(
WebClient client,
ReactiveRetryer retryer,
List<RequestInterceptor> requestInterceptors,
Logger logger,
Logger.Level logLevel,
feign.reactive.Logger logger,
MethodMetadata metadata,
Function<Object[], RequestTemplate> buildTemplateFromArgs,
ErrorDecoder errorDecoder,
Expand All @@ -68,8 +65,6 @@ private ReactiveMethodHandler(
"requestInterceptors for %s must be not null", target);
this.logger = checkNotNull(logger,
"logger for %s must be not null", target);
this.logLevel = checkNotNull(logLevel,
"logLevel for %s must be not null", target);
this.metadata = checkNotNull(metadata,
"metadata for %s must be not null", target);
this.buildTemplateFromArgs = checkNotNull(buildTemplateFromArgs,
Expand All @@ -78,6 +73,8 @@ private ReactiveMethodHandler(
"errorDecoder for %s must be not null", target);
this.decode404 = decode404;

this.methodTag = metadata.configKey().substring(0, metadata.configKey().indexOf('('));

final Type returnType = metadata.returnType();
returnPublisherType = ((ParameterizedType) returnType).getRawType();
returnActualType = ParameterizedTypeReference.forType(
Expand All @@ -100,8 +97,9 @@ public Publisher invoke(final Object[] argv) throws Throwable {
*/
private Publisher executeAndDecode(final RequestTemplate template) {
final Request request = targetRequest(template);
logRequest(request);
logger.logRequest(methodTag, request);

long start = System.currentTimeMillis();
WebClient.ResponseSpec response = client.method(HttpMethod.resolve(request.method()))
.uri(request.url())
.headers(httpHeaders -> request.headers().forEach(
Expand All @@ -111,29 +109,48 @@ private Publisher executeAndDecode(final RequestTemplate template) {
.onStatus( httpStatus -> decode404 && httpStatus == NOT_FOUND,
clientResponse -> null)
.onStatus(HttpStatus::isError,
clientResponse -> just(errorDecoder.decode(metadata.configKey(),
Response.create(
clientResponse.statusCode().value(),
clientResponse.statusCode().getReasonPhrase(),
clientResponse.headers().asHttpHeaders().entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)),
extractBodyContent(clientResponse)))));
clientResponse -> clientResponse.bodyToMono(ByteArrayResource.class)
.map(ByteArrayResource::getByteArray)
.defaultIfEmpty(new byte[0])
.map(bodyData -> errorDecoder.decode(metadata.configKey(),
Response.create(
clientResponse.statusCode().value(),
clientResponse.statusCode().getReasonPhrase(),
clientResponse.headers().asHttpHeaders().entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)),
bodyData)))

)
.onStatus(httpStatus -> true, clientResponse -> {
logger.logResponseHeaders(methodTag, clientResponse.headers().asHttpHeaders());
return null;
});

if (returnPublisherType == Mono.class){
return response.bodyToMono(returnActualType).retryWhen(whenFactory());
return response.bodyToMono(returnActualType)
.retryWhen(whenFactory())
.map(result -> {
logger.logResponse(methodTag, result, System.currentTimeMillis() - start);
return result;
});

} else {
return response.bodyToFlux(returnActualType).retryWhen(whenFactory());
return response.bodyToFlux(returnActualType)
.retryWhen(whenFactory())
.map(result -> {
logger.logResponse(methodTag, result, System.currentTimeMillis() - start);
return result;
});
}
}

protected Function<Flux<Throwable>, Publisher<?>> whenFactory() {
final ReactiveRetryer retryerFinal = retryer.clone();
return companion ->
companion.flatMap(error -> {
return companion -> companion.flatMap(
error -> {
long delay = retryerFinal.doRetryIn(error);
if(delay >= 0){
logRetry();
logger.logRetry(methodTag);
return Mono.delay(Duration.ofMillis(delay));
} else {
throw Exceptions.propagate(error);
Expand All @@ -155,57 +172,24 @@ private Request targetRequest(final RequestTemplate template) {
return target.apply(new RequestTemplate(template));
}

/**
* Logs request.
*
* @param request HTTP request
*/
private void logRequest(final Request request) {
if (logLevel != Logger.Level.NONE) {
logger.logRequest(metadata.configKey(), logLevel, request);
}
}

/**
* Logs retry.
*/
private void logRetry() {
if (logLevel != Logger.Level.NONE) {
logger.logRetry(metadata.configKey(), logLevel);
}
}

private static byte[] extractBodyContent(ClientResponse clientResponse) {
try {
return clientResponse.bodyToMono(ByteArrayResource.class)
.blockOptional(Duration.ZERO)
.map(ByteArrayResource::getByteArray).orElse(null);
} catch (Throwable e){
return null;
}
}

static class Factory {
private final WebClient client;
private final ReactiveRetryer retryer;
private final List<RequestInterceptor> requestInterceptors;
private final Logger logger;
private final Logger.Level logLevel;
private final feign.reactive.Logger logger;
private final boolean decode404;

Factory(
final WebClient client,
final ReactiveRetryer retryer,
final List<RequestInterceptor> requestInterceptors,
final Logger logger,
final Logger.Level logLevel,
final feign.reactive.Logger logger,
final boolean decode404) {
this.client = checkNotNull(client, "client must not be null");
this.retryer = checkNotNull(retryer, "retryer must not be null");
this.requestInterceptors = checkNotNull(requestInterceptors,
"requestInterceptors must not be null");
this.logger = checkNotNull(logger, "logger must not be null");
this.logLevel = checkNotNull(logLevel, "logLevel must not be null");
this.decode404 = decode404;
}

Expand All @@ -220,7 +204,6 @@ MethodHandler create(
retryer,
requestInterceptors,
logger,
logLevel,
metadata,
buildTemplateFromArgs,
errorDecoder,
Expand Down
Loading

0 comments on commit 56431fe

Please sign in to comment.