/usr/lib/gcc/x86_64-linux-gnu/5/include/d/std/experimental/logger/multilogger.d is in libphobos-5-dev 5.5.0-12ubuntu1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 | module std.experimental.logger.multilogger;
import std.experimental.logger.core;
import std.experimental.logger.filelogger;
/** This Element is stored inside the $(D MultiLogger) and associates a
$(D Logger) to a $(D string).
*/
struct MultiLoggerEntry
{
string name; /// The name if the $(D Logger)
Logger logger; /// The stored $(D Logger)
}
/** MultiLogger logs to multiple $(D Logger). The $(D Logger)s are stored in an
$(D Logger[]) in their order of insertion.
Every data logged to this $(D MultiLogger) will be distributed to all the $(D
Logger)s inserted into it. This $(D MultiLogger) implementation can
hold multiple $(D Logger)s with the same name. If the method $(D removeLogger)
is used to remove a $(D Logger) only the first occurrence with that name will
be removed.
*/
class MultiLogger : Logger
{
/** A constructor for the $(D MultiLogger) Logger.
Params:
lv = The $(D LogLevel) for the $(D MultiLogger). By default the
$(D LogLevel) for $(D MultiLogger) is $(D LogLevel.all).
Example:
-------------
auto l1 = new MultiLogger(LogLevel.trace);
-------------
*/
this(const LogLevel lv = LogLevel.all) @safe
{
super(lv);
}
/** This member holds all $(D Logger)s stored in the $(D MultiLogger).
When inheriting from $(D MultiLogger) this member can be used to gain
access to the stored $(D Logger).
*/
protected MultiLoggerEntry[] logger;
/** This method inserts a new Logger into the $(D MultiLogger).
Params:
name = The name of the $(D Logger) to insert.
newLogger = The $(D Logger) to insert.
*/
void insertLogger(string name, Logger newLogger) @safe
{
this.logger ~= MultiLoggerEntry(name, newLogger);
}
/** This method removes a Logger from the $(D MultiLogger).
Params:
toRemove = The name of the $(D Logger) to remove. If the $(D Logger)
is not found $(D null) will be returned. Only the first occurrence of
a $(D Logger) with the given name will be removed.
Returns: The removed $(D Logger).
*/
Logger removeLogger(in char[] toRemove) @safe
{
import std.algorithm : copy;
import std.range.primitives : back, popBack;
for (size_t i = 0; i < this.logger.length; ++i)
{
if (this.logger[i].name == toRemove)
{
Logger ret = this.logger[i].logger;
this.logger[i] = this.logger.back;
this.logger.popBack();
return ret;
}
}
return null;
}
/* The override to pass the payload to all children of the
$(D MultiLoggerBase).
*/
override protected void writeLogMsg(ref LogEntry payload) @safe
{
foreach (it; this.logger)
{
/* We don't perform any checks here to avoid race conditions.
Instead the child will check on its own if its log level matches
and assume LogLevel.all for the globalLogLevel (since we already
know the message passes this test).
*/
it.logger.forwardMsg(payload);
}
}
}
@safe unittest
{
import std.experimental.logger.nulllogger;
import std.exception : assertThrown;
auto a = new MultiLogger;
auto n0 = new NullLogger();
auto n1 = new NullLogger();
a.insertLogger("zero", n0);
a.insertLogger("one", n1);
auto n0_1 = a.removeLogger("zero");
assert(n0_1 is n0);
auto n = a.removeLogger("zero");
assert(n is null);
auto n1_1 = a.removeLogger("one");
assert(n1_1 is n1);
n = a.removeLogger("one");
assert(n is null);
}
@safe unittest
{
auto a = new MultiLogger;
auto n0 = new TestLogger;
auto n1 = new TestLogger;
a.insertLogger("zero", n0);
a.insertLogger("one", n1);
a.log("Hello TestLogger"); int line = __LINE__;
assert(n0.msg == "Hello TestLogger");
assert(n0.line == line);
assert(n1.msg == "Hello TestLogger");
assert(n0.line == line);
}
// Issue #16
unittest
{
import std.stdio : File;
import std.string : indexOf;
string logName = __FUNCTION__ ~ ".log";
auto logFileOutput = File(logName, "w");
scope(exit)
{
import std.file : remove;
logFileOutput.close();
remove(logName);
}
auto traceLog = new FileLogger(logFileOutput, LogLevel.all);
auto infoLog = new TestLogger(LogLevel.info);
auto root = new MultiLogger(LogLevel.all);
root.insertLogger("fileLogger", traceLog);
root.insertLogger("stdoutLogger", infoLog);
string tMsg = "A trace message";
root.trace(tMsg); int line1 = __LINE__;
assert(infoLog.line != line1);
assert(infoLog.msg != tMsg);
string iMsg = "A info message";
root.info(iMsg); int line2 = __LINE__;
assert(infoLog.line == line2);
assert(infoLog.msg == iMsg, infoLog.msg ~ ":" ~ iMsg);
logFileOutput.close();
logFileOutput = File(logName, "r");
assert(logFileOutput.isOpen);
assert(!logFileOutput.eof);
auto line = logFileOutput.readln();
assert(line.indexOf(tMsg) != -1, line ~ ":" ~ tMsg);
assert(!logFileOutput.eof);
line = logFileOutput.readln();
assert(line.indexOf(iMsg) != -1, line ~ ":" ~ tMsg);
}
@safe unittest
{
auto dl = cast(FileLogger)sharedLog;
assert(dl !is null);
assert(dl.logLevel == LogLevel.all);
assert(globalLogLevel == LogLevel.all);
auto tl = cast(StdForwardLogger)stdThreadLocalLog;
assert(tl !is null);
stdThreadLocalLog.logLevel = LogLevel.all;
}
|