Skip to content

Commit

Permalink
feat(alert): change alert plugin's arguments structure
Browse files Browse the repository at this point in the history
  • Loading branch information
macrat committed Dec 4, 2022
1 parent a21faec commit afc0f59
Show file tree
Hide file tree
Showing 9 changed files with 60 additions and 121 deletions.
25 changes: 7 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand All @@ -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.
Expand Down
8 changes: 4 additions & 4 deletions internal/scheme/alert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"},

Expand All @@ -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"}`, ""},
)
}

Expand Down
15 changes: 1 addition & 14 deletions internal/scheme/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,10 @@ package scheme
import (
"bufio"
"context"
"encoding/json"
"errors"
"fmt"
"os"
"os/exec"
"strconv"
"strings"
"time"

Expand Down Expand Up @@ -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(
Expand Down
13 changes: 3 additions & 10 deletions internal/scheme/plugin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
22 changes: 12 additions & 10 deletions internal/scheme/source_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}

Expand Down
6 changes: 3 additions & 3 deletions internal/scheme/testdata/ayd-foo-alert
Original file line number Diff line number Diff line change
@@ -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
6 changes: 5 additions & 1 deletion internal/scheme/testdata/ayd-foo-alert.bat
Original file line number Diff line number Diff line change
@@ -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}
)
46 changes: 16 additions & 30 deletions lib-ayd/args.go
Original file line number Diff line number Diff line change
@@ -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
}
Expand All @@ -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
Expand All @@ -49,45 +52,28 @@ 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])
if err != nil {
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
}

Expand Down
40 changes: 9 additions & 31 deletions lib-ayd/args_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -87,21 +87,21 @@ 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"},
"",
"",
"",
"",
"",
"",
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"}`},
"",
"",
"",
Expand All @@ -112,48 +112,26 @@ 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"}`},
"",
"",
"",
"",
"",
"",
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`},
"",
"",
"",
"",
"",
"",
nil,
"invalid extra values: invalid character 'i' looking for beginning of value",
`invalid record: invalid character 'w' looking for beginning of value`,
},
}

Expand Down

0 comments on commit afc0f59

Please sign in to comment.