ServiceRadar plugin SDK for Go (TinyGo/WASM).
This SDK lets you write ServiceRadar plugin checkers in Go without handling low-level WASM host calls. It handles:
- Config decoding from the host
- Result builder for
serviceradar.plugin_result.v1 - Logging bridge
- HTTP/TCP/UDP proxy wrappers
- Support for Websockets
- Event emission + alert promotion hints
go get github.com/carverauto/serviceradar-sdk-gopackage main
import (
"context"
"fmt"
"github.com/carverauto/serviceradar-sdk-go/sdk"
)
type Config struct {
URL string `json:"url"`
WarnMS float64 `json:"warn_ms"`
CritMS float64 `json:"crit_ms"`
}
//export run_check
func run_check() {
_ = sdk.Execute(func() (*sdk.Result, error) {
var cfg Config
if err := sdk.LoadConfig(&cfg); err != nil {
return nil, err
}
resp, err := sdk.HTTP.GetContext(context.Background(), cfg.URL)
if err != nil {
return nil, fmt.Errorf("http request failed: %w", err)
}
latency := float64(resp.Duration.Milliseconds())
thresholds := sdk.Thresholds(cfg.WarnMS, cfg.CritMS)
return sdk.NewResult().
WithSummary(fmt.Sprintf("http %d in %.0fms", resp.Status, latency)).
WithThresholds(latency, thresholds.Warn, thresholds.Crit).
WithMetric("latency_ms", latency, "ms", thresholds).
WithStatCard("Latency", fmt.Sprintf("%.0fms", latency), "success"), nil
})
}
func main() {}examples/http-check: HTTP latency check with thresholds and eventsexamples/tcp-check: TCP connectivity check with optional write/readexamples/udp-check: UDP send check with bytes-sent metricexamples/widgets-check: HTTP check demonstrating stat card, table, sparkline, and markdown widgets
Execute accepts a function that returns (*Result, error) and itself returns an error:
err := sdk.Execute(func() (*sdk.Result, error) {
// ...
return sdk.Ok("ok"), nil
})
if err != nil {
// Optional: handle submit/serialize errors (logging is already done by the SDK)
}If your function returns a non-nil error, the SDK auto-generates a critical result (or upgrades your result to critical) and records the error details in the payload. This keeps the happy path concise while still surfacing failures.
Defaults are applied at the edge (right before serialization) so Serialize does not mutate the original object:
SchemaVersiondefaults to1Statusdefaults toUNKNOWNSummarydefaults to the status stringObservedAtdefaults to “now” in RFC3339Nano
This means var r sdk.Result is safe; serialization produces a valid payload without altering r.
Result has both conventional setters (SetSummary, AddMetric, etc.) and fluent builders (WithSummary, WithMetric, etc.) so you can choose style:
return sdk.NewResult().
WithSummary("all good").
WithMetric("cpu", 10, "%", nil).
WithLabel("version", "1.2.3"), nilUse ThresholdSpec for warning/critical thresholds and Thresholds(warn, crit) to build one without helper functions:
thresholds := sdk.Thresholds(50, 100)
res.WithMetric("latency_ms", 10, "ms", thresholds)
res.WithThresholds(10, thresholds.Warn, thresholds.Crit)Context variants exist for host I/O to match Go expectations:
- HTTP:
HTTP.DoContext,HTTP.GetContext,HTTP.PostContext - TCP:
TCPDialContext,(*TCPConn).ReadContext,(*TCPConn).WriteContext - UDP:
UDPSendToContext - WebSocket:
WebSocketDialContext,(*WebSocketConn).ReadContext,(*WebSocketConn).WriteContext
These currently check ctx.Err() before the host call (TinyGo/Wasm is synchronous), but give you a stable API if cancellation support is added later.
The SDK provides WebSocket client capabilities for plugins that need to communicate with WebSocket servers:
// Dial a WebSocket endpoint
conn, err := sdk.WebSocketDialContext(ctx, "ws://localhost:8080/ws")
if err != nil {
return nil, fmt.Errorf("websocket dial failed: %w", err)
}
defer conn.Close()
// Send a message
if err := conn.WriteContext(ctx, []byte(`{"method": "getInfo"}`)); err != nil {
return nil, fmt.Errorf("websocket write failed: %w", err)
}
// Read response
data, err := conn.ReadContext(ctx)
if err != nil {
return nil, fmt.Errorf("websocket read failed: %w", err)
}WebSocket connections are mediated by the host runtime, which enforces:
- Domain allowlists: Only permitted domains can be connected to
- Port restrictions: Only allowed ports can be accessed
- Connection limits: Maximum concurrent connections per plugin
The plugin must have the following capabilities in its manifest:
websocket_connect: Permission to establish WebSocket connectionswebsocket_send: Permission to send messageswebsocket_recv: Permission to receive messageswebsocket_close: Permission to close connections
LoadConfig is an alias of GetConfig for more idiomatic naming in user code:
if err := sdk.LoadConfig(&cfg); err != nil {
return nil, err
}# Requires TinyGo
cd examples/http-check
tinygo build -o plugin.wasm -target=wasi ./The agent imports host functions from the env module:
get_configlogsubmit_resulthttp_requesttcp_connect/tcp_read/tcp_write/tcp_closeudp_sendtowebsocket_connect/websocket_send/websocket_recv/websocket_close
The SDK wraps these functions and exports alloc/dealloc for host memory access.
The SDK emits optional fields in the result payload to support event promotion:
events: list of OCSF Event Log Activity objectsalert_hint: boolean flag for immediate promotioncondition_id: string used for de-duplication and auto-clear logic
These fields are ignored safely by older control-plane builds.