-
Notifications
You must be signed in to change notification settings - Fork 288
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
saving cli log output to support bundle
- Loading branch information
1 parent
8e728f7
commit 9dfc2b8
Showing
5 changed files
with
165 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
package logger | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"time" | ||
|
||
"github.com/go-logr/logr" | ||
) | ||
|
||
type log struct { | ||
timestamp string | ||
level int | ||
msg string | ||
keyAndValues []interface{} | ||
} | ||
|
||
// CachingLogSink enhances the provided logger's implementation to save logs to memory. | ||
type CachingLogSink struct { | ||
logger logr.Logger | ||
logs []log | ||
} | ||
|
||
func (m *CachingLogSink) getLogs(level int) []log { | ||
filtered := []log{} | ||
|
||
for _, log := range m.logs { | ||
if log.level <= level { | ||
filtered = append(filtered, log) | ||
} | ||
} | ||
|
||
return filtered | ||
} | ||
|
||
func (l *log) keyAndValuesObject() map[string]string { | ||
m := make(map[string]string) | ||
for i := 0; i < len(l.keyAndValues); i += 2 { | ||
strKey := fmt.Sprintf("%v", l.keyAndValues[i]) | ||
value := l.keyAndValues[i+1] | ||
if value != nil || value == "<nil>" { | ||
m[strKey] = "null" | ||
} else { | ||
m[strKey] = fmt.Sprintf("%v", value) | ||
} | ||
|
||
} | ||
|
||
return m | ||
} | ||
|
||
func (l *log) keyAndValuesObjectStr() string { | ||
m := l.keyAndValuesObject() | ||
mJSON, err := json.Marshal(m) | ||
if err != nil { | ||
return fmt.Sprintf("%v", m) | ||
} | ||
|
||
return string(mJSON) | ||
} | ||
|
||
func formatLog(l log) string { | ||
if l.level < 0 { | ||
return fmt.Sprintf("%s \t %s", l.msg, l.keyAndValuesObjectStr()) | ||
} | ||
|
||
return fmt.Sprintf("%s \t %s \t %s \t %s", l.timestamp, fmt.Sprintf("V%d", l.level), l.msg, l.keyAndValuesObjectStr()) | ||
} | ||
|
||
// SetLogger assigns the provided Logger as a base for logging. | ||
func (m *CachingLogSink) SetLogger(l logr.Logger) { | ||
m.logger = l | ||
} | ||
|
||
func (m *CachingLogSink) save(level int, msg string, keysAndValues ...interface{}) { | ||
timestamp := time.Now().Format("2006-01-02T15:04:05.000-0600") | ||
m.logs = append(m.logs, log{timestamp, level, msg, keysAndValues}) | ||
} | ||
|
||
// Init receives optional information about the logr library for LogSink | ||
// implementations that need it. | ||
func (m *CachingLogSink) Init(info logr.RuntimeInfo) { | ||
m.logger.GetSink().Init(info) | ||
} | ||
|
||
// Enabled tests whether this LogSink is enabled at the specified V-level. | ||
// For example, commandline flags might be used to set the logging | ||
// verbosity and disable some info logs. | ||
func (m *CachingLogSink) Enabled(level int) bool { | ||
return m.logger.GetSink().Enabled(level) | ||
} | ||
|
||
// Info logs a non-error message with the given key/value pairs as context. | ||
// | ||
// The msg argument should be used to add some constant description to | ||
// the log line. The key/value pairs can then be used to add additional | ||
// variable information. The key/value pairs should alternate string | ||
// keys and arbitrary values. | ||
func (m *CachingLogSink) Info(level int, msg string, keysAndValues ...interface{}) { | ||
m.logger.GetSink().Info(level, msg, keysAndValues...) | ||
m.save(level, msg, keysAndValues...) | ||
} | ||
|
||
// Error logs an error, with the given message and key/value pairs as | ||
// context. See Logger.Error for more details. | ||
func (m *CachingLogSink) Error(err error, msg string, keysAndValues ...interface{}) { | ||
m.logger.GetSink().Error(err, msg, keysAndValues...) | ||
m.save(-1, msg, append(keysAndValues, err)...) | ||
} | ||
|
||
// WithValues returns a new LogSink with additional key/value pairs. See | ||
// Logger.WithValues for more details. | ||
func (m *CachingLogSink) WithValues(keysAndValues ...interface{}) logr.LogSink { | ||
return m.logger.GetSink().WithValues(keysAndValues...) | ||
} | ||
|
||
// WithName returns a new LogSink with the specified name appended. See | ||
// Logger.WithName for more details. | ||
func (m *CachingLogSink) WithName(name string) logr.LogSink { | ||
return m.logger.GetSink().WithName(name) | ||
} | ||
|
||
// GetLogs returns the logs stored in memory logged from the registered Logger. | ||
func (m *CachingLogSink) GetLogs(level int) []string { | ||
formatted := []string{} | ||
for _, log := range m.getLogs(level) { | ||
if log.level <= level { | ||
formatted = append(formatted, formatLog(log)) | ||
} | ||
} | ||
|
||
return formatted | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters