mirror of
https://github.com/corda/corda.git
synced 2024-12-18 20:47:57 +00:00
CORDA-2586 explorer exception handling (#4957)
* Initial version of new(old) dialog that won't print a stacktrace for rpc exceptions. * Decoupled CordaVersionProvider. Moved common files to common-logging to lower dependencies on the node explorer. * Removed unused import and duplicate documentation comment. * Moved error code rewrite policy in the new common/logging module according to PR review. * Removed extra line. * Updated log4j configurations with new package name where logging policies will be contained. * Included common-logging module with cliutils.
This commit is contained in:
parent
746fcc32e5
commit
e4615f7f47
26
common/logging/build.gradle
Normal file
26
common/logging/build.gradle
Normal file
@ -0,0 +1,26 @@
|
||||
apply plugin: 'kotlin'
|
||||
|
||||
apply plugin: 'net.corda.plugins.publish-utils'
|
||||
apply plugin: 'com.jfrog.artifactory'
|
||||
|
||||
dependencies {
|
||||
compile group: "org.jetbrains.kotlin", name: "kotlin-stdlib-jdk8", version: kotlin_version
|
||||
compile group: "org.jetbrains.kotlin", name: "kotlin-reflect", version: kotlin_version
|
||||
|
||||
compile group: "com.typesafe", name: "config", version: typesafe_config_version
|
||||
compile "org.apache.logging.log4j:log4j-slf4j-impl:$log4j_version"
|
||||
|
||||
|
||||
compile "com.jcabi:jcabi-manifests:$jcabi_manifests_version"
|
||||
|
||||
|
||||
testCompile project(":test-utils")
|
||||
}
|
||||
|
||||
jar {
|
||||
baseName 'corda-common-logging'
|
||||
}
|
||||
|
||||
publish {
|
||||
name jar.baseName
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package net.corda.common.logging
|
||||
|
||||
import com.jcabi.manifests.Manifests
|
||||
|
||||
class CordaVersion {
|
||||
companion object {
|
||||
private const val UNKNOWN = "Unknown"
|
||||
const val current_major_release = "4.0-SNAPSHOT"
|
||||
const val platformEditionCode = "OS"
|
||||
|
||||
private fun manifestValue(name: String): String? = if (Manifests.exists(name)) Manifests.read(name) else null
|
||||
|
||||
val releaseVersion: String by lazy { manifestValue("Corda-Release-Version") ?: UNKNOWN }
|
||||
val revision: String by lazy { manifestValue("Corda-Revision") ?: UNKNOWN }
|
||||
val vendor: String by lazy { manifestValue("Corda-Vendor") ?: UNKNOWN }
|
||||
val platformVersion: Int by lazy { manifestValue("Corda-Platform-Version")?.toInt() ?: 1 }
|
||||
|
||||
internal val semanticVersion: String by lazy { if(releaseVersion == UNKNOWN) current_major_release else releaseVersion }
|
||||
}
|
||||
|
||||
fun getVersion(): Array<String> {
|
||||
return if (Manifests.exists("Corda-Release-Version") && Manifests.exists("Corda-Revision")) {
|
||||
arrayOf("Version: $releaseVersion", "Revision: $revision", "Platform Version: $platformVersion", "Vendor: $vendor")
|
||||
} else {
|
||||
arrayOf("No version data is available in the MANIFEST file.")
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package net.corda.cliutils
|
||||
package net.corda.common.logging
|
||||
|
||||
import org.apache.logging.log4j.core.Core
|
||||
import org.apache.logging.log4j.core.LogEvent
|
@ -1,11 +1,11 @@
|
||||
package net.corda.cliutils
|
||||
package net.corda.common.logging
|
||||
|
||||
import org.apache.logging.log4j.Level
|
||||
import org.apache.logging.log4j.message.Message
|
||||
import org.apache.logging.log4j.message.SimpleMessage
|
||||
import java.util.*
|
||||
|
||||
internal fun Message.withErrorCodeFor(error: Throwable?, level: Level): Message {
|
||||
fun Message.withErrorCodeFor(error: Throwable?, level: Level): Message {
|
||||
|
||||
return when {
|
||||
error != null && level.isInRange(Level.FATAL, Level.WARN) -> CompositeMessage("$formattedMessage [errorCode=${error.errorCode()}, moreInformationAt=${error.errorCodeLocationUrl()}]", format, parameters, throwable)
|
||||
@ -13,9 +13,9 @@ internal fun Message.withErrorCodeFor(error: Throwable?, level: Level): Message
|
||||
}
|
||||
}
|
||||
|
||||
private fun Throwable.errorCodeLocationUrl() = "https://errors.corda.net/${CordaVersionProvider.platformEditionCode}/${CordaVersionProvider.semanticVersion}/${errorCode()}"
|
||||
fun Throwable.errorCodeLocationUrl() = "https://errors.corda.net/${CordaVersion.platformEditionCode}/${CordaVersion.semanticVersion}/${errorCode()}"
|
||||
|
||||
private fun Throwable.errorCode(hashedFields: (Throwable) -> Array<out Any?> = Throwable::defaultHashedFields): String {
|
||||
fun Throwable.errorCode(hashedFields: (Throwable) -> Array<out Any?> = Throwable::defaultHashedFields): String {
|
||||
|
||||
val hash = staticLocationBasedHash(hashedFields)
|
||||
return hash.toBase(36)
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Configuration status="info" packages="net.corda.cliutils">
|
||||
<Configuration status="info" packages="net.corda.common.logging">
|
||||
|
||||
<Properties>
|
||||
<Property name="log-path">${sys:log-path:-logs}</Property>
|
||||
|
@ -73,6 +73,7 @@ dependencies {
|
||||
compile project(':tools:cliutils')
|
||||
compile project(':common-validation')
|
||||
compile project(':common-configuration-parsing')
|
||||
compile project(':common-logging')
|
||||
|
||||
// Backwards compatibility goo: Apps expect confidential-identities to be loaded by default.
|
||||
// We could eventually gate this on a target-version check.
|
||||
|
@ -4,8 +4,8 @@ import io.netty.channel.unix.Errors
|
||||
import net.corda.cliutils.printError
|
||||
import net.corda.cliutils.CliWrapperBase
|
||||
import net.corda.cliutils.CordaCliWrapper
|
||||
import net.corda.cliutils.CordaVersionProvider
|
||||
import net.corda.cliutils.ExitCodes
|
||||
import net.corda.common.logging.CordaVersion
|
||||
import net.corda.core.contracts.HashAttachmentConstraint
|
||||
import net.corda.core.crypto.Crypto
|
||||
import net.corda.core.internal.*
|
||||
@ -269,9 +269,9 @@ open class NodeStartup : NodeStartupLogging {
|
||||
open fun getVersionInfo(): VersionInfo {
|
||||
return VersionInfo(
|
||||
PLATFORM_VERSION,
|
||||
CordaVersionProvider.releaseVersion,
|
||||
CordaVersionProvider.revision,
|
||||
CordaVersionProvider.vendor
|
||||
CordaVersion.releaseVersion,
|
||||
CordaVersion.revision,
|
||||
CordaVersion.vendor
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -71,6 +71,10 @@ project(":common-validation").projectDir = new File("$settingsDir/common/validat
|
||||
|
||||
include 'common-configuration-parsing'
|
||||
project(":common-configuration-parsing").projectDir = new File("$settingsDir/common/configuration-parsing")
|
||||
|
||||
|
||||
include 'common-logging'
|
||||
project(":common-logging").projectDir = new File("$settingsDir/common/logging")
|
||||
// Common libraries - end
|
||||
|
||||
apply from: 'buildCacheSettings.gradle'
|
||||
|
@ -6,6 +6,7 @@ dependencies {
|
||||
compile project(':core')
|
||||
compile project(':node-api')
|
||||
compile project(':tools:cliutils')
|
||||
compile project(":common-logging")
|
||||
|
||||
// Unit testing helpers.
|
||||
compile "junit:junit:$junit_version"
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Configuration status="info" packages="net.corda.cliutils">
|
||||
<Configuration status="info" packages="net.corda.common.logging">
|
||||
|
||||
<Properties>
|
||||
<Property name="log-path">${sys:log-path:-logs}</Property>
|
||||
|
@ -6,6 +6,7 @@ apply plugin: 'com.jfrog.artifactory'
|
||||
dependencies {
|
||||
compile project(':client:jackson')
|
||||
compile project(':tools:cliutils')
|
||||
compile project(":common-logging")
|
||||
compile "org.slf4j:jul-to-slf4j:$slf4j_version"
|
||||
compile "org.apache.logging.log4j:log4j-slf4j-impl:$log4j_version"
|
||||
compile "com.jcabi:jcabi-manifests:$jcabi_manifests_version"
|
||||
|
@ -7,6 +7,7 @@ description 'Network bootstrapper'
|
||||
dependencies {
|
||||
compile project(':node-api')
|
||||
compile project(':tools:cliutils')
|
||||
compile project(":common-logging")
|
||||
compile project(':common-configuration-parsing')
|
||||
compile "org.apache.logging.log4j:log4j-slf4j-impl:$log4j_version"
|
||||
|
||||
|
@ -7,6 +7,7 @@ description 'CLI Utilities'
|
||||
|
||||
dependencies {
|
||||
compile project(":core")
|
||||
compile project(":common-logging")
|
||||
|
||||
compile "info.picocli:picocli:$picocli_version"
|
||||
compile "commons-io:commons-io:$commons_io_version"
|
||||
|
@ -1,33 +1,16 @@
|
||||
package net.corda.cliutils
|
||||
|
||||
import com.jcabi.manifests.Manifests
|
||||
import picocli.CommandLine
|
||||
import net.corda.common.logging.CordaVersion
|
||||
|
||||
/**
|
||||
* Simple version printing when command is called with --version or -V flag. Assuming that we reuse Corda-Release-Version and Corda-Revision
|
||||
* in the manifest file.
|
||||
*/
|
||||
class CordaVersionProvider : CommandLine.IVersionProvider {
|
||||
companion object {
|
||||
private const val UNKNOWN = "Unknown"
|
||||
const val current_major_release = "4.0-SNAPSHOT"
|
||||
const val platformEditionCode = "OS"
|
||||
|
||||
private fun manifestValue(name: String): String? = if (Manifests.exists(name)) Manifests.read(name) else null
|
||||
|
||||
val releaseVersion: String by lazy { manifestValue("Corda-Release-Version") ?: UNKNOWN }
|
||||
val revision: String by lazy { manifestValue("Corda-Revision") ?: UNKNOWN }
|
||||
val vendor: String by lazy { manifestValue("Corda-Vendor") ?: UNKNOWN }
|
||||
val platformVersion: Int by lazy { manifestValue("Corda-Platform-Version")?.toInt() ?: 1 }
|
||||
|
||||
internal val semanticVersion: String by lazy { if(releaseVersion == UNKNOWN) current_major_release else releaseVersion }
|
||||
}
|
||||
val version = CordaVersion()
|
||||
|
||||
override fun getVersion(): Array<String> {
|
||||
return if (Manifests.exists("Corda-Release-Version") && Manifests.exists("Corda-Revision")) {
|
||||
arrayOf("Version: $releaseVersion", "Revision: $revision", "Platform Version: $platformVersion", "Vendor: $vendor")
|
||||
} else {
|
||||
arrayOf("No version data is available in the MANIFEST file.")
|
||||
}
|
||||
return version.getVersion()
|
||||
}
|
||||
}
|
@ -10,6 +10,7 @@ import java.nio.file.Path
|
||||
import java.nio.file.Paths
|
||||
import java.nio.file.StandardCopyOption
|
||||
import java.util.*
|
||||
import net.corda.common.logging.CordaVersion
|
||||
|
||||
private class ShellExtensionsGenerator(val parent: CordaCliWrapper) {
|
||||
private companion object {
|
||||
@ -72,7 +73,7 @@ private class ShellExtensionsGenerator(val parent: CordaCliWrapper) {
|
||||
// If on Windows, Path.toString() returns a path with \ instead of /, but for bash Windows users we want to convert those back to /'s
|
||||
private fun Path.toStringWithDeWindowsfication(): String = this.toAbsolutePath().toString().replace("\\", "/")
|
||||
|
||||
private fun jarVersion(alias: String) = "# $alias - Version: ${CordaVersionProvider.releaseVersion}, Revision: ${CordaVersionProvider.revision}"
|
||||
private fun jarVersion(alias: String) = "# $alias - Version: ${CordaVersion.releaseVersion}, Revision: ${CordaVersion.revision}"
|
||||
private fun getAutoCompleteFileLocation(alias: String) = userHome / ".completion" / alias
|
||||
|
||||
private fun generateAutoCompleteFile(alias: String) {
|
||||
|
@ -19,6 +19,7 @@ dependencies {
|
||||
compile project(':finance:contracts')
|
||||
compile project(':finance:workflows')
|
||||
compile project(':tools:worldmap')
|
||||
compile project(':common-logging')
|
||||
|
||||
// Log4J: logging framework (with SLF4J bindings)
|
||||
compile "org.apache.logging.log4j:log4j-slf4j-impl:$log4j_version"
|
||||
|
@ -0,0 +1,77 @@
|
||||
package net.corda.explorer.ui
|
||||
|
||||
|
||||
import impl.org.controlsfx.i18n.Localization.getString
|
||||
import impl.org.controlsfx.i18n.Localization.localize
|
||||
import javafx.event.ActionEvent
|
||||
import javafx.event.EventHandler
|
||||
import net.corda.common.logging.errorCodeLocationUrl
|
||||
import org.controlsfx.dialog.ProgressDialog
|
||||
import javafx.scene.control.*
|
||||
import javafx.scene.layout.GridPane
|
||||
import javafx.scene.layout.Priority
|
||||
import javafx.scene.text.Text
|
||||
import javafx.scene.text.TextFlow
|
||||
import java.awt.Desktop
|
||||
import java.io.PrintWriter
|
||||
import java.io.StringWriter
|
||||
import java.net.URI
|
||||
|
||||
/*
|
||||
Will generate a window showing the exception message with a generated link and if requested a stacktrace.
|
||||
The link opens the default browser towards the error.corda.com/ redirection pages.
|
||||
*/
|
||||
class AdvancedExceptionDialog(_exception: Throwable) : Dialog<ButtonType>() {
|
||||
|
||||
internal val exception = _exception
|
||||
|
||||
init {
|
||||
val dialogPane = super.getDialogPane()
|
||||
|
||||
//Dialog title
|
||||
super.setTitle(getString("exception.dlg.title"))
|
||||
dialogPane.headerText = getString("exception.dlg.header")
|
||||
dialogPane.styleClass.add("exception-dialog")
|
||||
dialogPane.stylesheets.add(ProgressDialog::class.java.getResource("dialogs.css").toExternalForm())
|
||||
dialogPane.buttonTypes.addAll(ButtonType.OK)
|
||||
|
||||
|
||||
val hyperlink = Hyperlink(exception.errorCodeLocationUrl())
|
||||
hyperlink.onAction = EventHandler<ActionEvent> {
|
||||
if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {
|
||||
Desktop.getDesktop().browse( URI(exception.errorCodeLocationUrl()))
|
||||
} //This should be tested out on other platforms, works on my mac but the stackoverflow opinions are mixed.
|
||||
}
|
||||
|
||||
|
||||
val textFlow = TextFlow(Text("${exception.message}\n"), hyperlink)
|
||||
|
||||
dialogPane.content = textFlow
|
||||
}
|
||||
}
|
||||
|
||||
//Attach a stacktrace for the exception that was used in the initialization of the dialog.
|
||||
fun AdvancedExceptionDialog.withStacktrace() : AdvancedExceptionDialog
|
||||
{
|
||||
val sw = StringWriter()
|
||||
val pw = PrintWriter(sw)
|
||||
exception.printStackTrace(pw)
|
||||
val textArea = TextArea(sw.toString()).apply {
|
||||
isEditable = false
|
||||
isWrapText = false
|
||||
maxWidth = Double.MAX_VALUE
|
||||
maxHeight = Double.MAX_VALUE
|
||||
}
|
||||
|
||||
GridPane.setVgrow(textArea, Priority.ALWAYS)
|
||||
GridPane.setHgrow(textArea, Priority.ALWAYS)
|
||||
|
||||
val root = GridPane().apply {
|
||||
maxWidth = Double.MAX_VALUE
|
||||
add(Label(localize(getString("exception.dlg.label"))), 0, 0)
|
||||
add(textArea,0 ,1)
|
||||
}
|
||||
|
||||
dialogPane.expandableContent = root
|
||||
return this
|
||||
}
|
@ -4,9 +4,11 @@ import javafx.beans.property.SimpleIntegerProperty
|
||||
import javafx.scene.control.*
|
||||
import net.corda.client.jfx.model.NodeMonitorModel
|
||||
import net.corda.client.jfx.model.objectProperty
|
||||
import net.corda.client.rpc.RPCException
|
||||
import net.corda.core.utilities.NetworkHostAndPort
|
||||
import net.corda.explorer.model.SettingsModel
|
||||
import org.controlsfx.dialog.ExceptionDialog
|
||||
import net.corda.explorer.ui.AdvancedExceptionDialog
|
||||
import net.corda.explorer.ui.withStacktrace
|
||||
import tornadofx.*
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
@ -50,10 +52,14 @@ class LoginView : View(WINDOW_TITLE) {
|
||||
}
|
||||
getModel<SettingsModel>().commit()
|
||||
LoginStatus.loggedIn
|
||||
} catch (e: RPCException) {
|
||||
e.printStackTrace()
|
||||
AdvancedExceptionDialog(e).apply { initOwner(root.scene.window) }.showAndWait()
|
||||
LoginStatus.exception
|
||||
} catch (e: Exception) {
|
||||
// TODO : Handle this in a more user friendly way.
|
||||
e.printStackTrace()
|
||||
ExceptionDialog(e).apply { initOwner(root.scene.window) }.showAndWait()
|
||||
AdvancedExceptionDialog(e).withStacktrace().apply { initOwner(root.scene.window) }.showAndWait()
|
||||
LoginStatus.exception
|
||||
} finally {
|
||||
root.isDisable = false
|
||||
|
@ -11,6 +11,7 @@ apply plugin: 'com.jfrog.artifactory'
|
||||
dependencies {
|
||||
compile project(':tools:shell')
|
||||
compile project(':tools:cliutils')
|
||||
compile project(":common-logging")
|
||||
compile "org.apache.logging.log4j:log4j-slf4j-impl:$log4j_version"
|
||||
compile "org.slf4j:jul-to-slf4j:$slf4j_version"
|
||||
|
||||
|
@ -29,6 +29,7 @@ dependencies {
|
||||
compile project(':client:rpc')
|
||||
compile project(':client:jackson')
|
||||
compile project(':tools:cliutils')
|
||||
compile project(":common-logging")
|
||||
|
||||
// Web stuff: for HTTP[S] servlets
|
||||
compile "org.eclipse.jetty:jetty-servlet:$jetty_version"
|
||||
|
Loading…
Reference in New Issue
Block a user