framework.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. package svcfw
  2. import (
  3. "context"
  4. "fmt"
  5. "git.swzry.com/zry/GoHiedaLogger/hiedabke_console"
  6. "git.swzry.com/zry/GoHiedaLogger/hiedalog"
  7. "git.swzry.com/zry/zry-go-program-framework/core"
  8. ordmap "github.com/edofic/go-ordmap/v2"
  9. "github.com/oklog/run"
  10. "github.com/s0rg/trie"
  11. "io"
  12. "sync"
  13. )
  14. var _ core.IAppFramework = (*AppFramework)(nil)
  15. var _ core.IModuleLogger = (*AppFramework)(nil)
  16. var _ core.IModuleLogLevelLimiter = (*AppFramework)(nil)
  17. type AppFramework struct {
  18. rg *run.Group
  19. logger *hiedalog.HiedaLogger
  20. gctx context.Context
  21. gcncl context.CancelFunc
  22. subSvc ordmap.NodeBuiltin[string, *core.SubServiceWrapper]
  23. moduleLoggers *trie.Trie[core.IModuleLogger]
  24. moduleLoggersLock sync.RWMutex
  25. appLogModuleName string
  26. globalDebugSwitch bool
  27. prepared bool
  28. consoleLogBackend *hiedabke_console.ConsoleBackend
  29. mainLogLevelLimit uint8
  30. core.IModuleLogger
  31. core.IModuleLogLevelLimiter
  32. }
  33. func NewAppFramework(globalDebugMode bool, appLogModuleName string) *AppFramework {
  34. f := &AppFramework{
  35. rg: &run.Group{},
  36. logger: hiedalog.NewHiedaLogger(),
  37. subSvc: ordmap.NewBuiltin[string, *core.SubServiceWrapper](),
  38. appLogModuleName: appLogModuleName,
  39. moduleLoggers: trie.New[core.IModuleLogger](),
  40. globalDebugSwitch: globalDebugMode,
  41. prepared: false,
  42. mainLogLevelLimit: 0,
  43. }
  44. mlog := core.NewModuleLogger(appLogModuleName, f)
  45. f.moduleLoggers.Add(appLogModuleName, mlog)
  46. f.IModuleLogger = mlog
  47. f.IModuleLogLevelLimiter = mlog
  48. return f
  49. }
  50. // InitConsoleLogBackend add a hiedalog console backend to logger system
  51. // if lv == "", for globalDebugMode is on, will use hiedalog.DLN_DEBUG;
  52. // for globalDebugMode is off, will use hiedalog.DLN_INFO.
  53. func (f *AppFramework) InitConsoleLogBackend(writer io.Writer, lv string) {
  54. klv := lv
  55. if klv == "" {
  56. if f.globalDebugSwitch {
  57. klv = hiedalog.DLN_DEBUG
  58. } else {
  59. klv = hiedalog.DLN_INFO
  60. }
  61. }
  62. f.consoleLogBackend = hiedabke_console.NewConsoleBackend(writer)
  63. f.logger.AddBackend(f.consoleLogBackend, f.logger.LevelFilter.NameToID(klv))
  64. }
  65. // ShutdownConsoleLogBackend shutdown the console backend which created by InitConsoleLogBackend
  66. func (f *AppFramework) ShutdownConsoleLogBackend() {
  67. if f.consoleLogBackend != nil {
  68. f.consoleLogBackend.Shutdown()
  69. }
  70. }
  71. func (f *AppFramework) MustPrepare(processName string, fn func() error) {
  72. err := fn()
  73. if err != nil {
  74. f.PanicF("failed prepare for '%s': %v", processName, err)
  75. }
  76. }
  77. // AddSubSvc add a sub service
  78. func (f *AppFramework) AddSubSvc(name string, svc core.ISubService) {
  79. _, ok := f.subSvc.Get(name)
  80. if ok {
  81. panic("SubService name exists.")
  82. }
  83. sw := core.NewSubServiceWrapper(f, name, svc)
  84. f.subSvc = f.subSvc.Insert(name, sw)
  85. f.rg.Add(sw.Run, sw.Stop)
  86. }
  87. // GetRawLogger get the HiedaLogger inside this
  88. func (f *AppFramework) GetRawLogger() *hiedalog.HiedaLogger {
  89. return f.logger
  90. }
  91. func (f *AppFramework) GetModuleLogger(module string) core.IModuleLogger {
  92. f.moduleLoggersLock.RLock()
  93. v, ok := f.moduleLoggers.Find(module)
  94. if !ok {
  95. f.moduleLoggersLock.RUnlock()
  96. f.moduleLoggersLock.Lock()
  97. v = core.NewModuleLogger(module, f)
  98. f.moduleLoggers.Add(module, v)
  99. f.moduleLoggersLock.Unlock()
  100. } else {
  101. f.moduleLoggersLock.RUnlock()
  102. }
  103. return v
  104. }
  105. func (f *AppFramework) DiscardSubLoggerByPrefix(prefix string) {
  106. f.moduleLoggersLock.Lock()
  107. defer f.moduleLoggersLock.Unlock()
  108. f.moduleLoggers.Iter(prefix, func(key string, value core.IModuleLogger) {
  109. f.moduleLoggers.Del(key)
  110. })
  111. }
  112. // Prepare call the `Prepare()` of each SubService by order of addition
  113. func (f *AppFramework) Prepare() error {
  114. var err error
  115. for i := f.subSvc.Iterate(); !i.Done(); i.Next() {
  116. f.DebugF("preparing for sub service '%s'...", i.GetKey())
  117. err = i.GetValue().Prepare()
  118. if err != nil {
  119. f.ErrorF("failed prepare sub service '%s': %v", i.GetKey(), err)
  120. return err
  121. }
  122. }
  123. f.prepared = true
  124. return nil
  125. }
  126. // Run start the app
  127. func (f *AppFramework) Run() error {
  128. if !f.prepared {
  129. return fmt.Errorf("failed run app: `Prepare()` not called")
  130. }
  131. return f.RunWithContext(context.Background())
  132. }
  133. // RunWithContext start the app with custom context
  134. func (f *AppFramework) RunWithContext(ctx context.Context) error {
  135. ctx, cncl := context.WithCancel(ctx)
  136. f.gcncl = cncl
  137. f.gctx = ctx
  138. f.rg.Add(f.bgRun, f.bgStop)
  139. return f.rg.Run()
  140. }
  141. // Stop stop the app
  142. func (f *AppFramework) Stop() {
  143. if f.gcncl != nil {
  144. f.gcncl()
  145. }
  146. }
  147. func (f *AppFramework) bgRun() error {
  148. select {
  149. case <-f.gctx.Done():
  150. return nil
  151. }
  152. }
  153. func (f *AppFramework) bgStop(xerr error) {
  154. f.Stop()
  155. }
  156. func (f *AppFramework) GetContext() context.Context {
  157. return f.gctx
  158. }
  159. func (f *AppFramework) IsGlobalDebugMode() bool {
  160. return f.globalDebugSwitch
  161. }
  162. func (f *AppFramework) SetGlobalDebugMode(en bool) {
  163. f.globalDebugSwitch = en
  164. }