github.com/telepresenceio/telepresence/v2@v2.20.0-pro.6.0.20240517030216-236ea954e789/pkg/client/logging/initcontext.go (about)

     1  package logging
     2  
     3  import (
     4  	"bufio"
     5  	"context"
     6  	"fmt"
     7  	"log"
     8  	"os"
     9  	"path/filepath"
    10  	"strconv"
    11  	"strings"
    12  
    13  	"github.com/sirupsen/logrus"
    14  
    15  	"github.com/datawire/dlib/dlog"
    16  	"github.com/telepresenceio/telepresence/v2/pkg/client"
    17  	"github.com/telepresenceio/telepresence/v2/pkg/dos"
    18  	"github.com/telepresenceio/telepresence/v2/pkg/filelocation"
    19  	tlog "github.com/telepresenceio/telepresence/v2/pkg/log"
    20  )
    21  
    22  // loggerForTest exposes internals to initcontext_test.go.
    23  var loggerForTest *logrus.Logger //nolint:gochecknoglobals // used by unit tests only
    24  
    25  // InitContext sets up standard Telepresence logging for a background process.
    26  func InitContext(ctx context.Context, name string, strategy RotationStrategy, captureStd bool) (context.Context, error) {
    27  	logger := logrus.StandardLogger()
    28  	loggerForTest = logger
    29  
    30  	// Start with InfoLevel so that the config is read using that level
    31  	logger.SetLevel(logrus.InfoLevel)
    32  	logger.ReportCaller = false // turned on when level >= logrus.TraceLevel
    33  
    34  	if captureStd && IsTerminal(int(os.Stdout.Fd())) {
    35  		logger.Formatter = tlog.NewFormatter("15:04:05.0000")
    36  	} else {
    37  		logger.Formatter = tlog.NewFormatter("2006-01-02 15:04:05.0000")
    38  		maxFiles := uint16(5)
    39  
    40  		// TODO: Also make this a configurable setting in config.yml
    41  		if me := os.Getenv("TELEPRESENCE_MAX_LOGFILES"); me != "" {
    42  			if mx, err := strconv.Atoi(me); err == nil && mx >= 0 {
    43  				maxFiles = uint16(mx)
    44  			}
    45  		}
    46  		rf, err := OpenRotatingFile(ctx, filepath.Join(filelocation.AppUserLogDir(ctx), name+".log"), "20060102T150405", true, 0o600, strategy, maxFiles)
    47  		if err != nil {
    48  			return ctx, err
    49  		}
    50  		logger.SetOutput(rf)
    51  
    52  		if captureStd {
    53  			if err := dupToStdOut(rf.file.(*os.File)); err != nil {
    54  				return ctx, err
    55  			}
    56  			if err := dupToStdErr(rf.file.(*os.File)); err != nil {
    57  				return ctx, err
    58  			}
    59  		}
    60  
    61  		// Configure the standard logger to write without any fields and with prefix "stdlog"
    62  		log.SetOutput(logger.Writer())
    63  		log.SetPrefix("stdlog : ")
    64  		log.SetFlags(0)
    65  	}
    66  
    67  	ctx = dlog.WithLogger(ctx, dlog.WrapLogrus(logger))
    68  
    69  	// Read the config and set the configured level.
    70  	logLevels := client.GetConfig(ctx).LogLevels()
    71  	level := logLevels.UserDaemon
    72  	if name == "daemon" {
    73  		level = logLevels.RootDaemon
    74  	}
    75  	tlog.SetLogrusLevel(logger, level.String(), false)
    76  	ctx = tlog.WithLevelSetter(ctx, logger)
    77  	return ctx, nil
    78  }
    79  
    80  func SummarizeLog(ctx context.Context, name string) (string, error) {
    81  	filename := filepath.Join(filelocation.AppUserLogDir(ctx), name+".log")
    82  	file, err := dos.Open(ctx, filename)
    83  	if err != nil {
    84  		if os.IsNotExist(err) {
    85  			err = nil
    86  		}
    87  		return "", err
    88  	}
    89  	defer file.Close()
    90  	scanner := bufio.NewScanner(file)
    91  
    92  	errorCount := 0
    93  	for scanner.Scan() {
    94  		// XXX: is there a better way to detect error lines?
    95  		txt := scanner.Text()
    96  		parts := strings.Fields(txt)
    97  		if len(parts) < 3 {
    98  			continue
    99  		}
   100  		switch parts[2] {
   101  		case "error":
   102  			errorCount++
   103  		case "info":
   104  			if strings.Contains(txt, "-- Starting new session") {
   105  				// Start over. No use counting errors from previous sessions
   106  				errorCount = 0
   107  			}
   108  		}
   109  	}
   110  	if errorCount == 0 {
   111  		return "", nil
   112  	}
   113  	desc := fmt.Sprintf("%d error", errorCount)
   114  	if errorCount > 1 {
   115  		desc += "s"
   116  	}
   117  
   118  	return fmt.Sprintf("See logs for details (%s found): %q", desc, filename), nil
   119  }