diff --git a/node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt b/node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt index e4c31906b9..ba8a87da89 100644 --- a/node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt +++ b/node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt @@ -1,10 +1,12 @@ package net.corda.node.internal 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.cliutils.ShellConstants import net.corda.core.contracts.HashAttachmentConstraint import net.corda.core.crypto.Crypto import net.corda.core.internal.* @@ -53,7 +55,7 @@ abstract class NodeCliCommand(alias: String, description: String, val startup: N const val LOGS_DIRECTORY_NAME = "logs" } - override fun initLogging() = this.initLogging(cmdLineOptions.baseDirectory) + override fun initLogging(): Boolean = this.initLogging(cmdLineOptions.baseDirectory) @Mixin val cmdLineOptions = SharedNodeCmdLineOptions() @@ -71,7 +73,7 @@ open class NodeStartupCli : CordaCliWrapper("corda", "Runs a Corda Node") { private val initialRegistrationCli by lazy { InitialRegistrationCli(startup) } private val validateConfigurationCli by lazy { ValidateConfigurationCli() } - override fun initLogging() = this.initLogging(cmdLineOptions.baseDirectory) + override fun initLogging(): Boolean = this.initLogging(cmdLineOptions.baseDirectory) override fun additionalSubCommands() = setOf(networkCacheCli, justGenerateNodeInfoCli, justGenerateRpcSslCertsCli, initialRegistrationCli, validateConfigurationCli) @@ -437,14 +439,32 @@ interface NodeStartupLogging { } } -fun CliWrapperBase.initLogging(baseDirectory: Path) { +fun CliWrapperBase.initLogging(baseDirectory: Path): Boolean { System.setProperty("defaultLogLevel", specifiedLogLevel) // These properties are referenced from the XML config file. if (verbose) { System.setProperty("consoleLoggingEnabled", "true") System.setProperty("consoleLogLevel", specifiedLogLevel) Node.renderBasicInfoToConsole = false } + + //Test for access to the logging path and shutdown if we are unable to reach it. + val logPath = baseDirectory / NodeCliCommand.LOGS_DIRECTORY_NAME + try { + logPath.createDirectories() + } catch (e: IOException) { + printError("Unable to create logging directory ${logPath.toString()}. Node will now shutdown.") + return false + } catch (e: SecurityException) { + printError("Current user is unable to access logging directory ${logPath.toString()}. Node will now shutdown.") + return false + } + if (!logPath.isDirectory()) { + printError("Unable to access logging directory ${logPath.toString()}. Node will now shutdown.") + return false + } + System.setProperty("log-path", (baseDirectory / NodeCliCommand.LOGS_DIRECTORY_NAME).toString()) SLF4JBridgeHandler.removeHandlersForRootLogger() // The default j.u.l config adds a ConsoleHandler. SLF4JBridgeHandler.install() + return true } diff --git a/node/src/main/kotlin/net/corda/node/internal/subcommands/InitialRegistrationCli.kt b/node/src/main/kotlin/net/corda/node/internal/subcommands/InitialRegistrationCli.kt index 228f6e3400..8cdea61831 100644 --- a/node/src/main/kotlin/net/corda/node/internal/subcommands/InitialRegistrationCli.kt +++ b/node/src/main/kotlin/net/corda/node/internal/subcommands/InitialRegistrationCli.kt @@ -30,7 +30,7 @@ class InitialRegistrationCli(val startup: NodeStartup): CliWrapperBase("initial- return startup.initialiseAndRun(cmdLineOptions, InitialRegistration(cmdLineOptions.baseDirectory, networkRootTrustStorePath, networkRootTrustStorePassword, startup)) } - override fun initLogging() = this.initLogging(cmdLineOptions.baseDirectory) + override fun initLogging(): Boolean = this.initLogging(cmdLineOptions.baseDirectory) @Mixin val cmdLineOptions = InitialRegistrationCmdLineOptions() diff --git a/node/src/main/kotlin/net/corda/node/internal/subcommands/ValidateConfigurationCli.kt b/node/src/main/kotlin/net/corda/node/internal/subcommands/ValidateConfigurationCli.kt index fd264e4563..7dca45faca 100644 --- a/node/src/main/kotlin/net/corda/node/internal/subcommands/ValidateConfigurationCli.kt +++ b/node/src/main/kotlin/net/corda/node/internal/subcommands/ValidateConfigurationCli.kt @@ -32,7 +32,7 @@ internal class ValidateConfigurationCli : CliWrapperBase("validate-configuration @Mixin private val cmdLineOptions = SharedNodeCmdLineOptions() - override fun initLogging() = initLogging(cmdLineOptions.baseDirectory) + override fun initLogging(): Boolean = initLogging(cmdLineOptions.baseDirectory) override fun runProgram(): Int { val rawConfig = cmdLineOptions.rawConfiguration().doOnErrors(cmdLineOptions::logRawConfigurationErrors).optional ?: return ExitCodes.FAILURE diff --git a/tools/cliutils/src/main/kotlin/net/corda/cliutils/CordaCliWrapper.kt b/tools/cliutils/src/main/kotlin/net/corda/cliutils/CordaCliWrapper.kt index 7a61cc3a28..0b219e67a5 100644 --- a/tools/cliutils/src/main/kotlin/net/corda/cliutils/CordaCliWrapper.kt +++ b/tools/cliutils/src/main/kotlin/net/corda/cliutils/CordaCliWrapper.kt @@ -1,5 +1,6 @@ package net.corda.cliutils +import net.corda.cliutils.ExitCodes import net.corda.core.internal.rootMessage import net.corda.core.utilities.contextLogger import org.fusesource.jansi.AnsiConsole @@ -123,12 +124,13 @@ abstract class CliWrapperBase(val alias: String, val description: String) : Call // This needs to be called before loggers (See: NodeStartup.kt:51 logger called by lazy, initLogging happens before). // Node's logging is more rich. In corda configurations two properties, defaultLoggingLevel and consoleLogLevel, are usually used. - open fun initLogging() { + open fun initLogging(): Boolean { System.setProperty("defaultLogLevel", specifiedLogLevel) // These properties are referenced from the XML config file. if (verbose) { System.setProperty("consoleLogLevel", specifiedLogLevel) } System.setProperty("log-path", Paths.get(".").toString()) + return true } // Override this function with the actual method to be run once all the arguments have been parsed. The return number @@ -141,7 +143,9 @@ abstract class CliWrapperBase(val alias: String, val description: String) : Call return runProgram() } - val specifiedLogLevel: String by lazy { System.getProperty("log4j2.level")?.toLowerCase(Locale.ENGLISH) ?: loggingLevel.name.toLowerCase(Locale.ENGLISH) } + val specifiedLogLevel: String by lazy { + System.getProperty("log4j2.level")?.toLowerCase(Locale.ENGLISH) ?: loggingLevel.name.toLowerCase(Locale.ENGLISH) + } } /** @@ -178,20 +182,20 @@ abstract class CordaCliWrapper(alias: String, description: String) : CliWrapperB } override fun call(): Int { - initLogging() + if (!initLogging()) { + return ExitCodes.FAILURE + } logger.info("Application Args: ${args.joinToString(" ")}") installShellExtensionsParser.updateShellExtensions() return runProgram() } fun printHelp() = cmd.usage(System.out) - } fun printWarning(message: String) = System.err.println("${ShellConstants.YELLOW}$message${ShellConstants.RESET}") fun printError(message: String) = System.err.println("${ShellConstants.RED}$message${ShellConstants.RESET}") - /** * Useful commonly used constants applicable to many CLI tools */ diff --git a/tools/shell-cli/src/main/kotlin/net/corda/tools/shell/StandaloneShell.kt b/tools/shell-cli/src/main/kotlin/net/corda/tools/shell/StandaloneShell.kt index 8d40c858ea..aa2016aef6 100644 --- a/tools/shell-cli/src/main/kotlin/net/corda/tools/shell/StandaloneShell.kt +++ b/tools/shell-cli/src/main/kotlin/net/corda/tools/shell/StandaloneShell.kt @@ -56,10 +56,11 @@ class StandaloneShell : CordaCliWrapper("corda-shell", "The Corda standalone she private fun getManifestEntry(key: String) = if (Manifests.exists(key)) Manifests.read(key) else "Unknown" - override fun initLogging() { + override fun initLogging() : Boolean { super.initLogging() SLF4JBridgeHandler.removeHandlersForRootLogger() // The default j.u.l config adds a ConsoleHandler. SLF4JBridgeHandler.install() + return true } override fun runProgram(): Int {