Skip to content

Commit

Permalink
Added logging capabilities using logback and secured default Standard…
Browse files Browse the repository at this point in the history
… Output Stream to reserve it for LSP4j
  • Loading branch information
dsalathe committed Aug 25, 2023
1 parent fa36eb0 commit b07526f
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 12 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
lsp
target
target
logs
15 changes: 12 additions & 3 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@
<encoding>UTF-8</encoding>
<scala.version>3.3.0</scala.version> <!-- Scala 2.12 not working because of copies of annotations issues -->
<lsp4j.version>0.21.0</lsp4j.version>
<typesafe.version>1.4.2</typesafe.version>
<typesafe.config.version>1.4.2</typesafe.config.version>
<ujson.version>3.1.2</ujson.version>
<logback.version>1.4.11</logback.version>
</properties>


Expand All @@ -47,13 +49,20 @@
<dependency>
<groupId>com.typesafe</groupId>
<artifactId>config</artifactId>
<version>${typesafe.version}</version>
<version>${typesafe.config.version}</version>
</dependency>

<dependency>
<groupId>com.lihaoyi</groupId>
<artifactId>ujson_3</artifactId>
<version>3.1.2</version>
<version>${ujson.version}</version>
</dependency>

<!-- Logging -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>


Expand Down
24 changes: 24 additions & 0 deletions src/main/resources/logback.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<configuration>

<!-- Appender to write logs to a file -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/myapp.log</file> <!-- Change the file name as needed -->
<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
<fileNamePattern>logs/myapp.%i.log</fileNamePattern>
<minIndex>1</minIndex>
<maxIndex>10</maxIndex>
</rollingPolicy>
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<maxFileSize>10MB</maxFileSize>
</triggeringPolicy>
<encoder>
<pattern>%date{dd-MM-yyyy HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>

<!-- Root logger settings -->
<root level="info">
<appender-ref ref="FILE"/>
</root>

</configuration>
23 changes: 15 additions & 8 deletions src/main/scala/io/smartdatalake/Main.scala
Original file line number Diff line number Diff line change
@@ -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) = {
Expand All @@ -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()
}

Expand Down
18 changes: 18 additions & 0 deletions src/main/scala/io/smartdatalake/logging/LoggerOutputStream.scala
Original file line number Diff line number Diff line change
@@ -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)
}
}

}
15 changes: 15 additions & 0 deletions src/main/scala/io/smartdatalake/logging/LoggingManager.scala
Original file line number Diff line number Diff line change
@@ -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")

}

0 comments on commit b07526f

Please sign in to comment.