changeset 1233:3cbe1f2437b0

Http2Metric
author Devel 2
date Mon, 29 Jun 2020 11:25:32 +0200
parents 0ca4d4cc31ef
children e0985c791eae
files stress-tester/src/main/java/com/passus/st/client/http/Http2FlowHandler.java stress-tester/src/main/java/com/passus/st/client/http/Http2FlowHandlerDataDecoder.java stress-tester/src/main/java/com/passus/st/client/http/Http2FlowHandlerDataEncoder.java stress-tester/src/main/java/com/passus/st/client/http/Http2Metric.java stress-tester/src/main/java/com/passus/st/client/http/HttpMetric.java
diffstat 5 files changed, 117 insertions(+), 19 deletions(-) [+]
line wrap: on
line diff
--- a/stress-tester/src/main/java/com/passus/st/client/http/Http2FlowHandler.java	Mon Jun 29 10:53:53 2020 +0200
+++ b/stress-tester/src/main/java/com/passus/st/client/http/Http2FlowHandler.java	Mon Jun 29 11:25:32 2020 +0200
@@ -1,8 +1,9 @@
 package com.passus.st.client.http;
 
+import com.passus.commons.Assert;
 import com.passus.commons.time.TimeAware;
 import com.passus.commons.time.TimeGenerator;
-import com.passus.net.http2.Http2Utils;
+import com.passus.net.http.HttpRequest;
 import com.passus.st.client.FlowContext;
 import com.passus.st.client.FlowHandler;
 import com.passus.st.client.FlowHandlerDataDecoder;
@@ -10,33 +11,41 @@
 import com.passus.st.metric.MetricsContainer;
 
 import static com.passus.st.Protocols.HTTP2;
