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

Cache Stats Bundle Laravel Package

pablok/cache-stats-bundle

Monitor and inspect your application's cache with detailed statistics on hits, misses, writes, and evictions. This bundle adds a simple dashboard and profiling tools so you can spot performance bottlenecks, tune cache configuration, and keep your cache healthy in development and production.

View on GitHub
Deep Wiki
Context7

Getting Started

pablok/cache-stats-bundle is a Symfony bundle, not a Laravel package — worth stating up front because it changes how you should consume it. It wraps the three PHP extension surfaces that silently degrade production apps: OPCache (opcache_get_status()), APCu (apcu_cache_info() / apcu_sma_info()), and the realpath cache (realpath_cache_size() / realpath_cache_get()).

There is no CacheStatsServiceProvider, no config/cache-stats.php, no publishable assets. composer require pablok/cache-stats-bundle in a Laravel app installs files and does nothing else, because Laravel only auto-discovers Illuminate\Support\ServiceProvider implementations.

So do this instead:

  1. Read the source, don't install it. The bundle is thin — a handful of classes calling the functions above. That is 40–80 lines of logic you can own.
  2. Look first at whatever wraps opcache_get_status() and note the flags the author passes (false vs true for the script list) — that's the one decision that matters for memory safety.
  3. First use case: a protected diagnostic route or artisan command that prints the four numbers you actually alert on.
// app/Support/CacheStats.php
class CacheStats
{
    public function opcache(): ?array
    {
        if (! function_exists('opcache_get_status')) return null;

        // false = skip the per-script list. Critical on large apps.
        return opcache_get_status(false) ?: null;
    }

    public function apcu(): ?array
    {
        if (! function_exists('apcu_enabled') || ! apcu_enabled()) return null;

        return [
            'info' => apcu_cache_info(true),
            'sma'  => apcu_sma_info(),
        ];
    }

    public function realpath(): array
    {
        return [
            'bytes' => realpath_cache_size(),
            'limit' => ini_get('realpath_cache_size'),
            'ttl'   => ini_get('realpath_cache_ttl'),
        ];
    }
}

Implementation Patterns

Artisan command for humans. php artisan cache:stats printing hit rate, wasted memory, free memory, restart counters. This is the direct port of what the bundle's console output gives a Symfony dev.

$s = $this->stats->opcache();
$this->table(['Metric', 'Value'], [
    ['Enabled',        $s['opcache_enabled'] ? 'yes' : 'no'],
    ['Hit rate',       $s['opcache_statistics']['opcache_hit_rate'].'%'],
    ['Cached scripts', $s['opcache_statistics']['num_cached_scripts']],
    ['Wasted memory',  $s['memory_usage']['wasted_memory']],
    ['OOM restarts',   $s['opcache_statistics']['oom_restarts']],
    ['Manual restarts',$s['opcache_statistics']['manual_restarts']],
]);

Health endpoint for scrapers. Expose a narrow JSON blob from a route behind auth or an internal-only middleware, then scrape it with Prometheus/Datadog. Keep it to numbers — never return opcache_get_status(true) or realpath_cache_get() output publicly; the script list is a filesystem map of your server.

Laravel Pulse card. If you already run Pulse, a custom card reading CacheStats is the idiomatic Laravel answer to what the bundle does with Symfony's profiler/toolbar. Same data, same polling cadence, no new infrastructure.

Scheduled baseline + alert. Schedule::call(...)->everyFiveMinutes() writing hit rate to a log channel or metrics store. Alert on deltas, not absolutes: a restart resets hits/misses, and oom_restarts incrementing is the single most actionable signal (your opcache.memory_consumption is too small for your codebase).

Octane. Under Octane the worker is long-lived, so opcache_get_status() reflects the real FPM-equivalent state and is genuinely useful. But never call opcache_reset() from a request or a queued job on a live pool — it invalidates every worker's compiled scripts at once. If you must, do it in a deploy step, not in application code.

Gotchas and Tips

  • SAPI separation is the big one. CLI PHP has its own OPCache and its own APCu segment. Running php artisan cache:stats shows nothing unless opcache.enable_cli=1 and apc.enable_cli=1. Most "the package is broken" reports are this. Your FPM numbers only come from an HTTP request.
  • Guard every function. opcache_get_status() emits a warning and returns false under opcache.restrict_api, and APCu functions are undefined when the extension isn't loaded. function_exists() + apcu_enabled() checks are not optional.
  • realpath_cache_get() is expensive on apps with tens of thousands of files — it materialises the whole map. Use only realpath_cache_size() in the hot path and compare it against realpath_cache_size ini (default 4096k is too low for a modern Laravel app with a fat vendor/).
  • Hit rate right after deploy is meaningless. OPCache restarts on deploy; you need a warmup window (or a warm-up request pass) before the percentage means anything. Same for APCu, which is empty on FPM pool restart.
  • APCu is per-pool, per-server, and not a Laravel cache driver. Laravel dropped the apc driver long ago. APCu is useful for local object caching and for config:cache-adjacent tricks, but it does not replace Redis for anything shared. Don't try to bridge it into Cache::store().
  • Memory accounting differs. apcu_sma_info()['avail_mem'] is free segment memory, apcu_cache_info()['mem_size'] is used-by-entries — they aren't complements, and expunges > 0 is your real "APCu is too small" alarm.
  • Info disclosure. The bundle's debug-toolbar orientation assumes a dev environment. In Laravel, gate any route behind can:viewCacheStats or restrict by IP; a public /cache-stats leaking absolute paths is a pentest finding.
  • Overlap with APM. New Relic, Datadog, and Blackfire already ship OPCache visibility. Check before adding a second source of truth — divergent dashboards are worse than none.
  • Bus factor. 10 stars, 0 dependents, single maintainer. Treat it as a reference implementation, not a dependency. Vendor the ~60 lines into app/Support/ and you get the same insight with zero upgrade risk and full control over what you expose.
  • Extension points, translated. Where the bundle expects Symfony's tagged collectors or a DataCollectorInterface, the Laravel equivalents are Pulse cards, a Manager-style class bound as a singleton, and a CacheStats facade for test fakes. Bind the class in a service provider so Http::fake()-style test doubles work.
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.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
cgv/localized-resource