mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-03 08:02:36 +09:00 
			
		
		
		
	* Deprecate "gopid" in log, it is not useful and requires very hacky approach * Remove "git.Command.SetDescription" because it is not useful and only makes the logs too flexible
		
			
				
	
	
		
			244 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			244 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Copyright 2023 The Gitea Authors. All rights reserved.
 | 
						|
// SPDX-License-Identifier: MIT
 | 
						|
 | 
						|
package log
 | 
						|
 | 
						|
import (
 | 
						|
	"bytes"
 | 
						|
	"fmt"
 | 
						|
	"strings"
 | 
						|
	"time"
 | 
						|
)
 | 
						|
 | 
						|
type Event struct {
 | 
						|
	Time time.Time
 | 
						|
 | 
						|
	Caller   string
 | 
						|
	Filename string
 | 
						|
	Line     int
 | 
						|
 | 
						|
	Level Level
 | 
						|
 | 
						|
	MsgSimpleText string
 | 
						|
 | 
						|
	msgFormat string // the format and args is only valid in the caller's goroutine
 | 
						|
	msgArgs   []any  // they are discarded before the event is passed to the writer's channel
 | 
						|
 | 
						|
	Stacktrace string
 | 
						|
}
 | 
						|
 | 
						|
type EventFormatted struct {
 | 
						|
	Origin *Event
 | 
						|
	Msg    any // the message formatted by the writer's formatter, the writer knows its type
 | 
						|
}
 | 
						|
 | 
						|
type EventFormatter func(mode *WriterMode, event *Event, msgFormat string, msgArgs ...any) []byte
 | 
						|
 | 
						|
type logStringFormatter struct {
 | 
						|
	v LogStringer
 | 
						|
}
 | 
						|
 | 
						|
var _ fmt.Formatter = logStringFormatter{}
 | 
						|
 | 
						|
func (l logStringFormatter) Format(f fmt.State, verb rune) {
 | 
						|
	if f.Flag('#') && verb == 'v' {
 | 
						|
		_, _ = fmt.Fprintf(f, "%#v", l.v)
 | 
						|
		return
 | 
						|
	}
 | 
						|
	_, _ = f.Write([]byte(l.v.LogString()))
 | 
						|
}
 | 
						|
 | 
						|
// Copy of cheap integer to fixed-width decimal to ascii from logger.
 | 
						|
// TODO: legacy bugs: doesn't support negative number, overflow if wid it too large.
 | 
						|
func itoa(buf []byte, i, wid int) []byte {
 | 
						|
	var s [20]byte
 | 
						|
	bp := len(s) - 1
 | 
						|
	for i >= 10 || wid > 1 {
 | 
						|
		wid--
 | 
						|
		q := i / 10
 | 
						|
		s[bp] = byte('0' + i - q*10)
 | 
						|
		bp--
 | 
						|
		i = q
 | 
						|
	}
 | 
						|
	// i < 10
 | 
						|
	s[bp] = byte('0' + i)
 | 
						|
	return append(buf, s[bp:]...)
 | 
						|
}
 | 
						|
 | 
						|
