Echopraxia is a structured logging framework that can organize arguments into key/value fields using Scala's implicit type safe mapping system, without any additional import tax.
These scalafix rules are useful for adding flow loggers to methods, and rewriting logging statements that use string interpolation to use Echopraxia's FieldBuilder API.
Add scalafix to project/plugins.sbt
:
addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.10.4")
If you want to include the scalafix rules as part of the project to run automatically:
Add echopraxia-scalafix to build.sbt
and enable semanticDB:
ThisBuild / scalafixDependencies += "com.tersesystems.echopraxia" %% "scalafix" % VERSION
ThisBuild / semanticdbEnabled := true
ThisBuild / semanticdbVersion := scalafixSemanticdb.revision
And then add rules to .scalafix.conf
as per configuration:
rules = [
EchopraxiaRewriteToStructured
]
Most likely you will want to use the sbt integration and do it from inside there, using the external rules:
This scalafix rule will rewrite statements that use string interpolation to structured arguments.
To run immediately (without build.sbt
changes):
scalafixEnable
scalafix dependency:EchopraxiaRewriteToStructured@com.tersesystems.echopraxia:scalafix:$VERSION
Given a logging statement that uses string interpolation, the EchopraxiaRewriteToStructured
rule will rewrite:
private val logger = com.tersesystems.echopraxia.plusscala.LoggerFactory.getLogger
final def someMethod: Unit = {
val world = "world"
val count = 2
logger.info(s"hello $world there are $count args")
}
would be rewritten as:
private val logger = com.tersesystems.echopraxia.plusscala.LoggerFactory.getLogger
final def someMethod: Unit = {
val world = "world"
val count = 2
logger.info("hello {} there are {} args", fb => fb.list(fb.value("world", world), fb.value("count", count)))
}
The rule can work when there is a single exception:
final def someMethod(e: Exception): Unit = {
val error = "some error text"
logger.error(s"error $error", e)
}
but will not change the statement when there are other arguments or more than one exception.
You can change the class of the logger as appropriate, if you have a custom logger, and change the method used:
// .scalafix.conf
rules = [
EchopraxiaRewriteToStructured
]
EchopraxiaRewriteToStructured.loggerClass = com.example.MyLogger
EchopraxiaRewriteToStructured.fieldBuilderMethod=keyValue
This scalafix rule will wrap methods in a flow logger block, using a flow or trace logger.
To run immediately (without build.sbt
changes):
scalafixEnable
scalafix dependency:EchopraxiaWrapMethodWithLogger@com.tersesystems.echopraxia:scalafix:VERSION
The given method:
object Main {
private val flowLogger = FlowLoggerFactory.getLogger(getClass)
def add(first: Int, second: Int): Int = {
first + second
}
}
would be rewritten as:
object Main {
private val flowLogger = FlowLoggerFactory.getLogger(getClass)
def add(first: Int, second: Int): Int = flowLogger.trace {
first + second
}
}
Add the configuration to .scalafix.conf
// .scalafix.conf
rules = [
EchopraxiaWrapMethodWithLogger
]
# The name of the logger variable to use, i.e. `flowLogger`
EchopraxiaWrapMethodWithLogger.loggerName = flowLogger
# The method call on the logger, i.e. `flowLogger.trace`
EchopraxiaWrapMethodWithLogger.loggerMethod = trace
# The access modifier to use for wrapping methods, by default only public methods are wrapped.
EchopraxiaWrapMethodWithLogger.methodAccess = public