github.com/tilt-dev/tilt@v0.36.0/internal/hud/log_filter.go (about)

     1  package hud
     2  
     3  import (
     4  	"strings"
     5  
     6  	"github.com/tilt-dev/tilt/pkg/logger"
     7  	"github.com/tilt-dev/tilt/pkg/model"
     8  	"github.com/tilt-dev/tilt/pkg/model/logstore"
     9  )
    10  
    11  type FilterSource string
    12  
    13  const (
    14  	FilterSourceAll     FilterSource = "all"
    15  	FilterSourceBuild   FilterSource = "build"
    16  	FilterSourceRuntime FilterSource = "runtime"
    17  )
    18  
    19  func (s FilterSource) String() string { return string(s) }
    20  
    21  type FilterResources []model.ManifestName
    22  
    23  func (r FilterResources) Matches(name model.ManifestName) bool {
    24  	if len(r) == 0 {
    25  		return true
    26  	}
    27  
    28  	for _, n := range r {
    29  		if n == name {
    30  			return true
    31  		}
    32  	}
    33  
    34  	return false
    35  }
    36  
    37  type FilterLevel logger.Level
    38  
    39  func NewLogFilter(
    40  	source FilterSource,
    41  	resources FilterResources,
    42  	level FilterLevel,
    43  ) LogFilter {
    44  	return LogFilter{
    45  		source:    source,
    46  		resources: resources,
    47  		level:     logger.Level(level),
    48  	}
    49  }
    50  
    51  type LogFilter struct {
    52  	source    FilterSource
    53  	resources FilterResources
    54  	level     logger.Level
    55  }
    56  
    57  // The implementation is identical to isBuildSpanId in web/src/logs.ts.
    58  func isBuildSpanID(spanID logstore.SpanID) bool {
    59  	return strings.HasPrefix(string(spanID), "build:") || strings.HasPrefix(string(spanID), "cmdimage:")
    60  }
    61  
    62  // The implementation is identical to matchesLevelFilter in web/src/OverviewLogPane.tsx
    63  func (f LogFilter) matchesLevelFilter(line logstore.LogLine) bool {
    64  	if !f.level.AsSevereAs(logger.WarnLvl) {
    65  		return true
    66  	}
    67  
    68  	return f.level == line.Level
    69  }
    70  
    71  // if printing logs for only one resource, don't need resource name prefix
    72  func (f LogFilter) SuppressPrefix() bool {
    73  	return len(f.resources) == 1
    74  }
    75  
    76  // Matches Checks if this line matches the current filter.
    77  // The implementation is identical to matchesFilter in web/src/OverviewLogPane.tsx.
    78  // except for term filtering as tools like grep can be used from the CLI.
    79  func (f LogFilter) Matches(line logstore.LogLine) bool {
    80  	if line.BuildEvent != "" {
    81  		// Always leave in build event logs.
    82  		// This makes it easier to see which logs belong to which builds.
    83  		return true
    84  	}
    85  
    86  	if !f.resources.Matches(line.ManifestName) {
    87  		return false
    88  	}
    89  
    90  	isBuild := isBuildSpanID(line.SpanID)
    91  	if f.source == FilterSourceRuntime && isBuild {
    92  		return false
    93  	}
    94  
    95  	if f.source == FilterSourceBuild && !isBuild {
    96  		return false
    97  	}
    98  
    99  	return f.matchesLevelFilter(line)
   100  }
   101  
   102  func (f LogFilter) Apply(lines []logstore.LogLine) []logstore.LogLine {
   103  	filtered := []logstore.LogLine{}
   104  	for _, line := range lines {
   105  		if f.Matches(line) {
   106  			filtered = append(filtered, line)
   107  		}
   108  	}
   109  
   110  	return filtered
   111  }