Skip to content

Commit

Permalink
add ability to print inline config for better readability in grafana
Browse files Browse the repository at this point in the history
  • Loading branch information
slim-bean committed Jul 11, 2020
1 parent ff43ca7 commit 02c923b
Showing 1 changed file with 90 additions and 5 deletions.
95 changes: 90 additions & 5 deletions cmd/loki/main.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package main

import (
"errors"
"flag"
"fmt"
"io"
"os"
"reflect"
"strings"

"github.com/go-kit/kit/log/level"
"github.com/prometheus/client_golang/prometheus"
Expand All @@ -26,9 +29,13 @@ func init() {
prometheus.MustRegister(version.NewCollector("loki"))
}

var lineReplacer = strings.NewReplacer("\n", "\\n ")

func main() {
printVersion := flag.Bool("version", false, "Print this builds version information")
printConfig := flag.Bool("print-config-stderr", false, "Dump the entire YAML config Loki will run with to stderr")
printConfig := flag.Bool("print-config-stderr", false, "Dump the entire Loki config object to stderr")
printConfigInline := flag.Bool("print-config-stderr-inline", false, "Dump the entire Loki config object to stderr broken up by sections with escaped newline characters, "+
"this will display much better when captured by Loki and shown in Grafana")

var config loki.Config
if err := cfg.Parse(&config); err != nil {
Expand Down Expand Up @@ -61,11 +68,16 @@ func main() {
}

if *printConfig {
lc, err := yaml.Marshal(&config)
err := dumpConfig(os.Stderr, &config, false)
if err != nil {
level.Error(util.Logger).Log("msg", "failed to marshal config for pretty printing", "err", err.Error())
} else {
fmt.Fprintf(os.Stderr, "---\n# Loki Config\n# %s\n%s\n\n", version.Info(), string(lc))
level.Error(util.Logger).Log("msg", "failed to print config to stderr", "err", err.Error())
}
}

if *printConfigInline {
err := dumpConfig(os.Stderr, &config, true)
if err != nil {
level.Error(util.Logger).Log("msg", "failed to print config to stderr", "err", err.Error())
}
}

Expand Down Expand Up @@ -94,3 +106,76 @@ func main() {
err = t.Run()
util.CheckFatal("running loki", err)
}

func dumpConfig(w io.Writer, config *loki.Config, escapeNewlines bool) error {
if !escapeNewlines {
lc, err := yaml.Marshal(&config)
if err != nil {
return err
}
fmt.Fprintf(w, "---\n# Loki Config\n# %s\n%s\n\n", version.Info(), string(lc))
return nil
}

s := reflect.ValueOf(config).Elem()
typeOfT := s.Type()

for i := 0; i < s.NumField(); i++ {
f := s.Field(i)
if !f.CanInterface() {
continue
}
// Lookup the yaml tag to print the field name by the yaml tag, skip if it's not present or empty
if alias, ok := typeOfT.Field(i).Tag.Lookup("yaml"); ok {
if alias == "" {
continue
} else {
// yaml tags can contain other data like `omitempty` so split by comma and only return first result
fmt.Fprint(w, strings.Split(alias, ",")[0]+": ")
}
} else {
continue
}

if f.Kind() == reflect.Slice {
return errors.New("the config dumping function was not programmed to handle a configuration array as a top level item in the Loki config")
}

kind := f.Kind()
val := f.Interface()

// Dereference any pointers so we can properly determine the kind of the underlying object
if f.Kind() == reflect.Ptr {
if !f.IsNil() {
kind = f.Elem().Kind()
val = f.Elem().Interface()
}
}

// If the field is a struct, unmarshal it with a yaml unmarshaller and print it
if kind == reflect.Struct {
err := unmarshall(w, val)
if err != nil {
return err
}
} else {
// If it's not a struct, just print the value
fmt.Fprint(w, val)
}
fmt.Fprint(w, "\n")
}

os.Exit(0)

return nil
}

func unmarshall(w io.Writer, v interface{}) error {
fmt.Fprint(w, "\\n")
sc, err := yaml.Marshal(v)
if err != nil {
return err
}
fmt.Fprint(w, lineReplacer.Replace(string(sc)))
return nil
}

0 comments on commit 02c923b

Please sign in to comment.