// package log_buf -- потокобезопасный буфер лога package log_buf import ( "fmt" "sync" "gitp78su.ipnodns.ru/svi/kern/v3/kc/helpers" "gitp78su.ipnodns.ru/svi/kern/v3/kc/log_buf/log_msg" "gitp78su.ipnodns.ru/svi/kern/v3/kc/safe_bool" . "gitp78su.ipnodns.ru/svi/kern/v3/krn/ktypes" ) // logBuf -- потокобезопасный буфер лога type logBuf struct { sync.RWMutex isTerm ISafeBool // Признак вывода в стандартный поток prefix string // Префикс для сообщений lst []ILogMsg lstErr []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) ILogBuf { sf := &logBuf{ isTerm: safe_bool.NewSafeBool(), lst: []ILogMsg{}, lstErr: []ILogMsg{}, } for _, opt := range opts { opt(sf) } return sf } // IsTerm -- возвращает признак логирования func (sf *logBuf) IsTerm() ISafeBool { return sf.isTerm } // GetErr -- возвращает сообщение ошибки по номеру func (sf *logBuf) GetErr(num int) 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) 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 ILogMsg) { if !sf.isTerm.Get() { return } level := msg.Level() if helpers.IsStageProd { switch level { case "ERRO", "WARN": fmt.Printf("%v %v\n", level, msg.String()) default: return } } fmt.Printf("%v\n", msg.String()) }