github.com/jxskiss/gopkg@v0.17.3/zlog/level.go (about)

     1  package zlog
     2  
     3  import (
     4  	"fmt"
     5  	"strconv"
     6  	"strings"
     7  
     8  	"go.uber.org/atomic"
     9  	"go.uber.org/zap"
    10  	"go.uber.org/zap/zapcore"
    11  )
    12  
    13  // A Level is a logging priority. Higher levels are more important.
    14  type Level int8
    15  
    16  const (
    17  	// TraceLevel logs are the most fine-grained information which helps
    18  	// developer "tracing" the code and trying to find one part of a
    19  	// function specifically. Use this level when you need full visibility
    20  	// of what is happening in your application and inside the third-party
    21  	// libraries that you use.
    22  	//
    23  	// You can expect this logging level to be very verbose. You can use it
    24  	// for example to annotate each step in the algorithm or each individual
    25  	// query with parameters in your code.
    26  	TraceLevel Level = iota - 2
    27  
    28  	// DebugLevel logs are less granular compared to TraceLevel, but it is
    29  	// more than you will need in everyday use. DebugLevel should be used
    30  	// for information that may be needed for diagnosing issues and
    31  	// troubleshooting or when running application in development or test
    32  	// environment for the purpose of making sure everything is running
    33  	// correctly.
    34  	//
    35  	// DebugLevel logs are helpful for diagnosing and troubleshooting to
    36  	// people more than just developers (e.g. IT, system admins, etc.).
    37  	DebugLevel
    38  
    39  	// InfoLevel logs are generally useful information which indicate that
    40  	// something happened, the application entered a certain state, etc.
    41  	// For example, a controller of your authorization API may write a
    42  	// message at InfoLevel with information on which user requested
    43  	// authorization if the authorization was successful or not.
    44  	//
    45  	// The information logged at InfoLevel should be purely informative
    46  	// that you don't need to care about under normal circumstances, and
    47  	// not looking into them on a regular basis shouldn't result in missing
    48  	// any important information.
    49  	//
    50  	// This should be the out-of-box level for most applications in
    51  	// service production deployment or application release configuration.
    52  	InfoLevel
    53  
    54  	// NoticeLevel logs are important information which should be always
    55  	// available and shall not be turned off, user should be aware of these
    56  	// events when they look into the system or application.
    57  	// (Such as service start/stop/restart, reconnecting to database, switching
    58  	// from a primary server to a backup server, retrying an operation, etc.)
    59  	//
    60  	// NoticeLevel is not implemented currently.
    61  	NoticeLevel
    62  
    63  	// WarnLevel logs indicate that something unexpected happened in the
    64  	// system or application, a problem, or a situation that might
    65  	// potentially cause application oddities, but the code can continue
    66  	// to work. For example, unexpected disconnection from server, being
    67  	// close to quota, suspicious web attach, temporarily heartbeat missing,
    68  	// or a parsing error that resulted in a certain document not being
    69  	// correctly processed.
    70  	//
    71  	// Warning messages may need human review, but generally that don't need
    72  	// immediately intervention.
    73  	WarnLevel
    74  
    75  	// ErrorLevel logs indicate that the application hit issues preventing
    76  	// one or more functionalities from properly functioning, they may be
    77  	// fatal to an operation, but not fatal to the entire service or
    78  	// application (e.g. can't open a required file, missing data,
    79  	// temporarily failure from database or downstream service, etc.),
    80  	// the application should continue running.
    81  	//
    82  	// These messages definitely need investigation and intervention from
    83  	// user (developer, system administrator, or direct user), continuous
    84  	// errors may cause serious problems, (e.g. service outage, lost of
    85  	// income, or customer complaints, etc.).
    86  	ErrorLevel
    87  
    88  	// CriticalLevel logs indicate that the system or application encountered
    89  	// critical condition preventing it to function properly, the system
    90  	// or application is in a very unhealthy state.
    91  	//
    92  	// Intervention actions must be taken immediately, which means you should
    93  	// go to get a system administrator or developer out of bed quickly.
    94  	//
    95  	// CriticalLevel is not implemented currently.
    96  	CriticalLevel
    97  
    98  	// DPanicLevel logs are particularly important errors.
    99  	// In development mode the logger panics after writing the message.
   100  	DPanicLevel
   101  
   102  	// PanicLevel logs indicate that the application encountered unrecoverable
   103  	// errors that it should abort immediately.
   104  	//
   105  	// The logger writes the message, then panics the application.
   106  	PanicLevel
   107  
   108  	// FatalLevel logs indicate that the application encountered unrecoverable
   109  	// errors that it should abort immediately.
   110  	//
   111  	// The logger writes the message, then calls os.Exit to abort the application.
   112  	FatalLevel
   113  )
   114  
   115  const (
   116  	TracePrefix    = "[TRACE] "
   117  	DebugPrefix    = "[DEBUG] "
   118  	InfoPrefix     = "[INFO] "
   119  	NoticePrefix   = "[NOTICE] "
   120  	WarnPrefix     = "[WARN] "
   121  	ErrorPrefix    = "[ERROR] "
   122  	CriticalPrefix = "[CRITICAL] "
   123  	PanicPrefix    = "[PANIC] "
   124  	FatalPrefix    = "[FATAL] "
   125  )
   126  
   127  const levelPrefixMinLen = 6
   128  
   129  var mapZapLevels = [...]zapcore.Level{
   130  	zap.InfoLevel,
   131  	zap.InfoLevel,
   132  	zap.WarnLevel,
   133  	zap.ErrorLevel,
   134  	zap.ErrorLevel,
   135  	zap.DPanicLevel,
   136  	zap.PanicLevel,
   137  	zap.FatalLevel,
   138  }
   139  
   140  func (l Level) toZapLevel() zapcore.Level {
   141  	if l < 0 {
   142  		return zapcore.Level(l)
   143  	}
   144  	return mapZapLevels[l]
   145  }
   146  
   147  func (l Level) String() string {
   148  	switch l {
   149  	case TraceLevel:
   150  		return "trace"
   151  	case DebugLevel:
   152  		return "debug"
   153  	case InfoLevel:
   154  		return "info"
   155  	case NoticeLevel:
   156  		return "notice"
   157  	case WarnLevel:
   158  		return "warn"
   159  	case ErrorLevel:
   160  		return "error"
   161  	case CriticalLevel:
   162  		return "critical"
   163  	case DPanicLevel:
   164  		return "dpanic"
   165  	case PanicLevel:
   166  		return "panic"
   167  	case FatalLevel:
   168  		return "fatal"
   169  	default:
   170  		return strconv.FormatInt(int64(l), 10)
   171  	}
   172  }
   173  
   174  func (l Level) CapitalString() string {
   175  	switch l {
   176  	case TraceLevel:
   177  		return "TRACE"
   178  	case DebugLevel:
   179  		return "DEBUG"
   180  	case InfoLevel:
   181  		return "INFO"
   182  	case NoticeLevel:
   183  		return "NOTICE"
   184  	case WarnLevel:
   185  		return "WARN"
   186  	case ErrorLevel:
   187  		return "ERROR"
   188  	case CriticalLevel:
   189  		return "CRITICAL"
   190  	case DPanicLevel:
   191  		return "DPANIC"
   192  	case PanicLevel:
   193  		return "PANIC"
   194  	case FatalLevel:
   195  		return "FATAL"
   196  	default:
   197  		return strconv.FormatInt(int64(l), 10)
   198  	}
   199  }
   200  
   201  func (l Level) Enabled(lvl zapcore.Level) bool {
   202  	return lvl >= l.toZapLevel()
   203  }
   204  
   205  func (l *Level) unmarshalText(text []byte) bool {
   206  	switch string(text) {
   207  	case "trace", "TRACE":
   208  		*l = TraceLevel
   209  	case "debug", "DEBUG":
   210  		*l = DebugLevel
   211  	case "info", "INFO":
   212  		*l = InfoLevel
   213  	case "notice", "NOTICE":
   214  		*l = NoticeLevel
   215  	case "warn", "warning", "WARN", "WARNING":
   216  		*l = WarnLevel
   217  	case "error", "ERROR":
   218  		*l = ErrorLevel
   219  	case "critical", "CRITICAL":
   220  		*l = CriticalLevel
   221  	case "dpanic", "DPANIC":
   222  		*l = DPanicLevel
   223  	case "panic", "PANIC":
   224  		*l = PanicLevel
   225  	case "fatal", "FATAL":
   226  		*l = FatalLevel
   227  	default:
   228  		return false
   229  	}
   230  	return true
   231  }
   232  
   233  type atomicLevel struct {
   234  	lvl *atomic.Int32
   235  	zl  zap.AtomicLevel
   236  }
   237  
   238  func newAtomicLevel() atomicLevel {
   239  	return atomicLevel{
   240  		lvl: atomic.NewInt32(int32(InfoLevel)),
   241  		zl:  zap.NewAtomicLevel(),
   242  	}
   243  }
   244  
   245  func (l atomicLevel) Level() Level { return Level(l.lvl.Load()) }
   246  
   247  func (l *atomicLevel) SetLevel(lvl Level) {
   248  	l.lvl.Store(int32(lvl))
   249  	l.zl.SetLevel(lvl.toZapLevel())
   250  }
   251  
   252  func (l *atomicLevel) UnmarshalText(text []byte) error {
   253  	var _lvl Level
   254  	if !_lvl.unmarshalText(text) {
   255  		return fmt.Errorf("unrecognized level: %s", text)
   256  	}
   257  	l.SetLevel(_lvl)
   258  	return nil
   259  }
   260  
   261  func fromZapLevel(lvl zapcore.Level) Level {
   262  	switch lvl {
   263  	case zapcore.DebugLevel:
   264  		return DebugLevel
   265  	case zapcore.InfoLevel:
   266  		return InfoLevel
   267  	case zapcore.WarnLevel:
   268  		return WarnLevel
   269  	case zapcore.ErrorLevel:
   270  		return ErrorLevel
   271  	case zapcore.DPanicLevel:
   272  		return DPanicLevel
   273  	case zap.PanicLevel:
   274  		return PanicLevel
   275  	case zap.FatalLevel:
   276  		return FatalLevel
   277  	}
   278  	if lvl < zapcore.DebugLevel {
   279  		return TraceLevel
   280  	}
   281  	return FatalLevel
   282  }
   283  
   284  func detectLevel(message string) (Level, bool) {
   285  	switch message[1] {
   286  	case 'T':
   287  		if strings.HasPrefix(message, TracePrefix) {
   288  			return TraceLevel, true
   289  		}
   290  	case 'D':
   291  		if strings.HasPrefix(message, DebugPrefix) {
   292  			return DebugLevel, true
   293  		}
   294  	case 'I':
   295  		if strings.HasPrefix(message, InfoPrefix) {
   296  			return InfoLevel, true
   297  		}
   298  	case 'N':
   299  		if strings.HasPrefix(message, NoticePrefix) {
   300  			return NoticeLevel, true
   301  		}
   302  	case 'W':
   303  		if strings.HasPrefix(message, WarnPrefix) {
   304  			return WarnLevel, true
   305  		}
   306  	case 'E':
   307  		if strings.HasPrefix(message, ErrorPrefix) {
   308  			return ErrorLevel, true
   309  		}
   310  	case 'C':
   311  		if strings.HasPrefix(message, CriticalPrefix) {
   312  			return CriticalLevel, true
   313  		}
   314  	case 'P':
   315  		if strings.HasPrefix(message, PanicPrefix) {
   316  			return PanicLevel, true
   317  		}
   318  	case 'F':
   319  		if strings.HasPrefix(message, FatalPrefix) {
   320  			return FatalLevel, true
   321  		}
   322  	}
   323  	return 0, false
   324  }