improving logger to write to a file

This commit is contained in:
hyung-hwan 2024-12-14 14:04:33 +09:00
parent 3299ca0fb2
commit bc9a40106c
4 changed files with 104 additions and 37 deletions

View File

@ -721,36 +721,53 @@ func (cts *ClientConn) AddClientRoutes(peer_addrs []string) error {
for _, v = range peer_addrs { for _, v = range peer_addrs {
va = strings.Split(v, ",") va = strings.Split(v, ",")
if len(va) <= 0 || len(va) >= 4 { if len(va) <= 0 { return fmt.Errorf("blank value") }
return fmt.Errorf("invalid address %v", va) if len(va) >= 5 { return fmt.Errorf("too many fields in %v", v) }
}
_, port, err = net.SplitHostPort(va[0]) _, port, err = net.SplitHostPort(strings.TrimSpace(va[0]))
if err != nil { if err != nil {
return fmt.Errorf("invalid address %s", va[0], err.Error()) return fmt.Errorf("invalid address %s", va[0], err.Error())
} }
if len(va) >= 2 { if len(va) >= 2 {
_, _, err = net.SplitHostPort(va[1]) var f string
f = strings.TrimSpace(va[1])
_, _, err = net.SplitHostPort(f)
if err != nil { if err != nil {
return fmt.Errorf("invalid address %s", va[1], err.Error()) return fmt.Errorf("invalid address %s", va[1], err.Error())
} }
svc_addr = va[1] svc_addr = f
}
if len(va) >= 3 {
ptc_name = va[2]
} }
option = RouteOption(ROUTE_OPTION_TCP) option = RouteOption(ROUTE_OPTION_TCP)
// automatic determination of protocol for common ports if len(va) >= 3 {
switch port { switch strings.ToLower(strings.TrimSpace(va[2])) {
case "22": case "ssh":
option |= RouteOption(ROUTE_OPTION_SSH) option |= RouteOption(ROUTE_OPTION_SSH)
case "80": case "http":
option |= RouteOption(ROUTE_OPTION_HTTP) option |= RouteOption(ROUTE_OPTION_HTTP)
case "443": case "https":
option |= RouteOption(ROUTE_OPTION_HTTPS) option |= RouteOption(ROUTE_OPTION_HTTPS)
case "":
fallthrough
case "auto":
// automatic determination of protocol for common ports
switch port {
case "22":
option |= RouteOption(ROUTE_OPTION_SSH)
case "80":
option |= RouteOption(ROUTE_OPTION_HTTP)
case "443":
option |= RouteOption(ROUTE_OPTION_HTTPS)
}
default:
return fmt.Errorf("invalid option value %s", va[2])
}
}
if len(va) >= 4 {
ptc_name = strings.TrimSpace(va[3])
} }
_, err = cts.AddNewClientRoute(va[0], ptc_name, svc_addr, "", option) _, err = cts.AddNewClientRoute(va[0], ptc_name, svc_addr, "", option)
@ -1460,6 +1477,9 @@ func (c *Client) StopServices() {
} }
} }
func (s *Client) FixServices() {
}
func (c *Client) WaitForTermination() { func (c *Client) WaitForTermination() {
c.wg.Wait() c.wg.Wait()
} }

View File

