Line data Source code
1 : // Copyright (c) 2006-2025 Made to Order Software Corp. All Rights Reserved
2 : //
3 : // https://snapwebsites.org/project/snaplogger
4 : // contact@m2osw.com
5 : //
6 : // This program is free software: you can redistribute it and/or modify
7 : // it under the terms of the GNU General Public License as published by
8 : // the Free Software Foundation, either version 3 of the License, or
9 : // (at your option) any later version.
10 : //
11 : // This program is distributed in the hope that it will be useful,
12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : // GNU General Public License for more details.
15 : //
16 : // You should have received a copy of the GNU General Public License
17 : // along with this program. If not, see <https://www.gnu.org/licenses/>.
18 :
19 : // self
20 : //
21 : #include "catch_main.h"
22 :
23 :
24 : // snaplogger
25 : //
26 : #include <snaplogger/console_appender.h>
27 : //#include <snaplogger/exception.h>
28 : //#include <snaplogger/format.h>
29 : #include <snaplogger/logger.h>
30 : #include <snaplogger/map_diagnostic.h>
31 : //#include <snaplogger/message.h>
32 : //#include <snaplogger/severity.h>
33 : //#include <snaplogger/version.h>
34 :
35 :
36 : // cppthread
37 : //
38 : #include <cppthread/runner.h>
39 : #include <cppthread/thread.h>
40 :
41 :
42 : // snapdev
43 : //
44 : #include <snapdev/ostream_to_buf.h>
45 :
46 :
47 : // C
48 : //
49 : //#include <unistd.h>
50 : //#include <netdb.h>
51 : //#include <sys/param.h>
52 :
53 :
54 : namespace
55 : {
56 :
57 :
58 :
59 : // a thread so we can create a pipe and read the other side so the write
60 : // does not get stuck
61 : //
62 : class pipe_reader
63 : : public cppthread::runner
64 : {
65 : public:
66 : typedef std::shared_ptr<pipe_reader> pointer_t;
67 :
68 :
69 1 : pipe_reader(int pipe)
70 1 : : runner("pipe-reader-runner")
71 3 : , f_pipe(pipe)
72 : {
73 1 : }
74 :
75 :
76 1 : virtual void enter() override
77 : {
78 : // avoid the cppthread "entering" message
79 1 : }
80 :
81 :
82 1 : virtual void run() override
83 : {
84 : for(;;)
85 : {
86 3 : char buf[256];
87 3 : ssize_t n(read(f_pipe, buf, sizeof(buf)));
88 3 : if(n < 0)
89 : {
90 2 : return;
91 : }
92 : //std::cout << "--- received [" << std::string(buf, n) << "]" << std::endl;
93 6 : f_received += std::string(buf, n);
94 2 : }
95 : }
96 :
97 :
98 1 : virtual void leave(cppthread::leave_status_t status) override
99 : {
100 : // avoid the cppthread "leaving" message
101 : //
102 1 : snapdev::NOT_USED(status);
103 1 : }
104 :
105 :
106 1 : std::string const & get_received() const
107 : {
108 1 : return f_received;
109 : }
110 :
111 : private:
112 : int f_pipe = -1;
113 : std::string f_received = std::string();
114 : };
115 :
116 :
117 :
118 : }
119 :
120 :
121 :
122 :
123 2 : CATCH_TEST_CASE("console_appender", "[appender]")
124 : {
125 2 : CATCH_START_SECTION("console_appender: create")
126 : {
127 5 : snaplogger::set_diagnostic(snaplogger::DIAG_KEY_PROGNAME, "one-console");
128 :
129 5 : snaplogger::appender::pointer_t console(snaplogger::create_appender("console", "test-console"));
130 1 : CATCH_REQUIRE(console != nullptr);
131 1 : CATCH_REQUIRE(console->get_type() == "console");
132 1 : CATCH_REQUIRE(console->get_name() == "test-console");
133 :
134 1 : snaplogger::console_appender::pointer_t console_appender(std::dynamic_pointer_cast<snaplogger::console_appender>(console));
135 1 : CATCH_REQUIRE(console_appender != nullptr);
136 :
137 1 : CATCH_REQUIRE_FALSE(console_appender->get_force_style());
138 1 : console_appender->set_force_style(true);
139 1 : CATCH_REQUIRE(console_appender->get_force_style());
140 1 : console_appender->set_force_style(false);
141 1 : CATCH_REQUIRE_FALSE(console_appender->get_force_style());
142 :
143 1 : snaplogger::logger::pointer_t l(snaplogger::logger::get_instance());
144 1 : snaplogger::appender::vector_t appenders(l->get_appenders());
145 1 : CATCH_REQUIRE(appenders.size() == 0);
146 3 : CATCH_REQUIRE_FALSE(l->has_appender("console"));
147 3 : CATCH_REQUIRE(l->get_appender("test-console") == nullptr);
148 1 : l->add_appender(console);
149 3 : CATCH_REQUIRE(l->has_appender("console"));
150 3 : CATCH_REQUIRE(l->get_appender("test-console") != nullptr);
151 1 : appenders = l->get_appenders();
152 1 : CATCH_REQUIRE(appenders.size() == 1);
153 :
154 : // trying to add another console "works" but the existing
155 : // appender (the "original") is kept and the second instance is
156 : // totally ignored
157 : //
158 5 : snaplogger::appender::pointer_t second_console(snaplogger::create_appender("console", "second-console"));
159 1 : CATCH_REQUIRE(second_console != nullptr);
160 1 : CATCH_REQUIRE(second_console->get_type() == "console");
161 1 : CATCH_REQUIRE(second_console->get_name() == "second-console");
162 1 : l->add_appender(second_console);
163 1 : appenders = l->get_appenders();
164 1 : CATCH_REQUIRE(appenders.size() == 1); // still 1!
165 1 : CATCH_REQUIRE(appenders[0] == console); // original, "second_console" was ignored
166 1 : CATCH_REQUIRE(console->get_name() == "test-console"); // still the original console!
167 :
168 1 : l->reset();
169 1 : }
170 2 : CATCH_END_SECTION()
171 :
172 2 : CATCH_START_SECTION("console_appender: default console + create user console")
173 : {
174 5 : snaplogger::set_diagnostic(snaplogger::DIAG_KEY_PROGNAME, "user-console");
175 :
176 1 : snaplogger::logger::pointer_t l(snaplogger::logger::get_instance());
177 1 : snaplogger::appender::vector_t appenders(l->get_appenders());
178 1 : CATCH_REQUIRE(appenders.size() == 0);
179 :
180 : // the default console is named "console"
181 : //
182 1 : snaplogger::appender::pointer_t console(l->add_console_appender());
183 1 : CATCH_REQUIRE(console != nullptr);
184 1 : CATCH_REQUIRE(console->get_type() == "console");
185 1 : CATCH_REQUIRE(console->get_name() == "console");
186 :
187 3 : CATCH_REQUIRE(l->has_appender("console"));
188 3 : CATCH_REQUIRE(l->get_appender("console") == console);
189 1 : appenders = l->get_appenders();
190 1 : CATCH_REQUIRE(appenders.size() == 1);
191 1 : CATCH_REQUIRE(appenders[0] == console);
192 :
193 : // trying to add another console "works" but the existing
194 : // appender (the "original") is kept and the second instance is
195 : // totally ignored except in this very special case where the
196 : // original was named "console"--here the original gets renamed
197 : // to the new console "user" name
198 : //
199 5 : snaplogger::appender::pointer_t second_console(snaplogger::create_appender("console", "user-console"));
200 1 : CATCH_REQUIRE(second_console != nullptr);
201 1 : CATCH_REQUIRE(second_console->get_type() == "console");
202 1 : CATCH_REQUIRE(second_console->get_name() == "user-console");
203 1 : l->add_appender(second_console);
204 1 : appenders = l->get_appenders();
205 1 : CATCH_REQUIRE(appenders.size() == 1); // still 1!
206 1 : CATCH_REQUIRE(appenders[0] == console); // original, "second_console" was ignored
207 1 : CATCH_REQUIRE(console->get_name() == "user-console"); // except that the name was updated
208 :
209 : {
210 : // by default, output is sent to stderr
211 : //
212 1 : int fifo[2]; // 0 -- read, 1 -- write
213 1 : int const r(pipe(fifo));
214 1 : CATCH_REQUIRE(r == 0);
215 :
216 1 : FILE * fout(fdopen(fifo[1], "w"));
217 1 : std::swap(*fout, *stderr);
218 :
219 1 : pipe_reader::pointer_t pc(std::make_shared<pipe_reader>(fifo[0]));
220 3 : cppthread::thread t("pipe-reader", pc.get());
221 1 : CATCH_REQUIRE(t.start());
222 :
223 2 : SNAP_LOG_ERROR << "Test the console." << SNAP_LOG_SEND;
224 :
225 1 : std::swap(*fout, *stderr);
226 1 : fclose(fout);
227 1 : close(fifo[0]);
228 :
229 : // we expect the default format to include the name of the
230 : // appender and the message above and the severity
231 : //
232 1 : std::string const & received(pc->get_received());
233 1 : CATCH_REQUIRE(received.find("Test the console.") != std::string::npos);
234 1 : CATCH_REQUIRE(received.find(console->get_name()) != std::string::npos);
235 1 : CATCH_REQUIRE(received.find("error") != std::string::npos);
236 1 : }
237 :
238 1 : l->reset();
239 1 : }
240 2 : CATCH_END_SECTION()
241 2 : }
242 :
243 :
244 :
245 : // vim: ts=4 sw=4 et
|