Injectable logging implementation

Refactor logging to allow providing custom logging implementations to plugin
manager. This should allow us to keep logging as it is when running OPA as a
server, while injecting noop-loggers or custom, provided loggers for SDK client
implementations.

Fixes #3180

Signed-off-by: Anders Eknert <anders@eknert.com>
This commit is contained in:
Anders Eknert
2021-03-01 15:23:03 +01:00
parent ef9814c9ab
commit 968d49de3d
15 changed files with 421 additions and 224 deletions
+10 -29
View File
@@ -13,8 +13,9 @@ import (
"path"
"time"
"github.com/open-policy-agent/opa/sdk"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/open-policy-agent/opa/metrics"
@@ -47,10 +48,10 @@ type Downloader struct {
path string // path to use in bundle download request
stop chan chan struct{} // used to signal plugin to stop running
f func(context.Context, Update) // callback function invoked when download updates occur
logAttrs [][2]string // optional attributes to include in log messages
etag string // HTTP Etag for caching purposes
sizeLimitBytes *int64 // max bundle file size in bytes (passed to reader)
bvc *bundle.VerificationConfig
logger sdk.Logger
}
// New returns a new Downloader that can be started.
@@ -60,6 +61,7 @@ func New(config Config, client rest.Client, path string) *Downloader {
client: client,
path: path,
stop: make(chan chan struct{}),
logger: client.Logger(),
}
}
@@ -71,8 +73,8 @@ func (d *Downloader) WithCallback(f func(context.Context, Update)) *Downloader {
// WithLogAttrs sets an optional set of key/value pair attributes to include in
// log messages emitted by the downloader.
func (d *Downloader) WithLogAttrs(attrs [][2]string) *Downloader {
d.logAttrs = attrs
func (d *Downloader) WithLogAttrs(attrs map[string]interface{}) *Downloader {
d.logger = d.logger.WithFields(attrs)
return d
}
@@ -123,7 +125,7 @@ func (d *Downloader) loop() {
delay = util.DefaultBackoff(float64(minRetryDelay), float64(*d.config.Polling.MaxDelaySeconds), retry)
}
d.logDebug("Waiting %v before next download/retry.", delay)
d.logger.Debug("Waiting %v before next download/retry.", delay)
timer := time.NewTimer(delay)
select {
@@ -155,8 +157,7 @@ func (d *Downloader) oneShot(ctx context.Context) error {
}
func (d *Downloader) download(ctx context.Context, m metrics.Metrics) (*bundle.Bundle, string, error) {
d.logDebug("Download starting.")
d.logger.Debug("Download starting.")
resp, err := d.client.WithHeader("If-None-Match", d.etag).Do(ctx, "GET", d.path)
if err != nil {
@@ -168,7 +169,7 @@ func (d *Downloader) download(ctx context.Context, m metrics.Metrics) (*bundle.B
switch resp.StatusCode {
case http.StatusOK:
if resp.Body != nil {
d.logDebug("Download in progress.")
d.logger.Debug("Download in progress.")
m.Timer(metrics.RegoLoadBundles).Start()
defer m.Timer(metrics.RegoLoadBundles).Stop()
baseURL := path.Join(d.client.Config().URL, d.path)
@@ -184,7 +185,7 @@ func (d *Downloader) download(ctx context.Context, m metrics.Metrics) (*bundle.B
return &b, resp.Header.Get("ETag"), nil
}
d.logDebug("Server replied with empty body.")
d.logger.Debug("Server replied with empty body.")
return nil, "", nil
case http.StatusNotModified:
@@ -197,23 +198,3 @@ func (d *Downloader) download(ctx context.Context, m metrics.Metrics) (*bundle.B
return nil, "", fmt.Errorf("server replied with HTTP %v", resp.StatusCode)
}
}
func (d *Downloader) logError(fmt string, a ...interface{}) {
logrus.WithFields(d.logrusFields()).Errorf(fmt, a...)
}
func (d *Downloader) logInfo(fmt string, a ...interface{}) {
logrus.WithFields(d.logrusFields()).Infof(fmt, a...)
}
func (d *Downloader) logDebug(fmt string, a ...interface{}) {
logrus.WithFields(d.logrusFields()).Debugf(fmt, a...)
}
func (d *Downloader) logrusFields() logrus.Fields {
flds := logrus.Fields{}
for i := range d.logAttrs {
flds[d.logAttrs[i][0]] = flds[d.logAttrs[i][1]]
}
return flds
}