// package log_buf -- потокобезопасный буфер лога. package log_buf import ( "fmt" "log" "sync" "gitp78su.ipnodns.ru/svi/kern/v4/lev0/helpers" mKt "gitp78su.ipnodns.ru/svi/kern/v4/lev0/ktypes" "gitp78su.ipnodns.ru/svi/kern/v4/lev1/log_msg" "gitp78su.ipnodns.ru/svi/kern/v4/lev1/safe_bool" ) // LogBuf -- потокобезопасный буфер лога. type LogBuf struct { sync.RWMutex isTerm mKt.ISafeBool // Признак вывода в стандартный поток prefix string // Префикс для сообщений lst []mKt.ILogMsg lstErr []mKt.ILogMsg } // OptionLogBuf -- опция для конфигурирования ILogBuf. type OptionLogBuf func(logBuf *LogBuf) // OptIsTerm -- устанавливает признак вывода в терминал. func OptIsTerm(isTerm bool) OptionLogBuf { return func(sf *LogBuf) { if isTerm { sf.IsTerm().Set() } } } // OptPrefix -- устанавливает префикс в сообщениях. func OptPrefix(prefix string) OptionLogBuf { return func(sf *LogBuf) { sf.prefix = prefix + "." } } // NewLogBuf -- возвращает новый потокобезопасный буфер лога. func NewLogBuf(opts ...OptionLogBuf) mKt.ILogBuf { sf := &LogBuf{ isTerm: safe_bool.NewSafeBool(), lst: []mKt.ILogMsg{}, lstErr: []mKt.ILogMsg{}, } for _, opt := range opts { opt(sf) } return sf } // IsTerm -- возвращает признак логирования. func (sf *LogBuf) IsTerm() mKt.ISafeBool { return sf.isTerm } // GetErr -- возвращает сообщение ошибки по номеру. func (sf *LogBuf) GetErr(num int) mKt.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) mKt.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 mKt.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()) }