From b07526f1b905ff009217eed8163998ed39833a88 Mon Sep 17 00:00:00 2001 From: coachDave Date: Fri, 25 Aug 2023 16:10:07 +0200 Subject: [PATCH] Added logging capabilities using logback and secured default Standard Output Stream to reserve it for LSP4j --- .gitignore | 3 ++- pom.xml | 15 +++++++++--- src/main/resources/logback.xml | 24 +++++++++++++++++++ src/main/scala/io/smartdatalake/Main.scala | 23 +++++++++++------- .../logging/LoggerOutputStream.scala | 18 ++++++++++++++ .../logging/LoggingManager.scala | 15 ++++++++++++ 6 files changed, 86 insertions(+), 12 deletions(-) create mode 100644 src/main/resources/logback.xml create mode 100644 src/main/scala/io/smartdatalake/logging/LoggerOutputStream.scala create mode 100644 src/main/scala/io/smartdatalake/logging/LoggingManager.scala diff --git a/.gitignore b/.gitignore index b408303..cec2193 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ lsp -target \ No newline at end of file +target +logs \ No newline at end of file diff --git a/pom.xml b/pom.xml index 9812aa7..1c94973 100644 --- a/pom.xml +++ b/pom.xml @@ -25,7 +25,9 @@ UTF-8 3.3.0 0.21.0 - 1.4.2 + 1.4.2 + 3.1.2 + 1.4.11 @@ -47,13 +49,20 @@ com.typesafe config - ${typesafe.version} + ${typesafe.config.version} com.lihaoyi ujson_3 - 3.1.2 + ${ujson.version} + + + + + ch.qos.logback + logback-classic + ${logback.version} diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml new file mode 100644 index 0000000..f8c0428 --- /dev/null +++ b/src/main/resources/logback.xml @@ -0,0 +1,24 @@ + + + + + logs/myapp.log + + logs/myapp.%i.log + 1 + 10 + + + 10MB + + + %date{dd-MM-yyyy HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + diff --git a/src/main/scala/io/smartdatalake/Main.scala b/src/main/scala/io/smartdatalake/Main.scala index 5d5af7c..a037a33 100644 --- a/src/main/scala/io/smartdatalake/Main.scala +++ b/src/main/scala/io/smartdatalake/Main.scala @@ -1,26 +1,31 @@ package io.smartdatalake +import io.smartdatalake.logging.LoggingManager import io.smartdatalake.modules.AppModule import org.eclipse.lsp4j.jsonrpc.Launcher import org.eclipse.lsp4j.launch.LSPLauncher import org.eclipse.lsp4j.services.{LanguageClient, LanguageClientAware, LanguageServer} -import java.io.{InputStream, PrintStream} -import java.util.logging.{Level, LogManager, Logger} +import java.io.{InputStream, OutputStream, PrintStream} +import org.slf4j.LoggerFactory /** * @author scalathe */ + object Main extends AppModule { def main(args : Array[String]): Unit = { - // We're using Standard Input and Standard Output for communication. - LogManager.getLogManager.reset() - val globalLogger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME) - globalLogger.setLevel(Level.OFF) + // We're using Standard Input and Standard Output for communication, so we need to ensure Standard Output is only used by the LSP4j server. + // Keep a reference on the default standard output + val systemOut = System.out + + // redirect default output to the same stream of the logback logger + LoggingManager.redirectStandardOutputToLoggerOutput() - startServer(System.in, System.out) + // give the Standard Output reference for the server. + startServer(System.in, systemOut) } private def startServer(in: InputStream, out: PrintStream) = { @@ -29,7 +34,9 @@ object Main extends AppModule { val client: LanguageClient = launcher.getRemoteProxy helloLanguageServer.connect(client) - + // Use the configured logger + val logger = LoggerFactory.getLogger(getClass) + logger.info("Server starts listening...") launcher.startListening().get() } diff --git a/src/main/scala/io/smartdatalake/logging/LoggerOutputStream.scala b/src/main/scala/io/smartdatalake/logging/LoggerOutputStream.scala new file mode 100644 index 0000000..bd15bf8 --- /dev/null +++ b/src/main/scala/io/smartdatalake/logging/LoggerOutputStream.scala @@ -0,0 +1,18 @@ +package io.smartdatalake.logging + +import org.slf4j.Logger + +import java.io.OutputStream + +private[logging] class LoggerOutputStream(logger: Logger) extends OutputStream { + private val builder = new StringBuilder + override def write(b: Int): Unit = { + if (b == '\n') { + logger.info(builder.toString) + builder.clear() + } else { + builder.append(b.toChar) + } + } + +} diff --git a/src/main/scala/io/smartdatalake/logging/LoggingManager.scala b/src/main/scala/io/smartdatalake/logging/LoggingManager.scala new file mode 100644 index 0000000..ef0ab69 --- /dev/null +++ b/src/main/scala/io/smartdatalake/logging/LoggingManager.scala @@ -0,0 +1,15 @@ +package io.smartdatalake.logging + +import org.slf4j.LoggerFactory + +import java.io.PrintStream + +object LoggingManager { + + def redirectStandardOutputToLoggerOutput(): Unit = + val loggerRedirectedOutput = LoggerFactory.getLogger("redirectedOutput") + val redirectedPrintStream = new PrintStream(new LoggerOutputStream(loggerRedirectedOutput)) + System.setOut(redirectedPrintStream) + println("Using new default output stream") + +}