package logmower import ( "bytes" "fmt" "log" "time" ms "git.k-space.ee/k-space/logmower-shipper/pkg/mongo_struct" prom "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" ) var promRecordPrefixParsingErr = promauto.NewCounterVec(prom.CounterOpts{ Namespace: PrometheusPrefix, Subsystem: "record", Name: "parsing_errors", Help: "Errors while parsing log line prefixes", }, []string{"filename"}) func (unparsed RawLines) parse(parsed chan<- singleLine) { for { raw, ok := <-unparsed if !ok { close(parsed) return } line := singleLine{RawLine: raw} if err := line.parse(); err != nil { promRecordPrefixParsingErr.WithLabelValues(raw.metricsName).Add(1) log.Printf("parsing kubernetes log line in %q: %e", raw.File.Path, err) } // TODO: should this only be on success? parsed <- line } } type ( singleLines <-chan singleLine singleLine struct { RawLine // populated by parse() ms.ParsedMetadata partial bool // P or F } ) func (line *singleLine) parse() (err error) { split := bytes.SplitN(line.B, []byte(" "), 4) if len(split) != 4 { return fmt.Errorf("expected at least 3 spaces in , got %d", len(split)-1) } line.TimeKubernetes, err = time.Parse(time.RFC3339Nano, string(split[0])) if err != nil { return fmt.Errorf("invalid time: %w", err) } line.StdErr = string(split[1]) == "stderr" // or stdout switch string(split[2]) { case "P": line.partial = true case "F": default: return fmt.Errorf("partial indicator must be 'P' or 'F', not %q", split[2]) } line.B = split[3] return nil }