mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-03 08:02:36 +09:00 
			
		
		
		
	
		
			
				
	
	
		
			362 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
			
		
		
	
	
			362 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
//  Copyright (c) 2016 Couchbase, Inc.
 | 
						|
//  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
 | 
						|
//  except in compliance with the License. You may obtain a copy of the License at
 | 
						|
//    http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
//  Unless required by applicable law or agreed to in writing, software distributed under the
 | 
						|
//  License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 | 
						|
//  either express or implied. See the License for the specific language governing permissions
 | 
						|
//  and limitations under the License.
 | 
						|
 | 
						|
package logging
 | 
						|
 | 
						|
import (
 | 
						|
	"os"
 | 
						|
	"runtime"
 | 
						|
	"strings"
 | 
						|
	"sync"
 | 
						|
)
 | 
						|
 | 
						|
type Level int
 | 
						|
 | 
						|
const (
 | 
						|
	NONE    = Level(iota) // Disable all logging
 | 
						|
	FATAL                 // System is in severe error state and has to abort
 | 
						|
	SEVERE                // System is in severe error state and cannot recover reliably
 | 
						|
	ERROR                 // System is in error state but can recover and continue reliably
 | 
						|
	WARN                  // System approaching error state, or is in a correct but undesirable state
 | 
						|
	INFO                  // System-level events and status, in correct states
 | 
						|
	REQUEST               // Request-level events, with request-specific rlevel
 | 
						|
	TRACE                 // Trace detailed system execution, e.g. function entry / exit
 | 
						|
	DEBUG                 // Debug
 | 
						|
)
 | 
						|
 | 
						|
type LogEntryFormatter int
 | 
						|
 | 
						|
const (
 | 
						|
	TEXTFORMATTER = LogEntryFormatter(iota)
 | 
						|
	JSONFORMATTER
 | 
						|
	KVFORMATTER
 | 
						|
	UNIFORMFORMATTER
 | 
						|
)
 | 
						|
 | 
						|
func (level Level) String() string {
 | 
						|
	return _LEVEL_NAMES[level]
 | 
						|
}
 | 
						|
 | 
						|
var _LEVEL_NAMES = []string{
 | 
						|
	DEBUG:   "DEBUG",
 | 
						|
	TRACE:   "TRACE",
 | 
						|
	REQUEST: "REQUEST",
 | 
						|
	INFO:    "INFO",
 | 
						|
	WARN:    "WARN",
 | 
						|
	ERROR:   "ERROR",
 | 
						|
	SEVERE:  "SEVERE",
 | 
						|
	FATAL:   "FATAL",
 | 
						|
	NONE:    "NONE",
 | 
						|
}
 | 
						|
 | 
						|
var _LEVEL_MAP = map[string]Level{
 | 
						|
	"debug":   DEBUG,
 | 
						|
	"trace":   TRACE,
 | 
						|
	"request": REQUEST,
 | 
						|
	"info":    INFO,
 | 
						|
	"warn":    WARN,
 | 
						|
	"error":   ERROR,
 | 
						|
	"severe":  SEVERE,
 | 
						|
	"fatal":   FATAL,
 | 
						|
	"none":    NONE,
 | 
						|
}
 | 
						|
 | 
						|
// cache logging enablement to improve runtime performance (reduces from multiple tests to a single test on each call)
 | 
						|
var (
 | 
						|
	cachedDebug   bool
 | 
						|
	cachedTrace   bool
 | 
						|
	cachedRequest bool
 | 
						|
	cachedInfo    bool
 | 
						|
	cachedWarn    bool
 | 
						|
	cachedError   bool
 | 
						|
	cachedSevere  bool
 | 
						|
	cachedFatal   bool
 | 
						|
)
 | 
						|
 | 
						|
// maintain the cached logging state
 | 
						|
