From 50c507be4d9985597b942e368194fe5c8d042821 Mon Sep 17 00:00:00 2001 From: Andrey Stolyarov Date: Thu, 5 Dec 2024 21:48:12 +0300 Subject: [PATCH] Add argument format-out --- .../src/main/resources/index-fullopt.html | 1 + frontend-laminar/src/main/scala/App.scala | 27 +++++++++++++++++-- .../src/main/scala/ViewElement.scala | 4 +-- .../ru/d10xa/jsonlogviewer/Application.scala | 5 +++- .../d10xa/jsonlogviewer/LogViewerStream.scala | 7 ++++- .../d10xa/jsonlogviewer/decline/Config.scala | 6 ++++- .../jsonlogviewer/decline/DeclineOpts.scala | 8 +++++- .../decline/FormatOutValidator.scala | 16 +++++++++++ .../{ => formatout}/ColorLineFormatter.scala | 4 ++- .../formatout/RawFormatter.scala | 12 +++++++++ .../query/LogLineQueryPredicateImplTest.scala | 3 ++- 11 files changed, 83 insertions(+), 10 deletions(-) create mode 100644 json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/decline/FormatOutValidator.scala rename json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/{ => formatout}/ColorLineFormatter.scala (96%) create mode 100644 json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/formatout/RawFormatter.scala diff --git a/frontend-laminar/src/main/resources/index-fullopt.html b/frontend-laminar/src/main/resources/index-fullopt.html index 5350917..8e5b39d 100644 --- a/frontend-laminar/src/main/resources/index-fullopt.html +++ b/frontend-laminar/src/main/resources/index-fullopt.html @@ -4,6 +4,7 @@ [FULL] json-log-viewer + diff --git a/frontend-laminar/src/main/scala/App.scala b/frontend-laminar/src/main/scala/App.scala index b73a2f7..f7dca2d 100644 --- a/frontend-laminar/src/main/scala/App.scala +++ b/frontend-laminar/src/main/scala/App.scala @@ -10,6 +10,7 @@ import org.scalajs.dom import org.scalajs.dom.HTMLButtonElement import org.scalajs.dom.HTMLDivElement import ru.d10xa.jsonlogviewer.decline.Config.FormatIn +import ru.d10xa.jsonlogviewer.decline.Config.FormatOut import ru.d10xa.jsonlogviewer.decline.Config.FormatIn.Json import ru.d10xa.jsonlogviewer.decline.Config.FormatIn.Logfmt import ru.d10xa.jsonlogviewer.decline.Config @@ -49,6 +50,9 @@ object App { val formatInVar: Var[FormatIn] = Var( FormatIn.Json ) + val formatOutVar: Var[FormatOut] = Var( + FormatOut.Pretty + ) val splitPattern: Regex = "([^\"]\\S*|\".+?\")\\s*".r def splitArgs(s: String): Seq[String] = @@ -61,12 +65,13 @@ object App { cli <- cliVar.signal filterString <- filterVar.signal formatIn <- formatInVar.signal + formatOut <- formatOutVar.signal filter = QueryCompiler(filterString) match case Left(value) => None case Right(value) => Some(value) } yield DeclineOpts.command .parse(splitArgs(cli)) - .map(cfg => cfg.copy(filter = filter, formatIn = Some(formatIn))) + .map(cfg => cfg.copy(filter = filter, formatIn = Some(formatIn), formatOut = Some(formatOut))) def main(args: Array[String]): Unit = { lazy val container = dom.document.getElementById("app-container") @@ -125,6 +130,22 @@ object App { option(value := "logfmt", "logfmt") ) ) + def formatOutDiv: ReactiveHtmlElement[HTMLDivElement] = div( + label("--format-out", cls := "col-2"), + select( + cls := "col-1", + value <-- formatOutVar.signal.map { + case FormatOut.Raw => "raw" + case FormatOut.Pretty => "pretty" + }, + onChange.mapToValue.map { + case "raw" => FormatOut.Raw + case "pretty" => FormatOut.Pretty + } --> formatOutVar, + option(value := "pretty", "pretty"), + option(value := "raw", "raw") + ) + ) def filterDiv: ReactiveHtmlElement[HTMLDivElement] = div( cls := "row-fluid", @@ -137,7 +158,7 @@ object App { onInput.mapToValue --> filterVar ) ) - ) +) def additionalArgsDiv: ReactiveHtmlElement[HTMLDivElement] = div( cls := "row-fluid", @@ -174,6 +195,7 @@ object App { private def renderLivePage(): HtmlElement = { div( formatInDiv, + formatOutDiv, filterDiv, additionalArgsDiv, buttonGenerateLogs, @@ -197,6 +219,7 @@ object App { private def renderEditPage(): HtmlElement = { div( formatInDiv, + formatOutDiv, filterDiv, additionalArgsDiv, buttonGenerateLogs, diff --git a/frontend-laminar/src/main/scala/ViewElement.scala b/frontend-laminar/src/main/scala/ViewElement.scala index 5666150..80fc995 100644 --- a/frontend-laminar/src/main/scala/ViewElement.scala +++ b/frontend-laminar/src/main/scala/ViewElement.scala @@ -9,7 +9,6 @@ import ru.d10xa.jsonlogviewer.JsonDetector import ru.d10xa.jsonlogviewer.JsonPrefixPostfix import ru.d10xa.jsonlogviewer.JsonLogLineParser import ru.d10xa.jsonlogviewer.TimestampFilter -import ru.d10xa.jsonlogviewer.ColorLineFormatter import ru.d10xa.jsonlogviewer.LogViewerStream import ru.d10xa.jsonlogviewer.LogLineFilter import fs2.* @@ -18,6 +17,7 @@ import ru.d10xa.jsonlogviewer.decline.Config import ru.d10xa.jsonlogviewer.decline.Config import ru.d10xa.jsonlogviewer.decline.TimestampConfig import ru.d10xa.jsonlogviewer.decline.TimestampConfig +import ru.d10xa.jsonlogviewer.formatout.ColorLineFormatter import ru.d10xa.jsonlogviewer.logfmt.LogfmtLogLineParser import scala.util.chaining.scalaUtilChainingOps @@ -55,7 +55,7 @@ object ViewElement { configSignal: Signal[Either[Help, Config]] ): HtmlElement = pre( - cls := "bg-dark font-monospace", + cls := "bg-dark font-monospace text-white", child <-- runApp(logLinesSignal, configSignal) ) diff --git a/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/Application.scala b/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/Application.scala index f01a961..7e855ce 100644 --- a/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/Application.scala +++ b/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/Application.scala @@ -12,6 +12,7 @@ import ru.d10xa.jsonlogviewer.decline.DeclineOpts import ru.d10xa.jsonlogviewer.logfmt.LogfmtLogLineParser import _root_.io.circe.yaml.scalayaml.parser import cats.syntax.all.* +import ru.d10xa.jsonlogviewer.decline.ConfigInit import ru.d10xa.jsonlogviewer.decline.ConfigInitImpl import ru.d10xa.jsonlogviewer.decline.ConfigYaml @@ -26,8 +27,10 @@ object Application .repartition(s => Chunk.array(s.split("\n", -1))) .filter(_.nonEmpty) + private val configInit: ConfigInit = new ConfigInitImpl + def main: Opts[IO[ExitCode]] = DeclineOpts.config.map { c => - new ConfigInitImpl().initConfig(c).flatMap { updatedConfig => + configInit.initConfig(c).flatMap { updatedConfig => IO { val jsonPrefixPostfix = JsonPrefixPostfix(JsonDetector()) val logLineParser = updatedConfig.formatIn match { 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 f321852..9c2ef63 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 @@ -3,6 +3,8 @@ package ru.d10xa.jsonlogviewer import fs2.* import fs2.io.* import ru.d10xa.jsonlogviewer.decline.Config +import ru.d10xa.jsonlogviewer.formatout.ColorLineFormatter +import ru.d10xa.jsonlogviewer.formatout.RawFormatter object LogViewerStream { def stream[F[_]]( @@ -10,7 +12,10 @@ object LogViewerStream { logLineParser: LogLineParser ): Pipe[F, String, String] = stream => val timestampFilter = TimestampFilter() - val outputLineFormatter = ColorLineFormatter(config) + val outputLineFormatter = config.formatOut match + case Some(Config.FormatOut.Raw) => RawFormatter() + case Some(Config.FormatOut.Pretty) | None => ColorLineFormatter(config) + val parseResultKeys = ParseResultKeys(config) val logLineFilter = LogLineFilter(config, parseResultKeys) stream 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 4e28364..0bf5698 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 @@ -13,7 +13,8 @@ final case class Config( timestamp: TimestampConfig, grep: List[ConfigGrep], filter: Option[QueryAST], - formatIn: Option[Config.FormatIn] + formatIn: Option[Config.FormatIn], + formatOut: Option[Config.FormatOut], ) object Config: @@ -21,5 +22,8 @@ object Config: enum FormatIn: case Json, Logfmt + + enum FormatOut: + case Pretty, Raw end Config 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 6af8fc7..b7fcaa1 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 @@ -9,6 +9,7 @@ import com.monovore.decline.Opts import com.monovore.decline.time.* import ru.d10xa.jsonlogviewer.decline.Config.ConfigGrep import ru.d10xa.jsonlogviewer.decline.Config.FormatIn +import ru.d10xa.jsonlogviewer.decline.Config.FormatOut import ru.d10xa.jsonlogviewer.query.QueryAST import ru.d10xa.jsonlogviewer.query.QueryCompiler @@ -46,6 +47,11 @@ object DeclineOpts { .option[String]("format-in", help = "json, logfmt") .mapValidated(FormatInValidator.toValidatedFormatIn) .orNone + + val formatOut: Opts[Option[FormatOut]] = Opts + .option[String]("format-out", help = "pretty, raw") + .mapValidated(FormatOutValidator.toValidatedFormatOut) + .orNone def timestampConfig: Opts[TimestampConfig] = (timestampField, timestampAfter, timestampBefore) @@ -57,7 +63,7 @@ object DeclineOpts { .orNone val config: Opts[Config] = - (configFile, timestampConfig, grepConfig, filterConfig, formatIn) + (configFile, timestampConfig, grepConfig, filterConfig, formatIn, formatOut) .mapN(Config.apply) val command: Command[Config] = Command( diff --git a/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/decline/FormatOutValidator.scala b/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/decline/FormatOutValidator.scala new file mode 100644 index 0000000..c86966b --- /dev/null +++ b/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/decline/FormatOutValidator.scala @@ -0,0 +1,16 @@ +package ru.d10xa.jsonlogviewer.decline + +import cats.data.NonEmptyList +import cats.data.Validated +import cats.data.ValidatedNel +import ru.d10xa.jsonlogviewer.decline.Config.FormatIn +import ru.d10xa.jsonlogviewer.decline.Config.FormatOut + +object FormatOutValidator { + def toValidatedFormatOut( + str: String + ): Validated[NonEmptyList[String], FormatOut] = str match + case "pretty" => Validated.valid(FormatOut.Pretty) + case "raw" => Validated.valid(FormatOut.Raw) + case other => Validated.invalidNel(s"Wrong format: $other") +} diff --git a/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/ColorLineFormatter.scala b/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/formatout/ColorLineFormatter.scala similarity index 96% rename from json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/ColorLineFormatter.scala rename to json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/formatout/ColorLineFormatter.scala index 34d159e..32dcd83 100644 --- a/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/ColorLineFormatter.scala +++ b/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/formatout/ColorLineFormatter.scala @@ -1,8 +1,10 @@ -package ru.d10xa.jsonlogviewer +package ru.d10xa.jsonlogviewer.formatout import fansi.ErrorMode.Strip import fansi.EscapeAttr import fansi.Str +import ru.d10xa.jsonlogviewer.OutputLineFormatter +import ru.d10xa.jsonlogviewer.ParseResult import ru.d10xa.jsonlogviewer.decline.Config class ColorLineFormatter(c: Config) extends OutputLineFormatter: diff --git a/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/formatout/RawFormatter.scala b/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/formatout/RawFormatter.scala new file mode 100644 index 0000000..3ed4fe6 --- /dev/null +++ b/json-log-viewer/shared/src/main/scala/ru/d10xa/jsonlogviewer/formatout/RawFormatter.scala @@ -0,0 +1,12 @@ +package ru.d10xa.jsonlogviewer.formatout + +import fansi.ErrorMode.Strip +import fansi.EscapeAttr +import fansi.Str +import ru.d10xa.jsonlogviewer.OutputLineFormatter +import ru.d10xa.jsonlogviewer.ParseResult +import ru.d10xa.jsonlogviewer.decline.Config + +class RawFormatter extends OutputLineFormatter: + override def formatLine(p: ParseResult): Str = + p.raw 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 ca8a286..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 @@ -90,7 +90,8 @@ class LogLineQueryPredicateImplTest extends munit.FunSuite { ), grep = List.empty, filter = None, - formatIn = None + formatIn = None, + formatOut = None ) private lazy val parseResultKeys = new ParseResultKeys(config = config)