stacknuts / magento-stackgauge
Reports version, patch, and operational health data from a Magento store to a central StackGauge fleet dashboard, so an agency can see every client site's update/security posture at a glance.
Package info
github.com/StackNuts/magento-stackgauge
Type:magento2-module
pkg:composer/stacknuts/magento-stackgauge
Requires
- php: ~8.1.0||~8.2.0||~8.3.0||~8.4.0
- colinmollenhour/credis: ^1.15
- magento/framework: >=103.0 <104
- magento/module-advanced-search: >=100.4 <101
- magento/module-backend: >=102.0 <103
- magento/module-config: >=101.2 <102
- magento/module-cron: >=100.4 <101
- magento/module-indexer: >=100.4 <101
- magento/module-page-cache: >=100.4 <101
- magento/module-store: >=100.0 <102
Requires (Dev)
- phpunit/phpunit: ^10.5 || ^11.5 || ^12.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
A lightweight, read-only agent that reports a Magento store's version, patch, and operational health data to a central StackGauge fleet dashboard - so an agency managing many client sites can see everyone's update/security posture at a glance, instead of checking each store by hand.
Why
External scanners only see what a store exposes publicly - they can't read composer.json,
true per-module versions, or DB schema drift. This module runs inside Magento and reports
what only the inside can see, on a schedule, to a dashboard your agency controls.
What it is
- Push only. This module calls out over HTTPS; it exposes no inbound endpoint and no new attack surface. The dashboard is the server; this module is purely a client.
- Read-only. Every built-in reporter only reads store/platform state. Nothing here modifies catalog, sales, or customer data.
- Boring on purpose. Collect and send, nothing else. Every interesting decision (alerting, severity rollups, retention) belongs on the dashboard side, not here.
- Extensible. Third-party modules can contribute their own status data via a public interface, without ever touching this module's code - see "Pluggable reporters" below.
Installation
composer require stacknuts/magento-stackgauge bin/magento module:enable StackNuts_StackGauge bin/magento setup:upgrade
Configuration
Go to Stores > Configuration > Advanced > StackGauge.
| Field | Notes |
|---|---|
| Enabled | Master switch. Off, no cron job or plugin sends anything - Send Now still works while off, so a site can be fully configured and verified before switching this on. |
| Dashboard Endpoint URL | Full ingest URL issued by the dashboard. |
| Site Identifier | Issued by the dashboard when the site is registered; sent in every report. |
| API Key | Bearer token issued by the dashboard for this site. Stored encrypted. |
| HMAC Secret | Shared secret used to sign every report. Stored encrypted. |
| Disabled Reporters | Which reporters to turn off - built-in or contributed by another module, same list. Opt-out, not opt-in: leave empty (the default) and everything runs, including any reporter a future update or newly-installed companion module adds, with no action needed here. |
| Monitored Log Files | Files (relative to var/log) the Logs reporter tails - pre-filled with the System/Exception logs, editable. |
| Storefront Self-Probe | Whether every heartbeat also curls this store's own homepage - see "Storefront self-probe" below. On by default. |
| Log Level | Minimum severity written to var/log/stacknuts_stackgauge.log. |
These settings apply to the whole Magento instance (default scope only) - one installation reports as one site, not one report per store view.
Click Send Now after saving to verify the endpoint URL and API key work end to end; a successful click sends a heartbeat, both report cadences, and a config sync immediately.
What gets collected
Everything below is read-only platform/store metadata - never catalog, sales, or customer data. Full detail on exact fields lives in the dashboard's own documentation.
| Reporter | Payload key | What it covers |
|---|---|---|
CoreReporter |
core |
Edition, Magento version, PHP version, deployment mode, static content deploy state |
ModuleReporter |
modules |
Every registered module (enabled or not) and its resolved version |
ComposerReporter |
composer |
composer.lock hash, a small watch-list of key platform package versions, and any package downloaded from outside the common registries |
DbSchemaReporter |
db_schema |
Modules whose code setup_version has moved ahead of what's actually applied |
PatchReporter |
patches |
Applied official Adobe Commerce security patches, via vendor/bin/patch-status when present |
IndexerReporter |
indexers |
Per-indexer status/mode, plus pending changelog backlog for schedule-mode indexers |
CronReporter |
cron |
Whether cron looks alive, plus last success and next due time per job |
CacheReporter |
cache |
Per-cache-type status/tags, plus the active Full Page Cache backend |
RedisReporter |
redis |
Reachability and version of each Redis-backed cache/session backend, checked separately |
SearchReporter |
search |
Configured search engine and whether it's actually reachable (Elasticsearch/OpenSearch only) |
RabbitMqReporter |
rabbitmq |
Per-queue message/consumer count, if RabbitMQ is configured |
DbQueueReporter |
db_queue |
Per-queue backlog and error count for every queue routed through the "db" message-queue connection |
UptimeReporter |
uptime |
Hourly storefront self-probe result (reachable / blocked / genuine error page) - see "Storefront self-probe" |
DiskSpaceReporter |
disk |
Free/total bytes for var/log, var/cache, and media, checked independently |
DatabaseReporter |
database |
MySQL/MariaDB version and reachability |
SalesReporter |
sales |
Lifetime order/quote counts, plus hourly order counts and revenue for the recent window |
CatalogReporter |
catalog |
Enabled product count |
CouponsReporter |
coupons |
Active cart price rules and their lifetime redemption counts |
InventoryReporter |
inventory |
Basic in-stock/out-of-stock counts |
CustomerSignalsReporter |
customers |
Customer counts and recent activity |
AbandonedCartsReporter |
abandoned_carts |
Counts of carts with items and no activity in the last 24h |
ProductHealthReporter |
product_health |
Counts of common product data issues (e.g. missing image/price) |
PaymentMethodsReporter |
payments |
Enabled payment methods and key configuration flags |
StoreViewsReporter |
store_views |
Configured store views, locale, and currency |
ThemeReporter |
themes |
Active frontend and admin themes |
PHPExtensionsReporter |
php_extensions |
Presence and versions of important PHP extensions |
LogReporter |
logs |
Recent log activity and exception summaries for the files configured under Monitored Log Files |
ReportReporter |
reports |
Recent var/report summaries |
Security-posture reporters (SecurityReporter, AdminAccountsReporter, ConfigHygieneReporter)
live in the optional StackNuts_StackGaugeSecurity
companion module, not here - see "Security module" below for why.
LogReporter reads each monitored file incrementally - only the bytes appended since its
last run, tracked via a byte offset this module stores per file name (see "Database" below) -
rather than rereading the whole file every time. One consequence: its "recent exceptions" and
tail sections show what's new since the last run, not a constant rehash of the same
historical lines every time, so they can be empty on a quiet run. exception.log's own
occurrence count is the one exception (no pun intended) - it keeps reading as a stable,
ever-growing total across runs, since that's what the dashboard's alerting expects.
Storefront self-probe
Every heartbeat (every few minutes, see below), this server curls its own homepage and classifies the result:
- reachable - got any HTTP response at all
- looks_like_error_page - the body matches Magento's own genuine production-mode fatal
error page (
pub/errors/default/report.phtml's exact text), i.e. Magento itself is broken - looks_blocked - the body matches a common WAF/CDN challenge/interstitial page (e.g. Cloudflare's "Just a moment..."), i.e. something in front of the site stopped this probe before it ever reached Magento
This distinction is the whole point: an external uptime monitor getting WAF-challenged looks
identical to the site actually being down unless the two are told apart, and this probe runs
from the server itself specifically so it can tell them apart. It never looks at response
headers to decide looks_blocked - a site fronted by Cloudflare (or similar) gets a
cf-ray-style header on every response, not just challenges, so header presence alone can't
be the signal. Disable it under Storefront Self-Probe if you'd rather this server never
make an outbound request to itself.
The same probe also runs once an hour as UptimeReporter, alongside every other reporter -
that's the copy with a trackable alert metric (uptime.reachable), since alerting attaches to
reporters, not to the heartbeat. The two aren't redundant: the heartbeat copy is what gets you
a signal within minutes instead of waiting up to an hour.
checkExposedPaths() also exists on this same StorefrontProbe class, for checking a fixed
list of sensitive paths (.git/HEAD, composer.lock, app/etc/env.php, etc.) for HTTP
exposure once a day - but nothing in core StackGauge calls it. It's consumed by
StackNuts_StackGaugeSecurity's SecurityReporter, if that optional companion module is
installed; see "Security module" below.
Security module
Admin-account hygiene, config hygiene, filesystem exposure, and core-tamper checks live in the
separate StackNuts_StackGaugeSecurity
module, not here. So does content-signature scanning: it checks CMS blocks and pages, admin-editable
HTML/JS config, pub/ PHP and generated/code/ for known webshell and Magecart patterns. Its
signature set is downloaded once a day from the public signatures repository on GitHub, verified
against a published SHA-256, and cached; a failed download keeps the previous set, or the copy
bundled with the module. That daily refresh runs in the companion's own cron group, so it never
delays this module's reports. Feed updates can be turned off under Signature Feed Updates in the
same StackGauge config section. Not every install wants this - plenty of agencies already have dedicated
security scanning (Sansec, host-level malware scanning, their own tooling), and running a
second, overlapping set of filesystem walks on every client site would just double that cost
for no benefit. Install it like any other reporter-contributing companion module (see
"Pluggable reporters" below) if you want it; its reporters then show up automatically in the
Disabled Reporters field above like any other.
Database
This module creates one table of its own, stacknuts_stackgauge_log_offset, to support
LogReporter's incremental reads (see above) - one row per monitored log file name, storing
how far it's read and (for exception.log only) a running occurrence count. Nothing else in
StackGauge persists any state locally. bin/magento module:uninstall --remove-data drops this
table; no catalog, sales, or customer data is ever touched.
Transport / auth
POSTto the configured endpoint URL.Authorization: Bearer <api_key>X-StackGauge-Signature: hex HMAC-SHA256 of the raw JSON body, using the configured HMAC secret.X-StackGauge-Site-Id: duplicates the site identifier also present in the JSON body.- Bodies of 1KB or more are gzip-compressed (
Content-Encoding: gzip) before sending; the signature is always computed over the raw, uncompressed body. - 5s connect / 10s total timeout - a slow or unreachable dashboard can never hang a site's cron.
Cron
Runs in its own stackgauge cron group:
stacknuts_stackgauge_send_report- full collection (hourly-cadence reporters), hourly by default.stacknuts_stackgauge_send_daily_report- full collection (daily-cadence reporters, e.g.catalog/coupons), daily by default.stacknuts_stackgauge_send_heartbeat- lightweight ping, every 5 minutes by default.stacknuts_stackgauge_send_config_sync- trackable-metric catalog sync, daily by default.
Every job, and the maintenance-mode plugin, catch every exception internally - a dashboard
outage or misconfiguration can never fail a cron run or block Magento's own maintenance
commands. No extra crontab entry is needed beyond the standard single bin/magento cron:run
entry virtually every Magento install already has.
CLI
bin/magento stackgauge:send # send everything now: every hourly + daily slot and the config sync bin/magento stackgauge:send --dry-run # list which reporters each run would carry, send nothing bin/magento stackgauge:send hourly:1 --dry-run # print one run's full payload bin/magento stackgauge:send daily # all daily slots (also: hourly, hourly:N, daily:N, current, config) bin/magento stackgauge:send --force # send regardless of "Enabled"
Set Log Level to "Info" to have every real send attempt (cron, CLI, Send Now) log its full payload before delivery - useful for verifying what's collected before a dashboard endpoint even exists.
Pluggable reporters
Third-party modules can contribute their own named block to the payload without this module
knowing about them in advance, by implementing StackNuts\StackGauge\Api\ReporterInterface
and registering it against ReporterPool's reporters array from their own di.xml.
A real example: stacknuts/magento-stackgauge-cloudflare-cache
adds a Cloudflare-specific reporter this way, in its own small compatibility module rather
than editing either parent module directly - the recommended pattern to copy for your own
integration.
Shape rules for a reporter's getStatus() return value:
- Build every field via
StackNuts\StackGauge\Api\Field\Field::bool()/varchar()/number()/datetime()/trackableNumber(), grouped into sections viaStackNuts\StackGauge\Api\Section\Section::facts()or::table(). No raw scalars, objects, or closures. - A field's key must stay unique across your reporter's sections.
- Return an empty section rather than throwing when there's nothing to report - a thrown exception is logged and surfaces as an error for that cycle instead of your data.
- Keep it small - no raw file contents, no PII, no binary blobs.
The admin Disabled Reporters toggle covers your reporter too, automatically - its options
are derived from every reporter actually registered with ReporterPool (see
Model\System\Config\Source\ReporterList), not a hardcoded list of built-in codes. Registering
your reporter via di.xml the way this section describes is the only step needed; there's no
separate registration for it to become individually toggleable.
Uninstall
bin/magento module:disable StackNuts_StackGauge composer remove stacknuts/magento-stackgauge bin/magento setup:upgrade
Contributing
See CONTRIBUTING.md.
License
PolyForm Shield 1.0.0. Free to install, run, and modify - including to report to your own dashboard - but not to build or operate a competing fleet-monitoring product. See LICENSE.