github.com/telepresenceio/telepresence/v2@v2.20.0-pro.6.0.20240517030216-236ea954e789/pkg/log/formatter.go (about)

     1  package log
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"sort"
     7  	"strings"
     8  
     9  	"github.com/sirupsen/logrus"
    10  
    11  	"github.com/telepresenceio/telepresence/v2/pkg/maps"
    12  )
    13  
    14  const thisModule = "github.com/telepresenceio/telepresence/v2"
    15  
    16  // Formatter formats log messages for Telepresence.
    17  type Formatter struct {
    18  	timestampFormat string
    19  }
    20  
    21  func NewFormatter(timestampFormat string) *Formatter {
    22  	return &Formatter{timestampFormat: timestampFormat}
    23  }
    24  
    25  // Format implements logrus.Formatter.
    26  func (f *Formatter) Format(entry *logrus.Entry) ([]byte, error) {
    27  	var b *bytes.Buffer
    28  	if entry.Buffer != nil {
    29  		b = entry.Buffer
    30  	} else {
    31  		b = &bytes.Buffer{}
    32  	}
    33  	data := maps.Copy(entry.Data)
    34  	goroutine, _ := data["THREAD"].(string)
    35  	delete(data, "THREAD")
    36  
    37  	if len(goroutine) > 0 {
    38  		fmt.Fprintf(b, "%s %-*s %s : %s",
    39  			entry.Time.Format(f.timestampFormat),
    40  			len("warning"), entry.Level,
    41  			strings.TrimPrefix(goroutine, "/"),
    42  			entry.Message)
    43  	} else {
    44  		fmt.Fprintf(b, "%s %-*s %s",
    45  			entry.Time.Format(f.timestampFormat),
    46  			len("warning"), entry.Level,
    47  			entry.Message)
    48  	}
    49  
    50  	if len(data) > 0 {
    51  		b.WriteString(" :")
    52  		keys := make([]string, 0, len(data))
    53  		for key := range data {
    54  			keys = append(keys, key)
    55  		}
    56  		sort.Slice(keys, func(i, j int) bool {
    57  			orders := map[string]int{
    58  				"dexec.pid":    -4,
    59  				"dexec.stream": -3,
    60  				"dexec.data":   -2,
    61  				"dexec.err":    -1,
    62  			}
    63  			iOrd := orders[keys[i]]
    64  			jOrd := orders[keys[j]]
    65  			if iOrd != jOrd {
    66  				return iOrd < jOrd
    67  			}
    68  			return keys[i] < keys[j]
    69  		})
    70  		for _, key := range keys {
    71  			val := fmt.Sprintf("%+v", data[key])
    72  			fmt.Fprintf(b, " %s=%q", key, val)
    73  		}
    74  	}
    75  
    76  	if entry.HasCaller() && strings.HasPrefix(entry.Caller.File, thisModule+"/") {
    77  		fmt.Fprintf(b, " (from %s:%d)", strings.TrimPrefix(entry.Caller.File, thisModule+"/"), entry.Caller.Line)
    78  	}
    79  
    80  	b.WriteByte('\n')
    81  
    82  	return b.Bytes(), nil
    83  }