Skip to content

Commit

Permalink
Improve performance of status map parser
Browse files Browse the repository at this point in the history
  • Loading branch information
itchyny committed Sep 29, 2023
1 parent cea26f1 commit 29d41e5
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 54 deletions.
95 changes: 52 additions & 43 deletions asstatusparse.go
Original file line number Diff line number Diff line change
@@ -1,63 +1,72 @@
package checkers

import (
"fmt"
"strings"
import "strings"

"golang.org/x/exp/slices"
)
type invalidStatusMapError string

var keywords = []string{"OK", "WARNING", "CRITICAL", "UNKNOWN"}
func (err invalidStatusMapError) Error() string {
return "invalid status map: " + string(err)
}

type duplicateStatusMapError Status

func (err duplicateStatusMapError) Error() string {
return "duplicate status in map: " + Status(err).String()
}

func strToStatus(s string) Status {
switch s {
case "OK":
return OK
case "WARNING":
return WARNING
case "CRITICAL":
return CRITICAL
case "UNKNOWN":
return UNKNOWN
func parseStatus(src string) (Status, string, bool) {
switch {
case strings.HasPrefix(src, "OK"):
return OK, src[len("OK"):], true
case strings.HasPrefix(src, "WARNING"):
return WARNING, src[len("WARNING"):], true
case strings.HasPrefix(src, "CRITICAL"):
return CRITICAL, src[len("CRITICAL"):], true
case strings.HasPrefix(src, "UNKNOWN"):
return UNKNOWN, src[len("UNKNOWN"):], true
default:
return OK, src, false
}
panic("invalid inputs.")
}

// Parse parses <status>=<status> notation string. <status> is one of:
// Parse parses a string of the form <status>=<status>. <status> is one of:
//
// - ok
// - warning
// - critical
// - unknown
//
// It can have multiple key-value pairs by comma.
func Parse(arg string) (map[Status]Status, error) {
if arg == "" {
return nil, nil
}

maps := make(map[Status]Status, 0)
args := strings.Split(arg, ",")

for _, s := range args {
if s == "" {
continue
// It can have multiple key-value pairs separated by comma.
func Parse(src string) (map[Status]Status, error) {
orig := src
statusMap := map[Status]Status{}
for src = strings.ToUpper(src); src != ""; {
var (
from, to Status
ok bool
)
from, src, ok = parseStatus(src)
if !ok {
return nil, invalidStatusMapError(orig)
}
rawFrom, rawTo, found := strings.Cut(s, "=")
if !found {
return nil, fmt.Errorf("arguments is invalid : %v", s)
src, ok = strings.CutPrefix(src, "=")
if !ok {
return nil, invalidStatusMapError(orig)
}
from := strings.ToUpper(rawFrom)
to := strings.ToUpper(rawTo)
if !slices.Contains(keywords, from) {
return nil, fmt.Errorf("from argument is invalid : %s", rawFrom)
to, src, ok = parseStatus(src)
if !ok {
return nil, invalidStatusMapError(orig)
}
if !slices.Contains(keywords, to) {
return nil, fmt.Errorf("to argument is invalid : %s", rawTo)
if _, ok = statusMap[from]; ok {
return nil, duplicateStatusMapError(from)
}
if _, ok := maps[strToStatus(from)]; ok {
return nil, fmt.Errorf("arguments is duplicate : %v", from)
statusMap[from] = to
if src != "" {
src, ok = strings.CutPrefix(src, ",")
if !ok || src == "" {
return nil, invalidStatusMapError(orig)
}
}
maps[strToStatus(from)] = strToStatus(to)
}
return maps, nil
return statusMap, nil
}
16 changes: 13 additions & 3 deletions asstatusparse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ func TestParse(t *testing.T) {
},
{
name: "multi",
source: "unknown=critical,warning=critical",
source: "unknown=ok,warning=critical",
expected: map[Status]Status{
UNKNOWN: CRITICAL,
UNKNOWN: OK,
WARNING: CRITICAL,
},
},
Expand All @@ -32,14 +32,24 @@ func TestParse(t *testing.T) {
source: "invalid=critical",
wantErr: true,
},
{
name: "= error",
source: "unknown critical",
wantErr: true,
},
{
name: "to error",
source: "critical=invalid",
wantErr: true,
},
{
name: "argument error",
source: "invalid=critical=invalid",
source: "unknown=critical=invalid",
wantErr: true,
},
{
name: "trailing comma error",
source: "unknown=ok,",
wantErr: true,
},
{
Expand Down
6 changes: 3 additions & 3 deletions checkers.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ const (

func (st Status) String() string {
switch st {
case 0:
case OK:
return "OK"
case 1:
case WARNING:
return "WARNING"
case 2:
case CRITICAL:
return "CRITICAL"
default:
return "UNKNOWN"
Expand Down
4 changes: 1 addition & 3 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
module github.com/mackerelio/checkers

go 1.18

require golang.org/x/exp v0.0.0-20230905200255-921286631fa9
go 1.20
2 changes: 0 additions & 2 deletions go.sum

This file was deleted.

0 comments on commit 29d41e5

Please sign in to comment.