Skip to content
Snippets Groups Projects
Unverified Commit 1c16ecd0 authored by Sean Young's avatar Sean Young Committed by GitHub
Browse files

Merge pull request #743 from silasdavis/file-logging-instruction

Add file and json logging instructions.
parents d0122f97 2eb748a3
No related branches found
No related tags found
No related merge requests found
......@@ -13,13 +13,14 @@ import (
// Returning the new subroot from which to apply any further Presets.
// When chained together in a pre-order instructions can be composed to form an entire Sink tree.
type Instruction struct {
name string
desc string
name string
desc string
nargs int
// The builder for the Instruction is a function that may modify the stack or ops string. Typically
// by mutating the sink at the top of the stack and may move the cursor or by pushing child sinks
// to the stack. The builder may also return a modified ops slice whereby it may insert Instruction calls
// acting as a macro or consume ops as arguments.
builder func(stack []*config.SinkConfig, ops []string) ([]*config.SinkConfig, []string, error)
builder func(stack []*config.SinkConfig, args []string) ([]*config.SinkConfig, error)
}
func (i Instruction) Name() string {
......@@ -37,88 +38,113 @@ const (
Stderr = "stderr"
Stdout = "stdout"
Terminal = "terminal"
JSON = "json"
Up = "up"
Down = "down"
File = "file"
)
var instructions = []Instruction{
{
name: Up,
desc: "Ascend the sink tree by travelling up the stack to the previous sink recorded on the stack",
builder: func(stack []*config.SinkConfig, ops []string) ([]*config.SinkConfig, []string, error) {
return pop(stack), ops, nil
builder: func(stack []*config.SinkConfig, args []string) ([]*config.SinkConfig, error) {
return pop(stack), nil
},
},
{
name: Down,
desc: "Descend the sink tree by inserting a sink as a child to the current sink and adding it to the stack",
builder: func(stack []*config.SinkConfig, ops []string) ([]*config.SinkConfig, []string, error) {
return push(stack, config.Sink()), ops, nil
builder: func(stack []*config.SinkConfig, args []string) ([]*config.SinkConfig, error) {
return push(stack, config.Sink()), nil
},
},
{
name: Minimal,
desc: "A generally less chatty log output, follow with output options",
builder: func(stack []*config.SinkConfig, ops []string) ([]*config.SinkConfig, []string, error) {
builder: func(stack []*config.SinkConfig, args []string) ([]*config.SinkConfig, error) {
return push(stack,
config.Sink().SetTransform(config.PruneTransform(structure.TraceKey, structure.RunId)),
config.Sink().SetTransform(config.FilterTransform(config.IncludeWhenAllMatch,
structure.ChannelKey, structure.InfoChannelName)),
config.Sink().SetTransform(config.FilterTransform(config.ExcludeWhenAnyMatches,
structure.ComponentKey, "Tendermint",
"module", "p2p",
"module", "mempool"))),
ops, nil
config.Sink().SetTransform(config.PruneTransform(structure.TraceKey, structure.RunId)),
config.Sink().SetTransform(config.FilterTransform(config.IncludeWhenAllMatch,
structure.ChannelKey, structure.InfoChannelName)),
config.Sink().SetTransform(config.FilterTransform(config.ExcludeWhenAnyMatches,
structure.ComponentKey, "Tendermint",
"module", "p2p",
"module", "mempool"))), nil
},
},
{
name: IncludeAny,
desc: "Establish an 'include when any predicate matches' filter transform at this this sink",
builder: func(stack []*config.SinkConfig, ops []string) ([]*config.SinkConfig, []string, error) {
builder: func(stack []*config.SinkConfig, args []string) ([]*config.SinkConfig, error) {
sink := peek(stack)
ensureFilter(sink)
sink.Transform.FilterConfig.FilterMode = config.IncludeWhenAnyMatches
return stack, ops, nil
return stack, nil
},
},
{
name: Info,
desc: "Add a filter predicate to match the Info logging channel",
builder: func(stack []*config.SinkConfig, ops []string) ([]*config.SinkConfig, []string, error) {
builder: func(stack []*config.SinkConfig, args []string) ([]*config.SinkConfig, error) {
sink := peek(stack)
ensureFilter(sink)
sink.Transform.FilterConfig.AddPredicate(structure.ChannelKey, structure.InfoChannelName)
return stack, ops, nil
return stack, nil
},
},
{
name: Stdout,
desc: "Use Stdout output for this sink",
builder: func(stack []*config.SinkConfig, ops []string) ([]*config.SinkConfig, []string, error) {
builder: func(stack []*config.SinkConfig, args []string) ([]*config.SinkConfig, error) {
sink := peek(stack)
ensureOutput(sink)
sink.Output.OutputType = config.Stdout
return stack, ops, nil
return stack, nil
},
},
{
name: Stderr,
desc: "Use Stderr output for this sink",
builder: func(stack []*config.SinkConfig, ops []string) ([]*config.SinkConfig, []string, error) {
builder: func(stack []*config.SinkConfig, args []string) ([]*config.SinkConfig, error) {
sink := peek(stack)
ensureOutput(sink)
sink.Output.OutputType = config.Stderr
return stack, ops, nil
return stack, nil
},
},
{
name: Terminal,
desc: "Use the the terminal output format for this sink",
builder: func(stack []*config.SinkConfig, ops []string) ([]*config.SinkConfig, []string, error) {
builder: func(stack []*config.SinkConfig, args []string) ([]*config.SinkConfig, error) {
sink := peek(stack)
ensureOutput(sink)
sink.Output.Format = loggers.TerminalFormat
return stack, ops, nil
return stack, nil
},
},
{
name: JSON,
desc: "Use the the terminal output format for this sink",
builder: func(stack []*config.SinkConfig, args []string) ([]*config.SinkConfig, error) {
sink := peek(stack)
ensureOutput(sink)
sink.Output.Format = loggers.JSONFormat
return stack, nil
},
},
{
name: File,
desc: "Use the the terminal output format for this sink",
nargs: 1,
builder: func(stack []*config.SinkConfig, args []string) ([]*config.SinkConfig, error) {
sink := peek(stack)
ensureOutput(sink)
sink.Output.OutputType = config.File
sink.Output.FileConfig = &config.FileConfig{
Path: args[0],
}
return stack, nil
},
},
}
......@@ -149,16 +175,26 @@ func Describe(name string) string {
func BuildSinkConfig(ops ...string) (*config.SinkConfig, error) {
stack := []*config.SinkConfig{config.Sink()}
var err error
pos := 0
for len(ops) > 0 {
// Keep applying instructions until their are no ops left
preset, ok := instructionsMap[ops[0]]
instruction, ok := instructionsMap[ops[0]]
if !ok {
return nil, fmt.Errorf("could not find logging preset '%s'", ops[0])
}
stack, ops, err = preset.builder(stack, ops[1:])
// pop instruction name
ops = ops[1:]
if len(ops) < instruction.nargs {
return nil, fmt.Errorf("did not have enough arguments for instruction %s at position %v "+
"(requires %v arguments)", instruction.name, pos, instruction.nargs)
}
stack, err = instruction.builder(stack, ops[:instruction.nargs])
if err != nil {
return nil, err
}
// pop instruction args
ops = ops[instruction.nargs:]
pos++
}
return stack[0], nil
}
......
......@@ -39,3 +39,13 @@ func TestMinimalPreset(t *testing.T) {
//fmt.Println(config.TOMLString(expectedSink), "\n", config.TOMLString(builtSink))
assert.Equal(t, config.TOMLString(expectedSink), config.TOMLString(builtSink))
}
func TestFileOutput(t *testing.T) {
path := "foo.log"
builtSink, err := BuildSinkConfig(Down, File, path, JSON)
require.NoError(t, err)
expectedSink := config.Sink().
AddSinks(config.Sink().SetOutput(config.FileOutput(path).SetFormat(loggers.JSONFormat)))
//fmt.Println(config.TOMLString(expectedSink), "\n", config.TOMLString(builtSink))
assert.Equal(t, config.TOMLString(expectedSink), config.TOMLString(builtSink))
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment