Open sschuberth opened 2 months ago
I realize #99 might be a bit related, though I do not want to write to a file.
I can see something like that being useful. On JVM at least, you can also redirect all of stdout through mordant: https://github.com/ajalt/mordant/issues/171#issuecomment-2131244827
Yeah, though a Mordant log appender which would allow you to redirect all log output e.g. to a Mordant table cell / panel would really be nice, I guess.
A Mordant appender would be great
I have an internal app framework that wraps Mordant and it does this. At some point I hope to be able to contribute some of this stuff upstream, but unfortunately I don't have a whole lot of time to work on it. The gist is:
class RedirectingTerminalInterface(
private val stdOut: PrintStream,
private val stdErr: PrintStream,
private val delegate: TerminalInterface
) : TerminalInterface by delegate {
override fun completePrintRequest(request: PrintRequest) {
val target = if (request.stderr) stdErr else stdOut
if (request.trailingLinebreak) {
if (request.text.isEmpty()) {
target.println()
} else {
target.println(request.text)
}
} else {
target.print(request.text)
}
}
override fun readLineOrNull(hideInput: Boolean): String? {
if (hideInput) {
val console = System.console()
if (console != null) {
// Workaround to a bug in macOS Terminal: if we don't send anything in the prompt to readPassword, the little "key" glyph
// that indicates the input isn't going to be echoed doesn't display consistently. So we send the ANSI "reset" escape, which
// doesn't really do anything.
//
// TODO(low): Is this still required after the upgrade to Mordant 2.6?
return console.readPassword("\u001B[m")?.concatToString()
}
}
return readlnOrNull()
}
}
private class PrintStreamWrapper(private val terminal: Terminal, target: PrintStream) : PrintStream(target) {
override fun print(obj: Any?) {
// TODO: Accept progress report objects.
print(obj?.toString())
}
override fun print(s: String?) {
// Work around a bug in Mordant.
if (s != null && s.endsWith('\n'))
terminal.println(s)
else
terminal.print(s)
}
override fun print(b: Boolean) {
terminal.print(b)
}
override fun print(c: Char) {
terminal.print(c)
}
override fun print(i: Int) {
terminal.print(i)
}
override fun print(l: Long) {
terminal.print(l)
}
override fun print(f: Float) {
terminal.print(f)
}
override fun print(d: Double) {
terminal.print(d)
}
override fun print(s: CharArray) {
terminal.print(s)
}
override fun println() {
terminal.println()
}
override fun println(x: Boolean) {
terminal.println(x)
}
override fun println(x: Char) {
terminal.println(x)
}
override fun println(x: Int) {
terminal.println(x)
}
override fun println(x: Long) {
terminal.println(x)
}
override fun println(x: Float) {
terminal.println(x)
}
override fun println(x: Double) {
terminal.println(x)
}
override fun println(x: CharArray) {
terminal.println(x)
}
override fun println(x: String?) {
terminal.println(x)
}
}
val terminal = Terminal(terminalInterface = RedirectingTerminalInterface(System.out, System.err, Terminal().terminalInterface))
// Ensure printing to stdout still works and pushes the messages _above_ the animation.
System.setOut(PrintStreamWrapper(terminal, System.out))
I'm wondering whether there are and hints / best practices on how to deal with log statements from third-party libraries while displaying a
MultiProgressBarAnimation
on the console. Log output from third-part libraries causes lines being printed to the console that mess up Mordant's rendering of progress bars etc.As the log out is useful and should not be suppressed, would it maybe even make sense to have a Mordant-based log "appender" that can be used with common logging frameworks like Log4j or SLF4J to direct log output to a console are that Mordant "knows of" and thus does not mess with the progress bars?