Example: Use a ZendHQ monitoring webhook to send a Slack notification
One use case for ZendHQ monitoring webhooks is to send pro-active notifications to DevOps staff. A common integration is to send these to a shared notification channel such as a Slack channel, PagerDuty, etc.
This example demonstrates a webhook that will react to ZendHQ warning
and critical
events, and send a Slack notification on receipt. The webhook handler is written using PHP 8.1, and uses the following libraries:
- maznz/slack, a library for sending Slack notifications from PHP. This example does not detail how to configure the Slack client, only sending messages.
- a PSR-15 request handler responding to the webhook; it makes the assumption that previous middleware has parsed the JSON response into the "parsed body" of the request.
- a PSR-17 HTTP response factory to send a 204 response on receipt.
The webhook handler itself:
<?php declare(strict_types=1); namespace App\Handler; use DateTimeImmutable; use Maknz\Slack\Client; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\RequestHandlerInterface; use Psr\Http\Message\ResponseFactoryInterface; use Throwable; class MonitoringWebhookHandler implements RequestHandlerInterface { private const SEVERITIES = [ 'warning', 'critical', ]; public function __construct( private Client $slack, private ResponseFactoryInterface $responseFactory, ) { } public function handle(ServerRequestInterface $request) : ResponseInterface { $response = $this->responseFactory->createResponse(204); $event = $request->getParsedBody(); if (! isset($event['severity']) || ! in_array($event['severity'], self::SEVERITIES, true)) { return $response; } $data = [ 'Type' => $event['name'], 'URL' => $event['request']['url'], 'Node' => $event['request']['node_name'], 'Request ID' => $event['request_id'], 'Timestamp' => (new DateTimeImmutable("@{$event['time_sec']}"))->format('c'), ]; $fields = []; foreach ($data as $key => $value) { $fields[] = [ 'title' => $key, 'value' => $value, 'short' => false, ]; } try { $this->slack ->to('#infra-php-issues') ->attach([ 'fallback' => "Issue of type {$event['severity']} in PHP application", 'text' => 'Issue in PHP application', 'color' => match ($event['severity']) { 'warning' => 'warning', 'critical' => 'danger', }, 'fields' => $fields, ]) ->send('New alert for PHP application'); } catch (Throwable) { } finally { return $response; } } }
The webhook workflow is as follows:
- It checks to see if the severity of the event is of interest; if not, it immediately returns a response without further processing.
- It then gathers data from the event: the event type, the URL and ZendPHP node triggering the event, the request ID, and the time it was triggered.
- It creates a Slack message that it sends to the
#infra-php-issues
channel with field attachments. In Slack, this message generates a table with the data. - It sends the message.
- It returns a response indicating it has completed.
The data available in the webhook is detailed in the mon.get_issues method documentation of the Websocket API.