@ -29,10 +29,30 @@ var hodul_tls_key_text []byte
// -------------------------------------------------------------------- // --------------------------------------------------------------------
type AppLogger struct { type AppLogger struct {
id string Id string
out io.Writer Out io.Writer
mtx sync.Mutex Mask hodu.LogMask
mask hodu.LogMask
_mtx sync.Mutex
_file *os.File
}
func NewAppLogger (id string, w io.Writer, mask hodu.LogMask) *AppLogger {
return &AppLogger{Id: id, Out: w, Mask: mask}
}
func NewAppLoggerToFile (id string, file string, mask hodu.LogMask) (*AppLogger, error) {
var err error
var f *os.File
f, err = os.OpenFile(file, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
if err != nil { return nil, err }
return &AppLogger{Id: id, Out: f, Mask: mask, _file: f}, nil
}
func (l* AppLogger) Close() {
if l._file != nil { l._file.Close() }
} }
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{}) {
@ -47,7 +67,7 @@ func (l* AppLogger) Write(id string, level hodu.LogLevel, fmtstr string, args ..
var caller_line int var caller_line int
var caller_ok bool var caller_ok bool
if l.mask & hodu.LogMask(level) == 0 { return } if l.Mask & hodu.LogMask(level) == 0 { return }
now = time.Now() now = time.Now()
@ -65,20 +85,20 @@ func (l* AppLogger) Write(id string, level hodu.LogLevel, fmtstr string, args ..
// TODO: add pid? // TODO: add pid?
msg = fmt.Sprintf(fmtstr, args...) msg = fmt.Sprintf(fmtstr, args...)
if id == "" { if id == "" {
lid = fmt.Sprintf("%s: ", l.id) lid = fmt.Sprintf("%s: ", l.Id)
} else { } else {
lid = fmt.Sprintf("%s(%s): ", l.id, id) lid = fmt.Sprintf("%s(%s): ", l.Id, id)
} }
l.mtx.Lock() l._mtx.Lock()
l.out.Write([]byte(hdr)) l.Out.Write([]byte(hdr))
if caller_ok { if caller_ok {
l.out.Write([]byte(fmt.Sprintf("[%s:%d] ", filepath.Base(caller_file), caller_line))) l.Out.Write([]byte(fmt.Sprintf("[%s:%d] ", filepath.Base(caller_file), caller_line)))
} }
if lid != "" { l.out.Write([]byte(lid)) } if lid != "" { l.Out.Write([]byte(lid)) }
l.out.Write([]byte(msg)) l.Out.Write([]byte(msg))
if msg[len(msg) - 1] != '\n' { l.out.Write([]byte("\n")) } if msg[len(msg) - 1] != '\n' { l.Out.Write([]byte("\n")) }
l.mtx.Unlock() l._mtx.Unlock()
} }
// -------------------------------------------------------------------- // --------------------------------------------------------------------
@ -105,8 +125,8 @@ chan_loop:
for { for {
select { select {
case <-sighup_chan: case <-sighup_chan:
// TODO: sh.svc.FixServices()
//sh.svc.ReqReload()
case sig = <-sigterm_chan: case sig = <-sigterm_chan:
sh.svc.StopServices() sh.svc.StopServices()
sh.svc.WriteLog ("", hodu.LOG_INFO, "Received %s signal", sig) sh.svc.WriteLog ("", hodu.LOG_INFO, "Received %s signal", sig)
@ -132,6 +152,9 @@ func (sh *signal_handler) StopServices() {
syscall.Kill(syscall.Getpid(), syscall.SIGTERM) // TODO: find a better to terminate the signal handler... syscall.Kill(syscall.Getpid(), syscall.SIGTERM) // TODO: find a better to terminate the signal handler...
} }
func (sh *signal_handler) FixServices() {
}
func (sh *signal_handler) WaitForTermination() { func (sh *signal_handler) WaitForTermination() {
// not implemented. see the comment in StartServices() // not implemented. see the comment in StartServices()
// sh.wg.Wait() // sh.wg.Wait()
@ -151,6 +174,7 @@ func server_main(ctl_addrs []string, rpc_addrs []string, pxy_addrs []string, cfg
var ctl_prefix string var ctl_prefix string
var logger *AppLogger var logger *AppLogger
var log_mask hodu.LogMask var log_mask hodu.LogMask
var log_file string
var max_rpc_conns int var max_rpc_conns int
var max_peers int var max_peers int
var err error var err error
@ -179,6 +203,7 @@ func server_main(ctl_addrs []string, rpc_addrs []string, pxy_addrs []string, cfg
ctl_prefix = cfg.CTL.Service.Prefix ctl_prefix = cfg.CTL.Service.Prefix
log_mask = log_strings_to_mask(cfg.APP.LogMask) log_mask = log_strings_to_mask(cfg.APP.LogMask)
log_file = cfg.APP.LogFile
max_rpc_conns = cfg.APP.MaxRpcConns max_rpc_conns = cfg.APP.MaxRpcConns
max_peers = cfg.APP.MaxPeers max_peers = cfg.APP.MaxPeers
} }
@ -187,8 +212,15 @@ func server_main(ctl_addrs []string, rpc_addrs []string, pxy_addrs []string, cfg
return fmt.Errorf("no rpc service addresses specified") return fmt.Errorf("no rpc service addresses specified")
} }
// TODO: Change out field depending on cfg.APP.LogFile if log_file == "" {
logger = &AppLogger{id: "server", out: os.Stderr, mask: log_mask} logger = NewAppLogger("server", os.Stderr, log_mask)
} else {
logger, err = NewAppLoggerToFile("server", log_file, log_mask)
if err != nil {
return fmt.Errorf("failed to initialize logger - %s", err.Error())
}
}
s, err = hodu.NewServer( s, err = hodu.NewServer(
context.Background(), context.Background(),
logger, logger,
@ -210,6 +242,7 @@ func server_main(ctl_addrs []string, rpc_addrs []string, pxy_addrs []string, cfg
s.StartPxyService() s.StartPxyService()
s.StartExtService(&signal_handler{svc:s}, nil) s.StartExtService(&signal_handler{svc:s}, nil)
s.WaitForTermination() s.WaitForTermination()
logger.Close()
return nil return nil
} }
@ -224,6 +257,7 @@ func client_main(ctl_addrs []string, rpc_addrs []string, peer_addrs []string, cf
var cc hodu.ClientConfig var cc hodu.ClientConfig
var logger *AppLogger var logger *AppLogger
var log_mask hodu.LogMask var log_mask hodu.LogMask
var log_file string
var max_rpc_conns int var max_rpc_conns int
var max_peers int var max_peers int
var peer_conn_tmout time.Duration var peer_conn_tmout time.Duration
@ -247,6 +281,7 @@ func client_main(ctl_addrs []string, rpc_addrs []string, peer_addrs []string, cf
cc.ServerSeedTmout = cfg.RPC.Endpoint.SeedTmout cc.ServerSeedTmout = cfg.RPC.Endpoint.SeedTmout
cc.ServerAuthority = cfg.RPC.Endpoint.Authority cc.ServerAuthority = cfg.RPC.Endpoint.Authority
log_mask = log_strings_to_mask(cfg.APP.LogMask) log_mask = log_strings_to_mask(cfg.APP.LogMask)
log_file = cfg.APP.LogFile
max_rpc_conns = cfg.APP.MaxRpcConns max_rpc_conns = cfg.APP.MaxRpcConns
max_peers = cfg.APP.MaxPeers max_peers = cfg.APP.MaxPeers
peer_conn_tmout = cfg.APP.PeerConnTmout peer_conn_tmout = cfg.APP.PeerConnTmout
@ -257,7 +292,14 @@ func client_main(ctl_addrs []string, rpc_addrs []string, peer_addrs []string, cf
cc.ServerAddrs = rpc_addrs cc.ServerAddrs = rpc_addrs
cc.PeerAddrs = peer_addrs cc.PeerAddrs = peer_addrs
logger = &AppLogger{id: "client", out: os.Stderr, mask: log_mask} if log_file == "" {
logger = NewAppLogger("server", os.Stderr, log_mask)
} else {
logger, err = NewAppLoggerToFile("server", log_file, log_mask)
if err != nil {
return fmt.Errorf("failed to initialize logger - %s", err.Error())
}
}
c = hodu.NewClient( c = hodu.NewClient(
context.Background(), context.Background(),
logger, logger,
@ -273,6 +315,7 @@ func client_main(ctl_addrs []string, rpc_addrs []string, peer_addrs []string, cf
c.StartCtlService() // control channel c.StartCtlService() // control channel
c.StartExtService(&signal_handler{svc:c}, nil) // signal handler task c.StartExtService(&signal_handler{svc:c}, nil) // signal handler task
c.WaitForTermination() c.WaitForTermination()
logger.Close()
return nil return nil
} }

View File

@ -34,6 +34,7 @@ type Service interface {
RunTask(wg *sync.WaitGroup) // blocking. run the actual task loop. it must call wg.Done() upon exit from itself. RunTask(wg *sync.WaitGroup) // blocking. run the actual task loop. it must call wg.Done() upon exit from itself.
StartService(data interface{}) // non-blocking. spin up a service. it may be invokded multiple times for multiple instances StartService(data interface{}) // non-blocking. spin up a service. it may be invokded multiple times for multiple instances
StopServices() // non-blocking. send stop request to all services spun up StopServices() // non-blocking. send stop request to all services spun up
FixServices() // do some fixup as needed
WaitForTermination() // blocking. must wait until all services are stopped WaitForTermination() // blocking. must wait until all services are stopped
WriteLog(id string, level LogLevel, fmtstr string, args ...interface{}) WriteLog(id string, level LogLevel, fmtstr string, args ...interface{})
} }

View File

@ -1373,6 +1373,9 @@ func (s *Server) StopServices() {
} }
} }
func (s *Server) FixServices() {
}
func (s *Server) WaitForTermination() { func (s *Server) WaitForTermination() {
s.wg.Wait() s.wg.Wait()
} }