timacdonald/log-fake 问题修复 & 功能扩展

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

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

timacdonald/log-fake

Composer 安装命令:

composer require --dev timacdonald/log-fake

包简介

A drop in fake logger for testing with the Laravel framework.

README 文档

README

Log Fake: a Laravel package by Tim MacDonald

Log fake for Laravel

A bunch of Laravel facades / services are able to be faked, such as the Dispatcher with Bus::fake(), to help with testing and assertions. This package gives you the ability to fake the logger in your app, and includes the ability to make assertions against channels, stacks, and a whole bunch more.

Installation

You can install using composer:

composer require timacdonald/log-fake --dev

Basic usage

use Illuminate\Support\Facades\Log;
use TiMacDonald\Log\LogEntry;
use TiMacDonald\Log\LogFake;

public function testItLogsWhenAUserAuthenticates()
{
    /*
     * Test setup.
     *
     * In the setup of your tests, you can call the following `bind` helper,
     * which will switch out the underlying log driver with the fake.
     */
    LogFake::bind();

    /*
     * Application implementation.
     *
     * In your application's implementation, you then utilise the logger, as you
     * normally would.
     */
    Log::info('User logged in.', ['user_id' => $user->id]);

    /*
     * Test assertions.
     *
     * Finally you can make assertions against the log channels, stacks, etc. to
     * ensure the expected logging occurred in your implementation.
     */
    Log::assertLogged(fn (LogEntry $log) =>
        $log->level === 'info'
        && $log->message === 'User logged in.' 
        && $log->context === ['user_id' => 5]
    );
}

Channels

If you are logging to a specific channel (i.e. not the default channel) in your app, you need to also prefix your assertions in the same manner.

public function testItLogsWhenAUserAuthenticates()
{
    // setup...
    LogFake::bind();

    // implementation...
    Log::channel('slack')->info('User logged in.', ['user_id' => $user->id]);

    // assertions...
    Log::channel('slack')->assertLogged(
        fn (LogEntry $log) => $log->message === 'User logged in.'
    );
}

Stacks

If you are logging to a stack in your app, like with channels, you will need to prefix your assertions. Note that the order of the stack does not matter.

public function testItLogsWhenAUserAuthenticates()
{
    // setup...
    LogFake::bind();

    // implementation...
    Log::stack(['stderr', 'single'])->info('User logged in.', ['user_id' => $user->id]);

    // assertions...
    Log::stack(['stderr', 'single'])->assertLogged(
        fn (LogEntry $log) => $log->message === 'User logged in.'
    );
}

That's it really. Now let's dig into the available assertions to improve your experience testing your applications logging.

Available assertions

Remember that all assertions are relative to the channel or stack as shown above.

assertLogged()

Assert that a log was created.

Can be called on

  • Facade base (default channel)
  • Channels
  • Stacks

Example tests

/*
 * implementation...
 */

Log::info('User logged in.');

/*
 * assertions...
 */

Log::assertLogged(
    fn (LogEntry $log) => $log->message === 'User logged in.'
); // ✅

Log::assertLogged(
    fn (LogEntry $log) => $log->level === 'critical'
); // ❌ as log had a level of `info`.

assertLoggedTimes()

Assert that a log was created a specific number of times.

Can be called on

  • Facade base (default channel)
  • Channels
  • Stacks

Example tests

/*
 * implementation...
 */

Log::info('Stripe request initiated.');

Log::info('Stripe request initiated.');

/*
 * assertions...
 */

Log::assertLoggedTimes(
    fn (LogEntry $log) => $log->message === 'Stripe request initiated.',
    2
); // ✅

Log::assertLoggedTimes(
    fn (LogEntry $log) => $log->message === 'Stripe request initiated.',
    99
); // ❌ as the log was created twice, not 99 times.

assertNotLogged()

Assert that a log was never created.

Can be called on

  • Facade base (default channel)
  • Channels
  • Stacks

Example tests

/*
 * implementation...
 */

Log::info('User logged in.');

/*
 * assertions...
 */

