blob: 2274dd23c075ce8a6e99cf17c33d51a98b1af114 [file] [edit]
// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package logs
import (
"compress/gzip"
"context"
"fmt"
"io"
"os/exec"
"regexp"
)
// croslogCursorRegexp parses output from a `croslog --show-cursor` command. Example output:
// -- cursor: s=bfd03b7e4c464cc09b43e1843880f9ee;i=a5eab;b=cdd933be...
var croslogCursorRegexp = regexp.MustCompile(`^-- cursor:\s+(\S+)`)
// GetUnifiedLogCursor returns a log cursor to the current tip of the unified system logs.
// The return cursor can later be passed to WriteLogs.
func GetUnifiedLogCursor(ctx context.Context) (string, error) {
cmd := exec.CommandContext(ctx, "croslog", "--lines=0", "--show-cursor", "--quiet", "--no-pager")
out, err := cmd.Output()
if err != nil {
return "", err
}
m := croslogCursorRegexp.FindSubmatch(out)
if m == nil {
return "", fmt.Errorf("failed to find %q in %q", croslogCursorRegexp, out)
}
return string(m[1]), nil
}
// UnifiedLogFormat is a format for syslog entries.
type UnifiedLogFormat int
const (
// CompactLogFormat corresponds to human-readable single-line log entries.
CompactLogFormat UnifiedLogFormat = iota
// GzippedExportLogFormat corresponds to croslog's "--output=export" multiline format that preserves metadata.
// The data is additionally gzip-compressed.
GzippedExportLogFormat
)
// ExportUnifiedLogs writes unified system log entries generated after cursor to w using fm.
// cursor should have been generated by an earlier call to GetUnifiedLogCursor.
func ExportUnifiedLogs(ctx context.Context, w io.Writer, cursor string, fm UnifiedLogFormat) error {
args := []string{"--after-cursor=" + cursor}
if fm == GzippedExportLogFormat {
args = append(args, "--output=export")
}
cmd := exec.CommandContext(ctx, "croslog", args...)
var ww io.WriteCloser // wraps w; may be nil
if fm == GzippedExportLogFormat {
ww = gzip.NewWriter(w)
cmd.Stdout = ww
} else {
cmd.Stdout = w
}
err := cmd.Run()
// If the writer was wrapped, close the wrapper to flush data.
if ww != nil {
if cerr := ww.Close(); cerr != nil && err == nil {
err = cerr
}
}
return err
}