glesys/butler-audit

Glesys Butler Audit 包。

v0.8.0 2024-05-28 12:40 UTC

README

🚧 尚未准备用于生产。

Butler Audit

Laravel 包,用于将审计事件发送到远程端点。

示例

audit($user)->subscribed(['months' => 12]);
POST /log HTTP/1.1
Host: example.local
Accept: application/json
Content-Type: application/json
Authorization: Bearer secret

{
    "correlationId": "d9afea6a-14ed-4777-ae2f-a4d8baf4d5b7",
    "correlationTrail": "Mv9Jd6VM:GaIngT2j",
    "entities": [
        {
            "type": "user",
            "identifier": 1
        }
    ],
    "event": "user.subscribed",
    "eventContext": [
        {
            "key": "months",
            "value": 12
        }
    ],
    "initiator": "service-a",
    "occurredAt": 1600432185
}

入门

composer require glesys/butler-audit
php artisan vendor:publish --provider="Butler\Audit\ServiceProvider" --tag=config

配置

BUTLER_AUDIT_DRIVER=http
BUTLER_AUDIT_URL=https://example.local/log
BUTLER_AUDIT_TOKEN=secret

确保您已配置了一个 队列 以加快您的应用程序。

日志驱动程序

在开发过程中,您可以使用日志驱动程序来防止发送 HTTP 请求。

BUTLER_AUDIT_DRIVER=log

发起者解析器

ServiceProvider 中注册了一个默认的 "initiator resolver"。

您的应用程序可以有自己的解析器以避免为每次审计调用手动设置发起者。您仍然可以使用 initiator()initiatorContext() 来覆盖解析器设置的值。

Auditor::initiatorResolver(fn () => [
    auth()->id(),
    [
        'ip' => request()->ip(),
        'userAgent' => request()->userAgent(),
    ]
]);

您可以通过将 butler.audit.default_initiator_resolver 设置为 false 来禁用默认解析器。

可审计的

您可以将 "Auditables" 传递给辅助方法。

class Car extends Fluent implements Auditable
{
    public function auditorType(): string
    {
        return $this->type;
    }

    public function auditorIdentifier()
    {
        return $this->id;
    }
}

$car = new Car(['id' => 1, 'type' => 'volvo']);

audit($car)->started(); // equivalent to audit(['volvo', 1])->started();

Eloquent 模型特质

为了方便,有一个 IsAuditable 特质可以用于 eloquent 模型。

class User extends Model implements Auditable
{
    use IsAuditable;
}

$user = User::find(1);

audit($user)->subscribed(); // equivalent to audit(['user', 1])->subscribed();

X-Correlation-ID

我们使用 "X-Correlation-ID" 标头来 "关联" 审计。

"X-Correlation-Trail" 标头也用于确定事件的顺序,而不依赖于事件的 occured_at,请参阅下面的示例 json。

Http 客户端宏

使用 "withCorrelation" 宏在发送请求时添加 "X-Correlation-ID" 标头。

在下面的示例中,所有 "audits" 将具有相同的关联-id。

// Service A
audit($user)->signedUp();
Http::withCorrelation()->post('https://service-b.example/welcome-email', $user);

// Service B
audit($user)->welcomed();
Http::withCorrelation()->post('https://service-c.example/notify-staff');

// Service C
audit($employee)->notified();

发送到您配置的 BUTLER_AUDIT_URL 的请求将类似于以下内容

{
    "initiator": "api",
    "event": "user.signedUp",
    "correlationId": "92a55a99-82c1-4129-a587-96006f6aac82",
    "correlationTrail": null
}

{
    "initiator": "service-a",
    "event": "user.welcomed",
    "correlationId": "92a55a99-82c1-4129-a587-96006f6aac82",
    "correlationTrail": "Mv9Jd6VM"
}

{
    "initiator": "service-b",
    "event": "employee.notified",
    "correlationId": "92a55a99-82c1-4129-a587-96006f6aac82",
    "correlationTrail": "Mv9Jd6VM:GaIngT2j"
}

队列作业

可以在需要与请求相同的关联 id 的可队列作业上使用 WithCorrelation 特质。

工作原理

  1. 使用 WithCorrelation 特质的作业被调度到队列。
  2. 我们的 Dispatcher 将在作业上设置一个 correlationId 属性。
  3. 作业由工作进程处理。
  4. 中间件 SetCorrelation 将告诉 Auditor 使用作业中的关联 id。

可以通过将 butler.audit.extend_bus_dispatcher 设置为 false 来禁用扩展调度器。

Auditor 假设

您不需要在测试中模拟队列(例如,使用 Queue::assertPushed(function (AuditJob) {})),而是可以模拟请求,如下所示。

public function test_welcome_user()
{
    Auditor::fake();

    // Assert that nothing was logged...
    Auditor::nothingLogged();

    // Perform user welcoming...

    // Assert 1 event was logged...
    Auditor::assertLoggedCount(1);

    // Assert a event was logged...
    Auditor::assertLogged('user.welcomed');

    // Assert a event with context, initiator and entity was logged...
    Auditor::assertLogged('user.welcomed', fn (AuditData $audit)
        => $audit->initiator === 'service-a'
        && $audit->hasEntity('user', 1)
        && $audit->hasEventContext('months', 12)
    );
}

测试

vendor/bin/phpunit
vendor/bin/pint --test

如何贡献

开发在 GitHub 上进行;欢迎任何使用 Pull Requests 的典型工作流程。同样地,我们使用 GitHub 问题跟踪器来处理所有报告(无论报告的性质、功能请求、错误等)。

所有更改都应通过单元测试进行覆盖,如果测试不可能或非常不实际,则需要在 pull 请求的评论部分进行讨论。

代码规范

由于这个库是为Laravel应用程序设计的,我们鼓励遵循上游Laravel实践的代码标准——简而言之,这意味着要遵循PSR-2PSR-4