mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-31 17:02:25 -05:00 
			
		
		
		
	Grand test fixup (#138)
* start fixing up tests * fix up tests + automate with drone * fiddle with linting * messing about with drone.yml * some more fiddling * hmmm * add cache * add vendor directory * verbose * ci updates * update some little things * update sig
This commit is contained in:
		
					parent
					
						
							
								329a5e8144
							
						
					
				
			
			
				commit
				
					
						98263a7de6
					
				
			
		
					 2677 changed files with 1090869 additions and 219 deletions
				
			
		
							
								
								
									
										339
									
								
								vendor/github.com/sirupsen/logrus/text_formatter.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										339
									
								
								vendor/github.com/sirupsen/logrus/text_formatter.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,339 @@ | |||
| package logrus | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"runtime" | ||||
| 	"sort" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"time" | ||||
| 	"unicode/utf8" | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| 	red    = 31 | ||||
| 	yellow = 33 | ||||
| 	blue   = 36 | ||||
| 	gray   = 37 | ||||
| ) | ||||
| 
 | ||||
| var baseTimestamp time.Time | ||||
| 
 | ||||
| func init() { | ||||
| 	baseTimestamp = time.Now() | ||||
| } | ||||
| 
 | ||||
| // TextFormatter formats logs into text | ||||
| type TextFormatter struct { | ||||
| 	// Set to true to bypass checking for a TTY before outputting colors. | ||||
| 	ForceColors bool | ||||
| 
 | ||||
| 	// Force disabling colors. | ||||
| 	DisableColors bool | ||||
| 
 | ||||
| 	// Force quoting of all values | ||||
| 	ForceQuote bool | ||||
| 
 | ||||
| 	// DisableQuote disables quoting for all values. | ||||
| 	// DisableQuote will have a lower priority than ForceQuote. | ||||
| 	// If both of them are set to true, quote will be forced on all values. | ||||
| 	DisableQuote bool | ||||
| 
 | ||||
| 	// Override coloring based on CLICOLOR and CLICOLOR_FORCE. - https://bixense.com/clicolors/ | ||||
| 	EnvironmentOverrideColors bool | ||||
| 
 | ||||
| 	// Disable timestamp logging. useful when output is redirected to logging | ||||
| 	// system that already adds timestamps. | ||||
| 	DisableTimestamp bool | ||||
| 
 | ||||
| 	// Enable logging the full timestamp when a TTY is attached instead of just | ||||
| 	// the time passed since beginning of execution. | ||||
| 	FullTimestamp bool | ||||
| 
 | ||||
| 	// TimestampFormat to use for display when a full timestamp is printed. | ||||
| 	// The format to use is the same than for time.Format or time.Parse from the standard | ||||
| 	// library. | ||||
| 	// The standard Library already provides a set of predefined format. | ||||
| 	TimestampFormat string | ||||
| 
 | ||||
| 	// The fields are sorted by default for a consistent output. For applications | ||||
| 	// that log extremely frequently and don't use the JSON formatter this may not | ||||
| 	// be desired. | ||||
| 	DisableSorting bool | ||||
| 
 | ||||
| 	// The keys sorting function, when uninitialized it uses sort.Strings. | ||||
| 	SortingFunc func([]string) | ||||
| 
 | ||||
| 	// Disables the truncation of the level text to 4 characters. | ||||
| 	DisableLevelTruncation bool | ||||
| 
 | ||||
| 	// PadLevelText Adds padding the level text so that all the levels output at the same length | ||||
| 	// PadLevelText is a superset of the DisableLevelTruncation option | ||||
| 	PadLevelText bool | ||||
| 
 | ||||
| 	// QuoteEmptyFields will wrap empty fields in quotes if true | ||||
| 	QuoteEmptyFields bool | ||||
| 
 | ||||
| 	// Whether the logger's out is to a terminal | ||||
| 	isTerminal bool | ||||
| 
 | ||||
| 	// FieldMap allows users to customize the names of keys for default fields. | ||||
| 	// As an example: | ||||
| 	// formatter := &TextFormatter{ | ||||
| 	//     FieldMap: FieldMap{ | ||||
| 	//         FieldKeyTime:  "@timestamp", | ||||
| 	//         FieldKeyLevel: "@level", | ||||
| 	//         FieldKeyMsg:   "@message"}} | ||||
| 	FieldMap FieldMap | ||||
| 
 | ||||
| 	// CallerPrettyfier can be set by the user to modify the content | ||||
| 	// of the function and file keys in the data when ReportCaller is | ||||
| 	// activated. If any of the returned value is the empty string the | ||||
| 	// corresponding key will be removed from fields. | ||||
| 	CallerPrettyfier func(*runtime.Frame) (function string, file string) | ||||
| 
 | ||||
| 	terminalInitOnce sync.Once | ||||
| 
 | ||||
| 	// The max length of the level text, generated dynamically on init | ||||
| 	levelTextMaxLength int | ||||
| } | ||||
| 
 | ||||
