Skip to content

Commit b93772c

Browse files
committed
feat: add log support
1 parent bf17b3c commit b93772c

File tree

4 files changed

+291
-16
lines changed

4 files changed

+291
-16
lines changed

common.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,13 @@
2626
#define SERVER_MESSAGE "[%s] say >> %s"
2727

2828

29+
#define INITCOLOR(color) std::string("\033[1;") + std::string(color) + std::string("m")
30+
#define RED_COLOR "31"
31+
#define GREEN_COLOR "32"
32+
#define YELLOW_COLOR "33"
33+
#define BLUE_COLOR "34"
34+
#define ZERO_COLOR "0"
35+
2936

3037
static inline void addfd(int epFd, int fd, bool enable_et) {
3138
struct epoll_event ev;
@@ -52,7 +59,6 @@ static inline void set_nonblocking(int fd) {
5259

5360

5461
static inline void trim(const char *strIn, char *strOut) {
55-
5662
size_t i, j;
5763

5864
i = 0;
@@ -64,7 +70,9 @@ static inline void trim(const char *strIn, char *strOut) {
6470

6571
while (strIn[j] == ' ')
6672
--j;
73+
6774
strncpy(strOut, strIn + i, j - i + 1);
75+
6876
strOut[j - i + 1] = '\0';
6977
}
7078

server/logger.hpp

Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
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

server/server.hpp

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@
2828
* debug output in the program*/
2929
#define __DEVELOPMENT__ 0
3030

31-
#include <string>
3231
#include <map>
32+
#include <string>
3333
#include <iostream>
3434
#include <cstdlib>
3535
#include <cstdio>
@@ -38,14 +38,18 @@
3838
#include <ctime> //time
3939
#include <cstring>
4040
#include <unistd.h> // close
41-
#include <pthread.h>
41+
#include <pthread.h> //pthread_create
4242
#include <sys/mman.h> // mmap
4343
#include <fcntl.h> // fcntl
4444
#include <sys/epoll.h> //epoll_create epoll_ctl epoll_wait
4545
#include <sys/socket.h> // socket getaddrinfo/getnameinfo
4646
#include <netdb.h> //gai_strerror NI_MAXHOST NI_MAXSERV
47-
#include "error_functions.hpp"
47+
48+
#include "logger.hpp"
4849
#include "common.h" // addfd set_nonblocking trim
50+
#include "error_functions.hpp"
51+
52+
using namespace vogro;
4953

5054
/* 监听缓冲队列大小 */
5155
#define LISTENQ 50
@@ -74,26 +78,33 @@ namespace server_ns {
7478
std::string clientPort;
7579
std::string clientNickname;
7680
std::string joinAt;
77-
int connFd;
78-
bool isNicknameSet;
79-
81+
int connFd=0;
82+
bool isNicknameSet=false;
8083
} ClientInfo; // struct ClientInfo
8184

82-
static std::map<int, ClientInfo> clients;
85+
86+
8387
static int listenFd;
8488
static int epollFd;
85-
static std::mutex io_event_mux, clients_map_mux;
89+
static std::map<int, ClientInfo> clients;
90+
91+
static std::mutex io_event_mux;
92+
static std::mutex clients_map_mux;
93+
static Logger<FilePolicy> &logger=Logger<FilePolicy>::getLoggerInstance("qiaqia.log");
94+
8695

8796
class Server {
8897
private:
8998
std::string serverPort;
9099

100+
91101
int workerNum;
92102

93103
static int broadcast(int sender_fd, char *msg) {
94104
for (auto it: clients) {
95105
if (it.first != sender_fd) {
96-
if (send(it.first, msg, MAXLINE, 0) < 0 && (errno != EAGAIN || errno != EWOULDBLOCK)) {
106+
if (send(it.first, msg, MAXLINE, 0) < 0
107+
&& (errno != EAGAIN || errno != EWOULDBLOCK)) {
97108
return -1;
98109
}
99110
}
@@ -390,7 +401,8 @@ namespace server_ns {
390401
// format the msg to be send to clients
391402
sprintf(message, SERVER_MESSAGE, clients[connfd].clientNickname.c_str(), byte_stream.c_str());
392403

393-
printf("消息:%s\n", byte_stream.c_str());
404+
// printf("消息:%s\n", byte_stream.c_str());
405+
logger.LOG_INFO("消息:",byte_stream);
394406
// broadcast
395407
if (broadcast(connfd, message) == -1) return -1;
396408
else return 0;
@@ -405,6 +417,7 @@ namespace server_ns {
405417
this->workerNum = workerNum;
406418
}
407419

420+
408421
~Server() {
409422
if (close(listenFd) == -1) errExit("close listenFd");
410423
if (close(epollFd) == -1) errExit("close epollFd");

0 commit comments

Comments
 (0)