🚧 Improved access log
This commit is contained in:
parent
04f1ccffcb
commit
f7895cf961
@ -1,8 +1,10 @@
|
|||||||
package dev.dinauer.oidcproxy;
|
package dev.dinauer.oidcproxy;
|
||||||
|
|
||||||
import dev.dinauer.oidcproxy.callback.CallbackService;
|
import dev.dinauer.oidcproxy.callback.CallbackService;
|
||||||
|
import dev.dinauer.oidcproxy.proxy.AccessLog;
|
||||||
import dev.dinauer.oidcproxy.proxy.ForwardService;
|
import dev.dinauer.oidcproxy.proxy.ForwardService;
|
||||||
import dev.dinauer.oidcproxy.proxy.ResponseHandler;
|
import dev.dinauer.oidcproxy.proxy.ResponseHandler;
|
||||||
|
import dev.dinauer.oidcproxy.proxy.TimedHttpResponse;
|
||||||
import dev.dinauer.oidcproxy.proxy.exception.ProxyHttpException;
|
import dev.dinauer.oidcproxy.proxy.exception.ProxyHttpException;
|
||||||
import dev.dinauer.oidcproxy.proxy.exception.TokenNotFoundException;
|
import dev.dinauer.oidcproxy.proxy.exception.TokenNotFoundException;
|
||||||
import dev.dinauer.oidcproxy.startup.PathConverter;
|
import dev.dinauer.oidcproxy.startup.PathConverter;
|
||||||
@ -38,6 +40,9 @@ public class Resource
|
|||||||
@Inject
|
@Inject
|
||||||
LogoutService logoutService;
|
LogoutService logoutService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
AccessLog accessLog;
|
||||||
|
|
||||||
@Route(path = "/auth/callback", order = 0)
|
@Route(path = "/auth/callback", order = 0)
|
||||||
@Blocking
|
@Blocking
|
||||||
public void callback(@Context RoutingContext context)
|
public void callback(@Context RoutingContext context)
|
||||||
@ -72,16 +77,16 @@ public class Resource
|
|||||||
private void route(RoutingContext context, String path, ProxyRoute route)
|
private void route(RoutingContext context, String path, ProxyRoute route)
|
||||||
{
|
{
|
||||||
List<String> requestSegments = PathConverter.toSegments(path);
|
List<String> requestSegments = PathConverter.toSegments(path);
|
||||||
LOG.info("Matched route with target '{}'", route.target());
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
String targetURI = route.target() + PathConverter.toPath(requestSegments);
|
String targetURI = route.target() + PathConverter.toPath(requestSegments);
|
||||||
HttpResponse<byte[]> response = forwardService.send(context, targetURI, route.strategy());
|
TimedHttpResponse<byte[]> response = forwardService.send(context, targetURI, route.strategy());
|
||||||
ResponseHandler.success(context, response);
|
accessLog.log(AccessLog.Type.INFO, context, PathConverter.toPath(requestSegments), route.target(), response.response().statusCode(), response.time());
|
||||||
|
ResponseHandler.success(context, response.response());
|
||||||
}
|
}
|
||||||
catch (ProxyHttpException e)
|
catch (ProxyHttpException e)
|
||||||
{
|
{
|
||||||
LOG.error("Upstream returned error status {}.", e.getStatusCode(), e);
|
accessLog.log(AccessLog.Type.ERROR, context, PathConverter.toPath(requestSegments), route.target(), e.getStatusCode(), e.getTime());
|
||||||
ResponseHandler.error(context, e.getStatusCode());
|
ResponseHandler.error(context, e.getStatusCode());
|
||||||
}
|
}
|
||||||
catch (TokenNotFoundException e)
|
catch (TokenNotFoundException e)
|
||||||
@ -97,7 +102,7 @@ public class Resource
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
LOG.error("Error occurred on upstream.", e);
|
accessLog.logUpstream(context, PathConverter.toPath(requestSegments), route.target());
|
||||||
ResponseHandler.error(context, 502);
|
ResponseHandler.error(context, 502);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
41
src/main/java/dev/dinauer/oidcproxy/proxy/AccessLog.java
Normal file
41
src/main/java/dev/dinauer/oidcproxy/proxy/AccessLog.java
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
package dev.dinauer.oidcproxy.proxy;
|
||||||
|
|
||||||
|
import dev.dinauer.oidcproxy.startup.PathConverter;
|
||||||
|
import io.vertx.ext.web.RoutingContext;
|
||||||
|
import jakarta.enterprise.context.ApplicationScoped;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
@ApplicationScoped
|
||||||
|
public class AccessLog
|
||||||
|
{
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(AccessLog.class);
|
||||||
|
|
||||||
|
public void log(Type type, RoutingContext context, String request, String target, int statusCode, long time)
|
||||||
|
{
|
||||||
|
String log = String.format("[%s] [%s %s] %s - %s - %sms", context.request().remoteAddress().host(), context.request().method().toString().toUpperCase(), request, target, statusCode, time);
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case INFO ->
|
||||||
|
{
|
||||||
|
LOG.info(log);
|
||||||
|
}
|
||||||
|
case ERROR ->
|
||||||
|
{
|
||||||
|
LOG.error(log);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void logUpstream(RoutingContext context, String request, String target)
|
||||||
|
{
|
||||||
|
String log = String.format("[%s] [%s %s] %s - UPSTREAM ERROR", context.request().remoteAddress().host(), context.request().method().toString().toUpperCase(), request, target);
|
||||||
|
LOG.error(log);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public enum Type
|
||||||
|
{
|
||||||
|
INFO, ERROR
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -23,7 +23,7 @@ public class ForwardService
|
|||||||
@Inject
|
@Inject
|
||||||
HeaderFilter headerFilter;
|
HeaderFilter headerFilter;
|
||||||
|
|
||||||
public HttpResponse<byte[]> send(RoutingContext context, String route, String strategy) throws IOException, InterruptedException, ProxyHttpException, TokenNotFoundException
|
public TimedHttpResponse<byte[]> send(RoutingContext context, String route, String strategy) throws IOException, InterruptedException, ProxyHttpException, TokenNotFoundException
|
||||||
{
|
{
|
||||||
HttpRequestBuilder builder = HttpRequestBuilder.create();
|
HttpRequestBuilder builder = HttpRequestBuilder.create();
|
||||||
builder.setUri(route);
|
builder.setUri(route);
|
||||||
@ -32,12 +32,16 @@ public class ForwardService
|
|||||||
builder.setHeaders(headerFilter.filter(context.request(), strategy));
|
builder.setHeaders(headerFilter.filter(context.request(), strategy));
|
||||||
builder.setBody(extractBody(context));
|
builder.setBody(extractBody(context));
|
||||||
|
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
HttpResponse<byte[]> response = CLIENT.send(builder.build(), HttpResponse.BodyHandlers.ofByteArray());
|
HttpResponse<byte[]> response = CLIENT.send(builder.build(), HttpResponse.BodyHandlers.ofByteArray());
|
||||||
|
long end = System.currentTimeMillis();
|
||||||
|
|
||||||
|
long time = end - start;
|
||||||
if (response.statusCode() < 400)
|
if (response.statusCode() < 400)
|
||||||
{
|
{
|
||||||
return response;
|
return new TimedHttpResponse<>(time, response);
|
||||||
}
|
}
|
||||||
throw new ProxyHttpException(response.statusCode());
|
throw new ProxyHttpException(time, response.statusCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] extractBody(RoutingContext context)
|
private byte[] extractBody(RoutingContext context)
|
||||||
|
|||||||
@ -0,0 +1,7 @@
|
|||||||
|
package dev.dinauer.oidcproxy.proxy;
|
||||||
|
|
||||||
|
import java.net.http.HttpResponse;
|
||||||
|
|
||||||
|
public record TimedHttpResponse<T>(long time, HttpResponse<T> response)
|
||||||
|
{
|
||||||
|
}
|
||||||
@ -2,13 +2,20 @@ package dev.dinauer.oidcproxy.proxy.exception;
|
|||||||
|
|
||||||
public class ProxyHttpException extends Exception
|
public class ProxyHttpException extends Exception
|
||||||
{
|
{
|
||||||
|
private final long time;
|
||||||
private final int statusCode;
|
private final int statusCode;
|
||||||
|
|
||||||
public ProxyHttpException(int statusCode)
|
public ProxyHttpException(long time, int statusCode)
|
||||||
{
|
{
|
||||||
|
this.time = time;
|
||||||
this.statusCode = statusCode;
|
this.statusCode = statusCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long getTime()
|
||||||
|
{
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
|
||||||
public int getStatusCode()
|
public int getStatusCode()
|
||||||
{
|
{
|
||||||
return statusCode;
|
return statusCode;
|
||||||
|
|||||||
@ -10,10 +10,14 @@ import java.net.http.HttpRequest;
|
|||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class HttpRequestBuilder
|
public class HttpRequestBuilder
|
||||||
{
|
{
|
||||||
|
private static final Set<String> DISALLOWED_HEADERS = Set.of("connection", "content-length", "expect", "host", "upgrade");
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(HttpRequestBuilder.class);
|
private static final Logger LOG = LoggerFactory.getLogger(HttpRequestBuilder.class);
|
||||||
|
|
||||||
private String method;
|
private String method;
|
||||||
@ -57,20 +61,11 @@ public class HttpRequestBuilder
|
|||||||
HttpRequest.Builder builder = HttpRequest.newBuilder();
|
HttpRequest.Builder builder = HttpRequest.newBuilder();
|
||||||
builder.uri(buildURI(this.uri, this.params));
|
builder.uri(buildURI(this.uri, this.params));
|
||||||
builder.method(method, buildBody(body));
|
builder.method(method, buildBody(body));
|
||||||
|
for (Map.Entry<String, String> element : Optional.ofNullable(this.headers).orElse(List.of()))
|
||||||
if (this.headers != null)
|
|
||||||
{
|
{
|
||||||
for (Map.Entry<String, String> element : this.headers)
|
if (!DISALLOWED_HEADERS.contains(element.getKey()))
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
builder.setHeader(element.getKey(), element.getValue());
|
builder.setHeader(element.getKey(), element.getValue());
|
||||||
LOG.info("added header " + element.getKey());
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
LOG.info("Failed to add header.", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return builder.build();
|
return builder.build();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user