...

Source file src/gitlab.com/tymonx/go-logger/logger/logger.go

Documentation: gitlab.com/tymonx/go-logger/logger

     1  // Copyright 2020 Tymoteusz Blazejczyk
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package logger
    16  
    17  import (
    18  	"os"
    19  	"runtime"
    20  	"sync"
    21  	"time"
    22  )
    23  
    24  // These constants define log level values and names used by various logger
    25  // functions like for example Debug or Info. It defines also default logger
    26  // values.
    27  const (
    28  	OffsetLevel = 10
    29  
    30  	TraceLevel    = 0
    31  	DebugLevel    = OffsetLevel + TraceLevel
    32  	InfoLevel     = OffsetLevel + DebugLevel
    33  	NoticeLevel   = OffsetLevel + InfoLevel
    34  	WarningLevel  = OffsetLevel + NoticeLevel
    35  	ErrorLevel    = OffsetLevel + WarningLevel
    36  	CriticalLevel = OffsetLevel + ErrorLevel
    37  	AlertLevel    = OffsetLevel + CriticalLevel
    38  	FatalLevel    = OffsetLevel + AlertLevel
    39  	PanicLevel    = OffsetLevel + FatalLevel
    40  
    41  	MinimumLevel = TraceLevel
    42  	MaximumLevel = PanicLevel
    43  
    44  	TraceName    = "trace"
    45  	DebugName    = "debug"
    46  	InfoName     = "info"
    47  	NoticeName   = "notice"
    48  	WarningName  = "warning"
    49  	ErrorName    = "error"
    50  	CriticalName = "critical"
    51  	AlertName    = "alert"
    52  	FatalName    = "fatal"
    53  	PanicName    = "panic"
    54  
    55  	DefaultTypeName = "log"
    56  
    57  	DefaultErrorCode = 1
    58  
    59  	loggerSkipCall = 2
    60  )
    61  
    62  // A Logger represents an active logging object that generates log messages for
    63  // different added log handlers. Each logging operations creates and sends
    64  // lightweight not formatted log message to separate worker thread. It offloads
    65  // main code from unnecessary resource consuming formatting and I/O operations.
    66  type Logger struct {
    67  	name        string
    68  	handlers    Handlers
    69  	idGenerator IDGenerator
    70  	errorCode   int
    71  	mutex       sync.RWMutex
    72  }
    73  
    74  // New creates new logger instance with default handlers.
    75  func New() *Logger {
    76  	return &Logger{
    77  		handlers: Handlers{
    78  			"stdout": NewStdout(),
    79  			"stderr": NewStderr(),
    80  		},
    81  		errorCode:   DefaultErrorCode,
    82  		idGenerator: NewUUID4(),
    83  	}
    84  }
    85  
    86  // Enable enables all added log handlers.
    87  func (l *Logger) Enable() *Logger {
    88  	l.mutex.Lock()
    89  	defer l.mutex.Unlock()
    90  
    91  	for _, handler := range l.handlers {
    92  		handler.Enable()
    93  	}
    94  
    95  	return l
    96  }
    97  
    98  // Disable disabled all added log handlers.
    99  func (l *Logger) Disable() *Logger {
   100  	l.mutex.Lock()
   101  	defer l.mutex.Unlock()
   102  
   103  	for _, handler := range l.handlers {
   104  		handler.Disable()
   105  	}
   106  
   107  	return l
   108  }
   109  
   110  // IsEnabled returns true if at least one of added log handlers is enabled.
   111  func (l *Logger) IsEnabled() bool {
   112  	l.mutex.RLock()
   113  	defer l.mutex.RUnlock()
   114  
   115  	for _, handler := range l.handlers {
   116  		if handler.IsEnabled() {
   117  			return true
   118  		}
   119  	}
   120  
   121  	return false
   122  }
   123  
   124  // SetLevel sets log level to all added log handlers.
   125  func (l *Logger) SetLevel(level int) *Logger {
   126  	l.mutex.Lock()
   127  	defer l.mutex.Unlock()
   128  
   129  	for _, handler := range l.handlers {
   130  		handler.SetLevel(level)
   131  	}
   132  
   133  	return l
   134  }
   135  
   136  // SetMinimumLevel sets minimum log level to all added log handlers.
   137  func (l *Logger) SetMinimumLevel(level int) *Logger {
   138  	l.mutex.Lock()
   139  	defer l.mutex.Unlock()
   140  
   141  	for _, handler := range l.handlers {
   142  		handler.SetMinimumLevel(level)
   143  	}
   144  
   145  	return l
   146  }
   147  
   148  // SetMaximumLevel sets maximum log level to all added log handlers.
   149  func (l *Logger) SetMaximumLevel(level int) *Logger {
   150  	l.mutex.Lock()
   151  	defer l.mutex.Unlock()
   152  
   153  	for _, handler := range l.handlers {
   154  		handler.SetMaximumLevel(level)
   155  	}
   156  
   157  	return l
   158  }
   159  
   160  // SetLevelRange sets minimum and maximum log level values to all added log handlers.
   161  func (l *Logger) SetLevelRange(min, max int) *Logger {
   162  	l.mutex.Lock()
   163  	defer l.mutex.Unlock()
   164  
   165  	for _, handler := range l.handlers {
   166  		handler.SetLevelRange(min, max)
   167  	}
   168  
   169  	return l
   170  }
   171  
   172  // SetFormatter sets provided formatter to all added log handlers.
   173  func (l *Logger) SetFormatter(formatter *Formatter) *Logger {
   174  	l.mutex.Lock()
   175  	defer l.mutex.Unlock()
   176  
   177  	for _, handler := range l.handlers {
   178  		handler.SetFormatter(formatter)
   179  	}
   180  
   181  	return l
   182  }
   183  
   184  // SetFormat sets provided format string to all added log handlers.
   185  func (l *Logger) SetFormat(format string) *Logger {
   186  	l.mutex.Lock()
   187  	defer l.mutex.Unlock()
   188  
   189  	for _, handler := range l.handlers {
   190  		handler.GetFormatter().SetFormat(format)
   191  	}
   192  
   193  	return l
   194  }
   195  
   196  // SetDateFormat sets provided date format string to all added log handlers.
   197  func (l *Logger) SetDateFormat(format string) *Logger {
   198  	l.mutex.Lock()
   199  	defer l.mutex.Unlock()
   200  
   201  	for _, handler := range l.handlers {
   202  		handler.GetFormatter().SetDateFormat(format)
   203  	}
   204  
   205  	return l
   206  }
   207  
   208  // SetPlaceholder sets provided placeholder string to all added log handlers.
   209  func (l *Logger) SetPlaceholder(placeholder string) *Logger {
   210  	l.mutex.Lock()
   211  	defer l.mutex.Unlock()
   212  
   213  	for _, handler := range l.handlers {
   214  		handler.GetFormatter().SetPlaceholder(placeholder)
   215  	}
   216  
   217  	return l
   218  }
   219  
   220  // AddFuncs adds template functions to format log message to all added log handlers.
   221  func (l *Logger) AddFuncs(funcs FormatterFuncs) *Logger {
   222  	l.mutex.Lock()
   223  	defer l.mutex.Unlock()
   224  
   225  	for _, handler := range l.handlers {
   226  		handler.GetFormatter().AddFuncs(funcs)
   227  	}
   228  
   229  	return l
   230  }
   231  
   232  // ResetFormatters resets all formatters from added log handlers.
   233  func (l *Logger) ResetFormatters() *Logger {
   234  	l.mutex.Lock()
   235  	defer l.mutex.Unlock()
   236  
   237  	for _, handler := range l.handlers {
   238  		handler.GetFormatter().Reset()
   239  	}
   240  
   241  	return l
   242  }
   243  
   244  // SetErrorCode sets error code that is returned during Fatal call.
   245  // On default it is 1.
   246  func (l *Logger) SetErrorCode(errorCode int) *Logger {
   247  	l.mutex.Lock()
   248  	defer l.mutex.Unlock()
   249  
   250  	l.errorCode = errorCode
   251  
   252  	return l
   253  }
   254  
   255  // GetErrorCode returns error code.
   256  func (l *Logger) GetErrorCode() int {
   257  	l.mutex.RLock()
   258  	defer l.mutex.RUnlock()
   259  
   260  	return l.errorCode
   261  }
   262  
   263  // SetName sets logger name.
   264  func (l *Logger) SetName(name string) *Logger {
   265  	l.mutex.Lock()
   266  	defer l.mutex.Unlock()
   267  
   268  	l.name = name
   269  
   270  	return l
   271  }
   272  
   273  // GetName returns logger name.
   274  func (l *Logger) GetName() string {
   275  	l.mutex.RLock()
   276  	defer l.mutex.RUnlock()
   277  
   278  	return l.name
   279  }
   280  
   281  // AddHandler sets log handler under provided identifier name.
   282  func (l *Logger) AddHandler(name string, handler Handler) *Logger {
   283  	l.mutex.Lock()
   284  	defer l.mutex.Unlock()
   285  
   286  	l.handlers[name] = handler
   287  
   288  	return l
   289  }
   290  
   291  // SetHandler sets a single log handler for logger. It is equivalent to
   292  // logger.RemoveHandlers().SetHandlers(logger.Handlers{name: handler}).
   293  func (l *Logger) SetHandler(name string, handler Handler) *Logger {
   294  	l.mutex.Lock()
   295  	defer l.mutex.Unlock()
   296  
   297  	l.handlers = Handlers{name: handler}
   298  
   299  	return l
   300  }
   301  
   302  // SetHandlers sets log handlers for logger.
   303  func (l *Logger) SetHandlers(handlers Handlers) *Logger {
   304  	l.mutex.Lock()
   305  	defer l.mutex.Unlock()
   306  
   307  	l.handlers = handlers
   308  
   309  	return l
   310  }
   311  
   312  // GetHandler returns added log handler by provided name.
   313  func (l *Logger) GetHandler(name string) (Handler, error) {
   314  	l.mutex.RLock()
   315  	defer l.mutex.RUnlock()
   316  
   317  	handler, ok := l.handlers[name]
   318  
   319  	if !ok {
   320  		return nil, NewRuntimeError("cannot get handler", name)
   321  	}
   322  
   323  	return handler, nil
   324  }
   325  
   326  // GetHandlers returns all added log handlers.
   327  func (l *Logger) GetHandlers() Handlers {
   328  	l.mutex.RLock()
   329  	defer l.mutex.RUnlock()
   330  
   331  	return l.handlers
   332  }
   333  
   334  // RemoveHandler removes added log handler by provided name.
   335  func (l *Logger) RemoveHandler(name string) *Logger {
   336  	l.mutex.Lock()
   337  	defer l.mutex.Unlock()
   338  
   339  	delete(l.handlers, name)
   340  
   341  	return l
   342  }
   343  
   344  // RemoveHandlers removes all added log handlers.
   345  func (l *Logger) RemoveHandlers() *Logger {
   346  	l.mutex.Lock()
   347  	defer l.mutex.Unlock()
   348  
   349  	l.handlers = make(Handlers)
   350  
   351  	return l
   352  }
   353  
   354  // ResetHandlers sets logger default log handlers.
   355  func (l *Logger) ResetHandlers() *Logger {
   356  	l.mutex.Lock()
   357  	defer l.mutex.Unlock()
   358  
   359  	l.handlers = Handlers{
   360  		"stdout": NewStdout(),
   361  		"stderr": NewStderr(),
   362  	}
   363  
   364  	return l
   365  }
   366  
   367  // Reset resets logger to default state and default log handlers.
   368  func (l *Logger) Reset() *Logger {
   369  	l.mutex.Lock()
   370  	defer l.mutex.Unlock()
   371  
   372  	l.idGenerator = NewUUID4()
   373  	l.errorCode = DefaultErrorCode
   374  	l.handlers = Handlers{
   375  		"stdout": NewStdout(),
   376  		"stderr": NewStderr(),
   377  	}
   378  
   379  	return l
   380  }
   381  
   382  // SetIDGenerator sets ID generator function that is called by logger to
   383  // generate ID for created log messages.
   384  func (l *Logger) SetIDGenerator(idGenerator IDGenerator) *Logger {
   385  	l.mutex.Lock()
   386  	defer l.mutex.Unlock()
   387  
   388  	l.idGenerator = idGenerator
   389  
   390  	return l
   391  }
   392  
   393  // GetIDGenerator returns ID generator function that is called by logger to
   394  // generate ID for created log messages.
   395  func (l *Logger) GetIDGenerator() IDGenerator {
   396  	l.mutex.RLock()
   397  	defer l.mutex.RUnlock()
   398  
   399  	return l.idGenerator
   400  }
   401  
   402  // Trace logs finer-grained informational messages than the Debug. It creates
   403  // and sends lightweight not formatted log messages to separate running logger
   404  // thread for further formatting and I/O handling from different added log
   405  // handlers.
   406  func (l *Logger) Trace(message string, arguments ...interface{}) {
   407  	l.LogMessage(TraceLevel, TraceName, message, arguments...)
   408  }
   409  
   410  // Debug logs debugging messages. It creates and sends lightweight not formatted
   411  // log messages to separate running logger thread for further formatting and
   412  // I/O handling from different added log handlers.
   413  func (l *Logger) Debug(message string, arguments ...interface{}) {
   414  	l.LogMessage(DebugLevel, DebugName, message, arguments...)
   415  }
   416  
   417  // Info logs informational messages. It creates and sends lightweight not
   418  // formatted log messages to separate running logger thread for further
   419  // formatting and I/O handling from different added log handlers.
   420  func (l *Logger) Info(message string, arguments ...interface{}) {
   421  	l.LogMessage(InfoLevel, InfoName, message, arguments...)
   422  }
   423  
   424  // Notice logs messages for significant conditions. It creates and sends
   425  // lightweight not formatted log messages to separate running logger thread for
   426  // further formatting and I/O handling from different added log handlers.
   427  func (l *Logger) Notice(message string, arguments ...interface{}) {
   428  	l.LogMessage(NoticeLevel, NoticeName, message, arguments...)
   429  }
   430  
   431  // Warning logs messages for warning conditions that can be potentially harmful.
   432  // It creates and sends lightweight not formatted log messages to separate
   433  // running logger thread for further formatting and I/O handling from different
   434  // added log handlers.
   435  func (l *Logger) Warning(message string, arguments ...interface{}) {
   436  	l.LogMessage(WarningLevel, WarningName, message, arguments...)
   437  }
   438  
   439  // Error logs messages for error conditions. It creates and sends lightweight
   440  // not formatted log messages to separate running logger thread for further
   441  // formatting and I/O handling from different log handlers.
   442  func (l *Logger) Error(message string, arguments ...interface{}) {
   443  	l.LogMessage(ErrorLevel, ErrorName, message, arguments...)
   444  }
   445  
   446  // Critical logs messages for critical conditions. It creates and sends
   447  // lightweight not formatted log messages to separate running logger thread for
   448  // further formatting and I/O handling from different added log handlers.
   449  func (l *Logger) Critical(message string, arguments ...interface{}) {
   450  	l.LogMessage(CriticalLevel, CriticalName, message, arguments...)
   451  }
   452  
   453  // Alert logs messages for alert conditions. It creates and sends lightweight
   454  // not formatted log messages to separate running logger thread for further
   455  // formatting and I/O handling from different added log handlers.
   456  func (l *Logger) Alert(message string, arguments ...interface{}) {
   457  	l.LogMessage(AlertLevel, AlertName, message, arguments...)
   458  }
   459  
   460  // Fatal logs messages for fatal conditions. It stops logger worker thread and
   461  // it exists the application with an error code. It creates and sends
   462  // lightweight not formatted log messages to separate running logger thread for
   463  // further formatting and I/O handling from different added log handlers.
   464  func (l *Logger) Fatal(message string, arguments ...interface{}) {
   465  	l.LogMessage(FatalLevel, FatalName, message, arguments...)
   466  	Close()
   467  	os.Exit(l.errorCode) // revive:disable-line
   468  }
   469  
   470  // Panic logs messages for fatal conditions. It stops logger worker thread and
   471  // it exists the application with a panic. It creates and sends lightweight not
   472  // formatted log messages to separate running logger thread for further
   473  // formatting and I/O handling from different added log handlers.
   474  func (l *Logger) Panic(message string, arguments ...interface{}) {
   475  	l.LogMessage(PanicLevel, PanicName, message, arguments...)
   476  	Close()
   477  	panic(NewRuntimeError("Panic error"))
   478  }
   479  
   480  // Log logs messages with user defined log level value and name. It creates and
   481  // sends lightweight not formatted log messages to separate running logger
   482  // thread for further formatting and I/O handling from different added log
   483  // handlers.
   484  func (l *Logger) Log(level int, levelName, message string, arguments ...interface{}) {
   485  	l.LogMessage(level, levelName, message, arguments...)
   486  }
   487  
   488  // Flush flushes all log messages.
   489  func (l *Logger) Flush() *Logger {
   490  	GetWorker().Flush()
   491  
   492  	return l
   493  }
   494  
   495  // Close closes all added log handlers.
   496  func (l *Logger) Close() error {
   497  	GetWorker().Flush()
   498  
   499  	l.mutex.Lock()
   500  	defer l.mutex.Unlock()
   501  
   502  	var err error
   503  
   504  	for _, handler := range l.handlers {
   505  		handlerError := handler.Close()
   506  
   507  		if handlerError != nil {
   508  			err = NewRuntimeError("cannot close log handler", handlerError)
   509  			printError(err)
   510  		}
   511  	}
   512  
   513  	return err
   514  }
   515  
   516  // CloseDefer is a small helper function that invokes the .Close() method
   517  // and it does an error checking with logging. Useful when using with
   518  // the defer keyword to avoid creating an anonymous function wrapper only
   519  // to check for an error manually and passing the errcheck linter.
   520  func (l *Logger) CloseDefer() {
   521  	if err := l.Close(); err != nil {
   522  		printError(NewRuntimeError("cannot close logger", err))
   523  	}
   524  }
   525  
   526  // LogMessage logs message with defined log level value and name. It creates and
   527  // sends lightweight not formatted log messages to separate running logger
   528  // thread for further formatting and I/O handling from different added log
   529  // handlers. Use this method in custom log wrapper methods.
   530  func (l *Logger) LogMessage(level int, levelName, message string, arguments ...interface{}) {
   531  	now := time.Now()
   532  
   533  	pc, path, line, _ := runtime.Caller(loggerSkipCall)
   534  
   535  	GetWorker().records <- &Record{
   536  		Time:      now,
   537  		Message:   message,
   538  		Arguments: arguments,
   539  		Level: Level{
   540  			Name:  levelName,
   541  			Value: level,
   542  		},
   543  		File: Source{
   544  			Line:     line,
   545  			Path:     path,
   546  			Function: runtime.FuncForPC(pc).Name(),
   547  		},
   548  		logger: l,
   549  	}
   550  }
   551  
   552  // Emit emits provided log record to logger worker thread for further
   553  // formatting and I/O handling from different addded log handlers.
   554  func (l *Logger) Emit(record *Record) *Logger {
   555  	record.logger = l
   556  	GetWorker().records <- record
   557  
   558  	return l
   559  }
   560  

View as plain text