diff --git a/internal/logging/logging.go b/internal/logging/logging.go index c8d0094..05e9534 100644 --- a/internal/logging/logging.go +++ b/internal/logging/logging.go @@ -2,14 +2,20 @@ package logging import ( "fmt" + "hash/fnv" "log" "os" + "strconv" ) const ( ColorNone = iota ColorRed ColorGreen + ColorYellow + ColorBlue + ColorPurple + ColorTeal ) type Logger struct { @@ -43,14 +49,15 @@ func (l *Logger) Errorf(debug bool, format string, v ...interface{}) { // Eventf writes an event with timestamp to stdout func (l *Logger) Eventf(color int, format string, v ...interface{}) { msg := fmt.Sprintf(format, v...) - - switch color { - case ColorRed: - msg = fmt.Sprintf("\x1b[31;1m%s\x1b[0m", msg) - case ColorGreen: - msg = fmt.Sprintf("\x1b[32;1m%s\x1b[0m", msg) - default: + if color != ColorNone { + msg = fmt.Sprintf("\x1b[%d;1m%s\x1b[0m", 30+color, msg) } l.eventLogger.Printf("%s", msg) } + +func GetColorByUID(uid int) int { + h := fnv.New32a() + h.Write([]byte(strconv.Itoa(uid))) + return (int(h.Sum32()) % (ColorTeal)) + 1 +} diff --git a/internal/logging/logging_test.go b/internal/logging/logging_test.go index 690a2c6..2112302 100644 --- a/internal/logging/logging_test.go +++ b/internal/logging/logging_test.go @@ -33,6 +33,7 @@ var logTests = []struct { func TestLogging(t *testing.T) { for i, tt := range logTests { actual := captureOutput(tt.logger, tt.test) + log.Printf("OUT: %s", actual) // check colors and remove afterwards colors := ansiMatcher.FindAll(actual, 2) @@ -55,3 +56,46 @@ func captureOutput(logger *log.Logger, f func()) []byte { f() return buf.Bytes() } + +func TestGetColorByUID(t *testing.T) { + tests := []struct { + uid int + color int + }{ + {uid: 0, color: 4}, + {uid: 1, color: 5}, + {uid: 2, color: 2}, + {uid: 3, color: 3}, + {uid: 99999999999, color: 5}, + } + + for _, tt := range tests { + color := GetColorByUID(tt.uid) + if color != tt.color { + t.Errorf("GetColorByUID(%d)=%d but want %d", tt.uid, color, tt.color) + } + } + + minColor := 9999999 + maxColor := -9999999 + for i := 0; i < 1000; i++ { + color := GetColorByUID(i) + if color < 1 || color > ColorTeal { + t.Fatalf("GetColorByUID(%d)=%d but this is out of range [%d, %d]", i, color, ColorRed, ColorTeal) + } + + if color < minColor { + minColor = color + } + if color > maxColor { + maxColor = color + } + } + + if minColor != 1 { + t.Errorf("GetColorByUID returned minimum color %d, not %d, on 1000 trials, which is extremely unlikely", minColor, 1) + } + if maxColor != ColorTeal { + t.Errorf("GetColorByUID returned maximum color %d, not %d, on 1000 trials, which is extremely unlikely", maxColor, ColorTeal) + } +} diff --git a/internal/pspy/pspy.go b/internal/pspy/pspy.go index bdf37ad..70cd7c6 100644 --- a/internal/pspy/pspy.go +++ b/internal/pspy/pspy.go @@ -57,7 +57,7 @@ func Start(cfg *config.Config, b *Bindings, sigCh chan os.Signal) chan struct{} func printOutput(cfg *config.Config, b *Bindings, chans *chans) chan struct{} { exit := make(chan struct{}) - fsEventColor, psEventColor := getColors(cfg.Colored) + // fsEventColor, psEventColor := getColors(cfg.Colored) go func() { for { @@ -67,11 +67,15 @@ func printOutput(cfg *config.Config, b *Bindings, chans *chans) chan struct{} { exit <- struct{}{} case fe := <-chans.fsEventCh: if cfg.LogFS { - b.Logger.Eventf(fsEventColor, "FS: %+v", fe) + b.Logger.Eventf(logging.ColorNone, "FS: %+v", fe) } case pe := <-chans.psEventCh: if cfg.LogPS { - b.Logger.Eventf(psEventColor, "CMD: %+v", pe) + color := logging.ColorNone + if cfg.Colored { + color = logging.GetColorByUID(pe.UID) + } + b.Logger.Eventf(color, "CMD: %+v", pe) } } } @@ -79,17 +83,6 @@ func printOutput(cfg *config.Config, b *Bindings, chans *chans) chan struct{} { return exit } -func getColors(colored bool) (fsEventColor int, psEventColor int) { - if colored { - fsEventColor = logging.ColorGreen - psEventColor = logging.ColorRed - } else { - fsEventColor = logging.ColorNone - psEventColor = logging.ColorNone - } - return -} - func initFSW(fsw FSWatcher, rdirs, dirs []string, logger Logger) { errCh, doneCh := fsw.Init(rdirs, dirs) for { diff --git a/internal/pspy/pspy_test.go b/internal/pspy/pspy_test.go index c5cd88d..f66aefe 100644 --- a/internal/pspy/pspy_test.go +++ b/internal/pspy/pspy_test.go @@ -68,24 +68,6 @@ func TestStartPSS(t *testing.T) { expectMessage(t, l.Error, "ERROR: error during refresh") } -func TestGetColors(t *testing.T) { - tests := []struct { - colored bool - fsEventColor int - psEventColor int - }{ - {colored: true, fsEventColor: logging.ColorGreen, psEventColor: logging.ColorRed}, - {colored: false, fsEventColor: logging.ColorNone, psEventColor: logging.ColorNone}, - } - - for _, tt := range tests { - c1, c2 := getColors(tt.colored) - if c1 != tt.fsEventColor || c2 != tt.psEventColor { - t.Errorf("Got wrong colors when colored=%t: expected %d, %d but got %d, %d", tt.colored, tt.fsEventColor, tt.psEventColor, c1, c2) - } - } -} - func TestStart(t *testing.T) { drainFor := 10 * time.Millisecond triggerEvery := 999 * time.Second @@ -126,9 +108,9 @@ func TestStart(t *testing.T) { <-time.After(2 * drainFor) expectMessage(t, l.Info, "done") expectTrigger(t, pss.runTriggerCh) // pss receives triggers from fsw - expectMessage(t, l.Event, fmt.Sprintf("%d CMD: UID=1000 PID=12345 | pss event", logging.ColorRed)) + expectMessage(t, l.Event, fmt.Sprintf("%d CMD: UID=1000 PID=12345 | pss event", logging.ColorPurple)) expectMessage(t, l.Error, "ERROR: pss error") - expectMessage(t, l.Event, fmt.Sprintf("%d FS: fsw event", logging.ColorGreen)) + expectMessage(t, l.Event, fmt.Sprintf("%d FS: fsw event", logging.ColorNone)) expectMessage(t, l.Error, "ERROR: fsw error") expectMessage(t, l.Info, "Exiting program... (interrupt)")