github.com/qlik-oss/gopherciser@v0.18.6/logger/entry.go (about)

     1  package logger
     2  
     3  import (
     4  	"fmt"
     5  	"strconv"
     6  	"sync"
     7  	"time"
     8  
     9  	"github.com/qlik-oss/gopherciser/atomichandlers"
    10  	"github.com/qlik-oss/gopherciser/helpers"
    11  )
    12  
    13  type (
    14  	// SessionEntry log fields living of entire session
    15  	SessionEntry struct {
    16  		User        string
    17  		Thread      uint64
    18  		Session     uint64
    19  		SessionName string
    20  		AppName     string
    21  		AppGUID     string
    22  	}
    23  
    24  	// ActionEntry log fields living during action
    25  	ActionEntry struct {
    26  		Action     string
    27  		Label      string
    28  		ActionID   uint64
    29  		ObjectType string
    30  	}
    31  
    32  	// EphemeralEntry log fields living during log entry only
    33  	ephemeralEntry struct {
    34  		ResponseTime int64
    35  		Success      bool
    36  		Warnings     uint64
    37  		Errors       uint64
    38  		Stack        error
    39  		Sent         uint64
    40  		Received     uint64
    41  		Details      string
    42  		InfoType     string
    43  		RequestsSent uint64
    44  	}
    45  
    46  	//LogEntry entry used for logging
    47  	LogEntry struct {
    48  		logger  *Log
    49  		Session *SessionEntry
    50  		Action  *ActionEntry
    51  		// logging interceptor return false to break.
    52  		interceptors map[LogLevel]func(msg *LogEntry) bool
    53  		mu           sync.Mutex
    54  	}
    55  )
    56  
    57  var tickCounter = atomichandlers.AtomicCounter{}
    58  
    59  // NewLogEntry new instance of LogEntry
    60  func NewLogEntry(log *Log) *LogEntry {
    61  	return &LogEntry{
    62  		logger: log,
    63  	}
    64  }
    65  
    66  // ShallowCopy log entry, creates new log entry with pointers to exact same data, but with a new mutex
    67  func (entry *LogEntry) ShallowCopy() *LogEntry {
    68  	newLogEntry := NewLogEntry(entry.logger)
    69  	newLogEntry.interceptors = entry.interceptors
    70  	return newLogEntry
    71  }
    72  
    73  // Logf write formatted log entry to log
    74  func (entry *LogEntry) Logf(level LogLevel, format string, args ...interface{}) {
    75  	if entry == nil {
    76  		return
    77  	}
    78  
    79  	entry.log(level, fmt.Sprintf(format, args...), nil)
    80  }
    81  
    82  // Log write log entry to log
    83  func (entry *LogEntry) Log(level LogLevel, args ...interface{}) {
    84  	if entry == nil {
    85  		return
    86  	}
    87  
    88  	entry.log(level, fmt.Sprint(args...), nil)
    89  }
    90  
    91  // LogTrafficMetric log traffic metric entry
    92  func (entry *LogEntry) LogTrafficMetric(responseTime int64, sent, received uint64, requestID int, method, params, trafficType, msg string) {
    93  	if entry == nil || entry.logger == nil || !entry.logger.Settings.Metrics {
    94  		return
    95  	}
    96  
    97  	separator := rune('\u001e') // 30 is RS (Record Separator)
    98  	var reqIDString string
    99  
   100  	if requestID != -1 {
   101  		reqIDString = strconv.Itoa(requestID)
   102  	}
   103  
   104  	buf := helpers.NewBuffer()
   105  	buf.WriteString(trafficType)
   106  	buf.WriteRune(separator)
   107  	buf.WriteString(reqIDString)
   108  	buf.WriteRune(separator)
   109  	buf.WriteString(method)
   110  	buf.WriteRune(separator)
   111  	buf.WriteString(params)
   112  
   113  	var details string
   114  	if buf.Error == nil {
   115  		details = buf.String()
   116  	}
   117  
   118  	entry.log(MetricsLevel, msg, &ephemeralEntry{
   119  		ResponseTime: responseTime,
   120  		Sent:         sent,
   121  		Received:     received,
   122  		Details:      details,
   123  	})
   124  }
   125  
   126  // LogDetail log message with detail
   127  func (entry *LogEntry) LogDetail(level LogLevel, msg, detail string) {
   128  	if entry == nil {
   129  		return
   130  	}
   131  
   132  	entry.log(level, msg, &ephemeralEntry{
   133  		Details: detail,
   134  	})
   135  }
   136  
   137  // LogResult log result entry
   138  func (entry *LogEntry) LogResult(success bool, warnings, errors, sent, received, requests uint64, responsetime int64, details string) {
   139  	if entry == nil {
   140  		return
   141  	}
   142  
   143  	entry.log(ResultLevel, "", &ephemeralEntry{
   144  		Success:      success,
   145  		Warnings:     warnings,
   146  		Errors:       errors,
   147  		Sent:         sent,
   148  		Received:     received,
   149  		RequestsSent: requests,
   150  		ResponseTime: responsetime,
   151  		Details:      details,
   152  	})
   153  }
   154  
   155  // LogInfo log info entry
   156  func (entry *LogEntry) LogInfo(infoType, msg string) {
   157  	if entry == nil {
   158  		return
   159  	}
   160  
   161  	entry.log(InfoLevel, msg, &ephemeralEntry{
   162  		InfoType: infoType,
   163  	})
   164  }
   165  
   166  // LogErrorReport log warning and error count
   167  func (entry *LogEntry) LogErrorReport(reportType string, errors, warnings uint64) {
   168  	if entry == nil {
   169  		return
   170  	}
   171  
   172  	entry.Action = nil
   173  	entry.log(InfoLevel, fmt.Sprintf("%d", errors+warnings), &ephemeralEntry{
   174  		InfoType: reportType,
   175  		Errors:   errors,
   176  		Warnings: warnings,
   177  	})
   178  }
   179  
   180  // LogError log error entry
   181  func (entry *LogEntry) LogError(err error) {
   182  	if entry == nil {
   183  		return
   184  	}
   185  
   186  	entry.log(ErrorLevel, fmt.Sprintf("%s", err), &ephemeralEntry{
   187  		Stack: err,
   188  	})
   189  }
   190  
   191  // LogErrorWithMsg log error entry with message
   192  func (entry *LogEntry) LogErrorWithMsg(msg string, err error) {
   193  	if entry == nil {
   194  		return
   195  	}
   196  	entry.log(ErrorLevel, msg, &ephemeralEntry{
   197  		Stack: err,
   198  	})
   199  }
   200  
   201  // LogDebug log debug entry with message
   202  func (entry *LogEntry) LogDebug(msg string) {
   203  	if !entry.ShouldLogDebug() {
   204  		return
   205  	}
   206  	entry.log(DebugLevel, msg, nil)
   207  }
   208  
   209  // LogDebugf log debug entry with message
   210  func (entry *LogEntry) LogDebugf(format string, args ...interface{}) {
   211  	if !entry.ShouldLogDebug() {
   212  		return
   213  	}
   214  	entry.log(DebugLevel, fmt.Sprintf(format, args...), nil)
   215  }
   216  
   217  func (entry *LogEntry) LogRegression(id string, data interface{}, meta map[string]interface{}) error {
   218  	return entry.logger.regressionLogger.Log(id, data, meta)
   219  }
   220  
   221  func (entry *LogEntry) log(level LogLevel, msg string, eph *ephemeralEntry) {
   222  	if entry == nil {
   223  		return
   224  	}
   225  
   226  	entry.mu.Lock()
   227  	defer entry.mu.Unlock()
   228  
   229  	m := message{
   230  		Level:   level,
   231  		Time:    time.Now(),
   232  		Message: msg,
   233  		Tick:    tickCounter.Inc(),
   234  	}
   235  
   236  	var s SessionEntry
   237  	if entry.Session != nil {
   238  		s = *entry.Session
   239  	} else {
   240  		s = SessionEntry{}
   241  	}
   242  
   243  	var a ActionEntry
   244  	if entry.Action != nil {
   245  		a = *entry.Action
   246  	} else {
   247  		a = ActionEntry{}
   248  	}
   249  
   250  	if eph == nil {
   251  		eph = &ephemeralEntry{}
   252  	}
   253  
   254  	chanMsg := &LogChanMsg{m, s, a, eph}
   255  
   256  	if entry.interceptors[level] != nil {
   257  		if !entry.interceptors[level](entry) {
   258  			return
   259  		}
   260  	}
   261  
   262  	go entry.queueWrite(chanMsg)
   263  }
   264  
   265  func (entry *LogEntry) queueWrite(msg *LogChanMsg) {
   266  	if entry == nil || entry.logger == nil {
   267  		return
   268  	}
   269  
   270  	entry.logger.logChan <- msg
   271  }
   272  
   273  // SetSessionEntry set new session entry
   274  func (entry *LogEntry) SetSessionEntry(s *SessionEntry) {
   275  	if entry == nil {
   276  		return
   277  	}
   278  
   279  	entry.mu.Lock()
   280  	defer entry.mu.Unlock()
   281  
   282  	entry.Session = s
   283  }
   284  
   285  // SetActionEntry set new session entry
   286  func (entry *LogEntry) SetActionEntry(a *ActionEntry) {
   287  	if entry == nil {
   288  		return
   289  	}
   290  
   291  	entry.mu.Lock()
   292  	defer entry.mu.Unlock()
   293  
   294  	entry.Action = a
   295  }
   296  
   297  // AddInterceptor to log entry, return false to avoid logging
   298  func (entry *LogEntry) AddInterceptor(level LogLevel, f func(msg *LogEntry) bool) {
   299  	if entry == nil {
   300  		return
   301  	}
   302  
   303  	if entry.interceptors == nil {
   304  		entry.interceptors = make(map[LogLevel]func(msg *LogEntry) bool)
   305  	}
   306  
   307  	entry.interceptors[level] = f
   308  }
   309  
   310  // ShouldLogTraffic should traffic be logged
   311  func (entry *LogEntry) ShouldLogTraffic() bool {
   312  	if entry == nil || entry.logger == nil {
   313  		return false
   314  	}
   315  	return entry.logger.Settings.Traffic
   316  }
   317  
   318  // ShouldLogTrafficMetrics should traffic metrics be logged
   319  func (entry *LogEntry) ShouldLogTrafficMetrics() bool {
   320  	if entry == nil || entry.logger == nil {
   321  		return false
   322  	}
   323  	return entry.logger.Settings.Metrics
   324  }
   325  
   326  // ShouldLogDebug should debug info be logged
   327  func (entry *LogEntry) ShouldLogDebug() bool {
   328  	if entry == nil || entry.logger == nil {
   329  		return false
   330  	}
   331  	return entry.logger.Settings.Debug
   332  }
   333  
   334  // ShouldLogRegression should regression data be logged
   335  func (entry *LogEntry) ShouldLogRegression() bool {
   336  	return entry != nil && entry.logger != nil && entry.logger.Settings.Regression
   337  }