diff --git a/rxlib/src/main/java/org/rx/bean/DateTime.java b/rxlib/src/main/java/org/rx/bean/DateTime.java index 2693bd36..e27b1b37 100644 --- a/rxlib/src/main/java/org/rx/bean/DateTime.java +++ b/rxlib/src/main/java/org/rx/bean/DateTime.java @@ -4,8 +4,7 @@ import lombok.SneakyThrows; import org.apache.commons.lang3.time.FastDateFormat; import org.rx.annotation.ErrorCode; -import org.rx.core.Arrays; -import org.rx.core.Linq; +import org.rx.core.RxConfig; import org.rx.exception.ApplicationException; import java.text.ParseException; @@ -15,6 +14,7 @@ import java.util.TimeZone; import static org.rx.core.Constants.NON_UNCHECKED; +import static org.rx.core.Extends.ifNull; import static org.rx.core.Extends.values; /** @@ -24,11 +24,14 @@ public final class DateTime extends Date { private static final long serialVersionUID = 414744178681347341L; public static final DateTime MIN = new DateTime(2000, 1, 1, 0, 0, 0), MAX = new DateTime(9999, 12, 31, 0, 0, 0); - static final String DATE_FORMAT = "yyy-MM-dd"; - static final String TIME_FORMAT = "HH:mm:ss"; + public static final String DATE_FORMAT = "yyy-MM-dd"; + public static final String TIME_FORMAT = "HH:mm:ss"; public static final String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss"; - public static final String FULL_FORMAT = "yyyy-MM-dd HH:mm:ss,SSSZ"; - public static final Linq FORMATS = Linq.from(DATE_TIME_FORMAT, "yyyy-MM-dd HH:mm:ss,SSS", FULL_FORMAT, "yyyyMMddHHmmssSSS"); + public static final String ISO_DATE_TIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"; + //2020-02-02 14:00:00.001 会适配 yyyy-MM-dd HH:mm:ss + public static final String[] FORMATS = new String[]{ISO_DATE_TIME_FORMAT, "yyyy-MM-dd HH:mm:ss.SSSZ", "yyyy-MM-dd HH:mm:ss.SSS", + DATE_TIME_FORMAT, DATE_FORMAT, TIME_FORMAT, + "yyyyMMddHHmmssSSS"}; static final TimeZone UTC_ZONE = TimeZone.getTimeZone("UTC"); public static DateTime now() { @@ -44,11 +47,20 @@ public static DateTime utcNow() { } @ErrorCode(cause = ParseException.class) - public static DateTime valueOf(String dateString) { + public static DateTime valueOf(@NonNull String dateString) { Throwable lastEx = null; - for (String format : Arrays.toList(DATE_TIME_FORMAT, "yyyy-MM-dd HH:mm:ss,SSS", FULL_FORMAT, "yyyyMMddHHmmssSSS")) { + int offset = dateString.length() >= 23 ? 0 : 3; + int len = offset + 3, fb = 6; + for (int i = offset; i < len; i++) { try { - return valueOf(dateString, format); + return valueOf(dateString, FORMATS[i]); + } catch (Throwable ex) { + lastEx = ex; + } + } + for (int i = fb; i < FORMATS.length; i++) { + try { + return valueOf(dateString, FORMATS[i]); } catch (Throwable ex) { lastEx = ex; } @@ -260,7 +272,7 @@ public String toDateTimeString() { @Override public String toString() { - return toString(FULL_FORMAT); + return toString(ifNull(RxConfig.INSTANCE.getDateFormat(), DATE_TIME_FORMAT)); } public String toString(@NonNull String format) { diff --git a/rxlib/src/main/java/org/rx/bean/Tuple.java b/rxlib/src/main/java/org/rx/bean/Tuple.java index f812797a..a0d61392 100644 --- a/rxlib/src/main/java/org/rx/bean/Tuple.java +++ b/rxlib/src/main/java/org/rx/bean/Tuple.java @@ -3,8 +3,10 @@ import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; +import org.apache.commons.collections4.keyvalue.DefaultMapEntry; import java.io.Serializable; +import java.util.Map; @Data @NoArgsConstructor @@ -23,4 +25,8 @@ public static Tuple of(T1 t1, T2 t2) { public T1 left; public T2 right; + + public DefaultMapEntry toMapEntry() { + return new DefaultMapEntry<>(left, right); + } } diff --git a/rxlib/src/main/java/org/rx/core/Constants.java b/rxlib/src/main/java/org/rx/core/Constants.java index 430c7c29..d58d6c4c 100644 --- a/rxlib/src/main/java/org/rx/core/Constants.java +++ b/rxlib/src/main/java/org/rx/core/Constants.java @@ -43,6 +43,8 @@ enum MetricName { int ADVICE_SHARE_TIME_INDEX = 0; int ADVICE_SHARE_FORK_JOIN_FUNC_INDEX = 1; + String ENABLE_FLAG = "1"; + /** * do not edit */ diff --git a/rxlib/src/main/java/org/rx/core/Extends.java b/rxlib/src/main/java/org/rx/core/Extends.java index 57f9b233..cadb39c7 100644 --- a/rxlib/src/main/java/org/rx/core/Extends.java +++ b/rxlib/src/main/java/org/rx/core/Extends.java @@ -67,6 +67,7 @@ static boolean quietly(@NonNull Action fn, int retryCount, boolean throwOnLast) TraceHandler.INSTANCE.log("quietly retry={}/{}", i, retryCount, e); last = e; } + sleep(0); } if (last != null && throwOnLast) { throw InvalidException.sneaky(last); diff --git a/rxlib/src/main/java/org/rx/core/RxConfig.java b/rxlib/src/main/java/org/rx/core/RxConfig.java index 571741a6..18b228c7 100644 --- a/rxlib/src/main/java/org/rx/core/RxConfig.java +++ b/rxlib/src/main/java/org/rx/core/RxConfig.java @@ -70,6 +70,7 @@ public interface ConfigNames { String APP_ID = "app.id"; String MX_SAMPLING_PERIOD = "app.mxSamplingPeriod"; + String DATE_FORMAT = "app.dateFormat"; String LOG_STRATEGY = "app.logStrategy"; String JSON_SKIP_TYPES = "app.jsonSkipTypes"; String AES_KEY = "app.aesKey"; @@ -188,6 +189,7 @@ public static class DnsConfig { String aesKey; String mxpwd; long mxSamplingPeriod; + String dateFormat; final Set> jsonSkipTypes = ConcurrentHashMap.newKeySet(); LogStrategy logStrategy; final Set logTypeWhitelist = ConcurrentHashMap.newKeySet(); @@ -271,6 +273,7 @@ public void refreshFromSystemProperty() { aesKey = SystemPropertyUtil.get(ConfigNames.AES_KEY, aesKey); mxpwd = SystemPropertyUtil.get(ConfigNames.MXPWD, mxpwd); mxSamplingPeriod = SystemPropertyUtil.getLong(ConfigNames.MX_SAMPLING_PERIOD, mxSamplingPeriod); + dateFormat = SystemPropertyUtil.get(ConfigNames.DATE_FORMAT, dateFormat); String v = SystemPropertyUtil.get(ConfigNames.JSON_SKIP_TYPES); if (v != null) { jsonSkipTypes.clear(); diff --git a/rxlib/src/main/java/org/rx/core/Sys.java b/rxlib/src/main/java/org/rx/core/Sys.java index d5432a82..d8089431 100644 --- a/rxlib/src/main/java/org/rx/core/Sys.java +++ b/rxlib/src/main/java/org/rx/core/Sys.java @@ -467,7 +467,7 @@ public static String formatNanosElapsed(long nanoseconds, int i) { //endregion //region common - public static T deepClone(T obj) { + public static T deepClone(T obj) { return Serializer.DEFAULT.deserialize(Serializer.DEFAULT.serialize(obj)); } diff --git a/rxlib/src/main/java/org/rx/io/MemoryStream.java b/rxlib/src/main/java/org/rx/io/MemoryStream.java index 764888a8..69f6c0a3 100644 --- a/rxlib/src/main/java/org/rx/io/MemoryStream.java +++ b/rxlib/src/main/java/org/rx/io/MemoryStream.java @@ -177,7 +177,9 @@ public MemoryStream(@NonNull ByteBuf buf, boolean forWrite) { @Override protected void freeObjects() { - buffer.release(); + if (buffer != null) { + buffer.release(); + } } @Override diff --git a/rxlib/src/main/java/org/rx/net/http/HttpClient.java b/rxlib/src/main/java/org/rx/net/http/HttpClient.java index d2848b63..de9273b1 100644 --- a/rxlib/src/main/java/org/rx/net/http/HttpClient.java +++ b/rxlib/src/main/java/org/rx/net/http/HttpClient.java @@ -168,13 +168,16 @@ public String getResponseText() { } @JSONField(serialize = false) - public Headers getHeaders() { + public Charset getCharset() { + return response.body() != null ? Reflects.invokeMethod(response.body(), "charset") : StandardCharsets.UTF_8; + } + + public Headers responseHeaders() { return response.headers(); } - @JSONField(serialize = false) - public Charset getCharset() { - return Reflects.invokeMethod(response.body(), "charset"); + public InputStream responseStream() { + return response.body() != null ? response.body().byteStream() : null; } @SneakyThrows @@ -619,13 +622,13 @@ public RequestBody toBody() { ResponseContent resContent = new ResponseContent(getClient().newCall(createRequest(forwardUrl).method(servletRequest.getMethod(), reqContent.toBody()).build()).execute()); resContent.cachingStream = cachingStream; servletResponse.setStatus(resContent.response.code()); - for (Pair header : resContent.getHeaders()) { + for (Pair header : resContent.responseHeaders()) { servletResponse.setHeader(header.getFirst(), header.getSecond()); } ResponseBody responseBody = resContent.response.body(); boolean hasResBody = responseBody != null; - log.info("Forward response: {}\nheaders: {} hasBody: {}", resContent.getResponseUrl(), toJsonString(resContent.getHeaders()), hasResBody); + log.info("Forward response: {}\nheaders: {} hasBody: {}", resContent.getResponseUrl(), toJsonString(resContent.responseHeaders()), hasResBody); if (hasResBody) { MediaType responseContentType = responseBody.contentType(); if (responseContentType != null) { diff --git a/rxlib/src/main/java/org/rx/spring/BaseInterceptor.java b/rxlib/src/main/java/org/rx/spring/BaseInterceptor.java index 055f4f1e..0045aa2c 100644 --- a/rxlib/src/main/java/org/rx/spring/BaseInterceptor.java +++ b/rxlib/src/main/java/org/rx/spring/BaseInterceptor.java @@ -63,6 +63,7 @@ public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable { RxConfig conf = RxConfig.INSTANCE; pe.setLogStrategy(conf.getLogStrategy()); pe.setLogTypeWhitelist(conf.getLogTypeWhitelist()); + String paramSnapshot = jsonString(signature, pe.getParameters()); try { pe.proceed(() -> joinPoint.proceed(pe.getParameters())); } catch (Throwable e) { @@ -73,7 +74,7 @@ public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable { } } finally { TraceHandler.INSTANCE.saveMethodTrace(pe, signature.getName()); - onLog(signature, pe); + onLog(signature, pe, paramSnapshot); raiseEvent(onProceed, pe); } return pe.getReturnValue(); @@ -84,10 +85,10 @@ public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable { } } - protected void onLog(Signature signature, ProceedEventArgs eventArgs) { + protected void onLog(Signature signature, ProceedEventArgs eventArgs, String paramSnapshot) { log(eventArgs, msg -> { msg.appendLine("Call:\t%s", signature.getName()); - msg.appendLine("Parameters:\t%s", jsonString(signature, eventArgs.getParameters())) + msg.appendLine("Parameters:\t%s", paramSnapshot) .appendLine("ReturnValue:\t%s\tElapsed=%s", jsonString(signature, eventArgs.getReturnValue()), Sys.formatNanosElapsed(eventArgs.getElapsedNanos())); if (eventArgs.getError() != null) { msg.appendLine("Error:\t%s", eventArgs.getError().getMessage()); diff --git a/rxlib/src/main/java/org/rx/spring/Interceptors.java b/rxlib/src/main/java/org/rx/spring/Interceptors.java index 76e95c77..0207ff87 100644 --- a/rxlib/src/main/java/org/rx/spring/Interceptors.java +++ b/rxlib/src/main/java/org/rx/spring/Interceptors.java @@ -12,6 +12,7 @@ import org.rx.bean.ProceedEventArgs; import org.rx.bean.Tuple; import org.rx.core.Arrays; +import org.rx.core.Constants; import org.rx.core.RxConfig; import org.rx.core.Strings; import org.rx.exception.ApplicationException; @@ -90,7 +91,7 @@ public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable { return joinPoint.proceed(); } - if (Strings.equals(httpEnv.left.getParameter("rmx"), RxConfig.INSTANCE.getMxpwd())) { + if (Strings.equals(httpEnv.left.getParameter("rmx"), Constants.ENABLE_FLAG)) { MxController controller = SpringContext.getBean(MxController.class); if (controller != null) { return controller.health(httpEnv.left); @@ -171,13 +172,13 @@ public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable { } @Override - protected void onLog(Signature signature, ProceedEventArgs eventArgs) { + protected void onLog(Signature signature, ProceedEventArgs eventArgs, String paramSnapshot) { Executable r = signature instanceof ConstructorSignature ? ((ConstructorSignature) signature).getConstructor() : ((MethodSignature) signature).getMethod(); EnableTrace a = r.getAnnotation(EnableTrace.class); if (a == null || a.doLog()) { - super.onLog(signature, eventArgs); + super.onLog(signature, eventArgs, paramSnapshot); } } diff --git a/rxlib/src/main/resources/rx.yml b/rxlib/src/main/resources/rx.yml index 6ca4a491..f8e0e4fb 100644 --- a/rxlib/src/main/resources/rx.yml +++ b/rxlib/src/main/resources/rx.yml @@ -56,6 +56,7 @@ app: aesKey: ℞FREEDOM mxpwd: rxlib mxSamplingPeriod: 60000 + dateFormat: yyyy-MM-dd HH:mm:ss jsonSkipTypes: - javax.servlet.ServletRequest - javax.servlet.ServletResponse diff --git a/rxlib/src/test/java/org/rx/core/TestCore.java b/rxlib/src/test/java/org/rx/core/TestCore.java index 0d5ac19d..acbba792 100644 --- a/rxlib/src/test/java/org/rx/core/TestCore.java +++ b/rxlib/src/test/java/org/rx/core/TestCore.java @@ -857,6 +857,10 @@ public void rasTest() { @Test public void json() { + System.out.println(DateTime.valueOf("2020-02-04 00:00:00")); + System.out.println(DateTime.valueOf("2020-02-05 00:00:00.000")); + System.out.println(DateTime.valueOf("20200206000000000")); + // RxConfig.INSTANCE.getJsonSkipTypes().add(ErrorBean.class); Object[] args = new Object[]{str_name_wyf, proxy(HttpServletResponse.class, (m, i) -> { throw new InvalidException("wont reach");