Download the PHP package herdwatch-oss/monolog-ecs-formatter without Composer

On this page you can find all versions of the php package herdwatch-oss/monolog-ecs-formatter. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package monolog-ecs-formatter

herdwatch-oss/monolog-ecs-formatter

A Monolog formatter and Symfony bundle that promotes typed ECS value objects from a log's context to top-level ECS-aligned JSON fields, for clean Elasticsearch mapping.

You log structured data as small typed objects — Metrics, Labels, Text, Tags, Service, User, Tracing, EcsError, or any of your own — and the formatter lifts them to the correct ECS location with key validation, per-namespace caps, and a never-drop guarantee. The JSON type of each value is fixed by the object's method signatures, so there is no guesswork or formatter-side coercion.

Installation

Register the bundle in config/bundles.php:

Configuration

Create config/packages/monolog_ecs_formatter.yaml:

Passing fields

Fields are detected by instanceof, not by array key — so the key is irrelevant. Pass them positionally (cleanest) or under any key; both work, and ordinary context entries flow through untouched:

Multiple bags of the same kind merge. EcsField objects are detected in both context and extra (context wins on a conflict) — this is how the identity processor's injected Service object gets promoted. Anything that is not an EcsField is left alone: non-field context goes under a leftover context object, and extra is emitted verbatim.

Recommended usage

Pass field objects positionally, without a key. The key is ignored for routing anyway, so a key is redundant and misleading; positional also reads cleanly and lets multiple fields merge:

Reserve string keys for the two cases where the key genuinely matters:

Governed namespaces (bags)

Bag ECS field Value typing Cap
Metrics metric.* count()/total() → int, gauge() → float, flag() → bool 8 keys
Labels labels.* scalars coerced to string 8 keys
Text text.* strings 2 keys
Tags tags de-duplicated keyword strings 8

Keys must match /^[a-z][a-z0-9]*(_[a-z][a-z0-9]*){0,2}$/ (lower snake_case, ≤ 3 segments).

Nothing is ever dropped. A key that fails validation or exceeds the cap is demoted into the leftover context with a dotted key — e.g. Labels::create()->add('Bad Key', 'x') ends up as "context": {"labels.Bad Key": "x"}. This is identical in both modes; the mode only governs the legacy base keys (see Modes).

Building a bag from an array

When you already hold an array (config-driven logging, generic middleware), use the fromArray() factories — values still go through the bag's typing/validation:

Identity fields

Object ECS fields
Service service.name, service.language (default php), and optional version, environment, node.name
User user.id, name, email, domain, full_name, hash (null fields omitted)
Tracing trace.id, transaction.id — for logs ↔ APM correlation
EcsError error.type (class), message, stack_trace (includes throw-site file:line + previous-exception chain); error.code only when non-zero

Standard ECS context fields

Bundled value objects for common runtime / request / host fields, so each service doesn't hand-roll them. All take named constructor arguments and omit null fields.

Object ECS fields
Http http.request.{method,body.bytes,mime_type}, http.response.{status_code,body.bytes,mime_type} — request/response nest, so separate Http objects deep-merge
Process process.pid, process.command_line, process.name
Client client.ip, client.port
UserAgent user_agent.original, user_agent.version, user_agent.device.name
Host host.name, host.ip
Event event.action, event.start/event.end, event.duration (nanoseconds), event.sequence (monotonic ordering number), event.outcome (the EventOutcome enum: success/failure/unknown), event.reason (short, low-cardinality reason for the outcome, e.g. timeout), event.type/event.category (the EventType/EventCategory closed-set enums, emitted as de-duplicated arrays), event.url (link to an external system to continue investigation) — merged additively onto the base event object; it cannot override event.kind/dataset/etc.
Url url.full, url.scheme, url.domain, url.port, url.path, url.query, url.fragment — pass parts by name, or use Url::parse($url) to split a URL string
Network network.direction (the NetworkDirection closed-set enum: inbound, outbound, ingress, egress, internal, external, unknown) — e.g. outbound on HTTP-client telemetry, inbound on request logging

Url records the URL faithfully — url.full/url.query keep whatever you pass, including any embedded credentials or query tokens/PII. Redaction is the application's job: sanitise the URL before logging it, or strip sensitive fields in a Monolog processor.

