#15 return exception information while failed to execute script
This commit is contained in:
@@ -9,6 +9,12 @@ var context = {
|
||||
[actionName]: 123, // 操作名称:耗时
|
||||
}],
|
||||
|
||||
// exception info
|
||||
exceptionMessage: "",
|
||||
exceptionStacks: "",
|
||||
exceptionData: "", // such as script source code that cause exception
|
||||
|
||||
|
||||
// 客户输入和接口的返回结果
|
||||
input: {
|
||||
request:{
|
||||
|
||||
67
src/main/java/we/exception/ExecuteScriptException.java
Normal file
67
src/main/java/we/exception/ExecuteScriptException.java
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (C) 2020 the original author or authors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package we.exception;
|
||||
|
||||
import we.fizz.StepContext;
|
||||
|
||||
/**
|
||||
* @author Francis
|
||||
*/
|
||||
public class ExecuteScriptException extends RuntimeException {
|
||||
|
||||
private StepContext<String, Object> stepContext;
|
||||
|
||||
private Object data;
|
||||
|
||||
public ExecuteScriptException(String message, StepContext<String, Object> stepContext, Object data) {
|
||||
super(message);
|
||||
this.data = data;
|
||||
this.stepContext = stepContext;
|
||||
this.stepContext.setExceptionInfo(this, data);
|
||||
}
|
||||
|
||||
public ExecuteScriptException(Throwable cause, StepContext<String, Object> stepContext, Object data) {
|
||||
super("execute script failed: " + cause.getMessage(), cause);
|
||||
this.data = data;
|
||||
this.stepContext = stepContext;
|
||||
this.setStackTrace(cause.getStackTrace());
|
||||
this.stepContext.setExceptionInfo(this, data);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public Object getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(Object data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public StepContext<String, Object> getStepContext() {
|
||||
return stepContext;
|
||||
}
|
||||
|
||||
public void setStepContext(StepContext<String, Object> stepContext) {
|
||||
this.stepContext = stepContext;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -29,8 +29,11 @@ import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.WebExceptionHandler;
|
||||
import reactor.core.publisher.Mono;
|
||||
import we.exception.ExecuteScriptException;
|
||||
import we.exception.RedirectException;
|
||||
import we.exception.StopAndResponseException;
|
||||
import we.legacy.RespEntity;
|
||||
import we.util.JacksonUtils;
|
||||
import we.util.WebUtils;
|
||||
|
||||
/**
|
||||
@@ -60,6 +63,21 @@ public class FilterExceptionHandlerConfig {
|
||||
resp.getHeaders().setLocation(URI.create(ex.getRedirectUrl()));
|
||||
return Mono.empty();
|
||||
}
|
||||
}
|
||||
if (t instanceof ExecuteScriptException) {
|
||||
ExecuteScriptException ex = (ExecuteScriptException) t;
|
||||
ServerHttpResponse resp = exchange.getResponse();
|
||||
resp.getHeaders().add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
|
||||
|
||||
RespEntity rs = null;
|
||||
String reqId = exchange.getRequest().getId();
|
||||
if (ex.getStepContext() != null && ex.getStepContext().returnContext()) {
|
||||
rs = new RespEntity(HttpStatus.INTERNAL_SERVER_ERROR.value(), t.getMessage(), reqId, ex.getStepContext());
|
||||
return resp.writeWith(Mono.just(resp.bufferFactory().wrap(JacksonUtils.writeValueAsString(rs).getBytes())));
|
||||
}else {
|
||||
rs = new RespEntity(HttpStatus.INTERNAL_SERVER_ERROR.value(), t.getMessage(), reqId);
|
||||
return resp.writeWith(Mono.just(resp.bufferFactory().wrap(rs.toString().getBytes())));
|
||||
}
|
||||
}
|
||||
Mono<Void> vm = WebUtils.responseError(exchange, filterExceptionHandler, HttpStatus.INTERNAL_SERVER_ERROR.value(), t.getMessage(), t);
|
||||
return vm;
|
||||
|
||||
@@ -74,7 +74,7 @@ public class FizzGatewayFilter implements WebFilter {
|
||||
ServerHttpRequest request = exchange.getRequest();
|
||||
ServerHttpResponse serverHttpResponse = exchange.getResponse();
|
||||
|
||||
String path = WebUtils.PATH_PREFIX + WebUtils.getServiceId(exchange) + WebUtils.getReqPath(exchange);
|
||||
String path = WebUtils.getPathPrefix(exchange) + WebUtils.getServiceId(exchange) + WebUtils.getReqPath(exchange);
|
||||
String method = request.getMethodValue();
|
||||
AggregateResource aggregateResource = configLoader.matchAggregateResource(method, path);
|
||||
if (aggregateResource == null) {
|
||||
|
||||
@@ -32,6 +32,8 @@ public class AggregateResult {
|
||||
|
||||
private Map<String, Object> body;
|
||||
|
||||
private StepContext<String, Object> stepContext;
|
||||
|
||||
public MultiValueMap<String, String> getHeaders() {
|
||||
return headers;
|
||||
}
|
||||
@@ -48,4 +50,12 @@ public class AggregateResult {
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
public StepContext<String, Object> getStepContext() {
|
||||
return stepContext;
|
||||
}
|
||||
|
||||
public void setStepContext(StepContext<String, Object> stepContext) {
|
||||
this.stepContext = stepContext;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -36,12 +36,14 @@ import com.alibaba.fastjson.JSON;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import we.exception.ExecuteScriptException;
|
||||
import we.fizz.input.ClientInputConfig;
|
||||
import we.fizz.input.Input;
|
||||
import we.fizz.input.InputConfig;
|
||||
import we.fizz.input.PathMapping;
|
||||
import we.fizz.input.ScriptHelper;
|
||||
import we.flume.clients.log4j2appender.LogService;
|
||||
import we.util.JacksonUtils;
|
||||
import we.util.JsonSchemaUtils;
|
||||
import we.util.MapUtil;
|
||||
|
||||
@@ -184,8 +186,8 @@ public class Pipeline {
|
||||
stepResponse.setResult(stepBody);
|
||||
}
|
||||
} catch (ScriptException e) {
|
||||
LOGGER.warn("execute script failed, {}", e);
|
||||
throw new RuntimeException("execute script failed");
|
||||
LOGGER.warn("execute script failed, {}", JacksonUtils.writeValueAsString(scriptCfg), e);
|
||||
throw new ExecuteScriptException(e, stepContext, scriptCfg);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -238,8 +240,8 @@ public class Pipeline {
|
||||
body.putAll((Map<String, Object>) respBody);
|
||||
}
|
||||
} catch (ScriptException e) {
|
||||
LOGGER.warn("execute script failed, {}", e);
|
||||
throw new RuntimeException("execute script failed");
|
||||
LOGGER.warn("execute script failed, {}", JacksonUtils.writeValueAsString(scriptCfg), e);
|
||||
throw new ExecuteScriptException(e, stepContext, scriptCfg);
|
||||
}
|
||||
}
|
||||
response.put("body", body);
|
||||
@@ -249,7 +251,7 @@ public class Pipeline {
|
||||
Map<String, Object> respBody = (Map<String, Object>) response.get("body");
|
||||
// 测试模式返回StepContext
|
||||
if(stepContext.returnContext()) {
|
||||
respBody.put("_context", stepContext);
|
||||
respBody.put(stepContext.CONTEXT_FIELD, stepContext);
|
||||
}
|
||||
|
||||
aggResult.setBody((Map<String, Object>) response.get("body"));
|
||||
@@ -302,8 +304,8 @@ public class Pipeline {
|
||||
return errorList;
|
||||
}
|
||||
} catch (ScriptException e) {
|
||||
LOGGER.warn("execute script failed", e);
|
||||
throw new RuntimeException("execute script failed");
|
||||
LOGGER.warn("execute script failed, {}", JacksonUtils.writeValueAsString(scriptValidate), e);
|
||||
throw new ExecuteScriptException(e, stepContext, scriptValidate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,13 @@ public class StepContext<K, V> extends ConcurrentHashMap<K, V> {
|
||||
public static final String ELAPSED_TIMES = "elapsedTimes";
|
||||
public static final String DEBUG = "debug";
|
||||
public static final String RETURN_CONTEXT = "returnContext";
|
||||
// context field in response body
|
||||
public static final String CONTEXT_FIELD = "_context";
|
||||
|
||||
// exception info
|
||||
public static final String EXCEPTION_MESSAGE = "exceptionMessage";
|
||||
public static final String EXCEPTION_STACKS = "exceptionStacks";
|
||||
public static final String EXCEPTION_DATA = "exceptionData";
|
||||
|
||||
public void setDebug(Boolean debug) {
|
||||
this.put((K)DEBUG, (V)debug);
|
||||
@@ -68,6 +75,29 @@ public class StepContext<K, V> extends ConcurrentHashMap<K, V> {
|
||||
return Boolean.valueOf((String)getInputReqHeader(RETURN_CONTEXT));
|
||||
}
|
||||
|
||||
/**
|
||||
* set exception information
|
||||
* @param cause exception
|
||||
* @param exceptionData data that cause the exception, such as script source code, etc.
|
||||
*/
|
||||
public void setExceptionInfo(Throwable cause, Object exceptionData) {
|
||||
this.put((K) EXCEPTION_MESSAGE, (V) cause.getMessage());
|
||||
this.put((K) EXCEPTION_DATA, (V) exceptionData);
|
||||
|
||||
StackTraceElement[] stacks = cause.getStackTrace();
|
||||
if (stacks != null && stacks.length > 0) {
|
||||
String[] arr = new String[stacks.length];
|
||||
for (int i = 0; i < stacks.length; i++) {
|
||||
StackTraceElement ste = stacks[i];
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append(ste.getClassName()).append(".").append(ste.getMethodName()).append("(")
|
||||
.append(ste.getFileName()).append(":").append(ste.getLineNumber()).append(")");
|
||||
arr[i] = sb.toString();
|
||||
}
|
||||
this.put((K) EXCEPTION_STACKS, (V) arr);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void addElapsedTime(String actionName, Long milliSeconds) {
|
||||
List<Map<String, Long>> elapsedTimes = (List<Map<String, Long>>) this.get(ELAPSED_TIMES);
|
||||
if (elapsedTimes == null) {
|
||||
|
||||
@@ -38,10 +38,12 @@ import com.alibaba.fastjson.JSON;
|
||||
import reactor.core.publisher.Mono;
|
||||
import we.FizzAppContext;
|
||||
import we.constants.CommonConstants;
|
||||
import we.exception.ExecuteScriptException;
|
||||
import we.fizz.StepContext;
|
||||
import we.fizz.StepResponse;
|
||||
import we.flume.clients.log4j2appender.LogService;
|
||||
import we.proxy.FizzWebClient;
|
||||
import we.util.JacksonUtils;
|
||||
import we.util.MapUtil;
|
||||
|
||||
/**
|
||||
@@ -131,8 +133,8 @@ public class RequestInput extends Input {
|
||||
}
|
||||
} catch (ScriptException e) {
|
||||
LogService.setBizId(inputContext.getStepContext().getTraceId());
|
||||
LOGGER.warn("execute script failed, {}", e);
|
||||
throw new RuntimeException("execute script failed");
|
||||
LOGGER.warn("execute script failed, {}", JacksonUtils.writeValueAsString(scriptCfg), e);
|
||||
throw new ExecuteScriptException(e, stepContext, scriptCfg);
|
||||
}
|
||||
}
|
||||
request.put("body", body);
|
||||
@@ -187,8 +189,8 @@ public class RequestInput extends Input {
|
||||
}
|
||||
} catch (ScriptException e) {
|
||||
LogService.setBizId(inputContext.getStepContext().getTraceId());
|
||||
LOGGER.warn("execute script failed, {}", e);
|
||||
throw new RuntimeException("execute script failed");
|
||||
LOGGER.warn("execute script failed, {}", JacksonUtils.writeValueAsString(scriptCfg), e);
|
||||
throw new ExecuteScriptException(e, stepContext, scriptCfg);
|
||||
}
|
||||
}
|
||||
response.put("body", body);
|
||||
@@ -247,8 +249,8 @@ public class RequestInput extends Input {
|
||||
return needRun != null ? needRun : Boolean.TRUE;
|
||||
} catch (ScriptException e) {
|
||||
LogService.setBizId(inputContext.getStepContext().getTraceId());
|
||||
LOGGER.warn("execute script failed", e);
|
||||
throw new RuntimeException("execute script failed");
|
||||
LOGGER.warn("execute script failed, {}", JacksonUtils.writeValueAsString(condition), e);
|
||||
throw new ExecuteScriptException(e, stepContext, condition);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,9 +32,11 @@ import com.alibaba.fastjson.JSON;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import we.constants.CommonConstants;
|
||||
import we.exception.ExecuteScriptException;
|
||||
import we.exception.RedirectException;
|
||||
import we.exception.StopAndResponseException;
|
||||
import we.fizz.StepContext;
|
||||
import we.util.JacksonUtils;
|
||||
import we.util.Script;
|
||||
import we.util.ScriptUtils;
|
||||
|
||||
@@ -118,8 +120,8 @@ public class ScriptHelper {
|
||||
PathMapping.setByPath(target, entry.getKey(), execute(scriptCfg, ctxNode, stepContext, clazz));
|
||||
}
|
||||
} catch (ScriptException e) {
|
||||
LOGGER.warn("execute script failed, {}", e);
|
||||
throw new RuntimeException("execute script failed");
|
||||
LOGGER.warn("execute script failed, {}", JacksonUtils.writeValueAsString(scriptCfg), e);
|
||||
throw new ExecuteScriptException(e, stepContext, scriptCfg);
|
||||
}
|
||||
}
|
||||
if(starEntryKey != null) {
|
||||
@@ -145,7 +147,7 @@ public class ScriptHelper {
|
||||
|
||||
// 测试模式返回StepContext
|
||||
if (stepContext.returnContext()) {
|
||||
rs.put("_context", stepContext);
|
||||
rs.put(stepContext.CONTEXT_FIELD, stepContext);
|
||||
}
|
||||
|
||||
// exception
|
||||
|
||||
@@ -38,12 +38,21 @@ public class RespEntity {
|
||||
|
||||
public String reqId;
|
||||
|
||||
public Object _context;
|
||||
|
||||
public RespEntity(int code, String msg, @Nullable String reqId) {
|
||||
msgCode = code;
|
||||
message = msg;
|
||||
this.reqId = reqId;
|
||||
}
|
||||
|
||||
public RespEntity(int code, String msg, @Nullable String reqId, Object stepContext) {
|
||||
msgCode = code;
|
||||
message = msg;
|
||||
this.reqId = reqId;
|
||||
this._context = stepContext;
|
||||
}
|
||||
|
||||
private static final String resb = "$resb";
|
||||
|
||||
static {
|
||||
|
||||
@@ -121,6 +121,11 @@ public abstract class WebUtils {
|
||||
return svc;
|
||||
}
|
||||
|
||||
public static String getPathPrefix(ServerWebExchange exchange) {
|
||||
String p = exchange.getRequest().getPath().value();
|
||||
return p.substring(0, p.indexOf(getServiceId(exchange)));
|
||||
}
|
||||
|
||||
public static Mono<Void> getDirectResponse(ServerWebExchange exchange) {
|
||||
return (Mono<Void>) exchange.getAttributes().get(WebUtils.directResponse);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user