Skip to content

Commit

Permalink
Debug logging
Browse files Browse the repository at this point in the history
This PR adds debug logging. Debug logging can be enabled through flags
to the yamlfmt command, and will tell you in very noisy detail about
things that are going on. Debug groups are separated into codes, so that
only certain debug logs can be enabled if you are debugging a specific
problem.

I also fixed a bug I introduced in the last config PR with the `-conf`
flag. It is fixed before ever going out in a release, so it will only
affect someone who installed from that exact commit before I fix it
here.
  • Loading branch information
braydonk committed Feb 3, 2024
1 parent be7dd1b commit 7bb4348
Show file tree
Hide file tree
Showing 10 changed files with 112 additions and 25 deletions.
38 changes: 22 additions & 16 deletions cmd/yamlfmt/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/google/yamlfmt"
"github.com/google/yamlfmt/command"
"github.com/google/yamlfmt/internal/collections"
"github.com/google/yamlfmt/internal/logger"
"github.com/mitchellh/mapstructure"
)

Expand All @@ -28,7 +29,7 @@ const configHomeDir string = "yamlfmt"
var (
errNoConfFlag = errors.New("config path not specified in --conf")
errConfPathInvalid = errors.New("config path specified in --conf was invalid")
errConfPathNotExist = errors.New("config path does not exist")
errConfPathNotExist = errors.New("no config file found")
errConfPathIsDir = errors.New("config path is dir")
errNoConfigHome = errors.New("missing required env var for config home")
)
Expand All @@ -40,13 +41,13 @@ type configPathError struct {

func (e *configPathError) Error() string {
if errors.Is(e.err, errConfPathInvalid) {
return fmt.Sprintf("Config path %s was invalid", e.path)
return fmt.Sprintf("config path %s was invalid", e.path)
}
if errors.Is(e.err, errConfPathNotExist) {
return fmt.Sprintf("Config path %s does not exist", e.path)
return fmt.Sprintf("no config file found in directory %s", filepath.Dir(e.path))
}
if errors.Is(e.err, errConfPathIsDir) {
return fmt.Sprintf("Config path %s is a directory", e.path)
return fmt.Sprintf("config path %s is a directory", e.path)
}
return e.err.Error()
}
Expand Down Expand Up @@ -100,21 +101,24 @@ func getConfigPath() (string, error) {

// All else fails, no path and no error (signals to
// use default config).
logger.Debug(logger.DebugCodeConfig, "No config file found, using default config")
return "", nil
}

func getConfigPathFromFlag() (string, error) {
// If there is a path specified in the conf flag, that takes precedence
configPath := *flagConf
if configPath == "" {
logger.Debug(logger.DebugCodeConfig, "No config path specified in -conf")
return configPath, errNoConfFlag
}
// Then we check if we want the global config
if *flagGlobalConf {
logger.Debug(logger.DebugCodeConfig, "Using -global_conf flag")
return getConfigPathFromXdgConfigHome()
}

return "", validatePath(configPath)
logger.Debug(logger.DebugCodeConfig, "Using config path %s from -conf flag", configPath)
return configPath, validatePath(configPath)
}

// This function searches up the directory tree until it finds
Expand All @@ -132,23 +136,14 @@ func getConfigPathFromDirTree() (string, error) {
for dir != filepath.Dir(dir) {
configPath, err := getConfigPathFromDir(dir)
if err == nil {
logger.Debug(logger.DebugCodeConfig, "Found config at %s", configPath)
return configPath, nil
}
dir = filepath.Dir(dir)
}
return "", errConfPathNotExist
}

func getConfigPathFromDir(dir string) (string, error) {
for filename := range configFileNames {
configPath := filepath.Join(dir, filename)
if err := validatePath(configPath); err == nil {
return configPath, nil
}
}
return "", errConfPathNotExist
}

func getConfigPathFromConfigHome() (string, error) {
// Build tags are a veritable pain in the behind,
// I'm putting both config home functions in this
Expand Down Expand Up @@ -184,6 +179,17 @@ func getConfigPathFromAppDataLocal() (string, error) {
return getConfigPathFromDir(homeConfigPath)
}

func getConfigPathFromDir(dir string) (string, error) {
for filename := range configFileNames {
configPath := filepath.Join(dir, filename)
if err := validatePath(configPath); err == nil {
return configPath, nil
}
}
logger.Debug(logger.DebugCodeConfig, "No config file found in %s", dir)
return "", errConfPathNotExist
}

func validatePath(path string) error {
info, err := os.Stat(path)
if err != nil {
Expand Down
2 changes: 2 additions & 0 deletions cmd/yamlfmt/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,14 @@ operation without performing it.`)
flagExclude = arrayFlag{}
flagFormatter = arrayFlag{}
flagExtensions = arrayFlag{}
flagDebug = arrayFlag{}
)

func bindArrayFlags() {
flag.Var(&flagExclude, "exclude", "Paths to exclude in the chosen format (standard or doublestar)")
flag.Var(&flagFormatter, "formatter", "Config value overrides to pass to the formatter")
flag.Var(&flagExtensions, "extensions", "File extensions to use for standard path collection")
flag.Var(&flagDebug, "debug", "Debug codes to activate for debug logging")
}

type arrayFlag []string
Expand Down
5 changes: 5 additions & 0 deletions cmd/yamlfmt/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"github.com/google/yamlfmt"
"github.com/google/yamlfmt/command"
"github.com/google/yamlfmt/formatters/basic"
"github.com/google/yamlfmt/internal/logger"
)

var version string = "0.11.0"
Expand All @@ -42,6 +43,10 @@ func run() error {
return nil
}

for _, code := range flagDebug {
logger.ActivateDebugCode(code)
}

c := &command.Command{
Operation: getOperationFromFlag(),
Registry: getFullRegistry(),
Expand Down
11 changes: 11 additions & 0 deletions docs/command-usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ The string array flags can be a bit confusing. See the [String Array Flags](#str
| Exclude | `-exclude` | []string | `yamlfmt -exclude ./not/,these_paths.yaml` | Patterns to exclude from path collection. These add to exclude patterns specified in the [config file](./config-file.md) |
| Extensions | `-extensions` | []string | `yamlfmt -extensions yaml,yml` | Extensions to use in standard path collection. Has no effect in Doublestar mode. These add to extensions specified in the [config file](./config-file.md)
| Formatter Config | `-formatter` | []string | `yamlfmt -formatter indent=2,include_document_start=true` | Provide configuration values for the formatter. See [Formatter Configuration Options](./config-file.md#basic-formatter) for options. Each field is specified as `configkey=value`. |
| Debug Logging | `-debug` | []string | `yamlfmt -debug paths,config` | Enable debug logging. See [Debug Logging](#debug-logging) for more information. |

#### String Array Flags

Expand All @@ -96,3 +97,13 @@ String array flags can be provided in two ways. For example with a flag called `
* Technically they can be combined but why would you?
- `-arrFlag a,b -arrFlag c`
- Result: `arrFlag: [a b c]`

## Debug Logging

Debug logging can be enabled through the `-debug` [array flag](#string-array-flags). The following is the list of supported debug codes:
* `paths`
- Log the details for the path discovery process. Use it to debug your include/exclude patterns.
* `config`
- Log the details for the configuration loading process. Use it to figure out which config file yamlfmt uses and why.
* `all`
- Enable all available debug codes.
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
---
hello:
world: 1
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
hello:
world: 1
world: 1
2 changes: 1 addition & 1 deletion integrationtest/command/testdata/path_arg/before/x.yaml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
6tark:
does: 64
does: 64
12 changes: 9 additions & 3 deletions internal/collections/set.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,18 @@ package collections

type Set[T comparable] map[T]struct{}

func (s Set[T]) Add(el T) {
s[el] = struct{}{}
func (s Set[T]) Add(el ...T) {
for _, el := range el {
s[el] = struct{}{}
}
}

func (s Set[T]) Remove(el T) {
func (s Set[T]) Remove(el T) bool {
if !s.Contains(el) {
return false
}
delete(s, el)
return true
}

func (s Set[T]) Contains(el T) bool {
Expand Down
37 changes: 37 additions & 0 deletions internal/logger/debug.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package logger

import (
"fmt"

"github.com/google/yamlfmt/internal/collections"
)

type DebugCode int

const (
DebugCodeAny DebugCode = iota
DebugCodeConfig
DebugCodePaths
)

var (
supportedDebugCodes = map[string][]DebugCode{
"config": {DebugCodeConfig},
"paths": {DebugCodePaths},
"all": {DebugCodeConfig, DebugCodePaths},
}
activeDebugCodes = collections.Set[DebugCode]{}
)

func ActivateDebugCode(code string) {
if debugCodes, ok := supportedDebugCodes[code]; ok {
activeDebugCodes.Add(debugCodes...)
}
}

// Debug prints a message if the given debug code is active.
func Debug(code DebugCode, msg string, args ...any) {
if activeDebugCodes.Contains(code) {
fmt.Printf("[DEBUG]: %s\n", fmt.Sprintf(msg, args...))
}
}
27 changes: 24 additions & 3 deletions path_collector.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

"github.com/bmatcuk/doublestar/v4"
"github.com/google/yamlfmt/internal/collections"
"github.com/google/yamlfmt/internal/logger"
)

type PathCollector interface {
Expand All @@ -21,6 +22,7 @@ type FilepathCollector struct {
}

func (c *FilepathCollector) CollectPaths() ([]string, error) {
logger.Debug(logger.DebugCodePaths, "using file path matching. include patterns: %s", c.Include)
pathsFound := []string{}
for _, inclPath := range c.Include {
info, err := os.Stat(inclPath)
Expand All @@ -40,6 +42,7 @@ func (c *FilepathCollector) CollectPaths() ([]string, error) {
}
pathsFound = append(pathsFound, paths...)
}
logger.Debug(logger.DebugCodePaths, "found paths: %s", pathsFound)

pathsFoundSet := collections.SliceToSet(pathsFound)
pathsToFormat := collections.SliceToSet(pathsFound)
Expand All @@ -53,17 +56,25 @@ func (c *FilepathCollector) CollectPaths() ([]string, error) {
}

if info.IsDir() {
logger.Debug(logger.DebugCodePaths, "for exclude dir: %s", exclPath)
for foundPath := range pathsFoundSet {
if strings.HasPrefix(foundPath, exclPath) {
logger.Debug(logger.DebugCodePaths, "excluding %s", foundPath)
pathsToFormat.Remove(foundPath)
}
}
} else {
pathsToFormat.Remove(exclPath)
logger.Debug(logger.DebugCodePaths, "for exclude file: %s", exclPath)
removed := pathsToFormat.Remove(exclPath)
if removed {
logger.Debug(logger.DebugCodePaths, "found in paths, excluding")
}
}
}

return pathsToFormat.ToSlice(), nil
pathsToFormatSlice := pathsToFormat.ToSlice()
logger.Debug(logger.DebugCodePaths, "paths to format: %s", pathsToFormatSlice)
return pathsToFormatSlice, nil
}

func (c *FilepathCollector) walkDirectoryForYaml(dir string) ([]string, error) {
Expand Down Expand Up @@ -93,12 +104,15 @@ type DoublestarCollector struct {
}

func (c *DoublestarCollector) CollectPaths() ([]string, error) {
logger.Debug(logger.DebugCodePaths, "using doublestar path matching. include patterns: %s", c.Include)
includedPaths := []string{}
for _, pattern := range c.Include {
logger.Debug(logger.DebugCodePaths, "trying pattern: %s", pattern)
globMatches, err := doublestar.FilepathGlob(pattern)
if err != nil {
return nil, err
}
logger.Debug(logger.DebugCodePaths, "pattern %s matches: %s", pattern, globMatches)
includedPaths = append(includedPaths, globMatches...)
}

Expand All @@ -109,19 +123,26 @@ func (c *DoublestarCollector) CollectPaths() ([]string, error) {
continue
}
excluded := false
logger.Debug(logger.DebugCodePaths, "calculating excludes for %s", path)
for _, pattern := range c.Exclude {
match, err := doublestar.PathMatch(filepath.Clean(pattern), path)
if err != nil {
return nil, err
}
if match {
logger.Debug(logger.DebugCodePaths, "pattern %s matched, excluding", pattern)
excluded = true
break
}
logger.Debug(logger.DebugCodePaths, "pattern %s did not match path", pattern)
}
if !excluded {
logger.Debug(logger.DebugCodePaths, "path %s included", path)
pathsToFormatSet.Add(path)
}
}

return pathsToFormatSet.ToSlice(), nil
pathsToFormat := pathsToFormatSet.ToSlice()
logger.Debug(logger.DebugCodePaths, "paths to format: %s", pathsToFormat)
return pathsToFormat, nil
}

0 comments on commit 7bb4348

Please sign in to comment.