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

Metric Bundle Laravel Package

mtxserv/metric-bundle

A Symfony bundle for collecting and exposing application metrics, giving developers a simple way to instrument services and report usage data within their projects.

View on GitHub
Deep Wiki
Context7

Getting Started

Know what you're actually installing. mtxserv/metric-bundle is a Symfony2 bundle (circa Symfony 2.7/2.8), not a Laravel package. It has no service provider, no facade, no config publishing, and no extra.laravel block. Dropping composer require mtxserv/metric-bundle into a Laravel app will pull Symfony2-era constraints into your dependency graph and still leave you with a bundle that never boots. Treat this as a reference implementation to read, not a dependency to install.

If you want it running in its native habitat (for comparison or a legacy port), the Symfony2 flow is:

// app/AppKernel.php
$bundles = [ /* ... */ new Mtxserv\MetricBundle\MtxservMetricBundle() ];

// app/config/config.yml
mtxserv_metric:
    host: 127.0.0.1
    port: 8086
    database: app_metrics
    # username/password if your InfluxDB has auth enabled

Where to look first, in this order:

  1. DependencyInjection/Configuration.php — the real config surface. Whatever keys exist here is what the bundle supports; the README (if any) is usually stale.
  2. DependencyInjection/*Extension.php — tells you the service IDs, the parameter names (mtxserv_metric.host, etc.), and which class actually talks to InfluxDB.
  3. Resources/config/services.yml — the wiring. Note the service ID; you'll inject that, never the raw client.
  4. Service/ (or Client//Metrics/) — the public methods. This is the only API that matters. Everything else is ceremony.

Your first use case in Laravel. The bundle does exactly one job: build a measurement + tags + fields payload and POST it to /write. Reproduce that as one small class bound in a service provider, using influxdb/influxdb-php (the same client the bundle wraps) or a plain Guzzle call:

// app/Services/Metrics.php
final class Metrics
{
    public function __construct(private Client $influx, private string $db) {}

    public function timing(string $measurement, float $ms, array $tags = []): void
    {
        $this->influx->writePoints([new Point($measurement, $ms, $tags)], Precision::MILLISECOND);
    }
}

// app/Providers/MetricsServiceProvider.php
$this->app->singleton(Metrics::class, fn () => new Metrics(
    new Client(config('metrics.host'), config('metrics.port')),
    config('metrics.database'),
));

That is a 30-line replacement for the entire bundle. Do that first, then decide whether you need anything more.

Implementation Patterns

Inject the writer, don't reach for it. In Symfony2 you'd inject @mtxserv_metric.* into a controller or listener. In Laravel, inject Metrics into the constructor of whatever needs it (job, listener, middleware). Calling app(Metrics::class) inside a loop is the fastest way to make this untestable.

Separate measurement from dimensions. The bundle's model — measurement name, tags, fields — maps cleanly onto a naming convention you should set on day one:

  • measurement = the verb/thing being counted: http_request, queue_job, login.
  • tags = low-cardinality dimensions you will filter or group by: env, route_name (not raw URI), status (not raw code), queue, job_class.
  • fields = the numbers: duration_ms, count, bytes.

Never put a user ID, a request ID, a raw URL, or an exception message in a tag. That is the single most common way to kill an InfluxDB instance (see Gotchas).

Instrument at request boundaries, flush after the response. Laravel middleware with terminate() is the natural analogue of the Symfony2 kernel listener the bundle is usually paired with:

public function handle($request, Closure $next) {
    $start = hrtime(true);
    $response = $next($request);
    $response->headers->set('X-Start', (string) $start); // or stash on a scoped instance
    return $response;
}

public function terminate($request, $response) {
    $this->metrics->timing('http_request', (hrtime(true) - $start) / 1e6, [
        'env'    => app()->environment(),
        'status' => $response->getStatusCode(),
    ]);
}

The point of terminate() is that the client never waits on the write. Keep it that way.

Buffer per request, write once. If you emit a metric from five places during a request, five HTTP round-trips is five chances to add latency. Accumulate Point objects in the singleton and flush as a single batch in terminate() or in a finally block of the outermost handler. The 2016-era client had no batching layer worth the name; you'll be adding it yourself.

Decouple writes from business logic. For anything that isn't request-scoped — "user imported 400 rows", "invoice generated" — dispatch a queued job or a domain listener that writes the metric. Metrics are observability, not a transaction participant; they should never roll back a real operation or appear in a try/catch that changes control flow.

Keep the Symfony2 idioms straight if you do port it. A 2016 bundle uses arguments: ["%mtxserv_metric.host%"], explicit service IDs, and constructor injection via @service_id. Modern Symfony autowiring won't touch any of it, and Laravel's container won't see it at all. If you're copying code, copy the class, rewrite the wiring.

Test with a recording double. Bind a fake Metrics implementation in tests/TestCase.php that appends to a public array, and assert on measurement/tags/fields. You get fast assertions and never touch a network in CI. This is far easier with a hand-written class than with the bundle's container-coupled service.

Gotchas and Tips

The package is archived and last released 2016-01-22. That release predates InfluxDB 2.x entirely. InfluxDB 2.x replaced /write?db= with /api/v2/write?org=&bucket= and token auth; InfluxDB 3.x moved again. The bundle will speak to InfluxDB 1.x and nothing newer. If your target is InfluxDB 2+, this code is not a starting point — the wire format is different and you're better off with a current client or OTLP.

Zero stars, zero dependents means zero eyes. Read every line of the service class before trusting it. Expect no retries, no timeouts, no batching, and probably @ suppression or swallowed exceptions somewhere. There is no maintainer to file an issue with.

Failures must not reach the user. The single worst pattern is a metrics write inside a request path that throws when InfluxDB is down or slow. Wrap every write in try { } catch (\Throwable $e) { report/log at debug level }. Metrics are optional infrastructure; the application is not.

Set connect and read timeouts explicitly. The client defaults can be generous. A blocked socket to an unreachable InfluxDB will stall a PHP-FPM worker for the full timeout, and under load you'll exhaust the pool. Two seconds, not thirty.

Timestamp precision is a landmine. InfluxDB defaults to nanosecond precision. Passing time() (seconds) without precision=s writes your data to 1970 and it vanishes from any sane query window. Always pass precision explicitly and always use a monotonic clock for durations (hrtime(true)), never microtime() deltas across a suspend.

Tag cardinality is the failure mode that doesn't announce itself. Adding user_id or request_id as a tag feels harmless in dev and then blows up series cardinality in production — InfluxDB keeps an index entry per unique tag set, memory climbs, and writes eventually fail with max-series-per-database. Enforce a rule: tags are enumerable values only. If you'd need a GROUP BY on the distinct count of it, it isn't a tag.

Silent data loss. Failed writes that are caught and logged at debug are indistinguishable from "no traffic". During rollout, verify with a direct curl against the write endpoint and a SELECT count(*) on the measurement — don't trust that the absence of errors means the pipeline works.

Debug by logging line protocol. When a point doesn't land, the payload is the artifact: print the exact line (measurement,tag=v field=1 <ts>) and compare it to InfluxDB's line protocol rules. Common culprits are unescaped commas/spaces in tag values, a field sent as a string when it's later queried numerically, and a missing field entirely (a point with no fields is rejected).

Extension points are thin, so extend by replacement. The bundle exposes a client service and a handful of write methods; there's no event dispatcher, no formatter interface, no sampler. Don't subclass it — write your own thin writer and keep the measurement/tag/field contract. That's also your migration path off it when you move to OpenTelemetry or a hosted metrics backend.

Check the license before copying source into your app. With an abandoned package, vendoring the class is often the pragmatic move, but confirm the license text in the repo first — it's not a given that it's MIT.

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