diff --git a/README.md b/README.md index d7df9a7a..2fa8fec6 100644 --- a/README.md +++ b/README.md @@ -416,7 +416,7 @@ There is [a library for create plugin](https://pkg.go.dev/github.com/macrat/ayd/ ##### Probe plugin -Probe plugin which to check the target, receives the target URL as the only one argument of the command. +Probe plugin, which to check the target, receives the target URL as the only one argument of the command. For example, target URL `foobar:your-target` has the same mean as below command. @@ -426,27 +426,16 @@ $ ayd-foobar-probe "foobar:your-target" ##### Alert plugin -Alert plugin which to send alerts, receives below arguments. - -1. Alert URL. -2. Timestamp in RFC3339 format. -3. Current status of the target. -4. Current latency in milliseconds. -5. Target URL that causes the incident. -6. Message from the latest probe. -7. Extra values in JSON format. +Alert plugin, which to send alerts, receives two arguments. +The first argument is a URL for alert itself. +The second one is the latest record that fired the alert in JSON format. For example, the alert URL `foobar:your-alert` for plugin `ayd-foobar-alert` will be called like a below command. ``` shell -$ ayd-foobar-alert \ - "foobar:your-alert" \ - "2001-02-30T16:05:06+09:00" \ - "FAILURE" \ - "1.234" \ - "ping:your-target" \ - "this is message of the record" \ - '{"extra values":"in json format"}' +$ ayd-foobar-alert \ + "foobar:your-alert" \ + '{"time":"2001-02-30T16:05:06+09:00", "status":"FAILURE", "latency":"1.234", "target":"ping:your-target", "message":"this is message of the record"}' ``` The output of the probe plugin will parsed the same way to [log file](#log-file), but all target URL will add `alert:` prefix and won't not show in status page. diff --git a/internal/scheme/alert_test.go b/internal/scheme/alert_test.go index 6de27067..a65c9b84 100644 --- a/internal/scheme/alert_test.go +++ b/internal/scheme/alert_test.go @@ -33,7 +33,7 @@ func TestAlerter(t *testing.T) { Error string } tests := []Test{ - {"exec:ayd-foo-alert", "alert:exec:ayd-foo-alert", `{"time":"2001-02-03T16:05:06Z","status":"HEALTHY","latency":123.456,"target":"","message":"\",,,,,\""}` + "\n---\nexit_code: 0", ""}, + {"exec:ayd-foo-alert", "alert:exec:ayd-foo-alert", `{"time":"2001-02-03T16:05:06Z","status":"HEALTHY","latency":123.456,"target":"","message":""}` + "\n---\nexit_code: 0", ""}, {"exec:ayd-bar-probe", "alert:exec:ayd-bar-probe", "arg \"\"\nenv ayd_time=2001-02-03T16:05:06Z ayd_status=FAILURE ayd_latency=12.345 ayd_target=dummy:failure ayd_message=foobar ayd_extra={\"hello\":\"world\"}\n---\nexit_code: 0", ""}, {"bar:", "", "", "unsupported scheme"}, @@ -60,9 +60,9 @@ func TestAlerter(t *testing.T) { // Windows can not run this test because bat doesn't support double quote character in argument :( tests = append( tests, - Test{"foo-bar:hello-world", "alert:foo-bar:hello-world", "\"foo-bar:hello-world,2001-02-03T16:05:06Z,FAILURE,12.345,dummy:failure,foobar\"\n---\nextras: {\"hello\":\"world\"}", ""}, - Test{"foo:", "alert:foo:", "\"foo:,2001-02-03T16:05:06Z,FAILURE,12.345,dummy:failure,foobar\"\n---\nextras: {\"hello\":\"world\"}", ""}, - Test{"foo:hello-world", "alert:foo:hello-world", "\"foo:hello-world,2001-02-03T16:05:06Z,FAILURE,12.345,dummy:failure,foobar\"\n---\nextras: {\"hello\":\"world\"}", ""}, + Test{"foo-bar:hello-world", "alert:foo-bar:hello-world", "foo-bar:hello-world\n---\n" + `record: {"hello":"world","latency":12.345,"message":"foobar","status":"FAILURE","target":"dummy:failure","time":"2001-02-03T16:05:06Z"}`, ""}, + Test{"foo:", "alert:foo:", "foo:\n---\n" + `record: {"hello":"world","latency":12.345,"message":"foobar","status":"FAILURE","target":"dummy:failure","time":"2001-02-03T16:05:06Z"}`, ""}, + Test{"foo:hello-world", "alert:foo:hello-world", "foo:hello-world\n---\n" + `record: {"hello":"world","latency":12.345,"message":"foobar","status":"FAILURE","target":"dummy:failure","time":"2001-02-03T16:05:06Z"}`, ""}, ) } diff --git a/internal/scheme/plugin.go b/internal/scheme/plugin.go index e7cf6b4d..18f727a1 100644 --- a/internal/scheme/plugin.go +++ b/internal/scheme/plugin.go @@ -3,12 +3,10 @@ package scheme import ( "bufio" "context" - "encoding/json" "errors" "fmt" "os" "os/exec" - "strconv" "strings" "time" @@ -151,18 +149,7 @@ func (p PluginScheme) Probe(ctx context.Context, r Reporter) { func (p PluginScheme) Alert(ctx context.Context, r Reporter, lastRecord api.Record) { args := []string{ p.target.String(), - lastRecord.Time.Format(time.RFC3339), - lastRecord.Status.String(), - strconv.FormatFloat(float64(lastRecord.Latency.Microseconds())/1000.0, 'f', -1, 64), - lastRecord.Target.String(), - lastRecord.Message, - "{}", - } - - if lastRecord.Extra != nil { - if bs, err := json.Marshal(lastRecord.Extra); err == nil { - args[len(args)-1] = string(bs) - } + lastRecord.String(), } p.execute( diff --git a/internal/scheme/plugin_test.go b/internal/scheme/plugin_test.go index b2673cb7..34068962 100644 --- a/internal/scheme/plugin_test.go +++ b/internal/scheme/plugin_test.go @@ -124,16 +124,9 @@ func TestPluginScheme_Alert(t *testing.T) { t.Parallel() PreparePluginPath(t) - if runtime.GOOS == "windows" { - // Windows can not handle double quote in argument :( - AssertAlert(t, []ProbeTest{ - {"foo:hello-world", api.StatusHealthy, "\"foo:hello-world,2001-02-03T16:05:06Z,FAILURE,123.456,dummy:failure,test-message\"", ""}, - }, 5) - } else { - AssertAlert(t, []ProbeTest{ - {"foo:hello-world", api.StatusHealthy, "\"foo:hello-world,2001-02-03T16:05:06Z,FAILURE,123.456,dummy:failure,test-message\"\n---\nextras: {\"hello\":\"world\"}", ""}, - }, 5) - } + AssertAlert(t, []ProbeTest{ + {"foo:hello-world", api.StatusHealthy, "foo:hello-world\n---\n" + `record: {"hello":"world","latency":123.456,"message":"test-message","status":"FAILURE","target":"dummy:failure","time":"2001-02-03T16:05:06Z"}`, ""}, + }, 5) } func TestPluginProbe_inactiveTargetHandling(t *testing.T) { diff --git a/internal/scheme/source_test.go b/internal/scheme/source_test.go index 1f9bf9d3..4ddcb9f4 100644 --- a/internal/scheme/source_test.go +++ b/internal/scheme/source_test.go @@ -304,20 +304,22 @@ func TestSourceScheme_Alert(t *testing.T) { r.Records[1], r.Records[2] = r.Records[2], r.Records[1] } - expected := `"foo:alert-test,2021-01-02T15:04:05Z,FAILURE,123.456,dummy:hello-world,test-message"` + expected := "foo:alert-test" if r.Records[1].Message != expected { t.Errorf("unexpected message for foo:alert-test\n--- expected --\n%s\n--- actual ---\n%s", expected, r.Records[1].Message) } - if runtime.GOOS == "windows" { - // Windows can not handle double quote in argument, so test on Windows does not use extra values :( - if r.Records[1].Extra != nil { - t.Errorf("unexpected extra values: %#v", r.Records[1].Extra) - } - } else { - if diff := cmp.Diff(r.Records[1].Extra, map[string]interface{}{"extras": map[string]interface{}{}}); diff != "" { - t.Errorf("unexpected extra values\n%s", diff) - } + extra := map[string]interface{}{ + "record": map[string]interface{}{ + "latency": 123.456, + "message": "test-message", + "status": "FAILURE", + "target": "dummy:hello-world", + "time": "2021-01-02T15:04:05Z", + }, + } + if diff := cmp.Diff(r.Records[1].Extra, extra); diff != "" { + t.Errorf("unexpected extra values\n%s", diff) } } diff --git a/internal/scheme/testdata/ayd-foo-alert b/internal/scheme/testdata/ayd-foo-alert index 1a6ac2dd..e1a1ea2f 100755 --- a/internal/scheme/testdata/ayd-foo-alert +++ b/internal/scheme/testdata/ayd-foo-alert @@ -1,7 +1,7 @@ #!/bin/sh -if [ "$7" = "" ]; then - echo '{"time":"2001-02-03T16:05:06Z","status":"HEALTHY","latency":123.456,"target":"'$1'","message":"\"'$1,$2,$3,$4,$5,$6'\""}' +if [ "$2" = "" ]; then + echo '{"time":"2001-02-03T16:05:06Z","status":"HEALTHY","latency":123.456,"target":"'$1'","message":"'$1'"}' else - echo '{"time":"2001-02-03T16:05:06Z","status":"HEALTHY","latency":123.456,"target":"'$1'","message":"\"'$1,$2,$3,$4,$5,$6'\"","extras":'"$7"'}' + echo '{"time":"2001-02-03T16:05:06Z","status":"HEALTHY","latency":123.456,"target":"'$1'","message":"'$1'","record":'$2'}' fi diff --git a/internal/scheme/testdata/ayd-foo-alert.bat b/internal/scheme/testdata/ayd-foo-alert.bat index adca00cc..03819997 100755 --- a/internal/scheme/testdata/ayd-foo-alert.bat +++ b/internal/scheme/testdata/ayd-foo-alert.bat @@ -1,3 +1,7 @@ @echo off -echo {"time":"2001-02-03T16:05:06Z","status":"HEALTHY","latency":123.456,"target":"%1","message":"\"%1,%2,%3,%4,%5,%6\""} +if "%2" == "" ( + echo {"time":"2001-02-03T16:05:06Z","status":"HEALTHY","latency":123.456,"target":"%1","message":"%1"} +) else ( + echo {"time":"2001-02-03T16:05:06Z","status":"HEALTHY","latency":123.456,"target":"%1","message":"%1","record":%2} +) diff --git a/lib-ayd/args.go b/lib-ayd/args.go index c95dce3e..eb3812d4 100644 --- a/lib-ayd/args.go +++ b/lib-ayd/args.go @@ -1,16 +1,16 @@ package ayd import ( - "encoding/json" "os" - "strconv" - "strings" "time" "github.com/macrat/ayd/internal/ayderr" ) // ProbePluginArgs is arguments for probe plugin +// +// Deprecated: since version 0.16. This struct will removed in future version. +// Please parse using ParseURL instead of this. type ProbePluginArgs struct { TargetURL *URL } @@ -37,6 +37,9 @@ func ParseProbePluginArgs() (ProbePluginArgs, error) { } // AlertPluginArgs is arguments for alert plugin +// +// Deprecated: since version 0.16. This struct will removed in future version. +// Please parse using ParseURL and ParseRecord instead of this. type AlertPluginArgs struct { AlertURL *URL Time time.Time @@ -49,8 +52,8 @@ type AlertPluginArgs struct { // ParseAlertPluginArgsFrom is parse arguments for alert plugin func ParseAlertPluginArgsFrom(args []string) (AlertPluginArgs, error) { - if len(args) != 8 { - return AlertPluginArgs{}, ayderr.New(ErrArgumentCount, nil, "invalid argument: should give exactly 7 arguments") + if len(args) != 3 { + return AlertPluginArgs{}, ayderr.New(ErrArgumentCount, nil, "invalid argument: should give exactly 2 arguments") } alertURL, err := ParseURL(args[1]) @@ -58,36 +61,19 @@ func ParseAlertPluginArgsFrom(args []string) (AlertPluginArgs, error) { return AlertPluginArgs{}, ayderr.New(ErrInvalidArgumentValue, err, "invalid alert URL") } - timestamp, err := ParseTime(args[2]) - if err != nil { - return AlertPluginArgs{}, ayderr.New(ErrInvalidArgumentValue, err, "invalid timestamp") - } - - status := ParseStatus(strings.ToUpper(args[3])) - - latency, err := strconv.ParseFloat(args[4], 64) + record, err := ParseRecord(args[2]) if err != nil { - return AlertPluginArgs{}, ayderr.New(ErrInvalidArgumentValue, err, "invalid latency") - } - - targetURL, err := ParseURL(args[5]) - if err != nil { - return AlertPluginArgs{}, ayderr.New(ErrInvalidArgumentValue, err, "invalid target URL") - } - - var extra map[string]interface{} - if err := json.Unmarshal([]byte(args[7]), &extra); err != nil { - return AlertPluginArgs{}, ayderr.New(ErrInvalidArgumentValue, err, "invalid extra values") + return AlertPluginArgs{}, err } return AlertPluginArgs{ AlertURL: alertURL, - Time: timestamp, - Status: status, - Latency: time.Duration(latency) * time.Millisecond, - TargetURL: targetURL, - Message: args[6], - Extra: extra, + Time: record.Time, + Status: record.Status, + Latency: record.Latency, + TargetURL: record.Target, + Message: record.Message, + Extra: record.Extra, }, nil } diff --git a/lib-ayd/args_test.go b/lib-ayd/args_test.go index aa2ab2a4..932f6533 100644 --- a/lib-ayd/args_test.go +++ b/lib-ayd/args_test.go @@ -68,7 +68,7 @@ func TestParseAlertPluginArgs(t *testing.T) { Error string }{ { - []string{"./ayd-test-alert", "foo:bar", "2001-02-03T16:05:06Z", "HEALTHY", "123.456", "bar:baz", "foo bar", `{"hello":"world"}`}, + []string{"./ayd-test-alert", "foo:bar", `{"time":"2001-02-03T16:05:06Z", "status":"HEALTHY", "latency":123.456, "target":"bar:baz", "message":"foo bar", "hello":"world"}`}, "foo:bar", "2001-02-03 16:05:06 +0000 UTC", "HEALTHY", @@ -87,10 +87,10 @@ func TestParseAlertPluginArgs(t *testing.T) { "", "", nil, - `invalid argument: should give exactly 7 arguments`, + `invalid argument: should give exactly 2 arguments`, }, { - []string{"./ayd-test-alert", "foo:bar", "2001-02-03T16:05:06Z", "HEALTHY", "123.456", "bar:baz", "foo bar", "{}", "unknown extra arg"}, + []string{"./ayd-test-alert", "foo:bar", `{"time":"2001-02-03T16:05:06Z", "status":"HEALTHY", "latency":123.456, "target":"bar:baz", "message":"foo bar", "hello":"world"}`, "extra something"}, "", "", "", @@ -98,10 +98,10 @@ func TestParseAlertPluginArgs(t *testing.T) { "", "", nil, - `invalid argument: should give exactly 7 arguments`, + `invalid argument: should give exactly 2 arguments`, }, { - []string{"./ayd-test-alert", "::invalid::", "2001-02-03T16:05:06Z", "HEALTHY", "123.456", "bar:baz", "foo bar", "{}"}, + []string{"./ayd-test-alert", "::invalid::", `{"time":"2001-02-03T16:05:06Z", "status":"HEALTHY", "latency":123.456, "target":"bar:baz", "message":"foo bar", "hello":"world"}`}, "", "", "", @@ -112,7 +112,7 @@ func TestParseAlertPluginArgs(t *testing.T) { `invalid alert URL: parse "::invalid::": missing protocol scheme`, }, { - []string{"./ayd-test-alert", "foo:bar", "2001-02-03T16:05:06Z", "HEALTHY", "123.456", "::invalid::", "foo bar", "{}"}, + []string{"./ayd-test-alert", "foo:bar", `{"time":"2001-02-03T16:05:06Z", "status":"HEALTHY", "latency":123.456, "target":"::invalid::", "message":"foo bar", "hello":"world"}`}, "", "", "", @@ -120,32 +120,10 @@ func TestParseAlertPluginArgs(t *testing.T) { "", "", nil, - `invalid target URL: parse "::invalid::": missing protocol scheme`, - }, - { - []string{"./ayd-test-alert", "foo:bar", "this is not a time", "HEALTHY", "123.456", "bar:baz", "foo bar", "{}"}, - "", - "", - "", - "", - "", - "", - nil, - `invalid timestamp: invalid format: "this is not a time"`, - }, - { - []string{"./ayd-test-alert", "foo:bar", "2001-02-03T16:05:06Z", "HEALTHY", "not a latency", "bar:baz", "foo bar", "{}"}, - "", - "", - "", - "", - "", - "", - nil, - `invalid latency: strconv.ParseFloat: parsing "not a latency": invalid syntax`, + `invalid record: target: parse "::invalid::": missing protocol scheme`, }, { - []string{"./ayd-test-alert", "foo:bar", "2001-02-03T16:05:06Z", "HEALTHY", "123.456", "bar:baz", "foo bar", `invalid extra`}, + []string{"./ayd-test-alert", "foo:bar", `wah`}, "", "", "", @@ -153,7 +131,7 @@ func TestParseAlertPluginArgs(t *testing.T) { "", "", nil, - "invalid extra values: invalid character 'i' looking for beginning of value", + `invalid record: invalid character 'w' looking for beginning of value`, }, }