Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consolidate rerouted requests in access log #39267

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions docs/src/main/asciidoc/http-reference.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -439,12 +439,27 @@
|Request header | | `%{i,request_header_name}`
|Response header | | `%{o,response_header_name}`
|Vert.x Routing Context Internal Data | | `%{d,map_key}`
|Vert.x MDC data (e.g. 'traceId' for OpenTelemetry) | | `%{X,mdc-key}`

Check warning on line 442 in docs/src/main/asciidoc/http-reference.adoc

View workflow job for this annotation

GitHub Actions / Linting with Vale

[vale] reported by reviewdog 🐶 [Quarkus.Spelling] Use correct American English spelling. Did you really mean 'traceId'? Raw Output: {"message": "[Quarkus.Spelling] Use correct American English spelling. Did you really mean 'traceId'?", "location": {"path": "docs/src/main/asciidoc/http-reference.adoc", "range": {"start": {"line": 442, "column": 25}}}, "severity": "WARNING"}
|===

Set `quarkus.http.access-log.consolidate-rerouted-requests=true` to enable support for the modifier `<`. This modifier can be used for requests that have been internally redirected to consult the original request.
The following attributes support this modifier:


[frame="topbot",options="header"]
|===
|Attribute |Short Form|Long Form
|First line of the request | `%<r` | `%{<REQUEST_LINE}`
|Request method | `%<m` | `%{<METHOD}`
|Request relative path | `%<R` | `%{<REQUEST_PATH}`
|Requested URL path | `%<U` | `%{<REQUEST_URL}`
|Query string (prepended with a '?' if it exists, otherwise an empty string) | `%<q` | `%{<QUERY_STRING}`
|Query parameter | | `%{<q,query_param_name}`
|===

[NOTE]
====
Set `quarkus.http.record-request-start-time=true` to enable recording request start times when using any of the attributes related to logging request processing times.

Check warning on line 462 in docs/src/main/asciidoc/http-reference.adoc

View workflow job for this annotation

GitHub Actions / Linting with Vale

[vale] reported by reviewdog 🐶 [Quarkus.TermsSuggestions] Depending on the context, consider using 'by using' or 'that uses' rather than 'using'. Raw Output: {"message": "[Quarkus.TermsSuggestions] Depending on the context, consider using 'by using' or 'that uses' rather than 'using'.", "location": {"path": "docs/src/main/asciidoc/http-reference.adoc", "range": {"start": {"line": 462, "column": 95}}}, "severity": "INFO"}
====

