mirror of
https://gitea.com/gitea/runner.git
synced 2026-11-06 23:30:29 +00:00
refactor(logging): use the logging package in internal (#1302)
Move the log calls in `internal` onto `logging`, and add what the process-wide logger setup and its tests need: `SetTextFormat` with a line filter for secret masking (replacing `report.MaskingFormatter`), `SetReportCaller`, `SetDefault` and `logtest.SetDefault`. After this only the `logging` package imports logrus. Stacked on https://gitea.com/gitea/runner/pulls/1301. Assisted-by: Codet Co-authored-by: bircni <[email protected]> Reviewed-on: https://gitea.com/gitea/runner/pulls/1302 Reviewed-by: bircni <[email protected]>
This commit is contained in:
1 parent
76110557ab
commit
4e8037a93b
25 files changed
+308
-246
No files matched your search
@@ -9,8 +9,6 @@ import (
|
||||
"sync/atomic"
|
||||
|
||||
"gitea.com/gitea/runner/act/runner"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// A job's plan runs before its job logger exists and logs through the process-wide one, which
|
||||
@@ -47,21 +45,12 @@ func rebuildGlobalReplacer() { // caller holds globalMu
|
||||
globalReplacer.Store(runner.NewSecretReplacer(oldnew))
|
||||
}
|
||||
|
||||
// MaskingFormatter wraps f so a registered value cannot reach the process-wide log, fields included.
|
||||
func MaskingFormatter(f log.Formatter) log.Formatter {
|
||||
return &maskingFormatter{inner: f}
|
||||
}
|
||||
|
||||
type maskingFormatter struct{ inner log.Formatter }
|
||||
|
||||
func (m *maskingFormatter) Format(entry *log.Entry) ([]byte, error) {
|
||||
line, err := m.inner.Format(entry)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// MaskGlobal hides every registered value in a formatted line of the process-wide log, fields
|
||||
// included. It is meant for logging.TextOptions.Filter.
|
||||
func MaskGlobal(line []byte) []byte {
|
||||
replacer := globalReplacer.Load()
|
||||
if replacer == nil { // nothing to hide, so an idle daemon pays no copy
|
||||
return line, nil
|
||||
return line
|
||||
}
|
||||
return []byte(replacer.Replace(string(line))), nil
|
||||
return []byte(replacer.Replace(string(line)))
|
||||
}
|
||||
@@ -4,19 +4,27 @@
|
||||
package report
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"gitea.com/gitea/runner/act/common/logging"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestGlobalMasks(t *testing.T) {
|
||||
formatter := MaskingFormatter(&log.TextFormatter{DisableTimestamp: true})
|
||||
prevOut := logging.Output()
|
||||
t.Cleanup(func() {
|
||||
logging.SetOutput(prevOut)
|
||||
logging.SetTextFormat(logging.TextOptions{})
|
||||
})
|
||||
var out strings.Builder
|
||||
logging.SetOutput(&out)
|
||||
logging.SetTextFormat(logging.TextOptions{DisableTimestamp: true, Filter: MaskGlobal})
|
||||
format := func(job string) string {
|
||||
line, err := formatter.Format(log.WithField("job", job))
|
||||
require.NoError(t, err)
|
||||
return string(line)
|
||||
out.Reset()
|
||||
logging.With("job", job).Info("line")
|
||||
return out.String()
|
||||
}
|
||||
register := func(oldnew ...string) *Reporter {
|
||||
r := &Reporter{oldnew: oldnew}
|
||||
|
||||
@@ -10,9 +10,8 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"gitea.com/gitea/runner/act/common/logging"
|
||||
"gitea.com/gitea/runner/internal/pkg/config"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -37,7 +36,7 @@ func openJobLog(cfg config.LogJob, taskID int64, started time.Time) *jobLog {
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(cfg.Dir, 0o700); err != nil { // repository output, readable by this user only
|
||||
log.Warnf("cannot create job log directory %s: %v", cfg.Dir, err)
|
||||
logging.Warnf("cannot create job log directory %s: %v", cfg.Dir, err)
|
||||
return nil
|
||||
}
|
||||
pruneJobLogs(cfg.Dir, cfg.Retention, started)
|
||||
@@ -45,10 +44,10 @@ func openJobLog(cfg config.LogJob, taskID int64, started time.Time) *jobLog {
|
||||
name := fmt.Sprintf("%s-task-%d.log", started.UTC().Format(jobLogNameLayout), taskID)
|
||||
file, err := os.OpenFile(filepath.Join(cfg.Dir, name), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o600)
|
||||
if err != nil {
|
||||
log.Warnf("cannot create job log: %v", err)
|
||||
logging.Warnf("cannot create job log: %v", err)
|
||||
return nil
|
||||
}
|
||||
log.Infof("writing the log of task %d to %s", taskID, file.Name())
|
||||
logging.Infof("writing the log of task %d to %s", taskID, file.Name())
|
||||
return &jobLog{file: file, max: int64(cfg.MaxSize)}
|
||||
}
|
||||
|
||||
@@ -72,7 +71,7 @@ func (j *jobLog) close(trailer string) {
|
||||
j.closed = true
|
||||
j.line(runnerLine(trailer)) // past the cap on purpose: no trailer means the runner died mid-job
|
||||
if err := j.file.Close(); err != nil {
|
||||
log.Warnf("cannot close %s: %v", j.file.Name(), err)
|
||||
logging.Warnf("cannot close %s: %v", j.file.Name(), err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,7 +82,7 @@ func (j *jobLog) line(content string) {
|
||||
j.size += int64(n)
|
||||
if err != nil {
|
||||
j.stopped = true // reported once, a failing write is a full disk and retrying floods the log
|
||||
log.Warnf("cannot write %s: %v", j.file.Name(), err)
|
||||
logging.Warnf("cannot write %s: %v", j.file.Name(), err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,7 +98,7 @@ func pruneJobLogs(root string, retention time.Duration, now time.Time) {
|
||||
}
|
||||
entries, err := os.ReadDir(root)
|
||||
if err != nil {
|
||||
log.Warnf("cannot list job log directory %s: %v", root, err)
|
||||
logging.Warnf("cannot list job log directory %s: %v", root, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -114,7 +113,7 @@ func pruneJobLogs(root string, retention time.Duration, now time.Time) {
|
||||
}
|
||||
name := filepath.Join(root, entry.Name())
|
||||
if err := os.Remove(name); err != nil {
|
||||
log.Warnf("cannot remove expired job log %s: %v", name, err)
|
||||
logging.Warnf("cannot remove expired job log %s: %v", name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,6 @@ import (
|
||||
"connectrpc.com/connect"
|
||||
runnerv1 "gitea.dev/actionslib/runner/v1"
|
||||
"github.com/avast/retry-go/v5"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
)
|
||||
@@ -357,10 +356,10 @@ func (r *Reporter) noteReport(method string, err error) {
|
||||
switch {
|
||||
case err != nil && !r.reportFailing[method]:
|
||||
r.reportFailing[method] = true
|
||||
log.Warnf("%s error: %v, retrying until reconnected", method, err)
|
||||
logging.Warnf("%s error: %v, retrying until reconnected", method, err)
|
||||
case err == nil && r.reportFailing[method]:
|
||||
delete(r.reportFailing, method)
|
||||
log.Infof("%s reconnected", method)
|
||||
logging.Infof("%s reconnected", method)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -497,17 +496,17 @@ func (r *Reporter) SetOutputs(outputs map[string]string) {
|
||||
}
|
||||
for k, v := range outputs {
|
||||
if l := len(k); l > maxOutputKeyLen {
|
||||
log.Warnf("ignore output %q because the key is too long: %d > %d", k, l, maxOutputKeyLen)
|
||||
logging.Warnf("ignore output %q because the key is too long: %d > %d", k, l, maxOutputKeyLen)
|
||||
r.logf("ignore output %q because the key is too long: %d > %d", k, l, maxOutputKeyLen)
|
||||
continue
|
||||
}
|
||||
if l := len(v); l > maxOutputValueLen {
|
||||
log.Warnf("ignore output %q because the value is too long: %d > %d", k, l, maxOutputValueLen)
|
||||
logging.Warnf("ignore output %q because the value is too long: %d > %d", k, l, maxOutputValueLen)
|
||||
r.logf("ignore output %q because the value is too long: %d > %d", k, l, maxOutputValueLen)
|
||||
continue
|
||||
}
|
||||
if r.logReplacer.Replace(v) != v { // GitHub skips an output that may carry a secret rather than masking it
|
||||
log.Warnf("ignore output %q because it may contain a secret", k)
|
||||
logging.Warnf("ignore output %q because it may contain a secret", k)
|
||||
r.logf("ignore output %q because it may contain a secret", k)
|
||||
continue
|
||||
}
|
||||
@@ -559,7 +558,7 @@ func (r *Reporter) Close(lastWords string) error {
|
||||
select {
|
||||
case <-r.daemon:
|
||||
case <-time.After(r.daemonWait):
|
||||
log.Errorf("No Response from RunDaemon for %s, continue best effort", r.daemonWait)
|
||||
logging.Errorf("No Response from RunDaemon for %s, continue best effort", r.daemonWait)
|
||||
}
|
||||
|
||||
// Gitea's UpdateLog short-circuits on len(Rows)==0 before honoring NoMore,
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"time"
|
||||
|
||||
"gitea.com/gitea/runner/act/common/logging"
|
||||
"gitea.com/gitea/runner/act/common/logging/logtest"
|
||||
"gitea.com/gitea/runner/act/runner"
|
||||
"gitea.com/gitea/runner/internal/pkg/client/mocks"
|
||||
"gitea.com/gitea/runner/internal/pkg/config"
|
||||
@@ -26,7 +27,6 @@ import (
|
||||
connect_go "connectrpc.com/connect"
|
||||
"gitea.dev/actionslib/pkg/model"
|
||||
runnerv1 "gitea.dev/actionslib/runner/v1"
|
||||
logrustest "github.com/sirupsen/logrus/hooks/test"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -1311,24 +1311,23 @@ func TestReporter_ServerFailureResultIsReportedAsFailure(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestReporter_NoteReport(t *testing.T) {
|
||||
hook := logrustest.NewGlobal()
|
||||
defer hook.Reset()
|
||||
hook := logtest.SetDefault(t)
|
||||
|
||||
reporter := &Reporter{reportFailing: map[string]bool{}}
|
||||
|
||||
// A pending output is not a transport failure and must not read as one.
|
||||
reporter.noteReport(metrics.LabelMethodUpdateTask, fmt.Errorf("wrapped: %w", errOutputsNotSent))
|
||||
assert.Empty(t, hook.AllEntries())
|
||||
assert.Empty(t, hook.AllRecords())
|
||||
|
||||
// An outage logs once at each end, not every report interval for hours.
|
||||
reporter.noteReport(metrics.LabelMethodUpdateTask, errors.New("connection refused"))
|
||||
reporter.noteReport(metrics.LabelMethodUpdateTask, errors.New("connection refused"))
|
||||
require.Len(t, hook.AllEntries(), 1)
|
||||
assert.Contains(t, hook.LastEntry().Message, "connection refused")
|
||||
require.Len(t, hook.AllRecords(), 1)
|
||||
assert.Contains(t, hook.LastRecord().Message, "connection refused")
|
||||
|
||||
reporter.noteReport(metrics.LabelMethodUpdateTask, nil)
|
||||
require.Len(t, hook.AllEntries(), 2)
|
||||
assert.Contains(t, hook.LastEntry().Message, "reconnected")
|
||||
require.Len(t, hook.AllRecords(), 2)
|
||||
assert.Contains(t, hook.LastRecord().Message, "reconnected")
|
||||
}
|
||||
|
||||
// A job's final error can carry a secret, e.g. one interpolated into a failing
|
||||
|
||||
Reference in new issue
Block a user