| func (f *TextFormatter) init(entry *Entry) { | ||||
| 	if entry.Logger != nil { | ||||
| 		f.isTerminal = checkIfTerminal(entry.Logger.Out) | ||||
| 	} | ||||
| 	// Get the max length of the level text | ||||
| 	for _, level := range AllLevels { | ||||
| 		levelTextLength := utf8.RuneCount([]byte(level.String())) | ||||
| 		if levelTextLength > f.levelTextMaxLength { | ||||
| 			f.levelTextMaxLength = levelTextLength | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (f *TextFormatter) isColored() bool { | ||||
| 	isColored := f.ForceColors || (f.isTerminal && (runtime.GOOS != "windows")) | ||||
| 
 | ||||
| 	if f.EnvironmentOverrideColors { | ||||
| 		switch force, ok := os.LookupEnv("CLICOLOR_FORCE"); { | ||||
| 		case ok && force != "0": | ||||
| 			isColored = true | ||||
| 		case ok && force == "0", os.Getenv("CLICOLOR") == "0": | ||||
| 			isColored = false | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return isColored && !f.DisableColors | ||||
| } | ||||
| 
 | ||||
| // Format renders a single log entry | ||||
| func (f *TextFormatter) Format(entry *Entry) ([]byte, error) { | ||||
| 	data := make(Fields) | ||||
| 	for k, v := range entry.Data { | ||||
| 		data[k] = v | ||||
| 	} | ||||
| 	prefixFieldClashes(data, f.FieldMap, entry.HasCaller()) | ||||
| 	keys := make([]string, 0, len(data)) | ||||
| 	for k := range data { | ||||
| 		keys = append(keys, k) | ||||
| 	} | ||||
| 
 | ||||
| 	var funcVal, fileVal string | ||||
| 
 | ||||
| 	fixedKeys := make([]string, 0, 4+len(data)) | ||||
| 	if !f.DisableTimestamp { | ||||
| 		fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyTime)) | ||||
| 	} | ||||
| 	fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyLevel)) | ||||
| 	if entry.Message != "" { | ||||
| 		fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyMsg)) | ||||
| 	} | ||||
| 	if entry.err != "" { | ||||
| 		fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyLogrusError)) | ||||
| 	} | ||||
| 	if entry.HasCaller() { | ||||
| 		if f.CallerPrettyfier != nil { | ||||
| 			funcVal, fileVal = f.CallerPrettyfier(entry.Caller) | ||||
| 		} else { | ||||
| 			funcVal = entry.Caller.Function | ||||
| 			fileVal = fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line) | ||||
| 		} | ||||
| 
 | ||||
