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