The EventOutcome / EventType / EventCategory enums encode the ECS 8.11 allowed-value sets — the schema this formatter targets. Newer ECS releases extend these sets additively (e.g. the api and email categories didn't exist in ECS 8.0); setting a newer ecs_version in config only changes the advertised ecs.version string — new enum cases arrive with library updates.

Project-specific fields

Any class implementing EcsField is detected automatically — no registration, no formatter change. EcsField extends JsonSerializable; use SerializesToEcs to satisfy it (it maps jsonSerialize() to toEcs()):

Rules that keep this safe:

Serialisation under other handlers. Because EcsField is JsonSerializable, the same object also serialises to its ECS data under a non-ECS formatter/handler (a JSON handler emits the bare fragment; a line-based one wraps it under the class name) instead of an empty {}. That path is raw toEcs() — the validation, caps and never-drop demotion above are applied only by EcsFieldsFormatter, which pulls the objects out before normalising. If a non-ECS handler needs the governed, promoted form, point it at EcsFieldsFormatter too.

To apply a custom field to every record, inject it from a Monolog processor (the pattern the bundled identity processor uses).

ECS base fields emitted on every record

Field Value
@timestamp record datetime, ISO-8601 with microseconds
log.level lowercased level name (dotted top-level key, per the ecs-logging spec)
message log message
ecs.version configurable; defaults to 8.11.0 (the ECS schema this formatter's fields conform to — bump it if you emit fields from a newer ECS version)
log.logger channel name
event.kind / module / dataset event / symfony / symfony.logs
event.severity Monolog level integer

event.created is deliberately not emitted: per ECS it is the agent's/pipeline's read time (the record's own time is @timestamp; datastore arrival is event.ingested, typically set by an ingest pipeline).

Exceptions

A \Throwable at context['exception'] (the Monolog convention) is promoted to error.* by the formatter automatically — no processor or configuration required. So existing $log->error($msg, ['exception' => $e]) call sites get error.{type,message,code,stack_trace} for free. The consumed exception is then removed from the leftover context (in both modes — it now lives, typed, under error.*). An explicit new EcsError($e) always takes precedence.

Service identity processor (service.*)

When service_name is configured, EcsIdentityProcessor is registered as a global Monolog processor and injects a Service object into every record, which the formatter promotes to service.*. Omitting service_name disables it. The processor does not handle exceptions — that is the formatter's job (see above).

The optional service_version and service_environment keys ride along on that injected Service, so every record carries service.version and service.environment (bind them to %env(APP_VERSION)% / %env(APP_ENV)% to track deploys per environment). Both require service_name — setting either without it is a configuration error. A Service set explicitly at the call site still wins (the processor only fills the gap).

Modes

The mode controls one thing only: whether the legacy Monolog top-level keys (channel, level_name, level, datetime) are emitted alongside the ECS fields. Promotion of ECS fields and the never-drop handling of un-promotable entries are identical in both modes.

copy (default)

ECS fields are promoted to top-level and the legacy top-level keys (channel, level_name, level, datetime) are kept. This is the default because the bundle is normally installed into an existing application: dashboards still querying the old keys keep working while you migrate them to the ECS fields (log.logger, log.level, event.severity, @timestamp).

move

The clean ECS-only shape: ECS fields are promoted to top-level, everything else stays under context/extra, and no legacy top-level keys are emitted. Switch to move once nothing depends on the legacy keys — the duplicated base keys in copy cost storage and can muddy your Elasticsearch mapping.

Wiring the formatter in monolog.yaml

For service-type handlers wired in services.yaml:

Test command

In dev/test environments the bundle registers a console command that emits sample records covering every field type, the governance rules, and a custom EcsField:

License

Released under the MIT License. Copyright © Herdwatch.


All versions of monolog-ecs-formatter with dependencies

PHP Build Version
Package Version
Requires php Version >=8.3
monolog/monolog Version ^3.0
psr/log Version ^3.0
symfony/config Version ^7.0
symfony/console Version ^7.0
symfony/dependency-injection Version ^7.0
symfony/http-kernel Version ^7.0
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package herdwatch-oss/monolog-ecs-formatter contains the following files

Loading the files please wait ...