go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/logger/cliwriter.go (about)

     1  // Copyright (c) Mondoo, Inc.
     2  // SPDX-License-Identifier: BUSL-1.1
     3  
     4  package logger
     5  
     6  import (
     7  	"fmt"
     8  	"github.com/muesli/termenv"
     9  	"go.mondoo.com/cnquery/cli/theme/colors"
    10  	"io"
    11  	"os"
    12  	"runtime"
    13  	"strings"
    14  
    15  	"github.com/rs/zerolog"
    16  	"github.com/rs/zerolog/log"
    17  )
    18  
    19  func NewConsoleWriter(out io.Writer, compact bool) zerolog.Logger {
    20  	w := zerolog.ConsoleWriter{Out: out}
    21  	// zerolog's own color output implementation does not work on Windows, therefore we re-implement all
    22  	// colored methods here
    23  	// TODO: its unclear why but the first 3 messages are outputted wrongly on windows
    24  	// therefore we disable the colors for the indicators for now
    25  
    26  	if compact && runtime.GOOS != "windows" {
    27  		w.FormatLevel = consoleFormatLevel()
    28  	} else if compact {
    29  		w.FormatLevel = consoleFormatLevelNoColor()
    30  	}
    31  
    32  	w.FormatFieldName = consoleDefaultFormatFieldName()
    33  	w.FormatFieldValue = consoleDefaultFormatFieldValue
    34  	w.FormatErrFieldName = consoleDefaultFormatErrFieldName()
    35  	w.FormatErrFieldValue = consoleDefaultFormatErrFieldValue()
    36  	w.FormatCaller = consoleDefaultFormatCaller()
    37  	w.FormatMessage = consoleDefaultFormatMessage
    38  	w.FormatTimestamp = func(i interface{}) string { return "" }
    39  
    40  	return log.Output(w)
    41  }
    42  
    43  func consoleDefaultFormatCaller() zerolog.Formatter {
    44  	return func(i interface{}) string {
    45  		var c string
    46  		if cc, ok := i.(string); ok {
    47  			c = cc
    48  		}
    49  		if len(c) > 0 {
    50  			cwd, err := os.Getwd()
    51  			if err == nil {
    52  				c = strings.TrimPrefix(c, cwd)
    53  				c = strings.TrimPrefix(c, "/")
    54  			}
    55  		}
    56  		return c
    57  	}
    58  }
    59  
    60  func consoleDefaultFormatMessage(i interface{}) string {
    61  	if i == nil {
    62  		return ""
    63  	}
    64  	return fmt.Sprintf("%s", i)
    65  }
    66  
    67  func consoleDefaultFormatFieldName() zerolog.Formatter {
    68  	return func(i interface{}) string {
    69  		return termenv.String(fmt.Sprintf("%s=", i)).Foreground(colors.DefaultColorTheme.Primary).String()
    70  	}
    71  }
    72  
    73  func consoleDefaultFormatFieldValue(i interface{}) string {
    74  	return fmt.Sprintf("%s", i)
    75  }
    76  
    77  func consoleDefaultFormatErrFieldName() zerolog.Formatter {
    78  	return func(i interface{}) string {
    79  		return termenv.String(fmt.Sprintf("%s=", i)).Foreground(colors.DefaultColorTheme.Error).String()
    80  	}
    81  }
    82  
    83  func consoleDefaultFormatErrFieldValue() zerolog.Formatter {
    84  	return func(i interface{}) string {
    85  		return termenv.String(fmt.Sprintf("%s", i)).Foreground(colors.DefaultColorTheme.Error).String()
    86  	}
    87  }
    88  
    89  // consoleFormatLevelNoColor returns a formatter that outputs the level in uppercase without any color
    90  // this is used for compact mode and primarily for windows which has a restricted color palette and character set
    91  // for the console
    92  func consoleFormatLevelNoColor() zerolog.Formatter {
    93  	return func(i interface{}) string {
    94  		var l string
    95  
    96  		if ll, ok := i.(string); ok {
    97  			switch ll {
    98  			case "trace":
    99  				l = "TRC"
   100  			case "debug":
   101  				l = "DBG"
   102  			case "info":
   103  				l = "-"
   104  			case "warn":
   105  				l = "WRN"
   106  			case "error":
   107  				l = "ERR"
   108  			case "fatal":
   109  				l = "FTL"
   110  			case "panic":
   111  				l = "PNC"
   112  			default:
   113  				l = "UNK"
   114  			}
   115  		} else {
   116  			if i == nil {
   117  				l = "UNK"
   118  			} else {
   119  				l = strings.ToUpper(fmt.Sprintf("%s", i))[0:3]
   120  			}
   121  		}
   122  
   123  		return l
   124  	}
   125  }
   126  
   127  func consoleFormatLevel() zerolog.Formatter {
   128  	return func(i interface{}) string {
   129  		var l string
   130  		var color termenv.Color
   131  
   132  		// set no color as default
   133  		color = termenv.NoColor{}
   134  
   135  		if ll, ok := i.(string); ok {
   136  			switch ll {
   137  			case "trace":
   138  				l = "TRC"
   139  				color = colors.DefaultColorTheme.Secondary
   140  			case "debug":
   141  				l = "DBG"
   142  				color = colors.DefaultColorTheme.Primary
   143  			case "info":
   144  				l = "→"
   145  				color = colors.DefaultColorTheme.Good
   146  			case "warn":
   147  				l = "!"
   148  				color = colors.DefaultColorTheme.Medium
   149  			case "error":
   150  				l = "x"
   151  				color = colors.DefaultColorTheme.Error
   152  			case "fatal":
   153  				l = "FTL"
   154  				color = colors.DefaultColorTheme.Error
   155  			case "panic":
   156  				l = "PNC"
   157  				color = colors.DefaultColorTheme.Error
   158  			default:
   159  				l = "???"
   160  			}
   161  		} else {
   162  			if i == nil {
   163  				l = "???"
   164  			} else {
   165  				l = strings.ToUpper(fmt.Sprintf("%s", i))[0:3]
   166  			}
   167  		}
   168  
   169  		return termenv.String(l).Foreground(color).String()
   170  	}
   171  }