quendistudio / monitoring
Report Winter CMS exceptions to a configurable HTTP webhook
Package info
github.com/quendistudio/monitoring
Type:winter-plugin
pkg:composer/quendistudio/monitoring
Requires
- php: >=8.1
README
Winter CMS plugin — reports application exceptions to a configurable HTTP webhook endpoint (JSON POST + Bearer token).
Lightweight, no external dependencies: ideal for hooking up a custom worker, n8n, Zapier, or any API that accepts JSON.
Installation
Composer (recommended)
composer require quendistudio/monitoring php artisan winter:up
Manual
Clone into plugins/quendistudio/monitoring, then:
php artisan winter:up
Backend → Settings → Monitoring (QuendiStudio Plugins category). Full documentation is also available in the Documentation tab of the settings page.
Grant the quendistudio.monitoring.access_settings permission to the relevant administrators.
Configuration
| Field | Description |
|---|---|
| Enable reporting | Master switch |
| Site identifier | Unique slug (e.g. mywebsite-www) — useful for multi-site setups |
| Site URL | Empty = APP_URL |
| Webhook URL | Public HTTP/HTTPS endpoint only (local/private addresses rejected) |
| Webhook secret | Key sent as Authorization: Bearer … |
| Deduplication (minutes) | Do not resend the same error before this interval |
| HTTP timeout | Max duration of the call (seconds) |
| Log lines to include | Tail excerpt from storage/logs/system*.log |
| Log file (optional) | Custom path inside storage/logs/ only |
| Verify SSL | Off = skip certificate check (local dev). On = always verify (production) |
| Report console errors | Includes CLI exceptions (artisan, cron) |
| Allow test route | Debug route (see Tests) |
Which exceptions are reported?
Winter’s built-in $dontReport list (in Handler.php) tells the core not to log certain exception types to the application log — it does not mean they are unimportant. This plugin hooks exception.beforeReport, which runs before that filter, so the following are included when they reach the exception handler:
ApplicationException,ValidationException,AjaxException- HTTP, authentication, and model-not-found exceptions
- Any other
Throwablepassed toHandler::report()
Not reported: exceptions caught and handled before report() is called (expected control flow, successful validation redirects, etc.).
Sensitive data in payloads
The JSON payload is designed for automated analysis. It may contain:
- Full exception messages and stack traces
- Request URL including query string (tokens, emails, etc.)
- Tail of
storage/logs/system*.log(may include secrets from log context)
Ensure the webhook endpoint and downstream services (agent, email provider) are trusted and secured. Restrict backend access to Monitoring settings.
JSON schema
Each exception triggers a POST to webhook_url with headers:
Content-Type: application/json
Authorization: Bearer {webhook_secret}
User-Agent: Quendistudio.Monitoring/1.0
Root fields
| Field | Type | Description |
|---|---|---|
event |
string | Always winter.exception |
source |
string | Always quendistudio.monitoring |
site_id |
string | Site identifier (settings or hostname) |
site_url |
string | Site URL |
platform |
string | Always wintercms |
occurred_at |
string | ISO 8601 timestamp |
exception |
object | Exception details (see below) |
request |
object | HTTP context (empty in CLI) |
logs_tail |
string | Last lines of the system log file |
test |
bool | Present and true only for test payloads |
exception object
| Field | Type | Description |
|---|---|---|
class |
string | Exception FQCN |
message |
string | Error message |
file |
string | Source file |
line |
int | Source line |
code |
int | Error code |
trace |
string | Stack trace (truncated per settings) |
request object
| Field | Type | Description |
|---|---|---|
url |
string | Full request URL |
method |
string | HTTP method |
ip |
string | Client IP address |
user_agent |
string | User-Agent (max 500 characters) |
Example (real exception)
{
"event": "winter.exception",
"source": "quendistudio.monitoring",
"site_id": "mywebsite-www",
"site_url": "https://www.example.com",
"platform": "wintercms",
"occurred_at": "2026-06-15T14:30:00+02:00",
"exception": {
"class": "Winter\\Storm\\Exception\\ApplicationException",
"message": "Something went wrong",
"file": "/var/www/plugins/vendor/plugin/SomeClass.php",
"line": 42,
"code": 0,
"trace": "#0 /var/www/index.php(42): ..."
},
"request": {
"url": "https://www.example.com/page",
"method": "GET",
"ip": "203.0.113.1",
"user_agent": "Mozilla/5.0 ..."
},
"logs_tail": "[2026-06-15 14:29:58] production.ERROR: ..."
}
Example (test payload)
Same as above, plus "test": true and a simulated message.
Adapting your endpoint
The plugin sends a generic JSON format. Your endpoint (or an intermediary) is responsible for:
- validating the Bearer token;
- parsing the
exception,request, andlogs_tailfields; - triggering the desired action (email, ticket, centralized logging, etc.).
Integration examples:
- Serverless worker (Cloudflare Workers, AWS Lambda): receive the POST, format an email or alert.
- n8n / Zapier / Make: webhook trigger → map JSON fields to Slack, email, database.
- Internal API: store errors in your own monitoring system.
Extension plugins for native formats (Slack, Discord, Sentry, etc.) may be developed later; this plugin deliberately focuses on the generic webhook.
Tests
# Test JSON payload (without throwing an exception)
php artisan monitoring:testwebhook
Intentional exception route (Development tab):
- Enable Allow test route
- Ensure
APP_DEBUG=true - Open
/quendistudio/monitoring/test-exception
Do not enable the test route in production.
Application flow
Winter Handler::report()
→ exception.beforeReport (this plugin)
→ ExceptionPayloadBuilder (JSON)
→ ErrorReporter (deduplication after successful POST, async at end of request)
→ Your webhook
Appendix: Cursor Automation integration
Cursor Automations can act as a webhook receiver with a Webhook trigger:
- Create an automation with a Webhook trigger.
- Copy the URL and authentication key into Webhook URL and Webhook secret.
- Configure the agent prompt to analyze the JSON payload (
exception,logs_tail,request). - Optional: chain a second webhook (email, Resend, Slack, etc.) from the automation.
The JSON schema documented above can be used directly by the Cursor agent — no transformation on the plugin side is required.
License
MIT — see LICENCE.md.