// package log_buf -- потокобезопасный буфер лога. package log_buf import ( "fmt" "log" "sync" "gitp78su.ipnodns.ru/svi/kern/v4/lev0/core_spec" "gitp78su.ipnodns.ru/svi/kern/v4/lev0/defs" "gitp78su.ipnodns.ru/svi/kern/v4/lev0/helpers" "gitp78su.ipnodns.ru/svi/kern/v4/lev1/log_buf/log_msg" ) // ILogBuf -- буферизованный лог для диагностики. // // Буфер для Error -- отдельный. type ILogBuf interface { // Debug -- сообщение отладки Debug(fMsg defs.ITxtFix, args ...any) // LogBus -- возвращает объект публикации в шину // LogBus()ILogBus // Info -- информационные сообщения Info(fMsg defs.ITxtFix, args ...any) // Warn -- предупреждающие сообщения Warn(fMsg defs.ITxtFix, args ...any) // Err -- сообщения об ошибках Err(fMsg defs.IErr, args ...any) // Get -- возвращает сообщение по номеру (0..99) Get(num defs.Int) log_msg.ILogMsg // GetErr -- возвращает сообщение ошибки по номеру (0..99) GetErr(num defs.Int) log_msg.ILogMsg // Size -- возвращает размер лога Size() defs.Int // IsTerm -- возвращает признак логирования в терминал IsTerm() core_spec.ISafeBool } var ( hassert = helpers.Hassert ) // LogBufParam -- параметры логирующего буфера. type LogBufParam struct { Prefix_ defs.ITxtFix // Префикс для сообщений IsTerm_ core_spec.ISafeBool // Признак вывода в терминал } // SelfCheck -- проверяет корректность параметров. func (sf *LogBufParam) SelfCheck() { hassert(sf.IsTerm_ != nil, "LogBufParam.SelfCheck(): IsTerm_==nil") } // LogBuf -- потокобезопасный буфер лога. type LogBuf struct { sync.RWMutex *LogBufParam lst []log_msg.ILogMsg lstErr []log_msg.ILogMsg } // NewLogBuf -- возвращает новый потокобезопасный буфер лога. func NewLogBuf(param *LogBufParam) ILogBuf { hassert(param != nil, "NewLogBuf(): param=nil") param.SelfCheck() sf := &LogBuf{ LogBufParam: param, lst: []log_msg.ILogMsg{}, lstErr: []log_msg.ILogMsg{}, } pref := sf.Prefix_.Get() + defs.ATxt(".") sf.Prefix_ = defs.Txt(pref) return sf } // IsTerm -- возвращает признак логирования. func (sf *LogBuf) IsTerm() core_spec.ISafeBool { return sf.IsTerm_ } // GetErr -- возвращает сообщение ошибки по номеру. func (sf *LogBuf) GetErr(num defs.Int) log_msg.ILogMsg { sf.RLock() defer sf.RUnlock() if len(sf.lstErr) == 0 { msg := sf.Prefix_.Get() + "not error msg" return log_msg.NewLogMsg(log_msg.DEBUG, defs.Txt(msg)) } if num.Int() >= len(sf.lstErr) { return sf.lstErr[len(sf.lstErr)-1] } if num <= 0 { return sf.lstErr[0] } return sf.lstErr[num] } // Get -- возвращает сообщение по номеру. func (sf *LogBuf) Get(num defs.Int) log_msg.ILogMsg { sf.RLock() defer sf.RUnlock() msg := sf.Prefix_.Get() + "*no msg*" if len(sf.lst) == 0 { return log_msg.NewLogMsg(log_msg.DEBUG, defs.Txt(msg)) } if num.Int() >= len(sf.lst) { return log_msg.NewLogMsg(log_msg.DEBUG, defs.Txt(msg)) } if num <= 0 { return log_msg.NewLogMsg(log_msg.DEBUG, defs.Txt(msg)) } return sf.lst[num] } // Debug -- сообщение отладки. func (sf *LogBuf) Debug(fTxt defs.ITxtFix, args ...any) { sf.Lock() defer sf.Unlock() strMsg := fmt.Sprintf(fTxt.String(), args...) msg := sf.Prefix_.Get() + defs.ATxt(strMsg) _msg := log_msg.NewLogMsg(log_msg.DEBUG, defs.Txt(msg)) sf.lst = append(sf.lst, _msg) sf.checkLen() sf.printTerm(_msg) } // Info -- информационные сообщения. func (sf *LogBuf) Info(fMsg defs.ITxtFix, args ...any) { sf.Lock() defer sf.Unlock() strMsg := fmt.Sprintf(fMsg.String(), args...) msg := sf.Prefix_.Get() + defs.ATxt(strMsg) _msg := log_msg.NewLogMsg(log_msg.INFO, defs.Txt(msg)) sf.lst = append(sf.lst, _msg) sf.checkLen() sf.printTerm(_msg) } // Warn -- предупреждающие сообщения. func (sf *LogBuf) Warn(fMsg defs.ITxtFix, args ...any) { sf.Lock() defer sf.Unlock() strMsg := fmt.Sprintf(fMsg.String(), args...) msg := sf.Prefix_.Get() + defs.ATxt(strMsg) _msg := log_msg.NewLogMsg(log_msg.WARN, defs.Txt(msg)) sf.lst = append(sf.lst, _msg) sf.checkLen() sf.printTerm(_msg) } // Err -- сообщения об ошибках. func (sf *LogBuf) Err(err defs.IErr, args ...any) { sf.Lock() defer sf.Unlock() strMsg := fmt.Sprintf(err.String(), args...) msg := sf.Prefix_.Get() + defs.ATxt(strMsg) _msg := log_msg.NewLogMsg(log_msg.ERROR, defs.Txt(msg)) sf.lst = append(sf.lst, _msg) sf.lstErr = append(sf.lstErr, _msg) sf.checkLen() sf.checkLenErr() sf.printTerm(_msg) } // Size -- возвращает размер буфера. func (sf *LogBuf) Size() defs.Int { sf.RLock() defer sf.RUnlock() return defs.Int(len(sf.lst)) } // Проверяет длину общую лога. func (sf *LogBuf) checkLen() { for len(sf.lst) > 100 { sf.lst = sf.lst[1:] } } // Проверяет длину лога ошибок. func (sf *LogBuf) checkLenErr() { for len(sf.lstErr) > 100 { sf.lstErr = sf.lstErr[1:] } } // Печатает сообщение в терминал, если разрешено. func (sf *LogBuf) printTerm(msg log_msg.ILogMsg) { if !sf.IsTerm_.Get() { return } level := msg.Level() if helpers.IsStageProd { switch level.Get() { case "ERRO", "WARN": log.Printf("%v %v\n", level, msg.String()) default: return } } log.Printf("%v\n", msg.String()) }