fortio.org/log@v1.12.2/console_logging.go (about)

     1  // Copyright 2023 Fortio Authors
     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 log
    16  
    17  import (
    18  	"fmt"
    19  	"os"
    20  	"time"
    21  
    22  	"fortio.org/log/goroutine"
    23  )
    24  
    25  // to avoid making a new package/namespace for colors, we use a struct.
    26  type color struct {
    27  	Reset     string
    28  	Red       string
    29  	Green     string
    30  	Yellow    string
    31  	Blue      string
    32  	Purple    string
    33  	Cyan      string
    34  	Gray      string
    35  	White     string
    36  	BrightRed string
    37  	DarkGray  string
    38  }
    39  
    40  var (
    41  	// these should really be constants but go doesn't have constant structs, arrays etc...
    42  
    43  	// ANSI color codes.
    44  	// This isn't meant to be used directly and is here only to document the names of the struct.
    45  	// Use the Colors variable instead.
    46  	ANSIColors = color{
    47  		Reset:     "\033[0m",
    48  		Red:       "\033[31m",
    49  		Green:     "\033[32m",
    50  		Yellow:    "\033[33m",
    51  		Blue:      "\033[34m",
    52  		Purple:    "\033[35m",
    53  		Cyan:      "\033[36m",
    54  		Gray:      "\033[37m",
    55  		White:     "\033[97m",
    56  		BrightRed: "\033[91m",
    57  		DarkGray:  "\033[90m",
    58  	}
    59  
    60  	// ANSI color codes or empty depending on ColorMode.
    61  	// These will be reset to empty string if color is disabled (see ColorMode() and SetColorMode()).
    62  	// Start with actual colors, will be reset to empty if color is disabled.
    63  	Colors = ANSIColors
    64  
    65  	// Mapping of log levels to color.
    66  	LevelToColor = []string{
    67  		Colors.Gray,
    68  		Colors.Cyan,
    69  		Colors.Green,
    70  		Colors.Yellow,
    71  		Colors.Red,
    72  		Colors.Purple,
    73  		Colors.BrightRed,
    74  		Colors.Green, // NoLevel log.Printf
    75  	}
    76  	// Used for color version of console logging.
    77  	LevelToText = []string{
    78  		"DBG",
    79  		"VRB",
    80  		"INF",
    81  		"WRN",
    82  		"ERR",
    83  		"CRI",
    84  		"FTL",
    85  		"",
    86  	}
    87  	// Cached flag for whether to use color output or not.
    88  	Color = false
    89  )
    90  
    91  // ConsoleLogging is a utility to check if the current logger output is a console (terminal).
    92  func ConsoleLogging() bool {
    93  	f, ok := jWriter.w.(*os.File)
    94  	if !ok {
    95  		return false
    96  	}
    97  	s, _ := f.Stat()
    98  	return (s.Mode() & os.ModeCharDevice) == os.ModeCharDevice
    99  }
   100  
   101  // SetColorMode computes whether we currently should be using color text mode or not.
   102  // Need to be reset if config changes (but is already automatically re evaluated when calling SetOutput()).
   103  // It will reset the Colors variable to either be the actual escape sequences or empty strings (when
   104  // color is disabled).
   105  func SetColorMode() {
   106  	Color = ColorMode()
   107  	if Color {
   108  		Colors = ANSIColors
   109  	} else {
   110  		Colors = color{}
   111  	}
   112  	// Also reset the level to color mapping to empty or customized colors, as needed.
   113  	LevelToColor = []string{
   114  		Colors.Gray,
   115  		Colors.Cyan,
   116  		Colors.Green,
   117  		Colors.Yellow,
   118  		Colors.Red,
   119  		Colors.Purple,
   120  		Colors.BrightRed,
   121  		Colors.Green, // NoLevel log.Printf
   122  	}
   123  }
   124  
   125  // ColorMode returns true if we should be using color text mode, which is either because it's
   126  // forced or because we are in a console and the config allows it.
   127  // Should not be called often, instead read/update the Color variable when needed.
   128  func ColorMode() bool {
   129  	return Config.ForceColor || (Config.ConsoleColor && ConsoleLogging())
   130  }
   131  
   132  func colorTimestamp() string {
   133  	if Config.NoTimestamp {
   134  		return ""
   135  	}
   136  	return time.Now().Format(Colors.DarkGray + "15:04:05.000 ")
   137  }
   138  
   139  // Color version of jsonGID().
   140  func colorGID() string {
   141  	if !Config.GoroutineID {
   142  		return ""
   143  	}
   144  	return Colors.Gray + fmt.Sprintf("r%d ", goroutine.ID())
   145  }
   146  
   147  // Longer version when colorizing on console of the level text.
   148  func ColorLevelToStr(lvl Level) string {
   149  	if lvl == NoLevel {
   150  		return Colors.DarkGray
   151  	}
   152  	return Colors.DarkGray + "[" + LevelToColor[lvl] + LevelToText[lvl] + Colors.DarkGray + "]"
   153  }