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-issueschannel 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.