Example: Use a ZendHQ monitoring webhook to send an email

One use case for ZendHQ monitoring webhooks is to send pro-active notifications to DevOps staff. A common integration is to send these to an email address monitored by IT or DevOps personnel.

This example demonstrates a webhook that will react to ZendHQ warning and critical events, and send an email. The webhook handler is written using PHP 8.1, and uses the following libraries:

  • symfony/mailer, a library for sending emails from PHP. The example DOES NOT detail how to configure the mail transport (represented by Symfony\Component\Mailer\MailerInterface); refer to the library documentation for details on configuring a mail transport.
  • 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.
<?php

declare(strict_types=1);

namespace App\Handler;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Psr\Http\Message\ResponseFactoryInterface;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mime\Email;
use Throwable;

class EmailWebhookHandler implements RequestHandlerInterface
{
	private const SEVERITIES = [
		'warning',
		'critical',
	];

	public function __construct(
		private MailerInterface $mailer,
		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;
			}

	$mail = (new Email())
		->from('it-noreply@example.com')
		->to('it-triage@example.com')
		->subject("[{$event['severity']}] {$event['name']}")
		->text(<<<END
			A monitoring event with severity {$event['severity']} occurred.

			- Event type: {$event['name']}
			- Server: {$event['request']['node_name']}
			- Request ID: {$event['request_id']}
			- URL: {$event['request']['url']}
			- Location: {$event['source']['function_name']} in {$event['source']['file_name']}, line {$event['source']['line_no']}

			Please investigate and resolve.
			END);

		try {
			$this->mailer->send($mail);
		} 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 creates an email from the event (the event type, the filename and ZendPHP node triggering the event, the request ID, and more).
  • It sends the email
  • 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.