Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
B
beego
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
go
beego
Commits
0eaf923a
Commit
0eaf923a
authored
Jan 13, 2016
by
astaxie
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1560 from JessonChan/log_enhancement
Log enhancement
parents
9c559859
5befc673
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
265 additions
and
196 deletions
+265
-196
console_test.go
logs/console_test.go
+0
-8
file.go
logs/file.go
+138
-116
file_test.go
logs/file_test.go
+56
-15
log.go
logs/log.go
+71
-57
No files found.
logs/console_test.go
View file @
0eaf923a
...
@@ -43,11 +43,3 @@ func TestConsole(t *testing.T) {
...
@@ -43,11 +43,3 @@ func TestConsole(t *testing.T) {
testConsoleCalls
(
log2
)
testConsoleCalls
(
log2
)
}
}
func
BenchmarkConsole
(
b
*
testing
.
B
)
{
log
:=
NewLogger
(
10000
)
log
.
EnableFuncCallDepth
(
true
)
log
.
SetLogger
(
"console"
,
""
)
for
i
:=
0
;
i
<
b
.
N
;
i
++
{
log
.
Debug
(
"debug"
)
}
}
logs/file.go
View file @
0eaf923a
...
@@ -20,7 +20,6 @@ import (
...
@@ -20,7 +20,6 @@ import (
"errors"
"errors"
"fmt"
"fmt"
"io"
"io"
"log"
"os"
"os"
"path/filepath"
"path/filepath"
"strings"
"strings"
...
@@ -31,85 +30,59 @@ import (
...
@@ -31,85 +30,59 @@ import (
// fileLogWriter implements LoggerInterface.
// fileLogWriter implements LoggerInterface.
// It writes messages by lines limit, file size limit, or time frequency.
// It writes messages by lines limit, file size limit, or time frequency.
type
fileLogWriter
struct
{
type
fileLogWriter
struct
{
*
log
.
Logger
sync
.
Mutex
// write log order by order and atomic incr maxLinesCurLines and maxSizeCurSize
mw
*
MuxWriter
// The opened file
// The opened file
Filename
string
`json:"filename"`
Filename
string
`json:"filename"`
fileWriter
*
os
.
File
Maxlines
int
`json:"maxlines"`
// Rotate at line
maxlinesCurlines
int
MaxLines
int
`json:"maxlines"`
maxLinesCurLines
int
// Rotate at size
// Rotate at size
Max
s
ize
int
`json:"maxsize"`
Max
S
ize
int
`json:"maxsize"`
max
sizeCurs
ize
int
max
SizeCurS
ize
int
// Rotate daily
// Rotate daily
Daily
bool
`json:"daily"`
Daily
bool
`json:"daily"`
Max
d
ays
int64
`json:"maxdays"`
Max
D
ays
int64
`json:"maxdays"`
dailyOpen
d
ate
int
dailyOpen
D
ate
int
Rotate
bool
`json:"rotate"`
Rotate
bool
`json:"rotate"`
startLock
sync
.
Mutex
// Only one log can write to the file
Level
int
`json:"level"`
Level
int
`json:"level"`
Perm
os
.
FileMode
`json:"perm"`
Perm
os
.
FileMode
`json:"perm"`
}
}
// MuxWriter is an *os.File writer with locker.
type
MuxWriter
struct
{
sync
.
Mutex
fd
*
os
.
File
}
// write to os.File.
func
(
l
*
MuxWriter
)
Write
(
b
[]
byte
)
(
int
,
error
)
{
l
.
Lock
()
defer
l
.
Unlock
()
return
l
.
fd
.
Write
(
b
)
}
// SetFd set os.File in writer.
func
(
l
*
MuxWriter
)
SetFd
(
fd
*
os
.
File
)
{
if
l
.
fd
!=
nil
{
l
.
fd
.
Close
()
}
l
.
fd
=
fd
}
// NewFileWriter create a FileLogWriter returning as LoggerInterface.
// NewFileWriter create a FileLogWriter returning as LoggerInterface.
func
newFileWriter
()
Logger
{
func
newFileWriter
()
Logger
{
w
:=
&
fileLogWriter
{
w
:=
&
fileLogWriter
{
Filename
:
""
,
Filename
:
""
,
Max
l
ines
:
1000000
,
Max
L
ines
:
1000000
,
Max
s
ize
:
1
<<
28
,
//256 MB
Max
S
ize
:
1
<<
28
,
//256 MB
Daily
:
true
,
Daily
:
true
,
Max
d
ays
:
7
,
Max
D
ays
:
7
,
Rotate
:
true
,
Rotate
:
true
,
Level
:
LevelTrace
,
Level
:
LevelTrace
,
Perm
:
0660
,
Perm
:
0660
,
}
}
// use MuxWriter instead direct use os.File for lock write when rotate
w
.
mw
=
new
(
MuxWriter
)
// set MuxWriter as Logger's io.Writer
w
.
Logger
=
log
.
New
(
w
.
mw
,
""
,
log
.
Ldate
|
log
.
Ltime
)
return
w
return
w
}
}
// Init file logger with json config.
// Init file logger with json config.
// json
c
onfig like:
// json
C
onfig like:
// {
// {
// "filename":"logs/beego.log",
// "filename":"logs/beego.log",
// "max
l
ines":10000,
// "max
L
ines":10000,
// "maxsize":1<<30,
// "maxsize":1<<30,
// "daily":true,
// "daily":true,
// "max
d
ays":15,
// "max
D
ays":15,
// "rotate":true,
// "rotate":true,
// "perm":0600
//
"perm":0600
// }
// }
func
(
w
*
fileLogWriter
)
Init
(
json
c
onfig
string
)
error
{
func
(
w
*
fileLogWriter
)
Init
(
json
C
onfig
string
)
error
{
err
:=
json
.
Unmarshal
([]
byte
(
json
c
onfig
),
w
)
err
:=
json
.
Unmarshal
([]
byte
(
json
C
onfig
),
w
)
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
...
@@ -122,27 +95,22 @@ func (w *fileLogWriter) Init(jsonconfig string) error {
...
@@ -122,27 +95,22 @@ func (w *fileLogWriter) Init(jsonconfig string) error {
// start file logger. create log file and set to locker-inside file writer.
// start file logger. create log file and set to locker-inside file writer.
func
(
w
*
fileLogWriter
)
startLogger
()
error
{
func
(
w
*
fileLogWriter
)
startLogger
()
error
{
f
d
,
err
:=
w
.
createLogFile
()
f
ile
,
err
:=
w
.
createLogFile
()
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
w
.
mw
.
SetFd
(
fd
)
if
w
.
fileWriter
!=
nil
{
w
.
fileWriter
.
Close
()
}
w
.
fileWriter
=
file
return
w
.
initFd
()
return
w
.
initFd
()
}
}
func
(
w
*
fileLogWriter
)
docheck
(
size
int
)
{
func
(
w
*
fileLogWriter
)
needRotate
(
size
int
,
day
int
)
bool
{
w
.
startLock
.
Lock
()
return
(
w
.
MaxLines
>
0
&&
w
.
maxLinesCurLines
>=
w
.
MaxLines
)
||
defer
w
.
startLock
.
Unlock
()
(
w
.
MaxSize
>
0
&&
w
.
maxSizeCurSize
>=
w
.
MaxSize
)
||
if
w
.
Rotate
&&
((
w
.
Maxlines
>
0
&&
w
.
maxlinesCurlines
>=
w
.
Maxlines
)
||
(
w
.
Daily
&&
day
!=
w
.
dailyOpenDate
)
(
w
.
Maxsize
>
0
&&
w
.
maxsizeCursize
>=
w
.
Maxsize
)
||
(
w
.
Daily
&&
time
.
Now
()
.
Day
()
!=
w
.
dailyOpendate
))
{
if
err
:=
w
.
DoRotate
();
err
!=
nil
{
fmt
.
Fprintf
(
os
.
Stderr
,
"FileLogWriter(%q): %s
\n
"
,
w
.
Filename
,
err
)
return
}
}
w
.
maxlinesCurlines
++
w
.
maxsizeCursize
+=
size
}
}
// WriteMsg write logger message into file.
// WriteMsg write logger message into file.
...
@@ -150,10 +118,68 @@ func (w *fileLogWriter) WriteMsg(msg string, level int) error {
...
@@ -150,10 +118,68 @@ func (w *fileLogWriter) WriteMsg(msg string, level int) error {
if
level
>
w
.
Level
{
if
level
>
w
.
Level
{
return
nil
return
nil
}
}
n
:=
24
+
len
(
msg
)
// 24 stand for the length "2013/06/23 21:00:22 [T] "
//2016/01/12 21:34:33
w
.
docheck
(
n
)
now
:=
time
.
Now
()
w
.
Logger
.
Println
(
msg
)
y
,
mo
,
d
:=
now
.
Date
()
return
nil
h
,
mi
,
s
:=
now
.
Clock
()
//len(2006/01/02 15:03:04)==19
var
buf
[
20
]
byte
t
:=
3
for
y
>=
10
{
p
:=
y
/
10
buf
[
t
]
=
byte
(
'0'
+
y
-
p
*
10
)
y
=
p
t
--
}
buf
[
0
]
=
byte
(
'0'
+
y
)
buf
[
4
]
=
'/'
if
mo
>
9
{
buf
[
5
]
=
'1'
buf
[
6
]
=
byte
(
'0'
+
mo
-
9
)
}
else
{
buf
[
5
]
=
'0'
buf
[
6
]
=
byte
(
'0'
+
mo
)
}
buf
[
7
]
=
'/'
t
=
d
/
10
buf
[
8
]
=
byte
(
'0'
+
t
)
buf
[
9
]
=
byte
(
'0'
+
d
-
t
*
10
)
buf
[
10
]
=
' '
t
=
h
/
10
buf
[
11
]
=
byte
(
'0'
+
t
)
buf
[
12
]
=
byte
(
'0'
+
h
-
t
*
10
)
buf
[
13
]
=
':'
t
=
mi
/
10
buf
[
14
]
=
byte
(
'0'
+
t
)
buf
[
15
]
=
byte
(
'0'
+
mi
-
t
*
10
)
buf
[
16
]
=
':'
t
=
s
/
10
buf
[
17
]
=
byte
(
'0'
+
t
)
buf
[
18
]
=
byte
(
'0'
+
s
-
t
*
10
)
buf
[
19
]
=
' '
msg
=
string
(
buf
[
0
:
])
+
msg
+
"
\n
"
if
w
.
Rotate
{
if
w
.
needRotate
(
len
(
msg
),
d
)
{
w
.
Lock
()
if
w
.
needRotate
(
len
(
msg
),
d
)
{
if
err
:=
w
.
doRotate
();
err
!=
nil
{
fmt
.
Fprintf
(
os
.
Stderr
,
"FileLogWriter(%q): %s
\n
"
,
w
.
Filename
,
err
)
}
}
w
.
Unlock
()
}
}
w
.
Lock
()
_
,
err
:=
w
.
fileWriter
.
Write
([]
byte
(
msg
))
if
err
==
nil
{
w
.
maxLinesCurLines
++
w
.
maxSizeCurSize
+=
len
(
msg
)
}
w
.
Unlock
()
return
err
}
}
func
(
w
*
fileLogWriter
)
createLogFile
()
(
*
os
.
File
,
error
)
{
func
(
w
*
fileLogWriter
)
createLogFile
()
(
*
os
.
File
,
error
)
{
...
@@ -163,20 +189,20 @@ func (w *fileLogWriter) createLogFile() (*os.File, error) {
...
@@ -163,20 +189,20 @@ func (w *fileLogWriter) createLogFile() (*os.File, error) {
}
}
func
(
w
*
fileLogWriter
)
initFd
()
error
{
func
(
w
*
fileLogWriter
)
initFd
()
error
{
fd
:=
w
.
mw
.
fd
fd
:=
w
.
fileWriter
f
i
nfo
,
err
:=
fd
.
Stat
()
f
I
nfo
,
err
:=
fd
.
Stat
()
if
err
!=
nil
{
if
err
!=
nil
{
return
fmt
.
Errorf
(
"get stat err: %s
\n
"
,
err
)
return
fmt
.
Errorf
(
"get stat err: %s
\n
"
,
err
)
}
}
w
.
max
sizeCursize
=
int
(
fi
nfo
.
Size
())
w
.
max
SizeCurSize
=
int
(
fI
nfo
.
Size
())
w
.
dailyOpen
d
ate
=
time
.
Now
()
.
Day
()
w
.
dailyOpen
D
ate
=
time
.
Now
()
.
Day
()
w
.
max
linesCurl
ines
=
0
w
.
max
LinesCurL
ines
=
0
if
f
i
nfo
.
Size
()
>
0
{
if
f
I
nfo
.
Size
()
>
0
{
count
,
err
:=
w
.
lines
()
count
,
err
:=
w
.
lines
()
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
w
.
max
linesCurl
ines
=
count
w
.
max
LinesCurL
ines
=
count
}
}
return
nil
return
nil
}
}
...
@@ -210,50 +236,47 @@ func (w *fileLogWriter) lines() (int, error) {
...
@@ -210,50 +236,47 @@ func (w *fileLogWriter) lines() (int, error) {
// DoRotate means it need to write file in new file.
// DoRotate means it need to write file in new file.
// new file name like xx.2013-01-01.2.log
// new file name like xx.2013-01-01.2.log
func
(
w
*
fileLogWriter
)
D
oRotate
()
error
{
func
(
w
*
fileLogWriter
)
d
oRotate
()
error
{
_
,
err
:=
os
.
Lstat
(
w
.
Filename
)
_
,
err
:=
os
.
Lstat
(
w
.
Filename
)
if
err
==
nil
{
// file exists
if
err
!=
nil
{
// Find the next available number
return
err
num
:=
1
}
fname
:=
""
// file exists
suffix
:=
filepath
.
Ext
(
w
.
Filename
)
// Find the next available number
filenameOnly
:=
strings
.
TrimSuffix
(
w
.
Filename
,
suffix
)
num
:=
1
if
suffix
==
""
{
fName
:=
""
suffix
=
".log"
suffix
:=
filepath
.
Ext
(
w
.
Filename
)
}
filenameOnly
:=
strings
.
TrimSuffix
(
w
.
Filename
,
suffix
)
for
;
err
==
nil
&&
num
<=
999
;
num
++
{
if
suffix
==
""
{
fname
=
filenameOnly
+
fmt
.
Sprintf
(
".%s.%03d%s"
,
time
.
Now
()
.
Format
(
"2006-01-02"
),
num
,
suffix
)
suffix
=
".log"
_
,
err
=
os
.
Lstat
(
fname
)
}
}
for
;
err
==
nil
&&
num
<=
999
;
num
++
{
// return error if the last file checked still existed
fName
=
filenameOnly
+
fmt
.
Sprintf
(
".%s.%03d%s"
,
time
.
Now
()
.
Format
(
"2006-01-02"
),
num
,
suffix
)
if
err
==
nil
{
_
,
err
=
os
.
Lstat
(
fName
)
return
fmt
.
Errorf
(
"Rotate: Cannot find free log number to rename %s
\n
"
,
w
.
Filename
)
}
}
// return error if the last file checked still existed
if
err
==
nil
{
// block Logger's io.Writer
return
fmt
.
Errorf
(
"Rotate: Cannot find free log number to rename %s
\n
"
,
w
.
Filename
)
w
.
mw
.
Lock
()
}
defer
w
.
mw
.
Unlock
()
fd
:=
w
.
mw
.
fd
fd
.
Close
()
// close fd before rename
// close fileWriter before rename
// Rename the file to its newfound home
w
.
fileWriter
.
Close
()
err
=
os
.
Rename
(
w
.
Filename
,
fname
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"Rotate: %s
\n
"
,
err
)
}
// re-start logger
// Rename the file to its new found name
err
=
w
.
startLogger
()
// even if occurs error,we MUST guarantee to restart new logger
if
err
!=
nil
{
renameErr
:=
os
.
Rename
(
w
.
Filename
,
fName
)
return
fmt
.
Errorf
(
"Rotate StartLogger: %s
\n
"
,
err
)
// re-start logger
}
startLoggerErr
:=
w
.
startLogger
()
go
w
.
deleteOldLog
()
go
w
.
deleteOldLog
()
if
startLoggerErr
!=
nil
{
return
fmt
.
Errorf
(
"Rotate StartLogger: %s
\n
"
,
startLoggerErr
)
}
if
renameErr
!=
nil
{
return
fmt
.
Errorf
(
"Rotate: %s
\n
"
,
renameErr
)
}
}
return
nil
return
nil
}
}
func
(
w
*
fileLogWriter
)
deleteOldLog
()
{
func
(
w
*
fileLogWriter
)
deleteOldLog
()
{
...
@@ -261,12 +284,11 @@ func (w *fileLogWriter) deleteOldLog() {
...
@@ -261,12 +284,11 @@ func (w *fileLogWriter) deleteOldLog() {
filepath
.
Walk
(
dir
,
func
(
path
string
,
info
os
.
FileInfo
,
err
error
)
(
returnErr
error
)
{
filepath
.
Walk
(
dir
,
func
(
path
string
,
info
os
.
FileInfo
,
err
error
)
(
returnErr
error
)
{
defer
func
()
{
defer
func
()
{
if
r
:=
recover
();
r
!=
nil
{
if
r
:=
recover
();
r
!=
nil
{
returnErr
=
fmt
.
Errorf
(
"Unable to delete old log '%s', error: %+v"
,
path
,
r
)
fmt
.
Fprintf
(
os
.
Stderr
,
"Unable to delete old log '%s', error: %v
\n
"
,
path
,
r
)
fmt
.
Println
(
returnErr
)
}
}
}()
}()
if
!
info
.
IsDir
()
&&
info
.
ModTime
()
.
Unix
()
<
(
time
.
Now
()
.
Unix
()
-
60
*
60
*
24
*
w
.
Max
d
ays
)
{
if
!
info
.
IsDir
()
&&
info
.
ModTime
()
.
Unix
()
<
(
time
.
Now
()
.
Unix
()
-
60
*
60
*
24
*
w
.
Max
D
ays
)
{
if
strings
.
HasPrefix
(
filepath
.
Base
(
path
),
filepath
.
Base
(
w
.
Filename
))
{
if
strings
.
HasPrefix
(
filepath
.
Base
(
path
),
filepath
.
Base
(
w
.
Filename
))
{
os
.
Remove
(
path
)
os
.
Remove
(
path
)
}
}
...
@@ -275,16 +297,16 @@ func (w *fileLogWriter) deleteOldLog() {
...
@@ -275,16 +297,16 @@ func (w *fileLogWriter) deleteOldLog() {
})
})
}
}
// Destroy close the file desciption, close file writer.
// Destroy close the file desc
r
iption, close file writer.
func
(
w
*
fileLogWriter
)
Destroy
()
{
func
(
w
*
fileLogWriter
)
Destroy
()
{
w
.
mw
.
fd
.
Close
()
w
.
fileWriter
.
Close
()
}
}
// Flush flush file logger.
// Flush flush file logger.
// there are no buffering messages in file logger in memory.
// there are no buffering messages in file logger in memory.
// flush file means sync file from disk.
// flush file means sync file from disk.
func
(
w
*
fileLogWriter
)
Flush
()
{
func
(
w
*
fileLogWriter
)
Flush
()
{
w
.
mw
.
fd
.
Sync
()
w
.
fileWriter
.
Sync
()
}
}
func
init
()
{
func
init
()
{
...
...
logs/file_test.go
View file @
0eaf923a
...
@@ -23,7 +23,7 @@ import (
...
@@ -23,7 +23,7 @@ import (
"time"
"time"
)
)
func
TestFile
(
t
*
testing
.
T
)
{
func
TestFile
1
(
t
*
testing
.
T
)
{
log
:=
NewLogger
(
10000
)
log
:=
NewLogger
(
10000
)
log
.
SetLogger
(
"file"
,
`{"filename":"test.log"}`
)
log
.
SetLogger
(
"file"
,
`{"filename":"test.log"}`
)
log
.
Debug
(
"debug"
)
log
.
Debug
(
"debug"
)
...
@@ -34,25 +34,24 @@ func TestFile(t *testing.T) {
...
@@ -34,25 +34,24 @@ func TestFile(t *testing.T) {
log
.
Alert
(
"alert"
)
log
.
Alert
(
"alert"
)
log
.
Critical
(
"critical"
)
log
.
Critical
(
"critical"
)
log
.
Emergency
(
"emergency"
)
log
.
Emergency
(
"emergency"
)
time
.
Sleep
(
time
.
Second
*
4
)
f
,
err
:=
os
.
Open
(
"test.log"
)
f
,
err
:=
os
.
Open
(
"test.log"
)
if
err
!=
nil
{
if
err
!=
nil
{
t
.
Fatal
(
err
)
t
.
Fatal
(
err
)
}
}
b
:=
bufio
.
NewReader
(
f
)
b
:=
bufio
.
NewReader
(
f
)
line
n
um
:=
0
line
N
um
:=
0
for
{
for
{
line
,
_
,
err
:=
b
.
ReadLine
()
line
,
_
,
err
:=
b
.
ReadLine
()
if
err
!=
nil
{
if
err
!=
nil
{
break
break
}
}
if
len
(
line
)
>
0
{
if
len
(
line
)
>
0
{
line
n
um
++
line
N
um
++
}
}
}
}
var
expected
=
LevelDebug
+
1
var
expected
=
LevelDebug
+
1
if
line
n
um
!=
expected
{
if
line
N
um
!=
expected
{
t
.
Fatal
(
line
n
um
,
"not "
+
strconv
.
Itoa
(
expected
)
+
" lines"
)
t
.
Fatal
(
line
N
um
,
"not "
+
strconv
.
Itoa
(
expected
)
+
" lines"
)
}
}
os
.
Remove
(
"test.log"
)
os
.
Remove
(
"test.log"
)
}
}
...
@@ -68,25 +67,24 @@ func TestFile2(t *testing.T) {
...
@@ -68,25 +67,24 @@ func TestFile2(t *testing.T) {
log
.
Alert
(
"alert"
)
log
.
Alert
(
"alert"
)
log
.
Critical
(
"critical"
)
log
.
Critical
(
"critical"
)
log
.
Emergency
(
"emergency"
)
log
.
Emergency
(
"emergency"
)
time
.
Sleep
(
time
.
Second
*
4
)
f
,
err
:=
os
.
Open
(
"test2.log"
)
f
,
err
:=
os
.
Open
(
"test2.log"
)
if
err
!=
nil
{
if
err
!=
nil
{
t
.
Fatal
(
err
)
t
.
Fatal
(
err
)
}
}
b
:=
bufio
.
NewReader
(
f
)
b
:=
bufio
.
NewReader
(
f
)
line
n
um
:=
0
line
N
um
:=
0
for
{
for
{
line
,
_
,
err
:=
b
.
ReadLine
()
line
,
_
,
err
:=
b
.
ReadLine
()
if
err
!=
nil
{
if
err
!=
nil
{
break
break
}
}
if
len
(
line
)
>
0
{
if
len
(
line
)
>
0
{
line
n
um
++
line
N
um
++
}
}
}
}
var
expected
=
LevelError
+
1
var
expected
=
LevelError
+
1
if
line
n
um
!=
expected
{
if
line
N
um
!=
expected
{
t
.
Fatal
(
line
n
um
,
"not "
+
strconv
.
Itoa
(
expected
)
+
" lines"
)
t
.
Fatal
(
line
N
um
,
"not "
+
strconv
.
Itoa
(
expected
)
+
" lines"
)
}
}
os
.
Remove
(
"test2.log"
)
os
.
Remove
(
"test2.log"
)
}
}
...
@@ -102,13 +100,13 @@ func TestFileRotate(t *testing.T) {
...
@@ -102,13 +100,13 @@ func TestFileRotate(t *testing.T) {
log
.
Alert
(
"alert"
)
log
.
Alert
(
"alert"
)
log
.
Critical
(
"critical"
)
log
.
Critical
(
"critical"
)
log
.
Emergency
(
"emergency"
)
log
.
Emergency
(
"emergency"
)
time
.
Sleep
(
time
.
Second
*
4
)
rotateName
:=
"test3"
+
fmt
.
Sprintf
(
".%s.%03d"
,
time
.
Now
()
.
Format
(
"2006-01-02"
),
1
)
+
".log"
rotatename
:=
"test3"
+
fmt
.
Sprintf
(
".%s.%03d"
,
time
.
Now
()
.
Format
(
"2006-01-02"
),
1
)
+
".log"
b
,
err
:=
exists
(
rotateName
)
b
,
err
:=
exists
(
rotatename
)
if
!
b
||
err
!=
nil
{
if
!
b
||
err
!=
nil
{
os
.
Remove
(
"test3.log"
)
t
.
Fatal
(
"rotate not generated"
)
t
.
Fatal
(
"rotate not generated"
)
}
}
os
.
Remove
(
rotate
n
ame
)
os
.
Remove
(
rotate
N
ame
)
os
.
Remove
(
"test3.log"
)
os
.
Remove
(
"test3.log"
)
}
}
...
@@ -131,3 +129,46 @@ func BenchmarkFile(b *testing.B) {
...
@@ -131,3 +129,46 @@ func BenchmarkFile(b *testing.B) {
}
}
os
.
Remove
(
"test4.log"
)
os
.
Remove
(
"test4.log"
)
}
}
func
BenchmarkFileAsynchronous
(
b
*
testing
.
B
)
{
log
:=
NewLogger
(
100000
)
log
.
SetLogger
(
"file"
,
`{"filename":"test4.log"}`
)
log
.
Async
()
for
i
:=
0
;
i
<
b
.
N
;
i
++
{
log
.
Debug
(
"debug"
)
}
os
.
Remove
(
"test4.log"
)
}
func
BenchmarkFileCallDepth
(
b
*
testing
.
B
)
{
log
:=
NewLogger
(
100000
)
log
.
SetLogger
(
"file"
,
`{"filename":"test4.log"}`
)
log
.
EnableFuncCallDepth
(
true
)
log
.
SetLogFuncCallDepth
(
2
)
for
i
:=
0
;
i
<
b
.
N
;
i
++
{
log
.
Debug
(
"debug"
)
}
os
.
Remove
(
"test4.log"
)
}
func
BenchmarkFileAsynchronousCallDepth
(
b
*
testing
.
B
)
{
log
:=
NewLogger
(
100000
)
log
.
SetLogger
(
"file"
,
`{"filename":"test4.log"}`
)
log
.
EnableFuncCallDepth
(
true
)
log
.
SetLogFuncCallDepth
(
2
)
log
.
Async
()
for
i
:=
0
;
i
<
b
.
N
;
i
++
{
log
.
Debug
(
"debug"
)
}
os
.
Remove
(
"test4.log"
)
}
func
BenchmarkFileOnGoroutine
(
b
*
testing
.
B
)
{
log
:=
NewLogger
(
100000
)
log
.
SetLogger
(
"file"
,
`{"filename":"test4.log"}`
)
for
i
:=
0
;
i
<
b
.
N
;
i
++
{
go
log
.
Debug
(
"debug"
)
}
os
.
Remove
(
"test4.log"
)
}
logs/log.go
View file @
0eaf923a
...
@@ -35,8 +35,10 @@ package logs
...
@@ -35,8 +35,10 @@ package logs
import
(
import
(
"fmt"
"fmt"
"os"
"path"
"path"
"runtime"
"runtime"
"strconv"
"sync"
"sync"
)
)
...
@@ -94,8 +96,13 @@ type BeeLogger struct {
...
@@ -94,8 +96,13 @@ type BeeLogger struct {
enableFuncCallDepth
bool
enableFuncCallDepth
bool
loggerFuncCallDepth
int
loggerFuncCallDepth
int
asynchronous
bool
asynchronous
bool
msg
chan
*
logMsg
msgChan
chan
*
logMsg
outputs
map
[
string
]
Logger
outputs
[]
*
nameLogger
}
type
nameLogger
struct
{
Logger
name
string
}
}
type
logMsg
struct
{
type
logMsg
struct
{
...
@@ -103,59 +110,79 @@ type logMsg struct {
...
@@ -103,59 +110,79 @@ type logMsg struct {
msg
string
msg
string
}
}
var
logMsgPool
*
sync
.
Pool
// NewLogger returns a new BeeLogger.
// NewLogger returns a new BeeLogger.
// channel
len means the number of messages in chan
.
// channel
Len means the number of messages in chan(used where asynchronous is true)
.
// if the buffering chan is full, logger adapters write to file or other way.
// if the buffering chan is full, logger adapters write to file or other way.
func
NewLogger
(
channel
l
en
int64
)
*
BeeLogger
{
func
NewLogger
(
channel
L
en
int64
)
*
BeeLogger
{
bl
:=
new
(
BeeLogger
)
bl
:=
new
(
BeeLogger
)
bl
.
level
=
LevelDebug
bl
.
level
=
LevelDebug
bl
.
loggerFuncCallDepth
=
2
bl
.
loggerFuncCallDepth
=
2
bl
.
msg
=
make
(
chan
*
logMsg
,
channellen
)
bl
.
msgChan
=
make
(
chan
*
logMsg
,
channelLen
)
bl
.
outputs
=
make
(
map
[
string
]
Logger
)
return
bl
return
bl
}
}
// Async set the log to asynchronous and start the goroutine
// Async set the log to asynchronous and start the goroutine
func
(
bl
*
BeeLogger
)
Async
()
*
BeeLogger
{
func
(
bl
*
BeeLogger
)
Async
()
*
BeeLogger
{
bl
.
asynchronous
=
true
bl
.
asynchronous
=
true
logMsgPool
=
&
sync
.
Pool
{
New
:
func
()
interface
{}
{
return
&
logMsg
{}
},
}
go
bl
.
startLogger
()
go
bl
.
startLogger
()
return
bl
return
bl
}
}
// SetLogger provides a given logger adapter into BeeLogger with config string.
// SetLogger provides a given logger adapter into BeeLogger with config string.
// config need to be correct JSON as string: {"interval":360}.
// config need to be correct JSON as string: {"interval":360}.
func
(
bl
*
BeeLogger
)
SetLogger
(
adapter
n
ame
string
,
config
string
)
error
{
func
(
bl
*
BeeLogger
)
SetLogger
(
adapter
N
ame
string
,
config
string
)
error
{
bl
.
lock
.
Lock
()
bl
.
lock
.
Lock
()
defer
bl
.
lock
.
Unlock
()
defer
bl
.
lock
.
Unlock
()
if
log
,
ok
:=
adapters
[
adapter
n
ame
];
ok
{
if
log
,
ok
:=
adapters
[
adapter
N
ame
];
ok
{
lg
:=
log
()
lg
:=
log
()
err
:=
lg
.
Init
(
config
)
err
:=
lg
.
Init
(
config
)
bl
.
outputs
[
adaptername
]
=
lg
if
err
!=
nil
{
if
err
!=
nil
{
fmt
.
Println
(
"logs.BeeLogger.SetLogger: "
+
err
.
Error
())
fmt
.
Fprintln
(
os
.
Stderr
,
"logs.BeeLogger.SetLogger: "
+
err
.
Error
())
return
err
return
err
}
}
bl
.
outputs
=
append
(
bl
.
outputs
,
&
nameLogger
{
name
:
adapterName
,
Logger
:
lg
})
}
else
{
}
else
{
return
fmt
.
Errorf
(
"logs: unknown adaptername %q (forgotten Register?)"
,
adapter
n
ame
)
return
fmt
.
Errorf
(
"logs: unknown adaptername %q (forgotten Register?)"
,
adapter
N
ame
)
}
}
return
nil
return
nil
}
}
// DelLogger remove a logger adapter in BeeLogger.
// DelLogger remove a logger adapter in BeeLogger.
func
(
bl
*
BeeLogger
)
DelLogger
(
adapter
n
ame
string
)
error
{
func
(
bl
*
BeeLogger
)
DelLogger
(
adapter
N
ame
string
)
error
{
bl
.
lock
.
Lock
()
bl
.
lock
.
Lock
()
defer
bl
.
lock
.
Unlock
()
defer
bl
.
lock
.
Unlock
()
if
lg
,
ok
:=
bl
.
outputs
[
adaptername
];
ok
{
outputs
:=
[]
*
nameLogger
{}
lg
.
Destroy
()
for
_
,
lg
:=
range
bl
.
outputs
{
delete
(
bl
.
outputs
,
adaptername
)
if
lg
.
name
==
adapterName
{
return
nil
lg
.
Destroy
()
}
else
{
outputs
=
append
(
outputs
,
lg
)
}
}
}
return
fmt
.
Errorf
(
"logs: unknown adaptername %q (forgotten Register?)"
,
adaptername
)
if
len
(
outputs
)
==
len
(
bl
.
outputs
)
{
return
fmt
.
Errorf
(
"logs: unknown adaptername %q (forgotten Register?)"
,
adapterName
)
}
bl
.
outputs
=
outputs
return
nil
}
}
func
(
bl
*
BeeLogger
)
writerMsg
(
loglevel
int
,
msg
string
)
error
{
func
(
bl
*
BeeLogger
)
writeToLoggers
(
msg
string
,
level
int
)
{
lm
:=
new
(
logMsg
)
for
_
,
l
:=
range
bl
.
outputs
{
lm
.
level
=
loglevel
err
:=
l
.
WriteMsg
(
msg
,
level
)
if
err
!=
nil
{
fmt
.
Fprintf
(
os
.
Stderr
,
"unable to WriteMsg to adapter:%v,error:%v
\n
"
,
l
.
name
,
err
)
}
}
}
func
(
bl
*
BeeLogger
)
writeMsg
(
logLevel
int
,
msg
string
)
error
{
if
bl
.
enableFuncCallDepth
{
if
bl
.
enableFuncCallDepth
{
_
,
file
,
line
,
ok
:=
runtime
.
Caller
(
bl
.
loggerFuncCallDepth
)
_
,
file
,
line
,
ok
:=
runtime
.
Caller
(
bl
.
loggerFuncCallDepth
)
if
!
ok
{
if
!
ok
{
...
@@ -163,20 +190,15 @@ func (bl *BeeLogger) writerMsg(loglevel int, msg string) error {
...
@@ -163,20 +190,15 @@ func (bl *BeeLogger) writerMsg(loglevel int, msg string) error {
line
=
0
line
=
0
}
}
_
,
filename
:=
path
.
Split
(
file
)
_
,
filename
:=
path
.
Split
(
file
)
lm
.
msg
=
fmt
.
Sprintf
(
"[%s:%d] %s"
,
filename
,
line
,
msg
)
msg
=
"["
+
filename
+
":"
+
strconv
.
FormatInt
(
int64
(
line
),
10
)
+
"]"
+
msg
}
else
{
lm
.
msg
=
msg
}
}
if
bl
.
asynchronous
{
if
bl
.
asynchronous
{
bl
.
msg
<-
lm
lm
:=
logMsgPool
.
Get
()
.
(
*
logMsg
)
lm
.
level
=
logLevel
lm
.
msg
=
msg
bl
.
msgChan
<-
lm
}
else
{
}
else
{
for
name
,
l
:=
range
bl
.
outputs
{
bl
.
writeToLoggers
(
msg
,
logLevel
)
err
:=
l
.
WriteMsg
(
lm
.
msg
,
lm
.
level
)
if
err
!=
nil
{
fmt
.
Println
(
"unable to WriteMsg to adapter:"
,
name
,
err
)
return
err
}
}
}
}
return
nil
return
nil
}
}
...
@@ -208,13 +230,9 @@ func (bl *BeeLogger) EnableFuncCallDepth(b bool) {
...
@@ -208,13 +230,9 @@ func (bl *BeeLogger) EnableFuncCallDepth(b bool) {
func
(
bl
*
BeeLogger
)
startLogger
()
{
func
(
bl
*
BeeLogger
)
startLogger
()
{
for
{
for
{
select
{
select
{
case
bm
:=
<-
bl
.
msg
:
case
bm
:=
<-
bl
.
msgChan
:
for
_
,
l
:=
range
bl
.
outputs
{
bl
.
writeToLoggers
(
bm
.
msg
,
bm
.
level
)
err
:=
l
.
WriteMsg
(
bm
.
msg
,
bm
.
level
)
logMsgPool
.
Put
(
bm
)
if
err
!=
nil
{
fmt
.
Println
(
"ERROR, unable to WriteMsg:"
,
err
)
}
}
}
}
}
}
}
}
...
@@ -225,7 +243,7 @@ func (bl *BeeLogger) Emergency(format string, v ...interface{}) {
...
@@ -225,7 +243,7 @@ func (bl *BeeLogger) Emergency(format string, v ...interface{}) {
return
return
}
}
msg
:=
fmt
.
Sprintf
(
"[M] "
+
format
,
v
...
)
msg
:=
fmt
.
Sprintf
(
"[M] "
+
format
,
v
...
)
bl
.
write
r
Msg
(
LevelEmergency
,
msg
)
bl
.
writeMsg
(
LevelEmergency
,
msg
)
}
}
// Alert Log ALERT level message.
// Alert Log ALERT level message.
...
@@ -234,7 +252,7 @@ func (bl *BeeLogger) Alert(format string, v ...interface{}) {
...
@@ -234,7 +252,7 @@ func (bl *BeeLogger) Alert(format string, v ...interface{}) {
return
return
}
}
msg
:=
fmt
.
Sprintf
(
"[A] "
+
format
,
v
...
)
msg
:=
fmt
.
Sprintf
(
"[A] "
+
format
,
v
...
)
bl
.
write
r
Msg
(
LevelAlert
,
msg
)
bl
.
writeMsg
(
LevelAlert
,
msg
)
}
}
// Critical Log CRITICAL level message.
// Critical Log CRITICAL level message.
...
@@ -243,7 +261,7 @@ func (bl *BeeLogger) Critical(format string, v ...interface{}) {
...
@@ -243,7 +261,7 @@ func (bl *BeeLogger) Critical(format string, v ...interface{}) {
return
return
}
}
msg
:=
fmt
.
Sprintf
(
"[C] "
+
format
,
v
...
)
msg
:=
fmt
.
Sprintf
(
"[C] "
+
format
,
v
...
)
bl
.
write
r
Msg
(
LevelCritical
,
msg
)
bl
.
writeMsg
(
LevelCritical
,
msg
)
}
}
// Error Log ERROR level message.
// Error Log ERROR level message.
...
@@ -252,7 +270,7 @@ func (bl *BeeLogger) Error(format string, v ...interface{}) {
...
@@ -252,7 +270,7 @@ func (bl *BeeLogger) Error(format string, v ...interface{}) {
return
return
}
}
msg
:=
fmt
.
Sprintf
(
"[E] "
+
format
,
v
...
)
msg
:=
fmt
.
Sprintf
(
"[E] "
+
format
,
v
...
)
bl
.
write
r
Msg
(
LevelError
,
msg
)
bl
.
writeMsg
(
LevelError
,
msg
)
}
}
// Warning Log WARNING level message.
// Warning Log WARNING level message.
...
@@ -261,7 +279,7 @@ func (bl *BeeLogger) Warning(format string, v ...interface{}) {
...
@@ -261,7 +279,7 @@ func (bl *BeeLogger) Warning(format string, v ...interface{}) {
return
return
}
}
msg
:=
fmt
.
Sprintf
(
"[W] "
+
format
,
v
...
)
msg
:=
fmt
.
Sprintf
(
"[W] "
+
format
,
v
...
)
bl
.
write
r
Msg
(
LevelWarning
,
msg
)
bl
.
writeMsg
(
LevelWarning
,
msg
)
}
}
// Notice Log NOTICE level message.
// Notice Log NOTICE level message.
...
@@ -270,7 +288,7 @@ func (bl *BeeLogger) Notice(format string, v ...interface{}) {
...
@@ -270,7 +288,7 @@ func (bl *BeeLogger) Notice(format string, v ...interface{}) {
return
return
}
}
msg
:=
fmt
.
Sprintf
(
"[N] "
+
format
,
v
...
)
msg
:=
fmt
.
Sprintf
(
"[N] "
+
format
,
v
...
)
bl
.
write
r
Msg
(
LevelNotice
,
msg
)
bl
.
writeMsg
(
LevelNotice
,
msg
)
}
}
// Informational Log INFORMATIONAL level message.
// Informational Log INFORMATIONAL level message.
...
@@ -279,7 +297,7 @@ func (bl *BeeLogger) Informational(format string, v ...interface{}) {
...
@@ -279,7 +297,7 @@ func (bl *BeeLogger) Informational(format string, v ...interface{}) {
return
return
}
}
msg
:=
fmt
.
Sprintf
(
"[I] "
+
format
,
v
...
)
msg
:=
fmt
.
Sprintf
(
"[I] "
+
format
,
v
...
)
bl
.
write
r
Msg
(
LevelInformational
,
msg
)
bl
.
writeMsg
(
LevelInformational
,
msg
)
}
}
// Debug Log DEBUG level message.
// Debug Log DEBUG level message.
...
@@ -288,7 +306,7 @@ func (bl *BeeLogger) Debug(format string, v ...interface{}) {
...
@@ -288,7 +306,7 @@ func (bl *BeeLogger) Debug(format string, v ...interface{}) {
return
return
}
}
msg
:=
fmt
.
Sprintf
(
"[D] "
+
format
,
v
...
)
msg
:=
fmt
.
Sprintf
(
"[D] "
+
format
,
v
...
)
bl
.
write
r
Msg
(
LevelDebug
,
msg
)
bl
.
writeMsg
(
LevelDebug
,
msg
)
}
}
// Warn Log WARN level message.
// Warn Log WARN level message.
...
@@ -298,7 +316,7 @@ func (bl *BeeLogger) Warn(format string, v ...interface{}) {
...
@@ -298,7 +316,7 @@ func (bl *BeeLogger) Warn(format string, v ...interface{}) {
return
return
}
}
msg
:=
fmt
.
Sprintf
(
"[W] "
+
format
,
v
...
)
msg
:=
fmt
.
Sprintf
(
"[W] "
+
format
,
v
...
)
bl
.
write
r
Msg
(
LevelWarning
,
msg
)
bl
.
writeMsg
(
LevelWarning
,
msg
)
}
}
// Info Log INFO level message.
// Info Log INFO level message.
...
@@ -308,7 +326,7 @@ func (bl *BeeLogger) Info(format string, v ...interface{}) {
...
@@ -308,7 +326,7 @@ func (bl *BeeLogger) Info(format string, v ...interface{}) {
return
return
}
}
msg
:=
fmt
.
Sprintf
(
"[I] "
+
format
,
v
...
)
msg
:=
fmt
.
Sprintf
(
"[I] "
+
format
,
v
...
)
bl
.
write
r
Msg
(
LevelInformational
,
msg
)
bl
.
writeMsg
(
LevelInformational
,
msg
)
}
}
// Trace Log TRACE level message.
// Trace Log TRACE level message.
...
@@ -318,7 +336,7 @@ func (bl *BeeLogger) Trace(format string, v ...interface{}) {
...
@@ -318,7 +336,7 @@ func (bl *BeeLogger) Trace(format string, v ...interface{}) {
return
return
}
}
msg
:=
fmt
.
Sprintf
(
"[D] "
+
format
,
v
...
)
msg
:=
fmt
.
Sprintf
(
"[D] "
+
format
,
v
...
)
bl
.
write
r
Msg
(
LevelDebug
,
msg
)
bl
.
writeMsg
(
LevelDebug
,
msg
)
}
}
// Flush flush all chan data.
// Flush flush all chan data.
...
@@ -331,14 +349,10 @@ func (bl *BeeLogger) Flush() {
...
@@ -331,14 +349,10 @@ func (bl *BeeLogger) Flush() {
// Close close logger, flush all chan data and destroy all adapters in BeeLogger.
// Close close logger, flush all chan data and destroy all adapters in BeeLogger.
func
(
bl
*
BeeLogger
)
Close
()
{
func
(
bl
*
BeeLogger
)
Close
()
{
for
{
for
{
if
len
(
bl
.
msg
)
>
0
{
if
len
(
bl
.
msgChan
)
>
0
{
bm
:=
<-
bl
.
msg
bm
:=
<-
bl
.
msgChan
for
_
,
l
:=
range
bl
.
outputs
{
bl
.
writeToLoggers
(
bm
.
msg
,
bm
.
level
)
err
:=
l
.
WriteMsg
(
bm
.
msg
,
bm
.
level
)
logMsgPool
.
Put
(
bm
)
if
err
!=
nil
{
fmt
.
Println
(
"ERROR, unable to WriteMsg (while closing logger):"
,
err
)
}
}
continue
continue
}
}
break
break
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment