484818 - Expose interesting HTTP/2 attributes and operations via JMX.

Initial work to expose already existing attributes on the server.
This commit is contained in:
Simone Bordet 2015-12-22 21:09:57 +01:00
parent 19d6e36ab9
commit b7ab9e0a22
7 changed files with 128 additions and 39 deletions

View File

@ -21,6 +21,7 @@ package org.eclipse.jetty.http2.client;
import org.eclipse.jetty.http2.FlowControlStrategy;
import org.eclipse.jetty.http2.HTTP2Session;
import org.eclipse.jetty.http2.IStream;
import org.eclipse.jetty.http2.api.Session;
import org.eclipse.jetty.http2.api.Stream;
import org.eclipse.jetty.http2.frames.HeadersFrame;
import org.eclipse.jetty.http2.frames.PushPromiseFrame;
@ -35,7 +36,7 @@ public class HTTP2ClientSession extends HTTP2Session
{
private static final Logger LOG = Log.getLogger(HTTP2ClientSession.class);
public HTTP2ClientSession(Scheduler scheduler, EndPoint endPoint, Generator generator, Listener listener, FlowControlStrategy flowControl)
public HTTP2ClientSession(Scheduler scheduler, EndPoint endPoint, Generator generator, Session.Listener listener, FlowControlStrategy flowControl)
{
super(scheduler, endPoint, generator, listener, flowControl, 1);
}

View File

@ -16,6 +16,12 @@
<artifactId>http2-hpack</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-jmx</artifactId>
<version>${project.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.toolchain</groupId>
<artifactId>jetty-test-helper</artifactId>
@ -23,30 +29,30 @@
</dependency>
</dependencies>
<properties>
<bundle-symbolic-name>${project.groupId}.common</bundle-symbolic-name>
</properties>
<properties>
<bundle-symbolic-name>${project.groupId}.common</bundle-symbolic-name>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<executions>
<execution>
<goals>
<goal>manifest</goal>
</goals>
<configuration>
<instructions>
<Export-Package>org.eclipse.jetty.http2.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}";</Export-Package>
</instructions>
</configuration>
</execution>
</executions>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<executions>
<execution>
<goals>
<goal>manifest</goal>
</goals>
<configuration>
<instructions>
<Export-Package>org.eclipse.jetty.http2.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}";</Export-Package>
</instructions>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</plugins>
</build>
</project>

View File

@ -20,9 +20,12 @@ package org.eclipse.jetty.http2;
import org.eclipse.jetty.http2.api.Stream;
import org.eclipse.jetty.http2.frames.WindowUpdateFrame;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@ManagedObject
public abstract class AbstractFlowControlStrategy implements FlowControlStrategy
{
protected static final Logger LOG = Log.getLogger(FlowControlStrategy.class);
@ -36,12 +39,14 @@ public abstract class AbstractFlowControlStrategy implements FlowControlStrategy
this.initialStreamRecvWindow = DEFAULT_WINDOW_SIZE;
}
protected int getInitialStreamSendWindow()
@ManagedAttribute(value = "The initial size of stream's flow control send window", readonly = true)
public int getInitialStreamSendWindow()
{
return initialStreamSendWindow;
}
protected int getInitialStreamRecvWindow()
@ManagedAttribute(value = "The initial size of stream's flow control receive window", readonly = true)
public int getInitialStreamRecvWindow()
{
return initialStreamRecvWindow;
}
@ -102,6 +107,8 @@ public abstract class AbstractFlowControlStrategy implements FlowControlStrategy
int oldSize = stream.updateSendWindow(delta);
if (LOG.isDebugEnabled())
LOG.debug("Updated stream send window {} -> {} for {}", oldSize, oldSize + delta, stream);
if (oldSize <= 0)
onStreamUnstalled(stream);
}
}
else
@ -109,6 +116,8 @@ public abstract class AbstractFlowControlStrategy implements FlowControlStrategy
int oldSize = session.updateSendWindow(delta);
if (LOG.isDebugEnabled())
LOG.debug("Updated session send window {} -> {} for {}", oldSize, oldSize + delta, session);
if (oldSize <= 0)
onSessionUnstalled(session);
}
}
@ -166,4 +175,16 @@ public abstract class AbstractFlowControlStrategy implements FlowControlStrategy
if (LOG.isDebugEnabled())
LOG.debug("Stream stalled {}", stream);
}
protected void onSessionUnstalled(ISession session)
{
if (LOG.isDebugEnabled())
LOG.debug("Session unstalled {}", session);
}
protected void onStreamUnstalled(IStream stream)
{
if (LOG.isDebugEnabled())
LOG.debug("Stream unstalled {}", stream);
}
}

