tibisoft/wide-events-bundle 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

tibisoft/wide-events-bundle

最新稳定版本:0.0.4

Composer 安装命令:

composer require tibisoft/wide-events-bundle

包简介

Wide events (canonical log lines) for Symfony — one structured JSON event per request

README 文档

README

A Symfony bundle for wide events — also known as canonical log lines.

Instead of scattering dozens of log statements across your codebase, you emit one rich, structured JSON event per request. It gets built up progressively as the request moves through your application, then emitted in a single shot after the response is sent.

"Instead of logging what your code is doing, log what happened to this request."loggingsucks.com

Installation

composer require tibisoft/wide-events-bundle

Register the bundle in config/bundles.php:

return [
    // ...
    Tibisoft\WideEventsBundle\WideEventsBundle::class => ['all' => true],
];

Configuration

Create config/packages/wide_events.yaml:

wide_events:
    service_name: '%env(APP_NAME)%'   # added to every event
    service_version: '1.0.0'          # optional
    emitter: stdout                   # stdout | monolog | null
    sampler: tail                     # tail | always
    tail_sampler:
        slow_threshold_ms: 1000       # requests slower than this are always emitted
        default_rate: 0.05            # 5% of fast, successful requests are emitted

Emitters

Value Behaviour
stdout Writes one JSON line to stdout — ideal for containerised environments
monolog Passes the event to Monolog as a structured context array
null Discards everything — useful in test environments

Samplers

Value Behaviour
tail Retains 100% of errors (4xx/5xx), 100% of slow requests, and a random sample of everything else
always Retains every single event — useful during development

What you get for free

Every event is automatically seeded with the following fields on each request:

Field Source
timestamp RFC 3339 with milliseconds
request_id X-Request-Id / X-Correlation-Id header, or a generated hex ID
service.name From config
service.version From config (if set)
http.method Request method
http.path Request path
http.user_agent User-Agent header
http.client_ip Client IP
http.status_code Response status code
duration_ms Total request duration in milliseconds
error.class Exception class (only when an exception occurs)
error.message Exception message (only when an exception occurs)
error.code Exception code (only when an exception occurs)

Adding your own context

Inject WideEventStore anywhere in your application and call set():

use Tibisoft\WideEventsBundle\WideEventStore;

final class CheckoutController
{
    public function __construct(private readonly WideEventStore $wideEvents) {}

    public function checkout(Order $order, User $user): Response
    {
        $this->wideEvents->current()
            ?->set('user.id', $user->getId())
            ->set('user.tier', $user->getSubscriptionTier())
            ->set('order.id', $order->getId())
            ->set('order.total', $order->getTotal())
            ->set('order.item_count', $order->getItemCount());

        // ... handle the request
    }
}

You can call set() from any service, at any point during the request. Everything lands in the same event.

Enrichers

For context that should be added to every event (e.g. the authenticated user), implement EnricherInterface. It is called automatically just before the event is emitted.

use Tibisoft\WideEventsBundle\Contract\EnricherInterface;
use Tibisoft\WideEventsBundle\WideEvent;

final class AuthenticatedUserEnricher implements EnricherInterface
{
    public function __construct(
        private readonly Security $security,
    ) {}

    public function enrich(WideEvent $event): void
    {
        $user = $this->security->getUser();
        if ($user === null) {
            return;
        }

        $event
            ->set('user.id', $user->getId())
            ->set('user.email', $user->getUserIdentifier());
    }
}

With Symfony's autoconfigure enabled (the default), this is all you need — the bundle automatically picks up any service implementing EnricherInterface via the wide_events.enricher tag.

Example output

A single request to POST /checkout might produce this event:

{
    "timestamp": "2026-04-16T14:23:01.847+00:00",
    "request_id": "a3f8c2d19e4b",
    "service.name": "shop-api",
    "service.version": "3.12.0",
    "http.method": "POST",
    "http.path": "/checkout",
    "http.user_agent": "Mozilla/5.0",
    "http.client_ip": "93.184.216.34",
    "http.status_code": 200,
    "duration_ms": 142.5,
    "user.id": 8821,
    "user.email": "alice@example.com",
    "user.tier": "premium",
    "order.id": "ord_9f3a",
    "order.total": 129.99,
    "order.item_count": 3,
    "payment.method": "card",
    "payment.last4": "4242",
    "feature.new_checkout": true
}

One event. Everything you need to debug, audit, or analyse — no log archaeology required.

Tail sampling

Wide events can generate a lot of data. The built-in tail sampler helps keep costs under control by making retention decisions after the request completes, when you have full context:

  • Always retain requests with 4xx or 5xx status codes
  • Always retain requests that exceed slow_threshold_ms
  • Randomly sample everything else at default_rate (default 5%)

This means you never miss an error or a slow request, while routine successful traffic is sampled down significantly.

Extending

You can swap out any part of the bundle by implementing the relevant interface and binding it in your container:

Interface Purpose
EmitterInterface Controls how/where the event is written
SamplerInterface Controls which events are retained
EnricherInterface Adds fields to every event before emit

统计信息

  • 总下载量: 9
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 8
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-04-16

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固