123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184 |
- package svcfw
- import (
- "context"
- "fmt"
- "git.swzry.com/zry/GoHiedaLogger/hiedabke_console"
- "git.swzry.com/zry/GoHiedaLogger/hiedalog"
- "git.swzry.com/zry/zry-go-program-framework/core"
- ordmap "github.com/edofic/go-ordmap/v2"
- "github.com/oklog/run"
- "github.com/s0rg/trie"
- "io"
- "sync"
- )
- var _ core.IAppFramework = (*AppFramework)(nil)
- var _ core.IModuleLogger = (*AppFramework)(nil)
- var _ core.IModuleLogLevelLimiter = (*AppFramework)(nil)
- type AppFramework struct {
- rg *run.Group
- logger *hiedalog.HiedaLogger
- gctx context.Context
- gcncl context.CancelFunc
- subSvc ordmap.NodeBuiltin[string, *core.SubServiceWrapper]
- moduleLoggers *trie.Trie[core.IModuleLogger]
- moduleLoggersLock sync.RWMutex
- appLogModuleName string
- globalDebugSwitch bool
- prepared bool
- consoleLogBackend *hiedabke_console.ConsoleBackend
- mainLogLevelLimit uint8
- core.IModuleLogger
- core.IModuleLogLevelLimiter
- }
- func NewAppFramework(globalDebugMode bool, appLogModuleName string) *AppFramework {
- f := &AppFramework{
- rg: &run.Group{},
- logger: hiedalog.NewHiedaLogger(),
- subSvc: ordmap.NewBuiltin[string, *core.SubServiceWrapper](),
- appLogModuleName: appLogModuleName,
- moduleLoggers: trie.New[core.IModuleLogger](),
- globalDebugSwitch: globalDebugMode,
- prepared: false,
- mainLogLevelLimit: 0,
- }
- mlog := core.NewModuleLogger(appLogModuleName, f)
- f.moduleLoggers.Add(appLogModuleName, mlog)
- f.IModuleLogger = mlog
- f.IModuleLogLevelLimiter = mlog
- return f
- }
- // InitConsoleLogBackend add a hiedalog console backend to logger system
- // if lv == "", for globalDebugMode is on, will use hiedalog.DLN_DEBUG;
- // for globalDebugMode is off, will use hiedalog.DLN_INFO.
- func (f *AppFramework) InitConsoleLogBackend(writer io.Writer, lv string) {
- klv := lv
- if klv == "" {
- if f.globalDebugSwitch {
- klv = hiedalog.DLN_DEBUG
- } else {
- klv = hiedalog.DLN_INFO
- }
- }
- f.consoleLogBackend = hiedabke_console.NewConsoleBackend(writer)
- f.logger.AddBackend(f.consoleLogBackend, f.logger.LevelFilter.NameToID(klv))
- }
- // ShutdownConsoleLogBackend shutdown the console backend which created by InitConsoleLogBackend
- func (f *AppFramework) ShutdownConsoleLogBackend() {
- if f.consoleLogBackend != nil {
- f.consoleLogBackend.Shutdown()
- }
- }
- func (f *AppFramework) MustPrepare(processName string, fn func() error) {
- err := fn()
- if err != nil {
- f.PanicF("failed prepare for '%s': %v", processName, err)
- }
- }
- // AddSubSvc add a sub service
- func (f *AppFramework) AddSubSvc(name string, svc core.ISubService) {
- _, ok := f.subSvc.Get(name)
- if ok {
- panic("SubService name exists.")
- }
- sw := core.NewSubServiceWrapper(f, name, svc)
- f.subSvc = f.subSvc.Insert(name, sw)
- f.rg.Add(sw.Run, sw.Stop)
- }
- // GetRawLogger get the HiedaLogger inside this
- func (f *AppFramework) GetRawLogger() *hiedalog.HiedaLogger {
- return f.logger
- }
- func (f *AppFramework) GetModuleLogger(module string) core.IModuleLogger {
- f.moduleLoggersLock.RLock()
- v, ok := f.moduleLoggers.Find(module)
- if !ok {
- f.moduleLoggersLock.RUnlock()
- f.moduleLoggersLock.Lock()
- v = core.NewModuleLogger(module, f)
- f.moduleLoggers.Add(module, v)
- f.moduleLoggersLock.Unlock()
- } else {
- f.moduleLoggersLock.RUnlock()
- }
- return v
- }
- func (f *AppFramework) DiscardSubLoggerByPrefix(prefix string) {
- f.moduleLoggersLock.Lock()
- defer f.moduleLoggersLock.Unlock()
- f.moduleLoggers.Iter(prefix, func(key string, value core.IModuleLogger) {
- f.moduleLoggers.Del(key)
- })
- }
- // Prepare call the `Prepare()` of each SubService by order of addition
- func (f *AppFramework) Prepare() error {
- var err error
- for i := f.subSvc.Iterate(); !i.Done(); i.Next() {
- f.DebugF("preparing for sub service '%s'...", i.GetKey())
- err = i.GetValue().Prepare()
- if err != nil {
- f.ErrorF("failed prepare sub service '%s': %v", i.GetKey(), err)
- return err
- }
- }
- f.prepared = true
- return nil
- }
- // Run start the app
- func (f *AppFramework) Run() error {
- if !f.prepared {
- return fmt.Errorf("failed run app: `Prepare()` not called")
- }
- return f.RunWithContext(context.Background())
- }
- // RunWithContext start the app with custom context
- func (f *AppFramework) RunWithContext(ctx context.Context) error {
- ctx, cncl := context.WithCancel(ctx)
- f.gcncl = cncl
- f.gctx = ctx
- f.rg.Add(f.bgRun, f.bgStop)
- return f.rg.Run()
- }
- // Stop stop the app
- func (f *AppFramework) Stop() {
- if f.gcncl != nil {
- f.gcncl()
- }
- }
- func (f *AppFramework) bgRun() error {
- select {
- case <-f.gctx.Done():
- return nil
- }
- }
- func (f *AppFramework) bgStop(xerr error) {
- f.Stop()
- }
- func (f *AppFramework) GetContext() context.Context {
- return f.gctx
- }
- func (f *AppFramework) IsGlobalDebugMode() bool {
- return f.globalDebugSwitch
- }
- func (f *AppFramework) SetGlobalDebugMode(en bool) {
- f.globalDebugSwitch = en
- }
|