All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.micrometer.core.instrument.binder.jetty.TimedHandler Maven / Gradle / Ivy

There is a newer version: 1.13.0
Show newest version
/**
 * Copyright 2019 VMware, Inc.
 * 

* Licensed 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 io.micrometer.core.instrument.binder.jetty; import io.micrometer.core.instrument.*; import io.micrometer.core.instrument.binder.BaseUnits; import io.micrometer.core.instrument.binder.http.DefaultHttpServletRequestTagsProvider; import io.micrometer.core.instrument.binder.http.HttpServletRequestTagsProvider; import io.micrometer.core.lang.NonNullApi; import io.micrometer.core.lang.NonNullFields; import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.server.AsyncContextEvent; import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.HttpChannelState; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.HandlerWrapper; import org.eclipse.jetty.util.FutureCallback; import org.eclipse.jetty.util.component.Graceful; import javax.servlet.AsyncEvent; import javax.servlet.AsyncListener; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicInteger; /** * Adapted from Jetty's StatisticsHandler. * * @author Jon Schneider * @since 1.4.0 */ @NonNullApi @NonNullFields public class TimedHandler extends HandlerWrapper implements Graceful { private static final String SAMPLE_REQUEST_TIMER_ATTRIBUTE = "__micrometer_timer_sample"; private static final String SAMPLE_REQUEST_LONG_TASK_TIMER_ATTRIBUTE = "__micrometer_ltt_sample"; private final MeterRegistry registry; private final Iterable tags; private final HttpServletRequestTagsProvider tagsProvider; private final Shutdown shutdown = new Shutdown() { @Override protected FutureCallback newShutdownCallback() { return TimedHandler.this.newShutdownCallback(); } }; private final LongTaskTimer openRequests; private final Counter asyncDispatches; private final Counter asyncExpires; private final AtomicInteger asyncWaits = new AtomicInteger(); public TimedHandler(MeterRegistry registry, Iterable tags) { this(registry, tags, new DefaultHttpServletRequestTagsProvider()); } public TimedHandler(MeterRegistry registry, Iterable tags, HttpServletRequestTagsProvider tagsProvider) { this.registry = registry; this.tags = tags; this.tagsProvider = tagsProvider; this.openRequests = LongTaskTimer.builder("jetty.server.dispatches.open") .description("Jetty dispatches that are currently in progress") .tags(tags) .register(registry); this.asyncDispatches = Counter.builder("jetty.server.async.dispatches") .description("Asynchronous dispatches") .tags(tags) .register(registry); this.asyncExpires = Counter.builder("jetty.server.async.expires") .description("Asynchronous operations that timed out before completing") .tags(tags) .register(registry); Gauge.builder("jetty.server.async.waits", asyncWaits, AtomicInteger::doubleValue) .description("Pending asynchronous wait operations") .baseUnit(BaseUnits.OPERATIONS) .tags(tags) .register(registry); } @Override public void handle(String path, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { Timer.Sample sample = Timer.start(registry); LongTaskTimer.Sample requestSample; HttpChannelState state = baseRequest.getHttpChannelState(); if (state.isInitial()) { requestSample = openRequests.start(); request.setAttribute(SAMPLE_REQUEST_TIMER_ATTRIBUTE, sample); request.setAttribute(SAMPLE_REQUEST_LONG_TASK_TIMER_ATTRIBUTE, requestSample); } else { asyncDispatches.increment(); request.setAttribute(SAMPLE_REQUEST_TIMER_ATTRIBUTE, sample); requestSample = (LongTaskTimer.Sample) request.getAttribute(SAMPLE_REQUEST_LONG_TASK_TIMER_ATTRIBUTE); } try { Handler handler = getHandler(); if (handler != null && !shutdown.isShutdown() && isStarted()) { handler.handle(path, baseRequest, request, response); } else { if (!baseRequest.isHandled()) { baseRequest.setHandled(true); } if (!baseRequest.getResponse().isCommitted()) { response.sendError(HttpStatus.SERVICE_UNAVAILABLE_503); } } } finally { if (state.isSuspended()) { if (state.isInitial()) { state.addListener(onCompletion); asyncWaits.incrementAndGet(); } } else if (state.isInitial()) { sample.stop(Timer.builder("jetty.server.requests") .description("HTTP requests to the Jetty server") .tags(tagsProvider.getTags(request, response)) .tags(tags) .register(registry)); requestSample.stop(); // If we have no more dispatches, should we signal shutdown? FutureCallback shutdownCallback = shutdown.get(); if (shutdownCallback != null) { response.flushBuffer(); if (openRequests.activeTasks() == 0) { shutdownCallback.succeeded(); } } } // else onCompletion will handle it. } } private final AsyncListener onCompletion = new OnCompletionAsyncListener(this); @Override protected void doStart() throws Exception { shutdown.cancel(); super.doStart(); } @Override protected void doStop() throws Exception { shutdown.cancel(); super.doStop(); } @Override public Future shutdown() { return shutdown.shutdown(); } @Override public boolean isShutdown() { return shutdown.isShutdown(); } void onAsyncTimeout(AsyncEvent event) { asyncExpires.increment(); HttpChannelState state = ((AsyncContextEvent) event).getHttpChannelState(); Request request = state.getBaseRequest(); LongTaskTimer.Sample lttSample = (LongTaskTimer.Sample) request.getAttribute(SAMPLE_REQUEST_LONG_TASK_TIMER_ATTRIBUTE); lttSample.stop(); } void onAsyncComplete(AsyncEvent event) { HttpChannelState state = ((AsyncContextEvent) event).getHttpChannelState(); Request request = state.getBaseRequest(); Timer.Sample sample = (Timer.Sample) request.getAttribute(SAMPLE_REQUEST_TIMER_ATTRIBUTE); LongTaskTimer.Sample lttSample = (LongTaskTimer.Sample) request.getAttribute(SAMPLE_REQUEST_LONG_TASK_TIMER_ATTRIBUTE); if (sample != null) { sample.stop(Timer.builder("jetty.server.requests") .description("HTTP requests to the Jetty server") .tags(tagsProvider.getTags(request, request.getResponse())) .tags(tags) .register(registry)); lttSample.stop(); } asyncWaits.decrementAndGet(); // If we have no more dispatches, should we signal shutdown? FutureCallback shutdownCallback = shutdown.get(); if (shutdownCallback != null && openRequests.activeTasks() == 0) { shutdownCallback.succeeded(); } } private FutureCallback newShutdownCallback() { return new FutureCallback(openRequests.activeTasks() == 0); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy