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

Monolog Ecs Formatter Laravel Package

herdwatch-oss/monolog-ecs-formatter

Monolog ECS Formatter outputs Elastic Common Schema compliant JSON from PHP and Laravel logs, making them easier to ship to Elasticsearch, Kibana, and other ECS-aware observability tools. A lightweight drop-in formatter for structured, searchable application logging.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit. Unchanged: the package sits at the Monolog formatter layer — below Laravel's LogManager, above the handler/transport — and Laravel's formatter + formatter_with keys on single, daily, or stack leaves still make this a config-only drop-in with no application code changes. The Symfony bundle half remains inert in Laravel (no extra.laravel provider), so the deliverable is still "one formatter class plus a config array."

What v0.2.1 changes is the shape of that deliverable. Adding a Network value object and a NetworkDirection closed-set enum moves the package from pure serialization toward a small typed payload API you are expected to construct and hand to the formatter. That is a modest expansion of the surface you must evaluate, fork, and keep current — but it is directionally meaningful: the package is accumulating modelling opinions, not just formatting them. Treat it as "a formatter plus a thin ECS vocabulary layer," and scope your review of future releases accordingly.

Integration feasibility. Still low-to-moderate, and v0.2.1 adds no new class of work — it adds one more field to the enrichment checklist. The formatter still does not enrich; populating service.*, trace.id, user.id, event.dataset, and now network.direction remains your responsibility via request-scoped Log::withContext and an Octane-safe lifecycle. network.direction is only worth emitting where the record actually has a network dimension: inbound from request middleware, outbound from an HTTP-client logging wrapper. Setting it on general application logs is noise. Budget unchanged at 2–5 dev-days for a vertical slice (add half a day if you standardize outbound HTTP-client telemetry), 2–3 weeks end to end.

Technical risk. Prior risks 1–7 stand. v0.2.1 adjusts two and adds three:

  1. Zero social proof — marginally softened. PR #3 from a second contributor is the first evidence of anyone other than the author touching the repo. It is not adoption: still no dependents, no production references, no CI badge worth citing. Supply-chain and bus-factor risk remain dominant; the mitigation is unchanged.
  2. Monolog major-version surface. Unchanged. Verify the FormatterInterface signature against your pinned Monolog 3 LogRecord and cover with a contract test.
  3. ECS level vocabulary mismatch. Unchanged and still the defect most likely to reach production silently.
  4. @timestamp correctness. Unchanged. Confirm derivation from DateTimeImmutable under Octane and an overridden app timezone.
  5. Mapping fragility. Unchanged for labels/tags — and now directly relevant to the change: if you run your index template with dynamic: strict, the new network.direction field will be rejected until the template is updated. A patch-level package bump can therefore produce silent log gaps. Template-before-package is now a hard ordering rule, not a nicety.
  6. Copy-mode permanence. Unchanged. network.direction should not be added to the copy-mode duplicated-key set; copy mode covers only the legacy keys you are migrating off (channel, level_name, level, datetime).
  7. Logging-path failure. Unchanged, with a new trigger: a closed-set enum validates, and validation in the log path throws. If NetworkDirection raises on an unexpected value (a proxy-supplied direction, a typo, a string from context), that exception surfaces inside the request that was only trying to log. Confirm the failure behaviour and keep the WhatFailureGroupHandler + fallback channel guard.
  8. ECS version pinning divergence. NetworkDirection is pinned to ECS 8.11 while the formatter may still emit an older or absent ecs.version. A document declaring one version and using another is worse than one declaring none — consumers cannot trust field semantics.
  9. 0.x API churn. A new public value object in a patch release confirms that anything can change at any version. Pin exactly (0.2.1), do not float ^0.2, and re-review on every bump.

Key questions. Carried forward: Monolog 3 LogRecord signature and PHP range; what log.level receives for critical/alert/emergency; timezone-correct @timestamp; per-field vs. all-or-nothing copy mode; exception normalization into error.*; whether ecs.version is emitted; commit cadence and test coverage.

New for v0.2.1:

  • How is Network passed in — first-class formatter argument, or serialized from context/extra? Does the formatter recognize it automatically?
  • Does an invalid NetworkDirection throw, coerce, or drop the field? Where in the write path does that happen?
  • Does the release bump ecs.version to 8.11, or only the enum's vocabulary?
  • Is Network immutable, and does it carry more than direction (any source.*/destination.*/url.*)?
  • Are network.direction and any sibling fields documented with an explicit mapping (keyword, expected low cardinality)?
  • Any plan to add source.ip/destination.ip? That moves the package into PII territory and needs a retention decision before adoption.