-import static com.passus.st.client.FlowUtils.queueFirstRequestSessionPayload;
-import static com.passus.st.client.SessionPayloadEvent.FLAG_RAW;
+import static com.passus.st.client.http.HttpConsts.TAG_TIME_END;
+import static com.passus.st.client.http.HttpConsts.TAG_TIME_START;
 
 public class Http2FlowHandler implements FlowHandler, TimeAware {
 
+    HttpMetric metric;
+
     boolean collectMetrics = false;
 
+    HttpScopes scopes;
+
     private final Http2FlowContext context;
 
     private final Http2FlowHandlerDataDecoder decoder;
 
     private final Http2FlowHandlerDataEncoder encoder;
 
+    TimeGenerator timeGenerator = TimeGenerator.getDefaultGenerator();
+
     public Http2FlowHandler() {
         context = new Http2FlowContext();
-        decoder = new Http2FlowHandlerDataDecoder(context);
-        encoder = new Http2FlowHandlerDataEncoder(context);
+        decoder = new Http2FlowHandlerDataDecoder(this, context);
+        encoder = new Http2FlowHandlerDataEncoder(this, context);
+        scopes = new HttpScopes();
     }
 
     @Override
     public TimeGenerator getTimeGenerator() {
-        return null;
+        return timeGenerator;
     }
 
     @Override
     public void setTimeGenerator(TimeGenerator generator) {
-
+        Assert.notNull(timeGenerator, "timeGenerator");
+        this.timeGenerator = generator;
     }
 
     @Override
@@ -62,21 +71,44 @@
     @Override
     public void setCollectMetrics(boolean collectMetrics) {
         this.collectMetrics = collectMetrics;
+        if (collectMetrics) {
+            metric = new Http2Metric();
+            synchronized (metric) {
+                metric.activate();
+            }
+        } else if (metric != null) {
+            synchronized (metric) {
+                metric.deactivate();
+            }
+            metric = null;
+        }
     }
 
     @Override
     public void writeMetrics(MetricsContainer container) {
-
+        if (collectMetrics) {
+            synchronized (metric) {
+                container.update(metric);
+                metric.reset();
+            }
+        }
     }
 
     @Override
     public void init(FlowContext flowContext) {
-
+        flowContext.setParam(HttpFlowConst.PARAM_HTTP_CONTEXT, new HttpFlowContext(flowContext, scopes));
     }
 
     @Override
-    public void onConnected(FlowContext flowContext) {
+    public void onDataWriteStart(FlowContext flowContext) {
+        long now = timeGenerator.currentTimeMillis();
+        ((HttpRequest) flowContext.sentEvent().getRequest()).setTag(TAG_TIME_START, now);
+    }
 
+    @Override
+    public void onDataWriteEnd(FlowContext flowContext) {
+        long now = timeGenerator.currentTimeMillis();
+        ((HttpRequest) (flowContext.sentEvent().getRequest())).setTag(TAG_TIME_END, now);
     }
 
 
--- a/stress-tester/src/main/java/com/passus/st/client/http/Http2FlowHandlerDataDecoder.java	Mon Jun 29 10:53:53 2020 +0200
+++ b/stress-tester/src/main/java/com/passus/st/client/http/Http2FlowHandlerDataDecoder.java	Mon Jun 29 11:25:32 2020 +0200
@@ -4,6 +4,7 @@
 import com.passus.net.FixedSizeLengthPduX;
 import com.passus.net.FixedSizeLengthPduXHandler;
 import com.passus.net.http.HttpHeadersImpl;
+import com.passus.net.http.HttpRequest;
 import com.passus.net.http.HttpResponse;
 import com.passus.net.http.HttpStatus;
 import com.passus.net.http2.*;
@@ -19,11 +20,14 @@
 import static com.passus.data.DataDecoder.STATE_DATA_NEEDED;
 import static com.passus.data.DataDecoder.STATE_FINISHED;
 import static com.passus.net.http2.Http2Utils.*;
+import static com.passus.st.client.http.HttpConsts.*;
 
 public class Http2FlowHandlerDataDecoder implements FlowHandlerDataDecoder<HttpResponse> {
 
     private final Logger LOGGER = LogManager.getLogger(Http2FlowHandlerDataDecoder.class);
 
+    private final Http2FlowHandler handler;
+
     private final Http2FrameDecoder decoder = new Http2FrameDecoder();
 
     private HttpResponse resp;
@@ -36,11 +40,13 @@
 
     private final FixedSizeLengthPduX pdu;
 
-    private List<Http2Frame> streamFrames;
+    private final PduHandler pduHandler;
 
-    public Http2FlowHandlerDataDecoder(Http2FlowContext context) {
+    public Http2FlowHandlerDataDecoder(Http2FlowHandler handler, Http2FlowContext context) {
+        this.handler = handler;
         this.context = context;
-        pdu = new FixedSizeLengthPduX(new PduHandler(), 3, 6);
+        pduHandler = new PduHandler();
+        pdu = new FixedSizeLengthPduX(pduHandler, 3, 6);
     }
 
     @Override
@@ -58,6 +64,7 @@
         state = STATE_DATA_NEEDED;
         error = null;
         pdu.clear();
+        pduHandler.clear();
         resp = null;
     }
 
@@ -68,12 +75,32 @@
 
     @Override
     public int decode(ByteBuff buffer, FlowContext flowContext) {
+        pduHandler.flowContext = flowContext;
         pdu.handle(buffer.buffer(), buffer.startIndex(), buffer.length());
         return buffer.length();
     }
 
     private class PduHandler implements FixedSizeLengthPduXHandler {
 
+        FlowContext flowContext;
+
+        private int headerSize;
+
+        private int contentSize;
+
+        private HttpRequest lastRequest(FlowContext flowContext) {
+            if (flowContext.sentEvent() != null) {
+                return (HttpRequest) flowContext.sentEvent().getRequest();
+            }
+
+            return null;
+        }
+
+        private void clear() {
+            headerSize = 0;
+            contentSize = 0;
+        }
+
         @Override
         public void decodeBlockLength(byte[] data, int offset, MutableInt value) {
             value.setValue(DataUtils.getInt3(data, offset));
@@ -158,7 +185,6 @@
             if ((frame.getFlags() & FLAG_END_STREAM) == FLAG_END_STREAM) {
                 context.streams.remove(streamId);
                 resp = assemble(stream.frames);
-                streamFrames = stream.frames;
                 state = STATE_FINISHED;
             }
         }
@@ -171,6 +197,8 @@
                 if (frame.getType() == FRAME_HEADERS) {
                     Http2HeadersFrame headersFrame = (Http2HeadersFrame) frame;
                     headers.addAll(headersFrame.getHeaders());
+
+                    headerSize = headersFrame.getLength() + 9;
                 } else if (frame.getType() == FRAME_DATA) {
                     if (dataFrames == null) {
                         dataFrames = new ArrayList<>();
@@ -179,6 +207,7 @@
                     dataFrames.add(dataFrame);
                     byte[] data = dataFrame.getData();
                     contentLength += data.length;
+                    contentSize += contentLength;
                 }
             }
 
@@ -217,6 +246,25 @@
             } else if (decoder.state() == STATE_FINISHED) {
                 processFrame(decoder.getResult());
                 decoder.clear();
+
+                if (resp != null) {
+                    long now = handler.timeGenerator.currentTimeMillis();
+                    if (handler.isCollectMetrics()) {
+                        HttpRequest lastRequest = lastRequest(flowContext);
+                        synchronized (handler.metric) {
+                            handler.metric.addResponseStatusCode(resp.getStatus().getCode());
+                            handler.metric.addResponseSize(headerSize + contentSize);
+                            if (lastRequest != null) {
+                                handler.metric.addResponseTime(now - (long) lastRequest.getTag(TAG_TIME_START));
+                            }
+                        }
+                    }
+
+                    resp.setTag(TAG_HEADER_SIZE, headerSize);
+                    resp.setTag(TAG_CONTENT_SIZE, contentSize);
+                    resp.setTag(TAG_TIME_START, flowContext.receivedStartTimestamp());
+                    resp.setTag(TAG_TIME_END, now);
+                }
             }
         }
     }
--- a/stress-tester/src/main/java/com/passus/st/client/http/Http2FlowHandlerDataEncoder.java	Mon Jun 29 10:53:53 2020 +0200
+++ b/stress-tester/src/main/java/com/passus/st/client/http/Http2FlowHandlerDataEncoder.java	Mon Jun 29 11:25:32 2020 +0200
@@ -2,7 +2,6 @@
 
 import com.passus.data.ByteBuff;
 import com.passus.data.HeapByteBuff;
-import com.passus.net.http.HttpHeaders;
 import com.passus.net.http.HttpMessage;
 import com.passus.net.http.HttpRequest;
 import com.passus.net.http2.Http2FrameEncoder;
@@ -13,11 +12,15 @@
 import com.passus.st.client.FlowHandlerDataEncoder;
 
 import static com.passus.net.http2.Http2Utils.*;
+import static com.passus.st.client.http.HttpConsts.TAG_CONTENT_SIZE;
+import static com.passus.st.client.http.HttpConsts.TAG_HEADER_SIZE;
 
 public class Http2FlowHandlerDataEncoder implements FlowHandlerDataEncoder<HttpRequest> {
 
     private static final int DEFAULT_BUFFER_CAPACITY = 1024;
 
+    private final Http2FlowHandler handler;
+
     private final Http2FlowContext context;
 
     private final Http2FrameEncoder encoder = new Http2FrameEncoder();
@@ -28,11 +31,12 @@
 
     private int windowSize = 1;
 
-    public Http2FlowHandlerDataEncoder(Http2FlowContext context) {
+    public Http2FlowHandlerDataEncoder(Http2FlowHandler handler, Http2FlowContext context) {
+        this.handler = handler;
         this.context = context;
     }
 
-    private void encodeHeaders(HttpMessage msg, ByteBuff out) {
+    private int encodeHeaders(HttpMessage msg, ByteBuff out) {
         byteBuffer.clear();
         encoder.encodeHeaders(msg.getHeaders(), byteBuffer);
 
@@ -48,6 +52,8 @@
         Http2Stream stream = new Http2Stream(nextStreamId);
         stream.state = Http2Stream.STATE_OPEN;
         context.registerStream(stream);
+
+        return byteBuffer.length();
     }
 
     @Override
@@ -78,7 +84,10 @@
             context.remoteFlags &= ~Http2FlowContext.FLAG_SETTINGS_SENT;
         }
 
-        encodeHeaders(request, out);
+        int headerSize = encodeHeaders(request, out);
+        request.setTag(TAG_HEADER_SIZE, headerSize);
+        request.setTag(TAG_CONTENT_SIZE, flowContext.buffer().readableBytes() - headerSize);
+
     }
 
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stress-tester/src/main/java/com/passus/st/client/http/Http2Metric.java	Mon Jun 29 11:25:32 2020 +0200
@@ -0,0 +1,10 @@
+package com.passus.st.client.http;
+
+public class Http2Metric extends HttpMetric {
+
+    public static final String DEFAULT_NAME = "HTTP2";
+
+    public Http2Metric() {
+        super(DEFAULT_NAME);
+    }
+}
--- a/stress-tester/src/main/java/com/passus/st/client/http/HttpMetric.java	Mon Jun 29 10:53:53 2020 +0200
+++ b/stress-tester/src/main/java/com/passus/st/client/http/HttpMetric.java	Mon Jun 29 11:25:32 2020 +0200
@@ -31,7 +31,6 @@
         attrs.put("responseStatusCodes", respStatuses);
         attrs.put("responseTimeDist", responseTimeHistogram);
         attrs.put("responseSizeHistogram", responseSizeHistogram);
-
     }
 
     @Override