enhanced logging by supporting --log-file and handling a log file under /dev specially
This commit is contained in:
parent
8cab165cc4
commit
fe67d9e16f
@ -10,6 +10,11 @@ import "strings"
|
|||||||
import "sync"
|
import "sync"
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
|
type app_logger_msg_t struct {
|
||||||
|
code int
|
||||||
|
data string
|
||||||
|
}
|
||||||
|
|
||||||
type AppLogger struct {
|
type AppLogger struct {
|
||||||
Id string
|
Id string
|
||||||
Out io.Writer
|
Out io.Writer
|
||||||
@ -19,39 +24,48 @@ type AppLogger struct {
|
|||||||
file_name string // you can get the file name from file but this is to preserve the original.
|
file_name string // you can get the file name from file but this is to preserve the original.
|
||||||
file_rotate int
|
file_rotate int
|
||||||
file_max_size int64
|
file_max_size int64
|
||||||
msg_chan chan string
|
msg_chan chan app_logger_msg_t
|
||||||
stop_req_chan chan struct{}
|
|
||||||
rotate_req_chan chan struct{}
|
|
||||||
wg sync.WaitGroup
|
wg sync.WaitGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAppLogger (id string, w io.Writer, mask hodu.LogMask) *AppLogger {
|
func NewAppLogger (id string, w io.Writer, mask hodu.LogMask) *AppLogger {
|
||||||
var l *AppLogger
|
var l *AppLogger
|
||||||
l = &AppLogger{Id: id, Out: w, Mask: mask, msg_chan: make(chan string, 256), stop_req_chan: make(chan struct{}, 1), rotate_req_chan: make(chan struct{}, 16) }
|
l = &AppLogger{
|
||||||
|
Id: id,
|
||||||
|
Out: w,
|
||||||
|
Mask: mask,
|
||||||
|
msg_chan: make(chan app_logger_msg_t, 256),
|
||||||
|
}
|
||||||
l.wg.Add(1)
|
l.wg.Add(1)
|
||||||
go l.logger_task()
|
go l.logger_task()
|
||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAppLoggerToFile (id string, file string, max_size int64, rotate int, mask hodu.LogMask) (*AppLogger, error) {
|
func NewAppLoggerToFile (id string, file_name string, max_size int64, rotate int, mask hodu.LogMask) (*AppLogger, error) {
|
||||||
var l *AppLogger
|
var l *AppLogger
|
||||||
var f *os.File
|
var f *os.File
|
||||||
|
var matched bool
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
f, err = os.OpenFile(file, os.O_CREATE | os.O_APPEND | os.O_WRONLY, 0666)
|
f, err = os.OpenFile(file_name, os.O_CREATE | os.O_APPEND | os.O_WRONLY, 0666)
|
||||||
if err != nil { return nil, err }
|
if err != nil { return nil, err }
|
||||||
|
|
||||||
|
matched, _ = filepath.Match("/dev/*", file_name)
|
||||||
|
if matched {
|
||||||
|
// if the log file is under /dev, disable rotation
|
||||||
|
max_size = 0
|
||||||
|
rotate = 0
|
||||||
|
}
|
||||||
|
|
||||||
l = &AppLogger{
|
l = &AppLogger{
|
||||||
Id: id,
|
Id: id,
|
||||||
Out: f,
|
Out: f,
|
||||||
Mask: mask,
|
Mask: mask,
|
||||||
file: f,
|
file: f,
|
||||||
file_name: file,
|
file_name: file_name,
|
||||||
file_max_size: max_size,
|
file_max_size: max_size,
|
||||||
file_rotate: rotate,
|
file_rotate: rotate,
|
||||||
msg_chan: make(chan string, 256),
|
msg_chan: make(chan app_logger_msg_t, 256),
|
||||||
stop_req_chan: make(chan struct{}, 1),
|
|
||||||
rotate_req_chan: make(chan struct{}, 16),
|
|
||||||
}
|
}
|
||||||
l.wg.Add(1)
|
l.wg.Add(1)
|
||||||
go l.logger_task()
|
go l.logger_task()
|
||||||
@ -59,42 +73,44 @@ func NewAppLoggerToFile (id string, file string, max_size int64, rotate int, mas
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (l *AppLogger) Close() {
|
func (l *AppLogger) Close() {
|
||||||
l.stop_req_chan <- struct{}{}
|
l.msg_chan <- app_logger_msg_t{code: 1}
|
||||||
l.wg.Wait()
|
l.wg.Wait()
|
||||||
if l.file != nil { l.file.Close() }
|
if l.file != nil { l.file.Close() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *AppLogger) Rotate() {
|
||||||
|
l.msg_chan <- app_logger_msg_t{code: 2}
|
||||||
|
}
|
||||||
|
|
||||||
func (l *AppLogger) logger_task() {
|
func (l *AppLogger) logger_task() {
|
||||||
var msg string
|
var msg app_logger_msg_t
|
||||||
defer l.wg.Done()
|
defer l.wg.Done()
|
||||||
|
|
||||||
main_loop:
|
main_loop:
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case msg = <-l.msg_chan:
|
case msg = <-l.msg_chan:
|
||||||
//l.Out.Write([]byte(msg))
|
if msg.code == 0 {
|
||||||
io.WriteString(l.Out, msg)
|
//l.Out.Write([]byte(msg))
|
||||||
if l.file_max_size > 0 && l.file != nil {
|
io.WriteString(l.Out, msg.data)
|
||||||
var fi os.FileInfo
|
if l.file_max_size > 0 && l.file != nil {
|
||||||
var err error
|
var fi os.FileInfo
|
||||||
fi, err = l.file.Stat()
|
var err error
|
||||||
if err == nil && fi.Size() >= l.file_max_size {
|
fi, err = l.file.Stat()
|
||||||
l.rotate()
|
if err == nil && fi.Size() >= l.file_max_size {
|
||||||
|
l.rotate()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else if msg.code == 1 {
|
||||||
|
break main_loop
|
||||||
|
} else if msg.code == 2 {
|
||||||
|
l.rotate()
|
||||||
}
|
}
|
||||||
|
// other code must not appear here.
|
||||||
case <-l.stop_req_chan:
|
|
||||||
break main_loop
|
|
||||||
|
|
||||||
case <- l.rotate_req_chan:
|
|
||||||
l.rotate()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *AppLogger) Rotate() {
|
|
||||||
l.rotate_req_chan <- struct{}{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *AppLogger) Write(id string, level hodu.LogLevel, fmtstr string, args ...interface{}) {
|
func (l *AppLogger) Write(id string, level hodu.LogLevel, fmtstr string, args ...interface{}) {
|
||||||
if l.Mask & hodu.LogMask(level) == 0 { return }
|
if l.Mask & hodu.LogMask(level) == 0 { return }
|
||||||
@ -148,7 +164,7 @@ func (l *AppLogger) write(id string, level hodu.LogLevel, call_depth int, fmtstr
|
|||||||
if msg[len(msg) - 1] != '\n' { sb.WriteRune('\n') }
|
if msg[len(msg) - 1] != '\n' { sb.WriteRune('\n') }
|
||||||
|
|
||||||
// use queue to avoid blocking operation as much as possible
|
// use queue to avoid blocking operation as much as possible
|
||||||
l.msg_chan <- sb.String()
|
l.msg_chan <- app_logger_msg_t{ code: 0, data: sb.String() }
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *AppLogger) rotate() {
|
func (l *AppLogger) rotate() {
|
||||||
|
14
cmd/main.go
14
cmd/main.go
@ -262,6 +262,7 @@ func main() {
|
|||||||
var ctl_addrs []string
|
var ctl_addrs []string
|
||||||
var pxy_addrs []string
|
var pxy_addrs []string
|
||||||
var cfgfile string
|
var cfgfile string
|
||||||
|
var logfile string
|
||||||
var cfg *ServerConfig
|
var cfg *ServerConfig
|
||||||
|
|
||||||
ctl_addrs = make([]string, 0)
|
ctl_addrs = make([]string, 0)
|
||||||
@ -281,6 +282,10 @@ func main() {
|
|||||||
pxy_addrs = append(pxy_addrs, v)
|
pxy_addrs = append(pxy_addrs, v)
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
flgs.Func("log-file", "specify a log file", func(v string) error {
|
||||||
|
logfile = v
|
||||||
|
return nil
|
||||||
|
})
|
||||||
flgs.Func("config-file", "specify a configuration file path", func(v string) error {
|
flgs.Func("config-file", "specify a configuration file path", func(v string) error {
|
||||||
cfgfile = v
|
cfgfile = v
|
||||||
return nil
|
return nil
|
||||||
@ -302,6 +307,7 @@ func main() {
|
|||||||
goto oops
|
goto oops
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if logfile != "" { cfg.APP.LogFile = logfile }
|
||||||
|
|
||||||
err = server_main(ctl_addrs, rpc_addrs, pxy_addrs, cfg)
|
err = server_main(ctl_addrs, rpc_addrs, pxy_addrs, cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -312,6 +318,7 @@ func main() {
|
|||||||
var rpc_addrs []string
|
var rpc_addrs []string
|
||||||
var ctl_addrs []string
|
var ctl_addrs []string
|
||||||
var cfgfile string
|
var cfgfile string
|
||||||
|
var logfile string
|
||||||
var cfg *ClientConfig
|
var cfg *ClientConfig
|
||||||
|
|
||||||
ctl_addrs = make([]string, 0)
|
ctl_addrs = make([]string, 0)
|
||||||
@ -326,6 +333,10 @@ func main() {
|
|||||||
rpc_addrs = append(rpc_addrs, v)
|
rpc_addrs = append(rpc_addrs, v)
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
flgs.Func("log-file", "specify a log file", func(v string) error {
|
||||||
|
logfile = v
|
||||||
|
return nil
|
||||||
|
})
|
||||||
flgs.Func("config-file", "specify a configuration file path", func(v string) error {
|
flgs.Func("config-file", "specify a configuration file path", func(v string) error {
|
||||||
cfgfile = v
|
cfgfile = v
|
||||||
return nil
|
return nil
|
||||||
@ -338,13 +349,14 @@ func main() {
|
|||||||
goto wrong_usage
|
goto wrong_usage
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cfgfile != "") {
|
if cfgfile != "" {
|
||||||
cfg, err = load_client_config(cfgfile)
|
cfg, err = load_client_config(cfgfile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf ("ERROR: failed to load configuration file %s - %s\n", cfgfile, err.Error())
|
fmt.Printf ("ERROR: failed to load configuration file %s - %s\n", cfgfile, err.Error())
|
||||||
goto oops
|
goto oops
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if logfile != "" { cfg.APP.LogFile = logfile }
|
||||||
|
|
||||||
err = client_main(ctl_addrs, rpc_addrs, flgs.Args(), cfg)
|
err = client_main(ctl_addrs, rpc_addrs, flgs.Args(), cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -278,7 +278,7 @@ func (r *ServerRoute) RunTask(wg *sync.WaitGroup) {
|
|||||||
r.ReqStop()
|
r.ReqStop()
|
||||||
|
|
||||||
r.pts_wg.Wait()
|
r.pts_wg.Wait()
|
||||||
r.cts.svr.log.Write(r.cts.sid, LOG_DEBUG, "All service-side peer handlers completed on route(%d)", r.id)
|
r.cts.svr.log.Write(r.cts.sid, LOG_DEBUG, "All service-side peer handlers ended on route(%d)", r.id)
|
||||||
|
|
||||||
r.cts.RemoveServerRoute(r) // final phase...
|
r.cts.RemoveServerRoute(r) // final phase...
|
||||||
}
|
}
|
||||||
@ -1060,10 +1060,10 @@ task_loop:
|
|||||||
s.ReqStop()
|
s.ReqStop()
|
||||||
|
|
||||||
s.rpc_wg.Wait()
|
s.rpc_wg.Wait()
|
||||||
s.log.Write("", LOG_DEBUG, "All RPC listeners completed")
|
s.log.Write("", LOG_DEBUG, "All RPC listeners ended")
|
||||||
|
|
||||||
s.cts_wg.Wait()
|
s.cts_wg.Wait()
|
||||||
s.log.Write("", LOG_DEBUG, "All CTS handlers completed")
|
s.log.Write("", LOG_DEBUG, "All CTS handlers ended")
|
||||||
|
|
||||||
// stop the main grpc server after all the other tasks are finished.
|
// stop the main grpc server after all the other tasks are finished.
|
||||||
s.rpc_svr.Stop()
|
s.rpc_svr.Stop()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user