func cacheLoggingChange() {
 | 
						|
	cachedDebug = !skipLogging(DEBUG)
 | 
						|
	cachedTrace = !skipLogging(TRACE)
 | 
						|
	cachedRequest = !skipLogging(REQUEST)
 | 
						|
	cachedInfo = !skipLogging(INFO)
 | 
						|
	cachedWarn = !skipLogging(WARN)
 | 
						|
	cachedError = !skipLogging(ERROR)
 | 
						|
	cachedSevere = !skipLogging(SEVERE)
 | 
						|
	cachedFatal = !skipLogging(FATAL)
 | 
						|
}
 | 
						|
 | 
						|
func ParseLevel(name string) (level Level, ok bool) {
 | 
						|
	level, ok = _LEVEL_MAP[strings.ToLower(name)]
 | 
						|
	return
 | 
						|
}
 | 
						|
 | 
						|
// Logger provides a common interface for logging libraries
 | 
						|
type Logger interface {
 | 
						|
	// Higher performance
 | 
						|
	Loga(level Level, f func() string)
 | 
						|
	Debuga(f func() string)
 | 
						|
	Tracea(f func() string)
 | 
						|
	Requesta(rlevel Level, f func() string)
 | 
						|
	Infoa(f func() string)
 | 
						|
	Warna(f func() string)
 | 
						|
	Errora(f func() string)
 | 
						|
	Severea(f func() string)
 | 
						|
	Fatala(f func() string)
 | 
						|
 | 
						|
	// Printf style
 | 
						|
	Logf(level Level, fmt string, args ...interface{})
 | 
						|
	Debugf(fmt string, args ...interface{})
 | 
						|
	Tracef(fmt string, args ...interface{})
 | 
						|
	Requestf(rlevel Level, fmt string, args ...interface{})
 | 
						|
	Infof(fmt string, args ...interface{})
 | 
						|
	Warnf(fmt string, args ...interface{})
 | 
						|
	Errorf(fmt string, args ...interface{})
 | 
						|
	Severef(fmt string, args ...interface{})
 | 
						|
	Fatalf(fmt string, args ...interface{})
 | 
						|
 | 
						|
	/*
 | 
						|
		These APIs control the logging level
 | 
						|
	*/
 | 
						|
	SetLevel(Level) // Set the logging level
 | 
						|
	Level() Level   // Get the current logging level
 | 
						|
}
 | 
						|
 | 
						|
var logger Logger = nil
 | 
						|
var curLevel Level = DEBUG // initially set to never skip
 | 
						|
 | 
						|
var loggerMutex sync.RWMutex
 | 
						|
 | 
						|
// All the methods below first acquire the mutex (mostly in exclusive mode)
 | 
						|
// and only then check if logging at the current level is enabled.
 | 
						|
// This introduces a fair bottleneck for those log entries that should be
 | 
						|
// skipped (the majority, at INFO or below levels)
 | 
						|
// We try to predict here if we should lock the mutex at all by caching
 | 
						|
// the current log level: while dynamically changing logger, there might
 | 
						|
// be the odd entry skipped as the new level is cached.
 | 
						|
// Since we seem to never change the logger, this is not an issue.
 | 
						|
func skipLogging(level Level) bool {
 | 
						|
	if logger == nil {
 | 
						|
		return true
 | 
						|
	}
 | 
						|
	return level > curLevel
 | 
						|
}
 | 
						|
 | 
						|
func SetLogger(newLogger Logger) {
 | 
						|
	loggerMutex.Lock()
 | 
						|
	defer loggerMutex.Unlock()
 | 
						|
	logger = newLogger
 | 
						|
	if logger == nil {
 | 
						|
		curLevel = NONE
 | 
						|
	} else {
 | 
						|
		curLevel = newLogger.Level()
 | 
						|
	}
 | 
						|
	cacheLoggingChange()
 | 
						|
}
 | 
						|
 | 
						|
// we are using deferred unlocking here throughout as we have to do this
 | 
						|
// for the anonymous function variants even though it would be more efficient
 | 
						|
// to not do this for the printf style variants
 | 
						|
// anonymous function variants
 | 
						|
 | 
						|
