github.com/nya3jp/tast@v0.0.0-20230601000426-85c8e4d83a9b/src/go.chromium.org/tast/core/internal/logs/reader.go (about)

     1  // Copyright 2020 The ChromiumOS Authors
     2  // Use of this source code is governed by a BSD-style license that can be
     3  // found in the LICENSE file.
     4  
     5  package logs
     6  
     7  import (
     8  	"compress/gzip"
     9  	"context"
    10  	"fmt"
    11  	"io"
    12  	"os/exec"
    13  	"regexp"
    14  )
    15  
    16  // croslogCursorRegexp parses output from a `croslog --show-cursor` command. Example output:
    17  // -- cursor: s=bfd03b7e4c464cc09b43e1843880f9ee;i=a5eab;b=cdd933be...
    18  var croslogCursorRegexp = regexp.MustCompile(`^-- cursor:\s+(\S+)`)
    19  
    20  // GetUnifiedLogCursor returns a log cursor to the current tip of the unified system logs.
    21  // The return cursor can later be passed to WriteLogs.
    22  func GetUnifiedLogCursor(ctx context.Context) (string, error) {
    23  	cmd := exec.CommandContext(ctx, "croslog", "--lines=0", "--show-cursor", "--quiet", "--no-pager")
    24  	out, err := cmd.Output()
    25  	if err != nil {
    26  		return "", err
    27  	}
    28  	m := croslogCursorRegexp.FindSubmatch(out)
    29  	if m == nil {
    30  		return "", fmt.Errorf("failed to find %q in %q", croslogCursorRegexp, out)
    31  	}
    32  	return string(m[1]), nil
    33  }
    34  
    35  // UnifiedLogFormat is a format for syslog entries.
    36  type UnifiedLogFormat int
    37  
    38  const (
    39  	// CompactLogFormat corresponds to human-readable single-line log entries.
    40  	CompactLogFormat UnifiedLogFormat = iota
    41  	// GzippedExportLogFormat corresponds to croslog's "--output=export" multiline format that preserves metadata.
    42  	// The data is additionally gzip-compressed.
    43  	GzippedExportLogFormat
    44  )
    45  
    46  // ExportUnifiedLogs writes unified system log entries generated after cursor to w using fm.
    47  // cursor should have been generated by an earlier call to GetUnifiedLogCursor.
    48  func ExportUnifiedLogs(ctx context.Context, w io.Writer, cursor string, fm UnifiedLogFormat) error {
    49  	args := []string{"--after-cursor=" + cursor}
    50  	if fm == GzippedExportLogFormat {
    51  		args = append(args, "--output=export")
    52  	}
    53  	cmd := exec.CommandContext(ctx, "croslog", args...)
    54  
    55  	var ww io.WriteCloser // wraps w; may be nil
    56  	if fm == GzippedExportLogFormat {
    57  		ww = gzip.NewWriter(w)
    58  		cmd.Stdout = ww
    59  	} else {
    60  		cmd.Stdout = w
    61  	}
    62  
    63  	err := cmd.Run()
    64  
    65  	// If the writer was wrapped, close the wrapper to flush data.
    66  	if ww != nil {
    67  		if cerr := ww.Close(); cerr != nil && err == nil {
    68  			err = cerr
    69  		}
    70  	}
    71  
    72  	return err
    73  }