diff --git a/README.md b/README.md index 5ad372a..bee93fa 100644 --- a/README.md +++ b/README.md @@ -27,9 +27,10 @@ You can run `pspy --help` to learn about the flags and their meaning. The summary is as follows: - -p: enables printing commands to stdout (enabled by default) - -f: enables printing file system events to stdout (disabled by default) -- -r: list of directories to watch with inotify. pspy will watch all subdirectories recursively (by default, watches /usr, /tmp, /etc, /home, /var, and /opt). -- -d: list of directories to watch with inotify. pspy will watch these directories only, not the subdirectories (empty by default). +- -r: list of directories to watch with Inotify. pspy will watch all subdirectories recursively (by default, watches /usr, /tmp, /etc, /home, /var, and /opt). +- -d: list of directories to watch with Inotify. pspy will watch these directories only, not the subdirectories (empty by default). - -i: interval in milliseconds between procfs scans. pspy scans regularly for new processes regardless of Inotify events, just in case some events are not received. +- -c: print events in different colors. Red for new processes, green for new Inotify events. The default settings should be fine for most applications. Watching files inside `/usr` is most important since many tools will access libraries inside it. diff --git a/cmd/root.go b/cmd/root.go index ee513eb..a868975 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -57,6 +57,7 @@ var defaultRDirs = []string{ } var defaultDirs = []string{} var triggerInterval int +var colored bool func init() { rootCmd.PersistentFlags().BoolVarP(&logPS, "procevents", "p", true, "print new processes to stdout") @@ -64,6 +65,7 @@ func init() { rootCmd.PersistentFlags().StringArrayVarP(&rDirs, "recursive_dirs", "r", defaultRDirs, "watch these dirs recursively") rootCmd.PersistentFlags().StringArrayVarP(&dirs, "dirs", "d", defaultDirs, "watch these dirs") rootCmd.PersistentFlags().IntVarP(&triggerInterval, "interval", "i", 100, "scan every 'interval' milliseconds for new processes") + rootCmd.PersistentFlags().BoolVarP(&colored, "color", "c", true, "color the printed events") log.SetOutput(os.Stdout) } @@ -78,6 +80,7 @@ func root(cmd *cobra.Command, args []string) { LogFS: logFS, DrainFor: 1 * time.Second, TriggerEvery: time.Duration(triggerInterval) * time.Millisecond, + Colored: colored, } fsw := fswatcher.NewFSWatcher() defer fsw.Close() diff --git a/internal/config/config.go b/internal/config/config.go index 134887a..c81d98a 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -12,8 +12,9 @@ type Config struct { LogPS bool DrainFor time.Duration TriggerEvery time.Duration + Colored bool } func (c Config) String() string { - return fmt.Sprintf("Printing events: processes=%t | file-system-events=%t ||| Scannning for processes every %v and on inotify events ||| Watching directories: %+v (recursive) | %+v (non-recursive)", c.LogPS, c.LogFS, c.TriggerEvery, c.RDirs, c.Dirs) + return fmt.Sprintf("Printing events (colored=%t): processes=%t | file-system-events=%t ||| Scannning for processes every %v and on inotify events ||| Watching directories: %+v (recursive) | %+v (non-recursive)", c.Colored, c.LogPS, c.LogFS, c.TriggerEvery, c.RDirs, c.Dirs) } diff --git a/internal/pspy/pspy.go b/internal/pspy/pspy.go index da3aa74..de94499 100644 --- a/internal/pspy/pspy.go +++ b/internal/pspy/pspy.go @@ -45,6 +45,8 @@ func Start(cfg *config.Config, b *Bindings, sigCh chan os.Signal) chan struct{} func printOutput(cfg *config.Config, b *Bindings, sigCh chan os.Signal, fsEventCh chan string, psEventCh chan string) chan struct{} { exit := make(chan struct{}) + fsEventColor, psEventColor := getColors(cfg.Colored) + go func() { for { select { @@ -53,11 +55,11 @@ func printOutput(cfg *config.Config, b *Bindings, sigCh chan os.Signal, fsEventC exit <- struct{}{} case fe := <-fsEventCh: if cfg.LogFS { - b.Logger.Eventf(logging.ColorGreen, "FS: %+v", fe) + b.Logger.Eventf(fsEventColor, "FS: %+v", fe) } case pe := <-psEventCh: if cfg.LogPS { - b.Logger.Eventf(logging.ColorRed, "CMD: %+v", pe) + b.Logger.Eventf(psEventColor, "CMD: %+v", pe) } } } @@ -65,6 +67,17 @@ func printOutput(cfg *config.Config, b *Bindings, sigCh chan os.Signal, fsEventC 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 0b99aff..a8a7b89 100644 --- a/internal/pspy/pspy_test.go +++ b/internal/pspy/pspy_test.go @@ -67,6 +67,24 @@ 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 @@ -86,6 +104,7 @@ func TestStart(t *testing.T) { LogPS: true, DrainFor: drainFor, TriggerEvery: triggerEvery, + Colored: true, } sigCh := make(chan os.Signal) @@ -101,7 +120,7 @@ func TestStart(t *testing.T) { }() exitCh := Start(cfg, b, sigCh) - expectMessage(t, l.Info, "Config: Printing events: processes=true | file-system-events=true ||| Scannning for processes every 16m39s and on inotify events ||| Watching directories: [rdir1 rdir2] (recursive) | [dir1 dir2] (non-recursive)") + expectMessage(t, l.Info, "Config: Printing events (colored=true): processes=true | file-system-events=true ||| Scannning for processes every 16m39s and on inotify events ||| Watching directories: [rdir1 rdir2] (recursive) | [dir1 dir2] (non-recursive)") expectMessage(t, l.Info, "Draining file system events due to startup...") <-time.After(2 * drainFor) expectMessage(t, l.Info, "done")