Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Metrics Laravel Package

eliseekn/laravel-metrics

Generate metrics and trends from your Laravel models for dashboards. Group counts and sums by day, month, or year, set custom date/label columns and tables, use date ranges, and query via Eloquent or the query builder. Supports MySQL, PostgreSQL, and SQLite.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit

  • Thin, stateless fluent builder that decorates an existing Eloquent\Builder or QueryBuilder instance — nothing is persisted, no migrations, no service container bindings to manage, no events or queues. It sits as a read-only projection layer between your models and whatever renders the dashboard.
  • Fits naturally into a "dashboard read path" architecture: controller or service method receives a scope (tenant, user, date window), the package emits GROUP BY aggregates, and the caller shapes the result for Chart.js/ApexCharts/Filament widgets.
  • It is explicitly not an analytics platform. There is no caching, no pre-aggregation, no rollup tables, no scheduled jobs, no metric registry. Every call is a live SQL aggregate. Treat it as syntactic sugar over hand-written selectRaw('COUNT(*) ... group by ...'), and scope it accordingly.
  • The HasMetrics trait is convenient but couples models to the package; prefer the static LaravelMetrics::query() entry point so the dependency stays in the presentation/service layer.

Integration feasibility

  • composer require and go. Pure PHP, PHP ^8.2, Laravel ^11/^12 (Laravel 13 only on the separate 4.x branch). MySQL, PostgreSQL, and SQLite supported. No config publishing, no asset pipeline, no queue worker changes. Integration effort is measured in hours, not sprints.
  • The verbose chain (->count()->byMonth(6)->trends()) is discoverable and self-documenting; the combined shortcuts (countByMonth, sumBetween) reduce boilerplate further. Low cognitive load for mid-level Laravel developers.

Technical risk

  • Bus factor / adoption risk is the dominant concern. 138 stars, zero dependents on record, and what appears to be a single maintainer. There is no commercial backing and no SLA. Mitigation is cheap (MIT, small surface, forkable), but it must be planned for, not assumed away.
  • Version and branch sprawl. Releases span 2.x, 3.x, and 4.x, with Laravel 13 support living only on 4.x. The mainline constraint targets Laravel 11/12. Choosing a version is a support-matrix decision, not a routine composer update.
  • Regression history on the same bug class. "Missing data labels auto discovery" is fixed, restored, and re-fixed across 2.9.4, 2.9.5, 3.0.3, and 3.0.4. Driver-specific date SQL has been patched more than once (2.9.3, 3.2.1). This signals thin automated coverage on exactly the paths dashboards depend on. Verify with your own integration tests per driver, not with the vendor's changelog.
  • Correctness sharp edges that fail silently. groupData() requires argument order to match data order — the README itself warns "follow same order to avoid false data." Missing buckets yield gaps unless fillMissingData() is called. labelColumn() with high cardinality can explode result sets. trends() vs metrics() vs metricsWithVariations() have different return shapes. These are not crash-on-deploy risks; they are wrong-chart-in-a-board-meeting risks.
  • SQL construction surface. table(), dateColumn(), and labelColumn() accept string identifiers that get interpolated into raw SQL. Since values are developer-supplied rather than user-supplied, this is manageable — but any path that lets a user influence those strings must be treated as injection surface.
  • Performance is unbounded by design. Date functions wrapped around columns (DATE_FORMAT, EXTRACT) generally defeat plain B-tree indexes, and there is no result caching. On multi-million-row tables, a dashboard with eight widgets becomes eight full-range aggregates per page load.

Key questions for the maintainer / spike

  1. What is the intended caching story — is a cache layer planned, or is it strictly the caller's responsibility?
  2. Is there an authorization/tenant-scoping convention, or is every query expected to be pre-scoped by the caller? (Assume the latter; enforce in a wrapper.)
  3. What is the automated test matrix across MySQL/PostgreSQL/SQLite and Laravel 11/12/13? Are there CI badges or coverage reports?
  4. Is 4.x intended as the long-term line, and will ^11|^12 constraints on the default branch be reconciled with Laravel 13?
  5. How are identifier arguments sanitized before interpolation into raw SQL?
  6. Timezone semantics: are bucket boundaries computed in config('app.timezone') or the DB session timezone? Off-by-one-day bugs at month and year edges are the most common dashboard defect and the hardest to spot.
  7. Is there a production reference beyond the demo repo, and roughly what row counts does it operate against?

Integration Approach

Stack fit

  • Native fit for a Laravel 11/12 monolith with Eloquent models and a Blade/Livewire/Filament/Inertia admin surface. Zero friction with existing app/Models, existing migrations, and existing auth scoping — you pass an already-constrained builder (->where('user_id', auth()->id())) and the package aggregates within that scope.
  • Poor fit for a service-oriented or event-driven analytics pipeline. If the requirement is "sub-second dashboards over 50M rows" or "historical metric retention independent of source tables," this is the wrong tool; that is a columnar store or a rollup-table problem.

