mirror of
https://github.com/caddyserver/caddy.git
synced 2024-12-25 21:23:48 +03:00
logging: Customizable zap cores (#6381)
This commit is contained in:
parent
04fb9fe87f
commit
d85cc2ec10
4 changed files with 69 additions and 2 deletions
|
@ -849,6 +849,7 @@ func parseInvoke(h Helper) (caddyhttp.MiddlewareHandler, error) {
|
||||||
// log <logger_name> {
|
// log <logger_name> {
|
||||||
// hostnames <hostnames...>
|
// hostnames <hostnames...>
|
||||||
// output <writer_module> ...
|
// output <writer_module> ...
|
||||||
|
// core <core_module> ...
|
||||||
// format <encoder_module> ...
|
// format <encoder_module> ...
|
||||||
// level <level>
|
// level <level>
|
||||||
// }
|
// }
|
||||||
|
@ -960,6 +961,22 @@ func parseLogHelper(h Helper, globalLogNames map[string]struct{}) ([]ConfigValue
|
||||||
}
|
}
|
||||||
cl.WriterRaw = caddyconfig.JSONModuleObject(wo, "output", moduleName, h.warnings)
|
cl.WriterRaw = caddyconfig.JSONModuleObject(wo, "output", moduleName, h.warnings)
|
||||||
|
|
||||||
|
case "core":
|
||||||
|
if !h.NextArg() {
|
||||||
|
return nil, h.ArgErr()
|
||||||
|
}
|
||||||
|
moduleName := h.Val()
|
||||||
|
moduleID := "caddy.logging.cores." + moduleName
|
||||||
|
unm, err := caddyfile.UnmarshalModule(h.Dispenser, moduleID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
core, ok := unm.(zapcore.Core)
|
||||||
|
if !ok {
|
||||||
|
return nil, h.Errf("module %s (%T) is not a zapcore.Core", moduleID, unm)
|
||||||
|
}
|
||||||
|
cl.CoreRaw = caddyconfig.JSONModuleObject(core, "module", moduleName, h.warnings)
|
||||||
|
|
||||||
case "format":
|
case "format":
|
||||||
if !h.NextArg() {
|
if !h.NextArg() {
|
||||||
return nil, h.ArgErr()
|
return nil, h.ArgErr()
|
||||||
|
|
|
@ -25,11 +25,12 @@ func TestLogDirectiveSyntax(t *testing.T) {
|
||||||
{
|
{
|
||||||
input: `:8080 {
|
input: `:8080 {
|
||||||
log {
|
log {
|
||||||
|
core mock
|
||||||
output file foo.log
|
output file foo.log
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
output: `{"logging":{"logs":{"default":{"exclude":["http.log.access.log0"]},"log0":{"writer":{"filename":"foo.log","output":"file"},"include":["http.log.access.log0"]}}},"apps":{"http":{"servers":{"srv0":{"listen":[":8080"],"logs":{"default_logger_name":"log0"}}}}}}`,
|
output: `{"logging":{"logs":{"default":{"exclude":["http.log.access.log0"]},"log0":{"writer":{"filename":"foo.log","output":"file"},"core":{"module":"mock"},"include":["http.log.access.log0"]}}},"apps":{"http":{"servers":{"srv0":{"listen":[":8080"],"logs":{"default_logger_name":"log0"}}}}}}`,
|
||||||
expectError: false,
|
expectError: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -53,11 +54,12 @@ func TestLogDirectiveSyntax(t *testing.T) {
|
||||||
{
|
{
|
||||||
input: `:8080 {
|
input: `:8080 {
|
||||||
log name-override {
|
log name-override {
|
||||||
|
core mock
|
||||||
output file foo.log
|
output file foo.log
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
output: `{"logging":{"logs":{"default":{"exclude":["http.log.access.name-override"]},"name-override":{"writer":{"filename":"foo.log","output":"file"},"include":["http.log.access.name-override"]}}},"apps":{"http":{"servers":{"srv0":{"listen":[":8080"],"logs":{"default_logger_name":"name-override"}}}}}}`,
|
output: `{"logging":{"logs":{"default":{"exclude":["http.log.access.name-override"]},"name-override":{"writer":{"filename":"foo.log","output":"file"},"core":{"module":"mock"},"include":["http.log.access.name-override"]}}},"apps":{"http":{"servers":{"srv0":{"listen":[":8080"],"logs":{"default_logger_name":"name-override"}}}}}}`,
|
||||||
expectError: false,
|
expectError: false,
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
|
|
12
logging.go
12
logging.go
|
@ -292,6 +292,10 @@ type BaseLog struct {
|
||||||
// The encoder is how the log entries are formatted or encoded.
|
// The encoder is how the log entries are formatted or encoded.
|
||||||
EncoderRaw json.RawMessage `json:"encoder,omitempty" caddy:"namespace=caddy.logging.encoders inline_key=format"`
|
EncoderRaw json.RawMessage `json:"encoder,omitempty" caddy:"namespace=caddy.logging.encoders inline_key=format"`
|
||||||
|
|
||||||
|
// Tees entries through a zap.Core module which can extract
|
||||||
|
// log entry metadata and fields for further processing.
|
||||||
|
CoreRaw json.RawMessage `json:"core,omitempty" caddy:"namespace=caddy.logging.cores inline_key=module"`
|
||||||
|
|
||||||
// Level is the minimum level to emit, and is inclusive.
|
// Level is the minimum level to emit, and is inclusive.
|
||||||
// Possible levels: DEBUG, INFO, WARN, ERROR, PANIC, and FATAL
|
// Possible levels: DEBUG, INFO, WARN, ERROR, PANIC, and FATAL
|
||||||
Level string `json:"level,omitempty"`
|
Level string `json:"level,omitempty"`
|
||||||
|
@ -366,6 +370,14 @@ func (cl *BaseLog) provisionCommon(ctx Context, logging *Logging) error {
|
||||||
cl.encoder = newDefaultProductionLogEncoder(cl.writerOpener)
|
cl.encoder = newDefaultProductionLogEncoder(cl.writerOpener)
|
||||||
}
|
}
|
||||||
cl.buildCore()
|
cl.buildCore()
|
||||||
|
if cl.CoreRaw != nil {
|
||||||
|
mod, err := ctx.LoadModule(cl, "CoreRaw")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("loading log core module: %v", err)
|
||||||
|
}
|
||||||
|
core := mod.(zapcore.Core)
|
||||||
|
cl.core = zapcore.NewTee(cl.core, core)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
36
modules/logging/cores.go
Normal file
36
modules/logging/cores.go
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
package logging
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go.uber.org/zap/zapcore"
|
||||||
|
|
||||||
|
"github.com/caddyserver/caddy/v2"
|
||||||
|
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
caddy.RegisterModule(MockCore{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// MockCore is a no-op module, purely for testing
|
||||||
|
type MockCore struct {
|
||||||
|
zapcore.Core `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CaddyModule returns the Caddy module information.
|
||||||
|
func (MockCore) CaddyModule() caddy.ModuleInfo {
|
||||||
|
return caddy.ModuleInfo{
|
||||||
|
ID: "caddy.logging.cores.mock",
|
||||||
|
New: func() caddy.Module { return new(MockCore) },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lec *MockCore) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interface guards
|
||||||
|
var (
|
||||||
|
_ zapcore.Core = (*MockCore)(nil)
|
||||||
|
_ caddy.Module = (*MockCore)(nil)
|
||||||
|
_ caddyfile.Unmarshaler = (*MockCore)(nil)
|
||||||
|
)
|
Loading…
Reference in a new issue