mirror of
				https://github.com/AlexxIT/go2rtc.git
				synced 2025-10-31 11:46:26 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			176 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			176 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package app
 | |
| 
 | |
| import (
 | |
| 	"io"
 | |
| 	"os"
 | |
| 	"strings"
 | |
| 
 | |
| 	"github.com/mattn/go-isatty"
 | |
| 	"github.com/rs/zerolog"
 | |
| )
 | |
| 
 | |
| var MemoryLog = newBuffer(16)
 | |
| 
 | |
| func GetLogger(module string) zerolog.Logger {
 | |
| 	if s, ok := modules[module]; ok {
 | |
| 		lvl, err := zerolog.ParseLevel(s)
 | |
| 		if err == nil {
 | |
| 			return Logger.Level(lvl)
 | |
| 		}
 | |
| 		Logger.Warn().Err(err).Caller().Send()
 | |
| 	}
 | |
| 
 | |
| 	return Logger
 | |
| }
 | |
| 
 | |
| // initLogger support:
 | |
| // - output: empty (only to memory), stderr, stdout
 | |
| // - format: empty (autodetect color support), color, json, text
 | |
| // - time:   empty (disable timestamp), UNIXMS, UNIXMICRO, UNIXNANO
 | |
| // - level:  disabled, trace, debug, info, warn, error...
 | |
| func initLogger() {
 | |
| 	var cfg struct {
 | |
| 		Mod map[string]string `yaml:"log"`
 | |
| 	}
 | |
| 
 | |
| 	cfg.Mod = modules // defaults
 | |
| 
 | |
| 	LoadConfig(&cfg)
 | |
| 
 | |
| 	var writer io.Writer
 | |
| 
 | |
| 	switch output, path, _ := strings.Cut(modules["output"], ":"); output {
 | |
| 	case "stderr":
 | |
| 		writer = os.Stderr
 | |
| 	case "stdout":
 | |
| 		writer = os.Stdout
 | |
| 	case "file":
 | |
| 		if path == "" {
 | |
| 			path = "go2rtc.log"
 | |
| 		}
 | |
| 		// if fail - only MemoryLog will be available
 | |
| 		writer, _ = os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
 | |
| 	}
 | |
| 
 | |
| 	timeFormat := modules["time"]
 | |
| 
 | |
| 	if writer != nil {
 | |
| 		if format := modules["format"]; format != "json" {
 | |
| 			console := &zerolog.ConsoleWriter{Out: writer}
 | |
| 
 | |
| 			switch format {
 | |
| 			case "text":
 | |
| 				console.NoColor = true
 | |
| 			case "color":
 | |
| 				console.NoColor = false // useless, but anyway
 | |
| 			default:
 | |
| 				// autodetection if output support color
 | |
| 				// go-isatty - dependency for go-colorable - dependency for ConsoleWriter
 | |
| 				console.NoColor = !isatty.IsTerminal(writer.(*os.File).Fd())
 | |
| 			}
 | |
| 
 | |
| 			if timeFormat != "" {
 | |
| 				console.TimeFormat = "15:04:05.000"
 | |
| 			} else {
 | |
| 				console.PartsOrder = []string{
 | |
| 					zerolog.LevelFieldName,
 | |
| 					zerolog.CallerFieldName,
 | |
| 					zerolog.MessageFieldName,
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			writer = console
 | |
| 		}
 | |
| 
 | |
| 		writer = zerolog.MultiLevelWriter(writer, MemoryLog)
 | |
| 	} else {
 | |
| 		writer = MemoryLog
 | |
| 	}
 | |
| 
 | |
| 	lvl, _ := zerolog.ParseLevel(modules["level"])
 | |
| 	Logger = zerolog.New(writer).Level(lvl)
 | |
| 
 | |
| 	if timeFormat != "" {
 | |
| 		zerolog.TimeFieldFormat = timeFormat
 | |
| 		Logger = Logger.With().Timestamp().Logger()
 | |
| 	}
 | |
| }
 | |
| 
 | |
| var Logger zerolog.Logger
 | |
| 
 | |
| // modules log levels
 | |
| var modules = map[string]string{
 | |
| 	"format": "", // useless, but anyway
 | |
| 	"level":  "info",
 | |
| 	"output": "stdout", // TODO: change to stderr someday
 | |
| 	"time":   zerolog.TimeFormatUnixMs,
 | |
| }
 | |
| 
 | |
| const chunkSize = 1 << 16
 | |
| 
 | |
| type circularBuffer struct {
 | |
| 	chunks [][]byte
 | |
| 	r, w   int
 | |
| }
 | |
| 
 | |
| func newBuffer(chunks int) *circularBuffer {
 | |
| 	b := &circularBuffer{chunks: make([][]byte, 0, chunks)}
 | |
| 	// create first chunk
 | |
| 	b.chunks = append(b.chunks, make([]byte, 0, chunkSize))
 | |
| 	return b
 | |
| }
 | |
| 
 | |
| func (b *circularBuffer) Write(p []byte) (n int, err error) {
 | |
| 	n = len(p)
 | |
| 
 | |
| 	// check if chunk has size
 | |
| 	if len(b.chunks[b.w])+n > chunkSize {
 | |
| 		// increase write chunk index
 | |
| 		if b.w++; b.w == cap(b.chunks) {
 | |
| 			b.w = 0
 | |
| 		}
 | |
| 		// check overflow
 | |
| 		if b.r == b.w {
 | |
| 			// increase read chunk index
 | |
| 			if b.r++; b.r == cap(b.chunks) {
 | |
| 				b.r = 0
 | |
| 			}
 | |
| 		}
 | |
| 		// check if current chunk exists
 | |
| 		if b.w == len(b.chunks) {
 | |
| 			// allocate new chunk
 | |
| 			b.chunks = append(b.chunks, make([]byte, 0, chunkSize))
 | |
| 		} else {
 | |
| 			// reset len of current chunk
 | |
| 			b.chunks[b.w] = b.chunks[b.w][:0]
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	b.chunks[b.w] = append(b.chunks[b.w], p...)
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (b *circularBuffer) WriteTo(w io.Writer) (n int64, err error) {
 | |
| 	for i := b.r; ; {
 | |
| 		var nn int
 | |
| 		if nn, err = w.Write(b.chunks[i]); err != nil {
 | |
| 			return
 | |
| 		}
 | |
| 		n += int64(nn)
 | |
| 
 | |
| 		if i == b.w {
 | |
| 			break
 | |
| 		}
 | |
| 		if i++; i == cap(b.chunks) {
 | |
| 			i = 0
 | |
| 		}
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (b *circularBuffer) Reset() {
 | |
| 	b.chunks[0] = b.chunks[0][:0]
 | |
| 	b.r = 0
 | |
| 	b.w = 0
 | |
| }
 | 
