github.com/TrueBlocks/trueblocks-core/src/apps/chifra@v0.0.0-20241022031540-b362680128f7/pkg/logger/logger.go (about)

     1  // Copyright 2021 The TrueBlocks Authors. All rights reserved.
     2  // Use of this source code is governed by a license that can
     3  // be found in the LICENSE file.
     4  
     5  package logger
     6  
     7  import (
     8  	"fmt"
     9  	"io"
    10  	"math"
    11  	"os"
    12  	"strings"
    13  	"time"
    14  
    15  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/colors"
    16  	"golang.org/x/term"
    17  )
    18  
    19  type severity int
    20  
    21  const (
    22  	progress severity = iota
    23  	infoC             // colored table
    24  	info
    25  	test
    26  	warning
    27  	err
    28  )
    29  
    30  var severityToLabel = map[severity]string{
    31  	progress: "PROG",
    32  	infoC:    "INFO",
    33  	info:     "INFO",
    34  	test:     "TEST",
    35  	warning:  "WARN",
    36  	err:      "EROR",
    37  }
    38  
    39  var (
    40  	testModeSet = false
    41  	testMode    = false
    42  )
    43  
    44  func SetTestMode(onOff bool) {
    45  	testMode = onOff
    46  	testModeSet = true
    47  }
    48  
    49  // TestLog is used to print log lines during testing only
    50  func TestLog(notDefault bool, a ...interface{}) {
    51  	if !testModeSet {
    52  		testModeSet = true
    53  		testMode = os.Getenv("TEST_MODE") == "true"
    54  	}
    55  
    56  	if !testMode {
    57  		return
    58  	}
    59  
    60  	if notDefault {
    61  		toLog(test, a...)
    62  	}
    63  }
    64  
    65  var (
    66  	isTestMode    = false
    67  	timingModeSet = false
    68  	timingMode    = true
    69  	decorationOff = false
    70  )
    71  
    72  func LogTimerOn() bool {
    73  	return timingMode
    74  }
    75  
    76  func ToggleDecoration() {
    77  	decorationOff = !decorationOff
    78  }
    79  
    80  var loggerWriter io.Writer = nil
    81  
    82  func init() {
    83  	if !timingModeSet {
    84  		on := os.Getenv("TB_LOGTIMER_OFF") == ""
    85  		isTestMode = os.Getenv("TEST_MODE") == "true"
    86  		timingMode = on && !isTestMode
    87  		timingModeSet = true
    88  	}
    89  	loggerWriter = os.Stderr
    90  }
    91  
    92  // SetLoggerWriter sets the writer to which log messages are written. Do not send
    93  // nil as a writer if you wish to disable logging. Instead, use
    94  //
    95  //	w := logger.GetLoggerWriter()
    96  //	defer logger.SetLoggerWriter(w)
    97  //	logger.SetLoggerWriter(io.Discard)
    98  //
    99  // Setting to `nil` will core dump.
   100  func SetLoggerWriter(w io.Writer) {
   101  	loggerWriter = w
   102  }
   103  
   104  func GetLoggerWriter() io.Writer {
   105  	return loggerWriter
   106  }
   107  
   108  // toLog prints `a` to stderr with a label corresponding to the severity level
   109  // prepended (e.g. <INFO>, <EROR>, etc.)
   110  func toLog(sev severity, a ...interface{}) {
   111  	if loggerWriter == nil {
   112  		return
   113  	}
   114  
   115  	timeDatePart := "DATE|TIME"
   116  	if timingMode {
   117  		now := time.Now()
   118  		timeDatePart = now.Format("02-01|15:04:05.000")
   119  	}
   120  
   121  	if !decorationOff {
   122  		fmt.Fprintf(loggerWriter, "%s[%s] ", severityToLabel[sev], timeDatePart)
   123  	}
   124  	if sev == progress {
   125  		for index, aa := range a {
   126  			if index > 0 {
   127  				fmt.Fprint(loggerWriter, " ")
   128  			}
   129  			fmt.Fprint(loggerWriter, aa)
   130  		}
   131  		fmt.Fprint(loggerWriter, "\r")
   132  
   133  	} else if sev == infoC {
   134  		fmt.Fprintf(loggerWriter, "%s%s%s ", colors.Green, a[0], colors.Off)
   135  		for _, aa := range a[1:] {
   136  			fmt.Fprintf(loggerWriter, "%s", aa)
   137  		}
   138  		fmt.Fprintln(loggerWriter, "")
   139  
   140  	} else if sev == warning {
   141  		defer fmt.Fprint(loggerWriter, colors.Off)
   142  		fmt.Fprint(loggerWriter, colors.Yellow)
   143  		fmt.Fprintln(loggerWriter, a...)
   144  
   145  	} else if sev == err {
   146  		defer fmt.Fprint(loggerWriter, colors.Off)
   147  		fmt.Fprint(loggerWriter, colors.Red)
   148  		fmt.Fprintln(loggerWriter, a...)
   149  
   150  	} else {
   151  		fmt.Fprintln(loggerWriter, a...)
   152  	}
   153  }
   154  
   155  func InfoTable(v ...any) {
   156  	toLog(infoC, v...)
   157  }
   158  
   159  func Info(v ...any) {
   160  	toLog(info, v...)
   161  }
   162  
   163  func Warn(v ...any) {
   164  	toLog(warning, v...)
   165  }
   166  
   167  func Error(v ...any) {
   168  	toLog(err, v...)
   169  }
   170  
   171  func Fatal(v ...any) {
   172  	toLog(err, v...)
   173  	os.Exit(1)
   174  }
   175  
   176  func Panic(v ...any) {
   177  	s := fmt.Sprint(v...)
   178  	toLog(err, s)
   179  	panic(s)
   180  }
   181  
   182  func CleanLine() {
   183  	// \033[K is escape sequence meaning "erase to end of line"
   184  	fmt.Print("\r\033[K")
   185  }
   186  
   187  func PctProgress(done int32, total int, tick int32) {
   188  	if done%tick != 0 {
   189  		return
   190  	}
   191  
   192  	percentage := math.Round(float64(done) / float64(total) * 100)
   193  	toLog(progress, fmt.Sprintf("\r\t\t\t Processing: %.f%% (%d of %d)%s", percentage, done, total, strings.Repeat(" ", 40)))
   194  }
   195  
   196  func Progress(tick bool, v ...any) {
   197  	if isTestMode || !tick {
   198  		return
   199  	}
   200  	toLog(progress, v...)
   201  }
   202  
   203  func IsTerminal() bool {
   204  	return term.IsTerminal(int(os.Stdout.Fd()))
   205  }