diff --git a/cmd/crowdsec-cli/bouncers_table.go b/cmd/crowdsec-cli/bouncers_table.go index 0ea725f55..5fe48b490 100644 --- a/cmd/crowdsec-cli/bouncers_table.go +++ b/cmd/crowdsec-cli/bouncers_table.go @@ -5,9 +5,9 @@ import ( "time" "github.com/aquasecurity/table" - "github.com/enescakir/emoji" "github.com/crowdsecurity/crowdsec/pkg/database/ent" + "github.com/crowdsecurity/crowdsec/pkg/emoji" ) func getBouncersTable(out io.Writer, bouncers []*ent.Bouncer) { @@ -17,11 +17,9 @@ func getBouncersTable(out io.Writer, bouncers []*ent.Bouncer) { t.SetAlignment(table.AlignLeft, table.AlignLeft, table.AlignLeft, table.AlignLeft, table.AlignLeft, table.AlignLeft) for _, b := range bouncers { - var revoked string - if !b.Revoked { - revoked = emoji.CheckMark.String() - } else { - revoked = emoji.Prohibited.String() + revoked := emoji.CheckMark + if b.Revoked { + revoked = emoji.Prohibited } t.AddRow(b.Name, b.IPAddress, revoked, b.LastPull.Format(time.RFC3339), b.Type, b.Version, b.AuthType) diff --git a/cmd/crowdsec-cli/console_table.go b/cmd/crowdsec-cli/console_table.go index e71ea8113..8f7ebb210 100644 --- a/cmd/crowdsec-cli/console_table.go +++ b/cmd/crowdsec-cli/console_table.go @@ -4,9 +4,9 @@ import ( "io" "github.com/aquasecurity/table" - "github.com/enescakir/emoji" "github.com/crowdsecurity/crowdsec/pkg/csconfig" + "github.com/crowdsecurity/crowdsec/pkg/emoji" ) func cmdConsoleStatusTable(out io.Writer, consoleCfg csconfig.ConsoleConfig) { @@ -17,28 +17,28 @@ func cmdConsoleStatusTable(out io.Writer, consoleCfg csconfig.ConsoleConfig) { t.SetHeaderAlignment(table.AlignLeft, table.AlignLeft, table.AlignLeft) for _, option := range csconfig.CONSOLE_CONFIGS { - activated := string(emoji.CrossMark) + activated := emoji.CrossMark switch option { case csconfig.SEND_CUSTOM_SCENARIOS: if *consoleCfg.ShareCustomScenarios { - activated = string(emoji.CheckMarkButton) + activated = emoji.CheckMarkButton } case csconfig.SEND_MANUAL_SCENARIOS: if *consoleCfg.ShareManualDecisions { - activated = string(emoji.CheckMarkButton) + activated = emoji.CheckMarkButton } case csconfig.SEND_TAINTED_SCENARIOS: if *consoleCfg.ShareTaintedScenarios { - activated = string(emoji.CheckMarkButton) + activated = emoji.CheckMarkButton } case csconfig.SEND_CONTEXT: if *consoleCfg.ShareContext { - activated = string(emoji.CheckMarkButton) + activated = emoji.CheckMarkButton } case csconfig.CONSOLE_MANAGEMENT: if *consoleCfg.ConsoleManagement { - activated = string(emoji.CheckMarkButton) + activated = emoji.CheckMarkButton } } diff --git a/cmd/crowdsec-cli/hubtest.go b/cmd/crowdsec-cli/hubtest.go index 8f5ab0873..d6ed45600 100644 --- a/cmd/crowdsec-cli/hubtest.go +++ b/cmd/crowdsec-cli/hubtest.go @@ -11,13 +11,13 @@ import ( "text/template" "github.com/AlecAivazis/survey/v2" - "github.com/enescakir/emoji" "github.com/fatih/color" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" "gopkg.in/yaml.v2" "github.com/crowdsecurity/crowdsec/pkg/dumps" + "github.com/crowdsecurity/crowdsec/pkg/emoji" "github.com/crowdsecurity/crowdsec/pkg/hubtest" ) diff --git a/cmd/crowdsec-cli/hubtest_table.go b/cmd/crowdsec-cli/hubtest_table.go index 4034da7e5..e6c5ee80a 100644 --- a/cmd/crowdsec-cli/hubtest_table.go +++ b/cmd/crowdsec-cli/hubtest_table.go @@ -5,8 +5,8 @@ import ( "io" "github.com/aquasecurity/table" - "github.com/enescakir/emoji" + "github.com/crowdsecurity/crowdsec/pkg/emoji" "github.com/crowdsecurity/crowdsec/pkg/hubtest" ) @@ -17,9 +17,9 @@ func hubTestResultTable(out io.Writer, testResult map[string]bool) { t.SetAlignment(table.AlignLeft) for testName, success := range testResult { - status := emoji.CheckMarkButton.String() + status := emoji.CheckMarkButton if !success { - status = emoji.CrossMark.String() + status = emoji.CrossMark } t.AddRow(testName, status) @@ -50,11 +50,12 @@ func hubTestParserCoverageTable(out io.Writer, coverage []hubtest.Coverage) { parserTested := 0 for _, test := range coverage { - status := emoji.RedCircle.String() + status := emoji.RedCircle if test.TestsCount > 0 { - status = emoji.GreenCircle.String() + status = emoji.GreenCircle parserTested++ } + t.AddRow(test.Name, status, fmt.Sprintf("%d times (across %d tests)", test.TestsCount, len(test.PresentIn))) } @@ -70,11 +71,12 @@ func hubTestAppsecRuleCoverageTable(out io.Writer, coverage []hubtest.Coverage) parserTested := 0 for _, test := range coverage { - status := emoji.RedCircle.String() + status := emoji.RedCircle if test.TestsCount > 0 { - status = emoji.GreenCircle.String() + status = emoji.GreenCircle parserTested++ } + t.AddRow(test.Name, status, fmt.Sprintf("%d times (across %d tests)", test.TestsCount, len(test.PresentIn))) } @@ -90,11 +92,12 @@ func hubTestScenarioCoverageTable(out io.Writer, coverage []hubtest.Coverage) { parserTested := 0 for _, test := range coverage { - status := emoji.RedCircle.String() + status := emoji.RedCircle if test.TestsCount > 0 { - status = emoji.GreenCircle.String() + status = emoji.GreenCircle parserTested++ } + t.AddRow(test.Name, status, fmt.Sprintf("%d times (across %d tests)", test.TestsCount, len(test.PresentIn))) } diff --git a/cmd/crowdsec-cli/machines_table.go b/cmd/crowdsec-cli/machines_table.go index e166fb785..120929ea6 100644 --- a/cmd/crowdsec-cli/machines_table.go +++ b/cmd/crowdsec-cli/machines_table.go @@ -5,9 +5,9 @@ import ( "time" "github.com/aquasecurity/table" - "github.com/enescakir/emoji" "github.com/crowdsecurity/crowdsec/pkg/database/ent" + "github.com/crowdsecurity/crowdsec/pkg/emoji" ) func getAgentsTable(out io.Writer, machines []*ent.Machine) { @@ -17,17 +17,16 @@ func getAgentsTable(out io.Writer, machines []*ent.Machine) { t.SetAlignment(table.AlignLeft, table.AlignLeft, table.AlignLeft, table.AlignLeft, table.AlignLeft, table.AlignLeft, table.AlignLeft) for _, m := range machines { - var validated string + validated := emoji.Prohibited if m.IsValidated { - validated = emoji.CheckMark.String() - } else { - validated = emoji.Prohibited.String() + validated = emoji.CheckMark } hb, active := getLastHeartbeat(m) if !active { - hb = emoji.Warning.String() + " " + hb + hb = emoji.Warning + " " + hb } + t.AddRow(m.MachineId, m.IpAddress, m.UpdatedAt.Format(time.RFC3339), validated, m.Version, m.AuthType, hb) } diff --git a/cmd/crowdsec-cli/notifications_table.go b/cmd/crowdsec-cli/notifications_table.go index e0f61d9ce..19d11cea7 100644 --- a/cmd/crowdsec-cli/notifications_table.go +++ b/cmd/crowdsec-cli/notifications_table.go @@ -6,7 +6,8 @@ import ( "strings" "github.com/aquasecurity/table" - "github.com/enescakir/emoji" + + "github.com/crowdsecurity/crowdsec/pkg/emoji" ) func notificationListTable(out io.Writer, ncfgs map[string]NotificationsCfg) { @@ -14,24 +15,31 @@ func notificationListTable(out io.Writer, ncfgs map[string]NotificationsCfg) { t.SetHeaders("Active", "Name", "Type", "Profile name") t.SetHeaderAlignment(table.AlignLeft, table.AlignLeft, table.AlignLeft, table.AlignLeft) t.SetAlignment(table.AlignLeft, table.AlignLeft, table.AlignLeft, table.AlignLeft) + keys := make([]string, 0, len(ncfgs)) for k := range ncfgs { keys = append(keys, k) } + sort.Slice(keys, func(i, j int) bool { return len(ncfgs[keys[i]].Profiles) > len(ncfgs[keys[j]].Profiles) }) + for _, k := range keys { b := ncfgs[k] profilesList := []string{} + for _, p := range b.Profiles { profilesList = append(profilesList, p.Name) } - active := emoji.CheckMark.String() + + active := emoji.CheckMark if len(profilesList) == 0 { - active = emoji.Prohibited.String() + active = emoji.Prohibited } + t.AddRow(active, b.Config.Name, b.Config.Type, strings.Join(profilesList, ", ")) } + t.Render() } diff --git a/cmd/crowdsec-cli/utils_table.go b/cmd/crowdsec-cli/utils_table.go index b1e4b6950..23bcff4e5 100644 --- a/cmd/crowdsec-cli/utils_table.go +++ b/cmd/crowdsec-cli/utils_table.go @@ -6,9 +6,9 @@ import ( "strconv" "github.com/aquasecurity/table" - "github.com/enescakir/emoji" "github.com/crowdsecurity/crowdsec/pkg/cwhub" + "github.com/crowdsecurity/crowdsec/pkg/emoji" ) func listHubItemTable(out io.Writer, title string, items []*cwhub.Item) { @@ -21,6 +21,7 @@ func listHubItemTable(out io.Writer, title string, items []*cwhub.Item) { status := fmt.Sprintf("%v %s", item.State.Emoji(), item.State.Text()) t.AddRow(item.Name, status, item.State.LocalVersion, item.State.LocalPath) } + renderTableTitle(out, title) t.Render() } @@ -42,6 +43,7 @@ func scenarioMetricsTable(out io.Writer, itemName string, metrics map[string]int if metrics["instantiation"] == 0 { return } + t := newTable(out) t.SetHeaders("Current Count", "Overflows", "Instantiated", "Poured", "Expired") @@ -72,6 +74,7 @@ func parserMetricsTable(out io.Writer, itemName string, metrics map[string]map[s strconv.Itoa(stats["parsed"]), strconv.Itoa(stats["unparsed"]), ) + showTable = true } } diff --git a/go.mod b/go.mod index e1da18387..c2d6ca2c1 100644 --- a/go.mod +++ b/go.mod @@ -33,7 +33,6 @@ require ( github.com/dghubble/sling v1.3.0 github.com/docker/docker v24.0.7+incompatible github.com/docker/go-connections v0.4.0 - github.com/enescakir/emoji v1.0.0 github.com/fatih/color v1.15.0 github.com/fsnotify/fsnotify v1.6.0 github.com/gin-gonic/gin v1.9.1 @@ -92,7 +91,6 @@ require ( gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 - gotest.tools/v3 v3.5.0 k8s.io/apiserver v0.28.4 ) @@ -210,6 +208,7 @@ require ( google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect + gotest.tools/v3 v3.5.0 // indirect k8s.io/api v0.28.4 // indirect k8s.io/apimachinery v0.28.4 // indirect k8s.io/klog/v2 v2.100.1 // indirect diff --git a/go.sum b/go.sum index 2daf22cc9..7e8603000 100644 --- a/go.sum +++ b/go.sum @@ -124,8 +124,6 @@ github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDD github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/enescakir/emoji v1.0.0 h1:W+HsNql8swfCQFtioDGDHCHri8nudlK1n5p2rHCJoog= -github.com/enescakir/emoji v1.0.0/go.mod h1:Bt1EKuLnKDTYpLALApstIkAjdDrS/8IAgTkKp+WKFD0= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= diff --git a/pkg/acquisition/modules/loki/loki_test.go b/pkg/acquisition/modules/loki/loki_test.go index 6cac1c0fe..8511d5445 100644 --- a/pkg/acquisition/modules/loki/loki_test.go +++ b/pkg/acquisition/modules/loki/loki_test.go @@ -2,6 +2,7 @@ package loki_test import ( "bytes" + "context" "encoding/json" "fmt" "io" @@ -13,19 +14,17 @@ import ( "testing" "time" - "context" + log "github.com/sirupsen/logrus" + "github.com/stretchr/testify/assert" + tomb "gopkg.in/tomb.v2" "github.com/crowdsecurity/go-cs-lib/cstest" "github.com/crowdsecurity/crowdsec/pkg/acquisition/modules/loki" "github.com/crowdsecurity/crowdsec/pkg/types" - log "github.com/sirupsen/logrus" - tomb "gopkg.in/tomb.v2" - "gotest.tools/v3/assert" ) func TestConfiguration(t *testing.T) { - log.Infof("Test 'TestConfigure'") tests := []struct { @@ -127,22 +126,26 @@ query: > subLogger := log.WithFields(log.Fields{ "type": "loki", }) + for _, test := range tests { t.Run(test.testName, func(t *testing.T) { lokiSource := loki.LokiSource{} err := lokiSource.Configure([]byte(test.config), subLogger) cstest.AssertErrorContains(t, err, test.expectedErr) + if test.password != "" { p := lokiSource.Config.Auth.Password if test.password != p { t.Fatalf("Password mismatch : %s != %s", test.password, p) } } + if test.waitForReady != 0 { if lokiSource.Config.WaitForReady != test.waitForReady { t.Fatalf("Wrong WaitForReady %v != %v", lokiSource.Config.WaitForReady, test.waitForReady) } } + if test.delayFor != 0 { if lokiSource.Config.DelayFor != test.delayFor { t.Fatalf("Wrong DelayFor %v != %v", lokiSource.Config.DelayFor, test.delayFor) @@ -154,6 +157,7 @@ query: > func TestConfigureDSN(t *testing.T) { log.Infof("Test 'TestConfigureDSN'") + tests := []struct { name string dsn string @@ -218,7 +222,9 @@ func TestConfigureDSN(t *testing.T) { "type": "loki", "name": test.name, }) + t.Logf("Test : %s", test.name) + lokiSource := &loki.LokiSource{} err := lokiSource.ConfigureByDSN(test.dsn, map[string]string{"type": "testtype"}, subLogger, "") cstest.AssertErrorContains(t, err, test.expectedErr) @@ -234,17 +240,20 @@ func TestConfigureDSN(t *testing.T) { t.Fatalf("Password mismatch : %s != %s", test.password, p) } } + if test.scheme != "" { url, _ := url.Parse(lokiSource.Config.URL) if test.scheme != url.Scheme { t.Fatalf("Schema mismatch : %s != %s", test.scheme, url.Scheme) } } + if test.waitForReady != 0 { if lokiSource.Config.WaitForReady != test.waitForReady { t.Fatalf("Wrong WaitForReady %v != %v", lokiSource.Config.WaitForReady, test.waitForReady) } } + if test.delayFor != 0 { if lokiSource.Config.DelayFor != test.delayFor { t.Fatalf("Wrong DelayFor %v != %v", lokiSource.Config.DelayFor, test.delayFor) @@ -272,27 +281,36 @@ func feedLoki(logger *log.Entry, n int, title string) error { Line: fmt.Sprintf("Log line #%d %v", i, title), } } + buff, err := json.Marshal(streams) if err != nil { return err } + req, err := http.NewRequest(http.MethodPost, "http://127.0.0.1:3100/loki/api/v1/push", bytes.NewBuffer(buff)) if err != nil { return err } + req.Header.Set("Content-Type", "application/json") req.Header.Set("X-Scope-OrgID", "1234") + resp, err := http.DefaultClient.Do(req) if err != nil { return err } + defer resp.Body.Close() + if resp.StatusCode != http.StatusNoContent { b, _ := io.ReadAll(resp.Body) logger.Error(string(b)) + return fmt.Errorf("Bad post status %d", resp.StatusCode) } + logger.Info(n, " Events sent") + return nil } @@ -300,9 +318,11 @@ func TestOneShotAcquisition(t *testing.T) { if runtime.GOOS == "windows" { t.Skip("Skipping test on windows") } + log.SetOutput(os.Stdout) log.SetLevel(log.InfoLevel) log.Info("Test 'TestStreamingAcquisition'") + title := time.Now().String() // Loki will be messy, with a lot of stuff, lets use a unique key tests := []struct { config string @@ -327,6 +347,7 @@ since: 1h }) lokiSource := loki.LokiSource{} err := lokiSource.Configure([]byte(ts.config), subLogger) + if err != nil { t.Fatalf("Unexpected error : %s", err) } @@ -338,19 +359,23 @@ since: 1h out := make(chan types.Event) read := 0 + go func() { for { <-out + read++ } }() + lokiTomb := tomb.Tomb{} + err = lokiSource.OneShotAcquisition(out, &lokiTomb) if err != nil { t.Fatalf("Unexpected error : %s", err) } - assert.Equal(t, 20, read) + assert.Equal(t, 20, read) } } @@ -358,9 +383,11 @@ func TestStreamingAcquisition(t *testing.T) { if runtime.GOOS == "windows" { t.Skip("Skipping test on windows") } + log.SetOutput(os.Stdout) log.SetLevel(log.InfoLevel) log.Info("Test 'TestStreamingAcquisition'") + title := time.Now().String() tests := []struct { name string @@ -396,6 +423,7 @@ query: > expectedLines: 20, }, } + for _, ts := range tests { t.Run(ts.name, func(t *testing.T) { logger := log.New() @@ -407,10 +435,12 @@ query: > out := make(chan types.Event) lokiTomb := tomb.Tomb{} lokiSource := loki.LokiSource{} + err := lokiSource.Configure([]byte(ts.config), subLogger) if err != nil { t.Fatalf("Unexpected error : %s", err) } + err = lokiSource.StreamingAcquisition(out, &lokiTomb) cstest.AssertErrorContains(t, err, ts.streamErr) @@ -418,22 +448,26 @@ query: > return } - time.Sleep(time.Second * 2) //We need to give time to start reading from the WS + time.Sleep(time.Second * 2) // We need to give time to start reading from the WS + readTomb := tomb.Tomb{} readCtx, cancel := context.WithTimeout(context.Background(), time.Second*10) count := 0 readTomb.Go(func() error { defer cancel() + for { select { case <-readCtx.Done(): return readCtx.Err() case evt := <-out: count++ + if !strings.HasSuffix(evt.Line.Raw, title) { return fmt.Errorf("Incorrect suffix : %s", evt.Line.Raw) } + if count == ts.expectedLines { return nil } @@ -447,20 +481,23 @@ query: > } err = readTomb.Wait() + cancel() + if err != nil { t.Fatalf("Unexpected error : %s", err) } - assert.Equal(t, count, ts.expectedLines) + + assert.Equal(t, ts.expectedLines, count) }) } - } func TestStopStreaming(t *testing.T) { if runtime.GOOS == "windows" { t.Skip("Skipping test on windows") } + config := ` mode: tail source: loki @@ -476,24 +513,30 @@ query: > }) title := time.Now().String() lokiSource := loki.LokiSource{} + err := lokiSource.Configure([]byte(config), subLogger) if err != nil { t.Fatalf("Unexpected error : %s", err) } + out := make(chan types.Event) lokiTomb := &tomb.Tomb{} + err = lokiSource.StreamingAcquisition(out, lokiTomb) if err != nil { t.Fatalf("Unexpected error : %s", err) } + time.Sleep(time.Second * 2) + err = feedLoki(subLogger, 1, title) if err != nil { t.Fatalf("Unexpected error : %s", err) } lokiTomb.Kill(nil) + err = lokiTomb.Wait() if err != nil { t.Fatalf("Unexpected error : %s", err) @@ -519,5 +562,6 @@ func (l *LogValue) MarshalJSON() ([]byte, error) { if err != nil { return nil, err } + return []byte(fmt.Sprintf(`["%d",%s]`, l.Time.UnixNano(), string(line))), nil } diff --git a/pkg/cwhub/item.go b/pkg/cwhub/item.go index 6c7da06c3..6cdb5cadc 100644 --- a/pkg/cwhub/item.go +++ b/pkg/cwhub/item.go @@ -7,7 +7,8 @@ import ( "slices" "github.com/Masterminds/semver/v3" - "github.com/enescakir/emoji" + + "github.com/crowdsecurity/crowdsec/pkg/emoji" ) const ( @@ -84,7 +85,7 @@ func (s *ItemState) Text() string { } // Emoji returns the status of the item as an emoji (eg. emoji.Warning). -func (s *ItemState) Emoji() emoji.Emoji { +func (s *ItemState) Emoji() string { switch { case s.IsLocal(): return emoji.House diff --git a/pkg/cwhub/itemupgrade.go b/pkg/cwhub/itemupgrade.go index ac3b94f98..6a8dc2f44 100644 --- a/pkg/cwhub/itemupgrade.go +++ b/pkg/cwhub/itemupgrade.go @@ -13,7 +13,7 @@ import ( "os" "path/filepath" - "github.com/enescakir/emoji" + "github.com/crowdsecurity/crowdsec/pkg/emoji" ) // Upgrade downloads and applies the last version of the item from the hub. @@ -60,6 +60,7 @@ func (i *Item) Upgrade(force bool) (bool, error) { // TODO: use a better way to communicate this fmt.Printf("updated %s\n", i.Name) i.hub.logger.Infof("%v %s: updated", emoji.Package, i.Name) + updated = true } @@ -151,7 +152,7 @@ func (i *Item) FetchLatest() ([]byte, string, error) { i.hub.logger.Errorf("Downloaded version doesn't match index, please 'hub update'") i.hub.logger.Debugf("got %s, expected %s", meow, i.Versions[i.Version].Digest) - return nil, "", fmt.Errorf("invalid download hash") + return nil, "", errors.New("invalid download hash") } return body, url, nil diff --git a/pkg/dumps/parser_dump.go b/pkg/dumps/parser_dump.go index 566b87a08..9b4cdb1c2 100644 --- a/pkg/dumps/parser_dump.go +++ b/pkg/dumps/parser_dump.go @@ -1,6 +1,7 @@ package dumps import ( + "errors" "fmt" "io" "os" @@ -8,13 +9,15 @@ import ( "strings" "time" - "github.com/crowdsecurity/crowdsec/pkg/types" - "github.com/crowdsecurity/go-cs-lib/maptools" - "github.com/enescakir/emoji" "github.com/fatih/color" diff "github.com/r3labs/diff/v2" log "github.com/sirupsen/logrus" "gopkg.in/yaml.v2" + + "github.com/crowdsecurity/go-cs-lib/maptools" + + "github.com/crowdsecurity/crowdsec/pkg/emoji" + "github.com/crowdsecurity/crowdsec/pkg/types" ) type ParserResult struct { @@ -56,7 +59,7 @@ func LoadParserDump(filepath string) (*ParserResults, error) { var lastStage string - //Loop over stages to find last successful one with at least one parser + // Loop over stages to find last successful one with at least one parser for i := len(stages) - 2; i >= 0; i-- { if len(pdump[stages[i]]) != 0 { lastStage = stages[i] @@ -73,7 +76,7 @@ func LoadParserDump(filepath string) (*ParserResults, error) { sort.Strings(parsers) if len(parsers) == 0 { - return nil, fmt.Errorf("no parser found. Please install the appropriate parser and retry") + return nil, errors.New("no parser found. Please install the appropriate parser and retry") } lastParser := parsers[len(parsers)-1] @@ -90,14 +93,15 @@ func LoadParserDump(filepath string) (*ParserResults, error) { } func DumpTree(parserResults ParserResults, bucketPour BucketPourInfo, opts DumpOpts) { - //note : we can use line -> time as the unique identifier (of acquisition) + // note : we can use line -> time as the unique identifier (of acquisition) state := make(map[time.Time]map[string]map[string]ParserResult) assoc := make(map[time.Time]string, 0) parser_order := make(map[string][]string) for stage, parsers := range parserResults { - //let's process parsers in the order according to idx + // let's process parsers in the order according to idx parser_order[stage] = make([]string, len(parsers)) + for pname, parser := range parsers { if len(parser) > 0 { parser_order[stage][parser[0].Idx-1] = pname @@ -128,14 +132,14 @@ func DumpTree(parserResults ParserResults, bucketPour BucketPourInfo, opts DumpO continue } - //it might be bucket overflow being reprocessed, skip this + // it might be bucket overflow being reprocessed, skip this if _, ok := state[evt.Line.Time]; !ok { state[evt.Line.Time] = make(map[string]map[string]ParserResult) assoc[evt.Line.Time] = evt.Line.Raw } - //there is a trick : to know if an event successfully exit the parsers, we check if it reached the pour() phase - //we thus use a fake stage "buckets" and a fake parser "OK" to know if it entered + // there is a trick : to know if an event successfully exit the parsers, we check if it reached the pour() phase + // we thus use a fake stage "buckets" and a fake parser "OK" to know if it entered if _, ok := state[evt.Line.Time]["buckets"]; !ok { state[evt.Line.Time]["buckets"] = make(map[string]ParserResult) } @@ -148,7 +152,7 @@ func DumpTree(parserResults ParserResults, bucketPour BucketPourInfo, opts DumpO red := color.New(color.FgRed).SprintFunc() green := color.New(color.FgGreen).SprintFunc() whitelistReason := "" - //get each line + // get each line for tstamp, rawstr := range assoc { if opts.SkipOk { if _, ok := state[tstamp]["buckets"]["OK"]; ok { @@ -161,8 +165,8 @@ func DumpTree(parserResults ParserResults, bucketPour BucketPourInfo, opts DumpO skeys := make([]string, 0, len(state[tstamp])) for k := range state[tstamp] { - //there is a trick : to know if an event successfully exit the parsers, we check if it reached the pour() phase - //we thus use a fake stage "buckets" and a fake parser "OK" to know if it entered + // there is a trick : to know if an event successfully exit the parsers, we check if it reached the pour() phase + // we thus use a fake stage "buckets" and a fake parser "OK" to know if it entered if k == "buckets" { continue } @@ -216,6 +220,7 @@ func DumpTree(parserResults ParserResults, bucketPour BucketPourInfo, opts DumpO whitelistReason = parsers[parser].Evt.WhitelistReason } } + updated++ case "delete": deleted++ @@ -277,7 +282,7 @@ func DumpTree(parserResults ParserResults, bucketPour BucketPourInfo, opts DumpO sep = "├" } - //did the event enter the bucket pour phase ? + // did the event enter the bucket pour phase ? if _, ok := state[tstamp]["buckets"]["OK"]; ok { fmt.Printf("\t%s-------- parser success %s\n", sep, emoji.GreenCircle) } else if whitelistReason != "" { @@ -286,7 +291,7 @@ func DumpTree(parserResults ParserResults, bucketPour BucketPourInfo, opts DumpO fmt.Printf("\t%s-------- parser failure %s\n", sep, emoji.RedCircle) } - //now print bucket info + // now print bucket info if len(state[tstamp]["buckets"]) > 0 { fmt.Printf("\t├ Scenarios\n") } @@ -294,8 +299,8 @@ func DumpTree(parserResults ParserResults, bucketPour BucketPourInfo, opts DumpO bnames := make([]string, 0, len(state[tstamp]["buckets"])) for k := range state[tstamp]["buckets"] { - //there is a trick : to know if an event successfully exit the parsers, we check if it reached the pour() phase - //we thus use a fake stage "buckets" and a fake parser "OK" to know if it entered + // there is a trick : to know if an event successfully exit the parsers, we check if it reached the pour() phase + // we thus use a fake stage "buckets" and a fake parser "OK" to know if it entered if k == "OK" { continue } diff --git a/pkg/emoji/emoji.go b/pkg/emoji/emoji.go new file mode 100644 index 000000000..51295a854 --- /dev/null +++ b/pkg/emoji/emoji.go @@ -0,0 +1,14 @@ +package emoji + +const ( + CheckMarkButton = "\u2705" // ✅ + CheckMark = "\u2714\ufe0f" // ✔️ + CrossMark = "\u274c" // ❌ + GreenCircle = "\U0001f7e2" // 🟢 + House = "\U0001f3e0" // 🏠 + Package = "\U0001f4e6" // 📦 + Prohibited = "\U0001f6ab" // 🚫 + QuestionMark = "\u2753" // ❓ + RedCircle = "\U0001f534" // 🔴 + Warning = "\u26a0\ufe0f" // ⚠️ +)