From fe67d9e16fee05a5417442be301c540a30cba5ca Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Mon, 16 Dec 2024 00:41:32 +0900 Subject: [PATCH] enhanced logging by supporting --log-file and handling a log file under /dev specially --- cmd/logger.go | 76 +++++++++++++++++++++++++++++++-------------------- cmd/main.go | 14 +++++++++- server.go | 6 ++-- 3 files changed, 62 insertions(+), 34 deletions(-) diff --git a/cmd/logger.go b/cmd/logger.go index 223abe1..3589577 100644 --- a/cmd/logger.go +++ b/cmd/logger.go @@ -10,6 +10,11 @@ import "strings" import "sync" import "time" +type app_logger_msg_t struct { + code int + data string +} + type AppLogger struct { Id string 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_rotate int file_max_size int64 - msg_chan chan string - stop_req_chan chan struct{} - rotate_req_chan chan struct{} + msg_chan chan app_logger_msg_t wg sync.WaitGroup } func NewAppLogger (id string, w io.Writer, mask hodu.LogMask) *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) go l.logger_task() 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 f *os.File + var matched bool 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 } + matched, _ = filepath.Match("/dev/*", file_name) + if matched { + // if the log file is under /dev, disable rotation + max_size = 0 + rotate = 0 + } + l = &AppLogger{ Id: id, Out: f, Mask: mask, file: f, - file_name: file, + file_name: file_name, file_max_size: max_size, file_rotate: rotate, - msg_chan: make(chan string, 256), - stop_req_chan: make(chan struct{}, 1), - rotate_req_chan: make(chan struct{}, 16), + msg_chan: make(chan app_logger_msg_t, 256), } l.wg.Add(1) go l.logger_task() @@ -59,42 +73,44 @@ func NewAppLoggerToFile (id string, file string, max_size int64, rotate int, mas } func (l *AppLogger) Close() { - l.stop_req_chan <- struct{}{} + l.msg_chan <- app_logger_msg_t{code: 1} l.wg.Wait() 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() { - var msg string + var msg app_logger_msg_t defer l.wg.Done() main_loop: for { select { case msg = <-l.msg_chan: - //l.Out.Write([]byte(msg)) - io.WriteString(l.Out, msg) - if l.file_max_size > 0 && l.file != nil { - var fi os.FileInfo - var err error - fi, err = l.file.Stat() - if err == nil && fi.Size() >= l.file_max_size { - l.rotate() + if msg.code == 0 { + //l.Out.Write([]byte(msg)) + io.WriteString(l.Out, msg.data) + if l.file_max_size > 0 && l.file != nil { + var fi os.FileInfo + var err error + fi, err = l.file.Stat() + 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() } - - case <-l.stop_req_chan: - break main_loop - - case <- l.rotate_req_chan: - l.rotate() + // other code must not appear here. } } } -func (l *AppLogger) Rotate() { - l.rotate_req_chan <- struct{}{} -} func (l *AppLogger) Write(id string, level hodu.LogLevel, fmtstr string, args ...interface{}) { 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') } // 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() { diff --git a/cmd/main.go b/cmd/main.go index 9082a7f..a6ff02f 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -262,6 +262,7 @@ func main() { var ctl_addrs []string var pxy_addrs []string var cfgfile string + var logfile string var cfg *ServerConfig ctl_addrs = make([]string, 0) @@ -281,6 +282,10 @@ func main() { pxy_addrs = append(pxy_addrs, v) 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 { cfgfile = v return nil @@ -302,6 +307,7 @@ func main() { goto oops } } + if logfile != "" { cfg.APP.LogFile = logfile } err = server_main(ctl_addrs, rpc_addrs, pxy_addrs, cfg) if err != nil { @@ -312,6 +318,7 @@ func main() { var rpc_addrs []string var ctl_addrs []string var cfgfile string + var logfile string var cfg *ClientConfig ctl_addrs = make([]string, 0) @@ -326,6 +333,10 @@ func main() { rpc_addrs = append(rpc_addrs, v) 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 { cfgfile = v return nil @@ -338,13 +349,14 @@ func main() { goto wrong_usage } - if (cfgfile != "") { + if cfgfile != "" { cfg, err = load_client_config(cfgfile) if err != nil { fmt.Printf ("ERROR: failed to load configuration file %s - %s\n", cfgfile, err.Error()) goto oops } } + if logfile != "" { cfg.APP.LogFile = logfile } err = client_main(ctl_addrs, rpc_addrs, flgs.Args(), cfg) if err != nil { diff --git a/server.go b/server.go index a9c8e3d..1f39c56 100644 --- a/server.go +++ b/server.go @@ -278,7 +278,7 @@ func (r *ServerRoute) RunTask(wg *sync.WaitGroup) { r.ReqStop() 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... } @@ -1060,10 +1060,10 @@ task_loop: s.ReqStop() 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.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. s.rpc_svr.Stop()