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

Ecs Logging Laravel Package

elastic/ecs-logging

ECS Logging for PHP transforms application logs into structured logs that comply with Elastic Common Schema. Supports Monolog 3, works with Filebeat, Elasticsearch, and Kibana, and helps correlate logs with APM traces for better observability.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit

elastic/ecs-logging is not a logging framework — it is a Monolog formatter (plus a small set of ECS type/value objects: Error, Service, User, Tracing). That is architecturally attractive for Laravel: Laravel already uses Monolog internally, so this package slots in as a rendering concern at the edge of the existing logging stack rather than requiring a replacement of Illuminate\Log. There is no transport, no agent, no daemon, and no Elasticsearch client bundled — which keeps coupling low and means an exit to a different shipper (Vector, Fluent Bit, OTel Collector) remains viable if the JSON is ECS-compliant.

The consequence of being formatter-only is that the package delivers half of an observability pipeline. The other half — Filebeat filestream input with parsers.ndjson (overwrite_keys, add_error_key, expand_keys) or the equivalent Kubernetes/Docker autodiscover annotations — is documented but must be built and owned by us. That is genuinely more work than a composer require.

Integration feasibility

Feasible with low engineering effort. The likely shape in Laravel is a dedicated channel in config/logging.php with a StreamHandler/RotatingFileHandler (or php://stderr for containerized deploys) and a formatter key pointing at Elastic\Monolog\Formatter\ElasticCommonSchemaFormatter. Context enrichment maps cleanly onto Laravel's existing Log::withContext() and per-call context arrays, since the formatter passes through additional keys — service, user, and trace context can therefore be populated from middleware (request ID, tenant ID, authenticated user, APM trace ID) without touching call sites.

Two feasibility caveats. First, the formatter is instantiated by the container from config, so any constructor arguments (service name/version, ECS version) need an explicit binding or a formatter_with-style config; this must be validated before promising a "config-only" rollout. Second, the documented context pattern uses typed objects (EcsError, Service, User, Tracing) rather than plain arrays — this is a developer-ergonomics decision, not a technical blocker, but it means either adopting those classes or writing thin wrappers.

Technical risk

  • Documentation contradiction (highest immediate risk). The README states Monolog 3.x only and shows Elastic\Monolog\Formatter\ElasticCommonSchemaFormatter; docs/reference/setup.md states Monolog v2.* only and shows Elastic\Monolog\v2\Formatter\ElasticCommonSchemaFormatter. Both namespaces appear to exist for historical reasons, but the guidance is contradictory. Which class is current, and which Monolog major is supported on our Laravel version, must be resolved from source, not docs, before commitment.
  • Adoption signal is near-zero. 21 stars, 0 dependents. There is no internal precedent to leverage and no meaningful ecosystem of blog posts, Stack Overflow answers, or Laravel-specific recipes. Every integration decision is ours to validate.
  • ECS schema drift. Shipped examples emit ecs.version: 1.2.0. Elasticsearch index templates, Kibana Logs views, and downstream detections expect a specific ECS major; a formatter pinned to an old ECS version can silently produce fields that don't match current mappings.
  • Vendor gravity despite Apache-2.0. The license is permissive and the output is plain JSON, so lock-in is low in principle. In practice, the documented ingestion path, the logs-* data views, and the trace-correlation story all assume the Elastic stack. If our log backend is Datadog or Splunk, the package still delivers value (ECS-shaped JSON is a reasonable neutral schema) but the documentation stops being useful.
  • PII exposure. User::setEmail() and arbitrary context passthrough make it easy to write emails, tokens, or request bodies into structured, indexed, retained storage. User::setHash() exists for obfuscation but is opt-in. This is a compliance surface, not a bug.

Key questions

  1. Do we target Elasticsearch/Kibana as the log backend, or is ECS being adopted purely as a neutral structured-log schema? This changes the scope by roughly 2x.
  2. Which Monolog major and which formatter namespace is authoritative for our Laravel version, and is that verified against the released tags rather than the docs?
  3. What ECS version does the current release emit, and does it match the index template/mappings we would deploy?
  4. Who owns the Filebeat/collector configuration and the index templates — application teams or platform engineering?
  5. Do we need trace-to-log correlation now? If APM is on the roadmap, adopting ECS logging early avoids a second migration; if not, this is a smaller, purely structural change.
  6. What is the retention/cost tolerance for JSON logs that are materially larger per line than our current line-formatted output?

Integration Approach

Stack fit

Good fit for a Laravel 10/11 + PHP 8.1+ estate. Laravel's LogManager already builds Monolog handlers per channel, and the formatter config key gives a zero-code injection point. php://stderr + Filebeat as a sidecar/DaemonSet is the cleanest target for containerized deployments; RotatingFileHandler + Filebeat filestream is the fallback for VM/bare-metal.

Migration path

Incremental, channel-by-channel, with no big-bang cutover:

  1. Spike (days). One non-critical service, one new ecs channel, verify emitted JSON against the ECS logging spec and confirm the formatter namespace/monolog version.
  2. Ingestion proof (days). Stand up Filebeat with ndjson + expand_keys + overwrite_keys + add_error_key, confirm dotted keys (log.level, trace.id) expand into the expected hierarchy and map cleanly.
  3. Dual-write. Keep the existing human-readable channel alongside the new JSON channel for one release cycle. This de-risks the transition and preserves grep-ability for on-call during ramp.
  4. Enrichment. Add request-scoped context via middleware: service.name/service.version (from config), trace.id (from APM agent if present), user.id (hashed), labels.environment/tenant.id.
  5. Cut over and template. Remove the legacy channel, publish a shared logging config stub (or a small internal package) so the pattern is copy-paste for the rest of the estate.

Compatibility

The formatter is a leaf dependency with no Elasticsearch client requirement, so it will not conflict with our existing PSR-3/Monolog stack. The only hard constraint is the Monolog major. Verify composer why monolog/monolog across the estate before standardizing — a mixed Monolog 2/3 fleet means two formatter namespaces in play, which is a support cost, not a blocker.

Sequencing

Schema convention and PII policy must land before the pilot, not after — retrofitting redaction onto shipped logs is expensive. Ingestion (step 2) must precede any volume, because unstructured JSON landing in Elasticsearch without expand_keys produces unusable indices and a reindex. Trace correlation should be sequenced after structured logging is stable, since it depends on an APM agent being present.


Operational Impact

Maintenance

Low and favorably shaped. Apache-2.0, formatter-only, no runtime agent, no network calls, no state. Version upgrades are composer update and a regenerated lock file. The real maintenance burden is not the package — it is the Filebeat/collector config, the index templates, and the field convention, all of which we now own. Budget platform-engineering time for those, not application-engineering time.

Counterweight: low release cadence and a small maintainer pool (Elastic's APM team). Patch latency for a JSON-escaping or timestamp bug could be measured in months. Mitigation is trivial here — the formatter is small enough that a fork-and-patch is a realistic fallback, which materially de-risks the low-activity signal.

Support

Upstream support is documentation plus GitHub issues; there is no SLA and adoption is thin enough that community answers will be scarce. Internal support load will concentrate in one or two engineers who build the pilot. Expect to answer "why is my log line broken JSON" questions during ramp — the add_error_key Filebeat setting exists precisely for that and should be enabled from day one.

Scaling

Cost and throughput both move in the wrong direction relative to plain text logs. Per-line JSON with a fixed envelope (@timestamp, ecs.version, log.logger, log.level) is meaningfully larger, and json_encode per record adds measurable CPU at high log volume. For high-throughput services, this argues for: raising log thresholds (this package is a strong forcing function for reducing INFO-level noise), sampling, and async/buffered handlers. Log storage cost should be modeled, not assumed — structured logs also make retention tiers and field-level exclusion possible, which can offset the size increase.

Failure modes

  • Silent unparseability. A context value that is not JSON-encodable (a resource, closure, or object without JsonSerializable) can produce a broken or truncated line. Downstream, one bad line per request can drop that event entirely. The EcsError/EcsThrowable wrappers exist to handle the most common case (exceptions) — they should be mandatory in error-path review.
  • Dotted-key collisions. Context keys like log or message can collide with the ECS envelope. Whether the formatter sanitizes or overwrites is worth an explicit test; the release notes mention label-key sanitization, implying this class of bug has occurred before.
  • Ingestion misconfiguration. Without expand_keys, log.level lands as a literal dotted field name and breaks every Kibana query written against log.level. This is a deploy-time failure with no runtime error — it surfaces as an empty dashboard.
  • Timestamp/timezone drift. Release 1.0.2 fixed timezone inclusion in @timestamp; older pins or forks may not have it. Verify UTC with explicit offset in emitted output.
  • PII leakage. Structured, indexed, retained user context is a durable compliance exposure. Redaction must be enforced in the shared middleware, not left to individual developers.

Ramp-up

Developer ramp-up is genuinely low — one config block, one middleware, one shared package. Half a day per team. The asymmetric cost is on the operations side: Filebeat configuration, index templates, data views, and field-convention governance represent a multi-week platform investment that must be funded separately. The honest TPM framing is that this package is a small application change that implies a medium-sized observability platform commitment — and the decision to proceed should be justified by the platform investment, not by the 21-star composer package.

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.
steadrun/laravel-monitor
labyrinthe/connect-laravel
elmogy/layan
drewdan/sentinel-client
dskripchenko/laravel-llm
fatryst/nuonuo
stevenay/myanfont
gmostafa/php-graphql-client
xeviant/paystack
snowsoft/faker
meditationsteps/blogetc
animalyoung/laravel-influxdb
onix-solutions/sms-telera
lonely-lights/prosetta
oxygen/data
oxygen/core
jengo/base
xiloryx/log-collector
a21ns1g4ts/filament-stripe
la-php/laravel-admin