make splitting of log lines configurable

- it might make sense to have newlines in a log message
  (e.g. when printing a backtrace) and they shouldn't
  be split into multiple log messages, e.g. when using syslog
- the splitting was fixed to work with more than one LF

(cherry picked from commit d14ce3dea1b98227dcd116acc6b175c56d9a1fb0)
This commit is contained in:
Martin Nowak 2016-02-24 12:10:00 +01:00 committed by Sönke Ludwig
parent 7e2d1dd038
commit dc9002de0e

View file

@ -196,6 +196,12 @@ struct LogLine {
class Logger { class Logger {
LogLevel minLevel = LogLevel.min; LogLevel minLevel = LogLevel.min;
/** Whether the logger can handle multiple lines in a single beginLine/endLine.
By default log text with newlines gets split into multiple log lines.
*/
protected bool multilineLogger = false;
private { private {
LogLine m_curLine; LogLine m_curLine;
Appender!string m_curLineText; Appender!string m_curLineText;
@ -830,14 +836,23 @@ private struct LogOutputRange {
void put(scope const(char)[] text) void put(scope const(char)[] text)
{ {
import std.string : indexOf; if (text.empty)
auto idx = text.indexOf('\n'); return;
if (idx >= 0) {
logger.put(text[0 .. idx]); if (logger.multilineLogger)
logger.endLine(); logger.put(text);
logger.beginLine(info); else
logger.put(text[idx+1 .. $]); {
} else logger.put(text); auto rng = text.splitter('\n');
logger.put(rng.front);
rng.popFront;
foreach (line; rng)
{
logger.endLine();
logger.beginLine(info);
logger.put(line);
}
}
} }
void put(char ch) @trusted { put((&ch)[0 .. 1]); } void put(char ch) @trusted { put((&ch)[0 .. 1]); }
@ -862,6 +877,31 @@ private version (Windows) {
extern(System) HANDLE GetStdHandle(DWORD nStdHandle); extern(System) HANDLE GetStdHandle(DWORD nStdHandle);
} }
unittest
{
static class TestLogger : Logger
{
string[] lines;
override void beginLine(ref LogLine msg) { lines.length += 1; }
override void put(scope const(char)[] text) { lines[$-1] ~= text; }
override void endLine() { }
}
auto logger = new TestLogger;
auto ll = (cast(shared(Logger))logger).lock();
auto rng = LogOutputRange(ll, __FILE__, __LINE__, LogLevel.info);
rng.formattedWrite("text\nwith\nnewlines");
rng.finalize();
assert(logger.lines == ["text", "with", "newlines"]);
logger.lines = null;
logger.multilineLogger = true;
rng = LogOutputRange(ll, __FILE__, __LINE__, LogLevel.info);
rng.formattedWrite("text\nwith\nnewlines");
rng.finalize();
assert(logger.lines == ["text\nwith\nnewlines"]);
}
unittest { // make sure the default logger doesn't allocate/is usable within finalizers unittest { // make sure the default logger doesn't allocate/is usable within finalizers
bool destroyed = false; bool destroyed = false;