View File

@ -26,6 +26,8 @@ import org.eclipse.jetty.http2.frames.Frame;
import org.eclipse.jetty.http2.frames.WindowUpdateFrame;
import org.eclipse.jetty.util.Atomics;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
/**
* <p>A flow control strategy that accumulates updates and emits window control
@ -49,6 +51,7 @@ import org.eclipse.jetty.util.Callback;
* <p>The application consumes the remaining 15, so now SB=15, and no window
* control frame is emitted.</p>
*/
@ManagedObject
public class BufferingFlowControlStrategy extends AbstractFlowControlStrategy
{
private final AtomicInteger maxSessionRecvWindow = new AtomicInteger(DEFAULT_WINDOW_SIZE);
@ -67,6 +70,12 @@ public class BufferingFlowControlStrategy extends AbstractFlowControlStrategy
this.bufferRatio = bufferRatio;
}
@ManagedAttribute("The ratio between the receive buffer and the consume buffer")
public float getBufferRatio()
{
return bufferRatio;
}
@Override
public void onStreamCreated(IStream stream)
{

View File

@ -54,11 +54,15 @@ import org.eclipse.jetty.util.Atomics;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.CountingCallback;
import org.eclipse.jetty.util.Promise;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.component.ContainerLifeCycle;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.thread.Scheduler;
public abstract class HTTP2Session implements ISession, Parser.Listener
@ManagedObject
public abstract class HTTP2Session extends ContainerLifeCycle implements ISession, Parser.Listener
{
private static final Logger LOG = Log.getLogger(HTTP2Session.class);
@ -73,7 +77,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener
private final Scheduler scheduler;
private final EndPoint endPoint;
private final Generator generator;
private final Listener listener;
private final Session.Listener listener;
private final FlowControlStrategy flowControl;
private final HTTP2Flusher flusher;
private int maxLocalStreams;
@ -81,7 +85,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener
private long streamIdleTimeout;
private boolean pushEnabled;
public HTTP2Session(Scheduler scheduler, EndPoint endPoint, Generator generator, Listener listener, FlowControlStrategy flowControl, int initialStreamId)
public HTTP2Session(Scheduler scheduler, EndPoint endPoint, Generator generator, Session.Listener listener, FlowControlStrategy flowControl, int initialStreamId)
{
this.scheduler = scheduler;
this.endPoint = endPoint;
@ -98,6 +102,14 @@ public abstract class HTTP2Session implements ISession, Parser.Listener
this.pushEnabled = true; // SPEC: by default, push is enabled.
}
@Override
protected void doStart() throws Exception
{
addBean(flowControl);
super.doStart();
}
@ManagedAttribute(value = "The flow control strategy", readonly = true)
public FlowControlStrategy getFlowControlStrategy()
{
return flowControl;
@ -123,6 +135,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener
this.maxRemoteStreams = maxRemoteStreams;
}
@ManagedAttribute("The stream's idle timeout")
public long getStreamIdleTimeout()
{
return streamIdleTimeout;
@ -709,17 +722,25 @@ public abstract class HTTP2Session implements ISession, Parser.Listener
return result;
}
@ManagedAttribute("The number of active streams")
public int getStreamCount()
{
return streams.size();
}
@Override
public IStream getStream(int streamId)
{
return streams.get(streamId);
}
@ManagedAttribute(value = "The flow control send window", readonly = true)
public int getSendWindow()
{
return sendWindow.get();
}
@ManagedAttribute(value = "The flow control receive window", readonly = true)
public int getRecvWindow()
{
return recvWindow.get();
@ -753,6 +774,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener
}
@Override
@ManagedAttribute(value = "Whether HTTP/2 push is enabled", readonly = true)
public boolean isPushEnabled()
{
return pushEnabled;

View File

@ -31,15 +31,21 @@ import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.server.AbstractConnectionFactory;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.annotation.Name;
import org.eclipse.jetty.util.component.ContainerLifeCycle;
import org.eclipse.jetty.util.component.LifeCycle;
@ManagedObject
public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConnectionFactory
{
private final Connection.Listener connectionListener = new ConnectionListener();
private final HttpConfiguration httpConfiguration;
private int maxDynamicTableSize = 4096;
private int initialStreamSendWindow = FlowControlStrategy.DEFAULT_WINDOW_SIZE;
private int maxConcurrentStreams = -1;
private int maxHeaderBlockFragment = 0;
private final HttpConfiguration httpConfiguration;
public AbstractHTTP2ServerConnectionFactory(@Name("config") HttpConfiguration httpConfiguration)
{
@ -50,8 +56,10 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne
{
super(protocols);
this.httpConfiguration = Objects.requireNonNull(httpConfiguration);
addBean(httpConfiguration);
}
@ManagedAttribute("The HPACK dynamic table maximum size")
public int getMaxDynamicTableSize()
{
return maxDynamicTableSize;
@ -62,6 +70,7 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne
this.maxDynamicTableSize = maxDynamicTableSize;
}
@ManagedAttribute("The initial size of stream's flow control send window")
public int getInitialStreamSendWindow()
{
return initialStreamSendWindow;
@ -72,6 +81,7 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne
this.initialStreamSendWindow = initialStreamSendWindow;
}
@ManagedAttribute("The max number of concurrent streams per session")
public int getMaxConcurrentStreams()
{
return maxConcurrentStreams;
@ -116,7 +126,7 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne
ServerParser parser = newServerParser(connector, session);
HTTP2Connection connection = new HTTP2ServerConnection(connector.getByteBufferPool(), connector.getExecutor(),
endPoint, httpConfiguration, parser, session, getInputBufferSize(), listener);
connection.addListener(connectionListener);
return configure(connection, connector, endPoint);
}
@ -131,4 +141,19 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne
{
return new ServerParser(connector.getByteBufferPool(), listener, getMaxDynamicTableSize(), getHttpConfiguration().getRequestHeaderSize());
}
private static class ConnectionListener extends ContainerLifeCycle implements Connection.Listener
{
@Override
public void onOpened(Connection connection)
{
addManaged((LifeCycle)((HTTP2Connection)connection).getSession());
}
@Override
public void onClosed(Connection connection)
{
removeBean(((HTTP2Connection)connection).getSession());
}
}
}

View File

@ -26,22 +26,25 @@ import org.eclipse.jetty.io.AbstractConnection;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.util.ArrayUtil;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.component.ContainerLifeCycle;
import org.eclipse.jetty.util.ssl.SslContextFactory;
/* ------------------------------------------------------------ */
/**
* Abstract ConnectionFactory
* <p>Provides the common handling for {@link ConnectionFactory} implementations including:<ul>
* <li>Protocol identification
* <li>Configuration of new Connections:<ul>
* <li>Setting inputbuffer size
* <li>Calling {@link Connection#addListener(Connection.Listener)} for all
* Connection.Listener instances found as beans on the {@link Connector} and this {@link ConnectionFactory}
* </ul>
* <p>Provides the common handling for {@link ConnectionFactory} implementations including:</p>
* <ul>
* <li>Protocol identification</li>
* <li>Configuration of new Connections:
* <ul>
* <li>Setting inputbuffer size</li>
* <li>Calling {@link Connection#addListener(Connection.Listener)} for all
* Connection.Listener instances found as beans on the {@link Connector}
* and this {@link ConnectionFactory}</li>
* </ul>
* </ul>
*/
@ManagedObject
public abstract class AbstractConnectionFactory extends ContainerLifeCycle implements ConnectionFactory
{
private final String _protocol;
@ -53,7 +56,7 @@ public abstract class AbstractConnectionFactory extends ContainerLifeCycle imple
_protocol=protocol;
_protocols=Collections.unmodifiableList(Arrays.asList(new String[]{protocol}));
}
protected AbstractConnectionFactory(String... protocols)
{
_protocol=protocols[0];
@ -61,6 +64,7 @@ public abstract class AbstractConnectionFactory extends ContainerLifeCycle imple
}
@Override
@ManagedAttribute(value = "The protocol name", readonly = true)
public String getProtocol()
{
return _protocol;
@ -72,6 +76,7 @@ public abstract class AbstractConnectionFactory extends ContainerLifeCycle imple
return _protocols;
}
@ManagedAttribute("The buffer size used to read from the network")
public int getInputBufferSize()
{
return _inputbufferSize;
@ -96,7 +101,7 @@ public abstract class AbstractConnectionFactory extends ContainerLifeCycle imple
// Add Connection.Listeners from this factory
for (Connection.Listener listener : getBeans(Connection.Listener.class))
connection.addListener(listener);
return connection;
}