Skip to content

Commit

Permalink
Direct plugin logs through vault's logger (#3142)
Browse files Browse the repository at this point in the history
* Direct plugin logs through vault's logger

* Pass in a logger in testConfig
  • Loading branch information
calvn authored Aug 15, 2017
1 parent e064863 commit e0c84d0
Show file tree
Hide file tree
Showing 8 changed files with 182 additions and 13 deletions.
5 changes: 3 additions & 2 deletions builtin/logical/database/dbplugin/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

"github.com/hashicorp/go-plugin"
"github.com/hashicorp/vault/helper/pluginutil"
log "github.com/mgutz/logxi/v1"
)

// DatabasePluginClient embeds a databasePluginRPCClient and wraps it's Close
Expand All @@ -29,13 +30,13 @@ func (dc *DatabasePluginClient) Close() error {
// newPluginClient returns a databaseRPCClient with a connection to a running
// plugin. The client is wrapped in a DatabasePluginClient object to ensure the
// plugin is killed on call of Close().
func newPluginClient(sys pluginutil.RunnerUtil, pluginRunner *pluginutil.PluginRunner) (Database, error) {
func newPluginClient(sys pluginutil.RunnerUtil, pluginRunner *pluginutil.PluginRunner, logger log.Logger) (Database, error) {
// pluginMap is the map of plugins we can dispense.
var pluginMap = map[string]plugin.Plugin{
"database": new(DatabasePlugin),
}

client, err := pluginRunner.Run(sys, pluginMap, handshakeConfig, []string{})
client, err := pluginRunner.Run(sys, pluginMap, handshakeConfig, []string{}, logger)
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion builtin/logical/database/dbplugin/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ func PluginFactory(pluginName string, sys pluginutil.LookRunnerUtil, logger log.

} else {
// create a DatabasePluginClient instance
db, err = newPluginClient(sys, pluginRunner)
db, err = newPluginClient(sys, pluginRunner, logger)
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion builtin/plugin/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func Backend(conf *logical.BackendConfig) (logical.Backend, error) {
name := conf.Config["plugin_name"]
sys := conf.System

b, err := bplugin.NewBackend(name, sys)
b, err := bplugin.NewBackend(name, sys, conf.Logger)
if err != nil {
return nil, err
}
Expand Down
4 changes: 3 additions & 1 deletion builtin/plugin/backend_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import (
"os"
"testing"

"github.com/hashicorp/vault/helper/logformat"
"github.com/hashicorp/vault/helper/pluginutil"
vaulthttp "github.com/hashicorp/vault/http"
"github.com/hashicorp/vault/logical"
"github.com/hashicorp/vault/logical/plugin"
"github.com/hashicorp/vault/logical/plugin/mock"
"github.com/hashicorp/vault/vault"
log "github.com/mgutz/logxi/v1"
)

func TestBackend(t *testing.T) {
Expand Down Expand Up @@ -71,7 +73,7 @@ func testConfig(t *testing.T) (*logical.BackendConfig, func()) {
sys := vault.TestDynamicSystemView(core.Core)

config := &logical.BackendConfig{
Logger: nil,
Logger: logformat.NewVaultLogger(log.LevelTrace),
System: sys,
Config: map[string]string{
"plugin_name": "mock-plugin",
Expand Down
158 changes: 158 additions & 0 deletions helper/pluginutil/logger.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
package pluginutil

import (
"bytes"
"fmt"
stdlog "log"
"strings"

hclog "github.com/hashicorp/go-hclog"
log "github.com/mgutz/logxi/v1"
)

// pluginLogFaker is a wrapper on logxi.Logger that
// implements hclog.Logger
type hclogFaker struct {
logger log.Logger

name string
implied []interface{}
}

func (f *hclogFaker) buildLog(msg string, args ...interface{}) (string, []interface{}) {
if f.name != "" {
msg = fmt.Sprintf("%s: %s", f.name, msg)
}
args = append(f.implied, args...)

return msg, args
}

func (f *hclogFaker) Trace(msg string, args ...interface{}) {
msg, args = f.buildLog(msg, args...)
f.logger.Trace(msg, args...)
}

func (f *hclogFaker) Debug(msg string, args ...interface{}) {
msg, args = f.buildLog(msg, args...)
f.logger.Debug(msg, args...)
}

func (f *hclogFaker) Info(msg string, args ...interface{}) {
msg, args = f.buildLog(msg, args...)
f.logger.Info(msg, args...)
}

func (f *hclogFaker) Warn(msg string, args ...interface{}) {
msg, args = f.buildLog(msg, args...)
f.logger.Warn(msg, args...)
}

func (f *hclogFaker) Error(msg string, args ...interface{}) {
msg, args = f.buildLog(msg, args...)
f.logger.Error(msg, args...)
}

func (f *hclogFaker) IsTrace() bool {
return f.logger.IsTrace()
}

func (f *hclogFaker) IsDebug() bool {
return f.logger.IsDebug()
}

func (f *hclogFaker) IsInfo() bool {
return f.logger.IsInfo()
}

func (f *hclogFaker) IsWarn() bool {
return f.logger.IsWarn()
}

func (f *hclogFaker) IsError() bool {
return !f.logger.IsTrace() && !f.logger.IsDebug() && !f.logger.IsInfo() && !f.IsWarn()
}

func (f *hclogFaker) With(args ...interface{}) hclog.Logger {
var nf = *f
nf.implied = append(nf.implied, args...)
return f
}

func (f *hclogFaker) Named(name string) hclog.Logger {
var nf = *f
if nf.name != "" {
nf.name = nf.name + "." + name
}
return &nf
}

func (f *hclogFaker) ResetNamed(name string) hclog.Logger {
var nf = *f
nf.name = name
return &nf
}

func (f *hclogFaker) StandardLogger(opts *hclog.StandardLoggerOptions) *stdlog.Logger {
if opts == nil {
opts = &hclog.StandardLoggerOptions{}
}

return stdlog.New(&stdlogAdapter{f, opts.InferLevels}, "", 0)
}

// Provides a io.Writer to shim the data out of *log.Logger
// and back into our Logger. This is basically the only way to
// build upon *log.Logger.
type stdlogAdapter struct {
hl hclog.Logger
inferLevels bool
}

// Take the data, infer the levels if configured, and send it through
// a regular Logger
func (s *stdlogAdapter) Write(data []byte) (int, error) {
str := string(bytes.TrimRight(data, " \t\n"))

if s.inferLevels {
level, str := s.pickLevel(str)
switch level {
case hclog.Trace:
s.hl.Trace(str)
case hclog.Debug:
s.hl.Debug(str)
case hclog.Info:
s.hl.Info(str)
case hclog.Warn:
s.hl.Warn(str)
case hclog.Error:
s.hl.Error(str)
default:
s.hl.Info(str)
}
} else {
s.hl.Info(str)
}

return len(data), nil
}

// Detect, based on conventions, what log level this is
func (s *stdlogAdapter) pickLevel(str string) (hclog.Level, string) {
switch {
case strings.HasPrefix(str, "[DEBUG]"):
return hclog.Debug, strings.TrimSpace(str[7:])
case strings.HasPrefix(str, "[TRACE]"):
return hclog.Trace, strings.TrimSpace(str[7:])
case strings.HasPrefix(str, "[INFO]"):
return hclog.Info, strings.TrimSpace(str[6:])
case strings.HasPrefix(str, "[WARN]"):
return hclog.Warn, strings.TrimSpace(str[7:])
case strings.HasPrefix(str, "[ERROR]"):
return hclog.Error, strings.TrimSpace(str[7:])
case strings.HasPrefix(str, "[ERR]"):
return hclog.Error, strings.TrimSpace(str[5:])
default:
return hclog.Info, str
}
}
10 changes: 9 additions & 1 deletion helper/pluginutil/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
plugin "github.com/hashicorp/go-plugin"
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/helper/wrapping"
log "github.com/mgutz/logxi/v1"
)

// Looker defines the plugin Lookup function that looks into the plugin catalog
Expand Down Expand Up @@ -45,7 +46,7 @@ type PluginRunner struct {

// Run takes a wrapper instance, and the go-plugin paramaters and executes a
// plugin.
func (r *PluginRunner) Run(wrapper RunnerUtil, pluginMap map[string]plugin.Plugin, hs plugin.HandshakeConfig, env []string) (*plugin.Client, error) {
func (r *PluginRunner) Run(wrapper RunnerUtil, pluginMap map[string]plugin.Plugin, hs plugin.HandshakeConfig, env []string, logger log.Logger) (*plugin.Client, error) {
// Get a CA TLS Certificate
certBytes, key, err := generateCert()
if err != nil {
Expand Down Expand Up @@ -79,12 +80,19 @@ func (r *PluginRunner) Run(wrapper RunnerUtil, pluginMap map[string]plugin.Plugi
Hash: sha256.New(),
}

// Create logger for the plugin client
clogger := &hclogFaker{
logger: logger,
}
namedLogger := clogger.ResetNamed("plugin")

client := plugin.NewClient(&plugin.ClientConfig{
HandshakeConfig: hs,
Plugins: pluginMap,
Cmd: cmd,
TLSConfig: clientTLSConfig,
SecureConfig: secureConfig,
Logger: namedLogger,
})

return client, nil
Expand Down
5 changes: 2 additions & 3 deletions logical/plugin/backend_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,8 @@ import (
// backendPluginClient implements logical.Backend and is the
// go-plugin client.
type backendPluginClient struct {
broker *plugin.MuxBroker
client *rpc.Client
pluginClient *plugin.Client
broker *plugin.MuxBroker
client *rpc.Client

system logical.SystemView
logger log.Logger
Expand Down
9 changes: 5 additions & 4 deletions logical/plugin/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/hashicorp/go-plugin"
"github.com/hashicorp/vault/helper/pluginutil"
"github.com/hashicorp/vault/logical"
log "github.com/mgutz/logxi/v1"
)

// Register these types since we have to serialize and de-serialize tls.ConnectionState
Expand Down Expand Up @@ -40,7 +41,7 @@ func (b *BackendPluginClient) Cleanup() {
// NewBackend will return an instance of an RPC-based client implementation of the backend for
// external plugins, or a concrete implementation of the backend if it is a builtin backend.
// The backend is returned as a logical.Backend interface.
func NewBackend(pluginName string, sys pluginutil.LookRunnerUtil) (logical.Backend, error) {
func NewBackend(pluginName string, sys pluginutil.LookRunnerUtil, logger log.Logger) (logical.Backend, error) {
// Look for plugin in the plugin catalog
pluginRunner, err := sys.LookupPlugin(pluginName)
if err != nil {
Expand All @@ -64,7 +65,7 @@ func NewBackend(pluginName string, sys pluginutil.LookRunnerUtil) (logical.Backe

} else {
// create a backendPluginClient instance
backend, err = newPluginClient(sys, pluginRunner)
backend, err = newPluginClient(sys, pluginRunner, logger)
if err != nil {
return nil, err
}
Expand All @@ -73,12 +74,12 @@ func NewBackend(pluginName string, sys pluginutil.LookRunnerUtil) (logical.Backe
return backend, nil
}

func newPluginClient(sys pluginutil.RunnerUtil, pluginRunner *pluginutil.PluginRunner) (logical.Backend, error) {
func newPluginClient(sys pluginutil.RunnerUtil, pluginRunner *pluginutil.PluginRunner, logger log.Logger) (logical.Backend, error) {
// pluginMap is the map of plugins we can dispense.
pluginMap := map[string]plugin.Plugin{
"backend": &BackendPlugin{},
}
client, err := pluginRunner.Run(sys, pluginMap, handshakeConfig, []string{})
client, err := pluginRunner.Run(sys, pluginMap, handshakeConfig, []string{}, logger)
if err != nil {
return nil, err
}
Expand Down

0 comments on commit e0c84d0

Please sign in to comment.