[NOTE]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,10 @@ public class AccessLogConfig {
@ConfigItem(defaultValue = "true")
public boolean rotate;

/**
* If rerouted requests should be consolidated into one log entry
*/
@ConfigItem(defaultValue = "false")
public boolean consolidateReroutedRequests;

}
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,8 @@ public void handle(RoutingContext event) {
} else {
receiver = new JBossLoggingAccessLogReceiver(accessLog.category);
}
AccessLogHandler handler = new AccessLogHandler(receiver, accessLog.pattern, getClass().getClassLoader(),
AccessLogHandler handler = new AccessLogHandler(receiver, accessLog.pattern, accessLog.consolidateReroutedRequests,
getClass().getClassLoader(),
accessLog.excludePattern);
if (rootPath.equals("/") || nonRootPath.equals("/")) {
mainRouterRuntimeValue.orElse(httpRouterRuntimeValue).getValue().route()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public int compare(ExchangeAttributeBuilder o1, ExchangeAttributeBuilder o2) {
* <p>
* Tokens are created according to the following rules:
* <p>
* %a - % followed by single character. %% is an escape for a literal %
* %<?a - % followed by an optional < and a single character. %% is an escape for a literal %
* %{.*}a? - % plus curly braces with any amount of content inside, followed by an optional character
* ${.*} - $ followed by a curly braces to reference an item from the predicate context
*
Expand All @@ -59,7 +59,7 @@ public int compare(ExchangeAttributeBuilder o1, ExchangeAttributeBuilder o2) {
public ExchangeAttribute parse(final String valueString) {
final List<ExchangeAttribute> attributes = new ArrayList<>();
int pos = 0;
int state = 0; //0 = literal, 1 = %, 2 = %{, 3 = $, 4 = ${
int state = 0; //0 = literal, 1 = %, 2 = %{, 3 = $, 4 = ${, 5 = %<
for (int i = 0; i < valueString.length(); ++i) {
char c = valueString.charAt(i);
switch (state) {
Expand All @@ -80,6 +80,8 @@ public ExchangeAttribute parse(final String valueString) {
case 1: {
if (c == '{') {
state = 2;
} else if (c == '<') {
state = 5;
} else if (c == '%') {
//literal percent
attributes.add(wrap(new ConstantExchangeAttribute("%")));
Expand Down Expand Up @@ -123,13 +125,20 @@ public ExchangeAttribute parse(final String valueString) {
}
break;
}
case 5: {
attributes.add(wrap(parseSingleToken(valueString.substring(pos, i + 1))));
pos = i + 1;
state = 0;
break;
}

}
}
switch (state) {
case 0:
case 1:
case 3: {
case 3:
case 5: {
if (pos != valueString.length()) {
attributes.add(wrap(parseSingleToken(valueString.substring(pos))));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.util.ArrayDeque;
import java.util.List;

import io.quarkus.vertx.http.runtime.filters.OriginalRequestContext;
import io.vertx.ext.web.RoutingContext;

/**
Expand All @@ -11,14 +12,17 @@
public class QueryParameterAttribute implements ExchangeAttribute {

private final String parameter;
private final boolean useOriginalRequest;

public QueryParameterAttribute(String parameter) {
public QueryParameterAttribute(String parameter, boolean useOriginalRequest) {
this.parameter = parameter;
this.useOriginalRequest = useOriginalRequest;
}

@Override
public String readAttribute(final RoutingContext exchange) {
List<String> res = exchange.queryParams().getAll(parameter);
List<String> res = useOriginalRequest ? OriginalRequestContext.getAllQueryParams(exchange, parameter)
: exchange.queryParams().getAll(parameter);
if (res == null) {
return null;
} else if (res.isEmpty()) {
Expand Down Expand Up @@ -57,7 +61,11 @@ public String name() {
public ExchangeAttribute build(final String token) {
if (token.startsWith("%{q,") && token.endsWith("}")) {
final String qp = token.substring(4, token.length() - 1);
return new QueryParameterAttribute(qp);
return new QueryParameterAttribute(qp, false);
}
if (token.startsWith("%{<q,") && token.endsWith("}")) {
final String qp = token.substring(5, token.length() - 1);
return new QueryParameterAttribute(qp, true);
}
return null;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.quarkus.vertx.http.runtime.attribute;

import io.quarkus.vertx.http.runtime.filters.OriginalRequestContext;
import io.vertx.ext.web.RoutingContext;

/**
Expand All @@ -11,19 +12,26 @@ public class QueryStringAttribute implements ExchangeAttribute {
public static final String QUERY_STRING_SHORT = "%q";
public static final String QUERY_STRING = "%{QUERY_STRING}";
public static final String BARE_QUERY_STRING = "%{BARE_QUERY_STRING}";
public static final String ORIGINAL_QUERY_STRING_SHORT = "%<q";
public static final String ORIGINAL_QUERY_STRING = "%{<QUERY_STRING}";
public static final String ORIGINAL_BARE_QUERY_STRING = "%{<BARE_QUERY_STRING}";

public static final ExchangeAttribute INSTANCE = new QueryStringAttribute(true);
public static final ExchangeAttribute BARE_INSTANCE = new QueryStringAttribute(false);
public static final ExchangeAttribute INSTANCE = new QueryStringAttribute(true, false);
public static final ExchangeAttribute BARE_INSTANCE = new QueryStringAttribute(false, false);
public static final ExchangeAttribute INSTANCE_ORIGINAL_REQUEST = new QueryStringAttribute(true, true);
public static final ExchangeAttribute BARE_INSTANCE_ORIGINAL_REQUEST = new QueryStringAttribute(false, true);

private final boolean includeQuestionMark;
private final boolean useOriginalRequest;

private QueryStringAttribute(boolean includeQuestionMark) {
private QueryStringAttribute(boolean includeQuestionMark, boolean useOriginalRequest) {
this.includeQuestionMark = includeQuestionMark;
this.useOriginalRequest = useOriginalRequest;
}

@Override
public String readAttribute(final RoutingContext exchange) {
String qs = exchange.request().query();
String qs = useOriginalRequest ? OriginalRequestContext.getQuery(exchange) : exchange.request().query();
if (qs == null) {
qs = "";
}
Expand Down Expand Up @@ -51,6 +59,10 @@ public ExchangeAttribute build(final String token) {
return QueryStringAttribute.INSTANCE;
} else if (token.equals(BARE_QUERY_STRING)) {
return QueryStringAttribute.BARE_INSTANCE;
} else if (token.equals(ORIGINAL_QUERY_STRING) || token.equals(ORIGINAL_QUERY_STRING_SHORT)) {
return QueryStringAttribute.INSTANCE_ORIGINAL_REQUEST;
} else if (token.equals(ORIGINAL_BARE_QUERY_STRING)) {
return QueryStringAttribute.BARE_INSTANCE_ORIGINAL_REQUEST;
}
return null;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package io.quarkus.vertx.http.runtime.attribute;

import io.quarkus.vertx.http.runtime.filters.OriginalRequestContext;
import io.vertx.core.http.HttpMethod;
import io.vertx.ext.web.RoutingContext;

/**
Expand All @@ -10,19 +12,36 @@ public class RequestLineAttribute implements ExchangeAttribute {

public static final String REQUEST_LINE_SHORT = "%r";
public static final String REQUEST_LINE = "%{REQUEST_LINE}";
public static final String ORIGINAL_REQUEST_LINE_SHORT = "%<r";
public static final String ORIGINAL_REQUEST_LINE = "%{<REQUEST_LINE}";

public static final ExchangeAttribute INSTANCE = new RequestLineAttribute();
public static final ExchangeAttribute INSTANCE = new RequestLineAttribute(false);
public static final ExchangeAttribute INSTANCE_ORIGINAL_REQUEST = new RequestLineAttribute(true);

private RequestLineAttribute() {
private final boolean useOriginalRequest;

private RequestLineAttribute(boolean useOriginalRequest) {
this.useOriginalRequest = useOriginalRequest;
}

@Override
public String readAttribute(final RoutingContext exchange) {
HttpMethod httpMethod;
String uri;
if (useOriginalRequest) {
if (!OriginalRequestContext.isPresent(exchange)) {
return null;
}
httpMethod = OriginalRequestContext.getMethod(exchange);
uri = OriginalRequestContext.getUri(exchange);
} else {
httpMethod = exchange.request().method();
uri = exchange.request().uri();
}
StringBuilder sb = new StringBuilder()
.append(exchange.request().method())
.append(httpMethod)
.append(' ')
.append(exchange.request().uri());
.append(uri);
sb.append(' ');
String httpVersion = "-";
switch (exchange.request().version()) {
Expand Down Expand Up @@ -63,6 +82,8 @@ public String name() {
public ExchangeAttribute build(final String token) {
if (token.equals(REQUEST_LINE) || token.equals(REQUEST_LINE_SHORT)) {
return RequestLineAttribute.INSTANCE;
} else if (token.equals(ORIGINAL_REQUEST_LINE) || token.equals(ORIGINAL_REQUEST_LINE_SHORT)) {
return RequestLineAttribute.INSTANCE_ORIGINAL_REQUEST;
}
return null;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.quarkus.vertx.http.runtime.attribute;

import io.quarkus.vertx.http.runtime.filters.OriginalRequestContext;
import io.vertx.ext.web.RoutingContext;

/**
Expand All @@ -10,16 +11,21 @@ public class RequestMethodAttribute implements ExchangeAttribute {

public static final String REQUEST_METHOD_SHORT = "%m";
public static final String REQUEST_METHOD = "%{METHOD}";
public static final String ORIGINAL_REQUEST_METHOD_SHORT = "%<m";
public static final String ORIGINAL_REQUEST_METHOD = "%{<METHOD}";

public static final ExchangeAttribute INSTANCE = new RequestMethodAttribute();
public static final ExchangeAttribute INSTANCE = new RequestMethodAttribute(false);
public static final ExchangeAttribute INSTANCE_ORIGINAL_REQUEST = new RequestMethodAttribute(true);

private RequestMethodAttribute() {
private final boolean useOriginalRequest;

private RequestMethodAttribute(boolean useOriginalRequest) {
this.useOriginalRequest = useOriginalRequest;
}

@Override
public String readAttribute(final RoutingContext exchange) {
return exchange.request().method().name();
return useOriginalRequest ? OriginalRequestContext.getMethod(exchange).name() : exchange.request().method().name();
}

@Override
Expand All @@ -38,6 +44,8 @@ public String name() {
public ExchangeAttribute build(final String token) {
if (token.equals(REQUEST_METHOD) || token.equals(REQUEST_METHOD_SHORT)) {
return RequestMethodAttribute.INSTANCE;
} else if (token.equals(ORIGINAL_REQUEST_METHOD) || token.equals(ORIGINAL_REQUEST_METHOD_SHORT)) {
return RequestMethodAttribute.INSTANCE_ORIGINAL_REQUEST;
}
return null;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,27 @@
package io.quarkus.vertx.http.runtime.attribute;

import io.quarkus.vertx.http.runtime.filters.OriginalRequestContext;
import io.vertx.ext.web.RoutingContext;

public class RequestPathAttribute implements ExchangeAttribute {

public static final String REQUEST_PATH = "%{REQUEST_PATH}";
public static final String REQUEST_PATH_SHORT = "%R";
public static final String ORIGINAL_REQUEST_PATH = "%{<REQUEST_PATH}";
public static final String ORIGINAL_REQUEST_PATH_SHORT = "%<R";

public static final ExchangeAttribute INSTANCE = new RequestPathAttribute();
public static final ExchangeAttribute INSTANCE = new RequestPathAttribute(false);
public static final ExchangeAttribute INSTANCE_ORIGINAL_REQUEST = new RequestPathAttribute(true);

private RequestPathAttribute() {
private final boolean useOriginalRequest;

private RequestPathAttribute(boolean useOriginalRequest) {
this.useOriginalRequest = useOriginalRequest;
}

@Override
public String readAttribute(final RoutingContext exchange) {
return exchange.request().path();
return useOriginalRequest ? OriginalRequestContext.getPath(exchange) : exchange.request().path();
}

@Override
Expand All @@ -32,6 +38,9 @@ public String name() {

@Override
public ExchangeAttribute build(final String token) {
if (token.equals(ORIGINAL_REQUEST_PATH) || token.equals(ORIGINAL_REQUEST_PATH_SHORT)) {
return INSTANCE_ORIGINAL_REQUEST;
}
return token.equals(REQUEST_PATH) || token.equals(REQUEST_PATH_SHORT) ? INSTANCE : null;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.quarkus.vertx.http.runtime.attribute;

import io.quarkus.vertx.http.runtime.filters.OriginalRequestContext;
import io.vertx.ext.web.RoutingContext;

/**
Expand All @@ -10,16 +11,21 @@ public class RequestURLAttribute implements ExchangeAttribute {

public static final String REQUEST_URL_SHORT = "%U";
public static final String REQUEST_URL = "%{REQUEST_URL}";
public static final String ORIGINAL_REQUEST_URL_SHORT = "%<U";
public static final String ORIGINAL_REQUEST_URL = "%{<REQUEST_URL}";

public static final ExchangeAttribute INSTANCE = new RequestURLAttribute();
public static final ExchangeAttribute INSTANCE = new RequestURLAttribute(false);
public static final ExchangeAttribute INSTANCE_ORIGINAL_REQUEST = new RequestURLAttribute(true);

private RequestURLAttribute() {
private final boolean useOriginalRequest;

private RequestURLAttribute(boolean useOriginalRequest) {
this.useOriginalRequest = useOriginalRequest;
}

@Override
public String readAttribute(final RoutingContext exchange) {
return exchange.request().uri();
return useOriginalRequest ? OriginalRequestContext.getUri(exchange) : exchange.request().uri();
}

@Override
Expand All @@ -38,6 +44,8 @@ public String name() {
public ExchangeAttribute build(final String token) {
if (token.equals(REQUEST_URL) || token.equals(REQUEST_URL_SHORT)) {
return RequestURLAttribute.INSTANCE;
} else if (token.equals(ORIGINAL_REQUEST_URL) || token.equals(ORIGINAL_REQUEST_URL_SHORT)) {
return RequestURLAttribute.INSTANCE_ORIGINAL_REQUEST;
}
return null;
}
Expand Down
Loading
Loading