-
Notifications
You must be signed in to change notification settings - Fork 20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add position formatter #90
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,7 +2,8 @@ package io.odin.formatter | |
|
||
import cats.syntax.show._ | ||
import io.odin.LoggerMessage | ||
import io.odin.formatter.options.ThrowableFormat | ||
import io.odin.formatter.options.{PositionFormat, ThrowableFormat} | ||
import io.odin.meta.Position | ||
import perfolation._ | ||
|
||
import scala.annotation.tailrec | ||
|
@@ -16,31 +17,31 @@ object Formatter { | |
|
||
val BRIGHT_BLACK = "\u001b[30;1m" | ||
|
||
val default: Formatter = Formatter.create(ThrowableFormat.Default, colorful = false) | ||
val default: Formatter = Formatter.create(ThrowableFormat.Default, PositionFormat.Full, colorful = false) | ||
|
||
val colorful: Formatter = Formatter.create(ThrowableFormat.Default, colorful = true) | ||
val colorful: Formatter = Formatter.create(ThrowableFormat.Default, PositionFormat.Full, colorful = true) | ||
|
||
def create(throwableFormat: ThrowableFormat, colorful: Boolean): Formatter = | ||
create(throwableFormat, PositionFormat.Full, colorful) | ||
|
||
/** | ||
* Creates new formatter with provided options | ||
* | ||
* @param throwableFormat @see [[formatThrowable]] | ||
* @param positionFormat @see [[formatPosition]] | ||
* @param colorful use different color for thread name, level, position and throwable | ||
*/ | ||
def create(throwableFormat: ThrowableFormat, colorful: Boolean): Formatter = { | ||
def create(throwableFormat: ThrowableFormat, positionFormat: PositionFormat, colorful: Boolean): Formatter = { | ||
|
||
@inline def withColor(color: String, message: String): String = | ||
if (colorful) p"$color$message$RESET" else message | ||
|
||
(msg: LoggerMessage) => { | ||
val ctx = withColor(MAGENTA, formatCtx(msg.context)) | ||
val timestamp = p"${msg.timestamp.t.F}T${msg.timestamp.t.T},${msg.timestamp.t.milliOfSecond}" | ||
val timestamp = formatTimestamp(msg.timestamp) | ||
val threadName = withColor(GREEN, msg.threadName) | ||
val level = withColor(BRIGHT_BLACK, msg.level.show) | ||
|
||
val position = { | ||
val lineNumber = if (msg.position.line >= 0) p":${msg.position.line}" else "" | ||
withColor(BLUE, p"${msg.position.enclosureName}$lineNumber") | ||
} | ||
val position = withColor(BLUE, formatPosition(msg.position, positionFormat)) | ||
|
||
val throwable = msg.exception match { | ||
case Some(t) => | ||
|
@@ -67,6 +68,35 @@ object Formatter { | |
builder.toString() | ||
} | ||
|
||
/** | ||
* Formats timestamp using the following format: yyyy-MM-ddTHH:mm:ss,SSS | ||
*/ | ||
def formatTimestamp(timestamp: Long): String = { | ||
val date = timestamp.t | ||
p"${date.F}T${date.T},${date.milliOfSecond}" | ||
} | ||
|
||
/** | ||
* The result differs depending on the format: | ||
* | ||
* `PositionFormat.Full` - prints full position | ||
* 'io.odin.formatter.Formatter formatPosition:75' formatted as 'io.odin.formatter.Formatter formatPosition:75' | ||
* | ||
* `PositionFormat.AbbreviatePackage` - prints abbreviated package and full enclosing | ||
* 'io.odin.formatter.Formatter formatPosition:75' formatted as 'i.o.f.Formatter formatPosition:75' | ||
*/ | ||
def formatPosition(position: Position, format: PositionFormat): String = { | ||
val lineNumber = if (position.line >= 0) p":${position.line}" else "" | ||
|
||
val enclosure = format match { | ||
case PositionFormat.Full => position.enclosureName | ||
case PositionFormat.AbbreviatePackage => abbreviate(position.enclosureName) | ||
|
||
} | ||
|
||
p"$enclosure$lineNumber" | ||
} | ||
|
||
/** | ||
* Default Throwable printer is twice as slow. This method was borrowed from scribe library. | ||
* | ||
|
@@ -127,4 +157,24 @@ object Formatter { | |
writeStackTrace(b, elements.tail, indent) | ||
} | ||
} | ||
|
||
private def abbreviate(enclosure: String): String = { | ||
@tailrec | ||
def loop(input: Array[String], builder: StringBuilder): StringBuilder = { | ||
input.length match { | ||
case 0 => builder | ||
case 1 => builder.append(input.head) | ||
case _ => | ||
val head = input.head | ||
val b = if (head.isEmpty) builder.append(questionMark) else builder.append(head.head) | ||
loop(input.tail, b.append(dot)) | ||
} | ||
} | ||
|
||
loop(enclosure.split('.'), new StringBuilder).toString() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's reuse There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah right, it's a special symbol. Nvm then, it's not worth it |
||
} | ||
|
||
private val questionMark = "?" | ||
private val dot = "." | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package io.odin.formatter.options | ||
|
||
sealed trait PositionFormat | ||
|
||
object PositionFormat { | ||
final case object Full extends PositionFormat | ||
final case object AbbreviatePackage extends PositionFormat | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ooops, you're breaking already released API here. Either create overloaded method
create
that takes three arguments, or put it in the end of arguments list and give it a default valueThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added overloaded methods to
Formatter
andcirce.Formatter
.