Log::assertNotLogged(
    fn (LogEntry $log) => $log->level === 'critical'
); // ✅

Log::assertNotLogged(
    fn (LogEntry $log) => $log->level === 'info'
); // ❌ as the level was `info`.

assertNothingLogged()

Assert that no logs were created.

Can be called on

  • Facade base (default channel)
  • Channels
  • Stacks

Example tests

/*
 * implementation...
 */

Log::channel('single')->info('User logged in.');

/*
 * assertions...
 */

Log::channel('stderr')->assertNothingLogged(); // ✅

Log::channel('single')->assertNothingLogged(); // ❌ as a log was created in the `single` channel.

assertWasForgotten()

Assert that the channel was forgotten at least one time.

Can be called on

  • Facade base (default channel)
  • Channels
  • Stacks

Example tests

/*
 * implementation...
 */

Log::channel('single')->info('User logged in.');

Log::forgetChannel('single');

/*
 * assertions...
 */

Log::channel('single')->assertWasForgotten(); // ✅

Log::channel('stderr')->assertWasForgotten(); // ❌ as it was the `single` not the `stderr` channel that was not forgotten.

assertWasForgottenTimes()

Assert that the channel was forgotten a specific number of times.

Can be called on

  • Facade base (default channel)
  • Channels
  • Stacks

Example tests

/*
 * implementation...
 */

Log::channel('single')->info('User logged in.');

Log::forgetChannel('single');

Log::channel('single')->info('User logged in.');

Log::forgetChannel('single');

/*
 * assertions...
 */

Log::channel('single')->assertWasForgottenTimes(2); // ✅

Log::channel('single')->assertWasForgottenTimes(99); // ❌ as the channel was forgotten twice, not 99 times.

assertWasNotForgotten()

Assert that the channel was not forgotten.

Can be called on

  • Facade base (default channel)
  • Channels
  • Stacks

Example tests

/*
 * implementation...
 */

Log::channel('single')->info('User logged in.');

/*
 * assertions...
 */

Log::channel('single')->assertWasNotForgotten(); // ✅

assertChannelIsCurrentlyForgotten()

Assert that a channel is currently forgotten. This is distinct from asserting that a channel was forgotten.

Can be called on

  • Facade base (default channel)
  • Channels
  • Stacks

Example tests

/*
 * implementation...
 */

Log::channel('single')->info('xxxx');

Log::forgetChannel('single');

/*
 * assertions...
 */

Log::assertChannelIsCurrentlyForgotten('single'); // ✅

Log::assertChannelIsCurrentlyForgotten('stderr'); // ❌ as the `single` channel was forgotten, not the `stderr` channel.

assertCurrentContext()

Assert that the channel currently has the specified context. It is possible to provide the expected context as an array or alternatively you can provide a truth-test closure to check the current context.

Can be called on

  • Facade base (default channel)
  • Channels
  • Stacks

Example tests

/*
 * implementation...
 */

Log::withContext([
    'app' => 'Acme CRM',
]);

Log::withContext([
    'env' => 'production',
]);

/*
 * assertions...
 */

Log::assertCurrentContext([
    'app' => 'Acme CRM',
    'env' => 'production',
]); // ✅

Log::assertCurrentContext(
    fn (array $context) => $context['app'] === 'Acme CRM')
); // ✅

Log::assertCurrentContext([
    'env' => 'production',
]); // ❌ missing the "app" key.

Log::assertCurrentContext(
    fn (array $context) => $context['env'] === 'develop')
); // ❌ the 'env' key is set to "production"

assertHasSharedContext()

Assert that the Log manager currently has the given shared context. It is possible to provide the expected context as an array or alternatively you can provide a truth-test closure to check the current context.

Can be called on

  • Facade base (default channel)
  • Channels
  • Stacks

Example tests

/*
 * implementation...
 */

Log::shareContext([
    'invocation-id' => '54',
]);

/*
 * assertions...
 */

Log::assertHasSharedContext([
    'invocation-id' => '54',
]); // ✅

