github.com/polarismesh/polaris@v1.17.8/common/log/scope.go (about)

     1  /**
     2   * Tencent is pleased to support the open source community by making Polaris available.
     3   *
     4   * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
     5   *
     6   * Licensed under the BSD 3-Clause License (the "License");
     7   * you may not use this file except in compliance with the License.
     8   * You may obtain a copy of the License at
     9   *
    10   * https://opensource.org/licenses/BSD-3-Clause
    11   *
    12   * Unless required by applicable law or agreed to in writing, software distributed
    13   * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
    14   * CONDITIONS OF ANY KIND, either express or implied. See the License for the
    15   * specific language governing permissions and limitations under the License.
    16   */
    17  
    18  package log
    19  
    20  import (
    21  	"fmt"
    22  	"runtime"
    23  	"strings"
    24  	"sync"
    25  	"time"
    26  
    27  	"go.uber.org/zap"
    28  	"go.uber.org/zap/zapcore"
    29  )
    30  
    31  // Scope let's you log data for an area of code, enabling the user full control over
    32  // the level of logging output produced.
    33  type Scope struct {
    34  	// immutable, set at creation
    35  	name        string
    36  	nameToEmit  string
    37  	description string
    38  	callerSkip  int
    39  
    40  	// set by the Configure method and adjustable dynamically
    41  	outputLevel     Level
    42  	stackTraceLevel Level
    43  	logCallers      bool
    44  	pt              *patchTable
    45  }
    46  
    47  var (
    48  	scopes = map[string]*Scope{}
    49  	lock   sync.RWMutex
    50  )
    51  
    52  // RegisterScope registers a new logging scope. If the same name is used multiple times
    53  // for a single process, the same Scope struct is returned.
    54  //
    55  // Scope names cannot include colons, commas, or periods.
    56  func RegisterScope(name string, description string, callerSkip int) *Scope {
    57  	if strings.ContainsAny(name, ":,.") {
    58  		panic(fmt.Sprintf("scope name %s is invalid, it cannot contain colons, commas, or periods", name))
    59  	}
    60  
    61  	lock.Lock()
    62  	defer lock.Unlock()
    63  
    64  	s, ok := scopes[name]
    65  	if !ok {
    66  		s = &Scope{
    67  			name:        name,
    68  			description: description,
    69  			callerSkip:  callerSkip,
    70  		}
    71  		s.SetOutputLevel(InfoLevel)
    72  		s.SetStackTraceLevel(NoneLevel)
    73  		s.SetDisableLogCaller(true)
    74  		if name != DefaultLoggerName {
    75  			s.nameToEmit = name
    76  		}
    77  
    78  		scopes[name] = s
    79  	}
    80  
    81  	return s
    82  }
    83  
    84  // FindScope returns a previously registered scope, or nil if the named scope wasn't previously registered
    85  func FindScope(scope string) *Scope {
    86  	lock.RLock()
    87  	defer lock.RUnlock()
    88  
    89  	s := scopes[scope]
    90  	return s
    91  }
    92  
    93  func GetScopeOrDefaultByName(name string) *Scope {
    94  	lock.RLock()
    95  	defer lock.RUnlock()
    96  	s := scopes[name]
    97  	if s == nil {
    98  		s = scopes[DefaultLoggerName]
    99  	}
   100  	return s
   101  }
   102  
   103  func GetScopeByName(name, defaultName string) *Scope {
   104  	lock.RLock()
   105  	defer lock.RUnlock()
   106  	s := scopes[name]
   107  	if s == nil {
   108  		s = scopes[defaultName]
   109  		if s == nil {
   110  			s = scopes[DefaultLoggerName]
   111  		}
   112  	}
   113  	return s
   114  }
   115  
   116  // Scopes returns a snapshot of the currently defined set of scopes
   117  func Scopes() map[string]*Scope {
   118  	lock.RLock()
   119  	defer lock.RUnlock()
   120  
   121  	s := make(map[string]*Scope, len(scopes))
   122  	for k, v := range scopes {
   123  		s[k] = v
   124  	}
   125  
   126  	return s
   127  }
   128  
   129  // Fatal outputs a message at fatal level.
   130  func (s *Scope) Fatal(msg string, fields ...zapcore.Field) {
   131  	if s.GetOutputLevel() >= FatalLevel {
   132  		s.emit(zapcore.FatalLevel, s.GetStackTraceLevel() >= FatalLevel, msg, fields)
   133  	}
   134  }
   135  
   136  // Fatala uses fmt.Sprint to construct and log a message at fatal level.
   137  func (s *Scope) Fatala(args ...interface{}) {
   138  	if s.GetOutputLevel() >= FatalLevel {
   139  		s.emit(zapcore.FatalLevel, s.GetStackTraceLevel() >= FatalLevel, fmt.Sprint(args...), nil)
   140  	}
   141  }
   142  
   143  // Fatalf uses fmt.Sprintf to construct and log a message at fatal level.
   144  func (s *Scope) Fatalf(template string, args ...interface{}) {
   145  	if s.GetOutputLevel() >= FatalLevel {
   146  		msg := template
   147  		if len(args) > 0 {
   148  			msg = fmt.Sprintf(template, args...)
   149  		}
   150  		s.emit(zapcore.FatalLevel, s.GetStackTraceLevel() >= FatalLevel, msg, nil)
   151  	}
   152  }
   153  
   154  // FatalEnabled returns whether output of messages using this scope is currently enabled for fatal-level output.
   155  func (s *Scope) FatalEnabled() bool {
   156  	return s.GetOutputLevel() >= FatalLevel
   157  }
   158  
   159  // Error outputs a message at error level.
   160  func (s *Scope) Error(msg string, fields ...zapcore.Field) {
   161  	if s.GetOutputLevel() >= ErrorLevel {
   162  		s.emit(zapcore.ErrorLevel, s.GetStackTraceLevel() >= ErrorLevel, msg, fields)
   163  	}
   164  }
   165  
   166  // Errora uses fmt.Sprint to construct and log a message at error level.
   167  func (s *Scope) Errora(args ...interface{}) {
   168  	if s.GetOutputLevel() >= ErrorLevel {
   169  		s.emit(zapcore.ErrorLevel, s.GetStackTraceLevel() >= ErrorLevel, fmt.Sprint(args...), nil)
   170  	}
   171  }
   172  
   173  // Errorf uses fmt.Sprintf to construct and log a message at error level.
   174  func (s *Scope) Errorf(template string, args ...interface{}) {
   175  	if s.GetOutputLevel() >= ErrorLevel {
   176  		msg := template
   177  		if len(args) > 0 {
   178  			msg = fmt.Sprintf(template, args...)
   179  		}
   180  		s.emit(zapcore.ErrorLevel, s.GetStackTraceLevel() >= ErrorLevel, msg, nil)
   181  	}
   182  }
   183  
   184  // ErrorEnabled returns whether output of messages using this scope is currently enabled for error-level output.
   185  func (s *Scope) ErrorEnabled() bool {
   186  	return s.GetOutputLevel() >= ErrorLevel
   187  }
   188  
   189  // Warn outputs a message at warn level.
   190  func (s *Scope) Warn(msg string, fields ...zapcore.Field) {
   191  	if s.GetOutputLevel() >= WarnLevel {
   192  		s.emit(zapcore.WarnLevel, s.GetStackTraceLevel() >= ErrorLevel, msg, fields)
   193  	}
   194  }
   195  
   196  // Warna uses fmt.Sprint to construct and log a message at warn level.
   197  func (s *Scope) Warna(args ...interface{}) {
   198  	if s.GetOutputLevel() >= WarnLevel {
   199  		s.emit(zapcore.WarnLevel, s.GetStackTraceLevel() >= ErrorLevel, fmt.Sprint(args...), nil)
   200  	}
   201  }
   202  
   203  // Warnf uses fmt.Sprintf to construct and log a message at warn level.
   204  func (s *Scope) Warnf(template string, args ...interface{}) {
   205  	if s.GetOutputLevel() >= WarnLevel {
   206  		msg := template
   207  		if len(args) > 0 {
   208  			msg = fmt.Sprintf(template, args...)
   209  		}
   210  		s.emit(zapcore.WarnLevel, s.GetStackTraceLevel() >= ErrorLevel, msg, nil)
   211  	}
   212  }
   213  
   214  // WarnEnabled returns whether output of messages using this scope is currently enabled for warn-level output.
   215  func (s *Scope) WarnEnabled() bool {
   216  	return s.GetOutputLevel() >= WarnLevel
   217  }
   218  
   219  // Info outputs a message at info level.
   220  func (s *Scope) Info(msg string, fields ...zapcore.Field) {
   221  	if s.GetOutputLevel() >= InfoLevel {
   222  		s.emit(zapcore.InfoLevel, s.GetStackTraceLevel() >= ErrorLevel, msg, fields)
   223  	}
   224  }
   225  
   226  // Infoa uses fmt.Sprint to construct and log a message at info level.
   227  func (s *Scope) Infoa(args ...interface{}) {
   228  	if s.GetOutputLevel() >= InfoLevel {
   229  		s.emit(zapcore.InfoLevel, s.GetStackTraceLevel() >= ErrorLevel, fmt.Sprint(args...), nil)
   230  	}
   231  }
   232  
   233  // Infof uses fmt.Sprintf to construct and log a message at info level.
   234  func (s *Scope) Infof(template string, args ...interface{}) {
   235  	if s.GetOutputLevel() >= InfoLevel {
   236  		msg := template
   237  		if len(args) > 0 {
   238  			msg = fmt.Sprintf(template, args...)
   239  		}
   240  		s.emit(zapcore.InfoLevel, s.GetStackTraceLevel() >= ErrorLevel, msg, nil)
   241  	}
   242  }
   243  
   244  // InfoEnabled returns whether output of messages using this scope is currently enabled for info-level output.
   245  func (s *Scope) InfoEnabled() bool {
   246  	return s.GetOutputLevel() >= InfoLevel
   247  }
   248  
   249  // Debug outputs a message at debug level.
   250  func (s *Scope) Debug(msg string, fields ...zapcore.Field) {
   251  	if s.GetOutputLevel() >= DebugLevel {
   252  		s.emit(zapcore.DebugLevel, s.GetStackTraceLevel() >= ErrorLevel, msg, fields)
   253  	}
   254  }
   255  
   256  // Debuga uses fmt.Sprint to construct and log a message at debug level.
   257  func (s *Scope) Debuga(args ...interface{}) {
   258  	if s.GetOutputLevel() >= DebugLevel {
   259  		s.emit(zapcore.DebugLevel, s.GetStackTraceLevel() >= ErrorLevel, fmt.Sprint(args...), nil)
   260  	}
   261  }
   262  
   263  // Debugf uses fmt.Sprintf to construct and log a message at debug level.
   264  func (s *Scope) Debugf(template string, args ...interface{}) {
   265  	if s.GetOutputLevel() >= DebugLevel {
   266  		msg := template
   267  		if len(args) > 0 {
   268  			msg = fmt.Sprintf(template, args...)
   269  		}
   270  		s.emit(zapcore.DebugLevel, s.GetStackTraceLevel() >= ErrorLevel, msg, nil)
   271  	}
   272  }
   273  
   274  // DebugEnabled returns whether output of messages using this scope is currently enabled for debug-level output.
   275  func (s *Scope) DebugEnabled() bool {
   276  	return s.GetOutputLevel() >= DebugLevel
   277  }
   278  
   279  // Name returns this scope's name.
   280  func (s *Scope) Name() string {
   281  	return s.name
   282  }
   283  
   284  // Description returns this scope's description
   285  func (s *Scope) Description() string {
   286  	return s.description
   287  }
   288  
   289  func (s *Scope) getPathTable() *patchTable {
   290  	return s.pt
   291  }
   292  
   293  const callerSkipOffset = 2
   294  
   295  func (s *Scope) emit(level zapcore.Level, dumpStack bool, msg string, fields []zapcore.Field) {
   296  	e := zapcore.Entry{
   297  		Message:    msg,
   298  		Level:      level,
   299  		Time:       time.Now(),
   300  		LoggerName: s.nameToEmit,
   301  	}
   302  
   303  	if !s.GetDisableLogCaller() {
   304  		e.Caller = zapcore.NewEntryCaller(runtime.Caller(s.callerSkip + callerSkipOffset))
   305  	}
   306  
   307  	if dumpStack {
   308  		e.Stack = zap.Stack("").String
   309  	}
   310  
   311  	pt := s.getPathTable()
   312  	if pt != nil && pt.write != nil {
   313  		if err := pt.write(e, fields); err != nil {
   314  			_, _ = fmt.Fprintf(pt.errorSink, "%v log write error: %v\n", time.Now(), err)
   315  			_ = pt.errorSink.Sync()
   316  		}
   317  	}
   318  }
   319  
   320  // SetOutputLevel adjusts the output level associated with the scope.
   321  func (s *Scope) SetOutputLevel(l Level) {
   322  	s.outputLevel = l
   323  }
   324  
   325  // GetOutputLevel returns the output level associated with the scope.
   326  func (s *Scope) GetOutputLevel() Level {
   327  	return s.outputLevel
   328  }
   329  
   330  // SetStackTraceLevel adjusts the stack tracing level associated with the scope.
   331  func (s *Scope) SetStackTraceLevel(l Level) {
   332  	s.stackTraceLevel = l
   333  }
   334  
   335  // GetStackTraceLevel returns the stack tracing level associated with the scope.
   336  func (s *Scope) GetStackTraceLevel() Level {
   337  	return s.stackTraceLevel
   338  }
   339  
   340  // SetDisableLogCaller adjusts the output level associated with the scope.
   341  func (s *Scope) SetDisableLogCaller(logCallers bool) {
   342  	s.logCallers = logCallers
   343  }
   344  
   345  // GetDisableLogCaller returns the output level associated with the scope.
   346  func (s *Scope) GetDisableLogCaller() bool {
   347  	return s.logCallers
   348  }
   349  
   350  // Sync 调用log的Sync方法
   351  func (s *Scope) Sync() error {
   352  	pt := s.getPathTable()
   353  	if pt != nil && pt.sync != nil {
   354  		return pt.sync()
   355  	}
   356  	return nil
   357  }