func colorSprintf(colorize bool, format string, args ...any) string {
 | 
						|
	hasColorValue := false
 | 
						|
	for _, v := range args {
 | 
						|
		if _, hasColorValue = v.(*ColoredValue); hasColorValue {
 | 
						|
			break
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if colorize || !hasColorValue {
 | 
						|
		return fmt.Sprintf(format, args...)
 | 
						|
	}
 | 
						|
 | 
						|
	noColors := make([]any, len(args))
 | 
						|
	copy(noColors, args)
 | 
						|
	for i, v := range args {
 | 
						|
		if cv, ok := v.(*ColoredValue); ok {
 | 
						|
			noColors[i] = cv.v
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return fmt.Sprintf(format, noColors...)
 | 
						|
}
 | 
						|
 | 
						|
// EventFormatTextMessage makes the log message for a writer with its mode. This function is a copy of the original package
 | 
						|
func EventFormatTextMessage(mode *WriterMode, event *Event, msgFormat string, msgArgs ...any) []byte {
 | 
						|
	buf := make([]byte, 0, 1024)
 | 
						|
	buf = append(buf, mode.Prefix...)
 | 
						|
	t := event.Time
 | 
						|
	flags := mode.Flags.Bits()
 | 
						|
	if flags&(Ldate|Ltime|Lmicroseconds) != 0 {
 | 
						|
		if mode.Colorize {
 | 
						|
			buf = append(buf, fgCyanBytes...)
 | 
						|
		}
 | 
						|
		if flags&LUTC != 0 {
 | 
						|
			t = t.UTC()
 | 
						|
		}
 | 
						|
		if flags&Ldate != 0 {
 | 
						|
			year, month, day := t.Date()
 | 
						|
			buf = itoa(buf, year, 4)
 | 
						|
			buf = append(buf, '/')
 | 
						|
			buf = itoa(buf, int(month), 2)
 | 
						|
			buf = append(buf, '/')
 | 
						|
			buf = itoa(buf, day, 2)
 | 
						|
			buf = append(buf, ' ')
 | 
						|
		}
 | 
						|
		if flags&(Ltime|Lmicroseconds) != 0 {
 | 
						|
			hour, minNum, sec := t.Clock()
 | 
						|
			buf = itoa(buf, hour, 2)
 | 
						|
			buf = append(buf, ':')
 | 
						|
			buf = itoa(buf, minNum, 2)
 | 
						|
			buf = append(buf, ':')
 | 
						|
			buf = itoa(buf, sec, 2)
 | 
						|
			if flags&Lmicroseconds != 0 {
 | 
						|
				buf = append(buf, '.')
 | 
						|
				buf = itoa(buf, t.Nanosecond()/1e3, 6)
 | 
						|
			}
 | 
						|
			buf = append(buf, ' ')
 | 
						|
		}
 | 
						|
		if mode.Colorize {
 | 
						|
			buf = append(buf, resetBytes...)
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if flags&(Lshortfile|Llongfile) != 0 {
 | 
						|
		if mode.Colorize {
 | 
						|
			buf = append(buf, fgGreenBytes...)
 | 
						|
		}
 | 
						|
		file := event.Filename
 | 
						|
		if flags&Lmedfile == Lmedfile {
 | 
						|
			startIndex := len(file) - 20
 | 
						|
			if startIndex > 0 {
 | 
						|
				file = "..." + file[startIndex:]
 | 
						|
			}
 | 
						|
		} else if flags&Lshortfile != 0 {
 | 
						|
			startIndex := strings.LastIndexByte(file, '/')
 | 
						|
			if startIndex > 0 && startIndex < len(file) {
 | 
						|
				file = file[startIndex+1:]
 | 
						|
			}
 | 
						|
		}
 | 
						|
		buf = append(buf, file...)
 | 
						|
		buf = append(buf, ':')
 | 
						|
		buf = itoa(buf, event.Line, -1)
 | 
						|
		if flags&(Lfuncname|Lshortfuncname) != 0 {
 | 
						|
			buf = append(buf, ':')
 | 
						|
		} else {
 | 
						|
			if mode.Colorize {
 | 
						|
				buf = append(buf, resetBytes...)
 | 
						|
			}
 | 
						|
			buf = append(buf, ' ')
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if flags&(Lfuncname|Lshortfuncname) != 0 {
 | 
						|
		if mode.Colorize {
 | 
						|
			buf = append(buf, fgGreenBytes...)
 | 
						|
		}
 | 
						|
		funcname := event.Caller
 | 
						|
		if flags&Lshortfuncname != 0 {
 | 
						|
			lastIndex := strings.LastIndexByte(funcname, '.')
 | 
						|
			if lastIndex > 0 && len(funcname) > lastIndex+1 {
 | 
						|
				funcname = funcname[lastIndex+1:]
 | 
						|
			}
 | 
						|
		}
 | 
						|
		buf = append(buf, funcname...)
 | 
						|
		if mode.Colorize {
 | 
						|
			buf = append(buf, resetBytes...)
 | 
						|
		}
 | 
						|
		buf = append(buf, ' ')
 | 
						|
	}
 | 
						|
 | 
						|
	if flags&(Llevel|Llevelinitial) != 0 {
 | 
						|
		level := strings.ToUpper(event.Level.String())
 | 
						|
		if mode.Colorize {
 | 
						|
			buf = append(buf, ColorBytes(levelToColor[event.Level]...)...)
 | 
						|
		}
 | 
						|
		buf = append(buf, '[')
 | 
						|
		if flags&Llevelinitial != 0 {
 | 
						|
			buf = append(buf, level[0])
 | 
						|
		} else {
 | 
						|
			buf = append(buf, level...)
 | 
						|
		}
 | 
						|
		buf = append(buf, ']')
 | 
						|
		if mode.Colorize {
 | 
						|
			buf = append(buf, resetBytes...)
 | 
						|
		}
 | 
						|
		buf = append(buf, ' ')
 | 
						|
	}
 | 
						|
 | 
						|
	var msg []byte
 | 
						|
 | 
						|
	// if the log needs colorizing, do it
 | 
						|
	if mode.Colorize && len(msgArgs) > 0 {
 | 
						|
		hasColorValue := false
 | 
						|
		for _, v := range msgArgs {
 | 
						|
			if _, hasColorValue = v.(*ColoredValue); hasColorValue {
 | 
						|
				break
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if hasColorValue {
 | 
						|
			msg = []byte(fmt.Sprintf(msgFormat, msgArgs...))
 | 
						|
		}
 | 
						|
	}
 | 
						|
	// try to re-use the pre-formatted simple text message
 | 
						|
	if len(msg) == 0 {
 | 
						|
		msg = []byte(event.MsgSimpleText)
 | 
						|
	}
 | 
						|
	// if still no message, do the normal Sprintf for the message
 | 
						|
	if len(msg) == 0 {
 | 
						|
		msg = []byte(colorSprintf(mode.Colorize, msgFormat, msgArgs...))
 | 
						|
	}
 | 
						|
	// remove at most one trailing new line
 | 
						|
	if len(msg) > 0 && msg[len(msg)-1] == '\n' {
 | 
						|
		msg = msg[:len(msg)-1]
 | 
						|
	}
 | 
						|
 | 
						|
	if flags&Lgopid == Lgopid {
 | 
						|
		deprecatedGoroutinePid := "no-gopid" // use a dummy value to avoid breaking the log format
 | 
						|
		buf = append(buf, '[')
 | 
						|
		if mode.Colorize {
 | 
						|
			buf = append(buf, ColorBytes(FgHiYellow)...)
 | 
						|
		}
 | 
						|
		buf = append(buf, deprecatedGoroutinePid...)
 | 
						|
		if mode.Colorize {
 | 
						|
			buf = append(buf, resetBytes...)
 | 
						|
		}
 | 
						|
		buf = append(buf, ']', ' ')
 | 
						|
	}
 | 
						|
	buf = append(buf, msg...)
 | 
						|
 | 
						|
	if event.Stacktrace != "" && mode.StacktraceLevel <= event.Level {
 | 
						|
		lines := bytes.Split([]byte(event.Stacktrace), []byte("\n"))
 | 
						|
		for _, line := range lines {
 | 
						|
			buf = append(buf, "\n\t"...)
 | 
						|
			buf = append(buf, line...)
 | 
						|
		}
 | 
						|
		buf = append(buf, '\n')
 | 
						|
	}
 | 
						|
	buf = append(buf, '\n')
 | 
						|
	return buf
 | 
						|
}
 |