You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by al...@apache.org on 2022/07/10 12:26:33 UTC
[dubbo] branch 3.1 updated: [Feature] Adds feature of displaying FAQ link in logger output. (#10292)
This is an automated email from the ASF dual-hosted git repository.
albumenj pushed a commit to branch 3.1
in repository https://gitbox.apache.org/repos/asf/dubbo.git
The following commit(s) were added to refs/heads/3.1 by this push:
new 6095d71062 [Feature] Adds feature of displaying FAQ link in logger output. (#10292)
6095d71062 is described below
commit 6095d71062bc6125167186ed0faa41d484251904
Author: Andy Cheung <wi...@users.noreply.github.com>
AuthorDate: Sun Jul 10 20:25:45 2022 +0800
[Feature] Adds feature of displaying FAQ link in logger output. (#10292)
* Add error type definition.
* Add interface of error type aware logger.
* Add fail-safe error type aware logger, and add getErrorTypeAwareLogger in logger factory.
In order to obtain 'disabled' field in FailsafeLogger, a method called 'getDisabled()' in FailsafeLogger is also added.
* Add corresponding test of FailsafeErrorTypeAwareLogger and LoggerFactory.
* Add error code definition.
* Add output of error code.
* Per Project's request, remove ErrorType enumeration, and add parameters into logger methods.
* Add error code checking logic.
* Let matcher checks trimmed string instead of checking the original argument.
* Remove debug, info, trace logging method per request.
---
.../dubbo/common/logger/ErrorTypeAwareLogger.java | 66 +++++++++++
.../apache/dubbo/common/logger/LoggerFactory.java | 22 ++++
.../support/FailsafeErrorTypeAwareLogger.java | 121 +++++++++++++++++++++
.../common/logger/support/FailsafeLogger.java | 4 +
.../dubbo/common/logger/LoggerFactoryTest.java | 8 ++
.../support/FailsafeErrorTypeAwareLoggerTest.java | 99 +++++++++++++++++
6 files changed, 320 insertions(+)
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/logger/ErrorTypeAwareLogger.java b/dubbo-common/src/main/java/org/apache/dubbo/common/logger/ErrorTypeAwareLogger.java
new file mode 100644
index 0000000000..fe9ebcc774
--- /dev/null
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/logger/ErrorTypeAwareLogger.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.common.logger;
+
+/**
+ * Logger interface with the ability of displaying solution of different types of error.
+ */
+public interface ErrorTypeAwareLogger extends Logger {
+
+ /**
+ * Logs a message with warn log level.
+ *
+ * @param code error code
+ * @param cause error cause
+ * @param extendedInformation extended information
+ * @param msg log this message
+ */
+ void warn(String code, String cause, String extendedInformation, String msg);
+
+ /**
+ * Logs a message with warn log level.
+ *
+ * @param code error code
+ * @param cause error cause
+ * @param extendedInformation extended information
+ * @param msg log this message
+ * @param e log this cause
+ */
+ void warn(String code, String cause, String extendedInformation, String msg, Throwable e);
+
+ /**
+ * Logs a message with error log level.
+ *
+ * @param code error code
+ * @param cause error cause
+ * @param extendedInformation extended information
+ * @param msg log this message
+ */
+ void error(String code, String cause, String extendedInformation, String msg);
+
+ /**
+ * Logs a message with error log level.
+ *
+ * @param code error code
+ * @param cause error cause
+ * @param extendedInformation extended information
+ * @param msg log this message
+ * @param e log this cause
+ */
+ void error(String code, String cause, String extendedInformation, String msg, Throwable e);
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/logger/LoggerFactory.java b/dubbo-common/src/main/java/org/apache/dubbo/common/logger/LoggerFactory.java
index 9f787c51b2..91c0e60020 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/logger/LoggerFactory.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/logger/LoggerFactory.java
@@ -21,6 +21,7 @@ import org.apache.dubbo.common.logger.jdk.JdkLoggerAdapter;
import org.apache.dubbo.common.logger.log4j.Log4jLoggerAdapter;
import org.apache.dubbo.common.logger.log4j2.Log4j2LoggerAdapter;
import org.apache.dubbo.common.logger.slf4j.Slf4jLoggerAdapter;
+import org.apache.dubbo.common.logger.support.FailsafeErrorTypeAwareLogger;
import org.apache.dubbo.common.logger.support.FailsafeLogger;
import org.apache.dubbo.rpc.model.FrameworkModel;
@@ -39,6 +40,7 @@ import java.util.concurrent.ConcurrentMap;
public class LoggerFactory {
private static final ConcurrentMap<String, FailsafeLogger> LOGGERS = new ConcurrentHashMap<>();
+ private static final ConcurrentMap<String, FailsafeErrorTypeAwareLogger> ERROR_TYPE_AWARE_LOGGERS = new ConcurrentHashMap<>();
private static volatile LoggerAdapter LOGGER_ADAPTER;
// search common-used logging frameworks
@@ -127,6 +129,26 @@ public class LoggerFactory {
return LOGGERS.computeIfAbsent(key, k -> new FailsafeLogger(LOGGER_ADAPTER.getLogger(k)));
}
+ /**
+ * Get error type aware logger by Class object.
+ *
+ * @param key the returned logger will be named after clazz
+ * @return error type aware logger
+ */
+ public static ErrorTypeAwareLogger getErrorTypeAwareLogger(Class<?> key) {
+ return ERROR_TYPE_AWARE_LOGGERS.computeIfAbsent(key.getName(), name -> new FailsafeErrorTypeAwareLogger(LOGGER_ADAPTER.getLogger(name)));
+ }
+
+ /**
+ * Get error type aware logger by a String key.
+ *
+ * @param key the returned logger will be named after key
+ * @return error type aware logger
+ */
+ public static ErrorTypeAwareLogger getErrorTypeAwareLogger(String key) {
+ return ERROR_TYPE_AWARE_LOGGERS.computeIfAbsent(key, k -> new FailsafeErrorTypeAwareLogger(LOGGER_ADAPTER.getLogger(k)));
+ }
+
/**
* Get logging level
*
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/logger/support/FailsafeErrorTypeAwareLogger.java b/dubbo-common/src/main/java/org/apache/dubbo/common/logger/support/FailsafeErrorTypeAwareLogger.java
new file mode 100644
index 0000000000..afecb19986
--- /dev/null
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/logger/support/FailsafeErrorTypeAwareLogger.java
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.common.logger.support;
+
+import org.apache.dubbo.common.Version;
+import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.utils.NetUtils;
+
+import java.util.regex.Pattern;
+
+/**
+ * A fail-safe (ignoring exception thrown by logger) wrapper of error type aware logger.
+ */
+public class FailsafeErrorTypeAwareLogger extends FailsafeLogger implements ErrorTypeAwareLogger {
+
+ /**
+ * Mock address for formatting.
+ */
+ private static final String INSTRUCTIONS_URL = "https://dubbo.apache.org/faq/%d/%d";
+
+ private static final Pattern ERROR_CODE_PATTERN = Pattern.compile("\\d+-\\d+");
+
+ public FailsafeErrorTypeAwareLogger(Logger logger) {
+ super(logger);
+ }
+
+ private String appendContextMessageWithInstructions(String code, String cause, String extendedInformation, String msg) {
+ return " [DUBBO] " + msg + ", dubbo version: " + Version.getVersion() +
+ ", current host: " + NetUtils.getLocalHost() + ", error code: " + code +
+ ". This may be caused by " + cause + ", " +
+ "go to " + getErrorUrl(code) + " to find instructions. " + extendedInformation;
+ }
+
+ private String getErrorUrl(String code) {
+
+ String trimmedString = code.trim();
+
+ if (!ERROR_CODE_PATTERN.matcher(trimmedString).matches()) {
+ error("Invalid error code: " + code + ", the format of error code is: X-X (where X is a number).");
+ return "";
+ }
+
+ String[] segments = trimmedString.split("[-]");
+
+ int[] errorCodeSegments = new int[2];
+
+ try {
+ errorCodeSegments[0] = Integer.parseInt(segments[0]);
+ errorCodeSegments[1] = Integer.parseInt(segments[1]);
+ } catch (NumberFormatException numberFormatException) {
+ error("Invalid error code: " + code + ", the format of error code is: X-X (where X is a number).",
+ numberFormatException);
+ }
+
+ return String.format(INSTRUCTIONS_URL, errorCodeSegments[0], errorCodeSegments[1]);
+ }
+
+ @Override
+ public void warn(String code, String cause, String extendedInformation, String msg) {
+ if (getDisabled()) {
+ return;
+ }
+
+ try {
+ getLogger().warn(appendContextMessageWithInstructions(code, cause, extendedInformation, msg));
+ } catch (Throwable t) {
+ }
+ }
+
+ @Override
+ public void warn(String code, String cause, String extendedInformation, String msg, Throwable e) {
+ if (getDisabled()) {
+ return;
+ }
+
+ try {
+ getLogger().warn(appendContextMessageWithInstructions(code, cause, extendedInformation, msg), e);
+ } catch (Throwable t) {
+ }
+ }
+
+ @Override
+ public void error(String code, String cause, String extendedInformation, String msg) {
+ if (getDisabled()) {
+ return;
+ }
+
+ try {
+ getLogger().error(appendContextMessageWithInstructions(code, cause, extendedInformation, msg));
+ } catch (Throwable t) {
+ }
+ }
+
+ @Override
+ public void error(String code, String cause, String extendedInformation, String msg, Throwable e) {
+ if (getDisabled()) {
+ return;
+ }
+
+ try {
+ getLogger().error(appendContextMessageWithInstructions(code, cause, extendedInformation, msg), e);
+ } catch (Throwable t) {
+ }
+ }
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/logger/support/FailsafeLogger.java b/dubbo-common/src/main/java/org/apache/dubbo/common/logger/support/FailsafeLogger.java
index ff6804bf70..66e369f83b 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/logger/support/FailsafeLogger.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/logger/support/FailsafeLogger.java
@@ -34,6 +34,10 @@ public class FailsafeLogger implements Logger {
FailsafeLogger.disabled = disabled;
}
+ static boolean getDisabled() {
+ return disabled;
+ }
+
public Logger getLogger() {
return logger;
}
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/logger/LoggerFactoryTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/logger/LoggerFactoryTest.java
index c83765f444..70a7ce8693 100644
--- a/dubbo-common/src/test/java/org/apache/dubbo/common/logger/LoggerFactoryTest.java
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/logger/LoggerFactoryTest.java
@@ -68,4 +68,12 @@ public class LoggerFactoryTest {
assertThat(logger1, is(logger2));
}
+
+ @Test
+ public void shouldReturnSameErrorTypeAwareLogger() {
+ ErrorTypeAwareLogger logger1 = LoggerFactory.getErrorTypeAwareLogger(this.getClass().getName());
+ ErrorTypeAwareLogger logger2 = LoggerFactory.getErrorTypeAwareLogger(this.getClass().getName());
+
+ assertThat(logger1, is(logger2));
+ }
}
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/logger/support/FailsafeErrorTypeAwareLoggerTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/logger/support/FailsafeErrorTypeAwareLoggerTest.java
new file mode 100644
index 0000000000..6eb3605556
--- /dev/null
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/logger/support/FailsafeErrorTypeAwareLoggerTest.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.common.logger.support;
+
+import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.rpc.model.FrameworkModel;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+/**
+ * Tests for FailsafeErrorTypeAwareLogger to test whether it 'ignores' exceptions thrown by logger or not.
+ */
+public class FailsafeErrorTypeAwareLoggerTest {
+ @Test
+ public void testFailsafeErrorTypeAwareForLoggingMethod() {
+ Logger failLogger = mock(Logger.class);
+ FailsafeErrorTypeAwareLogger failsafeLogger = new FailsafeErrorTypeAwareLogger(failLogger);
+
+ doThrow(new RuntimeException()).when(failLogger).error(anyString());
+ doThrow(new RuntimeException()).when(failLogger).warn(anyString());
+ doThrow(new RuntimeException()).when(failLogger).info(anyString());
+ doThrow(new RuntimeException()).when(failLogger).debug(anyString());
+ doThrow(new RuntimeException()).when(failLogger).trace(anyString());
+
+ failsafeLogger.error("1-1", "Registry center", "May be it's offline.", "error");
+ failsafeLogger.warn("1-1", "Registry center", "May be it's offline.", "warn");
+
+ doThrow(new RuntimeException()).when(failLogger).error(any(Throwable.class));
+ doThrow(new RuntimeException()).when(failLogger).warn(any(Throwable.class));
+ doThrow(new RuntimeException()).when(failLogger).info(any(Throwable.class));
+ doThrow(new RuntimeException()).when(failLogger).debug(any(Throwable.class));
+ doThrow(new RuntimeException()).when(failLogger).trace(any(Throwable.class));
+
+ failsafeLogger.error("1-1", "Registry center", "May be it's offline.", "error", new Exception("error"));
+ failsafeLogger.warn("1-1", "Registry center", "May be it's offline.", "warn", new Exception("warn"));
+ }
+
+ @Test
+ public void testSuccessLogger() {
+ Logger successLogger = mock(Logger.class);
+ FailsafeErrorTypeAwareLogger failsafeLogger = new FailsafeErrorTypeAwareLogger(successLogger);
+
+ failsafeLogger.error("1-1", "Registry center", "May be it's offline.", "error");
+ failsafeLogger.warn("1-1", "Registry center", "May be it's offline.", "warn");
+
+ verify(successLogger).error(anyString());
+ verify(successLogger).warn(anyString());
+
+ failsafeLogger.error("1-1", "Registry center", "May be it's offline.", "error", new Exception("error"));
+ failsafeLogger.warn("1-1", "Registry center", "May be it's offline.", "warn", new Exception("warn"));
+ }
+
+ @Test
+ public void testGetLogger() {
+ Assertions.assertThrows(RuntimeException.class, () -> {
+ Logger failLogger = mock(Logger.class);
+ FailsafeErrorTypeAwareLogger failsafeLogger = new FailsafeErrorTypeAwareLogger(failLogger);
+
+ doThrow(new RuntimeException()).when(failLogger).error(anyString());
+ failsafeLogger.getLogger().error("should get error");
+ });
+ }
+
+ @Test
+ public void testInstructionShownOrNot() {
+ LoggerFactory.setLoggerAdapter(FrameworkModel.defaultModel(), "jdk");
+
+ ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(FailsafeErrorTypeAwareLoggerTest.class);
+
+ logger.error("1-1", "Registry center", "May be it's offline.",
+ "error message", new Exception("error"));
+
+ logger.error("-1", "Registry center", "May be it's offline.",
+ "error message", new Exception("error"));
+ }
+}