mirror of
https://github.com/enso-org/enso.git
synced 2025-01-03 14:04:44 +03:00
Implement masking of sensitive data in logs (#1732)
This commit is contained in:
parent
c4c483683e
commit
1b6388702f
@ -7,6 +7,9 @@
|
||||
searcher to make more accurate suggestions when working with collection types.
|
||||
- Fixed an issue where symlinks were not extracted properly when installing a
|
||||
runtime for Enso ([#1718](https://github.com/enso-org/enso/pull/1718)).
|
||||
- Implemented log masking ([#1732](https://github.com/enso-org/enso/pull/1732)).
|
||||
This feature masks personally identifiable information in the logs, such as
|
||||
code literals, computed values, and user environment variables.
|
||||
|
||||
## Libraries
|
||||
|
||||
|
13
build.sbt
13
build.sbt
@ -190,6 +190,7 @@ lazy val enso = (project in file("."))
|
||||
logger.jvm,
|
||||
pkg,
|
||||
cli,
|
||||
`logging-utils`,
|
||||
`logging-service`,
|
||||
`akka-native`,
|
||||
`version-output`,
|
||||
@ -602,6 +603,16 @@ lazy val `akka-native` = project
|
||||
libraryDependencies += "org.graalvm.nativeimage" % "svm" % graalVersion % "provided"
|
||||
)
|
||||
|
||||
lazy val `logging-utils` = project
|
||||
.in(file("lib/scala/logging-utils"))
|
||||
.configs(Test)
|
||||
.settings(
|
||||
version := "0.1",
|
||||
libraryDependencies ++= Seq(
|
||||
"org.scalatest" %% "scalatest" % scalatestVersion % Test,
|
||||
)
|
||||
)
|
||||
|
||||
lazy val `logging-service` = project
|
||||
.in(file("lib/scala/logging-service"))
|
||||
.configs(Test)
|
||||
@ -625,6 +636,7 @@ lazy val `logging-service` = project
|
||||
(Compile / unmanagedSourceDirectories) += (Compile / sourceDirectory).value / "java-unix"
|
||||
)
|
||||
.dependsOn(`akka-native`)
|
||||
.dependsOn(`logging-utils`)
|
||||
|
||||
lazy val cli = project
|
||||
.in(file("lib/scala/cli"))
|
||||
@ -1063,6 +1075,7 @@ lazy val runtime = (project in file("engine/runtime"))
|
||||
.dependsOn(`text-buffer`)
|
||||
.dependsOn(searcher)
|
||||
.dependsOn(testkit % Test)
|
||||
.dependsOn(`logging-utils`)
|
||||
|
||||
/* Note [Unmanaged Classpath]
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
@ -23,6 +23,8 @@ components.
|
||||
- [JVM Architecture](#jvm-architecture)
|
||||
- [SLF4J Interface](#slf4j-interface)
|
||||
- [Setting Up Logging](#setting-up-logging)
|
||||
- [Log Masking](#log-masking)
|
||||
- [Logging in Tests](#logging-in-tests)
|
||||
|
||||
<!-- /MarkdownTOC -->
|
||||
|
||||
@ -252,6 +254,32 @@ shutdown hook is added that will print the pending log messages before exiting.
|
||||
Some of the messages may be dropped, however, if more messages are buffered than
|
||||
the buffer can hold.
|
||||
|
||||
### Log Masking
|
||||
|
||||
Logs should not contain personally identifiable information (PII). The following
|
||||
is considered PII:
|
||||
|
||||
- User code
|
||||
- Values of executed expressions
|
||||
- Values of user environment variables. Although variable names are not
|
||||
considered PII and can be logged.
|
||||
- File paths inside the user project directory. System and distribution paths
|
||||
and a path to the user project can be logged.
|
||||
|
||||
Project logging library implements masking of PII. To utilize it
|
||||
|
||||
1. Logged object should implement an interface that defines custom log-string
|
||||
representation of this object
|
||||
2. The logging should be performed by supplying a template string with `{}`
|
||||
placeholders, and the arguments
|
||||
```scala
|
||||
log.debug("Created {} at [{}].", obj, path)
|
||||
```
|
||||
|
||||
String interpolation in log statements `s"Created $obj"` should be avoided
|
||||
because it uses default `toString` implementation and can leak critical
|
||||
information even if the object implements custom interface for masked logging.
|
||||
|
||||
### Logging in Tests
|
||||
|
||||
The Logging Service provides several utilities for managing logs inside of
|
||||
|
@ -56,8 +56,8 @@ independent Scalafmt plugin.
|
||||
|
||||
## Naming
|
||||
|
||||
Enso has some fairly simple general naming conventions, though the sections
|
||||
below may provide more rules for use in specific cases.
|
||||
Enso has some fairly simple general naming conventions, though the sections w
|
||||
may provide more rules for use in specific cases.
|
||||
|
||||
- Types are written using `UpperCamelCase`.
|
||||
- Variables and function names are written using `camelCase`.
|
||||
|
@ -1,17 +1,14 @@
|
||||
package org.enso.languageserver.boot
|
||||
|
||||
/** Signal where the lang. server is deployed.
|
||||
*/
|
||||
/** Signal where the lang. server is deployed. */
|
||||
sealed trait DeploymentType
|
||||
|
||||
object DeploymentType {
|
||||
|
||||
/** Desktop deployment.
|
||||
*/
|
||||
/** Desktop deployment. */
|
||||
case object Desktop extends DeploymentType
|
||||
|
||||
/** Azure deployment.
|
||||
*/
|
||||
/** Azure deployment. */
|
||||
case object Azure extends DeploymentType
|
||||
|
||||
/** Determines the current deployment type from environment variables.
|
||||
|
@ -1,7 +1,11 @@
|
||||
package org.enso.languageserver.boot
|
||||
|
||||
import java.nio.file.Path
|
||||
import java.util.UUID
|
||||
|
||||
import org.enso.logger.masking.MaskingUtils.toMaskedPath
|
||||
import org.enso.logger.masking.ToLogString
|
||||
|
||||
import scala.concurrent.ExecutionContext
|
||||
|
||||
/** The config of the running Language Server instance.
|
||||
@ -20,4 +24,24 @@ case class LanguageServerConfig(
|
||||
contentRootPath: String,
|
||||
name: String = "language-server",
|
||||
computeExecutionContext: ExecutionContext = ExecutionContext.global
|
||||
)
|
||||
) extends ToLogString {
|
||||
|
||||
/** @inheritdoc */
|
||||
override def toLogString(shouldMask: Boolean): String = {
|
||||
val contentRootString =
|
||||
if (shouldMask) {
|
||||
toMaskedPath(Path.of(contentRootPath))
|
||||
} else {
|
||||
contentRootPath
|
||||
}
|
||||
s"LanguageServerConfig(" +
|
||||
s"interface=$interface, " +
|
||||
s"rpcPort=$rpcPort, " +
|
||||
s"dataPort=$dataPort, " +
|
||||
s"contentRootUuid=$contentRootUuid, " +
|
||||
s"contentRootPath=$contentRootString, " +
|
||||
s"name=$name, " +
|
||||
s"computeExecutionContext=$computeExecutionContext" +
|
||||
s")"
|
||||
}
|
||||
}
|
||||
|
@ -49,10 +49,11 @@ import scala.concurrent.duration._
|
||||
*/
|
||||
class MainModule(serverConfig: LanguageServerConfig, logLevel: LogLevel) {
|
||||
|
||||
val log = LoggerFactory.getLogger(this.getClass)
|
||||
private val log = LoggerFactory.getLogger(this.getClass)
|
||||
log.info(
|
||||
s"Initializing main module of the Language Server from " +
|
||||
s"$serverConfig $logLevel."
|
||||
"Initializing main module of the Language Server from [{}, {}]",
|
||||
serverConfig,
|
||||
logLevel
|
||||
)
|
||||
|
||||
val directoriesConfig = DirectoriesConfig(serverConfig.contentRootPath)
|
||||
@ -63,17 +64,17 @@ class MainModule(serverConfig: LanguageServerConfig, logLevel: LogLevel) {
|
||||
ExecutionContextConfig(),
|
||||
directoriesConfig
|
||||
)
|
||||
log.trace(s"Created Language Server config $languageServerConfig.")
|
||||
log.trace("Created Language Server config [{}].", languageServerConfig)
|
||||
|
||||
val zioExec = ZioExec(zio.Runtime.default)
|
||||
log.trace(s"Created ZIO executor $zioExec.")
|
||||
log.trace("Created ZIO executor [{}].", zioExec)
|
||||
|
||||
val fileSystem: FileSystem = new FileSystem
|
||||
log.trace(s"Created file system $fileSystem.")
|
||||
log.trace("Created file system [{}].", fileSystem)
|
||||
|
||||
implicit val versionCalculator: ContentBasedVersioning =
|
||||
Sha3_224VersionCalculator
|
||||
log.trace(s"Created Version Calculator $versionCalculator.")
|
||||
log.trace("Created Version Calculator [{}].", versionCalculator)
|
||||
|
||||
implicit val system =
|
||||
ActorSystem(
|
||||
@ -100,7 +101,7 @@ class MainModule(serverConfig: LanguageServerConfig, logLevel: LogLevel) {
|
||||
|
||||
val suggestionsRepo = new SqlSuggestionsRepo(sqlDatabase)(system.dispatcher)
|
||||
val versionsRepo = new SqlVersionsRepo(sqlDatabase)(system.dispatcher)
|
||||
log.trace(s"Created SQL repos: $suggestionsRepo, $versionsRepo.")
|
||||
log.trace("Created SQL repos: [{}. {}].", suggestionsRepo, versionsRepo)
|
||||
|
||||
lazy val sessionRouter =
|
||||
system.actorOf(SessionRouter.props(), "session-router")
|
||||
@ -197,10 +198,10 @@ class MainModule(serverConfig: LanguageServerConfig, logLevel: LogLevel) {
|
||||
} else null
|
||||
})
|
||||
.build()
|
||||
log.trace(s"Created Runtime context $context.")
|
||||
log.trace("Created Runtime context [{}].", context)
|
||||
|
||||
system.eventStream.setLogLevel(LogLevel.toAkka(logLevel))
|
||||
log.trace(s"Set akka log level to $logLevel.")
|
||||
log.trace("Set akka log level to [{}].", logLevel)
|
||||
|
||||
val runtimeKiller =
|
||||
system.actorOf(
|
||||
@ -249,7 +250,8 @@ class MainModule(serverConfig: LanguageServerConfig, logLevel: LogLevel) {
|
||||
runtimeConnector
|
||||
)
|
||||
log.trace(
|
||||
s"Created JSON connection controller factory $jsonRpcControllerFactory."
|
||||
"Created JSON connection controller factory [{}].",
|
||||
jsonRpcControllerFactory
|
||||
)
|
||||
|
||||
val pingHandlerProps =
|
||||
@ -277,7 +279,7 @@ class MainModule(serverConfig: LanguageServerConfig, logLevel: LogLevel) {
|
||||
.Config(outgoingBufferSize = 10000, lazyMessageTimeout = 10.seconds),
|
||||
List(healthCheckEndpoint)
|
||||
)
|
||||
log.trace(s"Created JSON RPC Server $jsonRpcServer.")
|
||||
log.trace("Created JSON RPC Server [{}].", jsonRpcServer)
|
||||
|
||||
val binaryServer =
|
||||
new BinaryWebSocketServer(
|
||||
@ -285,11 +287,11 @@ class MainModule(serverConfig: LanguageServerConfig, logLevel: LogLevel) {
|
||||
BinaryEncoder.empty,
|
||||
new BinaryConnectionControllerFactory(fileManager)
|
||||
)
|
||||
log.trace(s"Created Binary WebSocket Server $binaryServer.")
|
||||
log.trace("Created Binary WebSocket Server [{}].", binaryServer)
|
||||
|
||||
log.info(
|
||||
s"Main module of the Language Server initialized " +
|
||||
s"with config $languageServerConfig."
|
||||
"Main module of the Language Server initialized with config [{}].",
|
||||
languageServerConfig
|
||||
)
|
||||
|
||||
/** Close the main module releasing all resources. */
|
||||
|
@ -7,6 +7,7 @@ import akka.event.EventStream
|
||||
import org.apache.commons.io.FileUtils
|
||||
import org.enso.languageserver.data.DirectoriesConfig
|
||||
import org.enso.languageserver.event.InitializedEvent
|
||||
import org.enso.logger.masking.MaskedPath
|
||||
import org.enso.searcher.sql.{SqlDatabase, SqlSuggestionsRepo, SqlVersionsRepo}
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
@ -43,8 +44,8 @@ class RepoInitialization(
|
||||
for {
|
||||
_ <- Future {
|
||||
log.info(
|
||||
s"Initializing suggestions repo " +
|
||||
s"${directoriesConfig.suggestionsDatabaseFile}."
|
||||
"Initializing suggestions repo [{}].",
|
||||
MaskedPath(directoriesConfig.suggestionsDatabaseFile.toPath)
|
||||
)
|
||||
}
|
||||
_ <- suggestionsRepo.init.recoverWith { case NonFatal(error) =>
|
||||
@ -52,8 +53,8 @@ class RepoInitialization(
|
||||
}
|
||||
_ <- Future {
|
||||
log.info(
|
||||
s"Initialized Suggestions repo " +
|
||||
s"${directoriesConfig.suggestionsDatabaseFile}."
|
||||
"Initialized Suggestions repo [{}].",
|
||||
MaskedPath(directoriesConfig.suggestionsDatabaseFile.toPath)
|
||||
)
|
||||
}
|
||||
} yield ()
|
||||
@ -62,9 +63,9 @@ class RepoInitialization(
|
||||
eventStream.publish(InitializedEvent.SuggestionsRepoInitialized)
|
||||
case Failure(ex) =>
|
||||
log.error(
|
||||
s"Failed to initialize SQL suggestions repo " +
|
||||
s"${directoriesConfig.suggestionsDatabaseFile}. " +
|
||||
s"${ex.getMessage}"
|
||||
"Failed to initialize SQL suggestions repo [{}]. {}",
|
||||
MaskedPath(directoriesConfig.suggestionsDatabaseFile.toPath),
|
||||
ex.getMessage
|
||||
)
|
||||
}
|
||||
initAction
|
||||
@ -75,15 +76,15 @@ class RepoInitialization(
|
||||
for {
|
||||
_ <- Future {
|
||||
log.info(
|
||||
s"Initializing versions repo " +
|
||||
s"${directoriesConfig.suggestionsDatabaseFile}."
|
||||
"Initializing versions repo [{}].",
|
||||
MaskedPath(directoriesConfig.suggestionsDatabaseFile.toPath)
|
||||
)
|
||||
}
|
||||
_ <- versionsRepo.init
|
||||
_ <- Future {
|
||||
log.info(
|
||||
s"Initialized Versions repo " +
|
||||
s"${directoriesConfig.suggestionsDatabaseFile}."
|
||||
"Initialized Versions repo [{}].",
|
||||
MaskedPath(directoriesConfig.suggestionsDatabaseFile.toPath)
|
||||
)
|
||||
}
|
||||
} yield ()
|
||||
@ -92,9 +93,9 @@ class RepoInitialization(
|
||||
eventStream.publish(InitializedEvent.FileVersionsRepoInitialized)
|
||||
case Failure(ex) =>
|
||||
log.error(
|
||||
s"Failed to initialize SQL versions repo " +
|
||||
s"${directoriesConfig.suggestionsDatabaseFile}. " +
|
||||
s"${ex.getMessage}"
|
||||
"Failed to initialize SQL versions repo [{}]. {}",
|
||||
MaskedPath(directoriesConfig.suggestionsDatabaseFile.toPath),
|
||||
ex.getMessage
|
||||
)
|
||||
}
|
||||
initAction
|
||||
@ -107,9 +108,9 @@ class RepoInitialization(
|
||||
for {
|
||||
_ <- Future {
|
||||
log.warn(
|
||||
s"Failed to initialize the suggestions database " +
|
||||
s"${directoriesConfig.suggestionsDatabaseFile}. " +
|
||||
s"${error.getMessage}"
|
||||
"Failed to initialize the suggestions database [{}]. {}",
|
||||
MaskedPath(directoriesConfig.suggestionsDatabaseFile.toPath),
|
||||
error.getMessage
|
||||
)
|
||||
}
|
||||
_ <- Future(db.close())
|
||||
@ -123,14 +124,15 @@ class RepoInitialization(
|
||||
|
||||
private def clearDatabaseFile(retries: Int = 0): Future[Unit] = {
|
||||
Future {
|
||||
log.info(s"Clear database file. Attempt #${retries + 1}.")
|
||||
log.info("Clear database file. Attempt #{}.", retries + 1)
|
||||
Files.delete(directoriesConfig.suggestionsDatabaseFile.toPath)
|
||||
}.recoverWith {
|
||||
case _: NoSuchFileException =>
|
||||
log.warn(
|
||||
s"Failed to delete the database file. Attempt #${retries + 1}. " +
|
||||
s"File does not exist " +
|
||||
s"${directoriesConfig.suggestionsDatabaseFile}"
|
||||
"Failed to delete the database file. Attempt #{}. " +
|
||||
"File does not exist [{}].",
|
||||
retries + 1,
|
||||
MaskedPath(directoriesConfig.suggestionsDatabaseFile.toPath)
|
||||
)
|
||||
Future.successful(())
|
||||
case error: FileSystemException =>
|
||||
@ -144,8 +146,9 @@ class RepoInitialization(
|
||||
Future.failed(error)
|
||||
case error: IOException =>
|
||||
log.error(
|
||||
s"Failed to delete the database file. Attempt #${retries + 1}. " +
|
||||
s"${error.getMessage}"
|
||||
"Failed to delete the database file. Attempt #{}. {}",
|
||||
retries + 1,
|
||||
error.getMessage
|
||||
)
|
||||
if (retries < RepoInitialization.MaxRetries) {
|
||||
Thread.sleep(1000)
|
||||
|
@ -9,6 +9,7 @@ import org.enso.languageserver.filemanager.{
|
||||
FileSystemFailure,
|
||||
Path
|
||||
}
|
||||
import org.enso.logger.masking.{MaskingUtils, ToLogString}
|
||||
|
||||
import scala.concurrent.duration._
|
||||
|
||||
@ -77,7 +78,7 @@ object ExecutionContextConfig {
|
||||
*
|
||||
* @param root the root directory path
|
||||
*/
|
||||
case class DirectoriesConfig(root: File) {
|
||||
case class DirectoriesConfig(root: File) extends ToLogString {
|
||||
|
||||
/** The data directory path. */
|
||||
val dataDirectory: File =
|
||||
@ -87,6 +88,14 @@ case class DirectoriesConfig(root: File) {
|
||||
val suggestionsDatabaseFile: File =
|
||||
new File(dataDirectory, DirectoriesConfig.SuggestionsDatabaseFile)
|
||||
|
||||
/** @inheritdoc */
|
||||
override def toLogString(shouldMask: Boolean): String = {
|
||||
val rootString =
|
||||
if (shouldMask) MaskingUtils.toMaskedPath(root.toPath)
|
||||
else root.toString
|
||||
s"DirectoriesConfig($rootString)"
|
||||
}
|
||||
|
||||
/** Create data directories if not exist. */
|
||||
def createDirectories(): Unit =
|
||||
Files.createDirectories(dataDirectory.toPath)
|
||||
@ -127,7 +136,27 @@ case class Config(
|
||||
pathWatcher: PathWatcherConfig,
|
||||
executionContext: ExecutionContextConfig,
|
||||
directories: DirectoriesConfig
|
||||
) {
|
||||
) extends ToLogString {
|
||||
|
||||
/** @inheritdoc */
|
||||
override def toLogString(shouldMask: Boolean): String = {
|
||||
val maskedRoots =
|
||||
if (shouldMask) {
|
||||
contentRoots
|
||||
.map { case (k, v) =>
|
||||
k -> MaskingUtils.toMaskedPath(v.toPath)
|
||||
}
|
||||
} else {
|
||||
contentRoots
|
||||
}
|
||||
s"Config(" +
|
||||
s"contentRoots=$maskedRoots, " +
|
||||
s"fileManager=$fileManager, " +
|
||||
s"pathWatcher=$pathWatcher, " +
|
||||
s"executionContext=$executionContext, " +
|
||||
s"directories=${directories.toLogString(shouldMask)}" +
|
||||
s")"
|
||||
}
|
||||
|
||||
def findContentRoot(rootId: UUID): Either[FileSystemFailure, File] =
|
||||
contentRoots
|
||||
|
@ -9,7 +9,7 @@ import java.time.OffsetDateTime
|
||||
* @param lastAccessTime last access time
|
||||
* @param lastModifiedTime last modified time
|
||||
* @param kind type of [[FileSystemObject]], can be
|
||||
* [[FileSystemObject.DirectoryTruncated]]
|
||||
* [[FileSystemObject.SymlinkLoop]]
|
||||
* | [[FileSystemObject.File]]
|
||||
* | [[FileSystemObject.Other]]
|
||||
* @param byteSize size in bytes
|
||||
@ -28,7 +28,7 @@ object FileAttributes {
|
||||
*
|
||||
* @param root a root path
|
||||
* @param path a path to the file system object
|
||||
* @param attra file system attributes
|
||||
* @param attrs file system attributes
|
||||
* @return file attributes
|
||||
*/
|
||||
def fromFileSystemAttributes(
|
||||
|
@ -25,18 +25,15 @@ final class WatcherAdapter(
|
||||
.listener(this)
|
||||
.build()
|
||||
|
||||
/** Start watcher.
|
||||
*/
|
||||
/** Start watcher. */
|
||||
def start(): IO[Throwable, Unit] =
|
||||
IO(watcher.watch())
|
||||
|
||||
/** Stop watcher.
|
||||
*/
|
||||
/** Stop watcher. */
|
||||
def stop(): IO[Throwable, Unit] =
|
||||
IO(watcher.close())
|
||||
|
||||
/** A callback executed by `DirectoryWatcher` on file system event.
|
||||
*/
|
||||
/** A callback executed by `DirectoryWatcher` on file system event. */
|
||||
override def onEvent(event: DirectoryChangeEvent): Unit = {
|
||||
WatcherEvent
|
||||
.from(event)
|
||||
@ -50,8 +47,7 @@ final class WatcherAdapter(
|
||||
|
||||
object WatcherAdapter {
|
||||
|
||||
/** Type of a file event.
|
||||
*/
|
||||
/** Type of a file event. */
|
||||
sealed trait EventType
|
||||
|
||||
private object EventType {
|
||||
@ -70,16 +66,13 @@ object WatcherAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
/** Event type indicating file creation.
|
||||
*/
|
||||
/** Event type indicating file creation. */
|
||||
case object EventTypeCreate extends EventType
|
||||
|
||||
/** Event type indicating file modification.
|
||||
*/
|
||||
/** Event type indicating file modification. */
|
||||
case object EventTypeModify extends EventType
|
||||
|
||||
/** Event type indicating file deletion.
|
||||
*/
|
||||
/** Event type indicating file deletion. */
|
||||
case object EventTypeDelete extends EventType
|
||||
|
||||
/** Object representing file system event.
|
||||
|
@ -121,7 +121,9 @@ class BinaryWebSocketServer[A, B](
|
||||
.mapConcat[BinaryMessage] {
|
||||
case msg: TextMessage =>
|
||||
logger.warn(
|
||||
s"Received text message $msg over the data connection [$ip]"
|
||||
"Received text message [{}] over the data connection [{}].",
|
||||
msg,
|
||||
ip
|
||||
)
|
||||
Nil
|
||||
|
||||
|
@ -48,7 +48,7 @@ class InputRedirectionController(
|
||||
|
||||
private def running(liveContexts: Set[ContextData] = Set.empty): Receive = {
|
||||
case FeedStandardInput(input, isLineTerminated) =>
|
||||
log.debug(s"Feeding stdin [${input.length} bytes]")
|
||||
log.debug("Feeding stdin [{} bytes]", input.length)
|
||||
if (isLineTerminated) {
|
||||
val bytes =
|
||||
ByteString.createBuilder
|
||||
@ -68,7 +68,7 @@ class InputRedirectionController(
|
||||
context.become(running(liveContexts - ContextData(contextId, owner)))
|
||||
|
||||
case ReadBlocked =>
|
||||
log.debug("Blocked read detected")
|
||||
log.debug("Blocked read detected.")
|
||||
liveContexts foreach { case ContextData(_, owner) =>
|
||||
sessionRouter ! DeliverToJsonController(
|
||||
owner,
|
||||
|
@ -87,7 +87,11 @@ class BinaryConnectionController(
|
||||
outboundChannel ! responsePacket
|
||||
val session = BinarySession(clientId, self)
|
||||
context.system.eventStream.publish(BinarySessionInitialized(session))
|
||||
log.info(s"Data session initialized for client: $clientId [$clientIp]")
|
||||
log.info(
|
||||
"Data session initialized for client: {} [{}].",
|
||||
clientId,
|
||||
clientIp
|
||||
)
|
||||
context.become(
|
||||
connectionEndHandler(Some(session))
|
||||
orElse initialized(
|
||||
@ -111,7 +115,8 @@ class BinaryConnectionController(
|
||||
handler.forward(msg)
|
||||
} else {
|
||||
log.error(
|
||||
s"Received InboundMessage with unknown payload type: ${msg.payloadType()}"
|
||||
"Received InboundMessage with unknown payload type [{}].",
|
||||
msg.payloadType()
|
||||
)
|
||||
}
|
||||
|
||||
@ -124,7 +129,7 @@ class BinaryConnectionController(
|
||||
maybeDataSession: Option[BinarySession] = None
|
||||
): Receive = {
|
||||
case ConnectionClosed =>
|
||||
log.info(s"Connection closed [$clientIp]")
|
||||
log.info("Connection closed [{}].", clientIp)
|
||||
maybeDataSession.foreach(session =>
|
||||
context.system.eventStream.publish(BinarySessionTerminated(session))
|
||||
)
|
||||
@ -132,8 +137,9 @@ class BinaryConnectionController(
|
||||
|
||||
case ConnectionFailed(th) =>
|
||||
log.error(
|
||||
s"An error occurred during processing web socket connection [$clientIp]",
|
||||
th
|
||||
th,
|
||||
"An error occurred during processing web socket connection [{}].",
|
||||
clientIp
|
||||
)
|
||||
maybeDataSession.foreach(session =>
|
||||
context.system.eventStream.publish(BinarySessionTerminated(session))
|
||||
@ -154,7 +160,7 @@ class BinaryConnectionController(
|
||||
case EmptyPayload => ErrorFactory.createReceivedEmptyPayloadError()
|
||||
case DataCorrupted => ErrorFactory.createReceivedCorruptedDataError()
|
||||
case GenericDecodingFailure(th) =>
|
||||
log.error("Unrecognized error occurred in binary protocol", th)
|
||||
log.error(th, "Unrecognized error occurred in binary protocol.")
|
||||
ErrorFactory.createServiceError()
|
||||
}
|
||||
|
||||
|
@ -129,7 +129,7 @@ class JsonConnectionController(
|
||||
_,
|
||||
InitProtocolConnection.Params(clientId)
|
||||
) =>
|
||||
log.info("Initializing resources")
|
||||
log.info("Initializing resources.")
|
||||
mainComponent.init().pipeTo(self)
|
||||
context.become(initializing(webActor, clientId, req, sender()))
|
||||
|
||||
@ -147,7 +147,7 @@ class JsonConnectionController(
|
||||
receiver: ActorRef
|
||||
): Receive = {
|
||||
case InitializationComponent.Initialized =>
|
||||
log.info(s"RPC session initialized for client: $clientId")
|
||||
log.info("RPC session initialized for client [{}].", clientId)
|
||||
val session = JsonSession(clientId, self)
|
||||
context.system.eventStream.publish(JsonSessionInitialized(session))
|
||||
val requestHandlers = createRequestHandlers(session)
|
||||
@ -159,7 +159,7 @@ class JsonConnectionController(
|
||||
context.become(initialised(webActor, session, requestHandlers))
|
||||
|
||||
case Status.Failure(ex) =>
|
||||
log.error(ex, "Failed to initialize the resources")
|
||||
log.error(ex, "Failed to initialize the resources. {}", ex.getMessage)
|
||||
receiver ! ResponseError(Some(request.id), ResourcesInitializationError)
|
||||
context.become(connected(webActor))
|
||||
|
||||
|
@ -52,7 +52,10 @@ class AcquireCapabilityHandler(
|
||||
cancellable: Cancellable
|
||||
): Receive = {
|
||||
case RequestTimeout =>
|
||||
log.error(s"Acquiring capability for ${session.clientId} timed out")
|
||||
log.error(
|
||||
"Acquiring capability for client [{}] timed out.",
|
||||
session.clientId
|
||||
)
|
||||
replyTo ! ResponseError(Some(id), Errors.RequestTimeout)
|
||||
context.stop(self)
|
||||
|
||||
|
@ -50,7 +50,10 @@ class ReleaseCapabilityHandler(
|
||||
cancellable: Cancellable
|
||||
): Receive = {
|
||||
case RequestTimeout =>
|
||||
log.error(s"Releasing capability for ${session.clientId} timed out")
|
||||
log.error(
|
||||
"Releasing capability for client [{}] timed out.",
|
||||
session.clientId
|
||||
)
|
||||
replyTo ! ResponseError(Some(id), Errors.RequestTimeout)
|
||||
context.stop(self)
|
||||
|
||||
|
@ -51,7 +51,7 @@ class CreateHandler(
|
||||
cancellable: Cancellable
|
||||
): Receive = {
|
||||
case RequestTimeout =>
|
||||
log.error(s"Request $id timed out")
|
||||
log.error("Request [{}] timed out.", id)
|
||||
replyTo ! ResponseError(Some(id), Errors.RequestTimeout)
|
||||
context.stop(self)
|
||||
|
||||
|
@ -50,7 +50,7 @@ class DestroyHandler(
|
||||
cancellable: Cancellable
|
||||
): Receive = {
|
||||
case RequestTimeout =>
|
||||
log.error(s"Request $id timed out")
|
||||
log.error("Request [{}] timed out.", id)
|
||||
replyTo ! ResponseError(Some(id), Errors.RequestTimeout)
|
||||
context.stop(self)
|
||||
|
||||
|
@ -46,7 +46,7 @@ class PopHandler(
|
||||
cancellable: Cancellable
|
||||
): Receive = {
|
||||
case RequestTimeout =>
|
||||
log.error(s"Request $id timed out")
|
||||
log.error("Request [{}] timed out.", id)
|
||||
replyTo ! ResponseError(Some(id), Errors.RequestTimeout)
|
||||
context.stop(self)
|
||||
|
||||
|
@ -54,7 +54,7 @@ class PushHandler(
|
||||
cancellable: Cancellable
|
||||
): Receive = {
|
||||
case RequestTimeout =>
|
||||
log.error(s"Request $id timed out")
|
||||
log.error("Request [{}] timed out.", id)
|
||||
replyTo ! ResponseError(Some(id), Errors.RequestTimeout)
|
||||
context.stop(self)
|
||||
|
||||
|
@ -54,7 +54,7 @@ class RecomputeHandler(
|
||||
cancellable: Cancellable
|
||||
): Receive = {
|
||||
case RequestTimeout =>
|
||||
log.error(s"Request $id timed out")
|
||||
log.error("Request [{}] timed out.", id)
|
||||
replyTo ! ResponseError(Some(id), Errors.RequestTimeout)
|
||||
context.stop(self)
|
||||
|
||||
|
@ -9,6 +9,7 @@ import org.enso.languageserver.filemanager.{
|
||||
import org.enso.languageserver.filemanager.FileManagerApi.CopyFile
|
||||
import org.enso.languageserver.requesthandler.RequestTimeout
|
||||
import org.enso.languageserver.util.UnhandledLogging
|
||||
import org.enso.logger.masking.MaskedString
|
||||
|
||||
import scala.concurrent.duration.FiniteDuration
|
||||
|
||||
@ -35,13 +36,17 @@ class CopyFileHandler(requestTimeout: FiniteDuration, fileManager: ActorRef)
|
||||
cancellable: Cancellable
|
||||
): Receive = {
|
||||
case Status.Failure(ex) =>
|
||||
log.error(s"Failure during $CopyFile operation:", ex)
|
||||
log.error(
|
||||
"Failure during [{}] operation: {}",
|
||||
CopyFile,
|
||||
MaskedString(ex.getMessage)
|
||||
)
|
||||
replyTo ! ResponseError(Some(id), Errors.ServiceError)
|
||||
cancellable.cancel()
|
||||
context.stop(self)
|
||||
|
||||
case RequestTimeout =>
|
||||
log.error(s"Request $id timed out")
|
||||
log.error("Request [{}] timed out.", id)
|
||||
replyTo ! ResponseError(Some(id), Errors.RequestTimeout)
|
||||
context.stop(self)
|
||||
|
||||
|
@ -9,6 +9,7 @@ import org.enso.languageserver.filemanager.{
|
||||
import org.enso.languageserver.filemanager.FileManagerApi.CreateFile
|
||||
import org.enso.languageserver.requesthandler.RequestTimeout
|
||||
import org.enso.languageserver.util.UnhandledLogging
|
||||
import org.enso.logger.masking.MaskedString
|
||||
|
||||
import scala.concurrent.duration.FiniteDuration
|
||||
|
||||
@ -35,13 +36,17 @@ class CreateFileHandler(requestTimeout: FiniteDuration, fileManager: ActorRef)
|
||||
cancellable: Cancellable
|
||||
): Receive = {
|
||||
case Status.Failure(ex) =>
|
||||
log.error(s"Failure during $CreateFile operation:", ex)
|
||||
log.error(
|
||||
"Failure during [{}] operation: {}",
|
||||
CreateFile,
|
||||
MaskedString(ex.getMessage)
|
||||
)
|
||||
replyTo ! ResponseError(Some(id), Errors.ServiceError)
|
||||
cancellable.cancel()
|
||||
context.stop(self)
|
||||
|
||||
case RequestTimeout =>
|
||||
log.error(s"Request $id timed out")
|
||||
log.error("Request [{}] timed out.", id)
|
||||
replyTo ! ResponseError(Some(id), Errors.RequestTimeout)
|
||||
context.stop(self)
|
||||
|
||||
|
@ -11,6 +11,7 @@ import org.enso.languageserver.filemanager.{
|
||||
import org.enso.languageserver.filemanager.FileManagerApi.DeleteFile
|
||||
import org.enso.languageserver.requesthandler.RequestTimeout
|
||||
import org.enso.languageserver.util.UnhandledLogging
|
||||
import org.enso.logger.masking.MaskedString
|
||||
|
||||
import scala.concurrent.duration.FiniteDuration
|
||||
|
||||
@ -38,13 +39,17 @@ class DeleteFileHandler(requestTimeout: FiniteDuration, fileManager: ActorRef)
|
||||
path: Path
|
||||
): Receive = {
|
||||
case Status.Failure(ex) =>
|
||||
log.error(s"Failure during $DeleteFile operation:", ex)
|
||||
log.error(
|
||||
"Failure during [{}] operation: {}",
|
||||
DeleteFile,
|
||||
MaskedString(ex.getMessage)
|
||||
)
|
||||
replyTo ! ResponseError(Some(id), Errors.ServiceError)
|
||||
cancellable.cancel()
|
||||
context.stop(self)
|
||||
|
||||
case RequestTimeout =>
|
||||
log.error(s"Request $id timed out")
|
||||
log.error("Request [{}] timed out.", id)
|
||||
replyTo ! ResponseError(Some(id), Errors.RequestTimeout)
|
||||
context.stop(self)
|
||||
|
||||
|
@ -9,6 +9,7 @@ import org.enso.languageserver.filemanager.{
|
||||
import org.enso.languageserver.filemanager.FileManagerApi.ExistsFile
|
||||
import org.enso.languageserver.requesthandler.RequestTimeout
|
||||
import org.enso.languageserver.util.UnhandledLogging
|
||||
import org.enso.logger.masking.MaskedString
|
||||
|
||||
import scala.concurrent.duration.FiniteDuration
|
||||
|
||||
@ -35,13 +36,17 @@ class ExistsFileHandler(requestTimeout: FiniteDuration, fileManager: ActorRef)
|
||||
cancellable: Cancellable
|
||||
): Receive = {
|
||||
case Status.Failure(ex) =>
|
||||
log.error(s"Failure during $ExistsFile operation:", ex)
|
||||
log.error(
|
||||
"Failure during [{}] operation: {}",
|
||||
ExistsFile,
|
||||
MaskedString(ex.getMessage)
|
||||
)
|
||||
replyTo ! ResponseError(Some(id), Errors.ServiceError)
|
||||
cancellable.cancel()
|
||||
context.stop(self)
|
||||
|
||||
case RequestTimeout =>
|
||||
log.error(s"Request $id timed out")
|
||||
log.error("Request [{}] timed out.", id)
|
||||
replyTo ! ResponseError(Some(id), Errors.RequestTimeout)
|
||||
context.stop(self)
|
||||
|
||||
|
@ -9,6 +9,7 @@ import org.enso.languageserver.filemanager.{
|
||||
import org.enso.languageserver.filemanager.FileManagerApi.InfoFile
|
||||
import org.enso.languageserver.requesthandler.RequestTimeout
|
||||
import org.enso.languageserver.util.UnhandledLogging
|
||||
import org.enso.logger.masking.MaskedString
|
||||
|
||||
import scala.concurrent.duration.FiniteDuration
|
||||
|
||||
@ -40,13 +41,17 @@ class InfoFileHandler(requestTimeout: FiniteDuration, fileManager: ActorRef)
|
||||
cancellable: Cancellable
|
||||
): Receive = {
|
||||
case Status.Failure(ex) =>
|
||||
log.error(s"Failure during $InfoFile operation:", ex)
|
||||
log.error(
|
||||
"Failure during [{}] operation: {}",
|
||||
InfoFile,
|
||||
MaskedString(ex.getMessage)
|
||||
)
|
||||
replyTo ! ResponseError(Some(id), Errors.ServiceError)
|
||||
cancellable.cancel()
|
||||
context.stop(self)
|
||||
|
||||
case RequestTimeout =>
|
||||
log.error(s"Request $id timed out")
|
||||
log.error("Request [{}] timed out.", id)
|
||||
replyTo ! ResponseError(Some(id), Errors.RequestTimeout)
|
||||
context.stop(self)
|
||||
|
||||
|
@ -9,6 +9,7 @@ import org.enso.languageserver.filemanager.{
|
||||
import org.enso.languageserver.filemanager.FileManagerApi.ListFile
|
||||
import org.enso.languageserver.requesthandler.RequestTimeout
|
||||
import org.enso.languageserver.util.UnhandledLogging
|
||||
import org.enso.logger.masking.MaskedString
|
||||
|
||||
import scala.concurrent.duration.FiniteDuration
|
||||
|
||||
@ -35,13 +36,17 @@ class ListFileHandler(requestTimeout: FiniteDuration, fileManager: ActorRef)
|
||||
cancellable: Cancellable
|
||||
): Receive = {
|
||||
case Status.Failure(ex) =>
|
||||
log.error(s"Failure during $ListFile operation:", ex)
|
||||
log.error(
|
||||
"Failure during [{}] operation: {}",
|
||||
ListFile,
|
||||
MaskedString(ex.getMessage)
|
||||
)
|
||||
replyTo ! ResponseError(Some(id), Errors.ServiceError)
|
||||
cancellable.cancel()
|
||||
context.stop(self)
|
||||
|
||||
case RequestTimeout =>
|
||||
log.error(s"Request $id timed out")
|
||||
log.error("Request [{}] timed out.", id)
|
||||
replyTo ! ResponseError(Some(id), Errors.RequestTimeout)
|
||||
context.stop(self)
|
||||
|
||||
|
@ -9,6 +9,7 @@ import org.enso.languageserver.filemanager.{
|
||||
import org.enso.languageserver.filemanager.FileManagerApi.MoveFile
|
||||
import org.enso.languageserver.requesthandler.RequestTimeout
|
||||
import org.enso.languageserver.util.UnhandledLogging
|
||||
import org.enso.logger.masking.MaskedString
|
||||
|
||||
import scala.concurrent.duration.FiniteDuration
|
||||
|
||||
@ -35,13 +36,17 @@ class MoveFileHandler(requestTimeout: FiniteDuration, fileManager: ActorRef)
|
||||
cancellable: Cancellable
|
||||
): Receive = {
|
||||
case Status.Failure(ex) =>
|
||||
log.error(s"Failure during $MoveFile operation:", ex)
|
||||
log.error(
|
||||
"Failure during [{}] operation: {}",
|
||||
MoveFile,
|
||||
MaskedString(ex.getMessage)
|
||||
)
|
||||
replyTo ! ResponseError(Some(id), Errors.ServiceError)
|
||||
cancellable.cancel()
|
||||
context.stop(self)
|
||||
|
||||
case RequestTimeout =>
|
||||
log.error(s"Request $id timed out")
|
||||
log.error("Request [{}] timed out.", id)
|
||||
replyTo ! ResponseError(Some(id), Errors.RequestTimeout)
|
||||
context.stop(self)
|
||||
|
||||
|
@ -17,6 +17,7 @@ import org.enso.languageserver.protocol.binary.factory.{
|
||||
import org.enso.languageserver.requesthandler.RequestTimeout
|
||||
import org.enso.languageserver.util.UnhandledLogging
|
||||
import org.enso.languageserver.util.file.PathUtils
|
||||
import org.enso.logger.masking.MaskedString
|
||||
|
||||
import scala.concurrent.duration.FiniteDuration
|
||||
|
||||
@ -53,14 +54,17 @@ class ReadBinaryFileHandler(
|
||||
cancellable: Cancellable
|
||||
): Receive = {
|
||||
case Status.Failure(ex) =>
|
||||
log.error(s"Failure during ReadBinaryFile operation:", ex)
|
||||
log.error(
|
||||
s"Failure during ReadBinaryFile operation: {}",
|
||||
MaskedString(ex.getMessage)
|
||||
)
|
||||
val packet = ErrorFactory.createServiceError(Some(requestId))
|
||||
replyTo ! packet
|
||||
cancellable.cancel()
|
||||
context.stop(self)
|
||||
|
||||
case RequestTimeout =>
|
||||
log.error(s"Request ReadBinaryFile timed out")
|
||||
log.error("Request ReadBinaryFile [{}] timed out.", requestId)
|
||||
val packet = ErrorFactory.createServiceError(Some(requestId))
|
||||
replyTo ! packet
|
||||
context.stop(self)
|
||||
|
@ -9,6 +9,7 @@ import org.enso.languageserver.filemanager.{
|
||||
import org.enso.languageserver.filemanager.FileManagerApi.ReadFile
|
||||
import org.enso.languageserver.requesthandler.RequestTimeout
|
||||
import org.enso.languageserver.util.UnhandledLogging
|
||||
import org.enso.logger.masking.MaskedString
|
||||
|
||||
import scala.concurrent.duration.FiniteDuration
|
||||
|
||||
@ -37,13 +38,17 @@ class ReadTextualFileHandler(
|
||||
cancellable: Cancellable
|
||||
): Receive = {
|
||||
case Status.Failure(ex) =>
|
||||
log.error(s"Failure during $ReadFile operation:", ex)
|
||||
log.error(
|
||||
"Failure during [{}] operation: {}",
|
||||
ReadFile,
|
||||
MaskedString(ex.getMessage)
|
||||
)
|
||||
replyTo ! ResponseError(Some(id), Errors.ServiceError)
|
||||
cancellable.cancel()
|
||||
context.stop(self)
|
||||
|
||||
case RequestTimeout =>
|
||||
log.error(s"Request $id timed out")
|
||||
log.error("Request [{}] timed out.", id)
|
||||
replyTo ! ResponseError(Some(id), Errors.RequestTimeout)
|
||||
context.stop(self)
|
||||
|
||||
|
@ -9,6 +9,7 @@ import org.enso.languageserver.filemanager.{
|
||||
import org.enso.languageserver.filemanager.FileManagerApi.TreeFile
|
||||
import org.enso.languageserver.requesthandler.RequestTimeout
|
||||
import org.enso.languageserver.util.UnhandledLogging
|
||||
import org.enso.logger.masking.MaskedString
|
||||
|
||||
import scala.concurrent.duration.FiniteDuration
|
||||
|
||||
@ -35,13 +36,17 @@ class TreeFileHandler(requestTimeout: FiniteDuration, fileManager: ActorRef)
|
||||
cancellable: Cancellable
|
||||
): Receive = {
|
||||
case Status.Failure(ex) =>
|
||||
log.error(s"Failure during $TreeFile operation:", ex)
|
||||
log.error(
|
||||
"Failure during [{}] operation: {}",
|
||||
TreeFile,
|
||||
MaskedString(ex.getMessage)
|
||||
)
|
||||
replyTo ! ResponseError(Some(id), Errors.ServiceError)
|
||||
cancellable.cancel()
|
||||
context.stop(self)
|
||||
|
||||
case RequestTimeout =>
|
||||
log.error(s"Request $id timed out")
|
||||
log.error("Request [{}] timed out.", id)
|
||||
replyTo ! ResponseError(Some(id), Errors.RequestTimeout)
|
||||
context.stop(self)
|
||||
|
||||
|
@ -17,6 +17,7 @@ import org.enso.languageserver.protocol.binary.factory.{
|
||||
import org.enso.languageserver.requesthandler.RequestTimeout
|
||||
import org.enso.languageserver.util.UnhandledLogging
|
||||
import org.enso.languageserver.util.file.PathUtils
|
||||
import org.enso.logger.masking.MaskedString
|
||||
|
||||
import scala.concurrent.duration.FiniteDuration
|
||||
|
||||
@ -56,14 +57,17 @@ class WriteBinaryFileHandler(
|
||||
cancellable: Cancellable
|
||||
): Receive = {
|
||||
case Status.Failure(ex) =>
|
||||
log.error(s"Failure during WriteBinaryFile operation:", ex)
|
||||
log.error(
|
||||
"Failure during WriteBinaryFile operation: {}",
|
||||
MaskedString(ex.getMessage)
|
||||
)
|
||||
val packet = ErrorFactory.createServiceError(Some(requestId))
|
||||
replyTo ! packet
|
||||
cancellable.cancel()
|
||||
context.stop(self)
|
||||
|
||||
case RequestTimeout =>
|
||||
log.error(s"Request WriteBinaryFile timed out")
|
||||
log.error("Request WriteBinaryFile [{}] timed out.", requestId)
|
||||
val packet = ErrorFactory.createServiceError(Some(requestId))
|
||||
replyTo ! packet
|
||||
context.stop(self)
|
||||
|
@ -9,6 +9,7 @@ import org.enso.languageserver.filemanager.{
|
||||
import org.enso.languageserver.filemanager.FileManagerApi.WriteFile
|
||||
import org.enso.languageserver.requesthandler.RequestTimeout
|
||||
import org.enso.languageserver.util.UnhandledLogging
|
||||
import org.enso.logger.masking.MaskedString
|
||||
|
||||
import scala.concurrent.duration.FiniteDuration
|
||||
|
||||
@ -37,13 +38,17 @@ class WriteTextualFileHandler(
|
||||
cancellable: Cancellable
|
||||
): Receive = {
|
||||
case Status.Failure(ex) =>
|
||||
log.error(s"Failure during $WriteFile operation:", ex)
|
||||
log.error(
|
||||
s"Failure during [{}] operation: {}",
|
||||
WriteFile,
|
||||
MaskedString(ex.getMessage)
|
||||
)
|
||||
replyTo ! ResponseError(Some(id), Errors.ServiceError)
|
||||
cancellable.cancel()
|
||||
context.stop(self)
|
||||
|
||||
case RequestTimeout =>
|
||||
log.error(s"Request $id timed out")
|
||||
log.error("Request [{}] timed out.", id)
|
||||
replyTo ! ResponseError(Some(id), Errors.ServiceError)
|
||||
context.stop(self)
|
||||
|
||||
|
@ -49,7 +49,9 @@ class PingHandler(
|
||||
): Receive = {
|
||||
case RequestTimeout =>
|
||||
log.error(
|
||||
s"Health check timed out. Only $count/${subsystems.size} subsystems replied on time."
|
||||
"Health check timed out. Only {}/{} subsystems replied on time.",
|
||||
count,
|
||||
subsystems.size
|
||||
)
|
||||
if (shouldReplyWhenTimedOut) {
|
||||
replyTo ! ResponseError(Some(id), Errors.RequestTimeout)
|
||||
|
@ -49,7 +49,7 @@ class RenameProjectHandler(timeout: FiniteDuration, runtimeConnector: ActorRef)
|
||||
cancellable: Cancellable
|
||||
): Receive = {
|
||||
case RequestTimeout =>
|
||||
log.error(s"Request $id timed out")
|
||||
log.error("Request [{}] timed out.", id)
|
||||
replyTo ! ResponseError(Some(id), Errors.RequestTimeout)
|
||||
context.stop(self)
|
||||
|
||||
|
@ -52,13 +52,13 @@ class CompletionHandler(
|
||||
cancellable: Cancellable
|
||||
): Receive = {
|
||||
case Status.Failure(ex) =>
|
||||
log.error(ex, "Search completion error")
|
||||
log.error(ex, "Search completion error: {}", ex.getMessage)
|
||||
replyTo ! ResponseError(Some(id), SuggestionsDatabaseError)
|
||||
cancellable.cancel()
|
||||
context.stop(self)
|
||||
|
||||
case RequestTimeout =>
|
||||
log.error(s"Request $id timed out")
|
||||
log.error("Request [{}] timed out.", id)
|
||||
replyTo ! ResponseError(Some(id), Errors.RequestTimeout)
|
||||
context.stop(self)
|
||||
|
||||
|
@ -42,13 +42,13 @@ class GetSuggestionsDatabaseHandler(
|
||||
cancellable: Cancellable
|
||||
): Receive = {
|
||||
case Status.Failure(ex) =>
|
||||
log.error(ex, "GetSuggestionsDatabase error")
|
||||
log.error(ex, "GetSuggestionsDatabase error: {}", ex.getMessage)
|
||||
replyTo ! ResponseError(Some(id), SuggestionsDatabaseError)
|
||||
cancellable.cancel()
|
||||
context.stop(self)
|
||||
|
||||
case RequestTimeout =>
|
||||
log.error(s"Request $id timed out")
|
||||
log.error("Request [{}] timed out.", id)
|
||||
replyTo ! ResponseError(Some(id), Errors.RequestTimeout)
|
||||
context.stop(self)
|
||||
|
||||
|
@ -42,13 +42,13 @@ class GetSuggestionsDatabaseVersionHandler(
|
||||
cancellable: Cancellable
|
||||
): Receive = {
|
||||
case Status.Failure(ex) =>
|
||||
log.error(ex, "GetSuggestionsDatabaseVersion error")
|
||||
log.error(ex, "GetSuggestionsDatabaseVersion error: {}", ex.getMessage)
|
||||
replyTo ! ResponseError(Some(id), SuggestionsDatabaseError)
|
||||
cancellable.cancel()
|
||||
context.stop(self)
|
||||
|
||||
case RequestTimeout =>
|
||||
log.error(s"Request $id timed out")
|
||||
log.error("Request [{}] timed out.", id)
|
||||
replyTo ! ResponseError(Some(id), Errors.RequestTimeout)
|
||||
context.stop(self)
|
||||
|
||||
|
@ -42,13 +42,13 @@ class ImportHandler(
|
||||
cancellable: Cancellable
|
||||
): Receive = {
|
||||
case Status.Failure(ex) =>
|
||||
log.error(ex, "Search import error")
|
||||
log.error(ex, "Search import error: {}", ex.getMessage)
|
||||
replyTo ! ResponseError(Some(id), SuggestionsDatabaseError)
|
||||
cancellable.cancel()
|
||||
context.stop(self)
|
||||
|
||||
case RequestTimeout =>
|
||||
log.error(s"Request $id timed out")
|
||||
log.error("Request [{}] timed out.", id)
|
||||
replyTo ! ResponseError(Some(id), Errors.RequestTimeout)
|
||||
context.stop(self)
|
||||
|
||||
|
@ -46,13 +46,13 @@ class InvalidateSuggestionsDatabaseHandler(
|
||||
cancellable: Cancellable
|
||||
): Receive = {
|
||||
case Status.Failure(ex) =>
|
||||
log.error(ex, "InvalidateSuggestionsDatabase error")
|
||||
log.error(ex, "InvalidateSuggestionsDatabase error: {}", ex.getMessage)
|
||||
replyTo ! ResponseError(Some(id), SuggestionsDatabaseError)
|
||||
cancellable.cancel()
|
||||
context.stop(self)
|
||||
|
||||
case RequestTimeout =>
|
||||
log.error(s"Request $id timed out")
|
||||
log.error("Request [{}] timed out.", id)
|
||||
replyTo ! ResponseError(Some(id), Errors.RequestTimeout)
|
||||
context.stop(self)
|
||||
|
||||
|
@ -40,7 +40,7 @@ class InitProtocolConnectionHandler(
|
||||
cancellable: Cancellable
|
||||
): Receive = {
|
||||
case RequestTimeout =>
|
||||
log.error(s"Getting content roots timed out")
|
||||
log.error("Getting content roots request [{}] timed out.", id)
|
||||
replyTo ! ResponseError(Some(id), Errors.RequestTimeout)
|
||||
context.stop(self)
|
||||
|
||||
|
@ -43,7 +43,11 @@ class ApplyEditHandler(
|
||||
cancellable: Cancellable
|
||||
): Receive = {
|
||||
case RequestTimeout =>
|
||||
log.error(s"Applying edit for ${rpcSession.clientId} timed out")
|
||||
log.error(
|
||||
"Applying edit request [{}] for [{}] timed out.",
|
||||
id,
|
||||
rpcSession.clientId
|
||||
)
|
||||
replyTo ! ResponseError(Some(id), Errors.RequestTimeout)
|
||||
context.stop(self)
|
||||
|
||||
|
@ -43,7 +43,11 @@ class CloseFileHandler(
|
||||
cancellable: Cancellable
|
||||
): Receive = {
|
||||
case RequestTimeout =>
|
||||
log.error(s"Closing file for ${rpcSession.clientId} timed out")
|
||||
log.error(
|
||||
"Closing file request [{}] for [{}] timed out.",
|
||||
id,
|
||||
rpcSession.clientId
|
||||
)
|
||||
replyTo ! ResponseError(Some(id), Errors.RequestTimeout)
|
||||
context.stop(self)
|
||||
|
||||
|
@ -47,7 +47,11 @@ class OpenFileHandler(
|
||||
cancellable: Cancellable
|
||||
): Receive = {
|
||||
case RequestTimeout =>
|
||||
log.error(s"Opening file for ${rpcSession.clientId} timed out")
|
||||
log.error(
|
||||
"Opening file request [{}] for [{}] timed out.",
|
||||
id,
|
||||
rpcSession.clientId
|
||||
)
|
||||
replyTo ! ResponseError(Some(id), Errors.RequestTimeout)
|
||||
context.stop(self)
|
||||
|
||||
|
@ -53,7 +53,11 @@ class SaveFileHandler(
|
||||
cancellable: Cancellable
|
||||
): Receive = {
|
||||
case RequestTimeout =>
|
||||
log.error(s"Saving file for ${rpcSession.clientId} timed out")
|
||||
log.error(
|
||||
"Saving file request [{}] for [{}] timed out.",
|
||||
id,
|
||||
rpcSession.clientId
|
||||
)
|
||||
replyTo ! ResponseError(Some(id), Errors.RequestTimeout)
|
||||
context.stop(self)
|
||||
|
||||
|
@ -50,7 +50,7 @@ class AttachVisualisationHandler(
|
||||
cancellable: Cancellable
|
||||
): Receive = {
|
||||
case RequestTimeout =>
|
||||
log.error(s"Request $id timed out")
|
||||
log.error("Request [{}] timed out.", id)
|
||||
replyTo ! ResponseError(Some(id), Errors.RequestTimeout)
|
||||
context.stop(self)
|
||||
|
||||
|
@ -50,7 +50,7 @@ class DetachVisualisationHandler(
|
||||
cancellable: Cancellable
|
||||
): Receive = {
|
||||
case RequestTimeout =>
|
||||
log.error(s"Request $id timed out")
|
||||
log.error("Request [{}] timed out.", id)
|
||||
replyTo ! ResponseError(Some(id), Errors.RequestTimeout)
|
||||
context.stop(self)
|
||||
|
||||
|
@ -49,7 +49,7 @@ class ModifyVisualisationHandler(
|
||||
cancellable: Cancellable
|
||||
): Receive = {
|
||||
case RequestTimeout =>
|
||||
log.error(s"Request $id timed out")
|
||||
log.error("Request [{}] timed out.", id)
|
||||
replyTo ! ResponseError(Some(id), Errors.RequestTimeout)
|
||||
context.stop(self)
|
||||
|
||||
|
@ -157,7 +157,7 @@ final class ContextEventsListener(
|
||||
methodPointerToSuggestion.get(pointer) match {
|
||||
case suggestionId @ Some(_) => suggestionId
|
||||
case None =>
|
||||
log.error(s"Unable to find suggestion for $pointer")
|
||||
log.error("Unable to find suggestion for [{}].", pointer)
|
||||
None
|
||||
}
|
||||
},
|
||||
|
@ -23,8 +23,8 @@ class RuntimeConnector
|
||||
override def receive: Receive = {
|
||||
case RuntimeConnector.Initialize(engine) =>
|
||||
log.info(
|
||||
s"Runtime connector established connection with the message endpoint " +
|
||||
s"$engine."
|
||||
s"Runtime connector established connection with the message endpoint [{}].",
|
||||
engine
|
||||
)
|
||||
unstashAll()
|
||||
context.become(initialized(engine, Map()))
|
||||
|
@ -62,8 +62,10 @@ class RuntimeKiller(runtimeConnector: ActorRef, truffleContext: Context)
|
||||
private def shutDownTruffle(replyTo: ActorRef, retryCount: Int = 0): Unit = {
|
||||
try {
|
||||
log.info(
|
||||
s"Shutting down the Truffle context $truffleContext. " +
|
||||
s"Attempt #${retryCount + 1}."
|
||||
"Shutting down the Truffle context [{}]. " +
|
||||
"Attempt #{}.",
|
||||
truffleContext,
|
||||
retryCount + 1
|
||||
)
|
||||
truffleContext.close()
|
||||
replyTo ! RuntimeGracefullyStopped
|
||||
@ -72,8 +74,9 @@ class RuntimeKiller(runtimeConnector: ActorRef, truffleContext: Context)
|
||||
case NonFatal(ex) =>
|
||||
log.error(
|
||||
ex,
|
||||
s"An error occurred during stopping Truffle context " +
|
||||
s"$truffleContext. ${ex.getMessage}"
|
||||
s"An error occurred during stopping Truffle context [{}]. {}",
|
||||
truffleContext,
|
||||
ex.getMessage
|
||||
)
|
||||
if (retryCount < MaxRetries) {
|
||||
context.system.scheduler
|
||||
|
@ -26,6 +26,7 @@ import org.enso.languageserver.search.handler.{
|
||||
}
|
||||
import org.enso.languageserver.session.SessionRouter.DeliverToJsonController
|
||||
import org.enso.languageserver.util.UnhandledLogging
|
||||
import org.enso.logger.masking.MaskedPath
|
||||
import org.enso.pkg.PackageManager
|
||||
import org.enso.polyglot.Suggestion
|
||||
import org.enso.polyglot.data.TypeGraph
|
||||
@ -93,9 +94,10 @@ final class SuggestionsHandler(
|
||||
|
||||
override def preStart(): Unit = {
|
||||
log.info(
|
||||
s"Starting suggestions handler from $config " +
|
||||
s"$suggestionsRepo $fileVersionsRepo " +
|
||||
s"$sessionRouter $runtimeConnector"
|
||||
"Starting suggestions handler from [{}, {}, {}].",
|
||||
config,
|
||||
suggestionsRepo,
|
||||
fileVersionsRepo
|
||||
)
|
||||
context.system.eventStream
|
||||
.subscribe(self, classOf[Api.ExpressionUpdates])
|
||||
@ -120,19 +122,23 @@ final class SuggestionsHandler(
|
||||
|
||||
def initializing(init: SuggestionsHandler.Initialization): Receive = {
|
||||
case ProjectNameChangedEvent(oldName, newName) =>
|
||||
log.info(s"Initializing: project name changed from $oldName to $newName.")
|
||||
log.info(
|
||||
"Initializing: project name changed from [{}] to [{}].",
|
||||
oldName,
|
||||
newName
|
||||
)
|
||||
suggestionsRepo
|
||||
.renameProject(oldName, newName)
|
||||
.map(_ => ProjectNameUpdated(newName))
|
||||
.pipeTo(self)
|
||||
|
||||
case ProjectNameUpdated(name, updates) =>
|
||||
log.info(s"Initializing: project name is updated to $name.")
|
||||
log.info("Initializing: project name is updated to [{}].", name)
|
||||
updates.foreach(sessionRouter ! _)
|
||||
tryInitialize(init.copy(project = Some(name)))
|
||||
|
||||
case InitializedEvent.SuggestionsRepoInitialized =>
|
||||
log.info(s"Initializing: suggestions repo initialized.")
|
||||
log.info("Initializing: suggestions repo initialized.")
|
||||
tryInitialize(
|
||||
init.copy(suggestions =
|
||||
Some(InitializedEvent.SuggestionsRepoInitialized)
|
||||
@ -140,14 +146,14 @@ final class SuggestionsHandler(
|
||||
)
|
||||
|
||||
case InitializedEvent.TruffleContextInitialized =>
|
||||
log.info(s"Initializing: Truffle context initialized.")
|
||||
log.info("Initializing: Truffle context initialized.")
|
||||
val requestId = UUID.randomUUID()
|
||||
runtimeConnector
|
||||
.ask(Api.Request(requestId, Api.GetTypeGraphRequest()))(timeout, self)
|
||||
.pipeTo(self)
|
||||
|
||||
case Api.Response(_, Api.GetTypeGraphResponse(g)) =>
|
||||
log.info(s"Initializing: got type graph response.")
|
||||
log.info("Initializing: got type graph response.")
|
||||
tryInitialize(init.copy(typeGraph = Some(g)))
|
||||
|
||||
case _ => stash()
|
||||
@ -158,14 +164,14 @@ final class SuggestionsHandler(
|
||||
graph: TypeGraph
|
||||
): Receive = {
|
||||
case Api.Response(_, Api.VerifyModulesIndexResponse(toRemove)) =>
|
||||
log.info(s"Verifying: got verification response.")
|
||||
log.info("Verifying: got verification response.")
|
||||
suggestionsRepo
|
||||
.removeModules(toRemove)
|
||||
.map(_ => SuggestionsHandler.Verified)
|
||||
.pipeTo(self)
|
||||
|
||||
case SuggestionsHandler.Verified =>
|
||||
log.info(s"Verified.")
|
||||
log.info("Verified.")
|
||||
context.become(initialized(projectName, graph, Set()))
|
||||
unstashAll()
|
||||
|
||||
@ -213,15 +219,18 @@ final class SuggestionsHandler(
|
||||
case Success(None) =>
|
||||
case Failure(ex) =>
|
||||
log.error(
|
||||
s"Error applying suggestion database updates" +
|
||||
s" ${msg.file} ${msg.version}. ${ex.getMessage}"
|
||||
ex,
|
||||
"Error applying suggestion database updates [{}, {}]. {}",
|
||||
MaskedPath(msg.file.toPath),
|
||||
msg.version,
|
||||
ex.getMessage
|
||||
)
|
||||
}
|
||||
|
||||
case Api.ExpressionUpdates(_, updates) =>
|
||||
log.debug(
|
||||
s"Received expression updates: " +
|
||||
s"${updates.map(u => (u.expressionId, u.expressionType))}"
|
||||
"Received expression updates [{}].",
|
||||
updates.map(u => (u.expressionId, u.expressionType))
|
||||
)
|
||||
val types = updates.toSeq
|
||||
.flatMap(update => update.expressionType.map(update.expressionId -> _))
|
||||
@ -246,8 +255,10 @@ final class SuggestionsHandler(
|
||||
}
|
||||
case Failure(ex) =>
|
||||
log.error(
|
||||
s"Error applying changes from computed values: $updates. " +
|
||||
s"${ex.getMessage}"
|
||||
ex,
|
||||
"Error applying changes from computed values [{}]. {}",
|
||||
updates.map(_.expressionId),
|
||||
ex.getMessage
|
||||
)
|
||||
}
|
||||
|
||||
@ -320,13 +331,14 @@ final class SuggestionsHandler(
|
||||
}
|
||||
case Success(Left(err)) =>
|
||||
log.error(
|
||||
s"Error cleaning the index after file delete event. " +
|
||||
s"$err"
|
||||
s"Error cleaning the index after file delete event [{}].",
|
||||
err
|
||||
)
|
||||
case Failure(ex) =>
|
||||
log.error(
|
||||
s"Error cleaning the index after file delete event. " +
|
||||
s"${ex.getMessage}"
|
||||
ex,
|
||||
"Error cleaning the index after file delete event. {}",
|
||||
ex.getMessage
|
||||
)
|
||||
}
|
||||
|
||||
@ -403,7 +415,7 @@ final class SuggestionsHandler(
|
||||
private def tryInitialize(state: SuggestionsHandler.Initialization): Unit = {
|
||||
state.initialized.fold(context.become(initializing(state))) {
|
||||
case (name, graph) =>
|
||||
log.debug(s"Initialized with state $state.")
|
||||
log.debug("Initialized with state [{}].", state)
|
||||
val requestId = UUID.randomUUID()
|
||||
suggestionsRepo.getAllModules
|
||||
.flatMap { modules =>
|
||||
@ -442,10 +454,12 @@ final class SuggestionsHandler(
|
||||
val verb = action.getClass.getSimpleName
|
||||
action match {
|
||||
case Api.SuggestionAction.Add() =>
|
||||
if (ids.isEmpty) log.error(s"Failed to $verb: $suggestion")
|
||||
if (ids.isEmpty)
|
||||
log.error("Failed to {} [{}].", verb, suggestion)
|
||||
ids.map(id => SuggestionsDatabaseUpdate.Add(id, suggestion))
|
||||
case Api.SuggestionAction.Remove() =>
|
||||
if (ids.isEmpty) log.error(s"Failed to $verb: $suggestion")
|
||||
if (ids.isEmpty)
|
||||
log.error(s"Failed to {} [{}].", verb, suggestion)
|
||||
ids.map(id => SuggestionsDatabaseUpdate.Remove(id))
|
||||
case m: Api.SuggestionAction.Modify =>
|
||||
ids.map { id =>
|
||||
|
@ -67,7 +67,7 @@ class CollaborativeBuffer(
|
||||
|
||||
private def uninitialized: Receive = { case OpenFile(client, path) =>
|
||||
context.system.eventStream.publish(BufferOpened(path))
|
||||
log.info(s"Buffer opened for $path [client:${client.clientId}]")
|
||||
log.info("Buffer opened for [path:{}, client:{}].", path, client.clientId)
|
||||
readFile(client, path)
|
||||
}
|
||||
|
||||
|
@ -35,6 +35,7 @@ import org.enso.version.{VersionDescription, VersionDescriptionParameter}
|
||||
* @param cliOptions the global CLI options to use for the commands
|
||||
*/
|
||||
case class Launcher(cliOptions: GlobalCLIOptions) {
|
||||
|
||||
private val logger = Logger[Launcher]
|
||||
|
||||
private lazy val componentsManager =
|
||||
@ -89,9 +90,6 @@ case class Launcher(cliOptions: GlobalCLIOptions) {
|
||||
.get,
|
||||
JVMSettings(useSystemJVM, jvmOpts)
|
||||
) { command =>
|
||||
logger.trace(
|
||||
s"Executing a command that creates a new project: $command"
|
||||
)
|
||||
command.run().get
|
||||
}
|
||||
|
||||
@ -209,11 +207,16 @@ case class Launcher(cliOptions: GlobalCLIOptions) {
|
||||
val exitCode = runner
|
||||
.withCommand(
|
||||
runner
|
||||
.repl(projectPath, versionOverride, logLevel, additionalArguments)
|
||||
.repl(
|
||||
projectPath,
|
||||
versionOverride,
|
||||
logLevel,
|
||||
cliOptions.internalOptions.logMasking,
|
||||
additionalArguments
|
||||
)
|
||||
.get,
|
||||
JVMSettings(useSystemJVM, jvmOpts)
|
||||
) { command =>
|
||||
logger.trace(s"Executing a command that starts the REPL: $command")
|
||||
command.run().get
|
||||
}
|
||||
exitCode
|
||||
@ -247,12 +250,17 @@ case class Launcher(cliOptions: GlobalCLIOptions) {
|
||||
): Int = {
|
||||
val exitCode = runner
|
||||
.withCommand(
|
||||
runner.run(path, versionOverride, logLevel, additionalArguments).get,
|
||||
runner
|
||||
.run(
|
||||
path,
|
||||
versionOverride,
|
||||
logLevel,
|
||||
cliOptions.internalOptions.logMasking,
|
||||
additionalArguments
|
||||
)
|
||||
.get,
|
||||
JVMSettings(useSystemJVM, jvmOpts)
|
||||
) { command =>
|
||||
logger.trace(
|
||||
s"Executing a command that runs the Enso program: $command"
|
||||
)
|
||||
command.run().get
|
||||
}
|
||||
exitCode
|
||||
@ -295,9 +303,6 @@ case class Launcher(cliOptions: GlobalCLIOptions) {
|
||||
.get,
|
||||
JVMSettings(useSystemJVM, jvmOpts)
|
||||
) { command =>
|
||||
logger.trace(
|
||||
s"Executing a command that starts the Language Server: $command"
|
||||
)
|
||||
command.run().get
|
||||
}
|
||||
exitCode
|
||||
@ -441,10 +446,6 @@ case class Launcher(cliOptions: GlobalCLIOptions) {
|
||||
runtimeVersionRunSettings,
|
||||
JVMSettings(useSystemJVM = false, jvmOptions = Seq.empty)
|
||||
) { runtimeVersionCommand =>
|
||||
logger.trace(
|
||||
s"Executing a command that gets the runtime version: " +
|
||||
s"$runtimeVersionCommand"
|
||||
)
|
||||
runtimeVersionCommand.captureOutput().get
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@ case class GlobalCLIOptions(
|
||||
hideProgress: Boolean,
|
||||
useJSON: Boolean,
|
||||
colorMode: ColorMode,
|
||||
internalOptions: InternalOptions = InternalOptions(None, None)
|
||||
internalOptions: InternalOptions
|
||||
)
|
||||
|
||||
object GlobalCLIOptions {
|
||||
@ -38,9 +38,13 @@ object GlobalCLIOptions {
|
||||
*/
|
||||
case class InternalOptions(
|
||||
launcherLogLevel: Option[LogLevel],
|
||||
loggerConnectUri: Option[Uri]
|
||||
loggerConnectUri: Option[Uri],
|
||||
logMaskingDisabled: Boolean
|
||||
) {
|
||||
|
||||
/** @return `true` if log masking is enabled. */
|
||||
def logMasking: Boolean = !logMaskingDisabled
|
||||
|
||||
/** Creates command line options that can be passed to a launcher process to
|
||||
* set the same options.
|
||||
*/
|
||||
@ -51,12 +55,15 @@ object GlobalCLIOptions {
|
||||
val uri = loggerConnectUri
|
||||
.map(uri => Seq(s"--$CONNECT_LOGGER", uri.toString))
|
||||
.getOrElse(Seq())
|
||||
level ++ uri
|
||||
val noMasking =
|
||||
if (logMaskingDisabled) Seq(s"--$NO_LOG_MASKING") else Seq()
|
||||
level ++ uri ++ noMasking
|
||||
}
|
||||
}
|
||||
|
||||
val LOG_LEVEL = "launcher-log-level"
|
||||
val CONNECT_LOGGER = "internal-connect-logger"
|
||||
val NO_LOG_MASKING = "no-log-masking"
|
||||
|
||||
/** Converts the [[GlobalCLIOptions]] to a sequence of arguments that can be
|
||||
* added to a launcher invocation to set the same options.
|
||||
|
@ -508,6 +508,13 @@ object LauncherApplication {
|
||||
"connects to the logging service at the provided URI."
|
||||
)
|
||||
.hidden
|
||||
val noLogMasking = Opts.flag(
|
||||
GlobalCLIOptions.NO_LOG_MASKING,
|
||||
"Disable masking of personally identifiable information in logs. " +
|
||||
"Masking can be also disabled with the `NO_LOG_MASKING` environment " +
|
||||
"variable.",
|
||||
showInUsage = false
|
||||
)
|
||||
val colorMode =
|
||||
Opts
|
||||
.aliasedOptionalParameter[ColorMode](
|
||||
@ -531,6 +538,7 @@ object LauncherApplication {
|
||||
hideProgress,
|
||||
logLevel,
|
||||
connectLogger,
|
||||
noLogMasking,
|
||||
colorMode
|
||||
) mapN {
|
||||
(
|
||||
@ -542,6 +550,7 @@ object LauncherApplication {
|
||||
hideProgress,
|
||||
logLevel,
|
||||
connectLogger,
|
||||
disableLogMasking,
|
||||
colorMode
|
||||
) => () =>
|
||||
if (shouldEnsurePortable) {
|
||||
@ -553,8 +562,11 @@ object LauncherApplication {
|
||||
hideProgress = hideProgress,
|
||||
useJSON = useJSON,
|
||||
colorMode = colorMode,
|
||||
internalOptions =
|
||||
GlobalCLIOptions.InternalOptions(logLevel, connectLogger)
|
||||
internalOptions = GlobalCLIOptions.InternalOptions(
|
||||
logLevel,
|
||||
connectLogger,
|
||||
disableLogMasking
|
||||
)
|
||||
)
|
||||
|
||||
internalOptsCallback(globalCLIOptions)
|
||||
@ -562,7 +574,8 @@ object LauncherApplication {
|
||||
LauncherLogging.setup(
|
||||
logLevel,
|
||||
connectLogger,
|
||||
globalCLIOptions.colorMode
|
||||
globalCLIOptions.colorMode,
|
||||
!disableLogMasking
|
||||
)
|
||||
initializeApp()
|
||||
|
||||
|
@ -42,6 +42,7 @@ class LauncherRunner(
|
||||
projectPath: Option[Path],
|
||||
versionOverride: Option[SemVer],
|
||||
logLevel: LogLevel,
|
||||
logMasking: Boolean,
|
||||
additionalArguments: Seq[String]
|
||||
): Try[RunSettings] =
|
||||
Try {
|
||||
@ -68,7 +69,7 @@ class LauncherRunner(
|
||||
}
|
||||
RunSettings(
|
||||
version,
|
||||
arguments ++ setLogLevelArgs(logLevel)
|
||||
arguments ++ setLogLevelArgs(logLevel, logMasking)
|
||||
++ additionalArguments,
|
||||
connectLoggerIfAvailable = true
|
||||
)
|
||||
@ -82,6 +83,7 @@ class LauncherRunner(
|
||||
path: Option[Path],
|
||||
versionOverride: Option[SemVer],
|
||||
logLevel: LogLevel,
|
||||
logMasking: Boolean,
|
||||
additionalArguments: Seq[String]
|
||||
): Try[RunSettings] =
|
||||
Try {
|
||||
@ -128,14 +130,18 @@ class LauncherRunner(
|
||||
}
|
||||
RunSettings(
|
||||
version,
|
||||
arguments ++ setLogLevelArgs(logLevel)
|
||||
arguments ++ setLogLevelArgs(logLevel, logMasking)
|
||||
++ additionalArguments,
|
||||
connectLoggerIfAvailable = true
|
||||
)
|
||||
}
|
||||
|
||||
private def setLogLevelArgs(level: LogLevel): Seq[String] =
|
||||
Seq("--log-level", level.name)
|
||||
private def setLogLevelArgs(
|
||||
level: LogLevel,
|
||||
logMasking: Boolean
|
||||
): Seq[String] =
|
||||
Seq("--log-level", level.name) ++
|
||||
Option.unless(logMasking)("--no-log-masking")
|
||||
|
||||
/** Creates [[RunSettings]] for launching the Language Server.
|
||||
*
|
||||
|
@ -169,7 +169,8 @@ class LauncherRunnerSpec extends RuntimeVersionManagerTest {
|
||||
projectPath = None,
|
||||
versionOverride = None,
|
||||
additionalArguments = Seq("arg", "--flag"),
|
||||
logLevel = LogLevel.Info
|
||||
logLevel = LogLevel.Info,
|
||||
logMasking = true
|
||||
)
|
||||
.get
|
||||
|
||||
@ -194,7 +195,8 @@ class LauncherRunnerSpec extends RuntimeVersionManagerTest {
|
||||
projectPath = Some(projectPath),
|
||||
versionOverride = None,
|
||||
additionalArguments = Seq(),
|
||||
logLevel = LogLevel.Info
|
||||
logLevel = LogLevel.Info,
|
||||
logMasking = true
|
||||
)
|
||||
.get
|
||||
|
||||
@ -208,7 +210,8 @@ class LauncherRunnerSpec extends RuntimeVersionManagerTest {
|
||||
projectPath = None,
|
||||
versionOverride = None,
|
||||
additionalArguments = Seq(),
|
||||
logLevel = LogLevel.Info
|
||||
logLevel = LogLevel.Info,
|
||||
logMasking = true
|
||||
)
|
||||
.get
|
||||
|
||||
@ -222,7 +225,8 @@ class LauncherRunnerSpec extends RuntimeVersionManagerTest {
|
||||
projectPath = Some(projectPath),
|
||||
versionOverride = Some(overridden),
|
||||
additionalArguments = Seq(),
|
||||
logLevel = LogLevel.Info
|
||||
logLevel = LogLevel.Info,
|
||||
logMasking = true
|
||||
)
|
||||
.get
|
||||
|
||||
@ -290,7 +294,8 @@ class LauncherRunnerSpec extends RuntimeVersionManagerTest {
|
||||
path = Some(projectPath),
|
||||
versionOverride = None,
|
||||
additionalArguments = Seq(),
|
||||
logLevel = LogLevel.Info
|
||||
logLevel = LogLevel.Info,
|
||||
logMasking = true
|
||||
)
|
||||
.get
|
||||
|
||||
@ -304,7 +309,8 @@ class LauncherRunnerSpec extends RuntimeVersionManagerTest {
|
||||
path = None,
|
||||
versionOverride = None,
|
||||
additionalArguments = Seq(),
|
||||
logLevel = LogLevel.Info
|
||||
logLevel = LogLevel.Info,
|
||||
logMasking = true
|
||||
)
|
||||
.get
|
||||
|
||||
@ -318,7 +324,8 @@ class LauncherRunnerSpec extends RuntimeVersionManagerTest {
|
||||
path = Some(projectPath),
|
||||
versionOverride = Some(overridden),
|
||||
additionalArguments = Seq(),
|
||||
logLevel = LogLevel.Info
|
||||
logLevel = LogLevel.Info,
|
||||
logMasking = true
|
||||
)
|
||||
.get
|
||||
|
||||
@ -332,7 +339,8 @@ class LauncherRunnerSpec extends RuntimeVersionManagerTest {
|
||||
path = None,
|
||||
versionOverride = None,
|
||||
additionalArguments = Seq(),
|
||||
logLevel = LogLevel.Info
|
||||
logLevel = LogLevel.Info,
|
||||
logMasking = true
|
||||
)
|
||||
.isFailure,
|
||||
"Running outside project without providing any paths should be an error"
|
||||
@ -358,7 +366,8 @@ class LauncherRunnerSpec extends RuntimeVersionManagerTest {
|
||||
path = Some(outsideFile),
|
||||
versionOverride = None,
|
||||
additionalArguments = Seq(),
|
||||
logLevel = LogLevel.Info
|
||||
logLevel = LogLevel.Info,
|
||||
logMasking = true
|
||||
)
|
||||
.get
|
||||
|
||||
@ -382,7 +391,8 @@ class LauncherRunnerSpec extends RuntimeVersionManagerTest {
|
||||
path = Some(insideFile),
|
||||
versionOverride = None,
|
||||
additionalArguments = Seq(),
|
||||
logLevel = LogLevel.Info
|
||||
logLevel = LogLevel.Info,
|
||||
logMasking = true
|
||||
)
|
||||
.get
|
||||
|
||||
|
@ -39,6 +39,7 @@ object Main {
|
||||
private val JSON_OPTION = "json"
|
||||
private val LOG_LEVEL = "log-level"
|
||||
private val LOGGER_CONNECT = "logger-connect"
|
||||
private val NO_LOG_MASKING = "no-log-masking"
|
||||
|
||||
/** Builds the [[Options]] object representing the CLI syntax.
|
||||
*
|
||||
@ -175,6 +176,14 @@ object Main {
|
||||
.longOpt(LOGGER_CONNECT)
|
||||
.desc("Connects to a logging service server and passes all logs to it.")
|
||||
.build
|
||||
val noLogMaskingOption: CliOption = CliOption.builder
|
||||
.longOpt(NO_LOG_MASKING)
|
||||
.desc(
|
||||
"Disable masking of personally identifiable information in logs. " +
|
||||
"Masking can be also disabled with the `NO_LOG_MASKING` environment " +
|
||||
"variable."
|
||||
)
|
||||
.build()
|
||||
|
||||
val options = new Options
|
||||
options
|
||||
@ -197,6 +206,7 @@ object Main {
|
||||
.addOption(json)
|
||||
.addOption(logLevelOption)
|
||||
.addOption(loggerConnectOption)
|
||||
.addOption(noLogMaskingOption)
|
||||
|
||||
options
|
||||
}
|
||||
@ -545,7 +555,8 @@ object Main {
|
||||
.getOrElse(defaultLogLevel)
|
||||
val connectionUri =
|
||||
Option(line.getOptionValue(LOGGER_CONNECT)).map(parseUri)
|
||||
RunnerLogging.setup(connectionUri, logLevel)
|
||||
val logMasking = !line.hasOption(NO_LOG_MASKING)
|
||||
RunnerLogging.setup(connectionUri, logLevel, logMasking)
|
||||
|
||||
if (line.hasOption(NEW_OPTION)) {
|
||||
createNew(
|
||||
|
@ -2,6 +2,7 @@ package org.enso.runner
|
||||
|
||||
import akka.http.scaladsl.model.Uri
|
||||
import com.typesafe.scalalogging.Logger
|
||||
import org.enso.logger.masking.Masking
|
||||
import org.enso.loggingservice.printers.StderrPrinter
|
||||
import org.enso.loggingservice.{LogLevel, LoggerMode, LoggingServiceManager}
|
||||
|
||||
@ -20,9 +21,15 @@ object RunnerLogging {
|
||||
*
|
||||
* @param connectionUri optional uri of logging service server to connect to
|
||||
* @param logLevel log level to use for the runner and runtime
|
||||
* @param logMasking switches log masking on and off
|
||||
*/
|
||||
def setup(connectionUri: Option[Uri], logLevel: LogLevel): Unit = {
|
||||
def setup(
|
||||
connectionUri: Option[Uri],
|
||||
logLevel: LogLevel,
|
||||
logMasking: Boolean
|
||||
): Unit = {
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
Masking.setup(logMasking)
|
||||
val loggerSetup = connectionUri match {
|
||||
case Some(uri) =>
|
||||
LoggingServiceManager
|
||||
@ -31,7 +38,7 @@ object RunnerLogging {
|
||||
logLevel
|
||||
)
|
||||
.map { _ =>
|
||||
logger.trace(s"Connected to logging service at `$uri`.")
|
||||
logger.trace("Connected to logging service at [{}].", uri)
|
||||
}
|
||||
.recoverWith { _ =>
|
||||
logger.error(
|
||||
|
@ -23,6 +23,7 @@ import org.enso.interpreter.runtime.error.PanicException;
|
||||
import org.enso.interpreter.runtime.error.PanicSentinel;
|
||||
import org.enso.interpreter.runtime.tag.IdentifiedTag;
|
||||
import org.enso.interpreter.runtime.type.Types;
|
||||
import org.enso.logger.masking.MaskedString;
|
||||
import org.enso.pkg.QualifiedName;
|
||||
|
||||
import java.util.*;
|
||||
@ -135,7 +136,7 @@ public class IdExecutionInstrument extends TruffleInstrument {
|
||||
+ "expressionId="
|
||||
+ expressionId
|
||||
+ ", value="
|
||||
+ value
|
||||
+ new MaskedString(value.toString()).applyMasking()
|
||||
+ ", type='"
|
||||
+ type
|
||||
+ '\''
|
||||
|
@ -1,5 +1,8 @@
|
||||
package org.enso.interpreter.service.error;
|
||||
|
||||
import org.enso.logger.masking.MaskedPath;
|
||||
import org.enso.logger.masking.MaskedString;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/** Thrown when the edits can not be applied to the source. */
|
||||
@ -16,13 +19,13 @@ public class FailedToApplyEditsException extends RuntimeException implements Ser
|
||||
public FailedToApplyEditsException(File path, Object edits, Object failure, Object source) {
|
||||
super(
|
||||
"Filed to apply edits for file "
|
||||
+ path
|
||||
+ " edits="
|
||||
+ edits
|
||||
+ " failure="
|
||||
+ new MaskedPath(path.toPath()).applyMasking()
|
||||
+ ", edits="
|
||||
+ new MaskedString(edits.toString()).applyMasking()
|
||||
+ ", failure="
|
||||
+ failure
|
||||
+ " source='"
|
||||
+ source
|
||||
+ ", source='"
|
||||
+ new MaskedString(source.toString()).applyMasking()
|
||||
+ "'");
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
package org.enso.interpreter.service.error;
|
||||
|
||||
import org.enso.logger.masking.MaskedPath;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/** Thrown when a module for given file was requested but could not be found. */
|
||||
@ -11,6 +13,6 @@ public class ModuleNotFoundForFileException extends ModuleNotFoundException {
|
||||
* @param path the path of the module file.
|
||||
*/
|
||||
public ModuleNotFoundForFileException(File path) {
|
||||
super("Module not found for file " + path + ".");
|
||||
super("Module not found for file " + new MaskedPath(path.toPath()).applyMasking() + ".");
|
||||
}
|
||||
}
|
||||
|
@ -119,7 +119,7 @@ class EnsureCompiledJob(protected val files: Iterable[File])
|
||||
compile(module) match {
|
||||
case Left(err) =>
|
||||
ctx.executionService.getLogger
|
||||
.log(Level.SEVERE, s"Compilation error in ${module.getPath}", err)
|
||||
.log(Level.SEVERE, s"Compilation error in ${module.getName}", err)
|
||||
sendFailureUpdate(
|
||||
Api.ExecutionResult.Failure(
|
||||
err.getMessage,
|
||||
|
@ -1,8 +1,9 @@
|
||||
package org.enso.loggingservice
|
||||
|
||||
import org.enso.logger.masking.Masking
|
||||
import org.enso.loggingservice.internal.{InternalLogMessage, LoggerConnection}
|
||||
import org.slf4j.helpers.MessageFormatter
|
||||
import org.slf4j.{Logger => SLF4JLogger, Marker}
|
||||
import org.slf4j.{Marker, Logger => SLF4JLogger}
|
||||
|
||||
import scala.annotation.unused
|
||||
|
||||
@ -11,8 +12,13 @@ import scala.annotation.unused
|
||||
*
|
||||
* @param name name of the logger
|
||||
* @param connection the connection to pass the log messages to
|
||||
* @param masking object that masks personally identifiable information
|
||||
*/
|
||||
class Logger(name: String, connection: LoggerConnection) extends SLF4JLogger {
|
||||
class Logger(
|
||||
name: String,
|
||||
connection: LoggerConnection,
|
||||
masking: Masking
|
||||
) extends SLF4JLogger {
|
||||
override def getName: String = name
|
||||
|
||||
private def isEnabled(level: LogLevel): Boolean =
|
||||
@ -33,7 +39,8 @@ class Logger(name: String, connection: LoggerConnection) extends SLF4JLogger {
|
||||
arg: AnyRef
|
||||
): Unit = {
|
||||
if (isEnabled(level)) {
|
||||
val fp = MessageFormatter.format(format, arg)
|
||||
val maskedArg = masking.mask(arg)
|
||||
val fp = MessageFormatter.format(format, maskedArg)
|
||||
connection.send(
|
||||
InternalLogMessage(level, name, fp.getMessage, Option(fp.getThrowable))
|
||||
)
|
||||
@ -47,7 +54,9 @@ class Logger(name: String, connection: LoggerConnection) extends SLF4JLogger {
|
||||
arg2: AnyRef
|
||||
): Unit = {
|
||||
if (isEnabled(level)) {
|
||||
val fp = MessageFormatter.format(format, arg1, arg2)
|
||||
val maskedArg1 = masking.mask(arg1)
|
||||
val maskedArg2 = masking.mask(arg2)
|
||||
val fp = MessageFormatter.format(format, maskedArg1, maskedArg2)
|
||||
connection.send(
|
||||
InternalLogMessage(level, name, fp.getMessage, Option(fp.getThrowable))
|
||||
)
|
||||
@ -60,7 +69,8 @@ class Logger(name: String, connection: LoggerConnection) extends SLF4JLogger {
|
||||
args: Seq[AnyRef]
|
||||
): Unit = {
|
||||
if (isEnabled(level)) {
|
||||
val fp = MessageFormatter.arrayFormat(format, args.toArray)
|
||||
val maskedArgs = args.map(masking.mask)
|
||||
val fp = MessageFormatter.arrayFormat(format, maskedArgs.toArray)
|
||||
connection.send(
|
||||
InternalLogMessage(level, name, fp.getMessage, Option(fp.getThrowable))
|
||||
)
|
||||
|
@ -1,19 +1,22 @@
|
||||
package org.enso.loggingservice
|
||||
|
||||
import org.enso.logger.masking.Masking
|
||||
import org.slf4j.{ILoggerFactory, Logger => SLF4JLogger}
|
||||
|
||||
/** A [[ILoggerFactory]] instance for the SLF4J backend.
|
||||
*/
|
||||
/** A [[ILoggerFactory]] instance for the SLF4J backend. */
|
||||
class LoggerFactory extends ILoggerFactory {
|
||||
|
||||
/** @inheritdoc
|
||||
*/
|
||||
override def getLogger(name: String): SLF4JLogger = {
|
||||
loggers.getOrElseUpdate(
|
||||
name,
|
||||
new Logger(name, LoggingServiceManager.Connection)
|
||||
)
|
||||
}
|
||||
|
||||
private val loggers = scala.collection.concurrent.TrieMap[String, Logger]()
|
||||
|
||||
/** @inheritdoc */
|
||||
override def getLogger(name: String): SLF4JLogger = {
|
||||
val logger = loggers.getOrElseUpdate(
|
||||
name,
|
||||
new Logger(name, LoggingServiceManager.Connection, Masking())
|
||||
)
|
||||
if (!Masking.isMaskingEnabled) {
|
||||
logger.warn("Log masking is disabled!")
|
||||
}
|
||||
logger
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import java.nio.file.Path
|
||||
|
||||
import akka.http.scaladsl.model.Uri
|
||||
import com.typesafe.scalalogging.Logger
|
||||
import org.enso.logger.masking.Masking
|
||||
import org.enso.loggingservice.printers.{
|
||||
FileOutputPrinter,
|
||||
Printer,
|
||||
@ -47,13 +48,16 @@ abstract class LoggingServiceSetupHelper(implicit
|
||||
* its logs to; advanced feature, use with
|
||||
* caution
|
||||
* @param colorMode specifies how to handle colors in console output
|
||||
* @param logMasking switches the masking on and off
|
||||
*/
|
||||
def setup(
|
||||
logLevel: Option[LogLevel],
|
||||
connectToExternalLogger: Option[Uri],
|
||||
colorMode: ColorMode
|
||||
colorMode: ColorMode,
|
||||
logMasking: Boolean
|
||||
): Unit = {
|
||||
val actualLogLevel = logLevel.getOrElse(defaultLogLevel)
|
||||
Masking.setup(logMasking)
|
||||
connectToExternalLogger match {
|
||||
case Some(uri) =>
|
||||
setupLoggingConnection(uri, actualLogLevel)
|
||||
|
@ -0,0 +1,24 @@
|
||||
package org.enso.logger.masking
|
||||
|
||||
import java.nio.file.Path
|
||||
|
||||
/** A path that is masked when logged.
|
||||
*
|
||||
* @param value the underlying path.
|
||||
*/
|
||||
case class MaskedPath(value: Path) extends ToLogString {
|
||||
|
||||
/** @inheritdoc */
|
||||
override def toString: String =
|
||||
value.toAbsolutePath.normalize().toString
|
||||
|
||||
/** @inheritdoc */
|
||||
override def toLogString(shouldMask: Boolean): String = {
|
||||
val path = value.toAbsolutePath.normalize()
|
||||
if (shouldMask) {
|
||||
MaskingUtils.toMaskedPath(path)
|
||||
} else {
|
||||
path.toString
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package org.enso.logger.masking
|
||||
|
||||
/** A string that is masked when logged.
|
||||
*
|
||||
* @param value the underlying string.
|
||||
*/
|
||||
case class MaskedString(value: String) extends ToLogString {
|
||||
|
||||
/** @inheritdoc */
|
||||
override def toString: String =
|
||||
value
|
||||
|
||||
/** @inheritdoc */
|
||||
override def toLogString(shouldMask: Boolean): String =
|
||||
if (shouldMask) STUB else value
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
package org.enso.logger.masking
|
||||
|
||||
import scala.util.control.NonFatal
|
||||
|
||||
trait Masking {
|
||||
|
||||
/** Converts the provided object to a masked representation.
|
||||
*
|
||||
* @param obj the object to mask
|
||||
* @return the masked object
|
||||
*/
|
||||
def mask(obj: AnyRef): AnyRef
|
||||
}
|
||||
object Masking {
|
||||
|
||||
@volatile private var maskingEnabled: Boolean = true
|
||||
|
||||
/** Environment variable name that disables log masking. */
|
||||
val NO_LOG_MASKING = "NO_LOG_MASKING"
|
||||
|
||||
/** Setup the log masking.
|
||||
*
|
||||
* @param enabled if the log masking is enabled
|
||||
*/
|
||||
def setup(enabled: Boolean): Unit = {
|
||||
maskingEnabled = enabled
|
||||
}
|
||||
|
||||
/** Checks if the log masking is enabled. */
|
||||
def isMaskingEnabled: Boolean = {
|
||||
!sys.env.contains(NO_LOG_MASKING) &&
|
||||
maskingEnabled
|
||||
}
|
||||
|
||||
private def masking(shouldMask: Boolean): Masking = {
|
||||
case obj: ToLogString =>
|
||||
try obj.toLogString(shouldMask)
|
||||
catch {
|
||||
case NonFatal(error) =>
|
||||
System.err.println(
|
||||
"[internal-logger-error] " +
|
||||
"Failed `toMaskedString` invocation on object of type " +
|
||||
s"'${obj.getClass.getName}'. " +
|
||||
s"${error.getClass.getName}: " +
|
||||
s"${error.getMessage}"
|
||||
)
|
||||
"[Failed `toMaskedString`]"
|
||||
}
|
||||
case obj => obj
|
||||
}
|
||||
|
||||
/** Get the instance of [[Masking]] adapter. */
|
||||
def apply(): Masking = masking(isMaskingEnabled)
|
||||
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package org.enso.logger.masking
|
||||
|
||||
import java.nio.file.{FileSystems, Path}
|
||||
|
||||
object MaskingUtils {
|
||||
|
||||
/** A substitution for the masked data. */
|
||||
final val STUB: String = "***"
|
||||
|
||||
/** A platform-specific file separator string. */
|
||||
final val fileSeparator: String = FileSystems.getDefault.getSeparator
|
||||
|
||||
/** Mask a path to the file
|
||||
*
|
||||
* @param path the file to mask
|
||||
* @return a string with a path to the file masked
|
||||
*/
|
||||
def toMaskedPath(path: Path): String = {
|
||||
val segmentsCount = path.getNameCount
|
||||
if (segmentsCount > 1) {
|
||||
s"$STUB$fileSeparator${path.getFileName}"
|
||||
} else {
|
||||
STUB
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package org.enso.logger.masking
|
||||
|
||||
/** Indicates that an object has a custom string representation masking some
|
||||
* personally identifiable information.
|
||||
*
|
||||
* == Logging ==
|
||||
* This object should be supplied to the logger as an argument of the template
|
||||
* string. This way the logger will use the `toLogString` representation of
|
||||
* the object.
|
||||
*
|
||||
* {{{
|
||||
* log.debug("Created [{}].", obj)
|
||||
* }}}
|
||||
*
|
||||
* == Errors ==
|
||||
* Note that the string interpolation `s"Created [$obj]"` still uses the
|
||||
* default `toString` implementation. When creating errors, you should use
|
||||
* the `applyMasking()` function that returns the masked representation
|
||||
* depending on whether or not the masking is enabled in the application.
|
||||
*
|
||||
* {{{
|
||||
* throw new Exception(s"Failed to initialize [${obj.applyMasking}].")
|
||||
* }}}
|
||||
*/
|
||||
trait ToLogString {
|
||||
|
||||
/** A substitution for the masked data. */
|
||||
final protected val STUB: String = MaskingUtils.STUB
|
||||
|
||||
/** A synonym for the `STUB`. */
|
||||
final protected val *** = STUB
|
||||
|
||||
/** String representation of this object with masked personally identifiable
|
||||
* information.
|
||||
*
|
||||
* @param shouldMask decides whether or not the value should be masked
|
||||
*/
|
||||
def toLogString(shouldMask: Boolean): String
|
||||
|
||||
/** Returns the string representation defined by the `toMaskedString` method,
|
||||
* based on the current masking settings.
|
||||
*/
|
||||
def applyMasking(): String =
|
||||
Masking().mask(this).toString
|
||||
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package org.enso.logger.masking
|
||||
|
||||
import java.nio.file.Path
|
||||
|
||||
import org.enso.logger.masking.MaskingUtils.{fileSeparator, toMaskedPath, STUB}
|
||||
import org.scalatest.matchers.should.Matchers
|
||||
import org.scalatest.wordspec.AnyWordSpec
|
||||
|
||||
class MaskingUtilsSpec extends AnyWordSpec with Matchers {
|
||||
|
||||
"MaskingUtils" should {
|
||||
|
||||
"mask a path" in {
|
||||
toMaskedPath(Path.of("/")) shouldEqual STUB
|
||||
toMaskedPath(Path.of("/foo")) shouldEqual STUB
|
||||
toMaskedPath(Path.of("/foo/bar")) shouldEqual masked("bar")
|
||||
toMaskedPath(Path.of("/foo/bar.jar")) shouldEqual masked("bar.jar")
|
||||
toMaskedPath(Path.of("/foo/bar/baz")) shouldEqual masked("baz")
|
||||
toMaskedPath(Path.of("/foo/bar/baz.xyz")) shouldEqual masked("baz.xyz")
|
||||
}
|
||||
}
|
||||
|
||||
private def masked(suffix: String): String =
|
||||
s"$STUB$fileSeparator$suffix"
|
||||
}
|
@ -9,6 +9,7 @@ object Cli {
|
||||
|
||||
val JSON_OPTION = "json"
|
||||
val HELP_OPTION = "help"
|
||||
val NO_LOG_MASKING = "no-log-masking"
|
||||
val VERBOSE_OPTION = "verbose"
|
||||
val VERSION_OPTION = "version"
|
||||
|
||||
@ -23,7 +24,7 @@ object Cli {
|
||||
val verbose: cli.Option = cli.Option
|
||||
.builder("v")
|
||||
.longOpt(VERBOSE_OPTION)
|
||||
.desc("Increase logs verbosity. Can be added multiple times (-vv)")
|
||||
.desc("Increase logs verbosity. Can be added multiple times (-vv).")
|
||||
.build()
|
||||
|
||||
val version: cli.Option = cli.Option.builder
|
||||
@ -35,6 +36,15 @@ object Cli {
|
||||
.longOpt(JSON_OPTION)
|
||||
.desc("Switches the --version option to JSON output.")
|
||||
.build()
|
||||
|
||||
val noLogMasking: cli.Option = cli.Option.builder
|
||||
.longOpt(NO_LOG_MASKING)
|
||||
.desc(
|
||||
"Disable masking of personally identifiable information in logs. " +
|
||||
"Masking can be also disabled with the `NO_LOG_MASKING` environment " +
|
||||
"variable."
|
||||
)
|
||||
.build()
|
||||
}
|
||||
|
||||
val options: cli.Options =
|
||||
@ -43,6 +53,7 @@ object Cli {
|
||||
.addOption(option.verbose)
|
||||
.addOption(option.version)
|
||||
.addOption(option.json)
|
||||
.addOption(option.noLogMasking)
|
||||
|
||||
/** Parse the command line options. */
|
||||
def parse(args: Array[String]): Either[String, cli.CommandLine] = {
|
||||
|
@ -45,7 +45,7 @@ object ProjectManager extends App with LazyLogging {
|
||||
val computeExecutionContext: ExecutionContextExecutor =
|
||||
ExecutionContext.fromExecutor(
|
||||
computeThreadPool,
|
||||
th => logger.error("An expected error occurred", th)
|
||||
th => logger.error("An expected error occurred.", th)
|
||||
)
|
||||
|
||||
/** ZIO runtime.
|
||||
@ -76,7 +76,7 @@ object ProjectManager extends App with LazyLogging {
|
||||
.foldM(
|
||||
failure = th =>
|
||||
effectTotal {
|
||||
logger.error("An error occurred during killing lang servers", th)
|
||||
logger.error("An error occurred during killing lang servers.", th)
|
||||
},
|
||||
success = ZIO.succeed(_)
|
||||
)
|
||||
@ -90,7 +90,7 @@ object ProjectManager extends App with LazyLogging {
|
||||
failure = th =>
|
||||
effectTotal {
|
||||
logger
|
||||
.error("An error occurred during waiting for shutdown hooks", th)
|
||||
.error("An error occurred during waiting for shutdown hooks.", th)
|
||||
},
|
||||
success = ZIO.succeed(_)
|
||||
)
|
||||
@ -117,8 +117,9 @@ object ProjectManager extends App with LazyLogging {
|
||||
displayVersion(options.hasOption(Cli.JSON_OPTION))
|
||||
} else {
|
||||
val verbosity = options.getOptions.count(_ == Cli.option.verbose)
|
||||
val logMasking = !options.hasOption(Cli.NO_LOG_MASKING)
|
||||
logger.info("Starting Project Manager...")
|
||||
setupLogging(verbosity) *>
|
||||
setupLogging(verbosity, logMasking) *>
|
||||
mainProcess.fold(
|
||||
th => {
|
||||
logger.error("Main process execution failed.", th)
|
||||
@ -129,7 +130,10 @@ object ProjectManager extends App with LazyLogging {
|
||||
}
|
||||
}
|
||||
|
||||
private def setupLogging(verbosityLevel: Int): ZIO[Console, Nothing, Unit] = {
|
||||
private def setupLogging(
|
||||
verbosityLevel: Int,
|
||||
logMasking: Boolean
|
||||
): ZIO[Console, Nothing, Unit] = {
|
||||
val level = verbosityLevel match {
|
||||
case 0 => LogLevel.Info
|
||||
case 1 => LogLevel.Debug
|
||||
@ -142,7 +146,7 @@ object ProjectManager extends App with LazyLogging {
|
||||
|
||||
ZIO
|
||||
.effect {
|
||||
Logging.setup(Some(level), None, colorMode)
|
||||
Logging.setup(Some(level), None, colorMode, logMasking)
|
||||
}
|
||||
.catchAll { exception =>
|
||||
putStrLnErr(s"Failed to setup the logger: $exception")
|
||||
@ -164,8 +168,9 @@ object ProjectManager extends App with LazyLogging {
|
||||
private def logServerStartup(): UIO[Unit] =
|
||||
effectTotal {
|
||||
logger.info(
|
||||
s"Started server at ${config.server.host}:${config.server.port}, " +
|
||||
s"press enter to kill server"
|
||||
"Started server at {}:{}, press enter to kill server",
|
||||
config.server.host,
|
||||
config.server.port
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -96,7 +96,8 @@ object ExecutorWithUnlimitedPool extends LanguageServerExecutor {
|
||||
.get
|
||||
runner.withCommand(runSettings, descriptor.jvmSettings) { command =>
|
||||
Logger[ExecutorWithUnlimitedPool.type].trace(
|
||||
s"Starting Language Server Process: $command"
|
||||
"Starting Language Server Process [{}]",
|
||||
command
|
||||
)
|
||||
|
||||
val process = {
|
||||
|
@ -65,7 +65,7 @@ class HeartbeatSession(
|
||||
|
||||
private def pingStage: Receive = {
|
||||
case WebSocketConnected =>
|
||||
log.debug(s"Sending ping message to $socket")
|
||||
log.debug("Sending ping message to {}.", socket)
|
||||
connection.send(s"""
|
||||
|{
|
||||
| "jsonrpc": "2.0",
|
||||
@ -78,7 +78,11 @@ class HeartbeatSession(
|
||||
context.become(pongStage(cancellable))
|
||||
|
||||
case WebSocketStreamFailure(th) =>
|
||||
logError(th, s"An error occurred during connecting to websocket $socket")
|
||||
logError(
|
||||
th,
|
||||
"An error occurred during connecting to websocket {}.",
|
||||
socket
|
||||
)
|
||||
context.parent ! ServerUnresponsive
|
||||
stop()
|
||||
|
||||
@ -93,11 +97,11 @@ class HeartbeatSession(
|
||||
|
||||
maybeJson match {
|
||||
case Left(error) =>
|
||||
logError(error, "An error occurred during parsing pong reply")
|
||||
logError(error, "An error occurred during parsing pong reply.")
|
||||
|
||||
case Right(id) =>
|
||||
if (id == requestId.toString) {
|
||||
log.debug(s"Received correct pong message from $socket")
|
||||
log.debug("Received correct pong message from {}.", socket)
|
||||
|
||||
if (sendConfirmations) {
|
||||
context.parent ! HeartbeatReceived
|
||||
@ -106,12 +110,12 @@ class HeartbeatSession(
|
||||
cancellable.cancel()
|
||||
stop()
|
||||
} else {
|
||||
log.warning(s"Received unknown response $payload")
|
||||
log.warning("Received unknown response {}.", payload)
|
||||
}
|
||||
}
|
||||
|
||||
case HeartbeatTimeout =>
|
||||
log.debug(s"Heartbeat timeout detected for $requestId")
|
||||
log.debug("Heartbeat timeout detected for {}.", requestId)
|
||||
context.parent ! ServerUnresponsive
|
||||
stop()
|
||||
|
||||
@ -120,7 +124,7 @@ class HeartbeatSession(
|
||||
context.stop(self)
|
||||
|
||||
case WebSocketStreamFailure(th) =>
|
||||
logError(th, s"An error occurred during waiting for Pong message")
|
||||
logError(th, "An error occurred during waiting for Pong message.")
|
||||
context.parent ! ServerUnresponsive
|
||||
cancellable.cancel()
|
||||
stop()
|
||||
@ -136,12 +140,12 @@ class HeartbeatSession(
|
||||
cancellable.cancel()
|
||||
|
||||
case WebSocketStreamFailure(th) =>
|
||||
logError(th, s"An error occurred during closing web socket")
|
||||
logError(th, "An error occurred during closing web socket.")
|
||||
context.stop(self)
|
||||
cancellable.cancel()
|
||||
|
||||
case SocketClosureTimeout =>
|
||||
logError(s"Socket closure timed out")
|
||||
logError("Socket closure timed out.")
|
||||
context.stop(self)
|
||||
connection.detachListener(self)
|
||||
|
||||
@ -155,6 +159,18 @@ class HeartbeatSession(
|
||||
context.become(socketClosureStage(closureTimeout))
|
||||
}
|
||||
|
||||
private def logError(
|
||||
throwable: Throwable,
|
||||
message: String,
|
||||
arg: AnyRef
|
||||
): Unit = {
|
||||
if (quietErrors) {
|
||||
log.debug(s"$message ($throwable)", arg)
|
||||
} else {
|
||||
log.error(throwable, message, arg)
|
||||
}
|
||||
}
|
||||
|
||||
private def logError(throwable: Throwable, message: String): Unit = {
|
||||
if (quietErrors) {
|
||||
log.debug(s"$message ($throwable)")
|
||||
|
@ -50,7 +50,7 @@ class LanguageServerBootLoader(
|
||||
import context.dispatcher
|
||||
|
||||
override def preStart(): Unit = {
|
||||
log.info(s"Booting a language server [$descriptor]")
|
||||
log.info("Booting a language server [{}].", descriptor)
|
||||
self ! FindFreeSocket
|
||||
}
|
||||
|
||||
@ -62,16 +62,19 @@ class LanguageServerBootLoader(
|
||||
*/
|
||||
private def findingSocket(retry: Int = 0): Receive = {
|
||||
case FindFreeSocket =>
|
||||
log.debug("Looking for available socket to bind the language server")
|
||||
log.debug("Looking for available socket to bind the language server.")
|
||||
val jsonRpcPort = findPort()
|
||||
var binaryPort = findPort()
|
||||
while (binaryPort == jsonRpcPort) {
|
||||
binaryPort = findPort()
|
||||
}
|
||||
log.info(
|
||||
s"Found sockets for the language server " +
|
||||
s"[json:${descriptor.networkConfig.interface}:$jsonRpcPort, " +
|
||||
s"binary:${descriptor.networkConfig.interface}:$binaryPort]"
|
||||
"Found sockets for the language server " +
|
||||
"[json:{}:{}, binary:{}:{}].",
|
||||
descriptor.networkConfig.interface,
|
||||
jsonRpcPort,
|
||||
descriptor.networkConfig.interface,
|
||||
binaryPort
|
||||
)
|
||||
self ! Boot
|
||||
context.become(
|
||||
@ -117,7 +120,7 @@ class LanguageServerBootLoader(
|
||||
bootRequester: ActorRef
|
||||
): Receive = {
|
||||
case Boot =>
|
||||
log.debug("Booting a language server")
|
||||
log.debug("Booting a language server.")
|
||||
context.actorOf(
|
||||
LanguageServerProcess.props(
|
||||
progressTracker = bootProgressTracker,
|
||||
@ -155,7 +158,7 @@ class LanguageServerBootLoader(
|
||||
rpcPort = rpcPort,
|
||||
dataPort = dataPort
|
||||
)
|
||||
log.info(s"Language server booted [$connectionInfo].")
|
||||
log.info("Language server booted [{}].", connectionInfo)
|
||||
|
||||
bootRequester ! ServerBooted(connectionInfo, self)
|
||||
context.become(running(connectionInfo))
|
||||
@ -183,7 +186,8 @@ class LanguageServerBootLoader(
|
||||
} else {
|
||||
if (shouldRetry) {
|
||||
log.error(
|
||||
s"Tried $retryCount times to boot Language Server. Giving up."
|
||||
"Tried {} times to boot Language Server. Giving up.",
|
||||
retryCount
|
||||
)
|
||||
} else {
|
||||
log.error("Failed to restart the server. Giving up.")
|
||||
@ -204,7 +208,8 @@ class LanguageServerBootLoader(
|
||||
private def running(connectionInfo: LanguageServerConnectionInfo): Receive = {
|
||||
case msg @ LanguageServerProcess.ServerTerminated(exitCode) =>
|
||||
log.debug(
|
||||
s"Language Server process has terminated with exit code $exitCode"
|
||||
"Language Server process has terminated with exit code {}.",
|
||||
exitCode
|
||||
)
|
||||
context.parent ! msg
|
||||
context.stop(self)
|
||||
@ -230,8 +235,9 @@ class LanguageServerBootLoader(
|
||||
): Receive = {
|
||||
case LanguageServerProcess.ServerTerminated(exitCode) =>
|
||||
log.debug(
|
||||
s"Language Server process has terminated (as requested to reboot) " +
|
||||
s"with exit code $exitCode"
|
||||
"Language Server process has terminated (as requested to reboot) " +
|
||||
"with exit code {}.",
|
||||
exitCode
|
||||
)
|
||||
|
||||
context.become(rebooting(connectionInfo, rebootRequester))
|
||||
|
@ -115,12 +115,12 @@ class LanguageServerController(
|
||||
|
||||
private def booting(Bootloader: ActorRef): Receive = {
|
||||
case BootTimeout =>
|
||||
log.error(s"Booting failed for $descriptor")
|
||||
log.error("Booting failed for {}.", descriptor)
|
||||
unstashAll()
|
||||
context.become(bootFailed(LanguageServerProtocol.ServerBootTimedOut))
|
||||
|
||||
case ServerBootFailed(th) =>
|
||||
log.error(th, s"Booting failed for $descriptor")
|
||||
log.error(th, "Booting failed for {}.", descriptor)
|
||||
unstashAll()
|
||||
context.become(bootFailed(LanguageServerProtocol.ServerBootFailed(th)))
|
||||
|
||||
@ -139,12 +139,12 @@ class LanguageServerController(
|
||||
)
|
||||
|
||||
case Terminated(Bootloader) =>
|
||||
log.error(s"Bootloader for project ${project.name} failed")
|
||||
log.error("Bootloader for project {} failed.", project.name)
|
||||
unstashAll()
|
||||
context.become(
|
||||
bootFailed(
|
||||
LanguageServerProtocol.ServerBootFailed(
|
||||
new Exception("The number of boot retries exceeded")
|
||||
new Exception("The number of boot retries exceeded.")
|
||||
)
|
||||
)
|
||||
)
|
||||
@ -179,7 +179,7 @@ class LanguageServerController(
|
||||
)
|
||||
}
|
||||
case Terminated(_) =>
|
||||
log.debug(s"Bootloader for $project terminated.")
|
||||
log.debug("Bootloader for {} terminated.", project)
|
||||
|
||||
case StopServer(clientId, _) =>
|
||||
removeClient(
|
||||
@ -219,7 +219,7 @@ class LanguageServerController(
|
||||
)
|
||||
|
||||
case ServerDied =>
|
||||
log.error(s"Language server died [$connectionInfo]")
|
||||
log.error("Language server died [{}].", connectionInfo)
|
||||
context.stop(self)
|
||||
|
||||
}
|
||||
@ -243,7 +243,7 @@ class LanguageServerController(
|
||||
}
|
||||
|
||||
private def shutDownServer(maybeRequester: Option[ActorRef]): Unit = {
|
||||
log.debug(s"Shutting down a language server for project ${project.id}")
|
||||
log.debug("Shutting down a language server for project {}.", project.id)
|
||||
context.children.foreach(_ ! GracefulStop)
|
||||
val cancellable =
|
||||
context.system.scheduler
|
||||
@ -264,18 +264,19 @@ class LanguageServerController(
|
||||
case LanguageServerProcess.ServerTerminated(exitCode) =>
|
||||
cancellable.cancel()
|
||||
if (exitCode == 0) {
|
||||
log.info(s"Language server shut down successfully [$project].")
|
||||
log.info("Language server shut down successfully [{}].", project)
|
||||
} else {
|
||||
log.warning(
|
||||
s"Language server shut down with non-zero exit code: $exitCode " +
|
||||
s"[$project]."
|
||||
"Language server shut down with non-zero exit code: {} [{}].",
|
||||
exitCode,
|
||||
project
|
||||
)
|
||||
}
|
||||
maybeRequester.foreach(_ ! ServerStopped)
|
||||
stop()
|
||||
|
||||
case ShutdownTimeout =>
|
||||
log.error("Language server shutdown timed out")
|
||||
log.error("Language server shutdown timed out.")
|
||||
maybeRequester.foreach(_ ! ServerShutdownTimedOut)
|
||||
stop()
|
||||
|
||||
|
@ -40,7 +40,7 @@ class LanguageServerKiller(
|
||||
sender() ! AllServersKilled
|
||||
context.stop(self)
|
||||
} else {
|
||||
log.info("Killing all servers")
|
||||
log.info("Killing all servers [{}].", controllers)
|
||||
controllers.foreach(context.watch)
|
||||
controllers.foreach(_ ! ShutDownServer)
|
||||
val cancellable =
|
||||
@ -61,7 +61,7 @@ class LanguageServerKiller(
|
||||
case Terminated(dead) =>
|
||||
val updated = liveControllers - dead
|
||||
if (updated.isEmpty) {
|
||||
log.info("All language servers have been killed")
|
||||
log.info("All language servers have been killed.")
|
||||
cancellable.cancel()
|
||||
replyTo ! AllServersKilled
|
||||
context.stop(self)
|
||||
|
@ -82,9 +82,8 @@ class LanguageServerSupervisor(
|
||||
)
|
||||
|
||||
case ServerUnresponsive =>
|
||||
log.info(s"Server is unresponsive [$connectionInfo]. Restarting it...")
|
||||
cancellable.cancel()
|
||||
log.info(s"Restarting the server")
|
||||
log.info("Server is unresponsive. Restarting [{}].", connectionInfo)
|
||||
serverProcessManager ! Restart
|
||||
context.become(restarting)
|
||||
|
||||
@ -95,7 +94,7 @@ class LanguageServerSupervisor(
|
||||
|
||||
private def restarting: Receive = {
|
||||
case ServerBootFailed(_) =>
|
||||
log.error("Cannot restart language server")
|
||||
log.error("Cannot restart language server.")
|
||||
context.parent ! ServerDied
|
||||
context.stop(self)
|
||||
|
||||
@ -106,7 +105,7 @@ class LanguageServerSupervisor(
|
||||
"Supervisor may no longer work correctly."
|
||||
)
|
||||
}
|
||||
log.info(s"Language server restarted [$connectionInfo]")
|
||||
log.info("Language server restarted [{}].", connectionInfo)
|
||||
val cancellable =
|
||||
scheduler.scheduleAtFixedRate(
|
||||
supervisionConfig.initialDelay,
|
||||
|
@ -64,7 +64,7 @@ class ProjectRenameAction(
|
||||
private var maybeActionTimeoutCancellable: Option[Cancellable] = None
|
||||
|
||||
override def preStart(): Unit = {
|
||||
log.info(s"Requesting a Language Server to rename project $oldName")
|
||||
log.info("Requesting a Language Server to rename project [{}].", oldName)
|
||||
connection.attachListener(self)
|
||||
connection.connect()
|
||||
val cancellable =
|
||||
@ -92,7 +92,11 @@ class ProjectRenameAction(
|
||||
context.become(connected())
|
||||
|
||||
case WebSocketStreamFailure(th) =>
|
||||
log.error(th, s"An error occurred during connecting to websocket $socket")
|
||||
log.error(
|
||||
th,
|
||||
"An error occurred during connecting to websocket {}.",
|
||||
socket
|
||||
)
|
||||
replyTo ! CannotConnectToServer
|
||||
stop()
|
||||
|
||||
@ -102,7 +106,7 @@ class ProjectRenameAction(
|
||||
stop()
|
||||
|
||||
case GracefulStop =>
|
||||
log.warning("Ignoring stop command")
|
||||
log.warning("Ignoring stop command (Language Server is not connected).")
|
||||
}
|
||||
|
||||
private def connected(): Receive = {
|
||||
@ -122,7 +126,7 @@ class ProjectRenameAction(
|
||||
maybeActionTimeoutCancellable.foreach(_.cancel())
|
||||
|
||||
case WebSocketStreamFailure(th) =>
|
||||
log.error(th, s"An error occurred during waiting for Pong message")
|
||||
log.error(th, "An error occurred during waiting for Pong message.")
|
||||
replyTo ! ServerUnresponsive
|
||||
stop()
|
||||
|
||||
@ -132,7 +136,7 @@ class ProjectRenameAction(
|
||||
stop()
|
||||
|
||||
case GracefulStop =>
|
||||
log.warning("Ignoring stop command")
|
||||
log.warning("Ignoring stop command (Language Server is connected).")
|
||||
}
|
||||
|
||||
private def handleSuccess(payload: String): Unit = {
|
||||
@ -141,15 +145,15 @@ class ProjectRenameAction(
|
||||
|
||||
maybeRequestId match {
|
||||
case Left(error) =>
|
||||
log.error(error, "An error occurred during parsing rename reply")
|
||||
log.error(error, "An error occurred during parsing rename reply.")
|
||||
|
||||
case Right(id) =>
|
||||
if (id == requestId.toString) {
|
||||
log.info(s"Project renamed by the Language Server")
|
||||
log.info("Project renamed by the Language Server.")
|
||||
replyTo ! ProjectRenamed
|
||||
stop()
|
||||
} else {
|
||||
log.warning(s"Received unknown response $payload")
|
||||
log.warning("Received unknown response [{}].", payload)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -161,7 +165,9 @@ class ProjectRenameAction(
|
||||
.flatMap(_.hcursor.downField("message").as[String])
|
||||
.getOrElse("Not Provided")
|
||||
log.error(
|
||||
s"Error occurred during renaming project [code: $code message: $msg]"
|
||||
"Error occurred during renaming project [code: {}, message: {}]",
|
||||
code,
|
||||
msg
|
||||
)
|
||||
replyTo ! RenameFailure(code, msg)
|
||||
stop()
|
||||
@ -175,16 +181,18 @@ class ProjectRenameAction(
|
||||
closureTimeoutCancellable.cancel()
|
||||
|
||||
case WebSocketStreamFailure(th) =>
|
||||
log.error(th, s"An error occurred during closing web socket")
|
||||
log.error(th, "An error occurred during closing web socket.")
|
||||
context.stop(self)
|
||||
closureTimeoutCancellable.cancel()
|
||||
|
||||
case SocketClosureTimeout =>
|
||||
log.error(s"Socket closure timed out")
|
||||
log.error("Socket closure timed out.")
|
||||
context.stop(self)
|
||||
|
||||
case GracefulStop =>
|
||||
log.warning("Ignoring stop command")
|
||||
log.warning(
|
||||
"Ignoring stop command (closing connection to Language Server)."
|
||||
)
|
||||
}
|
||||
|
||||
private def stop(): Unit = {
|
||||
|
@ -30,7 +30,7 @@ class ShutdownHookRunner[F[+_, +_]: Exec: CovariantFlatMap](
|
||||
}
|
||||
|
||||
override def receive: Receive = { case Run =>
|
||||
log.info(s"Firing shutdown hooks for project with id=$projectId")
|
||||
log.info("Firing shutdown hooks for project [{}].", projectId)
|
||||
Exec[F].exec { traverse(hooks) { _.execute() } } pipeTo self
|
||||
context.become(running)
|
||||
}
|
||||
@ -39,12 +39,13 @@ class ShutdownHookRunner[F[+_, +_]: Exec: CovariantFlatMap](
|
||||
case Status.Failure(th) =>
|
||||
log.error(
|
||||
th,
|
||||
s"An error occurred during running shutdown hooks for project with id=$projectId"
|
||||
"An error occurred during running shutdown hooks for project [{}].",
|
||||
projectId
|
||||
)
|
||||
context.stop(self)
|
||||
|
||||
case Right(_) =>
|
||||
log.info(s"All shutdown hooks fired for project with id=$projectId")
|
||||
log.info("All shutdown hooks fired for project [{}].", projectId)
|
||||
context.stop(self)
|
||||
}
|
||||
|
||||
|
@ -8,8 +8,13 @@ trait Logging[F[+_, +_]] {
|
||||
|
||||
def debug(msg: String): F[Nothing, Unit]
|
||||
|
||||
def debug(msg: String, args: AnyRef*): F[Nothing, Unit]
|
||||
|
||||
def info(msg: String): F[Nothing, Unit]
|
||||
|
||||
def info(msg: String, args: AnyRef*): F[Nothing, Unit]
|
||||
|
||||
def error(msg: String): F[Nothing, Unit]
|
||||
|
||||
def error(msg: String, args: AnyRef*): F[Nothing, Unit]
|
||||
}
|
||||
|
@ -2,17 +2,24 @@ package org.enso.projectmanager.infrastructure.log
|
||||
import com.typesafe.scalalogging.LazyLogging
|
||||
import org.enso.projectmanager.control.effect.Sync
|
||||
|
||||
/** Slf4j logging interpreter.
|
||||
*/
|
||||
/** Slf4j logging interpreter. */
|
||||
class Slf4jLogging[F[+_, +_]: Sync] extends Logging[F] with LazyLogging {
|
||||
|
||||
override def debug(msg: String): F[Nothing, Unit] =
|
||||
Sync[F].effect(logger.debug(msg))
|
||||
|
||||
override def debug(msg: String, args: AnyRef*): F[Nothing, Unit] =
|
||||
Sync[F].effect(logger.debug(msg, args: _*))
|
||||
|
||||
override def info(msg: String): F[Nothing, Unit] =
|
||||
Sync[F].effect(logger.info(msg))
|
||||
|
||||
override def info(msg: String, args: AnyRef*): F[Nothing, Unit] =
|
||||
Sync[F].effect(logger.info(msg, args: _*))
|
||||
|
||||
override def error(msg: String): F[Nothing, Unit] =
|
||||
Sync[F].effect(logger.error(msg))
|
||||
|
||||
override def error(msg: String, args: AnyRef*): F[Nothing, Unit] =
|
||||
Sync[F].effect(logger.error(msg, args: _*))
|
||||
}
|
||||
|
@ -81,7 +81,8 @@ class ProjectFileRepository[
|
||||
/** @inheritdoc */
|
||||
override def findPathForNewProject(
|
||||
project: Project
|
||||
): F[ProjectRepositoryFailure, Path] = findTargetPath(project).map(_.toPath)
|
||||
): F[ProjectRepositoryFailure, Path] =
|
||||
findTargetPath(project).map(_.toPath)
|
||||
|
||||
private def tryLoadProject(
|
||||
directory: File
|
||||
|
@ -100,7 +100,7 @@ class ClientController[F[+_, +_]: Exec: CovariantFlatMap: ErrorChannel](
|
||||
|
||||
override def receive: Receive = {
|
||||
case JsonRpcServer.WebConnect(webActor) =>
|
||||
log.info(s"Client connected to Project Manager [$clientId]")
|
||||
log.info("Client connected to Project Manager [{}]", clientId)
|
||||
unstashAll()
|
||||
context.become(connected(webActor))
|
||||
context.system.eventStream.publish(ClientConnected(clientId))
|
||||
@ -110,7 +110,7 @@ class ClientController[F[+_, +_]: Exec: CovariantFlatMap: ErrorChannel](
|
||||
|
||||
def connected(@unused webActor: ActorRef): Receive = {
|
||||
case MessageHandler.Disconnected =>
|
||||
log.info(s"Client disconnected from the Project Manager [$clientId]")
|
||||
log.info("Client disconnected from the Project Manager [{}]", clientId)
|
||||
context.system.eventStream.publish(ClientDisconnected(clientId))
|
||||
context.stop(self)
|
||||
|
||||
|
@ -51,7 +51,7 @@ class LoggingServiceEndpointRequestHandler(
|
||||
timeoutCancellable: Cancellable
|
||||
): Receive = {
|
||||
case Status.Failure(ex) =>
|
||||
log.error(ex, s"Failure during $method operation:")
|
||||
log.error(ex, "Failure during {} operation.", method)
|
||||
replyTo ! ResponseError(
|
||||
Some(id),
|
||||
LoggingServiceUnavailable(s"Logging service failed to set up: $ex")
|
||||
@ -60,7 +60,7 @@ class LoggingServiceEndpointRequestHandler(
|
||||
context.stop(self)
|
||||
|
||||
case RequestTimeout =>
|
||||
log.error(s"Request $method with $id timed out")
|
||||
log.error("Request {} with {} timed out.", method, id)
|
||||
replyTo ! ResponseError(
|
||||
Some(id),
|
||||
LoggingServiceUnavailable(
|
||||
|
@ -51,18 +51,18 @@ class ProjectCloseHandler[F[+_, +_]: Exec](
|
||||
cancellable: Cancellable
|
||||
): Receive = {
|
||||
case Status.Failure(ex) =>
|
||||
log.error(ex, s"Failure during $ProjectClose operation:")
|
||||
log.error(ex, "Failure during {} operation.", ProjectClose)
|
||||
replyTo ! ResponseError(Some(id), ServiceError)
|
||||
cancellable.cancel()
|
||||
context.stop(self)
|
||||
|
||||
case RequestTimeout =>
|
||||
log.error(s"Request $ProjectClose with $id timed out")
|
||||
log.error("Request {} with {} timed out.", ProjectClose, id)
|
||||
replyTo ! ResponseError(Some(id), ServiceError)
|
||||
context.stop(self)
|
||||
|
||||
case Left(failure: ProjectServiceFailure) =>
|
||||
log.error(s"Request $id failed due to $failure")
|
||||
log.error("Request {} failed due to {}.", id, failure)
|
||||
replyTo ! ResponseError(Some(id), mapFailure(failure))
|
||||
cancellable.cancel()
|
||||
context.stop(self)
|
||||
|
@ -45,18 +45,18 @@ class ProjectDeleteHandler[F[+_, +_]: Exec](
|
||||
cancellable: Cancellable
|
||||
): Receive = {
|
||||
case Status.Failure(ex) =>
|
||||
log.error(ex, s"Failure during $ProjectDelete operation:")
|
||||
log.error(ex, "Failure during {} operation.", ProjectDelete)
|
||||
replyTo ! ResponseError(Some(id), ServiceError)
|
||||
cancellable.cancel()
|
||||
context.stop(self)
|
||||
|
||||
case RequestTimeout =>
|
||||
log.error(s"Request $ProjectDelete with $id timed out")
|
||||
log.error("Request {} with {} timed out.", ProjectDelete, id)
|
||||
replyTo ! ResponseError(Some(id), ServiceError)
|
||||
context.stop(self)
|
||||
|
||||
case Left(failure: ProjectServiceFailure) =>
|
||||
log.error(s"Request $id failed due to $failure")
|
||||
log.error("Request {} failed due to {}.", id, failure)
|
||||
replyTo ! ResponseError(Some(id), mapFailure(failure))
|
||||
cancellable.cancel()
|
||||
context.stop(self)
|
||||
|
@ -54,18 +54,18 @@ class ProjectListHandler[F[+_, +_]: Exec](
|
||||
cancellable: Cancellable
|
||||
): Receive = {
|
||||
case Status.Failure(ex) =>
|
||||
log.error(ex, s"Failure during $ProjectList operation:")
|
||||
log.error(ex, "Failure during {} operation.", ProjectList)
|
||||
replyTo ! ResponseError(Some(id), ServiceError)
|
||||
cancellable.cancel()
|
||||
context.stop(self)
|
||||
|
||||
case RequestTimeout =>
|
||||
log.error(s"Request $ProjectList with $id timed out")
|
||||
log.error("Request {} with {} timed out.", ProjectList, id)
|
||||
replyTo ! ResponseError(Some(id), ServiceError)
|
||||
context.stop(self)
|
||||
|
||||
case Left(failure: ProjectServiceFailure) =>
|
||||
log.error(s"Request $id failed due to $failure")
|
||||
log.error("Request {} failed due to {}.", id, failure)
|
||||
replyTo ! ResponseError(Some(id), mapFailure(failure))
|
||||
cancellable.cancel()
|
||||
context.stop(self)
|
||||
|
@ -48,18 +48,18 @@ class ProjectRenameHandler[F[+_, +_]: Exec](
|
||||
cancellable: Cancellable
|
||||
): Receive = {
|
||||
case Status.Failure(ex) =>
|
||||
log.error(ex, s"Failure during $ProjectRename operation:")
|
||||
log.error(ex, "Failure during {} operation.", ProjectRename)
|
||||
replyTo ! ResponseError(Some(id), ServiceError)
|
||||
cancellable.cancel()
|
||||
context.stop(self)
|
||||
|
||||
case RequestTimeout =>
|
||||
log.error(s"Request $ProjectRename with $id timed out")
|
||||
log.error("Request {} with {} timed out.", ProjectRename, id)
|
||||
replyTo ! ResponseError(Some(id), ServiceError)
|
||||
context.stop(self)
|
||||
|
||||
case Left(failure: ProjectServiceFailure) =>
|
||||
log.error(s"Request $id failed due to $failure")
|
||||
log.error(s"Request {} failed due to {}.", id, failure)
|
||||
replyTo ! ResponseError(Some(id), mapFailure(failure))
|
||||
cancellable.cancel()
|
||||
context.stop(self)
|
||||
|
@ -90,18 +90,18 @@ abstract class RequestHandler[
|
||||
timeoutCancellable: Option[Cancellable]
|
||||
): Receive = {
|
||||
case Status.Failure(ex) =>
|
||||
log.error(ex, s"Failure during $method operation:")
|
||||
log.error(ex, "Failure during {} operation.", method)
|
||||
replyTo ! ResponseError(Some(id), ServiceError)
|
||||
timeoutCancellable.foreach(_.cancel())
|
||||
context.stop(self)
|
||||
|
||||
case RequestTimeout =>
|
||||
log.error(s"Request $method with $id timed out")
|
||||
log.error("Request {} with {} timed out.", method, id)
|
||||
replyTo ! ResponseError(Some(id), ServiceError)
|
||||
context.stop(self)
|
||||
|
||||
case Left(failure: FailureType) =>
|
||||
log.error(s"Request $method with $id failed due to $failure")
|
||||
log.error("Request {} with {} failed due to {}.", method, id, failure)
|
||||
val error = implicitly[FailureMapper[FailureType]].mapFailure(failure)
|
||||
replyTo ! ResponseError(Some(id), error)
|
||||
timeoutCancellable.foreach(_.cancel())
|
||||
@ -134,8 +134,10 @@ abstract class RequestHandler[
|
||||
timeoutCancellable.foreach { cancellable =>
|
||||
cancellable.cancel()
|
||||
Logger[this.type].trace(
|
||||
s"The operation $method ($id) reported starting a long-running task, " +
|
||||
s"its request-timeout has been cancelled."
|
||||
"The operation {} ({}) reported starting a long-running task, " +
|
||||
"its request-timeout has been cancelled.",
|
||||
method,
|
||||
id
|
||||
)
|
||||
}
|
||||
context.become(responseStage(id, replyTo, None))
|
||||
|
@ -31,9 +31,9 @@ class MoveProjectDirCmd[F[+_, +_]: CovariantFlatMap: ErrorChannel](
|
||||
override def execute(): F[Nothing, Unit] = {
|
||||
def go() =
|
||||
for {
|
||||
_ <- log.debug(s"Moving project ${projectId} to $newName")
|
||||
_ <- log.debug("Moving project [{}] to [{}].", projectId, newName)
|
||||
dir <- repo.moveProjectToTargetDir(projectId, newName)
|
||||
_ <- log.info(s"Project $projectId moved to $dir")
|
||||
_ <- log.info("Project [{}] moved to [{}].", projectId, dir)
|
||||
} yield ()
|
||||
|
||||
go().fallbackTo(logError)
|
||||
@ -41,7 +41,9 @@ class MoveProjectDirCmd[F[+_, +_]: CovariantFlatMap: ErrorChannel](
|
||||
|
||||
private def logError(failure: ProjectRepositoryFailure): F[Nothing, Unit] = {
|
||||
log.error(
|
||||
s"An error occurred during moving project $projectId [$failure]"
|
||||
"An error occurred during moving project {} [{}].",
|
||||
projectId,
|
||||
failure
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -83,14 +83,17 @@ class ProjectService[
|
||||
missingComponentAction: MissingComponentAction
|
||||
): F[ProjectServiceFailure, UUID] = for {
|
||||
projectId <- gen.randomUUID()
|
||||
_ <- log.debug(s"Creating project $name $projectId.")
|
||||
_ <- log.debug("Creating project [{}, {}].", name, projectId)
|
||||
_ <- validateName(name)
|
||||
_ <- checkIfNameExists(name)
|
||||
creationTime <- clock.nowInUtc()
|
||||
project = Project(projectId, name, UserProject, creationTime)
|
||||
path <- repo.findPathForNewProject(project).mapError(toServiceFailure)
|
||||
_ <- log.debug(
|
||||
s"Found a path '$path' for a new project $name $projectId."
|
||||
"Found a path [{}] for a new project [{}, {}].",
|
||||
path,
|
||||
name,
|
||||
projectId
|
||||
)
|
||||
_ <- projectCreationService.createProject(
|
||||
progressTracker,
|
||||
@ -100,24 +103,27 @@ class ProjectService[
|
||||
missingComponentAction
|
||||
)
|
||||
_ <- log.debug(
|
||||
s"Project $projectId structure created with " +
|
||||
s"$path, $name, $engineVersion."
|
||||
"Project [{}] structure created with [{}, {}, {}].",
|
||||
projectId,
|
||||
path,
|
||||
name,
|
||||
engineVersion
|
||||
)
|
||||
_ <- repo
|
||||
.update(project.copy(path = Some(path.toString)))
|
||||
.mapError(toServiceFailure)
|
||||
_ <- log.debug(s"Project $projectId updated in repository $repo.")
|
||||
_ <- log.info(s"Project $project created.")
|
||||
_ <- log.debug("Project [{}] updated in repository [{}].", projectId, repo)
|
||||
_ <- log.info("Project created [{}].", project)
|
||||
} yield projectId
|
||||
|
||||
/** @inheritdoc */
|
||||
override def deleteUserProject(
|
||||
projectId: UUID
|
||||
): F[ProjectServiceFailure, Unit] =
|
||||
log.debug(s"Deleting project $projectId.") *>
|
||||
log.debug("Deleting project [{}].", projectId) *>
|
||||
ensureProjectIsNotRunning(projectId) *>
|
||||
repo.delete(projectId).mapError(toServiceFailure) *>
|
||||
log.info(s"Project $projectId deleted.")
|
||||
log.info("Project deleted [{}].", projectId)
|
||||
|
||||
private def ensureProjectIsNotRunning(
|
||||
projectId: UUID
|
||||
@ -141,7 +147,7 @@ class ProjectService[
|
||||
newPackage: String
|
||||
): F[ProjectServiceFailure, Unit] = {
|
||||
for {
|
||||
_ <- log.debug(s"Renaming project $projectId to $newPackage.")
|
||||
_ <- log.debug("Renaming project [{}] to [{}].", projectId, newPackage)
|
||||
_ <- validateName(newPackage)
|
||||
_ <- checkIfProjectExists(projectId)
|
||||
_ <- checkIfNameExists(newPackage)
|
||||
@ -149,7 +155,7 @@ class ProjectService[
|
||||
_ <- repo.rename(projectId, newPackage).mapError(toServiceFailure)
|
||||
_ <- renameProjectDirOrRegisterShutdownHook(projectId, newPackage)
|
||||
_ <- refactorProjectName(projectId, oldPackage, newPackage)
|
||||
_ <- log.info(s"Project $projectId renamed.")
|
||||
_ <- log.info("Project renamed [{}].", projectId)
|
||||
} yield ()
|
||||
}
|
||||
|
||||
@ -162,15 +168,19 @@ class ProjectService[
|
||||
.ifM(isServerRunning(projectId))(
|
||||
ifTrue = for {
|
||||
_ <- log.debug(
|
||||
s"Registering shutdown hook to rename the project $projectId " +
|
||||
s"with a new name '$newName''"
|
||||
"Registering shutdown hook to rename the project [{}] " +
|
||||
"with a new name [{}].",
|
||||
projectId,
|
||||
newName
|
||||
)
|
||||
_ <- languageServerGateway.registerShutdownHook(projectId, cmd)
|
||||
} yield (),
|
||||
ifFalse = for {
|
||||
_ <- log.debug(
|
||||
s"Running a command to rename the project $projectId " +
|
||||
s"with a new name '$newName"
|
||||
"Running a command to rename the project [{}] " +
|
||||
"with a new name [{}].",
|
||||
projectId,
|
||||
newName
|
||||
)
|
||||
_ <- cmd.execute()
|
||||
} yield ()
|
||||
@ -195,20 +205,22 @@ class ProjectService[
|
||||
case ProjectNotOpened => ProjectNotOpen //impossible
|
||||
case RenameTimeout => ProjectOperationTimeout
|
||||
case CannotConnectToServer =>
|
||||
LanguageServerFailure("Cannot connect to the language server")
|
||||
LanguageServerFailure("Cannot connect to the language server.")
|
||||
|
||||
case RenameFailure(code, msg) =>
|
||||
LanguageServerFailure(
|
||||
s"Failure during renaming [code: $code message: $msg]"
|
||||
s"Failure during renaming [code: $code message: $msg]."
|
||||
)
|
||||
|
||||
case ServerUnresponsive =>
|
||||
LanguageServerFailure("The language server is unresponsive")
|
||||
LanguageServerFailure("The language server is unresponsive.")
|
||||
}
|
||||
.flatMap { _ =>
|
||||
log.debug(
|
||||
s"Language Server replied to the project $projectId rename command " +
|
||||
s"from $oldPackage to $newPackage."
|
||||
"Language Server replied to the project [{}] rename command from {} to {}.",
|
||||
projectId,
|
||||
oldPackage,
|
||||
newPackage
|
||||
)
|
||||
}
|
||||
|
||||
@ -224,8 +236,9 @@ class ProjectService[
|
||||
}
|
||||
.flatMap { _ =>
|
||||
log.debug(
|
||||
s"Checked if the project $projectId exists " +
|
||||
s"in repo $repo."
|
||||
"Checked if the project [{}] exists in repo [{}].",
|
||||
projectId,
|
||||
repo
|
||||
)
|
||||
}
|
||||
|
||||
@ -238,7 +251,7 @@ class ProjectService[
|
||||
): F[ProjectServiceFailure, RunningLanguageServerInfo] = {
|
||||
// format: off
|
||||
for {
|
||||
_ <- log.debug(s"Opening project $projectId")
|
||||
_ <- log.debug(s"Opening project [{}].", projectId)
|
||||
project <- getUserProject(projectId)
|
||||
openTime <- clock.nowInUtc()
|
||||
updated = project.copy(lastOpened = Some(openTime))
|
||||
@ -262,7 +275,7 @@ class ProjectService[
|
||||
}
|
||||
.mapRuntimeManagerErrors(th =>
|
||||
ProjectOpenFailed(
|
||||
s"Cannot install the required engine ${th.getMessage}"
|
||||
s"Cannot install the required engine. ${th.getMessage}"
|
||||
)
|
||||
)
|
||||
|
||||
@ -276,8 +289,8 @@ class ProjectService[
|
||||
.resolveEnsoVersion(project.engineVersion)
|
||||
.mapError { case ConfigurationFileAccessFailure(message) =>
|
||||
ProjectOpenFailed(
|
||||
s"Could not deduce the default version to use for the project: " +
|
||||
s"$message"
|
||||
"Could not deduce the default version to use for the project: " +
|
||||
message
|
||||
)
|
||||
}
|
||||
_ <- preinstallEngine(progressTracker, version, missingComponentAction)
|
||||
@ -291,11 +304,11 @@ class ProjectService[
|
||||
)
|
||||
|
||||
case ServerBootTimedOut =>
|
||||
ProjectOpenFailed("Language server boot timed out")
|
||||
ProjectOpenFailed("Language server boot timed out.")
|
||||
|
||||
case ServerBootFailed(th) =>
|
||||
ProjectOpenFailed(
|
||||
s"Language server boot failed: ${th.getMessage}"
|
||||
s"Language server boot failed. ${th.getMessage}"
|
||||
)
|
||||
}
|
||||
} yield RunningLanguageServerInfo(version, sockets)
|
||||
@ -305,10 +318,10 @@ class ProjectService[
|
||||
clientId: UUID,
|
||||
projectId: UUID
|
||||
): F[ProjectServiceFailure, Unit] = {
|
||||
log.debug(s"Closing project $projectId") *>
|
||||
log.debug(s"Closing project [{}].", projectId) *>
|
||||
languageServerGateway.stop(clientId, projectId).mapError {
|
||||
case ServerShutdownTimedOut =>
|
||||
ProjectCloseFailed("Server shutdown timed out")
|
||||
ProjectCloseFailed("Server shutdown timed out.")
|
||||
|
||||
case FailureDuringShutdown(th) => ProjectCloseFailed(th.getMessage)
|
||||
case ServerNotRunning => ProjectNotOpen
|
||||
@ -336,8 +349,8 @@ class ProjectService[
|
||||
.resolveEnsoVersion(project.engineVersion)
|
||||
.mapError { case ConfigurationFileAccessFailure(message) =>
|
||||
GlobalConfigurationAccessFailure(
|
||||
s"Could not deduce the default version to use for the project: " +
|
||||
s"$message"
|
||||
"Could not deduce the default version to use for the project: " +
|
||||
message
|
||||
)
|
||||
}
|
||||
.map(toProjectMetadata(_, project))
|
||||
@ -365,7 +378,7 @@ class ProjectService[
|
||||
}
|
||||
.flatMap { project =>
|
||||
log
|
||||
.debug(s"Found project $projectId in the $repo.")
|
||||
.debug("Found project [{}] in [{}].", projectId, repo)
|
||||
.map(_ => project)
|
||||
}
|
||||
|
||||
@ -381,21 +394,22 @@ class ProjectService[
|
||||
}
|
||||
.flatMap { _ =>
|
||||
log.debug(
|
||||
s"Checked if the project name '$name' exists " +
|
||||
s"in the $repo."
|
||||
"Checked if the project name [{}] exists in [{}].",
|
||||
name,
|
||||
repo
|
||||
)
|
||||
}
|
||||
|
||||
private val toServiceFailure
|
||||
: ProjectRepositoryFailure => ProjectServiceFailure = {
|
||||
case CannotLoadIndex(msg) =>
|
||||
DataStoreFailure(s"Cannot load project index [$msg]")
|
||||
DataStoreFailure(s"Cannot load project index [$msg].")
|
||||
case StorageFailure(msg) =>
|
||||
DataStoreFailure(s"Storage failure [$msg]")
|
||||
DataStoreFailure(s"Storage failure [$msg].")
|
||||
case ProjectNotFoundInIndex =>
|
||||
ProjectNotFound
|
||||
case InconsistentStorage(msg) =>
|
||||
DataStoreFailure(s"Project repository inconsistency detected [$msg]")
|
||||
DataStoreFailure(s"Project repository inconsistency detected [$msg].")
|
||||
}
|
||||
|
||||
private def validateName(
|
||||
@ -406,23 +420,23 @@ class ProjectService[
|
||||
.mapError {
|
||||
case EmptyName =>
|
||||
ProjectServiceFailure.ValidationFailure(
|
||||
"Project name cannot be empty"
|
||||
"Project name cannot be empty."
|
||||
)
|
||||
case NameContainsForbiddenCharacter(chars) =>
|
||||
ProjectServiceFailure.ValidationFailure(
|
||||
s"Project name contains forbidden characters: ${chars.mkString(",")}"
|
||||
s"Project name contains forbidden characters: [${chars.mkString(",")}]."
|
||||
)
|
||||
case NameShouldStartWithCapitalLetter =>
|
||||
ProjectServiceFailure.ValidationFailure(
|
||||
"Project name should start with a capital letter"
|
||||
"Project name should start with a capital letter."
|
||||
)
|
||||
case NameShouldBeUpperSnakeCase(validName) =>
|
||||
ProjectServiceFailure.ValidationFailure(
|
||||
s"Project name should be in upper snake case: $validName"
|
||||
s"Project name should be in upper snake case: $validName."
|
||||
)
|
||||
}
|
||||
.flatMap { _ =>
|
||||
log.debug(s"Project name '$name' validated by $validator.")
|
||||
log.debug("Project name [{}] validated by [{}].", name, validator)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ import org.enso.projectmanager.versionmanagement.DistributionConfiguration
|
||||
import org.enso.runtimeversionmanager.components.ComponentMissingError
|
||||
|
||||
/** A facade for runtime version management logic that processes the requests
|
||||
* using the [[RuntimeVersionManager]].
|
||||
* using the [[org.enso.runtimeversionmanager.components.RuntimeVersionManager]].
|
||||
*
|
||||
* @param distributionConfiguration a distribution configuration
|
||||
*/
|
||||
|
@ -43,7 +43,7 @@ class ProjectManagementApiSpec
|
||||
client.expectJson(json"""
|
||||
{ "jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"error": { "code": 4001, "message": "Project name cannot be empty" }
|
||||
"error": { "code": 4001, "message": "Project name cannot be empty." }
|
||||
}
|
||||
""")
|
||||
}
|
||||
@ -64,7 +64,7 @@ class ProjectManagementApiSpec
|
||||
"id":1,
|
||||
"error":{
|
||||
"code":4001,
|
||||
"message":"Project name contains forbidden characters: -,/,#,$$,%,^,@,!"
|
||||
"message":"Project name contains forbidden characters: [-,/,#,$$,%,^,@,!]."
|
||||
}
|
||||
}
|
||||
""")
|
||||
@ -86,7 +86,7 @@ class ProjectManagementApiSpec
|
||||
"id":1,
|
||||
"error":{
|
||||
"code":4001,
|
||||
"message":"Project name should start with a capital letter"
|
||||
"message":"Project name should start with a capital letter."
|
||||
}
|
||||
}
|
||||
""")
|
||||
@ -108,7 +108,7 @@ class ProjectManagementApiSpec
|
||||
"id":1,
|
||||
"error":{
|
||||
"code":4001,
|
||||
"message":"Project name should be in upper snake case: Enso_Test_Project"
|
||||
"message":"Project name should be in upper snake case: Enso_Test_Project."
|
||||
}
|
||||
}
|
||||
""")
|
||||
@ -872,7 +872,7 @@ class ProjectManagementApiSpec
|
||||
client.expectJson(json"""
|
||||
{ "jsonrpc": "2.0",
|
||||
"id": 0,
|
||||
"error": { "code": 4001, "message": "Project name cannot be empty" }
|
||||
"error": { "code": 4001, "message": "Project name cannot be empty." }
|
||||
}
|
||||
""")
|
||||
//teardown
|
||||
@ -900,7 +900,7 @@ class ProjectManagementApiSpec
|
||||
"id":0,
|
||||
"error":{
|
||||
"code":4001,
|
||||
"message":"Project name contains forbidden characters: -,/,#,$$,%,^,@,!"
|
||||
"message":"Project name contains forbidden characters: [-,/,#,$$,%,^,@,!]."
|
||||
}
|
||||
}
|
||||
""")
|
||||
@ -929,7 +929,7 @@ class ProjectManagementApiSpec
|
||||
"id":0,
|
||||
"error":{
|
||||
"code":4001,
|
||||
"message":"Project name should start with a capital letter"
|
||||
"message":"Project name should start with a capital letter."
|
||||
}
|
||||
}
|
||||
""")
|
||||
@ -958,7 +958,7 @@ class ProjectManagementApiSpec
|
||||
"id":0,
|
||||
"error":{
|
||||
"code":4001,
|
||||
"message":"Project name should be in upper snake case: Enso_Test_Project"
|
||||
"message":"Project name should be in upper snake case: Enso_Test_Project."
|
||||
}
|
||||
}
|
||||
""")
|
||||
|
@ -4,9 +4,16 @@ import org.enso.projectmanager.infrastructure.log.Logging
|
||||
import zio.{IO, ZIO}
|
||||
|
||||
class NopLogging[R] extends Logging[ZIO[R, +*, +*]] {
|
||||
|
||||
override def debug(msg: String): IO[Nothing, Unit] = IO.unit
|
||||
|
||||
override def debug(msg: String, args: AnyRef*): IO[Nothing, Unit] = IO.unit
|
||||
|
||||
override def info(msg: String): IO[Nothing, Unit] = IO.unit
|
||||
|
||||
override def info(msg: String, args: AnyRef*): IO[Nothing, Unit] = IO.unit
|
||||
|
||||
override def error(msg: String): IO[Nothing, Unit] = IO.unit
|
||||
|
||||
override def error(msg: String, args: AnyRef*): IO[Nothing, Unit] = IO.unit
|
||||
}
|
||||
|
@ -30,7 +30,8 @@ object CurrentVersion {
|
||||
"release build."
|
||||
)
|
||||
else {
|
||||
Logger("TEST").debug(s"Overriding version to $newVersion.")
|
||||
Logger[CurrentVersion.type]
|
||||
.debug(s"Overriding version to [{}].", newVersion)
|
||||
currentVersion = newVersion
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user