2014-10-04 19:33:20 +08:00
// Copyright 2014 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package log
import (
"fmt"
2022-01-06 22:28:05 +08:00
"io"
2022-02-03 23:20:02 +08:00
"log"
2014-10-04 19:33:20 +08:00
"os"
"path/filepath"
2022-02-03 23:20:02 +08:00
"sort"
2014-10-04 19:33:20 +08:00
"strings"
2022-02-03 23:20:02 +08:00
"sync"
2022-01-06 22:28:05 +08:00
"time"
2014-10-04 19:33:20 +08:00
2022-01-06 22:28:05 +08:00
gokitlog "github.com/go-kit/log"
2016-06-11 19:49:11 +08:00
"github.com/go-stack/stack"
2022-01-14 02:30:28 +08:00
"github.com/mattn/go-isatty"
"gopkg.in/ini.v1"
2022-01-06 22:28:05 +08:00
"github.com/grafana/grafana/pkg/infra/log/level"
2022-01-26 19:19:43 +08:00
"github.com/grafana/grafana/pkg/infra/log/term"
2019-01-15 18:49:18 +08:00
"github.com/grafana/grafana/pkg/util"
2019-12-02 22:40:32 +08:00
"github.com/grafana/grafana/pkg/util/errutil"
2014-10-04 19:33:20 +08:00
)
2016-06-07 05:06:44 +08:00
var loggersToClose [ ] DisposableHandler
2018-09-04 16:31:41 +08:00
var loggersToReload [ ] ReloadableHandler
2022-02-03 23:20:02 +08:00
var root * logManager
2014-10-04 19:33:20 +08:00
2022-01-14 02:30:28 +08:00
const (
// top 7 calls in the stack are within logger
DefaultCallerDepth = 7
CallerContextKey = "caller"
)
2016-06-07 05:06:44 +08:00
func init ( ) {
loggersToClose = make ( [ ] DisposableHandler , 0 )
2018-09-04 16:31:41 +08:00
loggersToReload = make ( [ ] ReloadableHandler , 0 )
2022-01-26 19:19:43 +08:00
// Use console by default
format := getLogFormat ( "console" )
2022-02-03 23:20:02 +08:00
logger := level . NewFilter ( format ( os . Stderr ) , level . AllowInfo ( ) )
root = newManager ( logger )
2014-10-04 19:33:20 +08:00
}
2022-02-03 23:20:02 +08:00
// logManager manage loggers
type logManager struct {
* ConcreteLogger
loggersByName map [ string ] * ConcreteLogger
logFilters [ ] LogWithFilters
mutex sync . RWMutex
2016-02-17 14:43:13 +08:00
}
2022-02-03 23:20:02 +08:00
func newManager ( logger gokitlog . Logger ) * logManager {
return & logManager {
ConcreteLogger : newConcreteLogger ( logger ) ,
loggersByName : map [ string ] * ConcreteLogger { } ,
}
2022-01-06 22:28:05 +08:00
}
2022-02-03 23:20:02 +08:00
func ( lm * logManager ) initialize ( loggers [ ] LogWithFilters ) {
lm . mutex . Lock ( )
defer lm . mutex . Unlock ( )
2022-01-06 22:28:05 +08:00
2022-02-03 23:20:02 +08:00
defaultLoggers := make ( [ ] gokitlog . Logger , len ( loggers ) )
for index , logger := range loggers {
defaultLoggers [ index ] = level . NewFilter ( logger . val , logger . maxLevel )
}
2022-01-06 22:28:05 +08:00
2022-02-03 23:20:02 +08:00
lm . ConcreteLogger . SetLogger ( & compositeLogger { loggers : defaultLoggers } )
lm . logFilters = loggers
2022-01-06 22:28:05 +08:00
2022-02-03 23:20:02 +08:00
loggersByName := [ ] string { }
for k := range lm . loggersByName {
loggersByName = append ( loggersByName , k )
2014-10-04 19:33:20 +08:00
}
2022-02-03 23:20:02 +08:00
sort . Strings ( loggersByName )
for _ , name := range loggersByName {
ctxLoggers := make ( [ ] gokitlog . Logger , len ( loggers ) )
2020-12-15 16:32:06 +08:00
2022-02-03 23:20:02 +08:00
for index , logger := range loggers {
if filterLevel , exists := logger . filters [ name ] ; ! exists {
ctxLoggers [ index ] = level . NewFilter ( logger . val , logger . maxLevel )
} else {
ctxLoggers [ index ] = level . NewFilter ( logger . val , filterLevel )
}
}
lm . loggersByName [ name ] . SetLogger ( & compositeLogger { loggers : ctxLoggers } )
2022-01-06 22:28:05 +08:00
}
2014-10-04 19:33:20 +08:00
}
2022-02-03 23:20:02 +08:00
func ( lm * logManager ) SetLogger ( logger gokitlog . Logger ) {
lm . ConcreteLogger . SetLogger ( logger )
2022-01-06 22:28:05 +08:00
}
2022-02-03 23:20:02 +08:00
func ( lm * logManager ) GetLogger ( ) gokitlog . Logger {
return lm . ConcreteLogger . GetLogger ( )
2022-01-06 22:28:05 +08:00
}
2022-02-03 23:20:02 +08:00
func ( lm * logManager ) Log ( args ... interface { } ) error {
lm . mutex . RLock ( )
defer lm . mutex . RUnlock ( )
if err := lm . ConcreteLogger . Log ( args ... ) ; err != nil {
log . Println ( "Logging error" , "error" , err )
2018-09-04 16:31:41 +08:00
}
2022-02-03 23:20:02 +08:00
return nil
2022-01-06 22:28:05 +08:00
}
2022-02-03 23:20:02 +08:00
func ( lm * logManager ) New ( ctx ... interface { } ) * ConcreteLogger {
lm . mutex . Lock ( )
defer lm . mutex . Unlock ( )
2022-01-06 22:28:05 +08:00
if len ( ctx ) == 0 {
2022-02-03 23:20:02 +08:00
return lm . ConcreteLogger
2022-01-06 22:28:05 +08:00
}
2022-02-03 23:20:02 +08:00
loggerName , ok := ctx [ 0 ] . ( string )
if ! ok {
return lm . ConcreteLogger
}
if logger , exists := lm . loggersByName [ loggerName ] ; exists {
return logger
}
2022-01-06 22:28:05 +08:00
ctx = append ( [ ] interface { } { "logger" } , ctx ... )
2022-02-03 23:20:02 +08:00
if len ( lm . logFilters ) == 0 {
ctxLogger := newConcreteLogger ( lm . logger , ctx ... )
lm . loggersByName [ loggerName ] = ctxLogger
return ctxLogger
}
compositeLogger := newCompositeLogger ( )
for _ , logWithFilter := range lm . logFilters {
filterLevel , ok := logWithFilter . filters [ loggerName ]
2022-01-06 22:28:05 +08:00
if ok {
2022-02-03 23:20:02 +08:00
logWithFilter . val = level . NewFilter ( logWithFilter . val , filterLevel )
2022-01-06 22:28:05 +08:00
} else {
logWithFilter . val = level . NewFilter ( logWithFilter . val , logWithFilter . maxLevel )
}
2022-02-03 23:20:02 +08:00
compositeLogger . loggers = append ( compositeLogger . loggers , logWithFilter . val )
2022-01-06 22:28:05 +08:00
}
2022-02-03 23:20:02 +08:00
ctxLogger := newConcreteLogger ( compositeLogger , ctx ... )
lm . loggersByName [ loggerName ] = ctxLogger
return ctxLogger
2022-01-06 22:28:05 +08:00
}
2022-02-03 23:20:02 +08:00
type ConcreteLogger struct {
ctx [ ] interface { }
logger gokitlog . Logger
mutex sync . RWMutex
}
func newConcreteLogger ( logger gokitlog . Logger , ctx ... interface { } ) * ConcreteLogger {
2022-01-14 02:30:28 +08:00
if len ( ctx ) == 0 {
2022-02-03 23:20:02 +08:00
ctx = [ ] interface { } { }
} else {
logger = gokitlog . With ( logger , ctx ... )
2022-01-14 02:30:28 +08:00
}
2022-02-03 23:20:02 +08:00
return & ConcreteLogger {
ctx : ctx ,
logger : logger ,
2022-01-14 02:30:28 +08:00
}
2022-02-03 23:20:02 +08:00
}
func ( cl * ConcreteLogger ) SetLogger ( logger gokitlog . Logger ) {
cl . mutex . Lock ( )
cl . logger = gokitlog . With ( logger , cl . ctx ... )
cl . mutex . Unlock ( )
}
func ( cl * ConcreteLogger ) GetLogger ( ) gokitlog . Logger {
cl . mutex . Lock ( )
defer cl . mutex . Unlock ( )
return cl . logger
}
func ( cl * ConcreteLogger ) Warn ( msg string , args ... interface { } ) {
_ = cl . log ( msg , level . WarnValue ( ) , args ... )
}
func ( cl * ConcreteLogger ) Debug ( msg string , args ... interface { } ) {
// args = append([]interface{}{level.Key(), level.DebugValue(), "msg", msg}, args...)
_ = cl . log ( msg , level . DebugValue ( ) , args ... )
}
func ( cl * ConcreteLogger ) Error ( msg string , args ... interface { } ) {
_ = cl . log ( msg , level . ErrorValue ( ) , args ... )
}
func ( cl * ConcreteLogger ) Info ( msg string , args ... interface { } ) {
_ = cl . log ( msg , level . InfoValue ( ) , args ... )
}
func ( cl * ConcreteLogger ) log ( msg string , logLevel level . Value , args ... interface { } ) error {
cl . mutex . RLock ( )
logger := gokitlog . With ( cl . logger , "t" , gokitlog . TimestampFormat ( time . Now , "2006-01-02T15:04:05.99-0700" ) )
cl . mutex . RUnlock ( )
args = append ( [ ] interface { } { level . Key ( ) , logLevel , "msg" , msg } , args ... )
return logger . Log ( args ... )
}
func ( cl * ConcreteLogger ) Log ( keyvals ... interface { } ) error {
cl . mutex . RLock ( )
defer cl . mutex . RUnlock ( )
return cl . logger . Log ( keyvals ... )
}
func ( cl * ConcreteLogger ) New ( ctx ... interface { } ) * ConcreteLogger {
if len ( ctx ) == 0 {
root . New ( )
}
keyvals := [ ] interface { } { }
if len ( cl . ctx ) % 2 == 1 {
cl . ctx = append ( cl . ctx , nil )
}
for i := 0 ; i < len ( cl . ctx ) ; i += 2 {
k , v := cl . ctx [ i ] , cl . ctx [ i + 1 ]
if k == "logger" {
continue
}
keyvals = append ( keyvals , k , v )
}
keyvals = append ( keyvals , ctx ... )
return root . New ( keyvals ... )
}
func New ( ctx ... interface { } ) * ConcreteLogger {
return root . New ( ctx ... )
}
type LogWithFilters struct {
val gokitlog . Logger
filters map [ string ] level . Option
maxLevel level . Option
}
func with ( ctxLogger * ConcreteLogger , withFunc func ( gokitlog . Logger , ... interface { } ) gokitlog . Logger , ctx [ ] interface { } ) * ConcreteLogger {
if len ( ctx ) == 0 {
return ctxLogger
}
ctxLogger . logger = withFunc ( ctxLogger . logger , ctx ... )
return ctxLogger
2022-01-14 02:30:28 +08:00
}
// WithPrefix adds context that will be added to the log message
2022-02-03 23:20:02 +08:00
func WithPrefix ( ctxLogger * ConcreteLogger , ctx ... interface { } ) * ConcreteLogger {
return with ( ctxLogger , gokitlog . WithPrefix , ctx )
2022-01-14 02:30:28 +08:00
}
// WithSuffix adds context that will be appended at the end of the log message
2022-02-03 23:20:02 +08:00
func WithSuffix ( ctxLogger * ConcreteLogger , ctx ... interface { } ) * ConcreteLogger {
return with ( ctxLogger , gokitlog . WithSuffix , ctx )
2022-01-14 02:30:28 +08:00
}
2022-01-06 22:28:05 +08:00
var logLevels = map [ string ] level . Option {
"trace" : level . AllowDebug ( ) ,
"debug" : level . AllowDebug ( ) ,
"info" : level . AllowInfo ( ) ,
"warn" : level . AllowWarn ( ) ,
"error" : level . AllowError ( ) ,
"critical" : level . AllowError ( ) ,
2014-10-04 19:33:20 +08:00
}
2022-01-06 22:28:05 +08:00
func getLogLevelFromConfig ( key string , defaultName string , cfg * ini . File ) ( string , level . Option ) {
2016-12-15 20:54:47 +08:00
levelName := cfg . Section ( key ) . Key ( "level" ) . MustString ( defaultName )
2016-06-08 14:48:46 +08:00
levelName = strings . ToLower ( levelName )
2016-06-07 18:11:41 +08:00
level := getLogLevelFromString ( levelName )
return levelName , level
}
2014-10-04 19:33:20 +08:00
2022-01-06 22:28:05 +08:00
func getLogLevelFromString ( levelName string ) level . Option {
loglevel , ok := logLevels [ levelName ]
2016-06-07 18:11:41 +08:00
2016-06-07 05:06:44 +08:00
if ! ok {
2022-02-03 23:20:02 +08:00
_ = level . Error ( root ) . Log ( "Unknown log level" , "level" , levelName )
2022-01-06 22:28:05 +08:00
return level . AllowError ( )
2014-10-04 19:33:20 +08:00
}
2022-01-06 22:28:05 +08:00
return loglevel
2016-06-07 18:11:41 +08:00
}
2022-01-06 22:28:05 +08:00
// the filter is composed with logger name and level
func getFilters ( filterStrArray [ ] string ) map [ string ] level . Option {
filterMap := make ( map [ string ] level . Option )
2016-06-07 18:11:41 +08:00
for _ , filterStr := range filterStrArray {
parts := strings . Split ( filterStr , ":" )
2016-07-26 18:29:52 +08:00
if len ( parts ) > 1 {
filterMap [ parts [ 0 ] ] = getLogLevelFromString ( parts [ 1 ] )
}
2016-06-07 18:11:41 +08:00
}
return filterMap
2014-10-04 19:33:20 +08:00
}
2022-01-06 22:28:05 +08:00
func Stack ( skip int ) string {
call := stack . Caller ( skip )
s := stack . Trace ( ) . TrimBelow ( call ) . TrimRuntime ( )
return s . String ( )
}
2022-01-14 02:30:28 +08:00
// StackCaller returns a go-kit Valuer function that returns the stack trace from the place it is called. Argument `skip` allows skipping top n lines from the stack.
func StackCaller ( skip int ) gokitlog . Valuer {
return func ( ) interface { } {
return Stack ( skip + 1 )
}
}
// Caller proxies go-kit/log Caller and returns a Valuer function that returns a file and line from a specified depth
// in the callstack
func Caller ( depth int ) gokitlog . Valuer {
return gokitlog . Caller ( depth )
}
2022-01-06 22:28:05 +08:00
type Formatedlogger func ( w io . Writer ) gokitlog . Logger
func getLogFormat ( format string ) Formatedlogger {
2016-06-08 14:48:46 +08:00
switch format {
case "console" :
2017-10-24 01:57:19 +08:00
if isatty . IsTerminal ( os . Stdout . Fd ( ) ) {
2022-01-06 22:28:05 +08:00
return func ( w io . Writer ) gokitlog . Logger {
2022-01-26 19:19:43 +08:00
return term . NewTerminalLogger ( w )
2022-01-06 22:28:05 +08:00
}
}
return func ( w io . Writer ) gokitlog . Logger {
return gokitlog . NewLogfmtLogger ( w )
2016-06-08 14:48:46 +08:00
}
case "text" :
2022-01-06 22:28:05 +08:00
return func ( w io . Writer ) gokitlog . Logger {
return gokitlog . NewLogfmtLogger ( w )
}
2016-06-08 14:48:46 +08:00
case "json" :
2022-01-06 22:28:05 +08:00
return func ( w io . Writer ) gokitlog . Logger {
return gokitlog . NewJSONLogger ( gokitlog . NewSyncWriter ( w ) )
}
2016-06-08 14:48:46 +08:00
default :
2022-01-06 22:28:05 +08:00
return func ( w io . Writer ) gokitlog . Logger {
return gokitlog . NewLogfmtLogger ( w )
}
}
}
// this is for file logger only
func Close ( ) error {
var err error
for _ , logger := range loggersToClose {
if e := logger . Close ( ) ; e != nil && err == nil {
err = e
}
2016-06-08 14:48:46 +08:00
}
2022-01-06 22:28:05 +08:00
loggersToClose = make ( [ ] DisposableHandler , 0 )
return err
}
// Reload reloads all loggers.
func Reload ( ) error {
for _ , logger := range loggersToReload {
if err := logger . Reload ( ) ; err != nil {
return err
}
}
return nil
2016-06-08 14:48:46 +08:00
}
2019-12-02 22:40:32 +08:00
func ReadLoggingConfig ( modes [ ] string , logsPath string , cfg * ini . File ) error {
2020-12-15 16:32:06 +08:00
if err := Close ( ) ; err != nil {
return err
}
2014-10-04 19:33:20 +08:00
2016-06-08 14:48:46 +08:00
defaultLevelName , _ := getLogLevelFromConfig ( "log" , "info" , cfg )
2017-04-25 15:14:29 +08:00
defaultFilters := getFilters ( util . SplitString ( cfg . Section ( "log" ) . Key ( "filters" ) . String ( ) ) )
2016-06-07 18:11:41 +08:00
2022-01-06 22:28:05 +08:00
var configLoggers [ ] LogWithFilters
2016-06-07 05:06:44 +08:00
for _ , mode := range modes {
mode = strings . TrimSpace ( mode )
sec , err := cfg . GetSection ( "log." + mode )
if err != nil {
2022-02-03 23:20:02 +08:00
_ = level . Error ( root ) . Log ( "Unknown log mode" , "mode" , mode )
2019-12-02 22:40:32 +08:00
return errutil . Wrapf ( err , "failed to get config section log.%s" , mode )
2014-10-04 19:33:20 +08:00
}
2016-06-07 05:06:44 +08:00
// Log level.
2022-01-06 22:28:05 +08:00
_ , leveloption := getLogLevelFromConfig ( "log." + mode , defaultLevelName , cfg )
2019-03-06 18:58:27 +08:00
modeFilters := getFilters ( util . SplitString ( sec . Key ( "filters" ) . String ( ) ) )
2022-01-06 22:28:05 +08:00
2016-06-08 14:48:46 +08:00
format := getLogFormat ( sec . Key ( "format" ) . MustString ( "" ) )
2016-06-07 18:11:41 +08:00
2022-01-06 22:28:05 +08:00
var handler LogWithFilters
2016-06-07 05:06:44 +08:00
switch mode {
case "console" :
2022-01-06 22:28:05 +08:00
handler . val = format ( os . Stdout )
2016-06-07 05:06:44 +08:00
case "file" :
fileName := sec . Key ( "file_name" ) . MustString ( filepath . Join ( logsPath , "grafana.log" ) )
2019-10-10 22:42:11 +08:00
dpath := filepath . Dir ( fileName )
if err := os . MkdirAll ( dpath , os . ModePerm ) ; err != nil {
2022-02-03 23:20:02 +08:00
_ = level . Error ( root ) . Log ( "Failed to create directory" , "dpath" , dpath , "err" , err )
2019-12-02 22:40:32 +08:00
return errutil . Wrapf ( err , "failed to create log directory %q" , dpath )
2019-10-10 22:42:11 +08:00
}
2016-06-07 05:06:44 +08:00
fileHandler := NewFileWriter ( )
fileHandler . Filename = fileName
2016-06-08 14:48:46 +08:00
fileHandler . Format = format
2016-06-07 05:06:44 +08:00
fileHandler . Rotate = sec . Key ( "log_rotate" ) . MustBool ( true )
fileHandler . Maxlines = sec . Key ( "max_lines" ) . MustInt ( 1000000 )
fileHandler . Maxsize = 1 << uint ( sec . Key ( "max_size_shift" ) . MustInt ( 28 ) )
fileHandler . Daily = sec . Key ( "daily_rotate" ) . MustBool ( true )
fileHandler . Maxdays = sec . Key ( "max_days" ) . MustInt64 ( 7 )
2019-10-10 22:42:11 +08:00
if err := fileHandler . Init ( ) ; err != nil {
2022-02-03 23:20:02 +08:00
_ = level . Error ( root ) . Log ( "Failed to initialize file handler" , "dpath" , dpath , "err" , err )
2019-12-02 22:40:32 +08:00
return errutil . Wrapf ( err , "failed to initialize file handler" )
2019-10-10 22:42:11 +08:00
}
2016-06-07 05:06:44 +08:00
loggersToClose = append ( loggersToClose , fileHandler )
2018-09-04 16:31:41 +08:00
loggersToReload = append ( loggersToReload , fileHandler )
2022-01-06 22:28:05 +08:00
handler . val = fileHandler
2016-06-08 14:09:29 +08:00
case "syslog" :
2016-06-17 00:21:12 +08:00
sysLogHandler := NewSyslog ( sec , format )
2016-06-08 14:09:29 +08:00
loggersToClose = append ( loggersToClose , sysLogHandler )
2022-01-06 22:28:05 +08:00
handler . val = sysLogHandler . logger
2016-06-07 05:06:44 +08:00
}
2022-01-06 22:28:05 +08:00
if handler . val == nil {
2019-12-02 22:40:32 +08:00
panic ( fmt . Sprintf ( "Handler is uninitialized for mode %q" , mode ) )
}
2016-06-07 18:11:41 +08:00
2022-01-06 22:28:05 +08:00
// join default filters and mode filters together
2016-06-07 18:11:41 +08:00
for key , value := range defaultFilters {
2019-03-06 18:58:27 +08:00
if _ , exist := modeFilters [ key ] ; ! exist {
modeFilters [ key ] = value
}
}
2022-01-06 22:28:05 +08:00
handler . filters = modeFilters
handler . maxLevel = leveloption
configLoggers = append ( configLoggers , handler )
}
2022-02-03 23:20:02 +08:00
2022-01-06 22:28:05 +08:00
if len ( configLoggers ) > 0 {
2022-02-03 23:20:02 +08:00
root . initialize ( configLoggers )
2016-02-01 12:49:37 +08:00
}
2022-02-03 23:20:02 +08:00
2019-12-02 22:40:32 +08:00
return nil
2014-10-04 19:33:20 +08:00
}