func Loga(level Level, f func() string) {
 | 
						|
	if skipLogging(level) {
 | 
						|
		return
 | 
						|
	}
 | 
						|
	loggerMutex.Lock()
 | 
						|
	defer loggerMutex.Unlock()
 | 
						|
	logger.Loga(level, f)
 | 
						|
}
 | 
						|
 | 
						|
func Debuga(f func() string) {
 | 
						|
	if !cachedDebug {
 | 
						|
		return
 | 
						|
	}
 | 
						|
	loggerMutex.Lock()
 | 
						|
	defer loggerMutex.Unlock()
 | 
						|
	logger.Debuga(f)
 | 
						|
}
 | 
						|
 | 
						|
func Tracea(f func() string) {
 | 
						|
	if !cachedTrace {
 | 
						|
		return
 | 
						|
	}
 | 
						|
	loggerMutex.Lock()
 | 
						|
	defer loggerMutex.Unlock()
 | 
						|
	logger.Tracea(f)
 | 
						|
}
 | 
						|
 | 
						|
func Requesta(rlevel Level, f func() string) {
 | 
						|
	if !cachedRequest {
 | 
						|
		return
 | 
						|
	}
 | 
						|
	loggerMutex.Lock()
 | 
						|
	defer loggerMutex.Unlock()
 | 
						|
	logger.Requesta(rlevel, f)
 | 
						|
}
 | 
						|
 | 
						|
func Infoa(f func() string) {
 | 
						|
	if !cachedInfo {
 | 
						|
		return
 | 
						|
	}
 | 
						|
	loggerMutex.Lock()
 | 
						|
	defer loggerMutex.Unlock()
 | 
						|
	logger.Infoa(f)
 | 
						|
}
 | 
						|
 | 
						|
func Warna(f func() string) {
 | 
						|
	if !cachedWarn {
 | 
						|
		return
 | 
						|
	}
 | 
						|
	loggerMutex.Lock()
 | 
						|
	defer loggerMutex.Unlock()
 | 
						|
	logger.Warna(f)
 | 
						|
}
 | 
						|
 | 
						|
func Errora(f func() string) {
 | 
						|
	if !cachedError {
 | 
						|
		return
 | 
						|
	}
 | 
						|
	loggerMutex.Lock()
 | 
						|
	defer loggerMutex.Unlock()
 | 
						|
	logger.Errora(f)
 | 
						|
}
 | 
						|
 | 
						|
func Severea(f func() string) {
 | 
						|
	if !cachedSevere {
 | 
						|
		return
 | 
						|
	}
 | 
						|
	loggerMutex.Lock()
 | 
						|
	defer loggerMutex.Unlock()
 | 
						|
	logger.Severea(f)
 | 
						|
}
 | 
						|
 | 
						|
func Fatala(f func() string) {
 | 
						|
	if !cachedFatal {
 | 
						|
		return
 | 
						|
	}
 | 
						|
	loggerMutex.Lock()
 | 
						|
	defer loggerMutex.Unlock()
 | 
						|
	logger.Fatala(f)
 | 
						|
}
 | 
						|
 | 
						|
// printf-style variants
 | 
						|
 | 
						|
func Logf(level Level, fmt string, args ...interface{}) {
 | 
						|
	if skipLogging(level) {
 | 
						|
		return
 | 
						|
	}
 | 
						|
	loggerMutex.Lock()
 | 
						|
	defer loggerMutex.Unlock()
 | 
						|
	logger.Logf(level, fmt, args...)
 | 
						|
}
 | 
						|
 | 
						|
func Debugf(fmt string, args ...interface{}) {
 | 
						|
	if !cachedDebug {
 | 
						|
		return
 | 
						|
	}
 | 
						|
	loggerMutex.Lock()
 | 
						|
	defer loggerMutex.Unlock()
 | 
						|
	logger.Debugf(fmt, args...)
 | 
						|
}
 | 
						|
 | 
						|
