主要功能是在服务器运行的时候可以打印日志到日志文件中,主要运用到的知识点有线程, 线程锁,条件变量,STL的deque。大致思路是这样的:
这个类提供一个接口,可以直接调用他,并且可以打印日志到日志文件中。但是不能影响到服务器的正常运行,也就是说不能进行大量的文件操作;
大致 实现流程:
对象初始化时候创建一个线程在后台读取队列,并将读到的数据写入到日志文件中,并在队列中删除这一数据;
接口处,每次写日志时,其实是将日志存到队列中去。交由后台线程写入到文件中。
整个程序难点:对于临界区的控制,即线程锁,条件变量的使用。
对deque的理解与使用。
在C++类内部实现类实例化;
下边上代码
log.h
log.cpp
测试文件 main.cpp
别忘记:makefile
这个类提供一个接口,可以直接调用他,并且可以打印日志到日志文件中。但是不能影响到服务器的正常运行,也就是说不能进行大量的文件操作;
大致 实现流程:
对象初始化时候创建一个线程在后台读取队列,并将读到的数据写入到日志文件中,并在队列中删除这一数据;
接口处,每次写日志时,其实是将日志存到队列中去。交由后台线程写入到文件中。
整个程序难点:对于临界区的控制,即线程锁,条件变量的使用。
对deque的理解与使用。
在C++类内部实现类实例化;
下边上代码
log.h
#ifndef
LOG_H
#define
LOG_H
#include
<stdio.h>
#include
<iostream>
#include
<string>
#include
<stdarg.h>
#include
<pthread.h>
#include
<deque>
using
namespace
std
;
class
Log
{
public
:
static
Log
*
get_instance
(
)
{
static
Log
instance
;
return
&
instance
;
}
static
void
*
flush_log_thread
(
void
*
args
)
{
Log
::
get_instance
(
)
->
async_write_log
(
)
;
}
bool
init
(
const
char
*
file_name
,
int
log
_buf_size
=
8192
,
int
split_lines
=
5000000
,
int
max_queue_size
=
0
)
;
void
write_log
(
int
level
,
const
char
*
format
,
...
)
;
void
flush
(
void
)
;
private
:
Log
(
)
;
virtual
~
Log
(
)
;
void
*
async_write_log
(
)
{
string
sin
gle_log
;
while
(
1
)
{
printf
(
"%d\n"
,
!
m_log_queue
.
size
(
))
;
if
(
!
m_log_queue
.
size
(
)
)
{
pthread_mutex_lock
(
m_mutex
)
;
{
pthread_cond_wait
(
m_cond
,
m_mutex
)
;
sin
gle_log
=
m_log_queue
.
front
(
)
;
fputs
(
sin
gle_log
.
c_str
(
)
,
m_fp
)
;
m_log_queue
.
pop_front
(
)
;
pthread_mutex_unlock
(
m_mutex
)
;
}
}
else
{
pthread_mutex_lock
(
m_mutex
)
;
sin
gle_log
=
m_log_queue
.
front
(
)
;
fputs
(
sin
gle_log
.
c_str
(
)
,
m_fp
)
;
m_log_queue
.
pop_front
(
)
;
pthread_mutex_unlock
(
m_mutex
)
;
}
}
printf
(
"end\n"
)
;
}
private
:
pthread_mutex_t
*
m_mutex
;
pthread_cond_t
*
m_cond
;
char
dir_name
[
128
]
;
char
log
_name
[
128
]
;
int
m_split_lines
;
int
m_log_buf_size
;
long
long
m_count
;
int
m_today
;
FILE
*
m_fp
;
char
*
m_buf
;
deque
<
string
>
m_log_queue
;
bool
m_is_async
;
}
;
#define
LOG_DEBUG(format, ...) Log::get_instance()->write_log(0, format, __VA_ARGS__)
#define
LOG_INFO(format, ...) Log::get_instance()->write_log(1, format, __VA_ARGS__)
#define
LOG_WARN(format, ...) Log::get_instance()->write_log(2, format, __VA_ARGS__)
#define
LOG_ERROR(format, ...) Log::get_instance()->write_log(3, format, __VA_ARGS__)
#endif
log.cpp
*********************************************************/
#include
<string.h>
#include
<time.h>
#include
<sys/time.h>
#include
<stdarg.h>
#include
"log.h"
#include
<pthread.h>
using
namespace
std
;
Log
::
Log
(
)
{
m_count
=
0
;
m_mutex
=
new
pthread_mutex_t
;
m_cond
=
new
pthread_cond_t
;
m_is_async
=
false
;
pthread_mutex_init
(
m_mutex
,
NULL
)
;
}
Log
::
~
Log
(
)
{
if
(
m_fp
!=
NULL
)
{
fclose
(
m_fp
)
;
}
pthread_cond_destroy
(
m_cond
)
;
if
(
m_cond
!=
NULL
)
{
delete
m_cond
;
}
pthread_mutex_destroy
(
m_mutex
)
;
if
(
m_mutex
!=
NULL
)
{
delete
m_mutex
;
}
}
bool
Log
::
init
(
const
char
*
file_name
,
int
log
_buf_size
,
int
split_lines
,
int
max_queue_size
)
{
if
(
max_queue_size
>=
1
)
{
m_is_async
=
true
;
// m_log_queue = new block_queue<string>(max_queue_size);
deque
<
string
>
(
max_queue_size
)
;
pthread_t
tid
;
pthread_create
(
&
tid
,
NULL
,
flush_log_thread
,
NULL
)
;
}
m_log_buf_size
=
log
_buf_size
;
m_buf
=
new
char
[
m_log_buf_size
]
;
memset
(
m_buf
,
'\0'
,
sizeof
(
m_buf
))
;
m_split_lines
=
split_lines
;
time
_t
t
=
time
(
NULL
)
;
struct
tm
*
sys_tm
=
localtime
(
&
t
)
;
struct
tm
my_tm
=
*
sys_tm
;
const
char
*
p
=
strrchr
(
file_name
,
'/'
)
;
char
log
_full_name
[
256
]
=
{
0
}
;
if
(
p
==
NULL
)
{
snprintf
(
log
_full_name
,
255
,
"%d_%02d_%02d_%s"
,
my_tm
.
tm_year
+1900
,
my_tm
.
tm_mon
+1
,
my_tm
.
tm_mday
,
file_name
)
;
}
else
{
strcpy
(
log
_name
,
p
+1
)
;
strncpy
(
dir_name
,
file_name
,
p
-
file_name
+
1
)
;
snprintf
(
log
_full_name
,
255
,
"%s%d_%02d_%02d_%s"
,
dir_name
,
my_tm
.
tm_year
+1900
,
my_tm
.
tm_mon
+1
,
my_tm
.
tm_mday
,
log
_name
)
;
}
m_today
=
my_tm
.
tm_mday
;
m_fp
=
fopen
(
log
_full_name
,
"a"
)
;
if
(
m_fp
==
NULL
)
{
return
false
;
}
return
true
;
}
void
Log
::
write_log
(
int
level
,
const
char
*
format
,
...
)
{
struct
time
val
now
=
{
0
,
0
}
;
gettimeofday
(
&
now
,
NULL
)
;
time
_t
t
=
now
.
tv_sec
;
struct
tm
*
sys_tm
=
localtime
(
&
t
)
;
struct
tm
my_tm
=
*
sys_tm
;
char
s
[
16
]
=
{
0
}
;
switch
(
level
)
{
case
0
:
strcpy
(
s
,
"[debug]:"
)
;
break
;
case
1
:
strcpy
(
s
,
"[info]:"
)
;
break
;
case
2
:
strcpy
(
s
,
"[warn]:"
)
;
break
;
case
3
:
strcpy
(
s
,
"[erro]:"
)
;
break
;
default
:
strcpy
(
s
,
"[info]:"
)
;
break
;
}
pthread_mutex_lock
(
m_mutex
)
;
m_count
++
;
if
(
m_today
!=
my_tm
.
tm_mday
||
m_count
%
m_split_lines
==
0
)
//everyday log
{
char
new_log
[
256
]
=
{
0
}
;
fflush
(
m_fp
)
;
fclose
(
m_fp
)
;
char
tail
[
16
]
=
{
0
}
;
snprintf
(
tail
,
16
,
"%d_%02d_%02d_"
,
my_tm
.
tm_year
+1900
,
my_tm
.
tm_mon
+1
,
my_tm
.
tm_mday
)
;
if
(
m_today
!=
my_tm
.
tm_mday
)
{
snprintf
(
new_log
,
255
,
"%s%s%s"
,
dir_name
,
tail
,
log
_name
)
;
m_today
=
my_tm
.
tm_mday
;
m_count
=
0
;
}
else
{
snprintf
(
new_log
,
255
,
"%s%s%s.%d"
,
dir_name
,
tail
,
log
_name
,
m_count/
m_split_lines
)
;
}
m_fp
=
fopen
(
new_log
,
"a"
)
;
}
pthread_mutex_unlock
(
m_mutex
)
;
va_list
valst
;
va_start
(
valst
,
format
)
;
string
log
_str
;
pthread_mutex_lock
(
m_mutex
)
;
int
n
=
snprintf
(
m_buf
,
48
,
"%d-%02d-%02d %02d:%02d:%02d.%06d %s "
,
my_tm
.
tm_year
+1900
,
my_tm
.
tm_mon
+1
,
my_tm
.
tm_mday
,
my_tm
.
tm_hour
,
my_tm
.
tm_min
,
my_tm
.
tm_sec
,
now
.
tv_usec
,
s
)
;
int
m
=
vsnprintf
(
m_buf
+
n
,
m_log_buf_size
-1
,
format
,
valst
)
;
m_buf
[
n
+
m
-
1
]
=
'\n'
;
log
_str
=
m_buf
;
pthread_mutex_unlock
(
m_mutex
)
;
if
(
m_is_async
)
// && !m_log_queue->full())
{
pthread_mutex_lock
(
m_mutex
)
;
m_log_queue
.
push_back
(
log
_str
)
;
pthread_cond_broadcast
(
m_cond
)
;
pthread_mutex_unlock
(
m_mutex
)
;
}
else
{
pthread_mutex_lock
(
m_mutex
)
;
fputs
(
log
_str
.
c_str
(
)
,
m_fp
)
;
pthread_mutex_unlock
(
m_mutex
)
;
}
va_end
(
valst
)
;
}
void
Log
::
flush
(
void
)
{
pthread_mutex_lock
(
m_mutex
)
;
fflush
(
m_fp
)
;
pthread_mutex_unlock
(
m_mutex
)
;
}
#include
"log.h"
void
*
f
(
void
*
args
)
{
for
(
int
i
=
0
;
i
<
10000
;
i
++
)
{
Log
::
get_instance
(
)
->
write_log
(
1
,
"d=%d,c=%c,s=%s,f=%f"
,
i
,
'a'
,
"log"
,
1.000
)
;
Log
::
get_instance
(
)
->
write_log
(
2
,
"d=%d,c=%c,s=%s,f=%f"
,
i
,
'a'
,
"log"
,
1.000
)
;
Log
::
get_instance
(
)
->
write_log
(
3
,
"d=%d,c=%c,s=%s,f=%f"
,
i
,
'a'
,
"log"
,
1.000
)
;
LOG_INFO
(
"%d"
,
123456789
)
;
LOG_ERROR
(
"%d"
,
123456789
)
;
LOG_DEBUG
(
"%d"
,
123456789
)
;
LOG_WARN
(
"%d"
,
123456789
)
;
}
}
int
main
(
)
{
Log
::
get_instance
(
)
->
init
(
"./mylog.log"
,
100
,
2000000
,
10
)
;
//Log::get_instance()->init("./mylog.log", 100, 2000000, 0);//synchronization model
// printf("11111111111111\n");
// sleep(1);
int
i
=
0
;
Log
::
get_instance
(
)
->
write_log
(
1
,
"d=%d,c=%c,s=%s,f=%f"
,
i
,
'a'
,
"log"
,
1.000
)
;
Log
::
get_instance
(
)
->
write_log
(
2
,
"d=%d,c=%c,s=%s,f=%f"
,
i
,
'a'
,
"log"
,
1.000
)
;
Log
::
get_instance
(
)
->
write_log
(
3
,
"d=%d,c=%c,s=%s,f=%f"
,
i
,
'a'
,
"log"
,
1.000
)
;
LOG_INFO
(
"%d"
,
123456789
)
;
LOG_ERROR
(
"%d"
,
123456789
)
;
LOG_DEBUG
(
"%d"
,
123456789
)
;
LOG_WARN
(
"%d"
,
123456789
)
;
pthread_t
id
;
for
(
int
i
=
0
;
i
<
10
;
i
++
)
{
pthread_create
(
&
id
,
NULL
,
f
,
NULL
)
;
pthread_join
(
id
,
NULL
)
;
}
//for(;;)
{
sleep
(
15
)
;
Log
::
get_instance
(
)
->
flush
(
)
;
}
while
(
1
)
;
// Log::get_instance()->put_log();
return
0
;
}
别忘记:makefile
BIN := main
CFLAGS := -g -Wall -lpthread
CC := g++
SRCFILE := $(wildcard *.cpp)
OBJFILE := $(patsubst %.cpp,%.o,$(SRCFILE))
$(BIN): $(OBJFILE)
$(CC) $(CFLAGS) -o $(BIN) $(OBJFILE)
%.o:%.cpp
$(CC) $(CFLAGS) -c $< -o $@
clean :
rm -rf $(OBJFILE) ${BIN}