code-intelligence.com/cifuzz@v0.40.0/internal/cmd/run/reporthandler/metrics/updating_printer.go (about)

     1  package metrics
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"strings"
     7  	"sync/atomic"
     8  	"time"
     9  
    10  	"github.com/gookit/color"
    11  	"github.com/pkg/errors"
    12  	"github.com/pterm/pterm"
    13  
    14  	"code-intelligence.com/cifuzz/pkg/log"
    15  	"code-intelligence.com/cifuzz/pkg/report"
    16  )
    17  
    18  func NewUpdatingPrinter(output io.Writer) (*UpdatingPrinter, error) {
    19  	// pterm.SpinnerPrinter doesn't support specifying the output, it
    20  	// always uses color.output, so we have to set that. Note that this
    21  	// affects the default output of all methods from the pterm and
    22  	// color packages.
    23  	color.SetOutput(output)
    24  
    25  	var err error
    26  	p := &UpdatingPrinter{
    27  		SpinnerPrinter: pterm.DefaultSpinner.WithShowTimer(false),
    28  		startedAt:      time.Now(),
    29  		output:         output,
    30  		lastMetrics:    &atomic.Value{},
    31  	}
    32  	log.ActiveUpdatingPrinter = p
    33  
    34  	p.SpinnerPrinter, err = p.SpinnerPrinter.Start()
    35  	if err != nil {
    36  		return nil, errors.WithStack(err)
    37  	}
    38  
    39  	p.ticker = time.NewTicker(time.Second)
    40  	go func() {
    41  		for range p.ticker.C {
    42  			if !p.SpinnerPrinter.IsActive {
    43  				break
    44  			}
    45  			p.Update()
    46  		}
    47  	}()
    48  
    49  	return p, nil
    50  }
    51  
    52  type UpdatingPrinter struct {
    53  	*pterm.SpinnerPrinter
    54  	ticker    *time.Ticker
    55  	startedAt time.Time
    56  	output    io.Writer
    57  
    58  	lastMetrics *atomic.Value
    59  }
    60  
    61  func (p *UpdatingPrinter) Update() {
    62  	lastMetrics, ok := p.lastMetrics.Load().(*report.FuzzingMetric)
    63  	if ok {
    64  		lastMetrics.SecondsSinceLastFeature += 1
    65  		p.lastMetrics.Store(lastMetrics)
    66  	}
    67  	p.printMetrics(lastMetrics)
    68  }
    69  
    70  func (p *UpdatingPrinter) PrintMetrics(metrics *report.FuzzingMetric) {
    71  	p.lastMetrics.Store(metrics)
    72  	p.ticker.Reset(time.Second)
    73  	p.printMetrics(metrics)
    74  }
    75  
    76  func (p *UpdatingPrinter) printMetrics(metrics *report.FuzzingMetric) {
    77  	s := fmt.Sprint(
    78  		MetricsToString(metrics),
    79  		DelimString(" ("),
    80  		pterm.LightYellow(time.Since(p.startedAt).Truncate(time.Second).String()),
    81  		DelimString(")"),
    82  	)
    83  	p.UpdateText(s)
    84  }
    85  
    86  func (p *UpdatingPrinter) Clear() {
    87  	pterm.Fprinto(p.output, strings.Repeat(" ", pterm.GetTerminalWidth()), "\r")
    88  }