-
Notifications
You must be signed in to change notification settings - Fork 974
GH-6372: Expose client request metrics. #6502
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
base: main
Are you sure you want to change the base?
Changes from all commits
8dba066
19f87b7
166d258
0cf334f
a9c15f0
606bf40
002b1ea
3f8df1e
c6ffdc9
5243403
37dee31
3c173a0
bee21ea
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -53,6 +53,7 @@ | |
| import com.google.common.collect.ImmutableMap; | ||
| import com.google.common.primitives.Ints; | ||
|
|
||
| import com.linecorp.armeria.client.metric.ClientRequestLifecycleListener; | ||
| import com.linecorp.armeria.client.proxy.ProxyConfig; | ||
| import com.linecorp.armeria.client.proxy.ProxyConfigSelector; | ||
| import com.linecorp.armeria.common.CommonPools; | ||
|
|
@@ -135,6 +136,8 @@ public final class ClientFactoryBuilder implements TlsSetters { | |
| private ClientTlsSpec clientTlsSpec = ClientTlsSpec.of(); | ||
| private boolean staticTlsSettingsSet; | ||
| private boolean autoCloseConnectionPoolListener = true; | ||
| private ClientRequestLifecycleListener clientRequestLifecycleListener = | ||
| ClientRequestLifecycleListener.noop(); | ||
|
|
||
| ClientFactoryBuilder() { | ||
| connectTimeoutMillis(Flags.defaultConnectTimeoutMillis()); | ||
|
|
@@ -261,6 +264,21 @@ public <T> ClientFactoryBuilder channelOption(ChannelOption<T> option, T value) | |
| return this; | ||
| } | ||
|
|
||
| /** | ||
| * Sets the {@link ClientRequestLifecycleListener} that listens to the lifecycle events of | ||
| * client requests created by the {@link ClientFactory}. | ||
| * | ||
| * <p>If not set, {@link ClientRequestLifecycleListener#noop()} is used by default. | ||
| * | ||
| * @param listener the listener to be notified of client request lifecycle events. Must not be {@code null}. | ||
| * @return {@code this} to support method chaining. | ||
| */ | ||
| public ClientFactoryBuilder clientRequestLifecycleListener(ClientRequestLifecycleListener listener) { | ||
| requireNonNull(listener, "listener"); | ||
| clientRequestLifecycleListener = listener; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we allow multiple |
||
| return this; | ||
| } | ||
|
Comment on lines
+267
to
+280
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add This new public API method should be annotated with 🔎 Proposed fix /**
* Sets the {@link ClientRequestLifecycleListener} that listens to the lifecycle events of
* client requests created by the {@link ClientFactory}.
*
* <p>If not set, {@link ClientRequestLifecycleListener#noop()} is used by default.
*
* @param listener the listener to be notified of client request lifecycle events. Must not be {@code null}.
* @return {@code this} to support method chaining.
*/
+ @UnstableApi
public ClientFactoryBuilder clientRequestLifecycleListener(ClientRequestLifecycleListener listener) {
requireNonNull(listener, "listener");
clientRequestLifecycleListener = listener;
return this;
}Based on coding guidelines, new public API methods require 🤖 Prompt for AI Agents |
||
|
|
||
| private void channelOptions(Map<ChannelOption<?>, Object> newChannelOptions) { | ||
| @SuppressWarnings("unchecked") | ||
| final ClientFactoryOptionValue<Map<ChannelOption<?>, Object>> castOptions = | ||
|
|
@@ -1127,7 +1145,7 @@ public ClientFactory build() { | |
| final ClientFactoryOptions options = buildOptions(); | ||
| final ClientTlsSpec baseClientTlsSpec = buildTlsSpec(clientTlsSpec, tlsNoVerifySet, insecureHosts); | ||
| return new DefaultClientFactory(new HttpClientFactory( | ||
| options, autoCloseConnectionPoolListener, baseClientTlsSpec)); | ||
| options, autoCloseConnectionPoolListener, baseClientTlsSpec, clientRequestLifecycleListener)); | ||
| } | ||
|
|
||
| private static ClientTlsSpec buildTlsSpec( | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -104,6 +104,12 @@ public HttpResponse execute(ClientRequestContext ctx, HttpRequest req) throws Ex | |||||||||||||||||||||||
| final DecodedHttpResponse res = new DecodedHttpResponse(eventLoop); | ||||||||||||||||||||||||
| updateCancellationTask(ctx, req, res); | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| factory.clientRequestLifecycleListener().onRequestPending(ctx); | ||||||||||||||||||||||||
| ctx.log().addListener( | ||||||||||||||||||||||||
| factory.clientRequestLifecycleListener() | ||||||||||||||||||||||||
| .asRequestLogListener() | ||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||
|
Comment on lines
+107
to
+111
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion | 🟠 Major Cache the lifecycle listener to avoid redundant method calls. The listener is retrieved twice from the factory on the hot path. Store it in a local variable for efficiency. 🔎 Proposed fix+ final ClientRequestLifecycleListener lifecycleListener =
+ factory.clientRequestLifecycleListener();
- factory.clientRequestLifecycleListener().onRequestPending(ctx);
+ lifecycleListener.onRequestPending(ctx);
ctx.log().addListener(
- factory.clientRequestLifecycleListener()
- .asRequestLogListener()
+ lifecycleListener.asRequestLogListener()
);📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents🧩 Analysis chain🏁 Script executed: # Find ClientRequestLifecycleListener interface
fd -t f -e java -p . | xargs rg -l "interface ClientRequestLifecycleListener" 2>/dev/null | head -5
# Find HttpClientDelegate.java
fd -t f -name "HttpClientDelegate.java" 2>/dev/null
# Find any classes with "ClientRequestLifecycle" in their name
fd -t f -e java -p . | xargs rg -l "ClientRequestLifecycle" 2>/dev/nullRepository: line/armeria Length of output: 741 🏁 Script executed: # Read ClientRequestLifecycleListener.java
echo "=== ClientRequestLifecycleListener.java ==="
head -30 core/src/main/java/com/linecorp/armeria/client/metric/ClientRequestLifecycleListener.java
echo -e "\n=== DefaultClientRequestLogListener.java ==="
head -30 core/src/main/java/com/linecorp/armeria/client/logging/DefaultClientRequestLogListener.java
echo -e "\n=== ClientRequestMetrics.java ==="
head -30 core/src/main/java/com/linecorp/armeria/client/metric/ClientRequestMetrics.java
echo -e "\n=== NoopClientRequestLifecycleListener.java ==="
head -30 core/src/main/java/com/linecorp/armeria/client/metric/NoopClientRequestLifecycleListener.java
# Check HttpClientDelegate.java location and lines around 107-111
echo -e "\n=== HttpClientDelegate.java (around lines 100-115) ==="
sed -n '100,115p' core/src/main/java/com/linecorp/armeria/client/HttpClientDelegate.javaRepository: line/armeria Length of output: 5927 🏁 Script executed: # Get the full ClientRequestLifecycleListener interface declaration
echo "=== ClientRequestLifecycleListener interface ==="
sed -n '1,50p' core/src/main/java/com/linecorp/armeria/client/metric/ClientRequestLifecycleListener.java | tail -25
# Get the full DefaultClientRequestLogListener class declaration
echo -e "\n=== DefaultClientRequestLogListener class declaration ==="
sed -n '1,65p' core/src/main/java/com/linecorp/armeria/client/logging/DefaultClientRequestLogListener.java | tail -25
# Get the asRequestLogListener method signature
echo -e "\n=== asRequestLogListener method in ClientRequestLifecycleListener ==="
rg -A5 "asRequestLogListener" core/src/main/java/com/linecorp/armeria/client/metric/ClientRequestLifecycleListener.java
# Check ClientRequestMetrics for @UnstableApi
echo -e "\n=== ClientRequestMetrics @UnstableApi check ==="
rg "@UnstableApi|^public class ClientRequestMetrics" core/src/main/java/com/linecorp/armeria/client/metric/ClientRequestMetrics.java | head -5Repository: line/armeria Length of output: 3016 🏁 Script executed: # Check ClientRequestMetrics full class declaration with annotations
echo "=== ClientRequestMetrics full header ==="
sed -n '1,45p' core/src/main/java/com/linecorp/armeria/client/metric/ClientRequestMetrics.java
# Also check if there are any other public classes/methods in ClientRequestLifecycleListener
echo -e "\n=== Full ClientRequestLifecycleListener interface ==="
wc -l core/src/main/java/com/linecorp/armeria/client/metric/ClientRequestLifecycleListener.java
# Get full interface
cat core/src/main/java/com/linecorp/armeria/client/metric/ClientRequestLifecycleListener.java | head -150Repository: line/armeria Length of output: 6333 🏁 Script executed: # Check if ClientRequestMetrics has @UnstableApi annotation
echo "=== ClientRequestMetrics class with preceding annotations ==="
rg -B2 "^public class ClientRequestMetrics" core/src/main/java/com/linecorp/armeria/client/metric/ClientRequestMetrics.java
# Also verify DefaultClientRequestLogListener has @UnstableApi
echo -e "\n=== DefaultClientRequestLogListener with annotations ==="
rg -B2 "^public class DefaultClientRequestLogListener" core/src/main/java/com/linecorp/armeria/client/logging/DefaultClientRequestLogListener.java
# Check if DefaultClientRequestLogListener is in logging package (not .internal)
echo -e "\n=== Package declarations ==="
rg "^package" core/src/main/java/com/linecorp/armeria/client/logging/DefaultClientRequestLogListener.java
rg "^package" core/src/main/java/com/linecorp/armeria/client/metric/ClientRequestMetrics.java
rg "^package" core/src/main/java/com/linecorp/armeria/client/metric/ClientRequestLifecycleListener.javaRepository: line/armeria Length of output: 523 🏁 Script executed: # Get the full ClientRequestMetrics class definition to confirm it's missing @UnstableApi
echo "=== ClientRequestMetrics lines 30-50 ==="
sed -n '30,50p' core/src/main/java/com/linecorp/armeria/client/metric/ClientRequestMetrics.java
# Double-check by looking at all annotations before the class
echo -e "\n=== ClientRequestMetrics all lines before class declaration ==="
grep -n "@\|^public class" core/src/main/java/com/linecorp/armeria/client/metric/ClientRequestMetrics.java | head -10Repository: line/armeria Length of output: 1488 Add @UnstableApi annotation to ClientRequestMetrics. The 🤖 Prompt for AI Agents |
||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||
| resolveProxyConfig(protocol, endpoint, ctx, (proxyConfig, thrown) -> { | ||||||||||||||||||||||||
| if (thrown != null) { | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -38,6 +38,7 @@ | |
| import com.google.common.collect.MapMaker; | ||
|
|
||
| import com.linecorp.armeria.client.endpoint.EndpointGroup; | ||
| import com.linecorp.armeria.client.metric.ClientRequestLifecycleListener; | ||
| import com.linecorp.armeria.client.proxy.ProxyConfigSelector; | ||
| import com.linecorp.armeria.client.redirect.RedirectConfig; | ||
| import com.linecorp.armeria.common.Http1HeaderNaming; | ||
|
|
@@ -123,15 +124,23 @@ final class HttpClientFactory implements ClientFactory { | |
| private final boolean autoCloseConnectionPoolListener; | ||
| private final AsyncCloseableSupport closeable = AsyncCloseableSupport.of(this::closeAsync); | ||
| private final BootstrapSslContexts bootstrapSslContexts; | ||
| private final ClientRequestLifecycleListener clientRequestLifecycleListener; | ||
|
|
||
| HttpClientFactory(ClientFactoryOptions options, boolean autoCloseConnectionPoolListener, | ||
| ClientTlsSpec baseClientTlsSpec) { | ||
| this(options, autoCloseConnectionPoolListener, baseClientTlsSpec, | ||
| ClientRequestLifecycleListener.noop()); | ||
| } | ||
|
|
||
| HttpClientFactory(ClientFactoryOptions options, boolean autoCloseConnectionPoolListener, | ||
| ClientTlsSpec baseClientTlsSpec, | ||
| ClientRequestLifecycleListener clientRequestLifecycleListener) { | ||
|
Comment on lines
+135
to
+137
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion | 🟠 Major Add null validation for the listener parameter. The 🔎 Proposed fix HttpClientFactory(ClientFactoryOptions options, boolean autoCloseConnectionPoolListener,
ClientTlsSpec baseClientTlsSpec,
ClientRequestLifecycleListener clientRequestLifecycleListener) {
+ this.clientRequestLifecycleListener = requireNonNull(clientRequestLifecycleListener,
+ "clientRequestLifecycleListener");
workerGroup = options.workerGroup();And update line 211: this.options = options;
- this.clientRequestLifecycleListener = clientRequestLifecycleListener;Also applies to: 211-211 🤖 Prompt for AI Agents |
||
| workerGroup = options.workerGroup(); | ||
|
|
||
| @SuppressWarnings("unchecked") | ||
| final AddressResolverGroup<InetSocketAddress> group = | ||
| (AddressResolverGroup<InetSocketAddress>) options.addressResolverGroupFactory() | ||
| .apply(workerGroup); | ||
| .apply(workerGroup); | ||
| addressResolverGroup = group; | ||
|
|
||
| final Bootstrap bootstrap = new Bootstrap(); | ||
|
|
@@ -199,6 +208,7 @@ final class HttpClientFactory implements ClientFactory { | |
| this.autoCloseConnectionPoolListener = autoCloseConnectionPoolListener; | ||
|
|
||
| this.options = options; | ||
| this.clientRequestLifecycleListener = clientRequestLifecycleListener; | ||
|
|
||
| clientDelegate = new HttpClientDelegate(this, addressResolverGroup); | ||
| RequestTargetCache.registerClientMetrics(meterRegistry); | ||
|
|
@@ -306,6 +316,10 @@ Http1HeaderNaming http1HeaderNaming() { | |
| return http1HeaderNaming; | ||
| } | ||
|
|
||
| ClientRequestLifecycleListener clientRequestLifecycleListener() { | ||
| return clientRequestLifecycleListener; | ||
| } | ||
|
|
||
| @VisibleForTesting | ||
| AddressResolverGroup<InetSocketAddress> addressResolverGroup() { | ||
| return addressResolverGroup; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,75 @@ | ||
| /* | ||
| * Copyright 2025 LY Corporation | ||
| * | ||
| * LY Corporation licenses this file to you 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: | ||
| * | ||
| * https://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 com.linecorp.armeria.client.logging; | ||
|
|
||
| import com.linecorp.armeria.client.ClientRequestContext; | ||
| import com.linecorp.armeria.client.metric.ClientRequestLifecycleListener; | ||
| import com.linecorp.armeria.common.annotation.UnstableApi; | ||
| import com.linecorp.armeria.common.logging.RequestLog; | ||
| import com.linecorp.armeria.common.logging.RequestLogListener; | ||
| import com.linecorp.armeria.common.logging.RequestLogProperty; | ||
|
|
||
| /** | ||
| * A default implementation of {@link RequestLogListener} that delegates {@link RequestLog} events | ||
| * to a {@link ClientRequestLifecycleListener}. | ||
| * | ||
| * <p>This listener monitors the progress of a {@link RequestLog} and invokes the corresponding | ||
| * callback methods of the {@link ClientRequestLifecycleListener} when specific {@link RequestLogProperty} | ||
| * become available. | ||
| */ | ||
| @UnstableApi | ||
| public class DefaultClientRequestLogListener implements RequestLogListener { | ||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| private final ClientRequestLifecycleListener lifecycleListener; | ||
|
|
||
| /** | ||
| * Creates a new instance with the specified {@link ClientRequestLifecycleListener}. | ||
| * | ||
| * @param lifecycleListener the listener to which the {@link RequestLog} events will be delegated | ||
| */ | ||
| public DefaultClientRequestLogListener(ClientRequestLifecycleListener lifecycleListener) { | ||
| this.lifecycleListener = lifecycleListener; | ||
| } | ||
|
Comment on lines
+44
to
+46
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add null validation for the constructor parameter. The constructor should validate that Apply this diff to add validation: +import static java.util.Objects.requireNonNull;
+
/**
* Creates a new instance with the specified {@link ClientRequestLifecycleListener}.
*
* @param lifecycleListener the listener to which the {@link RequestLog} events will be delegated
*/
public DefaultClientRequestLogListener(ClientRequestLifecycleListener lifecycleListener) {
- this.lifecycleListener = lifecycleListener;
+ this.lifecycleListener = requireNonNull(lifecycleListener, "lifecycleListener");
}
🤖 Prompt for AI Agents |
||
|
|
||
| @Override | ||
| public void onEvent(RequestLogProperty property, RequestLog log) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would we create one public void onEvent(RequestLogProperty property, RequestLog log) {
...
switch (property) {
case REQUEST_FIRST_BYTES_TRANSFERRED_TIME:
for (var lifecycleListener: lifecycleListeners) {
lifecycleListener.onRequestStart(ctx);
}
break;
}Otherwise, |
||
| if (!(log.context() instanceof ClientRequestContext)) { | ||
| return; | ||
| } | ||
|
|
||
| final ClientRequestContext ctx = (ClientRequestContext) log.context(); | ||
| switch (property) { | ||
| case REQUEST_FIRST_BYTES_TRANSFERRED_TIME: | ||
| lifecycleListener.onRequestStart(ctx); | ||
| break; | ||
| case REQUEST_COMPLETE: | ||
| lifecycleListener.onRequestSendComplete(ctx); | ||
| break; | ||
| case RESPONSE_HEADERS: | ||
| lifecycleListener.onResponseHeaders(ctx, log.responseHeaders()); | ||
| break; | ||
| case RESPONSE_COMPLETE: | ||
| lifecycleListener.onResponseComplete(ctx); | ||
| break; | ||
| case ALL_COMPLETE: | ||
| lifecycleListener.onRequestComplete(ctx, log.responseCause()); | ||
| break; | ||
| default: | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,111 @@ | ||
| /* | ||
| * Copyright 2025 LY Corporation | ||
| * | ||
| * LY Corporation licenses this file to you 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: | ||
| * | ||
| * https://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 com.linecorp.armeria.client.metric; | ||
|
|
||
| import com.linecorp.armeria.client.ClientRequestContext; | ||
| import com.linecorp.armeria.client.logging.DefaultClientRequestLogListener; | ||
| import com.linecorp.armeria.common.ResponseHeaders; | ||
| import com.linecorp.armeria.common.annotation.Nullable; | ||
| import com.linecorp.armeria.common.annotation.UnstableApi; | ||
| import com.linecorp.armeria.common.logging.RequestLogListener; | ||
|
|
||
| /** | ||
| * Listens to the lifecycle events of client requests. | ||
| * | ||
| * <p>This interface provides a high-level view of a request's lifecycle (e.g., pending, started, completed). | ||
| * unlike {@link RequestLogListener} which provides low-level property changes. | ||
| * | ||
| * <p>Note: The methods in this interface are typically not invoked directly by the | ||
| * transport layer. Instead, they are triggered by inspecting the changes in | ||
| * {@link com.linecorp.armeria.common.logging.RequestLog}. | ||
| * Implementations should use {@link #asRequestLogListener()} to bridge | ||
| * {@link com.linecorp.armeria.common.logging.RequestLogProperty} | ||
| * changes to these lifecycle methods. | ||
| * | ||
| * <p>For example, a standard implementation might map: | ||
| * <ul> | ||
| * <li>{@link com.linecorp.armeria.common.logging.RequestLogProperty#REQUEST_FIRST_BYTES_TRANSFERRED_TIME} | ||
| * to {@link #onRequestStart(ClientRequestContext)}</li> | ||
| * <li>{@link com.linecorp.armeria.common.logging.RequestLogProperty#ALL_COMPLETE} | ||
| * to {@link #onRequestComplete(ClientRequestContext, Throwable)}</li> | ||
| * </ul> | ||
| * | ||
| * @see com.linecorp.armeria.client.ClientFactoryBuilder#clientRequestLifecycleListener( | ||
| * ClientRequestLifecycleListener) | ||
| */ | ||
| @UnstableApi | ||
| public interface ClientRequestLifecycleListener { | ||
|
|
||
| /** | ||
| * Invoked when a request is created and scheduled for execution but has not yet started. | ||
| * Note: This method is explicitly invoked by HttpClientDelegate when | ||
| * HttpClientDelegate starts to call execute(). | ||
| */ | ||
| void onRequestPending(ClientRequestContext ctx); | ||
|
|
||
| /** | ||
| * Called when the client begins execution (connection acquired, headers sent). | ||
| */ | ||
| void onRequestStart(ClientRequestContext ctx); | ||
|
|
||
| /** | ||
| * Called when the request is fully sent. | ||
| */ | ||
| void onRequestSendComplete(ClientRequestContext ctx); | ||
|
|
||
| /** | ||
| * Called when the first response headers are received. | ||
| */ | ||
| void onResponseHeaders(ClientRequestContext ctx, ResponseHeaders headers); | ||
|
|
||
| /** | ||
| * Called when the full response body is received successfully. | ||
| */ | ||
| void onResponseComplete(ClientRequestContext ctx); | ||
|
|
||
| /** | ||
| * Called when a request is completed with either success or failure. | ||
| */ | ||
| void onRequestComplete(ClientRequestContext ctx, @Nullable Throwable cause); | ||
|
|
||
| /** | ||
| * Returns a {@link RequestLogListener} that delegates | ||
| * {@link com.linecorp.armeria.common.logging.RequestLog} | ||
| * events to this lifecycle listener. | ||
| * This method bridges the low-level {@link com.linecorp.armeria.common.logging.RequestLog} | ||
| * updates to the high-level lifecycle methods | ||
| * defined in this interface. The returned listener is registered to the {@link ClientRequestContext} | ||
| * automatically when the request starts. | ||
| */ | ||
| default RequestLogListener asRequestLogListener() { | ||
| return new DefaultClientRequestLogListener(this); | ||
| } | ||
|
|
||
| /** | ||
| * Returns a {@link ClientRequestMetrics} that collects the number of pending and active requests. | ||
| */ | ||
| static ClientRequestMetrics counting() { | ||
| return new ClientRequestMetrics(); | ||
| } | ||
|
|
||
| /** | ||
| * Returns a {@link ClientRequestLifecycleListener} that does nothing. | ||
| */ | ||
| static ClientRequestLifecycleListener noop() { | ||
| return NoopClientRequestLifecycleListener.getInstance(); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For simplicity.