1+ /* * MIT License
2+
3+ Copyright (c) 2018 阿超 andrewpqc@mails.ccnu.edu.cn
4+
5+ Permission is hereby granted, free of charge, to any person obtaining a copy
6+ of this software and associated documentation files (the "Software"), to deal
7+ in the Software without restriction, including without limitation the rights
8+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+ copies of the Software, and to permit persons to whom the Software is
10+ furnished to do so, subject to the following conditions:
11+
12+ The above copyright notice and this permission notice shall be included in all
13+ copies or substantial portions of the Software.
14+
15+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+ SOFTWARE.
22+ */
23+
24+
25+ #ifndef __QIAQIA_LOGGER_HPP__
26+ #define __QIAQIA_LOGGER_HPP__
27+
28+
29+ #include < mutex>
30+ #include < cstdio>
31+ #include < cstdlib>
32+ #include < fstream>
33+ #include < iostream>
34+ #include < memory>
35+ #include < sstream>
36+ #include < string>
37+ #include < cstring>
38+ #include < typeinfo>
39+ #include " common.h"
40+
41+ namespace vogro {
42+
43+ enum severity_type {
44+ info = 1 ,
45+ debug,
46+ error,
47+ warn,
48+ };
49+
50+
51+ class BasePolicy {
52+ public:
53+ virtual void open_ostream () = 0;
54+
55+ virtual void close_ostream () = 0;
56+
57+ virtual void write (const std::string &msg) = 0;
58+
59+ virtual ~BasePolicy () {};
60+ }; // class BasePolicy
61+
62+ class FilePolicy : public BasePolicy {
63+ private:
64+ std::string filename;
65+ std::unique_ptr<std::ofstream> out_stream;
66+
67+ public:
68+ explicit FilePolicy (const std::string &f) : filename(f), out_stream(new std::ofstream) {
69+ this ->open_ostream ();
70+ }
71+
72+ void open_ostream () override {
73+ this ->out_stream ->open (filename,
74+ std::ofstream::out | std::ofstream::app);
75+ }
76+
77+ void close_ostream () override { this ->out_stream ->close (); }
78+
79+ void write (const std::string &msg) override {
80+ *(this ->out_stream ) << msg << std::endl;
81+ }
82+
83+ ~FilePolicy () override { this ->close_ostream (); }
84+ }; // class FilePolicy
85+
86+ class TerminalPolicy : public BasePolicy {
87+ public:
88+ // placehold 保持接口一致
89+ explicit TerminalPolicy (std::string &placehold) {};
90+
91+ void open_ostream () override {
92+ // do nothing
93+ }
94+
95+ void close_ostream () override {
96+ // do nothing
97+ }
98+
99+ void write (const std::string &msg) override {
100+ std::cout << msg << std::endl;
101+ }
102+ }; // class TerminalPolicy
103+
104+ // remaining impl
105+ class RemotePolicy : public BasePolicy {
106+ private:
107+ std::string remote_host;
108+ unsigned short remote_port;
109+
110+ public:
111+ explicit RemotePolicy (const std::string &addr) {
112+ auto pos = addr.find_first_of (' :' );
113+ this ->remote_host = addr.substr (0 , pos);
114+ this ->remote_port = (unsigned short ) atoi (addr.substr (pos + 1 ).c_str ());
115+
116+ this ->open_ostream ();
117+ }
118+
119+ ~RemotePolicy () override { this ->close_ostream (); }
120+
121+ void open_ostream () override {
122+ // do nothing
123+ }
124+
125+ void close_ostream () override {
126+ // do nothing
127+ }
128+
129+ void write (const std::string &msg) override {}
130+ }; // class RemotePolicy
131+
132+ // Logger<TerminalPolicy> &logger = Logger<TerminalPolicy>::getLoggerInstance("vogro.log");
133+
134+ template <typename policy_type>
135+ class Logger {
136+ public:
137+ static Logger &getLoggerInstance (std::string filename_or_addr) {
138+ static Logger logger (filename_or_addr);
139+ return logger;
140+ }
141+
142+ Logger (const Logger &) = delete ;
143+
144+ Logger &operator =(const Logger &) = delete ;
145+
146+ template <severity_type severity, typename ... Args>
147+ void PrintLog (const Args &... args) {
148+ // init p and ssp only once
149+ if (!p) {
150+ p = std::shared_ptr<policy_type>(
151+ new policy_type (this ->filename_or_addr ));
152+ if (typeid (TerminalPolicy) == typeid (*p)) {
153+ this ->is_terminal = true ;
154+ }
155+ }
156+ if (!ssp) {
157+ ssp = std::make_shared<std::stringstream>();
158+ }
159+
160+ write_mutex.lock ();
161+ (*ssp) << " [" << getCurrentTime () << " ] " ;
162+ switch (severity) {
163+ case severity_type::info:
164+ if (this ->is_terminal )
165+ (*ssp) << INITCOLOR (GREEN_COLOR) << " <INFO>"
166+ << INITCOLOR (ZERO_COLOR) << " : " ; // with color
167+ else
168+ (*ssp) << " <INFO>: " ; // no color
169+ break ;
170+
171+ case severity_type::debug:
172+ if (this ->is_terminal )
173+ (*ssp) << INITCOLOR (BLUE_COLOR) << " <DEBUG>"
174+ << INITCOLOR (ZERO_COLOR) << " : " ;
175+ else
176+ (*ssp) << " <DEBUG>: " ;
177+ break ;
178+
179+ case severity_type::warn:
180+ if (this ->is_terminal )
181+ (*ssp) << INITCOLOR (YELLOW_COLOR) << " <WARN>"
182+ << INITCOLOR (ZERO_COLOR) << " : " ;
183+ else
184+ (*ssp) << " <WARN>: " ;
185+ break ;
186+
187+ case severity_type::error:
188+ if (this ->is_terminal )
189+ (*ssp) << INITCOLOR (RED_COLOR) << " <ERROR>"
190+ << INITCOLOR (ZERO_COLOR) << " : " ;
191+ else
192+ (*ssp) << " <ERROR>: " ;
193+ break ;
194+ };
195+ this ->print_impl (args...);
196+ write_mutex.unlock ();
197+ }
198+
199+ template <typename ... Args>
200+ void LOG_INFO (const Args &... args) {
201+ this ->PrintLog <severity_type::info>(args...);
202+ }
203+
204+ template <typename ... Args>
205+ void LOG_DEBUG (const Args &... args) {
206+ this ->PrintLog <severity_type::debug>(args...);
207+ }
208+
209+ template <typename ... Args>
210+ void LOG_WARN (const Args &... args) {
211+ this ->PrintLog <severity_type::warn>(args...);
212+ }
213+
214+ template <typename ... Args>
215+ void LOG_ERROR (const Args &... args) {
216+ this ->PrintLog <severity_type::error>(args...);
217+ }
218+
219+ private:
220+ std::mutex write_mutex;
221+
222+ std::shared_ptr<policy_type> p;
223+
224+ std::string filename_or_addr;
225+
226+ std::shared_ptr<std::stringstream> ssp;
227+
228+ bool is_terminal = false ;
229+
230+ void print_impl () { // Recursive termination function
231+ p->write (ssp->str ());
232+ ssp->str (" " ); // ssp->empty(),ssp->clear() can not clean ssp
233+ }
234+
235+ template <typename First, typename ... Rest>
236+ void print_impl (const First &parm1, const Rest &... parm) {
237+ (*ssp) << parm1 << " " ;
238+ print_impl (parm...);
239+ }
240+
241+ std::string getCurrentTime () {
242+ time_t t;
243+ time (&t);
244+ struct tm *tmp_time = localtime (&t);
245+ char s[100 ];
246+ strftime (s, sizeof (s), " %04Y/%02m/%02d %H:%M:%S" , tmp_time);
247+ return static_cast <std::string>(s);
248+ }
249+
250+ explicit Logger (std::string &f) { this ->filename_or_addr = f; }
251+ }; // class Logger
252+ } // namespace vogro
253+ #endif
0 commit comments