Log::assertCurrentContext(
    fn (array $context) => $context['invocation-id'] === '54')
); // ✅

Log::assertCurrentContext([
    'invocation-id' => '99',
]); // ❌ wrong invocation ID

Log::assertCurrentContext(
    fn (array $context) => $context['invocation-id'] === '99')
); // ❌ wrong invocation ID

Inspection

Sometimes when debugging tests it's useful to be able to take a peek at the messages that have been logged. There are a couple of helpers to assist with this.

dump()

Dumps all the logs in the channel. You can also pass a truth-based closure to filter the logs that are dumped.

Can be called on

  • Facade base (default channel)
  • Channels
  • Stacks
/*
 * implementation...
 */

Log::info('User logged in.');

Log::channel('slack')->alert('Stripe request initiated.');

/*
 * inspection...
 */

Log::dump();

// array:1 [
//   0 => array:4 [
//     "level" => "info"
//     "message" => "User logged in."
//     "context" => []
//     "channel" => "stack"
//   ]
// ]

Log::channel('slack')->dump();

// array:1 [
//   0 => array:4 [
//     "level" => "alert"
//     "message" => "Stripe request initiated."
//     "context" => []
//     "channel" => "slack"
//   ]
// ]

dd()

The same as dump, but also ends the execution.

dumpAll()

Dumps the logs for all channels. Also accepts a truth-test closure to filter any logs.

Can be called on

  • Facade base (default channel)
  • Channels
  • Stacks

Example usage

/*
 * implementation...
 */

Log::info('User logged in.');

Log::channel('slack')->alert('Stripe request initiated.');

/*
 * inspection...
 */

Log::dumpAll();

// array:2 [
//   0 => array:4 [
//     "level" => "info"
//     "message" => "User logged in."
//     "context" => []
//     "times_channel_has_been_forgotten_at_time_of_writing_log" => 0
//     "channel" => "stack"
//   ]
//   1 => array:4 [
//     "level" => "alert"
//     "message" => "Stripe request initiated."
//     "context" => []
//     "times_channel_has_been_forgotten_at_time_of_writing_log" => 0
//     "channel" => "slack"
//   ]
// ]

ddAll()

The same as dumpAll(), but also ends the execution.

Other APIs

logs()

Get a collection of all log entries from a channel or stack.

Can be called on

  • Facade base (default channel)
  • Channels
  • Stacks

Example usage

/*
 * implementation...
 */

Log::channel('slack')->info('User logged in.');

Log::channel('slack')->alert('Stripe request initiated.');

/*
 * example usage...
 */

$logs = Log::channel('slack')->logs();

assert($logs->count() === 2); ✅

allLogs()

Similar to logs(), except that it is called on the Facade base and returns a collection of logs from all the channels and stacks.

Can be called on

  • Facade base (default channel)
  • Channels
  • Stacks

Example usage

/*
 * implementation...
 */

Log::info('User logged in.');

Log::channel('slack')->alert('Stripe request initiated.');

/*
 * example usage...
 */

$logs = Log::allLogs();

assert($logs->count() === 2); ✅

Credits

And a special (vegi) thanks to Caneco for the logo ✨

Thanksware

You are free to use this package, but I ask that you reach out to someone (not me) who has previously, or is currently, maintaining or contributing to an open source library you are using in your project and thank them for their work. Consider your entire tech stack: packages, frameworks, languages, databases, operating systems, frontend, backend, etc.

timacdonald/log-fake 适用场景与选型建议

timacdonald/log-fake 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 6.56M 次下载、GitHub Stars 达 423, 最近一次更新时间为 2018 年 10 月 06 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「log」 「testing」 「logger」 「fake」 「laravel」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 timacdonald/log-fake 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 timacdonald/log-fake 我们能提供哪些服务?
定制开发 / 二次开发

基于 timacdonald/log-fake 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 6.56M
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 423
  • 点击次数: 10
  • 依赖项目数: 54
  • 推荐数: 0

GitHub 信息

  • Stars: 423
  • Watchers: 5
  • Forks: 32
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2018-10-06