github.com/sagernet/sing-box@v1.2.7/log/format.go (about)

     1  package log
     2  
     3  import (
     4  	"context"
     5  	"strconv"
     6  	"strings"
     7  	"time"
     8  
     9  	F "github.com/sagernet/sing/common/format"
    10  
    11  	"github.com/logrusorgru/aurora"
    12  )
    13  
    14  type Formatter struct {
    15  	BaseTime         time.Time
    16  	DisableColors    bool
    17  	DisableTimestamp bool
    18  	FullTimestamp    bool
    19  	TimestampFormat  string
    20  }
    21  
    22  func (f Formatter) Format(ctx context.Context, level Level, tag string, message string, timestamp time.Time) string {
    23  	levelString := strings.ToUpper(FormatLevel(level))
    24  	if !f.DisableColors {
    25  		switch level {
    26  		case LevelDebug, LevelTrace:
    27  			levelString = aurora.White(levelString).String()
    28  		case LevelInfo:
    29  			levelString = aurora.Cyan(levelString).String()
    30  		case LevelWarn:
    31  			levelString = aurora.Yellow(levelString).String()
    32  		case LevelError, LevelFatal, LevelPanic:
    33  			levelString = aurora.Red(levelString).String()
    34  		}
    35  	}
    36  	if tag != "" {
    37  		message = tag + ": " + message
    38  	}
    39  	var id ID
    40  	var hasId bool
    41  	if ctx != nil {
    42  		id, hasId = IDFromContext(ctx)
    43  	}
    44  	if hasId {
    45  		activeDuration := formatDuration(time.Since(id.CreatedAt))
    46  		if !f.DisableColors {
    47  			var color aurora.Color
    48  			color = aurora.Color(uint8(id.ID))
    49  			color %= 215
    50  			row := uint(color / 36)
    51  			column := uint(color % 36)
    52  
    53  			var r, g, b float32
    54  			r = float32(row * 51)
    55  			g = float32(column / 6 * 51)
    56  			b = float32((column % 6) * 51)
    57  			luma := 0.2126*r + 0.7152*g + 0.0722*b
    58  			if luma < 60 {
    59  				row = 5 - row
    60  				column = 35 - column
    61  				color = aurora.Color(row*36 + column)
    62  			}
    63  			color += 16
    64  			color = color << 16
    65  			color |= 1 << 14
    66  			message = F.ToString("[", aurora.Colorize(id.ID, color).String(), " ", activeDuration, "] ", message)
    67  		} else {
    68  			message = F.ToString("[", id.ID, " ", activeDuration, "] ", message)
    69  		}
    70  	}
    71  	switch {
    72  	case f.DisableTimestamp:
    73  		message = levelString + " " + message
    74  	case f.FullTimestamp:
    75  		message = timestamp.Format(f.TimestampFormat) + " " + levelString + " " + message
    76  	default:
    77  		message = levelString + "[" + xd(int(timestamp.Sub(f.BaseTime)/time.Second), 4) + "] " + message
    78  	}
    79  	if message[len(message)-1] != '\n' {
    80  		message += "\n"
    81  	}
    82  	return message
    83  }
    84  
    85  func (f Formatter) FormatWithSimple(ctx context.Context, level Level, tag string, message string, timestamp time.Time) (string, string) {
    86  	levelString := strings.ToUpper(FormatLevel(level))
    87  	if !f.DisableColors {
    88  		switch level {
    89  		case LevelDebug, LevelTrace:
    90  			levelString = aurora.White(levelString).String()
    91  		case LevelInfo:
    92  			levelString = aurora.Cyan(levelString).String()
    93  		case LevelWarn:
    94  			levelString = aurora.Yellow(levelString).String()
    95  		case LevelError, LevelFatal, LevelPanic:
    96  			levelString = aurora.Red(levelString).String()
    97  		}
    98  	}
    99  	if tag != "" {
   100  		message = tag + ": " + message
   101  	}
   102  	messageSimple := message
   103  	var id ID
   104  	var hasId bool
   105  	if ctx != nil {
   106  		id, hasId = IDFromContext(ctx)
   107  	}
   108  	if hasId {
   109  		activeDuration := formatDuration(time.Since(id.CreatedAt))
   110  		if !f.DisableColors {
   111  			var color aurora.Color
   112  			color = aurora.Color(uint8(id.ID))
   113  			color %= 215
   114  			row := uint(color / 36)
   115  			column := uint(color % 36)
   116  
   117  			var r, g, b float32
   118  			r = float32(row * 51)
   119  			g = float32(column / 6 * 51)
   120  			b = float32((column % 6) * 51)
   121  			luma := 0.2126*r + 0.7152*g + 0.0722*b
   122  			if luma < 60 {
   123  				row = 5 - row
   124  				column = 35 - column
   125  				color = aurora.Color(row*36 + column)
   126  			}
   127  			color += 16
   128  			color = color << 16
   129  			color |= 1 << 14
   130  			message = F.ToString("[", aurora.Colorize(id.ID, color).String(), " ", activeDuration, "] ", message)
   131  		} else {
   132  			message = F.ToString("[", id.ID, " ", activeDuration, "] ", message)
   133  		}
   134  		messageSimple = F.ToString("[", id.ID, " ", activeDuration, "] ", messageSimple)
   135  
   136  	}
   137  	switch {
   138  	case f.DisableTimestamp:
   139  		message = levelString + " " + message
   140  	case f.FullTimestamp:
   141  		message = timestamp.Format(f.TimestampFormat) + " " + levelString + " " + message
   142  	default:
   143  		message = levelString + "[" + xd(int(timestamp.Sub(f.BaseTime)/time.Second), 4) + "] " + message
   144  	}
   145  	if message[len(message)-1] != '\n' {
   146  		message += "\n"
   147  	}
   148  	return message, messageSimple
   149  }
   150  
   151  func xd(value int, x int) string {
   152  	message := strconv.Itoa(value)
   153  	for len(message) < x {
   154  		message = "0" + message
   155  	}
   156  	return message
   157  }
   158  
   159  func formatDuration(duration time.Duration) string {
   160  	if duration < time.Second {
   161  		return F.ToString(duration.Milliseconds(), "ms")
   162  	} else if duration < time.Minute {
   163  		return F.ToString(int64(duration.Seconds()), ".", int64(duration.Seconds()*100)%100, "s")
   164  	} else {
   165  		return F.ToString(int64(duration.Minutes()), "m", int64(duration.Seconds())%60, "s")
   166  	}
   167  }