diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/Entry.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/Entry.java index 87400229..dd763773 100755 --- a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/Entry.java +++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/Entry.java @@ -15,6 +15,7 @@ */ package com.alibaba.csp.sentinel; +import com.alibaba.csp.sentinel.slots.block.BlockException; import com.alibaba.csp.sentinel.util.TimeUtil; import com.alibaba.csp.sentinel.context.ContextUtil; import com.alibaba.csp.sentinel.node.Node; @@ -44,6 +45,7 @@ import com.alibaba.csp.sentinel.context.Context; * @author qinan.qn * @author jialiang.linjl * @author leyou(lihao) + * @author Eric Zhao * @see SphU * @see Context * @see ContextUtil @@ -52,18 +54,23 @@ public abstract class Entry implements AutoCloseable { private static final Object[] OBJECTS0 = new Object[0]; - private long createTime; + private final long createTimestamp; + private long completeTimestamp; + private Node curNode; /** * {@link Node} of the specific origin, Usually the origin is the Service Consumer. */ private Node originNode; + private Throwable error; - protected ResourceWrapper resourceWrapper; + private BlockException blockError; + + protected final ResourceWrapper resourceWrapper; public Entry(ResourceWrapper resourceWrapper) { this.resourceWrapper = resourceWrapper; - this.createTime = TimeUtil.currentTimeMillis(); + this.createTimestamp = TimeUtil.currentTimeMillis(); } public ResourceWrapper getResourceWrapper() { @@ -119,8 +126,17 @@ public abstract class Entry implements AutoCloseable { */ public abstract Node getLastNode(); - public long getCreateTime() { - return createTime; + public long getCreateTimestamp() { + return createTimestamp; + } + + public long getCompleteTimestamp() { + return completeTimestamp; + } + + public Entry setCompleteTimestamp(long completeTimestamp) { + this.completeTimestamp = completeTimestamp; + return this; } public Node getCurNode() { @@ -131,6 +147,15 @@ public abstract class Entry implements AutoCloseable { this.curNode = node; } + public BlockException getBlockError() { + return blockError; + } + + public Entry setBlockError(BlockException blockError) { + this.blockError = blockError; + return this; + } + public Throwable getError() { return error; } diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/metric/extension/callback/MetricExitCallback.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/metric/extension/callback/MetricExitCallback.java index 334a8f3a..5f46bd83 100644 --- a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/metric/extension/callback/MetricExitCallback.java +++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/metric/extension/callback/MetricExitCallback.java @@ -14,14 +14,22 @@ import com.alibaba.csp.sentinel.util.TimeUtil; * @since 1.6.1 */ public class MetricExitCallback implements ProcessorSlotExitCallback { + @Override public void onExit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) { for (MetricExtension m : MetricExtensionProvider.getMetricExtensions()) { - if (context.getCurEntry().getError() == null) { - long realRt = TimeUtil.currentTimeMillis() - context.getCurEntry().getCreateTime(); - m.addRt(resourceWrapper.getName(), realRt, args); - m.addSuccess(resourceWrapper.getName(), count, args); - m.decreaseThreadNum(resourceWrapper.getName(), args); + if (context.getCurEntry().getBlockError() != null) { + continue; + } + String resource = resourceWrapper.getName(); + long realRt = TimeUtil.currentTimeMillis() - context.getCurEntry().getCreateTimestamp(); + m.addRt(resource, realRt, args); + m.addSuccess(resource, count, args); + m.decreaseThreadNum(resource, args); + + Throwable ex = context.getCurEntry().getError(); + if (ex != null) { + m.addException(resource, count, ex); } } } diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/statistic/StatisticSlot.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/statistic/StatisticSlot.java index 96005d31..d491a16a 100755 --- a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/statistic/StatisticSlot.java +++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/statistic/StatisticSlot.java @@ -17,7 +17,7 @@ package com.alibaba.csp.sentinel.slots.statistic; import java.util.Collection; -import com.alibaba.csp.sentinel.config.SentinelConfig; +import com.alibaba.csp.sentinel.node.Node; import com.alibaba.csp.sentinel.slotchain.ProcessorSlotEntryCallback; import com.alibaba.csp.sentinel.slotchain.ProcessorSlotExitCallback; import com.alibaba.csp.sentinel.slots.block.flow.PriorityWaitException; @@ -95,7 +95,7 @@ public class StatisticSlot extends AbstractLinkedProcessorSlot { } } catch (BlockException e) { // Blocked, set block exception to current entry. - context.getCurEntry().setError(e); + context.getCurEntry().setBlockError(e); // Add block count. node.increaseBlockQps(count); @@ -115,52 +115,31 @@ public class StatisticSlot extends AbstractLinkedProcessorSlot { throw e; } catch (Throwable e) { - // Unexpected error, set error to current entry. + // Unexpected internal error, set error to current entry. context.getCurEntry().setError(e); - // This should not happen. - node.increaseExceptionQps(count); - if (context.getCurEntry().getOriginNode() != null) { - context.getCurEntry().getOriginNode().increaseExceptionQps(count); - } - - if (resourceWrapper.getEntryType() == EntryType.IN) { - Constants.ENTRY_NODE.increaseExceptionQps(count); - } throw e; } } @Override public void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) { - DefaultNode node = (DefaultNode)context.getCurNode(); + Node node = context.getCurNode(); - if (context.getCurEntry().getError() == null) { - // Calculate response time (max RT is statisticMaxRt from SentinelConfig). - long rt = TimeUtil.currentTimeMillis() - context.getCurEntry().getCreateTime(); - int maxStatisticRt = SentinelConfig.statisticMaxRt(); - if (rt > maxStatisticRt) { - rt = maxStatisticRt; - } + if (context.getCurEntry().getBlockError() == null) { + // Calculate response time (use completeStatTime as the time of completion). + long completeStatTime = TimeUtil.currentTimeMillis(); + context.getCurEntry().setCompleteTimestamp(completeStatTime); + long rt = completeStatTime - context.getCurEntry().getCreateTimestamp(); + + Throwable error = context.getCurEntry().getError(); // Record response time and success count. - node.addRtAndSuccess(rt, count); - if (context.getCurEntry().getOriginNode() != null) { - context.getCurEntry().getOriginNode().addRtAndSuccess(rt, count); - } - - node.decreaseThreadNum(); - - if (context.getCurEntry().getOriginNode() != null) { - context.getCurEntry().getOriginNode().decreaseThreadNum(); - } - + recordCompleteFor(node, count, rt, error); + recordCompleteFor(context.getCurEntry().getOriginNode(), count, rt, error); if (resourceWrapper.getEntryType() == EntryType.IN) { - Constants.ENTRY_NODE.addRtAndSuccess(rt, count); - Constants.ENTRY_NODE.decreaseThreadNum(); + recordCompleteFor(Constants.ENTRY_NODE, count, rt, error); } - } else { - // Error may happen. } // Handle exit event with registered exit callback handlers. @@ -171,4 +150,16 @@ public class StatisticSlot extends AbstractLinkedProcessorSlot { fireExit(context, resourceWrapper, count); } + + private void recordCompleteFor(Node node, int batchCount, long rt, Throwable error) { + if (node == null) { + return; + } + node.addRtAndSuccess(rt, batchCount); + node.decreaseThreadNum(); + + if (error != null && !(error instanceof BlockException)) { + node.increaseExceptionQps(batchCount); + } + } } diff --git a/sentinel-core/src/test/java/com/alibaba/csp/sentinel/metric/extension/callback/MetricExitCallbackTest.java b/sentinel-core/src/test/java/com/alibaba/csp/sentinel/metric/extension/callback/MetricExitCallbackTest.java index 604c94c2..490912c6 100644 --- a/sentinel-core/src/test/java/com/alibaba/csp/sentinel/metric/extension/callback/MetricExitCallbackTest.java +++ b/sentinel-core/src/test/java/com/alibaba/csp/sentinel/metric/extension/callback/MetricExitCallbackTest.java @@ -55,7 +55,7 @@ public class MetricExitCallbackTest extends AbstractTimeBasedTest { int deltaMs = 100; when(entry.getError()).thenReturn(null); - when(entry.getCreateTime()).thenReturn(curMillis - deltaMs); + when(entry.getCreateTimestamp()).thenReturn(curMillis - deltaMs); when(context.getCurEntry()).thenReturn(entry); exitCallback.onExit(context, resourceWrapper, count, args); Assert.assertEquals(prevRt + deltaMs, extension.rt); diff --git a/sentinel-extension/sentinel-parameter-flow-control/src/main/java/com/alibaba/csp/sentinel/slots/statistic/ParamFlowStatisticExitCallback.java b/sentinel-extension/sentinel-parameter-flow-control/src/main/java/com/alibaba/csp/sentinel/slots/statistic/ParamFlowStatisticExitCallback.java index d3446ff5..97a2fc22 100644 --- a/sentinel-extension/sentinel-parameter-flow-control/src/main/java/com/alibaba/csp/sentinel/slots/statistic/ParamFlowStatisticExitCallback.java +++ b/sentinel-extension/sentinel-parameter-flow-control/src/main/java/com/alibaba/csp/sentinel/slots/statistic/ParamFlowStatisticExitCallback.java @@ -29,7 +29,7 @@ public class ParamFlowStatisticExitCallback implements ProcessorSlotExitCallback @Override public void onExit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) { - if (context.getCurEntry().getError() == null) { + if (context.getCurEntry().getBlockError() == null) { ParameterMetric parameterMetric = ParameterMetricStorage.getParamMetric(resourceWrapper); if (parameterMetric != null) {