Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ require (
github.com/golang/protobuf v1.5.4
github.com/google/uuid v1.6.0
github.com/grpc-ecosystem/grpc-gateway v1.16.0
github.com/hashicorp/go-hclog v1.6.3
github.com/hashicorp/go-plugin v1.8.0
github.com/influxdata/influxdb-client-go/v2 v2.14.0
github.com/juju/ansiterm v1.0.0
Expand Down Expand Up @@ -125,7 +126,6 @@ require (
github.com/gregdel/pushover v1.3.1 // indirect
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-hclog v1.6.3 // indirect
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
github.com/hashicorp/yamux v0.1.2 // indirect
github.com/huandu/xstrings v1.5.0 // indirect
Expand Down
28 changes: 28 additions & 0 deletions metricproviders/plugin/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@ package client

import (
"fmt"
"io"
"os/exec"
"sync"

"github.com/hashicorp/go-hclog"
goPlugin "github.com/hashicorp/go-plugin"
log "github.com/sirupsen/logrus"

"github.com/argoproj/argo-rollouts/metricproviders/plugin/rpc"
"github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1"
Expand Down Expand Up @@ -68,6 +71,7 @@ func (m *metricPlugin) startPluginSystem(metric v1alpha1.Metric) (rpc.MetricProv
Plugins: pluginMap,
Cmd: exec.Command(pluginPath, args...),
Managed: true,
Logger: newPluginLogger(),
})

rpcClient, err := m.pluginClient[pluginName].Client()
Expand Down Expand Up @@ -108,3 +112,27 @@ func (m *metricPlugin) startPluginSystem(metric v1alpha1.Metric) (rpc.MetricProv

return nil, fmt.Errorf("no plugin found")
}

// newPluginLogger builds the hclog.Logger used for the go-plugin client's own log output
// (handshake/lifecycle logs, and the plugin process's stderr relay). By default go-plugin
// falls back to its own unstructured text logger whenever ClientConfig.Logger is nil, which
// is inconsistent with the controller's own logs when the controller is run with
// `--logformat json`: every other component's logs are JSON, but metric plugin logs remain
// plain text. When the controller's standard logger is configured for JSON output, mirror
// that here so the plugin logger's output is JSON too. Returns nil (go-plugin's own default
// logger) in every other case, preserving prior behavior exactly.
func newPluginLogger() hclog.Logger {
return newPluginLoggerWithOutput(hclog.DefaultOutput)
}

func newPluginLoggerWithOutput(w io.Writer) hclog.Logger {
if _, ok := log.StandardLogger().Formatter.(*log.JSONFormatter); !ok {
return nil
}
return hclog.New(&hclog.LoggerOptions{
Output: w,
Level: hclog.Trace,
Name: "plugin",
JSONFormat: true,
})
}
41 changes: 41 additions & 0 deletions metricproviders/plugin/client/client_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package client

import (
"bytes"
"encoding/json"
"testing"

log "github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert"
)

// TestNewPluginLoggerRespectsControllerLogFormat verifies that the go-plugin client's own
// logger mirrors the controller's configured log format. Before this fix, the plugin
// client's Logger field was always left unset, so go-plugin always fell back to its
// unstructured, hardcoded-text default logger regardless of the controller's own
// `--logformat json` setting.
func TestNewPluginLoggerRespectsControllerLogFormat(t *testing.T) {
origFormatter := log.StandardLogger().Formatter
defer log.StandardLogger().SetFormatter(origFormatter)

t.Run("default text logformat leaves go-plugin's own default logger untouched", func(t *testing.T) {
log.StandardLogger().SetFormatter(&log.TextFormatter{})
logger := newPluginLogger()
assert.Nil(t, logger, "expected nil so go-plugin falls back to its own default logger")
})

t.Run("json logformat produces a JSON plugin logger", func(t *testing.T) {
log.StandardLogger().SetFormatter(&log.JSONFormatter{})

var buf bytes.Buffer
logger := newPluginLoggerWithOutput(&buf)
assert.NotNil(t, logger)

logger.Info("plugin log line", "plugin", "my-plugin")

var parsed map[string]any
err := json.Unmarshal(buf.Bytes(), &parsed)
assert.NoError(t, err, "expected the plugin logger to emit a single JSON object, got: %s", buf.String())
assert.Equal(t, "plugin log line", parsed["@message"])
})
}
Loading