forked from corda/corda
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
EG-433 - Error Reporting Framework (Merge)
Error Reporting Framework - Phase 1
- Loading branch information
Showing
72 changed files
with
1,353 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
31 changes: 31 additions & 0 deletions
31
...ging/src/main/kotlin/net/corda/common/logging/errorReporting/CordaErrorContextProvider.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package net.corda.common.logging.errorReporting | ||
|
||
import net.corda.common.logging.CordaVersion | ||
import java.util.* | ||
|
||
/** | ||
* Provides information specific to Corda to the error reporting library. | ||
* | ||
* The primary use of this is to provide the URL to the docs site where the error information is hosted. | ||
*/ | ||
class CordaErrorContextProvider : ErrorContextProvider { | ||
|
||
companion object { | ||
private const val BASE_URL = "https://docs.corda.net/docs" | ||
private const val OS_PAGES = "corda-os" | ||
private const val ENTERPRISE_PAGES = "corda-enterprise" | ||
private const val ERROR_CODE_PAGE = "error-codes.html" | ||
} | ||
|
||
override fun getURL(locale: Locale): String { | ||
val versionNumber = CordaVersion.releaseVersion | ||
|
||
// This slightly strange block here allows the code to be merged across to Enterprise with no changes. | ||
val productVersion = if (CordaVersion.platformEditionCode == "OS") { | ||
OS_PAGES | ||
} else { | ||
ENTERPRISE_PAGES | ||
} | ||
return "$BASE_URL/$productVersion/$versionNumber/$ERROR_CODE_PAGE" | ||
} | ||
} |
28 changes: 28 additions & 0 deletions
28
common/logging/src/main/kotlin/net/corda/common/logging/errorReporting/ErrorCode.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package net.corda.common.logging.errorReporting | ||
|
||
/** | ||
* A type representing an error condition. | ||
* | ||
* Error codes should be used in situations where an error is expected and information can be provided back to the user about what they've | ||
* done wrong. Each error code should have a resource bundle defined for it, which contains set of properties that define the error string | ||
* in different languages. See the resource bundles in common/logging/src/main/resources/errorReporting for more details. | ||
*/ | ||
interface ErrorCode<CODES> where CODES: ErrorCodes, CODES: Enum<CODES> { | ||
|
||
/** | ||
* The error code. | ||
* | ||
* Error codes are used to indicate what sort of error occurred. A unique code should be returned for each possible | ||
* error condition that could be reported within the defined namespace. The code should very briefly describe what has gone wrong, e.g. | ||
* "failed-to-store" or "connection-unavailable". | ||
*/ | ||
val code: CODES | ||
|
||
/** | ||
* Parameters to pass to the string template when reporting this error. The corresponding template that defines the error string in the | ||
* resource bundle must be expecting this list of parameters. Parameters should be in the order required by the message template - for | ||
* example, if the message template is "This error has argument {0} and argument {1}", the first element of this list will be placed | ||
* into {0}. | ||
*/ | ||
val parameters: List<Any> | ||
} |
16 changes: 16 additions & 0 deletions
16
common/logging/src/main/kotlin/net/corda/common/logging/errorReporting/ErrorCodes.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package net.corda.common.logging.errorReporting | ||
|
||
/** | ||
* A collection of error codes. | ||
* | ||
* Types implementing this are required to be enum classes to be used in an error. | ||
*/ | ||
interface ErrorCodes { | ||
/** | ||
* The namespace of this collection of errors. | ||
* | ||
* These are used to partition errors into categories, e.g. "database" or "cordapp". Namespaces should be unique, which can be enforced | ||
* by using enum elements. | ||
*/ | ||
val namespace: String | ||
} |
24 changes: 24 additions & 0 deletions
24
...n/logging/src/main/kotlin/net/corda/common/logging/errorReporting/ErrorContextProvider.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package net.corda.common.logging.errorReporting | ||
|
||
import java.util.* | ||
|
||
/** | ||
* Provide context around reported errors by supplying product specific information. | ||
*/ | ||
interface ErrorContextProvider { | ||
|
||
/** | ||
* Get the URL to the docs site where the error codes are hosted. | ||
* | ||
* Note that the correct docs site link is likely to depend on the following: | ||
* - The locale of the error message | ||
* - The product the error was reported from | ||
* - The version of the product the error was reported from | ||
* | ||
* The returned URL must be the link the to the error code table in the documentation. | ||
* | ||
* @param locale The locale of the link | ||
* @return The URL of the docs site, to be printed in the logs | ||
*/ | ||
fun getURL(locale: Locale) : String | ||
} |
16 changes: 16 additions & 0 deletions
16
common/logging/src/main/kotlin/net/corda/common/logging/errorReporting/ErrorReporter.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package net.corda.common.logging.errorReporting | ||
|
||
import org.slf4j.Logger | ||
|
||
/** | ||
* Reports error conditions to the logs, using localised error messages. | ||
*/ | ||
internal interface ErrorReporter { | ||
/** | ||
* Report a particular error condition | ||
* | ||
* @param error The error to report | ||
* @param logger The logger to use when reporting this error | ||
*/ | ||
fun report(error: ErrorCode<*>, logger: Logger) | ||
} |
36 changes: 36 additions & 0 deletions
36
common/logging/src/main/kotlin/net/corda/common/logging/errorReporting/ErrorReporterImpl.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package net.corda.common.logging.errorReporting | ||
|
||
import org.slf4j.Logger | ||
import java.text.MessageFormat | ||
import java.util.* | ||
|
||
internal const val ERROR_INFO_RESOURCE = "ErrorInfo" | ||
internal const val ERROR_CODE_MESSAGE = "errorCodeMessage" | ||
internal const val ERROR_CODE_URL = "errorCodeUrl" | ||
|
||
internal class ErrorReporterImpl(private val resourceLocation: String, | ||
private val locale: Locale, | ||
private val errorContextProvider: ErrorContextProvider) : ErrorReporter { | ||
|
||
private fun fetchAndFormat(resource: String, property: String, params: Array<out Any>) : String { | ||
val bundle = ResourceBundle.getBundle(resource, locale) | ||
val template = bundle.getString(property) | ||
val formatter = MessageFormat(template, locale) | ||
return formatter.format(params) | ||
} | ||
|
||
// Returns the string appended to all reported errors, indicating the error code and the URL to go to. | ||
// e.g. [Code: my-error-code, For further information, please go to https://docs.corda.net/corda-os/4.5/error-codes.html] | ||
private fun getErrorInfo(error: ErrorCode<*>) : String { | ||
val resource = "$resourceLocation/$ERROR_INFO_RESOURCE" | ||
val codeMessage = fetchAndFormat(resource, ERROR_CODE_MESSAGE, arrayOf(error.formatCode())) | ||
val urlMessage = fetchAndFormat(resource, ERROR_CODE_URL, arrayOf(errorContextProvider.getURL(locale))) | ||
return "[$codeMessage, $urlMessage]" | ||
} | ||
|
||
override fun report(error: ErrorCode<*>, logger: Logger) { | ||
val errorResource = ErrorResource.fromErrorCode(error, resourceLocation, locale) | ||
val message = "${errorResource.getErrorMessage(error.parameters.toTypedArray())} ${getErrorInfo(error)}" | ||
logger.error(message) | ||
} | ||
} |
70 changes: 70 additions & 0 deletions
70
common/logging/src/main/kotlin/net/corda/common/logging/errorReporting/ErrorReporting.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package net.corda.common.logging.errorReporting | ||
|
||
import java.util.* | ||
|
||
/** | ||
* Entry point into the Error Reporting framework. | ||
* | ||
* This creates the error reporter used to report errors. The `initialiseReporting` method should be called to build a reporter before any | ||
* errors are reported. | ||
*/ | ||
class ErrorReporting private constructor(private val localeString: String, | ||
private val resourceLocation: String, | ||
private val contextProvider: ErrorContextProvider?) { | ||
|
||
constructor() : this(DEFAULT_LOCALE, DEFAULT_LOCATION, null) | ||
|
||
private companion object { | ||
private const val DEFAULT_LOCALE = "en-US" | ||
private const val DEFAULT_LOCATION = "." | ||
|
||
private var errorReporter: ErrorReporter? = null | ||
} | ||
|
||
/** | ||
* Set the locale to use when reporting errors | ||
* | ||
* @param locale The locale tag to use when reporting errors, e.g. en-US | ||
*/ | ||
@Suppress("UNUSED_PARAMETER") | ||
fun withLocale(locale: String) : ErrorReporting { | ||
// Currently, if anything other than the default is used this is entirely untested. As a result, an exception is thrown here to | ||
// indicate that this functionality is not ready at this point in time. | ||
throw LocaleSettingUnsupportedException() | ||
} | ||
|
||
/** | ||
* Set the location of the resource bundles containing the error codes. | ||
* | ||
* @param location The location within the JAR of the resource bundle | ||
*/ | ||
fun usingResourcesAt(location: String) : ErrorReporting { | ||
return ErrorReporting(localeString, location, contextProvider) | ||
} | ||
|
||
/** | ||
* Set the context provider to supply project-specific information about the errors. | ||
* | ||
* @param contextProvider The context provider to use with error reporting | ||
*/ | ||
fun withContextProvider(contextProvider: ErrorContextProvider) : ErrorReporting { | ||
return ErrorReporting(localeString, resourceLocation, contextProvider) | ||
} | ||
|
||
/** | ||
* Set up the reporting of errors. | ||
*/ | ||
fun initialiseReporting() { | ||
if (contextProvider == null) { | ||
throw NoContextProviderSuppliedException() | ||
} | ||
if (errorReporter != null) { | ||
throw DoubleInitializationException() | ||
} | ||
errorReporter = ErrorReporterImpl(resourceLocation, Locale.forLanguageTag(localeString), contextProvider) | ||
} | ||
|
||
internal fun getReporter() : ErrorReporter { | ||
return errorReporter ?: throw ReportingUninitializedException() | ||
} | ||
} |
27 changes: 27 additions & 0 deletions
27
...gging/src/main/kotlin/net/corda/common/logging/errorReporting/ErrorReportingExceptions.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package net.corda.common.logging.errorReporting | ||
|
||
abstract class ErrorReportingException(message: String, cause: Throwable? = null) : Exception(message, cause) | ||
|
||
/** | ||
* Occurs when reporting is requested before the error reporting code has been initialized | ||
*/ | ||
class ReportingUninitializedException : ErrorReportingException("Error reporting is uninitialized") | ||
|
||
/** | ||
* Occurs when no error context provider is supplied while initializing error reporting | ||
*/ | ||
class NoContextProviderSuppliedException | ||
: ErrorReportingException("No error context provider was supplied when initializing error reporting") | ||
|
||
/** | ||
* Occurs if the error reporting framework has been initialized twice | ||
*/ | ||
class DoubleInitializationException : ErrorReportingException("Error reporting has previously been initialized") | ||
|
||
/** | ||
* Occurs if a locale is set while initializing the error reporting framework. | ||
* | ||
* This is done as locale support has not yet been properly designed, and so using anything other than the default is untested. | ||
*/ | ||
class LocaleSettingUnsupportedException : | ||
ErrorReportingException("Setting a locale other than the default is not supported in the first release") |
18 changes: 18 additions & 0 deletions
18
...on/logging/src/main/kotlin/net/corda/common/logging/errorReporting/ErrorReportingUtils.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package net.corda.common.logging.errorReporting | ||
|
||
import org.slf4j.Logger | ||
|
||
/** | ||
* Report errors that have occurred. | ||
* | ||
* Doing this allows the error reporting framework to find the corresponding resources for the error and pick the correct locale. | ||
* | ||
* @param error The error that has occurred. | ||
*/ | ||
fun Logger.report(error: ErrorCode<*>) = ErrorReporting().getReporter().report(error, this) | ||
|
||
internal fun ErrorCode<*>.formatCode() : String { | ||
val namespaceString = this.code.namespace.toLowerCase().replace("_", "-") | ||
val codeString = this.code.toString().toLowerCase().replace("_", "-") | ||
return "$namespaceString-$codeString" | ||
} |
60 changes: 60 additions & 0 deletions
60
common/logging/src/main/kotlin/net/corda/common/logging/errorReporting/ErrorResource.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
package net.corda.common.logging.errorReporting | ||
|
||
import net.corda.common.logging.errorReporting.ResourceBundleProperties.ACTIONS_TO_FIX | ||
import net.corda.common.logging.errorReporting.ResourceBundleProperties.ALIASES | ||
import net.corda.common.logging.errorReporting.ResourceBundleProperties.MESSAGE_TEMPLATE | ||
import net.corda.common.logging.errorReporting.ResourceBundleProperties.SHORT_DESCRIPTION | ||
import java.text.MessageFormat | ||
import java.util.* | ||
|
||
/** | ||
* A representation of a single error resource file. | ||
* | ||
* This handles selecting the right properties from the resource bundle and formatting the error message. | ||
*/ | ||
class ErrorResource private constructor(private val bundle: ResourceBundle, | ||
private val locale: Locale) { | ||
|
||
companion object { | ||
/** | ||
* Construct an error resource from a provided code. | ||
* | ||
* @param errorCode The code to get the resource bundle for | ||
* @param resourceLocation The location in the JAR of the error code resource bundles | ||
* @param locale The locale to use for this resource | ||
*/ | ||
fun fromErrorCode(errorCode: ErrorCode<*>, resourceLocation: String, locale: Locale) : ErrorResource { | ||
val resource = "$resourceLocation/${errorCode.formatCode()}" | ||
val bundle = ResourceBundle.getBundle(resource, locale) | ||
return ErrorResource(bundle, locale) | ||
} | ||
|
||
/** | ||
* Construct an error resource using resources loaded in a given classloader | ||
* | ||
* @param resource The resource bundle to load | ||
* @param classLoader The classloader used to load the resource bundles | ||
* @param locale The locale to use for this resource | ||
*/ | ||
fun fromLoader(resource: String, classLoader: ClassLoader, locale: Locale) : ErrorResource { | ||
val bundle = ResourceBundle.getBundle(resource, locale, classLoader) | ||
return ErrorResource(bundle, locale) | ||
} | ||
} | ||
|
||
private fun getProperty(propertyName: String) : String = bundle.getString(propertyName) | ||
|
||
private fun formatTemplate(template: String, args: Array<Any>) : String { | ||
val formatter = MessageFormat(template, locale) | ||
return formatter.format(args) | ||
} | ||
|
||
fun getErrorMessage(args: Array<Any>): String { | ||
val template = getProperty(MESSAGE_TEMPLATE) | ||
return formatTemplate(template, args) | ||
} | ||
|
||
val shortDescription: String = getProperty(SHORT_DESCRIPTION) | ||
val actionsToFix: String = getProperty(ACTIONS_TO_FIX) | ||
val aliases: String = getProperty(ALIASES) | ||
} |
33 changes: 33 additions & 0 deletions
33
common/logging/src/main/kotlin/net/corda/common/logging/errorReporting/Errors.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package net.corda.common.logging.errorReporting | ||
|
||
/** | ||
* Namespaces for errors within the node. | ||
*/ | ||
enum class NodeNamespaces { | ||
DATABASE, | ||
CORDAPP | ||
} | ||
|
||
/** | ||
* Errors related to database connectivity | ||
*/ | ||
enum class NodeDatabaseErrors : ErrorCodes { | ||
COULD_NOT_CONNECT, | ||
MISSING_DRIVER, | ||
FAILED_STARTUP, | ||
PASSWORD_REQUIRED_FOR_H2; | ||
|
||
override val namespace = NodeNamespaces.DATABASE.toString() | ||
} | ||
|
||
/** | ||
* Errors related to loading of Cordapps | ||
*/ | ||
enum class CordappErrors : ErrorCodes { | ||
DUPLICATE_CORDAPPS_INSTALLED, | ||
MULTIPLE_CORDAPPS_FOR_FLOW, | ||
MISSING_VERSION_ATTRIBUTE, | ||
INVALID_VERSION_IDENTIFIER; | ||
|
||
override val namespace = NodeNamespaces.CORDAPP.toString() | ||
} |
Oops, something went wrong.