// package log_buf -- потокобезопасный буфер лога. package log_buf import ( "fmt" "log" "sync" "gitp78su.ipnodns.ru/svi/kern/v4/lev0/helpers" mKs "gitp78su.ipnodns.ru/svi/kern/v4/lev0/kspec" "gitp78su.ipnodns.ru/svi/kern/v4/lev1/log_msg" ) var ( hassert = helpers.Hassert ) // LogBufParam -- параметры логирующего буфера type LogBufParam struct { Prefix_ string // Префикс для сообщений IsTerm_ mKs.ISafeBool // Признак вывода в терминал } // SelfCheck -- проверяет корректность параметров. func (sf *LogBufParam) SelfCheck() { hassert(sf.IsTerm_ != nil, "LogBufParam.SelfCheck(): IsTerm_==nil") } // LogBuf -- потокобезопасный буфер лога. type LogBuf struct { sync.RWMutex *LogBufParam lst []mKs.ILogMsg lstErr []mKs.ILogMsg } // NewLogBuf -- возвращает новый потокобезопасный буфер лога. func NewLogBuf(param *LogBufParam) mKs.ILogBuf { hassert(param != nil, "NewLogBuf(): param=nil") param.SelfCheck() sf := &LogBuf{ LogBufParam: param, lst: []mKs.ILogMsg{}, lstErr: []mKs.ILogMsg{}, } sf.Prefix_ += "." return sf } // IsTerm -- возвращает признак логирования. func (sf *LogBuf) IsTerm() mKs.ISafeBool { return sf.IsTerm_ } // GetErr -- возвращает сообщение ошибки по номеру. func (sf *LogBuf) GetErr(num int) mKs.ILogMsg { sf.RLock() defer sf.RUnlock() if len(sf.lstErr) == 0 { return log_msg.NewLogMsg(log_msg.DEBUG, sf.Prefix_+"not error msg") } if num >= 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 int) mKs.ILogMsg { sf.RLock() defer sf.RUnlock() if len(sf.lst) == 0 { return log_msg.NewLogMsg(log_msg.DEBUG, sf.Prefix_+"*no msg*") } if num >= len(sf.lst) { return log_msg.NewLogMsg(log_msg.DEBUG, sf.Prefix_+"*no msg*") } if num <= 0 { return log_msg.NewLogMsg(log_msg.DEBUG, sf.Prefix_+"*no msg*") } return sf.lst[num] } type tMsg struct { text string args []any } // Debug -- сообщение отладки. func (sf *LogBuf) Debug(fMsg string, args ...any) { sf.Lock() defer sf.Unlock() msg := tMsg{ text: fMsg, args: args, } strMsg := fmt.Sprintf(msg.text, msg.args...) _msg := log_msg.NewLogMsg(log_msg.DEBUG, sf.Prefix_+strMsg) sf.lst = append(sf.lst, _msg) sf.checkLen() sf.printTerm(_msg) } // Info -- информационные сообщения. func (sf *LogBuf) Info(fMsg string, args ...any) { sf.Lock() defer sf.Unlock() msg := tMsg{ text: fMsg, args: args, } strMsg := fmt.Sprintf(msg.text, msg.args...) _msg := log_msg.NewLogMsg(log_msg.INFO, sf.Prefix_+strMsg) sf.lst = append(sf.lst, _msg) sf.checkLen() sf.printTerm(_msg) } // Warn -- предупреждающие сообщения. func (sf *LogBuf) Warn(fMsg string, args ...any) { sf.Lock() defer sf.Unlock() msg := tMsg{ text: fMsg, args: args, } strMsg := fmt.Sprintf(msg.text, msg.args...) _msg := log_msg.NewLogMsg(log_msg.WARN, sf.Prefix_+strMsg) sf.lst = append(sf.lst, _msg) sf.checkLen() sf.printTerm(_msg) } // Err -- сообщения об ошибках. func (sf *LogBuf) Err(fMsg string, args ...any) { sf.Lock() defer sf.Unlock() msg := tMsg{ text: fMsg, args: args, } strMsg := fmt.Sprintf(msg.text, msg.args...) _msg := log_msg.NewLogMsg(log_msg.ERROR, sf.Prefix_+strMsg) sf.lst = append(sf.lst, _msg) sf.lstErr = append(sf.lstErr, _msg) sf.checkLen() sf.checkLenErr() sf.printTerm(_msg) } // Size -- возвращает размер буфера. func (sf *LogBuf) Size() int { sf.RLock() defer sf.RUnlock() return 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 mKs.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()) }