Skip to content

Commit

Permalink
feat: Add runtime logging with env. variable GITHOOKS_LOG_LEVEL ⚓ (#…
Browse files Browse the repository at this point in the history
…148)

- A value `debug`, `info`, `warn`, `error` or `disable` can be set
  in env. variable `GITHOOKS_LOG_LEVEL` to set the log level during runner execution.
  • Loading branch information
gabyx authored Mar 26, 2024
1 parent 570edd7 commit 9250172
Show file tree
Hide file tree
Showing 10 changed files with 96 additions and 26 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -643,6 +643,7 @@ not globally be defined.
| `GITHOOKS_CONTAINER_RUN` (defined by Githooks) | If a hook is run over a container, this variable is set and `true` |
| `GITHOOKS_DISABLE` | If defined, disables running hooks run by Githooks,<br>except `git lfs` and the replaced old hooks. |
| `GITHOOKS_RUNNER_TRACE` | If defined, enables tracing during <br>Githooks runner execution. A value of `1` enables more output. |
| `GITHOOKS_LOG_LEVEL` | A value `debug`, `info`, `warn`, `error` or `disable` sets the log level during <br>Githooks runner execution. |
| `GITHOOKS_SKIP_NON_EXISTING_SHARED_HOOKS=true` | Skips on `true` and fails on `false` (or empty) for non-existing shared hooks. <br>See [Trusting Hooks](#trusting-hooks). |
| `GITHOOKS_SKIP_UNTRUSTED_HOOKS=true` | Skips on `true` and fails on `false` (or empty) for untrusted hooks. <br>See [Trusting Hooks](#trusting-hooks). |

Expand Down
2 changes: 1 addition & 1 deletion githooks/apps/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func installSignalHandling() *cm.InterruptContext {

func mainRun(cleanUpX *cm.InterruptContext) (exitCode int) {

log, err := cm.CreateLogContext(false)
log, err := cm.CreateLogContext(false, false)
cm.AssertOrPanic(err == nil, "Could not create log")

exitCode = 1
Expand Down
2 changes: 1 addition & 1 deletion githooks/apps/dialog/dialog.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func mainRun() (exitCode int) {
// ===============================================================

// We only log to stderr, because we need stdout for the output.
log, err := cm.CreateLogContext(true)
log, err := cm.CreateLogContext(true, false)
cm.AssertOrPanic(err == nil, "Could not create log")

// Handle all panics and report the error
Expand Down
2 changes: 1 addition & 1 deletion githooks/apps/dialog/tools/generate-doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ func main() {

docRoot := path.Join(root, "docs", "dialog")

log, err := cm.CreateLogContext(false)
log, err := cm.CreateLogContext(false, false)
cm.AssertNoErrorPanic(err, "Could not create log")

ctx := dcm.CmdContext{Log: log}
Expand Down
2 changes: 1 addition & 1 deletion githooks/apps/runner/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ func createLog() {
// might read stdin for certain hooks.
// Either do redirection (which needs to be bombproof)
// or just use stderr.
log, err = cm.CreateLogContext(true)
log, err = cm.CreateLogContext(true, true)
cm.AssertOrPanic(err == nil, "Could not create log")
}

Expand Down
100 changes: 84 additions & 16 deletions githooks/common/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,16 @@ func (w *FormattedWriter) Write(p []byte) (n int, err error) {
return len(p), err
}

// Loglevel constants for runtime switching.
const (
debugLevel = -1
infoLevel = 0
warnLevel = 1
errorLevel = 2

disableLevel = 10
)

// LogContext defines the data for a log context.
type LogContext struct {
stdout *os.File
Expand All @@ -135,6 +145,8 @@ type LogContext struct {
doTrackStats bool
nWarnings int
nErrors int

level int
}

// NewColoredPromptWriter returns a colored prompt writer.
Expand Down Expand Up @@ -164,8 +176,10 @@ func NewColoredErrorWriter(writer io.Writer) io.Writer {
return &FormattedWriter{format: colorError, writer: writer}
}

// CreateLogContext creates a log context.
func CreateLogContext(onlyStderr bool) (*LogContext, error) {
// CreateLogContext creates a log context and if `setFromEnv` is set will
// set the log level from the environment variable `GITHOOKS_LOG_LEVEL` which can be
// `DebugLevel`, `InfoLevel`, `WarnLevel`, `ErrorLevel`, `DisableLevel`.
func CreateLogContext(onlyStderr bool, setLogLevelFromEnv bool) (*LogContext, error) {
var l LogContext
l.stdout = os.Stdout
l.stderr = os.Stderr
Expand All @@ -179,6 +193,8 @@ func CreateLogContext(onlyStderr bool) (*LogContext, error) {
l.isColorSupported = (l.infoIsTerminal && l.errorIsTerminal) && color.IsSupportColor()

l.setupWriters()
l.setupLogLevel(setLogLevelFromEnv)

l.doTrackStats = true

return &l, nil
Expand All @@ -198,6 +214,34 @@ func (c *LogContext) setupWriters() {
}
}

func parseLogLevel() int {
level := strings.TrimSpace(os.Getenv("GITHOOKS_LOG_LEVEL"))

switch level {
case "debug":
return debugLevel
default: // nolint: gocritic
fallthrough
case "info":
return infoLevel
case "warn":
return warnLevel
case "error":
return errorLevel
case "disable":
return disableLevel
}
}

func (c *LogContext) setupLogLevel(fromEnv bool) {
if DebugLog {
// Allways overwrites.
c.level = debugLevel
} else if fromEnv {
c.level = parseLogLevel()
}
}

// GetIndent returns the used indent.
func (c *LogContext) GetIndent() string {
return indent
Expand Down Expand Up @@ -235,55 +279,67 @@ func (c *LogContext) IsErrorATerminal() bool {

// Debug logs a debug message.
func (c *LogContext) Debug(lines ...string) {
if DebugLog {
if c.level <= debugLevel {
fmt.Fprint(c.debug, FormatMessage(debugSuffix, indent, lines...), "\n")
}
}

// DebugF logs a debug message.
func (c *LogContext) DebugF(format string, args ...interface{}) {
if DebugLog {
if c.level <= debugLevel {
fmt.Fprint(c.debug, FormatMessageF(debugSuffix, indent, format, args...), "\n")
}
}

// Info logs a info message.
func (c *LogContext) Info(lines ...string) {
fmt.Fprint(c.info, FormatInfo(lines...), "\n")
if c.level <= infoLevel {
fmt.Fprint(c.info, FormatInfo(lines...), "\n")
}
}

// InfoF logs a info message.
func (c *LogContext) InfoF(format string, args ...interface{}) {
fmt.Fprint(c.info, FormatInfoF(format, args...), "\n")
if c.level <= infoLevel {
fmt.Fprint(c.info, FormatInfoF(format, args...), "\n")
}
}

// Warn logs a warning message.
func (c *LogContext) Warn(lines ...string) {
fmt.Fprint(c.warn, FormatMessage(warnSuffix, indent, lines...), "\n")
if c.level <= warnLevel {
fmt.Fprint(c.warn, FormatMessage(warnSuffix, indent, lines...), "\n")
}
if c.doTrackStats {
c.nWarnings++
}
}

// WarnF logs a warning message.
func (c *LogContext) WarnF(format string, args ...interface{}) {
fmt.Fprint(c.warn, FormatMessageF(warnSuffix, indent, format, args...), "\n")
if c.level <= warnLevel {
fmt.Fprint(c.warn, FormatMessageF(warnSuffix, indent, format, args...), "\n")
}
if c.doTrackStats {
c.nWarnings++
}
}

// Error logs an error.
func (c *LogContext) Error(lines ...string) {
fmt.Fprint(c.error, FormatMessage(errorSuffix, indent, lines...), "\n")
if c.level <= errorLevel {
fmt.Fprint(c.error, FormatMessage(errorSuffix, indent, lines...), "\n")
}
if c.doTrackStats {
c.nErrors++
}
}

// ErrorF logs an error.
func (c *LogContext) ErrorF(format string, args ...interface{}) {
fmt.Fprint(c.error, FormatMessageF(errorSuffix, indent, format, args...), "\n")
if c.level <= errorLevel {
fmt.Fprint(c.error, FormatMessageF(errorSuffix, indent, format, args...), "\n")
}
if c.doTrackStats {
c.nErrors++
}
Expand Down Expand Up @@ -324,14 +380,22 @@ func (c *LogContext) ErrorWithStacktraceF(format string, args ...interface{}) {
// Panic logs an error and calls panic with a GithooksFailure.
func (c *LogContext) Panic(lines ...string) {
m := FormatMessage(errorSuffix, indent, lines...)
fmt.Fprint(c.error, m, "\n")

if c.level <= errorLevel {
fmt.Fprint(c.error, m, "\n")
}

panic(GithooksFailure{m})
}

// PanicF logs an error and calls panic with a GithooksFailure.
func (c *LogContext) PanicF(format string, args ...interface{}) {
m := FormatMessageF(errorSuffix, indent, format, args...)
fmt.Fprint(c.error, m, "\n")

if c.level <= errorLevel {
fmt.Fprint(c.error, m, "\n")
}

panic(GithooksFailure{m})
}

Expand Down Expand Up @@ -374,16 +438,19 @@ func (c *LogContext) AddFileWriter(file *os.File) {

c.file = file

if c.debug != nil {
if c.debug != nil && c.level <= debugLevel {
c.debug = io.MultiWriter(c.debug, file)
}
if c.info != nil {

if c.info != nil && c.level <= infoLevel {
c.info = io.MultiWriter(c.info, file)
}
if c.warn != nil {

if c.warn != nil && c.level <= warnLevel {
c.warn = io.MultiWriter(c.warn, file)
}
if c.error != nil {

if c.error != nil && c.level <= errorLevel {
c.error = io.MultiWriter(c.error, file)
}
}
Expand All @@ -394,6 +461,7 @@ func (c *LogContext) RemoveFileWriter() {
c.setupWriters()
c.file.Close()
}

c.file = nil
}

Expand Down
4 changes: 2 additions & 2 deletions githooks/container/manager-container_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ RUN apk add bash
_, _ = io.WriteString(file, dockerfile)
file.Close()

log, err := cm.CreateLogContext(false)
log, err := cm.CreateLogContext(false, false)
assert.Nil(t, err)

exists, err := mgr.ImageExists("alpine:mine-special")
Expand Down Expand Up @@ -98,7 +98,7 @@ RUN apk add bashhhh
_, _ = io.WriteString(file, dockerfile)
file.Close()

log, err := cm.CreateLogContext(false)
log, err := cm.CreateLogContext(false, false)
assert.Nil(t, err)

_, err = mgr.ImageBuild(log, file.Name(), ".", "stage2", "alpine:mine-special")
Expand Down
2 changes: 1 addition & 1 deletion githooks/hooks/images_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ RUN apk add bash
err = os.WriteFile(path.Join(repo, ".githooks/docker/Dockerfile"), content, cm.DefaultFileModeFile)
assert.Nil(t, err)

log, err := cm.CreateLogContext(false)
log, err := cm.CreateLogContext(false, false)
assert.Nil(t, err)

err = UpdateImages(log, "test-repo", repo, path.Join(repo, ".githooks"), "")
Expand Down
5 changes: 3 additions & 2 deletions githooks/prompt/show-gui-impl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@
package prompt_test

import (
"os"

cm "github.com/gabyx/githooks/githooks/common"
"github.com/gabyx/githooks/githooks/prompt"
"os"

"testing"
)

func TestCoverage(t *testing.T) {

log, err := cm.CreateLogContext(false)
log, err := cm.CreateLogContext(false, false)
cm.AssertNoErrorPanic(err)

os.Stdin = nil
Expand Down
2 changes: 1 addition & 1 deletion githooks/tools/generate-doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ func main() {

docRoot := path.Join(root, "docs", "cli")

log, err := cm.CreateLogContext(false)
log, err := cm.CreateLogContext(false, false)
cm.AssertNoErrorPanic(err, "Could not create log")

ctx := cmd.NewSettings(log, log, func() {}, nil)
Expand Down

0 comments on commit 9250172

Please sign in to comment.