From 51c072eca10a6ea3b49cd6f60e39264bc29fe588 Mon Sep 17 00:00:00 2001 From: Andrey Stolyarov Date: Sun, 12 Jan 2025 20:51:42 +0300 Subject: [PATCH 1/4] Ref --- .../ru/d10xa/jsonlogviewer/Application.scala | 21 ++-- .../decline/ConfigInitImpl.scala | 114 +++++++++++------- .../d10xa/jsonlogviewer/LogViewerStream.scala | 107 ++++++++-------- .../d10xa/jsonlogviewer/decline/Config.scala | 2 - .../jsonlogviewer/decline/ConfigInit.scala | 5 +- .../jsonlogviewer/decline/DeclineOpts.scala | 1 - .../query/LogLineQueryPredicateImplTest.scala | 1 - 7 files changed, 135 insertions(+), 116 deletions(-) rename json-log-viewer/{shared => jvm}/src/main/scala/ru/d10xa/jsonlogviewer/Application.scala (58%) diff --git a/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/Application.scala b/json-log-viewer/jvm/src/main/scala/ru/d10xa/jsonlogviewer/Application.scala similarity index 58% rename from json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/Application.scala rename to json-log-viewer/jvm/src/main/scala/ru/d10xa/jsonlogviewer/Application.scala index 14e01bb..9bf47f2 100644 --- a/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/Application.scala +++ b/json-log-viewer/jvm/src/main/scala/ru/d10xa/jsonlogviewer/Application.scala @@ -16,16 +16,15 @@ object Application private val configInit: ConfigInit = new ConfigInitImpl - def main: Opts[IO[ExitCode]] = DeclineOpts.config.map { c => - configInit.initConfig(c).flatMap { updatedConfig => - IO { - LogViewerStream - .stream(updatedConfig) - .through(text.utf8.encode) - .through(io.stdout) - .compile - .drain - .as(ExitCode.Success) - }.flatten + def main: Opts[IO[ExitCode]] = DeclineOpts.config.map { config => + configInit.initConfigYaml(config).use { configRef => + LogViewerStream + .stream(config, configRef) + .through(text.utf8.encode) + .through(fs2.io.stdout) + .compile + .drain + .as(ExitCode.Success) } + } diff --git a/json-log-viewer/jvm/src/main/scala/ru/d10xa/jsonlogviewer/decline/ConfigInitImpl.scala b/json-log-viewer/jvm/src/main/scala/ru/d10xa/jsonlogviewer/decline/ConfigInitImpl.scala index c28aa13..96ae459 100644 --- a/json-log-viewer/jvm/src/main/scala/ru/d10xa/jsonlogviewer/decline/ConfigInitImpl.scala +++ b/json-log-viewer/jvm/src/main/scala/ru/d10xa/jsonlogviewer/decline/ConfigInitImpl.scala @@ -1,59 +1,85 @@ package ru.d10xa.jsonlogviewer.decline -import cats.data.Validated -import cats.effect.IO -import ru.d10xa.jsonlogviewer.decline.Config.FormatIn -import cats.syntax.all.* -import ru.d10xa.jsonlogviewer.decline.yaml.ConfigYaml -import ru.d10xa.jsonlogviewer.decline.yaml.ConfigYamlLoader -import ru.d10xa.jsonlogviewer.decline.yaml.ConfigYamlLoaderImpl -import ru.d10xa.jsonlogviewer.decline.yaml.ConfigYamlReader +import cats.effect.std.Supervisor +import cats.effect.{IO, Ref, Resource} +import fs2.io.file.{Files, Path, Watcher} +import ru.d10xa.jsonlogviewer.decline.yaml.{ConfigYaml, ConfigYamlReader} import java.io.File class ConfigInitImpl extends ConfigInit { - override def initConfig(c: Config): IO[Config] = { - def findConfigFile( - baseName: String, - extensions: List[String] - ): Option[String] = { - extensions.collectFirst { - case ext if new File(s"$baseName.$ext").exists() => - s"$baseName.$ext" + override def initConfigYaml( + c: Config + ): Resource[IO, Ref[IO, Option[ConfigYaml]]] = { + val configFileOpt: Option[Path] = + c.configFile.map(file => Path(file.file)).orElse { + findConfigFile("json-log-viewer", List("yml", "yaml", "YML", "YAML")) + .map(Path.apply) } - } + loadConfigRef(configFileOpt) + } + + private def loadConfigRef( + configFileOpt: Option[Path] + ): Resource[IO, Ref[IO, Option[ConfigYaml]]] = { + for { + updatedConfig <- Resource.eval { + configFileOpt match { + case Some(filePath) => readConfig(filePath) + case None => IO.pure(None) + } + } + configRef <- Resource.eval(Ref.of[IO, Option[ConfigYaml]](updatedConfig)) + _ <- configFileOpt match { + case Some(filePath) => watchFileForChanges(filePath, configRef) + case None => Resource.unit[IO] + } + } yield configRef + } - val configFileOpt: Option[String] = c.configFile.map(_.file).orElse { - findConfigFile("json-log-viewer", List("yml", "yaml", "YML", "YAML")) + private def watchFileForChanges( + filePath: Path, + configRef: Ref[IO, Option[ConfigYaml]] + ): Resource[IO, Unit] = { + Resource.eval { + Supervisor[IO].use { supervisor => + supervisor.supervise { + Files[IO] + .watch(filePath) + .evalMap { + case Watcher.Event.Modified(_, _) => + for { + updatedConfig <- readConfig(filePath) + _ <- configRef.set(updatedConfig) + } yield () + case _ => IO.unit + } + .compile + .drain + }.void + } } + } - val configIO: IO[Option[ConfigYaml]] = configFileOpt match { - case Some(file) if new File(file).exists() => - ConfigYamlReader.fromYamlFile(file).flatMap { - case Validated.Valid(config) => - config.some.pure[IO] - case Validated.Invalid(errors) => - IO.raiseError( - new IllegalArgumentException(errors.toList.mkString(", ")) - ) - } - case Some(file) => - IO.raiseError( - new IllegalArgumentException(s"Configuration file not found: $file") - ) - case None => - None.pure[IO] + private def readConfig(filePath: Path): IO[Option[ConfigYaml]] = { + ConfigYamlReader.fromYamlFile(filePath.toString).flatMap { + case cats.data.Validated.Valid(configYaml) => + IO.pure(Some(configYaml)) + case cats.data.Validated.Invalid(errors) => + IO.println(s"Failed to parse config: ${errors.toList.mkString(", ")}") + .as(None) } - configIO.map { - case Some(config) => - c.copy( - filter = c.filter.orElse(config.filter), - formatIn = - c.formatIn.orElse(config.formatIn).orElse(Some(FormatIn.Json)), - configYaml = Some(config) - ) - case None => c + } + + private def findConfigFile( + baseName: String, + extensions: List[String] + ): Option[String] = { + extensions.collectFirst { + case ext if new File(s"$baseName.$ext").exists() => + s"$baseName.$ext" } } + } diff --git a/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/LogViewerStream.scala b/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/LogViewerStream.scala index 3e7277c..9909a7e 100644 --- a/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/LogViewerStream.scala +++ b/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/LogViewerStream.scala @@ -1,33 +1,59 @@ package ru.d10xa.jsonlogviewer -import cats.effect.IO -import cats.syntax.all.* +import cats.effect.{IO, Ref} import fs2.* -import fs2.io.* -import ru.d10xa.jsonlogviewer.StdInLinesStreamImpl import ru.d10xa.jsonlogviewer.decline.Config import ru.d10xa.jsonlogviewer.decline.Config.FormatIn -import ru.d10xa.jsonlogviewer.decline.ConfigInit -import ru.d10xa.jsonlogviewer.decline.ConfigInitImpl -import ru.d10xa.jsonlogviewer.decline.DeclineOpts -import ru.d10xa.jsonlogviewer.decline.yaml.ConfigYaml -import ru.d10xa.jsonlogviewer.decline.yaml.Feed -import ru.d10xa.jsonlogviewer.formatout.ColorLineFormatter -import ru.d10xa.jsonlogviewer.formatout.RawFormatter +import ru.d10xa.jsonlogviewer.decline.yaml.{ConfigYaml, Feed} +import ru.d10xa.jsonlogviewer.formatout.{ColorLineFormatter, RawFormatter} import ru.d10xa.jsonlogviewer.logfmt.LogfmtLogLineParser import ru.d10xa.jsonlogviewer.query.QueryAST import ru.d10xa.jsonlogviewer.shell.ShellImpl object LogViewerStream { - private def makeLogLineParser( + private val stdinLinesStream: Stream[IO, String] = + new StdInLinesStreamImpl().stdinLinesStream + + def stream( config: Config, - optFormatIn: Option[FormatIn] - ): LogLineParser = { - val jsonPrefixPostfix = JsonPrefixPostfix(JsonDetector()) - optFormatIn match { - case Some(FormatIn.Logfmt) => LogfmtLogLineParser(config) - case _ => JsonLogLineParser(config, jsonPrefixPostfix) + configYamlRef: Ref[IO, Option[ConfigYaml]] + ): Stream[IO, String] = { + Stream.eval(configYamlRef.get).flatMap { configYamlOpt => + val topCommandsOpt: Option[List[String]] = + configYamlOpt.flatMap(_.commands).filter(_.nonEmpty) + + val feedsOpt: Option[List[Feed]] = + configYamlOpt.flatMap(_.feeds).filter(_.nonEmpty) + + val finalStream = feedsOpt match { + case Some(feeds) => + val feedStreams = feeds.map { feed => + val feedStream: Stream[IO, String] = + commandsAndInlineInputToStream(feed.commands, feed.inlineInput) + processStream( + config, + feedStream, + feed.filter, + feed.formatIn, + feed.name + ) + } + Stream.emits(feedStreams).parJoin(feedStreams.size) + + case None => + val baseStream = topCommandsOpt match { + case Some(cmds) => + commandsAndInlineInputToStream(cmds, None) + case None => + stdinLinesStream + } + processStream(config, baseStream, None, None, None) + } + + finalStream + .intersperse("\n") + .append(Stream.emit("\n")) } } @@ -38,9 +64,6 @@ object LogViewerStream { new ShellImpl().mergeCommandsAndInlineInput(commands, inlineInput) } - private val stdinLinesStream: Stream[IO, String] = - new StdInLinesStreamImpl().stdinLinesStream - private def processStream( baseConfig: Config, lines: Stream[IO, String], @@ -82,40 +105,14 @@ object LogViewerStream { .map(_.toString) } - def stream(config: Config): Stream[IO, String] = { - val topCommandsOpt: Option[List[String]] = - config.configYaml.flatMap(_.commands).filter(_.nonEmpty) - - val feedsOpt: Option[List[Feed]] = - config.configYaml.flatMap(_.feeds).filter(_.nonEmpty) - - val finalStream = feedsOpt match { - case Some(feeds) => - val feedStreams = feeds.map { feed => - val feedStream: Stream[IO, String] = - commandsAndInlineInputToStream(feed.commands, feed.inlineInput) - processStream( - config, - feedStream, - feed.filter, - feed.formatIn, - feed.name - ) - } - Stream.emits(feedStreams).parJoin(feedStreams.size) - - case None => - val baseStream = topCommandsOpt match { - case Some(cmds) => - commandsAndInlineInputToStream(cmds, None) - case None => - stdinLinesStream - } - processStream(config, baseStream, None, None, None) + private def makeLogLineParser( + config: Config, + optFormatIn: Option[FormatIn] + ): LogLineParser = { + val jsonPrefixPostfix = JsonPrefixPostfix(JsonDetector()) + optFormatIn match { + case Some(FormatIn.Logfmt) => LogfmtLogLineParser(config) + case _ => JsonLogLineParser(config, jsonPrefixPostfix) } - - finalStream - .intersperse("\n") - .append(Stream.emit("\n")) } } diff --git a/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/decline/Config.scala b/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/decline/Config.scala index 2fecfc7..88315c8 100644 --- a/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/decline/Config.scala +++ b/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/decline/Config.scala @@ -1,14 +1,12 @@ package ru.d10xa.jsonlogviewer.decline import ru.d10xa.jsonlogviewer.decline.Config.ConfigGrep -import ru.d10xa.jsonlogviewer.decline.yaml.ConfigYaml import ru.d10xa.jsonlogviewer.query.QueryAST import scala.util.matching.Regex final case class Config( configFile: Option[ConfigFile], - configYaml: Option[ConfigYaml], timestamp: TimestampConfig, grep: List[ConfigGrep], filter: Option[QueryAST], diff --git a/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/decline/ConfigInit.scala b/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/decline/ConfigInit.scala index 88d64b5..040f2aa 100644 --- a/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/decline/ConfigInit.scala +++ b/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/decline/ConfigInit.scala @@ -1,7 +1,8 @@ package ru.d10xa.jsonlogviewer.decline -import cats.effect.IO +import cats.effect.{IO, Ref, Resource} +import ru.d10xa.jsonlogviewer.decline.yaml.ConfigYaml trait ConfigInit { - def initConfig(c: Config): IO[Config] + def initConfigYaml(c: Config): Resource[IO, Ref[IO, Option[ConfigYaml]]] } diff --git a/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/decline/DeclineOpts.scala b/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/decline/DeclineOpts.scala index 03f7a0b..acdac00 100644 --- a/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/decline/DeclineOpts.scala +++ b/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/decline/DeclineOpts.scala @@ -74,7 +74,6 @@ object DeclineOpts { ) => Config( configFile = configFile, - configYaml = None, timestamp = timestampConfig, grep = grepConfig, filter = filterConfig, diff --git a/json-log-viewer/shared/src/test/scala/ru/d10xa/jsonlogviewer/query/LogLineQueryPredicateImplTest.scala b/json-log-viewer/shared/src/test/scala/ru/d10xa/jsonlogviewer/query/LogLineQueryPredicateImplTest.scala index 77f4e09..69ec777 100644 --- a/json-log-viewer/shared/src/test/scala/ru/d10xa/jsonlogviewer/query/LogLineQueryPredicateImplTest.scala +++ b/json-log-viewer/shared/src/test/scala/ru/d10xa/jsonlogviewer/query/LogLineQueryPredicateImplTest.scala @@ -83,7 +83,6 @@ class LogLineQueryPredicateImplTest extends munit.FunSuite { private val config: Config = Config( configFile = None, - configYaml = None, timestamp = TimestampConfig( fieldName = "@timestamp", None, From a5167123c5df9e0449dc526c25126e44cec0bf3d Mon Sep 17 00:00:00 2001 From: Andrey Stolyarov Date: Sun, 12 Jan 2025 20:59:51 +0300 Subject: [PATCH 2/4] Remove top level filter, formatIn, commands --- .../decline/ConfigInitImpl.scala | 11 ++++++--- .../decline/yaml/ConfigYamlLoaderImpl.scala | 16 +------------ .../decline/yaml/ConfigYamlLoaderTest.scala | 24 ++++--------------- .../d10xa/jsonlogviewer/LogViewerStream.scala | 12 +--------- .../decline/yaml/ConfigYaml.scala | 8 +------ 5 files changed, 15 insertions(+), 56 deletions(-) diff --git a/json-log-viewer/jvm/src/main/scala/ru/d10xa/jsonlogviewer/decline/ConfigInitImpl.scala b/json-log-viewer/jvm/src/main/scala/ru/d10xa/jsonlogviewer/decline/ConfigInitImpl.scala index 96ae459..92f31da 100644 --- a/json-log-viewer/jvm/src/main/scala/ru/d10xa/jsonlogviewer/decline/ConfigInitImpl.scala +++ b/json-log-viewer/jvm/src/main/scala/ru/d10xa/jsonlogviewer/decline/ConfigInitImpl.scala @@ -1,9 +1,14 @@ package ru.d10xa.jsonlogviewer.decline import cats.effect.std.Supervisor -import cats.effect.{IO, Ref, Resource} -import fs2.io.file.{Files, Path, Watcher} -import ru.d10xa.jsonlogviewer.decline.yaml.{ConfigYaml, ConfigYamlReader} +import cats.effect.IO +import cats.effect.Ref +import cats.effect.Resource +import fs2.io.file.Files +import fs2.io.file.Path +import fs2.io.file.Watcher +import ru.d10xa.jsonlogviewer.decline.yaml.ConfigYaml +import ru.d10xa.jsonlogviewer.decline.yaml.ConfigYamlReader import java.io.File diff --git a/json-log-viewer/jvm/src/main/scala/ru/d10xa/jsonlogviewer/decline/yaml/ConfigYamlLoaderImpl.scala b/json-log-viewer/jvm/src/main/scala/ru/d10xa/jsonlogviewer/decline/yaml/ConfigYamlLoaderImpl.scala index bf08d35..ecc9895 100644 --- a/json-log-viewer/jvm/src/main/scala/ru/d10xa/jsonlogviewer/decline/yaml/ConfigYamlLoaderImpl.scala +++ b/json-log-viewer/jvm/src/main/scala/ru/d10xa/jsonlogviewer/decline/yaml/ConfigYamlLoaderImpl.scala @@ -170,23 +170,9 @@ class ConfigYamlLoaderImpl extends ConfigYamlLoader { json.asObject.map(_.toMap) match { case None => Validated.invalidNel("YAML is not a valid JSON object") case Some(fields) => - val filterValidated: ValidatedNel[String, Option[QueryAST]] = - parseOptionalQueryAST(fields, "filter") - - val formatInValidated: ValidatedNel[String, Option[FormatIn]] = - parseOptionalFormatIn(fields, "formatIn") - val commandsValidated - : ValidatedNel[String, Option[List[String]]] = - parseOptionalListString(fields, "commands") val feedsValidated: ValidatedNel[String, Option[List[Feed]]] = parseOptionalFeeds(fields, "feeds") - - ( - filterValidated, - formatInValidated, - commandsValidated, - feedsValidated - ).mapN(ConfigYaml.apply) + feedsValidated.map(ConfigYaml.apply) } } } diff --git a/json-log-viewer/jvm/src/test/scala/ru/d10xa/jsonlogviewer/decline/yaml/ConfigYamlLoaderTest.scala b/json-log-viewer/jvm/src/test/scala/ru/d10xa/jsonlogviewer/decline/yaml/ConfigYamlLoaderTest.scala index 3375e79..dd0a087 100644 --- a/json-log-viewer/jvm/src/test/scala/ru/d10xa/jsonlogviewer/decline/yaml/ConfigYamlLoaderTest.scala +++ b/json-log-viewer/jvm/src/test/scala/ru/d10xa/jsonlogviewer/decline/yaml/ConfigYamlLoaderTest.scala @@ -13,13 +13,7 @@ class ConfigYamlLoaderTest extends FunSuite { test("parse valid yaml with feeds") { val yaml = - """|commands: - | - ./mock-logs.sh pod1 - | - ./mock-logs.sh pod2 - |filter: | - | message = 'first line' - |formatIn: json - |feeds: + """|feeds: | - name: "pod-logs" | commands: | - "./mock-logs.sh pod1" @@ -39,12 +33,6 @@ class ConfigYamlLoaderTest extends FunSuite { assert(result.isValid, s"Result should be valid: $result") val config = result.toOption.get - assertEquals(config.formatIn, Some(FormatIn.Json)) - assertEquals( - config.commands.get, - List("./mock-logs.sh pod1", "./mock-logs.sh pod2") - ) - assert(config.filter.isDefined) val feeds = config.feeds.get assertEquals(feeds.size, 2) @@ -69,21 +57,17 @@ class ConfigYamlLoaderTest extends FunSuite { assert(result.isValid, s"Result should be valid for empty yaml: $result") val config = result.toOption.get - assert(config.filter.isEmpty) - assert(config.formatIn.isEmpty) - assert(config.commands.isEmpty) assert(config.feeds.isEmpty) } test("parse invalid yaml") { val yaml = - """formatIn: - | - not a string - |""".stripMargin + """feeds: "" + |""".stripMargin val result = configYamlLoader.parseYamlFile(yaml) assert(result.isInvalid, s"Result should be invalid: $result") val errors = result.swap.toOption.get - assert(errors.exists(_.contains("Invalid 'formatIn' field format"))) + assert(errors.exists(_.contains("Invalid 'feeds' field format, should be a list"))) } } diff --git a/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/LogViewerStream.scala b/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/LogViewerStream.scala index 9909a7e..8dc29a6 100644 --- a/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/LogViewerStream.scala +++ b/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/LogViewerStream.scala @@ -20,9 +20,6 @@ object LogViewerStream { configYamlRef: Ref[IO, Option[ConfigYaml]] ): Stream[IO, String] = { Stream.eval(configYamlRef.get).flatMap { configYamlOpt => - val topCommandsOpt: Option[List[String]] = - configYamlOpt.flatMap(_.commands).filter(_.nonEmpty) - val feedsOpt: Option[List[Feed]] = configYamlOpt.flatMap(_.feeds).filter(_.nonEmpty) @@ -40,15 +37,8 @@ object LogViewerStream { ) } Stream.emits(feedStreams).parJoin(feedStreams.size) - case None => - val baseStream = topCommandsOpt match { - case Some(cmds) => - commandsAndInlineInputToStream(cmds, None) - case None => - stdinLinesStream - } - processStream(config, baseStream, None, None, None) + processStream(config, stdinLinesStream, None, None, None) } finalStream diff --git a/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/decline/yaml/ConfigYaml.scala b/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/decline/yaml/ConfigYaml.scala index c869096..5663a02 100644 --- a/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/decline/yaml/ConfigYaml.scala +++ b/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/decline/yaml/ConfigYaml.scala @@ -1,14 +1,8 @@ package ru.d10xa.jsonlogviewer.decline.yaml -import ru.d10xa.jsonlogviewer.decline.Config -import ru.d10xa.jsonlogviewer.query.QueryAST - case class ConfigYaml( - filter: Option[QueryAST], - formatIn: Option[Config.FormatIn], - commands: Option[List[String]], feeds: Option[List[Feed]] ) object ConfigYaml: - val empty: ConfigYaml = ConfigYaml(None, None, None, None) + val empty: ConfigYaml = ConfigYaml(None) From 1f5445fe395bfa2880180aadb22d3a8741d917e2 Mon Sep 17 00:00:00 2001 From: Andrey Stolyarov Date: Tue, 14 Jan 2025 21:55:50 +0300 Subject: [PATCH 3/4] Supervisor --- .scalafmt.conf | 246 +----------------- .../ru/d10xa/jsonlogviewer/Application.scala | 22 +- .../decline/ConfigInitImpl.scala | 81 +++--- .../d10xa/jsonlogviewer/LogViewerStream.scala | 113 ++++---- .../jsonlogviewer/decline/ConfigInit.scala | 10 +- 5 files changed, 133 insertions(+), 339 deletions(-) diff --git a/.scalafmt.conf b/.scalafmt.conf index 4054b71..e4fc57a 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -1,243 +1,9 @@ -version = "3.7.14" +version = "3.8.4" maxColumn = 80 -docstrings.oneline = unfold -docstrings.removeEmpty = false -docstrings.wrap = yes -docstrings.wrapMaxColumn = null -docstrings.forceBlankLineBefore = null -docstrings.blankFirstLine = no -docstrings.style = SpaceAsterisk -comments.wrap = no -comments.wrapSingleLineMlcAsSlc = false -comments.wrapStandaloneSlcAsSlc = false -optIn.configStyleArguments = true -optIn.breaksInsideChains = false -optIn.breakChainOnFirstMethodDot = true -optIn.encloseClassicChains = false -optIn.selfAnnotationNewline = true -optIn.annotationNewlines = true -optIn.forceBlankLineBeforeDocstring = true -binPack.unsafeCallSite = Never -binPack.unsafeDefnSite = Never -binPack.bracketCallSite = null -binPack.bracketDefnSite = null -binPack.indentCallSiteOnce = false -binPack.indentCallSiteSingleArg = true -binPack.parentConstructors = source -binPack.literalArgumentLists = true -binPack.literalsIncludeSimpleExpr = false -binPack.literalsSingleLine = false -binPack.literalsMinArgCount = 5 -binPack.literalsInclude = [ - ".*" -] -binPack.literalsExclude = [ - String - "Term.Name" -] -indent.main = 2 -indent.significant = null -indent.callSite = 2 -indent.ctrlSite = null +encoding = "UTF-8" +runner.dialect = scala3 indent.defnSite = 2 -indent.caseSite = 2 -indent.matchSite = null -indent.ctorSite = null -indent.extraBeforeOpenParenDefnSite = 0 -indent.relativeToLhsLastLine = [] -indent.fewerBraces = never indent.extendSite = 2 -indent.withSiteRelativeToExtends = 0 -indent.commaSiteRelativeToExtends = 2 -align.allowOverflow = false -align.delayUntilSpace = true -align.multiline = false -align.stripMargin = true -align.closeParenSite = false -align.openBracketCallSite = null -align.openParenCallSite = false -align.openParenCtrlSite = false -align.openBracketDefnSite = null -align.openParenDefnSite = false -align.openParenTupleSite = null -align.beforeOpenParenDefnSite = false -align.beforeOpenParenCallSite = false -align.inInterpolation = false -align.tokens = [ - { - code = "=>" - owner = Case - owners = [] - } -] -align.arrowEnumeratorGenerator = false -align.treeCategory."Defn.Trait" = "class/object/trait/enum" -align.treeCategory."Defn.Object" = "class/object/trait/enum" -align.treeCategory."Defn.Val" = "given/val/var/def" -align.treeCategory."Defn.Enum" = "class/object/trait/enum" -align.treeCategory."Defn.Macro" = "given/val/var/def" -align.treeCategory."Decl.Def" = "given/val/var/def" -align.treeCategory."Defn.Def" = "given/val/var/def" -align.treeCategory."Defn.GivenAlias" = "given/val/var/def" -align.treeCategory."Defn.Var" = "given/val/var/def" -align.treeCategory."Enumerator.Generator" = for -align.treeCategory."Enumerator.Val" = for -align.treeCategory."Defn.Class" = "class/object/trait/enum" -spaces.beforeContextBoundColon = Never -spaces.beforeApplyArgInParens = Never -spaces.beforeInfixArgInParens = Always -spaces.afterTripleEquals = false -spaces.inImportCurlyBraces = false -spaces.inInterpolatedStringCurlyBraces = false -spaces.inParentheses = false -spaces.neverAroundInfixTypes = [] -spaces.afterKeywordBeforeParen = true -spaces.inByNameTypes = true -spaces.afterSymbolicDefs = false -literals.long = Upper -literals.float = Lower -literals.double = Lower -literals.hexDigits = Lower -literals.hexPrefix = Lower -literals.scientific = Lower -lineEndings = unix -rewrite.rules = [] -rewrite.scala3.convertToNewSyntax = false -rewrite.scala3.removeOptionalBraces = no -rewrite.scala3.countEndMarkerLines = all -rewrite.scala3.removeEndMarkerMaxLines = 0 -rewrite.scala3.insertEndMarkerMinLines = 0 -rewrite.insertBraces.minLines = 0 -rewrite.insertBraces.allBlocks = false -rewrite.redundantBraces.defnBodies = all -rewrite.redundantBraces.includeUnitMethods = true -rewrite.redundantBraces.maxBreaks = 100 -rewrite.redundantBraces.stringInterpolation = false -rewrite.redundantBraces.parensForOneLineApply = true -rewrite.redundantBraces.generalExpressions = true -rewrite.redundantBraces.ifElseExpressions = false -rewrite.redundantParens.infixSide = null -rewrite.sortModifiers.order = [ - implicit - final - sealed - abstract - override - private - protected - lazy - open - transparent - inline - infix - opaque -] -rewrite.imports.sort = none -rewrite.imports.expand = false -rewrite.imports.contiguousGroups = only -rewrite.imports.groups = [] -rewrite.preferCurlyFors.removeTrailingSemicolonsOnly = false -rewrite.trailingCommas.allowFolding = true -rewrite.trailingCommas.style = never -rewrite.allowInfixPlaceholderArg = true -rewrite.neverInfix.excludeFilters = [ - until - to - by - eq - ne - "should.*" - "contain.*" - "must.*" - in - ignore - be - taggedAs - thrownBy - synchronized - have - when - size - only - noneOf - oneElementOf - noElementsOf - atLeastOneElementOf - atMostOneElementOf - allElementsOf - inOrderElementsOf - theSameElementsAs -] -indentOperator.exemptScope = null -indentOperator.topLevelOnly = true -indentOperator.includeRegex = ".*" -newlines.avoidInResultType = false -newlines.neverBeforeJsNative = false -newlines.sometimesBeforeColonInMethodReturnType = true -newlines.penalizeSingleSelectMultiArgList = true -newlines.beforeCurlyLambdaParams = never -newlines.topLevelStatementBlankLines = [] -newlines.topLevelStatementsMinBreaks = 1 -newlines.topLevelStatements = [] -newlines.beforeTemplateBodyIfBreakInParentCtors = false -newlines.topLevelBodyIfMinStatements = [] -newlines.topLevelBodyMinStatements = 2 -newlines.afterCurlyLambdaParams = never -newlines.implicitParamListModifierForce = [] -newlines.alwaysBeforeElseAfterCurlyIf = false -newlines.forceBeforeAssign = never -newlines.alwaysBeforeMultilineDef = false -newlines.afterInfixBreakOnNested = false -newlines.afterInfixMaxCountPerExprForSome = 10 -newlines.afterInfixMaxCountPerFile = 500 -newlines.avoidForSimpleOverflow = [] -newlines.inInterpolation = allow -newlines.ignoreInSyntax = true -newlines.avoidAfterYield = true -runner.debug = false -runner.eventCallback = " Unit>" -runner.parser = Source -runner.optimizer.dequeueOnNewStatements = true -runner.optimizer.escapeInPathologicalCases = true -runner.optimizer.maxVisitsPerToken = 10000 -runner.optimizer.maxEscapes = 16 -runner.optimizer.maxDepth = 100 -runner.optimizer.acceptOptimalAtHints = true -runner.optimizer.disableOptimizationsInsideSensitiveAreas = true -runner.optimizer.pruneSlowStates = true -runner.optimizer.recurseOnBlocks = true -runner.optimizer.forceConfigStyleOnOffset = 150 -runner.optimizer.forceConfigStyleMinArgCount = 2 -runner.maxStateVisits = 1000000 -runner.dialect = scala3 -runner.ignoreWarnings = false -runner.fatalWarnings = false -indentYieldKeyword = true -importSelectors = noBinPack -includeCurlyBraceInSelectChains = true -includeNoParensInSelectChains = false -assumeStandardLibraryStripMargin = false -danglingParentheses.callSite = true -danglingParentheses.defnSite = true -danglingParentheses.ctrlSite = true -danglingParentheses.tupleSite = null -danglingParentheses.exclude = null -poorMansTrailingCommasInConfigStyle = false -trailingCommas = null -verticalMultiline.atDefnSite = false -verticalMultiline.arityThreshold = 100 -verticalMultiline.newlineAfterOpenParen = false -verticalAlignMultilineOperators = false -onTestFailure = "" -encoding = "UTF-8" -project.git = false -project.layout = null -project.includePaths = [ - "glob:**.scala" - "glob:**.sbt" - "glob:**.sc" -] -project.excludePaths = [] -project.includeFilters = [] -project.excludeFilters = [] -xmlLiterals.assumeFormatted = false +rewrite.rules = [Imports, RedundantBraces] +rewrite.imports.expand = true +rewrite.imports.sort = original diff --git a/json-log-viewer/jvm/src/main/scala/ru/d10xa/jsonlogviewer/Application.scala b/json-log-viewer/jvm/src/main/scala/ru/d10xa/jsonlogviewer/Application.scala index 9bf47f2..089496d 100644 --- a/json-log-viewer/jvm/src/main/scala/ru/d10xa/jsonlogviewer/Application.scala +++ b/json-log-viewer/jvm/src/main/scala/ru/d10xa/jsonlogviewer/Application.scala @@ -1,8 +1,9 @@ package ru.d10xa.jsonlogviewer import cats.effect.* -import com.monovore.decline.Opts +import cats.effect.std.Supervisor import com.monovore.decline.effect.CommandIOApp +import com.monovore.decline.Opts import fs2.* import ru.d10xa.jsonlogviewer.decline.ConfigInit import ru.d10xa.jsonlogviewer.decline.ConfigInitImpl @@ -17,14 +18,17 @@ object Application private val configInit: ConfigInit = new ConfigInitImpl def main: Opts[IO[ExitCode]] = DeclineOpts.config.map { config => - configInit.initConfigYaml(config).use { configRef => - LogViewerStream - .stream(config, configRef) - .through(text.utf8.encode) - .through(fs2.io.stdout) - .compile - .drain - .as(ExitCode.Success) + Supervisor[IO].use { supervisor => + configInit.initConfigYaml(config, supervisor).use { configRef => + LogViewerStream + .stream(config, configRef) + .through(text.utf8.encode) + .through(fs2.io.stdout) + .compile + .drain + .as(ExitCode.Success) + } } + } diff --git a/json-log-viewer/jvm/src/main/scala/ru/d10xa/jsonlogviewer/decline/ConfigInitImpl.scala b/json-log-viewer/jvm/src/main/scala/ru/d10xa/jsonlogviewer/decline/ConfigInitImpl.scala index 92f31da..dfd1989 100644 --- a/json-log-viewer/jvm/src/main/scala/ru/d10xa/jsonlogviewer/decline/ConfigInitImpl.scala +++ b/json-log-viewer/jvm/src/main/scala/ru/d10xa/jsonlogviewer/decline/ConfigInitImpl.scala @@ -7,27 +7,32 @@ import cats.effect.Resource import fs2.io.file.Files import fs2.io.file.Path import fs2.io.file.Watcher -import ru.d10xa.jsonlogviewer.decline.yaml.ConfigYaml -import ru.d10xa.jsonlogviewer.decline.yaml.ConfigYamlReader import java.io.File +import ru.d10xa.jsonlogviewer.decline.yaml.ConfigYaml +import ru.d10xa.jsonlogviewer.decline.yaml.ConfigYamlReader class ConfigInitImpl extends ConfigInit { override def initConfigYaml( - c: Config + c: Config, + supervisor: Supervisor[IO] ): Resource[IO, Ref[IO, Option[ConfigYaml]]] = { val configFileOpt: Option[Path] = - c.configFile.map(file => Path(file.file)).orElse { - findConfigFile("json-log-viewer", List("yml", "yaml", "YML", "YAML")) - .map(Path.apply) - } - loadConfigRef(configFileOpt) + c.configFile + .map(file => Path(file.file)) + .orElse(findDefaultFile()) + loadConfigRef(configFileOpt, supervisor) } + private def findDefaultFile(): Option[Path] = + findConfigFile("json-log-viewer", List("yml", "yaml", "YML", "YAML")) + .map(Path.apply) + private def loadConfigRef( - configFileOpt: Option[Path] - ): Resource[IO, Ref[IO, Option[ConfigYaml]]] = { + configFileOpt: Option[Path], + supervisor: Supervisor[IO] + ): Resource[IO, Ref[IO, Option[ConfigYaml]]] = for { updatedConfig <- Resource.eval { configFileOpt match { @@ -37,37 +42,39 @@ class ConfigInitImpl extends ConfigInit { } configRef <- Resource.eval(Ref.of[IO, Option[ConfigYaml]](updatedConfig)) _ <- configFileOpt match { - case Some(filePath) => watchFileForChanges(filePath, configRef) - case None => Resource.unit[IO] + case Some(filePath) => + watchFileForChanges( + absolutePath = filePath.absolute, + configRef = configRef, + supervisor = supervisor + ) + case None => Resource.unit[IO] } } yield configRef - } private def watchFileForChanges( - filePath: Path, - configRef: Ref[IO, Option[ConfigYaml]] - ): Resource[IO, Unit] = { - Resource.eval { - Supervisor[IO].use { supervisor => - supervisor.supervise { - Files[IO] - .watch(filePath) - .evalMap { - case Watcher.Event.Modified(_, _) => - for { - updatedConfig <- readConfig(filePath) - _ <- configRef.set(updatedConfig) - } yield () - case _ => IO.unit - } - .compile - .drain - }.void + absolutePath: Path, + configRef: Ref[IO, Option[ConfigYaml]], + supervisor: Supervisor[IO] + ): Resource[IO, Unit] = + val watch: IO[Unit] = Files[IO] + .watch(absolutePath) + .handleErrorWith { e => + fs2.Stream.eval(IO.println(s"Watcher error: ${e.getMessage}")) } - } - } + .evalMap { + case Watcher.Event.Modified(_, _) | Watcher.Event.Created(_, _) => + for { + updatedConfig <- readConfig(absolutePath) + _ <- configRef.set(updatedConfig) + } yield () + case _ => IO.unit + } + .compile + .drain + Resource.eval(supervisor.supervise(watch).void) - private def readConfig(filePath: Path): IO[Option[ConfigYaml]] = { + private def readConfig(filePath: Path): IO[Option[ConfigYaml]] = ConfigYamlReader.fromYamlFile(filePath.toString).flatMap { case cats.data.Validated.Valid(configYaml) => IO.pure(Some(configYaml)) @@ -75,16 +82,14 @@ class ConfigInitImpl extends ConfigInit { IO.println(s"Failed to parse config: ${errors.toList.mkString(", ")}") .as(None) } - } private def findConfigFile( baseName: String, extensions: List[String] - ): Option[String] = { + ): Option[String] = extensions.collectFirst { case ext if new File(s"$baseName.$ext").exists() => s"$baseName.$ext" } - } } diff --git a/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/LogViewerStream.scala b/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/LogViewerStream.scala index 8dc29a6..4181fc6 100644 --- a/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/LogViewerStream.scala +++ b/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/LogViewerStream.scala @@ -1,11 +1,14 @@ package ru.d10xa.jsonlogviewer -import cats.effect.{IO, Ref} +import cats.effect.IO +import cats.effect.Ref import fs2.* import ru.d10xa.jsonlogviewer.decline.Config import ru.d10xa.jsonlogviewer.decline.Config.FormatIn -import ru.d10xa.jsonlogviewer.decline.yaml.{ConfigYaml, Feed} -import ru.d10xa.jsonlogviewer.formatout.{ColorLineFormatter, RawFormatter} +import ru.d10xa.jsonlogviewer.decline.yaml.ConfigYaml +import ru.d10xa.jsonlogviewer.decline.yaml.Feed +import ru.d10xa.jsonlogviewer.formatout.ColorLineFormatter +import ru.d10xa.jsonlogviewer.formatout.RawFormatter import ru.d10xa.jsonlogviewer.logfmt.LogfmtLogLineParser import ru.d10xa.jsonlogviewer.query.QueryAST import ru.d10xa.jsonlogviewer.shell.ShellImpl @@ -25,20 +28,19 @@ object LogViewerStream { val finalStream = feedsOpt match { case Some(feeds) => - val feedStreams = feeds.map { feed => + val feedStreams = feeds.zipWithIndex.map { (feed, index) => val feedStream: Stream[IO, String] = commandsAndInlineInputToStream(feed.commands, feed.inlineInput) processStream( config, feedStream, - feed.filter, - feed.formatIn, - feed.name + configYamlRef, + index ) } Stream.emits(feedStreams).parJoin(feedStreams.size) case None => - processStream(config, stdinLinesStream, None, None, None) + processStream(config, stdinLinesStream, configYamlRef, -1) } finalStream @@ -54,48 +56,7 @@ object LogViewerStream { new ShellImpl().mergeCommandsAndInlineInput(commands, inlineInput) } - private def processStream( - baseConfig: Config, - lines: Stream[IO, String], - feedFilter: Option[QueryAST], - feedFormatIn: Option[FormatIn], - feedName: Option[String] - ): Stream[IO, String] = { - val effectiveFormatIn = feedFormatIn.orElse(baseConfig.formatIn) - val effectiveFilter = feedFilter.orElse(baseConfig.filter) - val effectiveConfig = baseConfig.copy( - filter = effectiveFilter, - formatIn = effectiveFormatIn - ) - - val timestampFilter = TimestampFilter() - val parseResultKeys = ParseResultKeys(effectiveConfig) - val logLineFilter = LogLineFilter(effectiveConfig, parseResultKeys) - val logLineParser = makeLogLineParser(effectiveConfig, effectiveFormatIn) - val outputLineFormatter = effectiveConfig.formatOut match - case Some(Config.FormatOut.Raw) => RawFormatter() - case Some(Config.FormatOut.Pretty) | None => - ColorLineFormatter(effectiveConfig, feedName) - - lines - .map { it => - logLineParser.parse(it) - } - .filter(logLineFilter.grep) - .filter(logLineFilter.logLineQueryPredicate) - .through( - timestampFilter.filterTimestampAfter(effectiveConfig.timestamp.after) - ) - .through( - timestampFilter.filterTimestampBefore( - effectiveConfig.timestamp.before - ) - ) - .map(outputLineFormatter.formatLine) - .map(_.toString) - } - - private def makeLogLineParser( + def makeLogLineParser( config: Config, optFormatIn: Option[FormatIn] ): LogLineParser = { @@ -105,4 +66,56 @@ object LogViewerStream { case _ => JsonLogLineParser(config, jsonPrefixPostfix) } } + + private def processStream( + baseConfig: Config, + lines: Stream[IO, String], + configYamlRef: Ref[IO, Option[ConfigYaml]], + index: Int + ): Stream[IO, String] = { + for { + line <- lines + optConfigYaml <- Stream.eval(configYamlRef.get) + formatIn = optConfigYaml + .flatMap(_.feeds) + .flatMap(_.lift(index).flatMap(_.formatIn)) + .orElse(baseConfig.formatIn) + filter = optConfigYaml + .flatMap(_.feeds) + .flatMap(_.lift(index).flatMap(_.filter)) + .orElse(baseConfig.filter) + feedName = optConfigYaml + .flatMap(_.feeds) + .flatMap(_.lift(index).flatMap(_.name)) + effectiveConfig = baseConfig.copy( + filter = filter, + formatIn = formatIn + ) + timestampFilter = TimestampFilter() + parseResultKeys = ParseResultKeys(effectiveConfig) + logLineFilter = LogLineFilter(effectiveConfig, parseResultKeys) + logLineParser = makeLogLineParser(effectiveConfig, formatIn) + outputLineFormatter = effectiveConfig.formatOut match + case Some(Config.FormatOut.Raw) => RawFormatter() + case Some(Config.FormatOut.Pretty) | None => + ColorLineFormatter(effectiveConfig, feedName) + + evaluatedLine <- Stream + .emit(logLineParser.parse(line)) + .filter(logLineFilter.grep) + .filter(logLineFilter.logLineQueryPredicate) + .through( + timestampFilter.filterTimestampAfter(effectiveConfig.timestamp.after) + ) + .through( + timestampFilter.filterTimestampBefore( + effectiveConfig.timestamp.before + ) + ) + .map(outputLineFormatter.formatLine) + .map(_.toString) + } yield evaluatedLine + + } + } diff --git a/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/decline/ConfigInit.scala b/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/decline/ConfigInit.scala index 040f2aa..3537d23 100644 --- a/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/decline/ConfigInit.scala +++ b/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/decline/ConfigInit.scala @@ -1,8 +1,14 @@ package ru.d10xa.jsonlogviewer.decline -import cats.effect.{IO, Ref, Resource} +import cats.effect.std.Supervisor +import cats.effect.IO +import cats.effect.Ref +import cats.effect.Resource import ru.d10xa.jsonlogviewer.decline.yaml.ConfigYaml trait ConfigInit { - def initConfigYaml(c: Config): Resource[IO, Ref[IO, Option[ConfigYaml]]] + def initConfigYaml( + c: Config, + supervisor: Supervisor[IO] + ): Resource[IO, Ref[IO, Option[ConfigYaml]]] } From 729132da9d6bf6f48a3f7623ff11d37fe43c3baf Mon Sep 17 00:00:00 2001 From: Andrey Stolyarov Date: Thu, 16 Jan 2025 20:47:53 +0300 Subject: [PATCH 4/4] Add Ref to frontend --- .../ru/d10xa/jsonlogviewer/ViewElement.scala | 43 +++++++++---------- .../decline/ConfigInitImpl.scala | 17 ++++---- .../logfmt/LogFmtTokenParser.scala | 2 + 3 files changed, 32 insertions(+), 30 deletions(-) diff --git a/frontend-laminar/src/main/scala/ru/d10xa/jsonlogviewer/ViewElement.scala b/frontend-laminar/src/main/scala/ru/d10xa/jsonlogviewer/ViewElement.scala index 2a3a8cc..32ea829 100644 --- a/frontend-laminar/src/main/scala/ru/d10xa/jsonlogviewer/ViewElement.scala +++ b/frontend-laminar/src/main/scala/ru/d10xa/jsonlogviewer/ViewElement.scala @@ -1,16 +1,17 @@ package ru.d10xa.jsonlogviewer -import cats.effect.IO import cats.effect.unsafe.implicits.global +import cats.effect.IO +import cats.effect.Ref import com.monovore.decline.Help import com.raquo.airstream.core.Signal import com.raquo.airstream.eventbus.EventBus import com.raquo.airstream.ownership.Owner -import com.raquo.laminar.DomApi import com.raquo.laminar.api.L.* -import ru.d10xa.jsonlogviewer.decline.Config +import com.raquo.laminar.DomApi import ru.d10xa.jsonlogviewer.decline.yaml.ConfigYaml import ru.d10xa.jsonlogviewer.decline.yaml.Feed +import ru.d10xa.jsonlogviewer.decline.Config import scala.util.chaining.* @@ -23,23 +24,16 @@ object ViewElement { .pipe(DomApi.unsafeParseHtmlString) .pipe(foreignHtmlElement) - def modifyConfigForInlineInput(string: String, config: Config): Config = - config.copy(configYaml = - Some( - ConfigYaml( - filter = None, - formatIn = None, - commands = None, - feeds = Some( - List( - Feed( - name = None, - commands = List.empty, - inlineInput = Some(string), - filter = config.filter, - formatIn = config.formatIn - ) - ) + def makeConfigYamlForInlineInput(string: String, config: Config): ConfigYaml = + ConfigYaml( + feeds = Some( + List( + Feed( + name = None, + commands = List.empty, + inlineInput = Some(string), + filter = config.filter, + formatIn = config.formatIn ) ) ) @@ -54,8 +48,13 @@ object ViewElement { .combineWith(configSignal) .foreach { case (string, Right(c)) => - LogViewerStream - .stream(modifyConfigForInlineInput(string, c)) + val configYamlRefIO = + Ref.of[IO, Option[ConfigYaml]]( + Some(makeConfigYamlForInlineInput(string, c)) + ) + fs2.Stream + .eval(configYamlRefIO) + .flatMap(configYamlRef => LogViewerStream.stream(c, configYamlRef)) .compile .toList .map(stringsToHtmlElement) diff --git a/json-log-viewer/js/src/main/scala/ru/d10xa/jsonlogviewer/decline/ConfigInitImpl.scala b/json-log-viewer/js/src/main/scala/ru/d10xa/jsonlogviewer/decline/ConfigInitImpl.scala index 811d241..c78acf5 100644 --- a/json-log-viewer/js/src/main/scala/ru/d10xa/jsonlogviewer/decline/ConfigInitImpl.scala +++ b/json-log-viewer/js/src/main/scala/ru/d10xa/jsonlogviewer/decline/ConfigInitImpl.scala @@ -1,16 +1,17 @@ package ru.d10xa.jsonlogviewer.decline +import cats.effect.std.Supervisor import cats.effect.IO +import cats.effect.Ref +import cats.effect.Resource +import ru.d10xa.jsonlogviewer.decline.yaml.ConfigYaml import ru.d10xa.jsonlogviewer.decline.Config.FormatIn class ConfigInitImpl extends ConfigInit { - override def initConfig(c: Config): IO[Config] = { - IO.pure( - c.copy( - formatIn = c.formatIn.orElse(Some(FormatIn.Json)), - filter = c.filter - ) - ) - } + override def initConfigYaml( + c: Config, + supervisor: Supervisor[IO] + ): Resource[IO, Ref[IO, Option[ConfigYaml]]] = + Resource.eval(Ref.of(None)) } diff --git a/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/logfmt/LogFmtTokenParser.scala b/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/logfmt/LogFmtTokenParser.scala index 40127ca..5615f89 100644 --- a/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/logfmt/LogFmtTokenParser.scala +++ b/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/logfmt/LogFmtTokenParser.scala @@ -66,4 +66,6 @@ object LogFmtTokenParser extends PackratParsers: program(reader) match { case NoSuccess(msg, next) => Left(TokenParserError(msg)) case Success(result, next) => Right(result) + case Failure(msg, _) => Left(TokenParserError(msg)) + case Error(msg, _) => Left(TokenParserError(msg)) }