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
|
@ -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) {
|
||||
var result log.Level
|
||||
logLevel = strings.ToLower(strings.TrimSpace(logLevel))
|
||||
|
@ -133,3 +135,24 @@ func ParseLogLevel(logLevel string) (log.Level, error) {
|
|||
|
||||
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)
|
||||
}
|
||||
|
||||
// SetLogLevel sets logging level for all tracked loggers to the level provided
|
||||
func (c *Core) SetLogLevel(level log.Level) {
|
||||
c.allLoggersLock.RLock()
|
||||
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()
|
||||
defer c.allLoggersLock.RUnlock()
|
||||
|
||||
found := false
|
||||
for _, logger := range c.allLoggers {
|
||||
if logger.Name() == name {
|
||||
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.
|
||||
|
|
|
@ -20,9 +20,6 @@ import (
|
|||
"time"
|
||||
"unicode"
|
||||
|
||||
"github.com/hashicorp/vault/helper/versions"
|
||||
"golang.org/x/crypto/sha3"
|
||||
|
||||
"github.com/hashicorp/errwrap"
|
||||
log "github.com/hashicorp/go-hclog"
|
||||
"github.com/hashicorp/go-memdb"
|
||||
|
@ -32,10 +29,12 @@ import (
|
|||
semver "github.com/hashicorp/go-version"
|
||||
"github.com/hashicorp/vault/helper/hostutil"
|
||||
"github.com/hashicorp/vault/helper/identity"
|
||||
"github.com/hashicorp/vault/helper/logging"
|
||||
"github.com/hashicorp/vault/helper/metricsutil"
|
||||
"github.com/hashicorp/vault/helper/monitor"
|
||||
"github.com/hashicorp/vault/helper/namespace"
|
||||
"github.com/hashicorp/vault/helper/random"
|
||||
"github.com/hashicorp/vault/helper/versions"
|
||||
"github.com/hashicorp/vault/sdk/framework"
|
||||
"github.com/hashicorp/vault/sdk/helper/consts"
|
||||
"github.com/hashicorp/vault/sdk/helper/jsonutil"
|
||||
|
@ -44,6 +43,7 @@ import (
|
|||
"github.com/hashicorp/vault/sdk/logical"
|
||||
"github.com/hashicorp/vault/sdk/version"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
"golang.org/x/crypto/sha3"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -4833,28 +4833,35 @@ 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) {
|
||||
var level log.Level
|
||||
func (b *SystemBackend) handleLoggersRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
|
||||
b.Core.allLoggersLock.RLock()
|
||||
defer b.Core.allLoggersLock.RUnlock()
|
||||
|
||||
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)
|
||||
loggers := make(map[string]interface{})
|
||||
warnings := make([]string, 0)
|
||||
|
||||
for _, logger := range b.Core.allLoggers {
|
||||
loggerName := logger.Name()
|
||||
|
||||
// ignore base logger
|
||||
if loggerName == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
return level, nil
|
||||
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) {
|
||||
|
@ -4869,7 +4876,7 @@ func (b *SystemBackend) handleLoggersWrite(ctx context.Context, req *logical.Req
|
|||
return logical.ErrorResponse("level is empty"), nil
|
||||
}
|
||||
|
||||
level, err := getLogLevel(logLevel)
|
||||
level, err := logging.ParseLogLevel(logLevel)
|
||||
if err != 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) {
|
||||
level, err := getLogLevel(b.Core.logLevel)
|
||||
level, err := logging.ParseLogLevel(b.Core.logLevel)
|
||||
if err != 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
|
||||
}
|
||||
|
||||
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) {
|
||||
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
|
||||
}
|
||||
|
||||
logLevelRaw, logLevelOk := d.GetOk("level")
|
||||
|
||||
if !logLevelOk {
|
||||
|
@ -4907,14 +4965,14 @@ func (b *SystemBackend) handleLoggersByNameWrite(ctx context.Context, req *logic
|
|||
return logical.ErrorResponse("level is empty"), nil
|
||||
}
|
||||
|
||||
level, err := getLogLevel(logLevel)
|
||||
level, err := logging.ParseLogLevel(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
|
||||
success := b.Core.SetLogLevelByName(name, level)
|
||||
if !success {
|
||||
return logical.ErrorResponse(fmt.Sprintf("logger %q not found", name)), nil
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
|
@ -4926,14 +4984,19 @@ func (b *SystemBackend) handleLoggersByNameDelete(ctx context.Context, req *logi
|
|||
return logical.ErrorResponse("name is required"), nil
|
||||
}
|
||||
|
||||
level, err := getLogLevel(b.Core.logLevel)
|
||||
level, err := logging.ParseLogLevel(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
|
||||
name := nameRaw.(string)
|
||||
if name == "" {
|
||||
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
|
||||
|
|
|
@ -298,6 +298,10 @@ func (b *SystemBackend) configPaths() []*framework.Path {
|
|||
},
|
||||
},
|
||||
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{
|
||||
Callback: b.handleLoggersWrite,
|
||||
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{
|
||||
logical.ReadOperation: &framework.PathOperation{
|
||||
Callback: b.handleLoggersByNameRead,
|
||||
Summary: "Read the log level for a single logger.",
|
||||
},
|
||||
logical.UpdateOperation: &framework.PathOperation{
|
||||
Callback: b.handleLoggersByNameWrite,
|
||||
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) {
|
||||
testCases := []struct {
|
||||
level string
|
||||
expectError bool
|
||||
level string
|
||||
expectedLevel string
|
||||
expectError bool
|
||||
}{
|
||||
{
|
||||
"trace",
|
||||
"trace",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"debug",
|
||||
"debug",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"notice",
|
||||
"info",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"info",
|
||||
"info",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"warn",
|
||||
"warn",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"warning",
|
||||
"warn",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"err",
|
||||
"error",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"error",
|
||||
"error",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"",
|
||||
"info",
|
||||
true,
|
||||
},
|
||||
{
|
||||
"invalid",
|
||||
"",
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
@ -4844,7 +4838,33 @@ func TestSystemBackend_Loggers(t *testing.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{
|
||||
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",
|
||||
Operation: logical.UpdateOperation,
|
||||
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()
|
||||
|
||||
if err != nil || (!tc.expectError && respIsError) {
|
||||
|
@ -4864,15 +4884,32 @@ func TestSystemBackend_Loggers(t *testing.T) {
|
|||
}
|
||||
|
||||
if !tc.expectError {
|
||||
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 {
|
||||
if !validateLevel(tc.level, logger) {
|
||||
t.Fatalf("expected logger %q to be %q", logger.Name(), tc.level)
|
||||
loggerName := 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: fmt.Sprintf("loggers"),
|
||||
Path: "loggers",
|
||||
Operation: logical.DeleteOperation,
|
||||
}
|
||||
|
||||
|
@ -4881,9 +4918,29 @@ func TestSystemBackend_Loggers(t *testing.T) {
|
|||
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 {
|
||||
if !validateLevel(core.logLevel, logger) {
|
||||
t.Errorf("expected level of logger %q to match original config", logger.Name())
|
||||
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 {
|
||||
logger string
|
||||
level string
|
||||
expectedLevel string
|
||||
expectWriteError bool
|
||||
expectDeleteError bool
|
||||
}{
|
||||
{
|
||||
"core",
|
||||
"trace",
|
||||
"trace",
|
||||
false,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"token",
|
||||
"debug",
|
||||
"debug",
|
||||
false,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"audit",
|
||||
"notice",
|
||||
"info",
|
||||
false,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"expiration",
|
||||
"info",
|
||||
"info",
|
||||
false,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"policy",
|
||||
"warn",
|
||||
"warn",
|
||||
false,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"activity",
|
||||
"warning",
|
||||
"warn",
|
||||
false,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"identity",
|
||||
"err",
|
||||
"error",
|
||||
false,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"rollback",
|
||||
"error",
|
||||
"error",
|
||||
false,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"system",
|
||||
"",
|
||||
"does-not-matter",
|
||||
true,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"quotas",
|
||||
"invalid",
|
||||
"does-not-matter",
|
||||
true,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"",
|
||||
"info",
|
||||
"does-not-matter",
|
||||
true,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"does_not_exist",
|
||||
"error",
|
||||
"does-not-matter",
|
||||
true,
|
||||
true,
|
||||
},
|
||||
|
@ -4979,16 +5049,41 @@ func TestSystemBackend_LoggersByName(t *testing.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{
|
||||
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),
|
||||
Operation: logical.UpdateOperation,
|
||||
Data: map[string]interface{}{
|
||||
"name": tc.logger,
|
||||
"level": tc.level,
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := b.HandleRequest(namespace.RootContext(nil), req)
|
||||
resp, err = b.HandleRequest(namespace.RootContext(nil), req)
|
||||
respIsError := resp != nil && resp.IsError()
|
||||
|
||||
if err != nil || (!tc.expectWriteError && respIsError) {
|
||||
|
@ -5000,13 +5095,34 @@ func TestSystemBackend_LoggersByName(t *testing.T) {
|
|||
}
|
||||
|
||||
if !tc.expectWriteError {
|
||||
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 {
|
||||
if logger.Name() != tc.logger && !validateLevel(core.logLevel, logger) {
|
||||
t.Errorf("expected level of logger %q to be unchanged", logger.Name())
|
||||
loggerName := logger.Name()
|
||||
levelRaw, currentOk := resp.Data[loggerName]
|
||||
initialLevelRaw, initialOk := initialLoggers[loggerName]
|
||||
|
||||
if !currentOk || !initialOk {
|
||||
t.Errorf("logger %q not found", loggerName)
|
||||
}
|
||||
|
||||
if !validateLevel(tc.level, logger) {
|
||||
t.Fatalf("expected logger %q to be %q", logger.Name(), tc.level)
|
||||
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{
|
||||
Path: fmt.Sprintf("loggers/%s", tc.logger),
|
||||
Operation: logical.DeleteOperation,
|
||||
Data: map[string]interface{}{
|
||||
"name": tc.logger,
|
||||
},
|
||||
}
|
||||
|
||||
resp, err = b.HandleRequest(namespace.RootContext(nil), req)
|
||||
|
@ -5031,10 +5144,28 @@ func TestSystemBackend_LoggersByName(t *testing.T) {
|
|||
}
|
||||
|
||||
if !tc.expectDeleteError {
|
||||
for _, logger := range core.allLoggers {
|
||||
if !validateLevel(core.logLevel, logger) {
|
||||
t.Errorf("expected level of logger %q to match original config", logger.Name())
|
||||
}
|
||||
req = &logical.Request{
|
||||
Path: fmt.Sprintf("loggers/%s", tc.logger),
|
||||
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)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -8,8 +8,8 @@ description: The `/sys/loggers` endpoint is used modify the verbosity level of l
|
|||
|
||||
The `/sys/loggers` endpoint is used modify the verbosity level of logging.
|
||||
|
||||
!> **NOTE:** Changes made to the log level using this endpoint are not persisted and will be restored
|
||||
to either the default log level (info) or the level specified using `log_level` in vault.hcl or the `VAULT_LOG_LEVEL`
|
||||
!> **NOTE:** Changes made to the log level using this endpoint are not persisted and will be restored
|
||||
to either the default log level (info) or the level specified using `log_level` in vault.hcl or the `VAULT_LOG_LEVEL`
|
||||
environment variable once the Vault service is reloaded or restarted.
|
||||
|
||||
## Modify verbosity level of all loggers
|
||||
|
@ -71,6 +71,52 @@ $ curl \
|
|||
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
|
||||
|
||||
| Method | Path |
|
||||
|
|
Loading…
Reference in New Issue