Integration Approach

Stack fit. Unchanged: Laravel 10/11, PHP 8.1+, Monolog 3, a dedicated ecs channel composed into a stack alongside the legacy channel during cutover, NDJSON to stdout → collector → Elasticsearch. On OpenSearch, verify the ECS 8.11 field subset you actually use rather than assuming compatibility.

Migration path. Copy mode remains the bridge, not the destination, and the template still lands before the first document. Insert the new field into the sequence:

  1. Add the ecs channel via formatter + formatter_with; ship to a non-production index only.
  2. Land (or update) the index template before any package bump: explicit mappings for @timestamp, log.level, service.*, trace.id, labels (flattened), tags (keyword), and now network.direction (keyword) plus ILM. If you adopted dynamic: strict, this step gates the upgrade.
  3. Dual-write in production: stack → [daily legacy, ecs] for N weeks; reconcile with a count-and-field-sample diff job.
  4. Port Kibana saved objects and alerts to ECS field names; run both dashboard sets in parallel.
  5. Flip consumers, disable copy mode, delete the legacy channel.

Compatibility. Pin exactly (0.2.1), pin Monolog, run composer audit, and confirm no symfony/* or psr/log collisions. Skip registering the Symfony bundle. Keep mirroring the repo into your VCS or private Packagist under a branch alias — with a single small upstream, an archive or delete must not be able to break your build. Add network.direction to your field-convention doc so outbound HTTP telemetry is instrumented once, centrally, rather than ad hoc per client wrapper.

Sequencing. Week 1: spike plus contract tests covering one record per level, an exception record, a non-UTF8 context record, and a record carrying Network. Week 2: index template (including network.direction), ILM, dual-write in staging. Weeks 3–4: production dual-write and dashboard port. Week 5+: retire copy mode. Do not begin with production traffic; the failure mode throws inside the request path.

Operational Impact

Maintenance. Still effectively fork-and-own, with a slightly better signal: one external contributor and an active version line means upstream is alive enough to matter and volatile enough to require attention. Budget 1–2 days per quarter for upstream review — unchanged — and treat every 0.x bump as a re-review, not a patch. Keep a thin internal wrapper (subclass or small factory) so the escape hatch to a homegrown JsonFormatter extension stays a one-file change. That wrapper should also shield your call sites from Network/NetworkDirection API churn, which is now a live concern.

Support. No issue history, no community corpus, no vendor. Your runbook stays yours: "logs malformed," "logs missing," "documents rejected." Add the known-good sample document to CI as a schema contract test and regenerate it with each package bump — v0.2.1 is exactly the kind of release that silently changes the wire format.

Scaling. Unchanged: per-record cost is one json_encode plus normalization, dominated by I/O. Copy-mode index growth and labels cardinality remain the two real pressures. network.direction is a closed-set low-cardinality keyword — negligible index cost, no cardinality concern, provided it is mapped as keyword and never fed arbitrary user strings. Buffered handler with flush on terminate; explicit flush interval on queue workers where terminate is not guaranteed.

Failure modes.

  • Formatter throws on unserializable context → 500 on the request that was only logging. Mitigate with WhatFailureGroupHandler plus a fallback channel.
  • Enum validation throws on an unexpected direction value → same blast radius, new trigger. Verify and guard.
  • dynamic: strict template not updated for network.direction → rejected documents, silent log gaps, found during an incident.
  • Level vocabulary drift → severity dashboards quietly wrong after migration; no error surfaces.
  • Mapping conflict on labels or tags → rejected documents, silent gaps.
  • Timezone drift on @timestamp → out-of-order indices, ILM rollover surprises, broken correlation.
  • ecs.version declaring a version the document does not conform to → consumer trust erosion.
  • Copy mode never retired → permanent dual schema and two truths for severity.
  • Upstream abandonment or deletion → broken builds; mitigated by mirroring.
  • PII exposure via user.* and — if the network model grows to addresses — source.*/destination.*. Set retention on those fields explicitly rather than inheriting it from index ILM.

Ramp-up. Unchanged for an individual developer: config plus one page of convention docs, now including a line on when to set network.direction. Moderate for the team, because the hard work is the index template, cross-service field-naming conventions, and dashboard migration. One engineer ~2 days to be productive with the package, ~2–3 weeks to land the platform slice end to end.

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.
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route