Migration path

  • Purely additive. No migrations, no schema changes, no data backfill, no dual-write period. It reads tables you already have.
  • Wrap every call behind an application-owned interface (e.g. App\Support\Metrics\DashboardMetrics) so the package never appears in controllers or views. This makes a future swap to hand-written SQL, a different package, or a fork a one-file change, and it gives you a single place to add caching and tenant scoping.
  • Rollback is composer remove plus deleting one wrapper class. This is the strongest argument for adopting it for low-stakes internal dashboards.

Compatibility

  • Pin the version explicitly in composer.json. Do not float on ^ across a package that ships breaking structural changes between major lines and whose minors carry bug fixes to core data shaping.
  • Validate DB driver parity before rollout — even if production is MySQL only, run the test suite against PostgreSQL and SQLite if those appear anywhere in staging or CI.
  • Confirm the Laravel/PHP matrix in CI matches the pinned branch: Laravel 13 requires 4.x, which is a different code line from the one most README examples were written against.

Sequencing

  1. Spike (1–2 days): two real dashboard widgets against production-shaped data, measured for query count, latency, and result correctness at date boundaries (month start/end, year rollover, empty ranges, a period with zero rows).
  2. Wrapper + guardrails: introduce the DashboardMetrics service, enforce tenant scoping there, add an explicit fillMissingData() convention, and forbid raw user input into table/labelColumn/dateColumn at the wrapper boundary.
  3. Caching layer: Cache::remember on the wrapper keyed by (widget, scope, period, timezone), with TTLs tuned per widget. This is not optional at any meaningful traffic level.
  4. Broaden: migrate remaining internal dashboards widget by widget, each with a golden-file assertion on the returned dataset shape and values.
  5. Document the exit: a short ADR recording the version pin, the wrapper boundary, the fork procedure, and the trigger conditions for replacing the package (e.g. two unpatched regressions, or a latency SLO breach that caching cannot fix).

Operational Impact

Maintenance

  • Low ongoing effort in normal operation — no runtime services, no config, no background processes. The real cost is upgrade diligence: read every changelog, and re-run the golden-file assertions on fillMissingData, groupData, labelColumn, and each DB driver before bumping.
  • Budget a contingency for a fork. MIT license and a compact codebase mean a fork-and-patch is a day of work, not a quarter. Pre-identify the engineer who would own it.

Support

  • Community-only: GitHub issues plus a security email. No SLA, no vendor escalation, no paid support tier. For an internal, non-revenue-critical dashboard this is acceptable; for a customer-facing billing or SLA dashboard it is not.
  • The single-maintainer profile means an unanswered issue can block you indefinitely. The wrapper boundary from the Integration section is the operational mitigation, not a nicety.

Scaling

  • Cost scales linearly with widget count and inversely with index usability. N widgets = N aggregate queries per render; date-function grouping typically forces a scan of the period range.
  • Levers, in order of cost-effectiveness: (1) cache at the wrapper with period-aligned TTLs; (2) ensure a composite index on (scope_column, date_column) for every metric source; (3) bound every query with the narrowest possible period — never let a default "current year" silently become "all time"; (4) route dashboard reads to a replica; (5) only if still insufficient, introduce nightly rollup tables and have the wrapper read those instead of source tables.
  • Watch labelColumn() cardinality. Grouping by a high-cardinality column (user_id, uuid) will produce large result sets that get serialized into a chart payload. Use groupData() with an explicit bucket list for status-like columns instead.

Failure modes

  • Silent gaps: missing date buckets produce holes in the series unless fillMissingData() is applied. Charts render "correctly" and are simply wrong.
  • Silent mislabeling: groupData() with mismatched argument order maps values to the wrong labels, with no error. Add an assertion comparing the returned label set to the requested set.
  • Timezone drift: bucket boundaries computed in a different timezone than the business expects produce off-by-one-day errors at month and year edges. Test explicitly at 23:59 on the last day of a month.
  • Driver divergence: date SQL is generated per driver and has been patched more than once (notably PostgreSQL in 3.2.1). A driver upgrade or a staging/production mismatch can change results without any application code changing.
  • Upgrade regressions: the recurring fillMissingData label-discovery defect has shipped in at least four releases. Assume any minor bump can regress it and gate upgrades on tests.
  • Unbounded queries: no built-in period cap or query timeout. A default byYear() over an unindexed column on a large table is a straightforward path to a dashboard-driven outage.
  • Empty-result exceptions: there is prior history of null/undefined-key exceptions on empty trends (2.4.1, 2.7.3, 2.9.2-beta-2). Always test the zero-data case for every widget.

Ramp-up

  • Very shallow learning curve: the README is unusually complete for a package this size, the API is fluent and chainable, and a competent Laravel developer is productive within half a day.
  • The hours saved on ramp-up are partly repaid in learning the sharp edges — ordering constraints in groupData, the difference between trends/metrics/metricsWithVariations return shapes, and the interaction between between() and groupBy*(). Capture these in a short internal "gotchas" note alongside the wrapper so the knowledge is institutional rather than personal.
  • Realistic assessment: adopt for internal, read-only dashboards on moderate data volumes, behind an application-owned wrapper with caching and explicit scoping. Do not adopt for customer-facing SLA reporting, for datasets requiring sub-second response over tens of millions of rows, or anywhere a silent wrong number carries commercial or regulatory consequences.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core