Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add endpoints to provide ability to modify logging verbosity #16111

Merged
merged 12 commits into from
Jun 27, 2022
3 changes: 3 additions & 0 deletions changelog/16111.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:improvement
core: Add `sys/loggers` and `sys/loggers/:name` endpoints to provide ability to modify logging verbosity
```
18 changes: 11 additions & 7 deletions command/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -460,8 +460,9 @@ func (c *ServerCommand) runRecoveryMode() int {
}

c.logger = hclog.NewInterceptLogger(&hclog.LoggerOptions{
Output: c.gatedWriter,
Level: level,
Output: c.gatedWriter,
Level: level,
IndependentLevels: true,
// Note that if logFormat is either unspecified or standard, then
// the resulting logger's format will be standard.
JSONFormat: logFormat == logging.JSONFormat,
Expand Down Expand Up @@ -592,6 +593,7 @@ func (c *ServerCommand) runRecoveryMode() int {
Physical: backend,
StorageType: config.Storage.Type,
Seal: barrierSeal,
LogLevel: logLevelString,
Logger: c.logger,
DisableMlock: config.DisableMlock,
RecoveryMode: c.flagRecovery,
Expand Down Expand Up @@ -1116,14 +1118,16 @@ func (c *ServerCommand) Run(args []string) int {

if c.flagDevThreeNode || c.flagDevFourCluster {
c.logger = hclog.NewInterceptLogger(&hclog.LoggerOptions{
Mutex: &sync.Mutex{},
Output: c.gatedWriter,
Level: hclog.Trace,
Mutex: &sync.Mutex{},
Output: c.gatedWriter,
Level: hclog.Trace,
IndependentLevels: true,
})
} else {
c.logger = hclog.NewInterceptLogger(&hclog.LoggerOptions{
Output: c.gatedWriter,
Level: level,
Output: c.gatedWriter,
Level: level,
IndependentLevels: true,
// Note that if logFormat is either unspecified or standard, then
// the resulting logger's format will be standard.
JSONFormat: logFormat == logging.JSONFormat,
Expand Down
7 changes: 4 additions & 3 deletions sdk/helper/logging/logging.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,10 @@ func NewVaultLogger(level log.Level) log.Logger {
// writer and a Vault formatter
func NewVaultLoggerWithWriter(w io.Writer, level log.Level) log.Logger {
opts := &log.LoggerOptions{
Level: level,
Output: w,
JSONFormat: ParseEnvLogFormat() == JSONFormat,
Level: level,
IndependentLevels: true,
Output: w,
JSONFormat: ParseEnvLogFormat() == JSONFormat,
}
return log.New(opts)
}
Expand Down
9 changes: 7 additions & 2 deletions vault/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -318,14 +318,19 @@ func (c *Core) startClusterListener(ctx context.Context) error {
networkLayer := c.clusterNetworkLayer

if networkLayer == nil {
networkLayer = cluster.NewTCPLayer(c.clusterListenerAddrs, c.logger.Named("cluster-listener.tcp"))
tcpLogger := c.logger.Named("cluster-listener.tcp")
networkLayer = cluster.NewTCPLayer(c.clusterListenerAddrs, tcpLogger)
c.AddLogger(tcpLogger)
}

listenerLogger := c.logger.Named("cluster-listener")
c.clusterListener.Store(cluster.NewListener(networkLayer,
c.clusterCipherSuites,
c.logger.Named("cluster-listener"),
listenerLogger,
5*c.clusterHeartbeatInterval))

c.AddLogger(listenerLogger)

err := c.getClusterListener().Run(ctx)
if err != nil {
return err
Expand Down
23 changes: 23 additions & 0 deletions vault/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,9 @@ type Core struct {
baseLogger log.Logger
logger log.Logger

// log level provided by config, CLI flag, or env
logLevel string

// Disables the trace display for Sentinel checks
sentinelTraceDisabled bool

Expand Down Expand Up @@ -665,6 +668,8 @@ type CoreConfig struct {

SecureRandomReader io.Reader

LogLevel string

Logger log.Logger

// Disables the trace display for Sentinel checks
Expand Down Expand Up @@ -848,6 +853,7 @@ func CreateCore(conf *CoreConfig) (*Core, error) {
standbyStopCh: new(atomic.Value),
baseLogger: conf.Logger,
logger: conf.Logger.Named("core"),
logLevel: conf.LogLevel,

defaultLeaseTTL: conf.DefaultLeaseTTL,
maxLeaseTTL: conf.MaxLeaseTTL,
Expand Down Expand Up @@ -1034,6 +1040,10 @@ func NewCore(conf *CoreConfig) (*Core, error) {

c.loginMFABackend = NewLoginMFABackend(c, conf.Logger)

if c.loginMFABackend.mfaLogger != nil {
c.AddLogger(c.loginMFABackend.mfaLogger)
}

logicalBackends := make(map[string]logical.Factory)
for k, f := range conf.LogicalBackends {
logicalBackends[k] = f
Expand Down Expand Up @@ -2816,6 +2826,19 @@ func (c *Core) SetLogLevel(level log.Level) {
}
}

func (c *Core) SetLogLevelByName(name string, level log.Level) error {
c.allLoggersLock.RLock()
defer c.allLoggersLock.RUnlock()
for _, logger := range c.allLoggers {
if logger.Name() == name {
ncabatoff marked this conversation as resolved.
Show resolved Hide resolved
logger.SetLevel(level)
return nil
}
}

return fmt.Errorf("logger %q does not exist", name)
}

// SetConfig sets core's config object to the newly provided config.
func (c *Core) SetConfig(conf *server.Config) {
c.rawConfig.Store(conf)
Expand Down
8 changes: 6 additions & 2 deletions vault/expiration.go
Original file line number Diff line number Diff line change
Expand Up @@ -313,9 +313,12 @@ func getNumExpirationWorkers(c *Core, l log.Logger) int {
// NewExpirationManager creates a new ExpirationManager that is backed
// using a given view, and uses the provided router for revocation.
func NewExpirationManager(c *Core, view *BarrierView, e ExpireLeaseStrategy, logger log.Logger) *ExpirationManager {
jobManager := fairshare.NewJobManager("expire", getNumExpirationWorkers(c, logger), logger.Named("job-manager"), c.metricSink)
managerLogger := logger.Named("job-manager")
jobManager := fairshare.NewJobManager("expire", getNumExpirationWorkers(c, logger), managerLogger, c.metricSink)
jobManager.Start()

c.AddLogger(managerLogger)

exp := &ExpirationManager{
core: c,
router: c.router,
Expand Down Expand Up @@ -1268,7 +1271,8 @@ func (m *ExpirationManager) Renew(ctx context.Context, leaseID string, increment
// RenewToken is used to renew a token which does not need to
// invoke a logical backend.
func (m *ExpirationManager) RenewToken(ctx context.Context, req *logical.Request, te *logical.TokenEntry,
increment time.Duration) (*logical.Response, error) {
increment time.Duration,
) (*logical.Response, error) {
defer metrics.MeasureSince([]string{"expire", "renew-token"}, time.Now())

tokenNS, err := NamespaceByID(ctx, te.NamespaceID, m.core)
Expand Down
106 changes: 106 additions & 0 deletions vault/logical_system.go
Original file line number Diff line number Diff line change
Expand Up @@ -4436,6 +4436,112 @@ func (b *SystemBackend) handleVersionHistoryList(ctx context.Context, req *logic
return logical.ListResponseWithInfo(respKeys, respKeyInfo), nil
}

// getLogLevel returns the hclog.Level that corresponds with the provided level string.
// This differs hclog.LevelFromString in that it supports additional level strings so
// that in remains consistent with the handling found in the "vault server" command.
func getLogLevel(logLevel string) (log.Level, error) {
ncabatoff marked this conversation as resolved.
Show resolved Hide resolved
var level log.Level

switch logLevel {
case "trace":
level = log.Trace
case "debug":
level = log.Debug
case "notice", "info", "":
level = log.Info
case "warn", "warning":
level = log.Warn
case "err", "error":
level = log.Error
default:
return level, fmt.Errorf("unrecognized log level %q", logLevel)
}

return level, nil
}

func (b *SystemBackend) handleLoggersWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
logLevelRaw, ok := d.GetOk("level")

if !ok {
return logical.ErrorResponse("level is required"), nil
}

logLevel := logLevelRaw.(string)
if logLevel == "" {
return logical.ErrorResponse("level is empty"), nil
}

level, err := getLogLevel(logLevel)
if err != nil {
return logical.ErrorResponse(fmt.Sprintf("invalid level provided: %s", err.Error())), nil
}

b.Core.SetLogLevel(level)

return nil, nil
}

func (b *SystemBackend) handleLoggersDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
level, err := getLogLevel(b.Core.logLevel)
if err != nil {
return logical.ErrorResponse(fmt.Sprintf("log level from config is invalid: %s", err.Error())), nil
}

b.Core.SetLogLevel(level)

return nil, nil
}

func (b *SystemBackend) handleLoggersByNameWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
nameRaw, nameOk := d.GetOk("name")
if !nameOk {
return logical.ErrorResponse("name is required"), nil
}

logLevelRaw, logLevelOk := d.GetOk("level")

if !logLevelOk {
return logical.ErrorResponse("level is required"), nil
}

logLevel := logLevelRaw.(string)
if logLevel == "" {
return logical.ErrorResponse("level is empty"), nil
}

level, err := getLogLevel(logLevel)
if err != nil {
return logical.ErrorResponse(fmt.Sprintf("invalid level provided: %s", err.Error())), nil
}

err = b.Core.SetLogLevelByName(nameRaw.(string), level)
if err != nil {
return logical.ErrorResponse(fmt.Sprintf("invalid params: %s", err.Error())), nil
}

return nil, nil
}

func (b *SystemBackend) handleLoggersByNameDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
nameRaw, ok := d.GetOk("name")
if !ok {
return logical.ErrorResponse("name is required"), nil
}

level, err := getLogLevel(b.Core.logLevel)
if err != nil {
return logical.ErrorResponse(fmt.Sprintf("log level from config is invalid: %s", err.Error())), nil
}

err = b.Core.SetLogLevelByName(nameRaw.(string), level)
if err != nil {
return logical.ErrorResponse(fmt.Sprintf("invalid params: %s", err.Error())), nil
}

return nil, nil
}

func sanitizePath(path string) string {
if !strings.HasSuffix(path, "/") {
path += "/"
Expand Down
44 changes: 44 additions & 0 deletions vault/logical_system_paths.go
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,50 @@ func (b *SystemBackend) configPaths() []*framework.Path {
},
},
},
{
Pattern: "loggers$",
Fields: map[string]*framework.FieldSchema{
"level": {
Type: framework.TypeString,
Description: "Log verbosity level. Supported values (in order of detail) are " +
"\"trace\", \"debug\", \"info\", \"warn\", and \"error\".",
},
},
Operations: map[logical.Operation]framework.OperationHandler{
logical.UpdateOperation: &framework.PathOperation{
Callback: b.handleLoggersWrite,
Summary: "Modify the log level for all existing loggers.",
},
logical.DeleteOperation: &framework.PathOperation{
Callback: b.handleLoggersDelete,
Summary: "Revert the all loggers to use log level provided in config.",
},
},
},
{
Pattern: "loggers/" + framework.MatchAllRegex("name"),
Fields: map[string]*framework.FieldSchema{
"name": {
Type: framework.TypeString,
Description: "The name of the logger to be modified.",
},
"level": {
Type: framework.TypeString,
Description: "Log verbosity level. Supported values (in order of detail) are " +
"\"trace\", \"debug\", \"info\", \"warn\", and \"error\".",
},
},
Operations: map[logical.Operation]framework.OperationHandler{
logical.UpdateOperation: &framework.PathOperation{
Callback: b.handleLoggersByNameWrite,
Summary: "Modify the log level of a single logger.",
},
logical.DeleteOperation: &framework.PathOperation{
Callback: b.handleLoggersByNameDelete,
Summary: "Revert a single logger to use log level provided in config.",
},
},
},
}
}

Expand Down
Loading