Skip to content

Commit

Permalink
configurable log writer
Browse files Browse the repository at this point in the history
Signed-off-by: razzle <harry@razzle.cloud>
  • Loading branch information
Noxsios committed Mar 14, 2024
1 parent 1ec8849 commit 8de55bd
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 31 deletions.
11 changes: 4 additions & 7 deletions src/pkg/message/credentials.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ package message

import (
"fmt"
"os"
"strings"

"github.com/defenseunicorns/zarf/src/config"
Expand All @@ -31,8 +30,7 @@ func PrintCredentialTable(state *types.ZarfState, componentsToDeploy []types.Dep
componentsToDeploy = []types.DeployedComponent{{Name: "logging"}, {Name: "git-server"}}
}

// Set output to os.Stderr to avoid creds being printed in logs
pterm.SetDefaultOutput(os.Stderr)
MultLogger.DisableLogFile()

loginData := [][]string{}
if state.RegistryInfo.InternalRegistry {
Expand Down Expand Up @@ -64,7 +62,7 @@ func PrintCredentialTable(state *types.ZarfState, componentsToDeploy []types.Dep

// Restore the log file if it was specified
if !config.SkipLogFile {
UseLogFile()
MultLogger.EnableLogFile()
}
}

Expand Down Expand Up @@ -96,8 +94,7 @@ func PrintComponentCredential(state *types.ZarfState, componentName string) {

// PrintCredentialUpdates displays credentials that will be updated
func PrintCredentialUpdates(oldState *types.ZarfState, newState *types.ZarfState, services []string) {
// Set output to os.Stderr to avoid creds being printed in logs
pterm.SetDefaultOutput(os.Stderr)
MultLogger.DisableLogFile()

for _, service := range services {

Expand Down Expand Up @@ -147,7 +144,7 @@ func PrintCredentialUpdates(oldState *types.ZarfState, newState *types.ZarfState

// Restore the log file if it was specified
if !config.SkipLogFile {
UseLogFile()
MultLogger.EnableLogFile()
}
}

Expand Down
51 changes: 50 additions & 1 deletion src/pkg/message/generic.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@
// Package message provides a rich set of functions for displaying messages to the user.
package message

import "github.com/pterm/pterm"
import (
"io"
"os"

"github.com/pterm/pterm"
)

// Generic is used to implement the io.Writer interface for generic messages.
type Generic struct{}
Expand All @@ -14,3 +19,47 @@ func (g *Generic) Write(p []byte) (n int, err error) {
pterm.Println(text)
return len(p), nil
}

// MultiLogWriter is an implementation of an io.Writer that writes to both a file and a writer.
//
// This is useful for writing to both a log file and the terminal at the same time.
//
// While maintaining the ability to disable one or the other as needed.
//
// This struct is NOT thread-safe and should normally be a global singleton.
type MultiLogWriter struct {
f *os.File
wr io.Writer
multi io.Writer
}

// NewMultiLogWriter creates a new MultiLogWriter instance.
func NewMultiLogWriter(f *os.File, wr io.Writer) *MultiLogWriter {
multi := io.MultiWriter(f, wr)
return &MultiLogWriter{f, wr, multi}
}

// DisableLogFile disables the log file writer.
func (l *MultiLogWriter) DisableLogFile() {
l.multi = l.wr
}

// EnableLogFile enables the log file writer.
func (l *MultiLogWriter) EnableLogFile() {
l.multi = io.MultiWriter(l.f, l.wr)
}

// DisableWriter disables the writer.
func (l *MultiLogWriter) DisableWriter() {
l.multi = l.f
}

// EnableWriter enables the writer.
func (l *MultiLogWriter) EnableWriter() {
l.multi = io.MultiWriter(l.f, l.wr)
}

// Write writes to the multi writer. Satisfaction of the io.Writer interface.
func (l *MultiLogWriter) Write(p []byte) (n int, err error) {
return l.multi.Write(p)
}
40 changes: 17 additions & 23 deletions src/pkg/message/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ package message
import (
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"runtime/debug"
Expand Down Expand Up @@ -44,14 +43,11 @@ var NoProgress bool
// RuleLine creates a line of ━ as wide as the terminal
var RuleLine = strings.Repeat("━", TermWidth)

// LogWriter is the stream to write logs to.
var LogWriter io.Writer = os.Stderr

// logLevel holds the pterm compatible log level integer
var logLevel = InfoLevel

// logFile acts as a buffer for logFile generation
var logFile *os.File
// MultLogger acts as a buffer for MultLogger generation
var MultLogger *MultiLogWriter

// useLogFile controls whether to use the log file or not
var useLogFile bool
Expand Down Expand Up @@ -84,26 +80,24 @@ func init() {

// UseLogFile writes output to stderr and a logFile.
func UseLogFile() {
// If a log file has already been created, don't create another one
if MultLogger != nil {
return
}
// Prepend the log filename with a timestamp.
ts := time.Now().Format("2006-01-02-15-04-05")

var err error
if logFile != nil {
// Use the existing log file if logFile is set
LogWriter = io.MultiWriter(os.Stderr, logFile)
pterm.SetDefaultOutput(LogWriter)
} else {
// Try to create a temp log file if one hasn't been made already
if logFile, err = os.CreateTemp("", fmt.Sprintf("zarf-%s-*.log", ts)); err != nil {
WarnErr(err, "Error saving a log file to a temporary directory")
} else {
useLogFile = true
LogWriter = io.MultiWriter(os.Stderr, logFile)
pterm.SetDefaultOutput(LogWriter)
message := fmt.Sprintf("Saving log file to %s", logFile.Name())
Note(message)
}
// Try to create a temp log file if one hasn't been made already
logFile, err := os.CreateTemp("", fmt.Sprintf("zarf-%s-*.log", ts))
if err != nil {
WarnErr(err, "Error saving a log file to a temporary directory")
}

MultLogger = NewMultiLogWriter(logFile, os.Stderr)

pterm.SetDefaultOutput(MultLogger)
message := fmt.Sprintf("Saving log file to %s", logFile.Name())
Note(message)
}

// SetLogLevel sets the log level.
Expand Down Expand Up @@ -371,7 +365,7 @@ func debugPrinter(offset int, a ...any) {
WithShowLineNumber(true).
WithLineNumberOffset(offset).
WithDebugger(false).
WithWriter(logFile).
WithWriter(MultLogger).
Println(a...)
}
}
Expand Down

0 comments on commit 8de55bd

Please sign in to comment.