func Tracef(fmt string, args ...interface{}) {
 | 
						|
	if !cachedTrace {
 | 
						|
		return
 | 
						|
	}
 | 
						|
	loggerMutex.Lock()
 | 
						|
	defer loggerMutex.Unlock()
 | 
						|
	logger.Tracef(fmt, args...)
 | 
						|
}
 | 
						|
 | 
						|
func Requestf(rlevel Level, fmt string, args ...interface{}) {
 | 
						|
	if !cachedRequest {
 | 
						|
		return
 | 
						|
	}
 | 
						|
	loggerMutex.Lock()
 | 
						|
	defer loggerMutex.Unlock()
 | 
						|
	logger.Requestf(rlevel, fmt, args...)
 | 
						|
}
 | 
						|
 | 
						|
func Infof(fmt string, args ...interface{}) {
 | 
						|
	if !cachedInfo {
 | 
						|
		return
 | 
						|
	}
 | 
						|
	loggerMutex.Lock()
 | 
						|
	defer loggerMutex.Unlock()
 | 
						|
	logger.Infof(fmt, args...)
 | 
						|
}
 | 
						|
 | 
						|
func Warnf(fmt string, args ...interface{}) {
 | 
						|
	if !cachedWarn {
 | 
						|
		return
 | 
						|
	}
 | 
						|
	loggerMutex.Lock()
 | 
						|
	defer loggerMutex.Unlock()
 | 
						|
	logger.Warnf(fmt, args...)
 | 
						|
}
 | 
						|
 | 
						|
func Errorf(fmt string, args ...interface{}) {
 | 
						|
	if !cachedError {
 | 
						|
		return
 | 
						|
	}
 | 
						|
	loggerMutex.Lock()
 | 
						|
	defer loggerMutex.Unlock()
 | 
						|
	logger.Errorf(fmt, args...)
 | 
						|
}
 | 
						|
 | 
						|
func Severef(fmt string, args ...interface{}) {
 | 
						|
	if !cachedSevere {
 | 
						|
		return
 | 
						|
	}
 | 
						|
	loggerMutex.Lock()
 | 
						|
	defer loggerMutex.Unlock()
 | 
						|
	logger.Severef(fmt, args...)
 | 
						|
}
 | 
						|
 | 
						|
func Fatalf(fmt string, args ...interface{}) {
 | 
						|
	if !cachedFatal {
 | 
						|
		return
 | 
						|
	}
 | 
						|
	loggerMutex.Lock()
 | 
						|
	defer loggerMutex.Unlock()
 | 
						|
	logger.Fatalf(fmt, args...)
 | 
						|
}
 | 
						|
 | 
						|
func SetLevel(level Level) {
 | 
						|
	loggerMutex.Lock()
 | 
						|
	defer loggerMutex.Unlock()
 | 
						|
	logger.SetLevel(level)
 | 
						|
	curLevel = level
 | 
						|
	cacheLoggingChange()
 | 
						|
}
 | 
						|
 | 
						|
func LogLevel() Level {
 | 
						|
	loggerMutex.RLock()
 | 
						|
	defer loggerMutex.RUnlock()
 | 
						|
	return logger.Level()
 | 
						|
}
 | 
						|
 | 
						|
func Stackf(level Level, fmt string, args ...interface{}) {
 | 
						|
	if skipLogging(level) {
 | 
						|
		return
 | 
						|
	}
 | 
						|
	buf := make([]byte, 1<<16)
 | 
						|
	n := runtime.Stack(buf, false)
 | 
						|
	s := string(buf[0:n])
 | 
						|
	loggerMutex.Lock()
 | 
						|
	defer loggerMutex.Unlock()
 | 
						|
	logger.Logf(level, fmt, args...)
 | 
						|
	logger.Logf(level, s)
 | 
						|
}
 | 
						|
 | 
						|
func init() {
 | 
						|
	logger := NewLogger(os.Stderr, INFO, TEXTFORMATTER)
 | 
						|
	SetLogger(logger)
 | 
						|
}
 |