Signed-off-by: Eric Zhao <sczyh16@gmail.com>master
@@ -61,7 +61,8 @@ public @interface SentinelResource { | |||||
String fallback() default ""; | String fallback() default ""; | ||||
/** | /** | ||||
* @return the exception classes to trace, Throwable.class by default | |||||
* @return the list of exception classes to trace, {@link Throwable} by default | |||||
* @since 1.5.1 | |||||
*/ | */ | ||||
Class<? extends Throwable>[] exceptionsToTrace() default {Throwable.class}; | Class<? extends Throwable>[] exceptionsToTrace() default {Throwable.class}; | ||||
} | } |
@@ -11,6 +11,7 @@ The `@SentinelResource` annotation indicates a resource definition, including: | |||||
- `entryType`: Resource entry type (inbound or outbound), `EntryType.OUT` by default | - `entryType`: Resource entry type (inbound or outbound), `EntryType.OUT` by default | ||||
- `fallback`: Fallback method when degraded (optional). The fallback method should be located in the same class with original method. The signature of the fallback method should match the original method (parameter types and return type). | - `fallback`: Fallback method when degraded (optional). The fallback method should be located in the same class with original method. The signature of the fallback method should match the original method (parameter types and return type). | ||||
- `blockHandler`: Handler method that handles `BlockException` when blocked. The signature should match original method, with the last additional parameter type `BlockException`. The block handler method should be located in the same class with original method by default. If you want to use method in other classes, you can set the `blockHandlerClass` with corresponding `Class` (Note the method in other classes must be *static*). | - `blockHandler`: Handler method that handles `BlockException` when blocked. The signature should match original method, with the last additional parameter type `BlockException`. The block handler method should be located in the same class with original method by default. If you want to use method in other classes, you can set the `blockHandlerClass` with corresponding `Class` (Note the method in other classes must be *static*). | ||||
- `exceptionsToTrace`: List of business exception classes to trace and record (since 1.5.1). | |||||
For example: | For example: | ||||
@@ -15,6 +15,7 @@ | |||||
*/ | */ | ||||
package com.alibaba.csp.sentinel.annotation.aspectj; | package com.alibaba.csp.sentinel.annotation.aspectj; | ||||
import com.alibaba.csp.sentinel.Tracer; | |||||
import com.alibaba.csp.sentinel.annotation.SentinelResource; | import com.alibaba.csp.sentinel.annotation.SentinelResource; | ||||
import com.alibaba.csp.sentinel.log.RecordLog; | import com.alibaba.csp.sentinel.log.RecordLog; | ||||
import com.alibaba.csp.sentinel.slots.block.BlockException; | import com.alibaba.csp.sentinel.slots.block.BlockException; | ||||
@@ -76,6 +77,31 @@ public abstract class AbstractSentinelAspectSupport { | |||||
throw ex; | throw ex; | ||||
} | } | ||||
protected void traceException(Throwable ex, SentinelResource annotation) { | |||||
if (isTracedException(ex, annotation.exceptionsToTrace())) { | |||||
Tracer.trace(ex); | |||||
} | |||||
} | |||||
/** | |||||
* Check whether the exception is in tracked list of exception classes. | |||||
* | |||||
* @param ex provided throwable | |||||
* @param exceptionsToTrace list of exceptions to trace | |||||
* @return true if it should be traced, otherwise false | |||||
*/ | |||||
private boolean isTracedException(Throwable ex, Class<? extends Throwable>[] exceptionsToTrace) { | |||||
if (exceptionsToTrace == null) { | |||||
return false; | |||||
} | |||||
for (Class<? extends Throwable> exceptionToTrace : exceptionsToTrace) { | |||||
if (exceptionToTrace.isAssignableFrom(ex.getClass())) { | |||||
return true; | |||||
} | |||||
} | |||||
return false; | |||||
} | |||||
private boolean isDegradeFailure(/*@NonNull*/ BlockException ex) { | private boolean isDegradeFailure(/*@NonNull*/ BlockException ex) { | ||||
return ex instanceof DegradeException; | return ex instanceof DegradeException; | ||||
} | } | ||||
@@ -18,7 +18,6 @@ package com.alibaba.csp.sentinel.annotation.aspectj; | |||||
import com.alibaba.csp.sentinel.Entry; | import com.alibaba.csp.sentinel.Entry; | ||||
import com.alibaba.csp.sentinel.EntryType; | import com.alibaba.csp.sentinel.EntryType; | ||||
import com.alibaba.csp.sentinel.SphU; | import com.alibaba.csp.sentinel.SphU; | ||||
import com.alibaba.csp.sentinel.Tracer; | |||||
import com.alibaba.csp.sentinel.annotation.SentinelResource; | import com.alibaba.csp.sentinel.annotation.SentinelResource; | ||||
import com.alibaba.csp.sentinel.slots.block.BlockException; | import com.alibaba.csp.sentinel.slots.block.BlockException; | ||||
import org.aspectj.lang.ProceedingJoinPoint; | import org.aspectj.lang.ProceedingJoinPoint; | ||||
@@ -59,9 +58,7 @@ public class SentinelResourceAspect extends AbstractSentinelAspectSupport { | |||||
} catch (BlockException ex) { | } catch (BlockException ex) { | ||||
return handleBlockException(pjp, annotation, ex); | return handleBlockException(pjp, annotation, ex); | ||||
} catch (Throwable ex) { | } catch (Throwable ex) { | ||||
if (isTrackedException(ex, annotation.exceptionsToTrace())) { | |||||
Tracer.trace(ex); | |||||
} | |||||
traceException(ex, annotation); | |||||
throw ex; | throw ex; | ||||
} finally { | } finally { | ||||
if (entry != null) { | if (entry != null) { | ||||
@@ -69,23 +66,4 @@ public class SentinelResourceAspect extends AbstractSentinelAspectSupport { | |||||
} | } | ||||
} | } | ||||
} | } | ||||
/** | |||||
* whether the exception is in tracked list of exception classes | |||||
* | |||||
* @param ex | |||||
* @param exceptionsToTrace | |||||
* @return | |||||
*/ | |||||
private boolean isTrackedException(Throwable ex, Class<? extends Throwable>[] exceptionsToTrace) { | |||||
if (exceptionsToTrace == null) { | |||||
return false; | |||||
} | |||||
for (Class exceptionToTrace : exceptionsToTrace) { | |||||
if (exceptionToTrace.isAssignableFrom(ex.getClass())) { | |||||
return true; | |||||
} | |||||
} | |||||
return false; | |||||
} | |||||
} | } |
@@ -98,7 +98,15 @@ public class SentinelAnnotationIntegrationTest extends AbstractJUnit4SpringConte | |||||
try { | try { | ||||
fooService.foo(5758); | fooService.foo(5758); | ||||
fail("should not reach here"); | fail("should not reach here"); | ||||
} catch (IllegalAccessException ex) { | |||||
} catch (Exception ex) { | |||||
// Should not be traced. | |||||
assertThat(cn.exceptionQps()).isZero(); | |||||
} | |||||
try { | |||||
fooService.foo(5763); | |||||
fail("should not reach here"); | |||||
} catch (Exception ex) { | |||||
assertThat(cn.exceptionQps()).isPositive(); | assertThat(cn.exceptionQps()).isPositive(); | ||||
} | } | ||||
@@ -18,6 +18,7 @@ package com.alibaba.csp.sentinel.annotation.aspectj.integration.service; | |||||
import com.alibaba.csp.sentinel.annotation.SentinelResource; | import com.alibaba.csp.sentinel.annotation.SentinelResource; | ||||
import com.alibaba.csp.sentinel.slots.block.BlockException; | import com.alibaba.csp.sentinel.slots.block.BlockException; | ||||
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException; | import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException; | ||||
import org.springframework.stereotype.Service; | import org.springframework.stereotype.Service; | ||||
import java.util.concurrent.ThreadLocalRandom; | import java.util.concurrent.ThreadLocalRandom; | ||||
@@ -28,7 +29,8 @@ import java.util.concurrent.ThreadLocalRandom; | |||||
@Service | @Service | ||||
public class FooService { | public class FooService { | ||||
@SentinelResource(value = "apiFoo", blockHandler = "fooBlockHandler", fallback = "fooFallbackFunc") | |||||
@SentinelResource(value = "apiFoo", blockHandler = "fooBlockHandler", fallback = "fooFallbackFunc", | |||||
exceptionsToTrace = {IllegalArgumentException.class}) | |||||
public String foo(int i) throws Exception { | public String foo(int i) throws Exception { | ||||
if (i == 9527) { | if (i == 9527) { | ||||
throw new DegradeException("ggg"); | throw new DegradeException("ggg"); | ||||
@@ -36,6 +38,9 @@ public class FooService { | |||||
if (i == 5758) { | if (i == 5758) { | ||||
throw new IllegalAccessException(); | throw new IllegalAccessException(); | ||||
} | } | ||||
if (i == 5763) { | |||||
throw new IllegalArgumentException(); | |||||
} | |||||
return "Hello for " + i; | return "Hello for " + i; | ||||
} | } | ||||