| 		if funcVal != "" { | ||||
| 			fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyFunc)) | ||||
| 		} | ||||
| 		if fileVal != "" { | ||||
| 			fixedKeys = append(fixedKeys, f.FieldMap.resolve(FieldKeyFile)) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if !f.DisableSorting { | ||||
| 		if f.SortingFunc == nil { | ||||
| 			sort.Strings(keys) | ||||
| 			fixedKeys = append(fixedKeys, keys...) | ||||
| 		} else { | ||||
| 			if !f.isColored() { | ||||
| 				fixedKeys = append(fixedKeys, keys...) | ||||
| 				f.SortingFunc(fixedKeys) | ||||
| 			} else { | ||||
| 				f.SortingFunc(keys) | ||||
| 			} | ||||
| 		} | ||||
| 	} else { | ||||
| 		fixedKeys = append(fixedKeys, keys...) | ||||
| 	} | ||||
| 
 | ||||
| 	var b *bytes.Buffer | ||||
| 	if entry.Buffer != nil { | ||||
| 		b = entry.Buffer | ||||
| 	} else { | ||||
| 		b = &bytes.Buffer{} | ||||
| 	} | ||||
| 
 | ||||
| 	f.terminalInitOnce.Do(func() { f.init(entry) }) | ||||
| 
 | ||||
| 	timestampFormat := f.TimestampFormat | ||||
| 	if timestampFormat == "" { | ||||
| 		timestampFormat = defaultTimestampFormat | ||||
| 	} | ||||
| 	if f.isColored() { | ||||
| 		f.printColored(b, entry, keys, data, timestampFormat) | ||||
| 	} else { | ||||
| 
 | ||||
| 		for _, key := range fixedKeys { | ||||
| 			var value interface{} | ||||
| 			switch { | ||||
| 			case key == f.FieldMap.resolve(FieldKeyTime): | ||||
| 				value = entry.Time.Format(timestampFormat) | ||||
| 			case key == f.FieldMap.resolve(FieldKeyLevel): | ||||
| 				value = entry.Level.String() | ||||
| 			case key == f.FieldMap.resolve(FieldKeyMsg): | ||||
| 				value = entry.Message | ||||
| 			case key == f.FieldMap.resolve(FieldKeyLogrusError): | ||||
| 				value = entry.err | ||||
| 			case key == f.FieldMap.resolve(FieldKeyFunc) && entry.HasCaller(): | ||||
| 				value = funcVal | ||||
| 			case key == f.FieldMap.resolve(FieldKeyFile) && entry.HasCaller(): | ||||
| 				value = fileVal | ||||
| 			default: | ||||
| 				value = data[key] | ||||
| 			} | ||||
| 			f.appendKeyValue(b, key, value) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	b.WriteByte('\n') | ||||
| 	return b.Bytes(), nil | ||||
| } | ||||
| 
 | ||||
| func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []string, data Fields, timestampFormat string) { | ||||
| 	var levelColor int | ||||
| 	switch entry.Level { | ||||
| 	case DebugLevel, TraceLevel: | ||||
| 		levelColor = gray | ||||
| 	case WarnLevel: | ||||
| 		levelColor = yellow | ||||
| 	case ErrorLevel, FatalLevel, PanicLevel: | ||||
| 		levelColor = red | ||||
| 	case InfoLevel: | ||||
| 		levelColor = blue | ||||
| 	default: | ||||
| 		levelColor = blue | ||||
| 	} | ||||
| 
 | ||||
| 	levelText := strings.ToUpper(entry.Level.String()) | ||||
| 	if !f.DisableLevelTruncation && !f.PadLevelText { | ||||
| 		levelText = levelText[0:4] | ||||
| 	} | ||||
| 	if f.PadLevelText { | ||||
| 		// Generates the format string used in the next line, for example "%-6s" or "%-7s". | ||||
| 		// Based on the max level text length. | ||||
| 		formatString := "%-" + strconv.Itoa(f.levelTextMaxLength) + "s" | ||||
| 		// Formats the level text by appending spaces up to the max length, for example: | ||||
| 		// 	- "INFO   " | ||||
| 		//	- "WARNING" | ||||
| 		levelText = fmt.Sprintf(formatString, levelText) | ||||
| 	} | ||||
| 
 | ||||
| 	// Remove a single newline if it already exists in the message to keep | ||||
| 	// the behavior of logrus text_formatter the same as the stdlib log package | ||||
| 	entry.Message = strings.TrimSuffix(entry.Message, "\n") | ||||
| 
 | ||||
| 	caller := "" | ||||
| 	if entry.HasCaller() { | ||||
| 		funcVal := fmt.Sprintf("%s()", entry.Caller.Function) | ||||
| 		fileVal := fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line) | ||||
| 
 | ||||
| 		if f.CallerPrettyfier != nil { | ||||
| 			funcVal, fileVal = f.CallerPrettyfier(entry.Caller) | ||||
| 		} | ||||
| 
 | ||||
| 		if fileVal == "" { | ||||
| 			caller = funcVal | ||||
| 		} else if funcVal == "" { | ||||
| 			caller = fileVal | ||||
| 		} else { | ||||
| 			caller = fileVal + " " + funcVal | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	switch { | ||||
| 	case f.DisableTimestamp: | ||||
| 		fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m%s %-44s ", levelColor, levelText, caller, entry.Message) | ||||
| 	case !f.FullTimestamp: | ||||
| 		fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d]%s %-44s ", levelColor, levelText, int(entry.Time.Sub(baseTimestamp)/time.Second), caller, entry.Message) | ||||
| 	default: | ||||
| 		fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s]%s %-44s ", levelColor, levelText, entry.Time.Format(timestampFormat), caller, entry.Message) | ||||
| 	} | ||||
| 	for _, k := range keys { | ||||
| 		v := data[k] | ||||
| 		fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=", levelColor, k) | ||||
| 		f.appendValue(b, v) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (f *TextFormatter) needsQuoting(text string) bool { | ||||
| 	if f.ForceQuote { | ||||
| 		return true | ||||
| 	} | ||||
| 	if f.QuoteEmptyFields && len(text) == 0 { | ||||
| 		return true | ||||
| 	} | ||||
| 	if f.DisableQuote { | ||||
| 		return false | ||||
| 	} | ||||
| 	for _, ch := range text { | ||||
| 		if !((ch >= 'a' && ch <= 'z') || | ||||
| 			(ch >= 'A' && ch <= 'Z') || | ||||
| 			(ch >= '0' && ch <= '9') || | ||||
| 			ch == '-' || ch == '.' || ch == '_' || ch == '/' || ch == '@' || ch == '^' || ch == '+') { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value interface{}) { | ||||
| 	if b.Len() > 0 { | ||||
| 		b.WriteByte(' ') | ||||
| 	} | ||||
| 	b.WriteString(key) | ||||
| 	b.WriteByte('=') | ||||
| 	f.appendValue(b, value) | ||||
| } | ||||
| 
 | ||||
| func (f *TextFormatter) appendValue(b *bytes.Buffer, value interface{}) { | ||||
| 	stringVal, ok := value.(string) | ||||
| 	if !ok { | ||||
| 		stringVal = fmt.Sprint(value) | ||||
| 	} | ||||
| 
 | ||||
| 	if !f.needsQuoting(stringVal) { | ||||
| 		b.WriteString(stringVal) | ||||
| 	} else { | ||||
| 		b.WriteString(fmt.Sprintf("%q", stringVal)) | ||||
| 	} | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue