github.com/minio/minio@v0.0.0-20240328213742-3f72439b8a27/internal/logger/console.go (about)

     1  // Copyright (c) 2015-2021 MinIO, Inc.
     2  //
     3  // This file is part of MinIO Object Storage stack
     4  //
     5  // This program is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Affero General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // This program is distributed in the hope that it will be useful
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  // GNU Affero General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Affero General Public License
    16  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17  
    18  package logger
    19  
    20  import (
    21  	"encoding/json"
    22  	"fmt"
    23  	"os"
    24  	"strings"
    25  	"time"
    26  
    27  	"github.com/minio/minio/internal/color"
    28  	c "github.com/minio/pkg/v2/console"
    29  	"github.com/minio/pkg/v2/logger/message/log"
    30  )
    31  
    32  // ConsoleLoggerTgt is a stringified value to represent console logging
    33  const ConsoleLoggerTgt = "console+http"
    34  
    35  // ExitFunc is called by Fatal() class functions, by default it calls os.Exit()
    36  var ExitFunc = os.Exit
    37  
    38  // Logger interface describes the methods that need to be implemented to satisfy the interface requirements.
    39  type Logger interface {
    40  	json(msg string, args ...interface{})
    41  	quiet(msg string, args ...interface{})
    42  	pretty(msg string, args ...interface{})
    43  }
    44  
    45  func consoleLog(console Logger, msg string, args ...interface{}) {
    46  	switch {
    47  	case jsonFlag:
    48  		// Strip escape control characters from json message
    49  		msg = ansiRE.ReplaceAllLiteralString(msg, "")
    50  		console.json(msg, args...)
    51  	case quietFlag:
    52  		if len(msg) != 0 && len(args) == 0 {
    53  			args = append(args, msg)
    54  			msg = "%s"
    55  		}
    56  		console.quiet(msg+"\n", args...)
    57  	default:
    58  		if len(msg) != 0 && len(args) == 0 {
    59  			args = append(args, msg)
    60  			msg = "%s"
    61  		}
    62  		console.pretty(msg+"\n", args...)
    63  	}
    64  }
    65  
    66  // Fatal prints only fatal error message with no stack trace
    67  // it will be called for input validation failures
    68  func Fatal(err error, msg string, data ...interface{}) {
    69  	fatal(err, msg, data...)
    70  }
    71  
    72  func fatal(err error, msg string, data ...interface{}) {
    73  	var errMsg string
    74  	if msg != "" {
    75  		errMsg = errorFmtFunc(fmt.Sprintf(msg, data...), err, jsonFlag)
    76  	} else {
    77  		errMsg = err.Error()
    78  	}
    79  	consoleLog(fatalMessage, errMsg)
    80  }
    81  
    82  var fatalMessage fatalMsg
    83  
    84  type fatalMsg struct{}
    85  
    86  func (f fatalMsg) json(msg string, args ...interface{}) {
    87  	var message string
    88  	if msg != "" {
    89  		message = fmt.Sprintf(msg, args...)
    90  	} else {
    91  		message = fmt.Sprint(args...)
    92  	}
    93  	logJSON, err := json.Marshal(&log.Entry{
    94  		Level:   FatalKind,
    95  		Message: message,
    96  		Time:    time.Now().UTC(),
    97  		Trace:   &log.Trace{Message: message, Source: []string{getSource(6)}},
    98  	})
    99  	if err != nil {
   100  		panic(err)
   101  	}
   102  	fmt.Println(string(logJSON))
   103  
   104  	ExitFunc(1)
   105  }
   106  
   107  func (f fatalMsg) quiet(msg string, args ...interface{}) {
   108  	f.pretty(msg, args...)
   109  }
   110  
   111  var (
   112  	logTag      = "ERROR"
   113  	logBanner   = color.BgRed(color.FgWhite(color.Bold(logTag))) + " "
   114  	emptyBanner = color.BgRed(strings.Repeat(" ", len(logTag))) + " "
   115  	bannerWidth = len(logTag) + 1
   116  )
   117  
   118  func (f fatalMsg) pretty(msg string, args ...interface{}) {
   119  	// Build the passed error message
   120  	errMsg := fmt.Sprintf(msg, args...)
   121  
   122  	tagPrinted := false
   123  
   124  	// Print the error message: the following code takes care
   125  	// of splitting error text and always pretty printing the
   126  	// red banner along with the error message. Since the error
   127  	// message itself contains some colored text, we needed
   128  	// to use some ANSI control escapes to cursor color state
   129  	// and freely move in the screen.
   130  	for _, line := range strings.Split(errMsg, "\n") {
   131  		if len(line) == 0 {
   132  			// No more text to print, just quit.
   133  			break
   134  		}
   135  
   136  		for {
   137  			// Save the attributes of the current cursor helps
   138  			// us save the text color of the passed error message
   139  			ansiSaveAttributes()
   140  			// Print banner with or without the log tag
   141  			if !tagPrinted {
   142  				c.Print(logBanner)
   143  				tagPrinted = true
   144  			} else {
   145  				c.Print(emptyBanner)
   146  			}
   147  			// Restore the text color of the error message
   148  			ansiRestoreAttributes()
   149  			ansiMoveRight(bannerWidth)
   150  			// Continue  error message printing
   151  			c.Println(line)
   152  			break
   153  		}
   154  	}
   155  
   156  	// Exit because this is a fatal error message
   157  	ExitFunc(1)
   158  }
   159  
   160  type infoMsg struct{}
   161  
   162  var info infoMsg
   163  
   164  func (i infoMsg) json(msg string, args ...interface{}) {
   165  	var message string
   166  	if msg != "" {
   167  		message = fmt.Sprintf(msg, args...)
   168  	} else {
   169  		message = fmt.Sprint(args...)
   170  	}
   171  	logJSON, err := json.Marshal(&log.Entry{
   172  		Level:   InfoKind,
   173  		Message: message,
   174  		Time:    time.Now().UTC(),
   175  	})
   176  	if err != nil {
   177  		panic(err)
   178  	}
   179  	fmt.Println(string(logJSON))
   180  }
   181  
   182  func (i infoMsg) quiet(msg string, args ...interface{}) {
   183  }
   184  
   185  func (i infoMsg) pretty(msg string, args ...interface{}) {
   186  	if msg == "" {
   187  		c.Println(args...)
   188  	}
   189  	c.Printf(msg, args...)
   190  }
   191  
   192  type errorMsg struct{}
   193  
   194  var errorm errorMsg
   195  
   196  func (i errorMsg) json(msg string, args ...interface{}) {
   197  	var message string
   198  	if msg != "" {
   199  		message = fmt.Sprintf(msg, args...)
   200  	} else {
   201  		message = fmt.Sprint(args...)
   202  	}
   203  	logJSON, err := json.Marshal(&log.Entry{
   204  		Level:   ErrorKind,
   205  		Message: message,
   206  		Time:    time.Now().UTC(),
   207  		Trace:   &log.Trace{Message: message, Source: []string{getSource(6)}},
   208  	})
   209  	if err != nil {
   210  		panic(err)
   211  	}
   212  	fmt.Println(string(logJSON))
   213  }
   214  
   215  func (i errorMsg) quiet(msg string, args ...interface{}) {
   216  	i.pretty(msg, args...)
   217  }
   218  
   219  func (i errorMsg) pretty(msg string, args ...interface{}) {
   220  	if msg == "" {
   221  		c.Println(args...)
   222  	}
   223  	c.Printf(msg, args...)
   224  }
   225  
   226  // Error :
   227  func Error(msg string, data ...interface{}) {
   228  	if DisableErrorLog {
   229  		return
   230  	}
   231  	consoleLog(errorm, msg, data...)
   232  }
   233  
   234  // Info :
   235  func Info(msg string, data ...interface{}) {
   236  	if DisableErrorLog {
   237  		return
   238  	}
   239  	consoleLog(info, msg, data...)
   240  }