VAULT-9427: Add read support to sys/loggers
endpoints (#17979)
* add logger->log-level str func * ensure SetLogLevelByName accounts for duplicates * add read handlers for sys/loggers endpoints * add changelog entry * update docs * ignore base logger * fix docs formatting issue * add ReadOperation support to TestSystemBackend_Loggers * add more robust checks to TestSystemBackend_Loggers * add more robust checks to TestSystemBackend_LoggersByName * check for empty name in delete handler
This commit is contained in:
parent
a04855c98d
commit
2843cfcdc1
3
changelog/17979.txt
Normal file
3
changelog/17979.txt
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
```release-note:improvement
|
||||||
|
core: Add read support to `sys/loggers` and `sys/loggers/:name` endpoints
|
||||||
|
```
|
|
@ -112,6 +112,8 @@ func ParseLogFormat(format string) (LogFormat, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ParseLogLevel returns the hclog.Level that corresponds with the provided level string.
|
||||||
|
// This differs hclog.LevelFromString in that it supports additional level strings.
|
||||||
func ParseLogLevel(logLevel string) (log.Level, error) {
|
func ParseLogLevel(logLevel string) (log.Level, error) {
|
||||||
var result log.Level
|
var result log.Level
|
||||||
logLevel = strings.ToLower(strings.TrimSpace(logLevel))
|
logLevel = strings.ToLower(strings.TrimSpace(logLevel))
|
||||||
|
@ -133,3 +135,24 @@ func ParseLogLevel(logLevel string) (log.Level, error) {
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TranslateLoggerLevel returns the string that corresponds with logging level of the hclog.Logger.
|
||||||
|
func TranslateLoggerLevel(logger log.Logger) (string, error) {
|
||||||
|
var result string
|
||||||
|
|
||||||
|
if logger.IsTrace() {
|
||||||
|
result = "trace"
|
||||||
|
} else if logger.IsDebug() {
|
||||||
|
result = "debug"
|
||||||
|
} else if logger.IsInfo() {
|
||||||
|
result = "info"
|
||||||
|
} else if logger.IsWarn() {
|
||||||
|
result = "warn"
|
||||||
|
} else if logger.IsError() {
|
||||||
|
result = "error"
|
||||||
|
} else {
|
||||||
|
return "", fmt.Errorf("unknown log level")
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
|
@ -2866,6 +2866,7 @@ func (c *Core) AddLogger(logger log.Logger) {
|
||||||
c.allLoggers = append(c.allLoggers, logger)
|
c.allLoggers = append(c.allLoggers, logger)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetLogLevel sets logging level for all tracked loggers to the level provided
|
||||||
func (c *Core) SetLogLevel(level log.Level) {
|
func (c *Core) SetLogLevel(level log.Level) {
|
||||||
c.allLoggersLock.RLock()
|
c.allLoggersLock.RLock()
|
||||||
defer c.allLoggersLock.RUnlock()
|
defer c.allLoggersLock.RUnlock()
|
||||||
|
@ -2874,17 +2875,22 @@ func (c *Core) SetLogLevel(level log.Level) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Core) SetLogLevelByName(name string, level log.Level) error {
|
// SetLogLevelByName sets the logging level of named logger to level provided
|
||||||
|
// if it exists. Core.allLoggers is a slice and as such it is entirely possible
|
||||||
|
// that multiple entries exist for the same name. Each instance will be modified.
|
||||||
|
func (c *Core) SetLogLevelByName(name string, level log.Level) bool {
|
||||||
c.allLoggersLock.RLock()
|
c.allLoggersLock.RLock()
|
||||||
defer c.allLoggersLock.RUnlock()
|
defer c.allLoggersLock.RUnlock()
|
||||||
|
|
||||||
|
found := false
|
||||||
for _, logger := range c.allLoggers {
|
for _, logger := range c.allLoggers {
|
||||||
if logger.Name() == name {
|
if logger.Name() == name {
|
||||||
logger.SetLevel(level)
|
logger.SetLevel(level)
|
||||||
return nil
|
found = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Errorf("logger %q does not exist", name)
|
return found
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetConfig sets core's config object to the newly provided config.
|
// SetConfig sets core's config object to the newly provided config.
|
||||||
|
|
|
@ -20,9 +20,6 @@ import (
|
||||||
"time"
|
"time"
|
||||||
"unicode"
|
"unicode"
|
||||||
|
|
||||||
"github.com/hashicorp/vault/helper/versions"
|
|
||||||
"golang.org/x/crypto/sha3"
|
|
||||||
|
|
||||||
"github.com/hashicorp/errwrap"
|
"github.com/hashicorp/errwrap"
|
||||||
log "github.com/hashicorp/go-hclog"
|
log "github.com/hashicorp/go-hclog"
|
||||||
"github.com/hashicorp/go-memdb"
|
"github.com/hashicorp/go-memdb"
|
||||||
|
@ -32,10 +29,12 @@ import (
|
||||||
semver "github.com/hashicorp/go-version"
|
semver "github.com/hashicorp/go-version"
|
||||||
"github.com/hashicorp/vault/helper/hostutil"
|
"github.com/hashicorp/vault/helper/hostutil"
|
||||||
"github.com/hashicorp/vault/helper/identity"
|
"github.com/hashicorp/vault/helper/identity"
|
||||||
|
"github.com/hashicorp/vault/helper/logging"
|
||||||
"github.com/hashicorp/vault/helper/metricsutil"
|
"github.com/hashicorp/vault/helper/metricsutil"
|
||||||
"github.com/hashicorp/vault/helper/monitor"
|
"github.com/hashicorp/vault/helper/monitor"
|
||||||
"github.com/hashicorp/vault/helper/namespace"
|
"github.com/hashicorp/vault/helper/namespace"
|
||||||
"github.com/hashicorp/vault/helper/random"
|
"github.com/hashicorp/vault/helper/random"
|
||||||
|
"github.com/hashicorp/vault/helper/versions"
|
||||||
"github.com/hashicorp/vault/sdk/framework"
|
"github.com/hashicorp/vault/sdk/framework"
|
||||||
"github.com/hashicorp/vault/sdk/helper/consts"
|
"github.com/hashicorp/vault/sdk/helper/consts"
|
||||||
"github.com/hashicorp/vault/sdk/helper/jsonutil"
|
"github.com/hashicorp/vault/sdk/helper/jsonutil"
|
||||||
|
@ -44,6 +43,7 @@ import (
|
||||||
"github.com/hashicorp/vault/sdk/logical"
|
"github.com/hashicorp/vault/sdk/logical"
|
||||||
"github.com/hashicorp/vault/sdk/version"
|
"github.com/hashicorp/vault/sdk/version"
|
||||||
"github.com/mitchellh/mapstructure"
|
"github.com/mitchellh/mapstructure"
|
||||||
|
"golang.org/x/crypto/sha3"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -4833,28 +4833,35 @@ func (b *SystemBackend) handleVersionHistoryList(ctx context.Context, req *logic
|
||||||
return logical.ListResponseWithInfo(respKeys, respKeyInfo), nil
|
return logical.ListResponseWithInfo(respKeys, respKeyInfo), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// getLogLevel returns the hclog.Level that corresponds with the provided level string.
|
func (b *SystemBackend) handleLoggersRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
|
||||||
// This differs hclog.LevelFromString in that it supports additional level strings so
|
b.Core.allLoggersLock.RLock()
|
||||||
// that in remains consistent with the handling found in the "vault server" command.
|
defer b.Core.allLoggersLock.RUnlock()
|
||||||
func getLogLevel(logLevel string) (log.Level, error) {
|
|
||||||
var level log.Level
|
|
||||||
|
|
||||||
switch logLevel {
|
loggers := make(map[string]interface{})
|
||||||
case "trace":
|
warnings := make([]string, 0)
|
||||||
level = log.Trace
|
|
||||||
case "debug":
|
for _, logger := range b.Core.allLoggers {
|
||||||
level = log.Debug
|
loggerName := logger.Name()
|
||||||
case "notice", "info", "":
|
|
||||||
level = log.Info
|
// ignore base logger
|
||||||
case "warn", "warning":
|
if loggerName == "" {
|
||||||
level = log.Warn
|
continue
|
||||||
case "err", "error":
|
|
||||||
level = log.Error
|
|
||||||
default:
|
|
||||||
return level, fmt.Errorf("unrecognized log level %q", logLevel)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return level, nil
|
logLevel, err := logging.TranslateLoggerLevel(logger)
|
||||||
|
if err != nil {
|
||||||
|
warnings = append(warnings, fmt.Sprintf("cannot translate level for %q: %s", loggerName, err.Error()))
|
||||||
|
} else {
|
||||||
|
loggers[loggerName] = logLevel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &logical.Response{
|
||||||
|
Data: loggers,
|
||||||
|
Warnings: warnings,
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *SystemBackend) handleLoggersWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
|
func (b *SystemBackend) handleLoggersWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
|
||||||
|
@ -4869,7 +4876,7 @@ func (b *SystemBackend) handleLoggersWrite(ctx context.Context, req *logical.Req
|
||||||
return logical.ErrorResponse("level is empty"), nil
|
return logical.ErrorResponse("level is empty"), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
level, err := getLogLevel(logLevel)
|
level, err := logging.ParseLogLevel(logLevel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return logical.ErrorResponse(fmt.Sprintf("invalid level provided: %s", err.Error())), nil
|
return logical.ErrorResponse(fmt.Sprintf("invalid level provided: %s", err.Error())), nil
|
||||||
}
|
}
|
||||||
|
@ -4880,7 +4887,7 @@ func (b *SystemBackend) handleLoggersWrite(ctx context.Context, req *logical.Req
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *SystemBackend) handleLoggersDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
|
func (b *SystemBackend) handleLoggersDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
|
||||||
level, err := getLogLevel(b.Core.logLevel)
|
level, err := logging.ParseLogLevel(b.Core.logLevel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return logical.ErrorResponse(fmt.Sprintf("log level from config is invalid: %s", err.Error())), nil
|
return logical.ErrorResponse(fmt.Sprintf("log level from config is invalid: %s", err.Error())), nil
|
||||||
}
|
}
|
||||||
|
@ -4890,12 +4897,63 @@ func (b *SystemBackend) handleLoggersDelete(ctx context.Context, req *logical.Re
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *SystemBackend) handleLoggersByNameRead(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
|
||||||
|
}
|
||||||
|
|
||||||
|
name := nameRaw.(string)
|
||||||
|
if name == "" {
|
||||||
|
return logical.ErrorResponse("name is empty"), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
b.Core.allLoggersLock.RLock()
|
||||||
|
defer b.Core.allLoggersLock.RUnlock()
|
||||||
|
|
||||||
|
loggers := make(map[string]interface{})
|
||||||
|
warnings := make([]string, 0)
|
||||||
|
|
||||||
|
for _, logger := range b.Core.allLoggers {
|
||||||
|
loggerName := logger.Name()
|
||||||
|
|
||||||
|
// ignore base logger
|
||||||
|
if loggerName == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if loggerName == name {
|
||||||
|
logLevel, err := logging.TranslateLoggerLevel(logger)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
warnings = append(warnings, fmt.Sprintf("cannot translate level for %q: %s", loggerName, err.Error()))
|
||||||
|
} else {
|
||||||
|
loggers[loggerName] = logLevel
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &logical.Response{
|
||||||
|
Data: loggers,
|
||||||
|
Warnings: warnings,
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (b *SystemBackend) handleLoggersByNameWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
|
func (b *SystemBackend) handleLoggersByNameWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
|
||||||
nameRaw, nameOk := d.GetOk("name")
|
nameRaw, nameOk := d.GetOk("name")
|
||||||
if !nameOk {
|
if !nameOk {
|
||||||
return logical.ErrorResponse("name is required"), nil
|
return logical.ErrorResponse("name is required"), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
name := nameRaw.(string)
|
||||||
|
if name == "" {
|
||||||
|
return logical.ErrorResponse("name is empty"), nil
|
||||||
|
}
|
||||||
|
|
||||||
logLevelRaw, logLevelOk := d.GetOk("level")
|
logLevelRaw, logLevelOk := d.GetOk("level")
|
||||||
|
|
||||||
if !logLevelOk {
|
if !logLevelOk {
|
||||||
|
@ -4907,14 +4965,14 @@ func (b *SystemBackend) handleLoggersByNameWrite(ctx context.Context, req *logic
|
||||||
return logical.ErrorResponse("level is empty"), nil
|
return logical.ErrorResponse("level is empty"), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
level, err := getLogLevel(logLevel)
|
level, err := logging.ParseLogLevel(logLevel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return logical.ErrorResponse(fmt.Sprintf("invalid level provided: %s", err.Error())), nil
|
return logical.ErrorResponse(fmt.Sprintf("invalid level provided: %s", err.Error())), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
err = b.Core.SetLogLevelByName(nameRaw.(string), level)
|
success := b.Core.SetLogLevelByName(name, level)
|
||||||
if err != nil {
|
if !success {
|
||||||
return logical.ErrorResponse(fmt.Sprintf("invalid params: %s", err.Error())), nil
|
return logical.ErrorResponse(fmt.Sprintf("logger %q not found", name)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
@ -4926,14 +4984,19 @@ func (b *SystemBackend) handleLoggersByNameDelete(ctx context.Context, req *logi
|
||||||
return logical.ErrorResponse("name is required"), nil
|
return logical.ErrorResponse("name is required"), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
level, err := getLogLevel(b.Core.logLevel)
|
level, err := logging.ParseLogLevel(b.Core.logLevel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return logical.ErrorResponse(fmt.Sprintf("log level from config is invalid: %s", err.Error())), nil
|
return logical.ErrorResponse(fmt.Sprintf("log level from config is invalid: %s", err.Error())), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
err = b.Core.SetLogLevelByName(nameRaw.(string), level)
|
name := nameRaw.(string)
|
||||||
if err != nil {
|
if name == "" {
|
||||||
return logical.ErrorResponse(fmt.Sprintf("invalid params: %s", err.Error())), nil
|
return logical.ErrorResponse("name is empty"), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
success := b.Core.SetLogLevelByName(name, level)
|
||||||
|
if !success {
|
||||||
|
return logical.ErrorResponse(fmt.Sprintf("logger %q not found", name)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
|
|
@ -298,6 +298,10 @@ func (b *SystemBackend) configPaths() []*framework.Path {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Operations: map[logical.Operation]framework.OperationHandler{
|
Operations: map[logical.Operation]framework.OperationHandler{
|
||||||
|
logical.ReadOperation: &framework.PathOperation{
|
||||||
|
Callback: b.handleLoggersRead,
|
||||||
|
Summary: "Read the log level for all existing loggers.",
|
||||||
|
},
|
||||||
logical.UpdateOperation: &framework.PathOperation{
|
logical.UpdateOperation: &framework.PathOperation{
|
||||||
Callback: b.handleLoggersWrite,
|
Callback: b.handleLoggersWrite,
|
||||||
Summary: "Modify the log level for all existing loggers.",
|
Summary: "Modify the log level for all existing loggers.",
|
||||||
|
@ -322,6 +326,10 @@ func (b *SystemBackend) configPaths() []*framework.Path {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Operations: map[logical.Operation]framework.OperationHandler{
|
Operations: map[logical.Operation]framework.OperationHandler{
|
||||||
|
logical.ReadOperation: &framework.PathOperation{
|
||||||
|
Callback: b.handleLoggersByNameRead,
|
||||||
|
Summary: "Read the log level for a single logger.",
|
||||||
|
},
|
||||||
logical.UpdateOperation: &framework.PathOperation{
|
logical.UpdateOperation: &framework.PathOperation{
|
||||||
Callback: b.handleLoggersByNameWrite,
|
Callback: b.handleLoggersByNameWrite,
|
||||||
Summary: "Modify the log level of a single logger.",
|
Summary: "Modify the log level of a single logger.",
|
||||||
|
|
|
@ -4772,66 +4772,60 @@ func TestProcessLimit(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateLevel(level string, logger hclog.Logger) bool {
|
|
||||||
switch level {
|
|
||||||
case "trace":
|
|
||||||
return logger.IsTrace()
|
|
||||||
case "debug":
|
|
||||||
return logger.IsDebug()
|
|
||||||
case "notice", "info", "":
|
|
||||||
return logger.IsInfo()
|
|
||||||
case "warn", "warning":
|
|
||||||
return logger.IsWarn()
|
|
||||||
case "err", "error":
|
|
||||||
return logger.IsError()
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSystemBackend_Loggers(t *testing.T) {
|
func TestSystemBackend_Loggers(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
level string
|
level string
|
||||||
|
expectedLevel string
|
||||||
expectError bool
|
expectError bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
|
"trace",
|
||||||
"trace",
|
"trace",
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"debug",
|
||||||
"debug",
|
"debug",
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"notice",
|
"notice",
|
||||||
|
"info",
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"info",
|
||||||
"info",
|
"info",
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"warn",
|
||||||
"warn",
|
"warn",
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"warning",
|
"warning",
|
||||||
|
"warn",
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"err",
|
"err",
|
||||||
|
"error",
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"error",
|
||||||
"error",
|
"error",
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"",
|
"",
|
||||||
|
"info",
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"invalid",
|
"invalid",
|
||||||
|
"",
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -4844,7 +4838,33 @@ func TestSystemBackend_Loggers(t *testing.T) {
|
||||||
|
|
||||||
core, b, _ := testCoreSystemBackend(t)
|
core, b, _ := testCoreSystemBackend(t)
|
||||||
|
|
||||||
|
// Test core overrides logging level outside of config,
|
||||||
|
// an initial delete will ensure that we an initial read
|
||||||
|
// to get expected values is based off of config and not
|
||||||
|
// the test override that is hidden from this test
|
||||||
req := &logical.Request{
|
req := &logical.Request{
|
||||||
|
Path: "loggers",
|
||||||
|
Operation: logical.DeleteOperation,
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := b.HandleRequest(namespace.RootContext(nil), req)
|
||||||
|
if err != nil || (resp != nil && resp.IsError()) {
|
||||||
|
t.Fatalf("unexpected error, err: %v, resp: %#v", err, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
req = &logical.Request{
|
||||||
|
Path: "loggers",
|
||||||
|
Operation: logical.ReadOperation,
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err = b.HandleRequest(namespace.RootContext(nil), req)
|
||||||
|
if err != nil || (resp != nil && resp.IsError()) {
|
||||||
|
t.Fatalf("unexpected error, err: %v, resp: %#v", err, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
initialLoggers := resp.Data
|
||||||
|
|
||||||
|
req = &logical.Request{
|
||||||
Path: "loggers",
|
Path: "loggers",
|
||||||
Operation: logical.UpdateOperation,
|
Operation: logical.UpdateOperation,
|
||||||
Data: map[string]interface{}{
|
Data: map[string]interface{}{
|
||||||
|
@ -4852,7 +4872,7 @@ func TestSystemBackend_Loggers(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := b.HandleRequest(namespace.RootContext(nil), req)
|
resp, err = b.HandleRequest(namespace.RootContext(nil), req)
|
||||||
respIsError := resp != nil && resp.IsError()
|
respIsError := resp != nil && resp.IsError()
|
||||||
|
|
||||||
if err != nil || (!tc.expectError && respIsError) {
|
if err != nil || (!tc.expectError && respIsError) {
|
||||||
|
@ -4864,16 +4884,9 @@ func TestSystemBackend_Loggers(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !tc.expectError {
|
if !tc.expectError {
|
||||||
for _, logger := range core.allLoggers {
|
|
||||||
if !validateLevel(tc.level, logger) {
|
|
||||||
t.Fatalf("expected logger %q to be %q", logger.Name(), tc.level)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
req = &logical.Request{
|
req = &logical.Request{
|
||||||
Path: fmt.Sprintf("loggers"),
|
Path: "loggers",
|
||||||
Operation: logical.DeleteOperation,
|
Operation: logical.ReadOperation,
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err = b.HandleRequest(namespace.RootContext(nil), req)
|
resp, err = b.HandleRequest(namespace.RootContext(nil), req)
|
||||||
|
@ -4882,8 +4895,52 @@ func TestSystemBackend_Loggers(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, logger := range core.allLoggers {
|
for _, logger := range core.allLoggers {
|
||||||
if !validateLevel(core.logLevel, logger) {
|
loggerName := logger.Name()
|
||||||
t.Errorf("expected level of logger %q to match original config", logger.Name())
|
levelRaw, ok := resp.Data[loggerName]
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
t.Errorf("logger %q not found in response", loggerName)
|
||||||
|
}
|
||||||
|
|
||||||
|
if levelStr := levelRaw.(string); levelStr != tc.expectedLevel {
|
||||||
|
t.Errorf("unexpected level of logger %q, expected: %s, actual: %s", loggerName, tc.expectedLevel, levelStr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
req = &logical.Request{
|
||||||
|
Path: "loggers",
|
||||||
|
Operation: logical.DeleteOperation,
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err = b.HandleRequest(namespace.RootContext(nil), req)
|
||||||
|
if err != nil || (resp != nil && resp.IsError()) {
|
||||||
|
t.Fatalf("unexpected error, err: %v, resp: %#v", err, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
req = &logical.Request{
|
||||||
|
Path: "loggers",
|
||||||
|
Operation: logical.ReadOperation,
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err = b.HandleRequest(namespace.RootContext(nil), req)
|
||||||
|
if err != nil || (resp != nil && resp.IsError()) {
|
||||||
|
t.Fatalf("unexpected error, err: %v, resp: %#v", err, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, logger := range core.allLoggers {
|
||||||
|
loggerName := logger.Name()
|
||||||
|
levelRaw, currentOk := resp.Data[loggerName]
|
||||||
|
initialLevelRaw, initialOk := initialLoggers[loggerName]
|
||||||
|
|
||||||
|
if !currentOk || !initialOk {
|
||||||
|
t.Errorf("logger %q not found", loggerName)
|
||||||
|
}
|
||||||
|
|
||||||
|
levelStr := levelRaw.(string)
|
||||||
|
initialLevelStr := initialLevelRaw.(string)
|
||||||
|
if levelStr != initialLevelStr {
|
||||||
|
t.Errorf("expected level of logger %q to match original config, expected: %s, actual: %s", loggerName, initialLevelStr, levelStr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -4894,78 +4951,91 @@ func TestSystemBackend_LoggersByName(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
logger string
|
logger string
|
||||||
level string
|
level string
|
||||||
|
expectedLevel string
|
||||||
expectWriteError bool
|
expectWriteError bool
|
||||||
expectDeleteError bool
|
expectDeleteError bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
"core",
|
"core",
|
||||||
"trace",
|
"trace",
|
||||||
|
"trace",
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"token",
|
"token",
|
||||||
"debug",
|
"debug",
|
||||||
|
"debug",
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"audit",
|
"audit",
|
||||||
"notice",
|
"notice",
|
||||||
|
"info",
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"expiration",
|
"expiration",
|
||||||
"info",
|
"info",
|
||||||
|
"info",
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"policy",
|
"policy",
|
||||||
"warn",
|
"warn",
|
||||||
|
"warn",
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"activity",
|
"activity",
|
||||||
"warning",
|
"warning",
|
||||||
|
"warn",
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"identity",
|
"identity",
|
||||||
"err",
|
"err",
|
||||||
|
"error",
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"rollback",
|
"rollback",
|
||||||
"error",
|
"error",
|
||||||
|
"error",
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"system",
|
"system",
|
||||||
"",
|
"",
|
||||||
|
"does-not-matter",
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"quotas",
|
"quotas",
|
||||||
"invalid",
|
"invalid",
|
||||||
|
"does-not-matter",
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"",
|
"",
|
||||||
"info",
|
"info",
|
||||||
|
"does-not-matter",
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"does_not_exist",
|
"does_not_exist",
|
||||||
"error",
|
"error",
|
||||||
|
"does-not-matter",
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
|
@ -4979,16 +5049,41 @@ func TestSystemBackend_LoggersByName(t *testing.T) {
|
||||||
|
|
||||||
core, b, _ := testCoreSystemBackend(t)
|
core, b, _ := testCoreSystemBackend(t)
|
||||||
|
|
||||||
|
// Test core overrides logging level outside of config,
|
||||||
|
// an initial delete will ensure that we an initial read
|
||||||
|
// to get expected values is based off of config and not
|
||||||
|
// the test override that is hidden from this test
|
||||||
req := &logical.Request{
|
req := &logical.Request{
|
||||||
|
Path: "loggers",
|
||||||
|
Operation: logical.DeleteOperation,
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := b.HandleRequest(namespace.RootContext(nil), req)
|
||||||
|
if err != nil || (resp != nil && resp.IsError()) {
|
||||||
|
t.Fatalf("unexpected error, err: %v, resp: %#v", err, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
req = &logical.Request{
|
||||||
|
Path: "loggers",
|
||||||
|
Operation: logical.ReadOperation,
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err = b.HandleRequest(namespace.RootContext(nil), req)
|
||||||
|
if err != nil || (resp != nil && resp.IsError()) {
|
||||||
|
t.Fatalf("unexpected error, err: %v, resp: %#v", err, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
initialLoggers := resp.Data
|
||||||
|
|
||||||
|
req = &logical.Request{
|
||||||
Path: fmt.Sprintf("loggers/%s", tc.logger),
|
Path: fmt.Sprintf("loggers/%s", tc.logger),
|
||||||
Operation: logical.UpdateOperation,
|
Operation: logical.UpdateOperation,
|
||||||
Data: map[string]interface{}{
|
Data: map[string]interface{}{
|
||||||
"name": tc.logger,
|
|
||||||
"level": tc.level,
|
"level": tc.level,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := b.HandleRequest(namespace.RootContext(nil), req)
|
resp, err = b.HandleRequest(namespace.RootContext(nil), req)
|
||||||
respIsError := resp != nil && resp.IsError()
|
respIsError := resp != nil && resp.IsError()
|
||||||
|
|
||||||
if err != nil || (!tc.expectWriteError && respIsError) {
|
if err != nil || (!tc.expectWriteError && respIsError) {
|
||||||
|
@ -5000,13 +5095,34 @@ func TestSystemBackend_LoggersByName(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !tc.expectWriteError {
|
if !tc.expectWriteError {
|
||||||
for _, logger := range core.allLoggers {
|
req = &logical.Request{
|
||||||
if logger.Name() != tc.logger && !validateLevel(core.logLevel, logger) {
|
Path: "loggers",
|
||||||
t.Errorf("expected level of logger %q to be unchanged", logger.Name())
|
Operation: logical.ReadOperation,
|
||||||
}
|
}
|
||||||
|
|
||||||
if !validateLevel(tc.level, logger) {
|
resp, err = b.HandleRequest(namespace.RootContext(nil), req)
|
||||||
t.Fatalf("expected logger %q to be %q", logger.Name(), tc.level)
|
if err != nil || (resp != nil && resp.IsError()) {
|
||||||
|
t.Fatalf("unexpected error, err: %v, resp: %#v", err, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, logger := range core.allLoggers {
|
||||||
|
loggerName := logger.Name()
|
||||||
|
levelRaw, currentOk := resp.Data[loggerName]
|
||||||
|
initialLevelRaw, initialOk := initialLoggers[loggerName]
|
||||||
|
|
||||||
|
if !currentOk || !initialOk {
|
||||||
|
t.Errorf("logger %q not found", loggerName)
|
||||||
|
}
|
||||||
|
|
||||||
|
levelStr := levelRaw.(string)
|
||||||
|
initialLevelStr := initialLevelRaw.(string)
|
||||||
|
|
||||||
|
if loggerName == tc.logger && levelStr != tc.expectedLevel {
|
||||||
|
t.Fatalf("expected logger %q to be %q, actual: %s", loggerName, tc.expectedLevel, levelStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
if loggerName != tc.logger && levelStr != initialLevelStr {
|
||||||
|
t.Errorf("expected level of logger %q to be unchanged, exepcted: %s, actual: %s", loggerName, initialLevelStr, levelStr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5014,9 +5130,6 @@ func TestSystemBackend_LoggersByName(t *testing.T) {
|
||||||
req = &logical.Request{
|
req = &logical.Request{
|
||||||
Path: fmt.Sprintf("loggers/%s", tc.logger),
|
Path: fmt.Sprintf("loggers/%s", tc.logger),
|
||||||
Operation: logical.DeleteOperation,
|
Operation: logical.DeleteOperation,
|
||||||
Data: map[string]interface{}{
|
|
||||||
"name": tc.logger,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err = b.HandleRequest(namespace.RootContext(nil), req)
|
resp, err = b.HandleRequest(namespace.RootContext(nil), req)
|
||||||
|
@ -5031,10 +5144,28 @@ func TestSystemBackend_LoggersByName(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !tc.expectDeleteError {
|
if !tc.expectDeleteError {
|
||||||
for _, logger := range core.allLoggers {
|
req = &logical.Request{
|
||||||
if !validateLevel(core.logLevel, logger) {
|
Path: fmt.Sprintf("loggers/%s", tc.logger),
|
||||||
t.Errorf("expected level of logger %q to match original config", logger.Name())
|
Operation: logical.ReadOperation,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resp, err = b.HandleRequest(namespace.RootContext(nil), req)
|
||||||
|
if err != nil || (resp != nil && resp.IsError()) {
|
||||||
|
t.Fatalf("unexpected error, err: %v, resp: %#v", err, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
currentLevel, ok := resp.Data[tc.logger].(string)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("expected resp to include %q, resp: %#v", tc.logger, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
initialLevel, ok := initialLoggers[tc.logger].(string)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("expected initial loggers to include %q, resp: %#v", tc.logger, initialLoggers)
|
||||||
|
}
|
||||||
|
|
||||||
|
if currentLevel != initialLevel {
|
||||||
|
t.Errorf("expected level of logger %q to match original config, expected: %s, actual: %s", tc.logger, initialLevel, currentLevel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -71,6 +71,52 @@ $ curl \
|
||||||
http://127.0.0.1:8200/v1/sys/loggers/core
|
http://127.0.0.1:8200/v1/sys/loggers/core
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Read verbosity level of all loggers
|
||||||
|
|
||||||
|
| Method | Path |
|
||||||
|
| :----- | :------------- |
|
||||||
|
| `GET` | `/sys/loggers` |
|
||||||
|
|
||||||
|
### Sample Request
|
||||||
|
|
||||||
|
```shell-session
|
||||||
|
$ curl \
|
||||||
|
--header "X-Vault-Token: ..." \
|
||||||
|
https://127.0.0.1:8200/v1/sys/loggers
|
||||||
|
```
|
||||||
|
|
||||||
|
### Sample Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"audit": "trace",
|
||||||
|
"core": "info",
|
||||||
|
"policy": "debug"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Read verbosity level of a single logger
|
||||||
|
|
||||||
|
| Method | Path |
|
||||||
|
| :----- | :------------------- |
|
||||||
|
| `GET` | `/sys/loggers/:name` |
|
||||||
|
|
||||||
|
### Sample Request
|
||||||
|
|
||||||
|
```shell-session
|
||||||
|
$ curl \
|
||||||
|
--header "X-Vault-Token: ..." \
|
||||||
|
https://127.0.0.1:8200/v1/sys/loggers/core
|
||||||
|
```
|
||||||
|
|
||||||
|
### Sample Response
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"core": "info"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Revert verbosity of all loggers to configured level
|
## Revert verbosity of all loggers to configured level
|
||||||
|
|
||||||
| Method | Path |
|
| Method | Path |
|
||||||
|
|
Loading…
Reference in a new issue