diff --git a/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/handler/AbstractLatencyRecordingHandler.java b/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/handler/AbstractLatencyRecordingHandler.java new file mode 100644 index 000000000000..bfb0584bde59 --- /dev/null +++ b/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/handler/AbstractLatencyRecordingHandler.java @@ -0,0 +1,86 @@ +// +// ======================================================================== +// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// ======================================================================== +// + +package org.eclipse.jetty.server.handler; + +import java.util.function.Function; + +import org.eclipse.jetty.server.Handler; +import org.eclipse.jetty.server.HttpStream; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.Response; +import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.NanoTime; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A Handler that allows recording the latencies of the requests executed by the wrapped handler. + */ +public abstract class AbstractLatencyRecordingHandler extends Handler.Wrapper +{ + private static final Logger LOG = LoggerFactory.getLogger(AbstractLatencyRecordingHandler.class); + + private final Function recordingWrapper; + + public AbstractLatencyRecordingHandler() + { + this.recordingWrapper = httpStream -> new HttpStream.Wrapper(httpStream) + { + @Override + public void succeeded() + { + long begin = httpStream.getNanoTime(); + super.succeeded(); + try + { + onRequestComplete(NanoTime.since(begin)); + } + catch (Throwable t) + { + if (LOG.isDebugEnabled()) + LOG.debug("Error thrown by onRequestComplete", t); + } + } + + @Override + public void failed(Throwable x) + { + long begin = httpStream.getNanoTime(); + super.failed(x); + try + { + onRequestComplete(NanoTime.since(begin)); + } + catch (Throwable t) + { + if (LOG.isDebugEnabled()) + LOG.debug("Error thrown by onRequestComplete", t); + } + } + }; + } + + @Override + public boolean process(Request request, Response response, Callback callback) throws Exception + { + request.addHttpStreamWrapper(recordingWrapper); + return super.process(request, response, callback); + } + + /** + * Called back for each completed request with its execution's duration. + * @param durationInNs the duration in nanoseconds of the completed request + */ + protected abstract void onRequestComplete(long durationInNs); +}