{"id":13828438,"url":"https://github.com/timacdonald/log-fake","last_synced_at":"2025-05-14T09:08:41.639Z","repository":{"id":37778163,"uuid":"151792408","full_name":"timacdonald/log-fake","owner":"timacdonald","description":"A drop in fake logger for testing with the Laravel framework.","archived":false,"fork":false,"pushed_at":"2025-03-10T23:39:25.000Z","size":1341,"stargazers_count":409,"open_issues_count":1,"forks_count":30,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-04-03T19:47:58.673Z","etag":null,"topics":["fake","hacktoberfest","laravel","logging","php","testing"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/timacdonald.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"license.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-10-06T00:49:03.000Z","updated_at":"2025-03-31T10:43:56.000Z","dependencies_parsed_at":"2024-11-28T02:01:37.165Z","dependency_job_id":"3e4e2874-5acf-4ad6-a83e-46469d3ee230","html_url":"https://github.com/timacdonald/log-fake","commit_stats":{"total_commits":202,"total_committers":13,"mean_commits":"15.538461538461538","dds":0.09405940594059403,"last_synced_commit":"0d32515c5456de04cf21245c3769b0203aa40d2b"},"previous_names":[],"tags_count":17,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timacdonald%2Flog-fake","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timacdonald%2Flog-fake/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timacdonald%2Flog-fake/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timacdonald%2Flog-fake/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/timacdonald","download_url":"https://codeload.github.com/timacdonald/log-fake/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248335002,"owners_count":21086488,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["fake","hacktoberfest","laravel","logging","php","testing"],"created_at":"2024-08-04T09:02:46.907Z","updated_at":"2025-04-11T03:27:36.025Z","avatar_url":"https://github.com/timacdonald.png","language":"PHP","funding_links":[],"categories":["PHP"],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\u003cimg src=\"/art/header.png\" alt=\"Log Fake: a Laravel package by Tim MacDonald\"\u003e\u003c/p\u003e\n\n# Log fake for Laravel\n\nA 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.\n\n## Installation\n\nYou can install using [composer](https://getcomposer.org/):\n\n```sh\ncomposer require timacdonald/log-fake --dev\n```\n\n## Basic usage\n\n```php\nuse Illuminate\\Support\\Facades\\Log;\nuse TiMacDonald\\Log\\LogEntry;\nuse TiMacDonald\\Log\\LogFake;\n\npublic function testItLogsWhenAUserAuthenticates()\n{\n    /*\n     * Test setup.\n     *\n     * In the setup of your tests, you can call the following `bind` helper,\n     * which will switch out the underlying log driver with the fake.\n     */\n    LogFake::bind();\n\n    /*\n     * Application implementation.\n     *\n     * In your application's implementation, you then utilise the logger, as you\n     * normally would.\n     */\n    Log::info('User logged in.', ['user_id' =\u003e $user-\u003eid]);\n\n    /*\n     * Test assertions.\n     *\n     * Finally you can make assertions against the log channels, stacks, etc. to\n     * ensure the expected logging occurred in your implementation.\n     */\n    Log::assertLogged(fn (LogEntry $log) =\u003e\n        $log-\u003elevel === 'info'\n        \u0026\u0026 $log-\u003emessage === 'User logged in.' \n        \u0026\u0026 $log-\u003econtext === ['user_id' =\u003e 5]\n    );\n}\n```\n\n## Channels\n\nIf 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.\n\n```php\npublic function testItLogsWhenAUserAuthenticates()\n{\n    // setup...\n    LogFake::bind();\n\n    // implementation...\n    Log::channel('slack')-\u003einfo('User logged in.', ['user_id' =\u003e $user-\u003eid]);\n\n    // assertions...\n    Log::channel('slack')-\u003eassertLogged(\n        fn (LogEntry $log) =\u003e $log-\u003emessage === 'User logged in.'\n    );\n}\n```\n\n## Stacks\n\nIf 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.\n\n```php\npublic function testItLogsWhenAUserAuthenticates()\n{\n    // setup...\n    LogFake::bind();\n\n    // implementation...\n    Log::stack(['stderr', 'single'])-\u003einfo('User logged in.', ['user_id' =\u003e $user-\u003eid]);\n\n    // assertions...\n    Log::stack(['stderr', 'single'])-\u003eassertLogged(\n        fn (LogEntry $log) =\u003e $log-\u003emessage === 'User logged in.'\n    );\n}\n```\n\nThat's it really. Now let's dig into the available assertions to improve your experience testing your applications logging.\n\n## Available assertions\n\nRemember that all assertions are relative to the channel or stack as shown above.\n\n- [`assertLogged()`](#assertlogged)\n- [`assertLoggedTimes()`](#assertloggedtimes)\n- [`assertNotLogged()`](#assertnotlogged)\n- [`assertNothingLogged()`](#assertnothinglogged)\n- [`assertWasForgotten()`](#assertwasforgotten)\n- [`assertWasForgottenTimes()`](#assertwasforgottentimes)\n- [`assertWasNotForgotten()`](#assertwasnotforgotten)\n- [`assertChannelIsCurrentlyForgotten()`](#assertchanneliscurrentlyforgotten)\n- [`assertCurrentContext()`](#assertcurrentcontext)\n\n### assertLogged()\n\nAssert that a log was created.\n\n#### Can be called on\n\n- [x] Facade base (default channel)\n- [x] Channels\n- [x] Stacks\n\n#### Example tests\n\n```php\n/*\n * implementation...\n */\n\nLog::info('User logged in.');\n\n/*\n * assertions...\n */\n\nLog::assertLogged(\n    fn (LogEntry $log) =\u003e $log-\u003emessage === 'User logged in.'\n); // ✅\n\nLog::assertLogged(\n    fn (LogEntry $log) =\u003e $log-\u003elevel === 'critical'\n); // ❌ as log had a level of `info`.\n```\n\n### assertLoggedTimes()\n\nAssert that a log was created a specific number of times.\n\n#### Can be called on\n\n- [x] Facade base (default channel)\n- [x] Channels\n- [x] Stacks\n\n#### Example tests\n\n```php\n/*\n * implementation...\n */\n\nLog::info('Stripe request initiated.');\n\nLog::info('Stripe request initiated.');\n\n/*\n * assertions...\n */\n\nLog::assertLoggedTimes(\n    fn (LogEntry $log) =\u003e $log-\u003emessage === 'Stripe request initiated.',\n    2\n); // ✅\n\nLog::assertLoggedTimes(\n    fn (LogEntry $log) =\u003e $log-\u003emessage === 'Stripe request initiated.',\n    99\n); // ❌ as the log was created twice, not 99 times.\n```\n\n### assertNotLogged()\n\nAssert that a log was never created.\n\n#### Can be called on\n\n- [x] Facade base (default channel)\n- [x] Channels\n- [x] Stacks\n\n#### Example tests\n\n```php\n/*\n * implementation...\n */\n\nLog::info('User logged in.');\n\n/*\n * assertions...\n */\n\nLog::assertNotLogged(\n    fn (LogEntry $log) =\u003e $log-\u003elevel === 'critical'\n); // ✅\n\nLog::assertNotLogged(\n    fn (LogEntry $log) =\u003e $log-\u003elevel === 'info'\n); // ❌ as the level was `info`.\n```\n\n### assertNothingLogged()\n\nAssert that no logs were created.\n\n#### Can be called on\n\n- [x] Facade base (default channel)\n- [x] Channels\n- [x] Stacks\n\n#### Example tests\n\n```php\n/*\n * implementation...\n */\n\nLog::channel('single')-\u003einfo('User logged in.');\n\n/*\n * assertions...\n */\n\nLog::channel('stderr')-\u003eassertNothingLogged(); // ✅\n\nLog::channel('single')-\u003eassertNothingLogged(); // ❌ as a log was created in the `single` channel.\n```\n\n### assertWasForgotten()\n\nAssert that the channel was forgotten at least one time.\n\n#### Can be called on\n\n- [x] Facade base (default channel)\n- [x] Channels\n- [ ] Stacks\n\n#### Example tests\n\n```php\n/*\n * implementation...\n */\n\nLog::channel('single')-\u003einfo('User logged in.');\n\nLog::forgetChannel('single');\n\n/*\n * assertions...\n */\n\nLog::channel('single')-\u003eassertWasForgotten(); // ✅\n\nLog::channel('stderr')-\u003eassertWasForgotten(); // ❌ as it was the `single` not the `stderr` channel that was not forgotten.\n```\n\n### assertWasForgottenTimes()\n\nAssert that the channel was forgotten a specific number of times.\n\n#### Can be called on\n\n- [x] Facade base (default channel)\n- [x] Channels\n- [ ] Stacks\n\n#### Example tests\n\n```php\n/*\n * implementation...\n */\n\nLog::channel('single')-\u003einfo('User logged in.');\n\nLog::forgetChannel('single');\n\nLog::channel('single')-\u003einfo('User logged in.');\n\nLog::forgetChannel('single');\n\n/*\n * assertions...\n */\n\nLog::channel('single')-\u003eassertWasForgottenTimes(2); // ✅\n\nLog::channel('single')-\u003eassertWasForgottenTimes(99); // ❌ as the channel was forgotten twice, not 99 times.\n```\n\n### assertWasNotForgotten()\n\nAssert that the channel was not forgotten.\n\n#### Can be called on\n\n- [x] Facade base (default channel)\n- [x] Channels\n- [ ] Stacks\n\n#### Example tests\n\n```php\n/*\n * implementation...\n */\n\nLog::channel('single')-\u003einfo('User logged in.');\n\n/*\n * assertions...\n */\n\nLog::channel('single')-\u003eassertWasNotForgotten(); // ✅\n```\n\n### assertChannelIsCurrentlyForgotten()\n\nAssert that a channel is _currently_ forgotten. This is distinct from [asserting that a channel _was_ forgotten](https://github.com/timacdonald/log-fake#assertwasforgotten).\n\n#### Can be called on\n\n- [x] Facade base ~(default channel)~\n- [ ] Channels\n- [ ] Stacks\n\n#### Example tests\n\n```php\n/*\n * implementation...\n */\n\nLog::channel('single')-\u003einfo('xxxx');\n\nLog::forgetChannel('single');\n\n/*\n * assertions...\n */\n\nLog::assertChannelIsCurrentlyForgotten('single'); // ✅\n\nLog::assertChannelIsCurrentlyForgotten('stderr'); // ❌ as the `single` channel was forgotten, not the `stderr` channel.\n```\n\n### assertCurrentContext()\n\nAssert 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.\n\n#### Can be called on\n\n- [x] Facade base (default channel)\n- [x] Channels\n- [ ] Stacks\n\n#### Example tests\n\n```php\n/*\n * implementation...\n */\n\nLog::withContext([\n    'app' =\u003e 'Acme CRM',\n]);\n\nLog::withContext([\n    'env' =\u003e 'production',\n]);\n\n/*\n * assertions...\n */\n\nLog::assertCurrentContext([\n    'app' =\u003e 'Acme CRM',\n    'env' =\u003e 'production',\n]); // ✅\n\nLog::assertCurrentContext(\n    fn (array $context) =\u003e $context['app'] === 'Acme CRM')\n); // ✅\n\nLog::assertCurrentContext([\n    'env' =\u003e 'production',\n]); // ❌ missing the \"app\" key.\n\nLog::assertCurrentContext(\n    fn (array $context) =\u003e $context['env'] === 'develop')\n); // ❌ the 'env' key is set to \"production\"\n```\n\n### assertHasSharedContext()\n\nAssert 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.\n\n#### Can be called on\n\n- [x] Facade base (default channel)\n- [ ] Channels\n- [ ] Stacks\n\n#### Example tests\n\n```php\n/*\n * implementation...\n */\n\nLog::shareContext([\n    'invocation-id' =\u003e '54',\n]);\n\n/*\n * assertions...\n */\n\nLog::assertHasSharedContext([\n    'invocation-id' =\u003e '54',\n]); // ✅\n\nLog::assertCurrentContext(\n    fn (array $context) =\u003e $context['invocation-id'] === '54')\n); // ✅\n\nLog::assertCurrentContext([\n    'invocation-id' =\u003e '99',\n]); // ❌ wrong invocation ID\n\nLog::assertCurrentContext(\n    fn (array $context) =\u003e $context['invocation-id'] === '99')\n); // ❌ wrong invocation ID\n```\n\n## Inspection\n\nSometimes 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.\n\n### dump()\n\nDumps all the logs in the channel. You can also pass a truth-based closure to filter the logs that are dumped.\n\n#### Can be called on\n\n- [x] Facade base (default channel)\n- [x] Channels\n- [x] Stacks\n\n```php\n/*\n * implementation...\n */\n\nLog::info('User logged in.');\n\nLog::channel('slack')-\u003ealert('Stripe request initiated.');\n\n/*\n * inspection...\n */\n\nLog::dump();\n\n// array:1 [\n//   0 =\u003e array:4 [\n//     \"level\" =\u003e \"info\"\n//     \"message\" =\u003e \"User logged in.\"\n//     \"context\" =\u003e []\n//     \"channel\" =\u003e \"stack\"\n//   ]\n// ]\n\nLog::channel('slack')-\u003edump();\n\n// array:1 [\n//   0 =\u003e array:4 [\n//     \"level\" =\u003e \"alert\"\n//     \"message\" =\u003e \"Stripe request initiated.\"\n//     \"context\" =\u003e []\n//     \"channel\" =\u003e \"slack\"\n//   ]\n// ]\n```\n\n### dd()\n\nThe same as [`dump`](https://github.com/timacdonald/log-fake#dump), but also ends the execution.\n\n### dumpAll()\n\nDumps the logs for all channels. Also accepts a truth-test closure to filter any logs.\n\n#### Can be called on\n\n- [x] Facade base ~(default channel)~\n- [ ] Channels\n- [ ] Stacks\n\n#### Example usage\n\n```php\n/*\n * implementation...\n */\n\nLog::info('User logged in.');\n\nLog::channel('slack')-\u003ealert('Stripe request initiated.');\n\n/*\n * inspection...\n */\n\nLog::dumpAll();\n\n// array:2 [\n//   0 =\u003e array:4 [\n//     \"level\" =\u003e \"info\"\n//     \"message\" =\u003e \"User logged in.\"\n//     \"context\" =\u003e []\n//     \"times_channel_has_been_forgotten_at_time_of_writing_log\" =\u003e 0\n//     \"channel\" =\u003e \"stack\"\n//   ]\n//   1 =\u003e array:4 [\n//     \"level\" =\u003e \"alert\"\n//     \"message\" =\u003e \"Stripe request initiated.\"\n//     \"context\" =\u003e []\n//     \"times_channel_has_been_forgotten_at_time_of_writing_log\" =\u003e 0\n//     \"channel\" =\u003e \"slack\"\n//   ]\n// ]\n```\n\n### ddAll()\n\nThe same as [`dumpAll()`](https://github.com/timacdonald/log-fake#dumpall), but also ends the execution.\n\n## Other APIs\n\n### logs()\n\nGet a collection of all log entries from a channel or stack.\n\n#### Can be called on\n\n- [x] Facade base (default channel)\n- [x] Channels\n- [x] Stacks\n\n#### Example usage\n\n```php\n/*\n * implementation...\n */\n\nLog::channel('slack')-\u003einfo('User logged in.');\n\nLog::channel('slack')-\u003ealert('Stripe request initiated.');\n\n/*\n * example usage...\n */\n\n$logs = Log::channel('slack')-\u003elogs();\n\nassert($logs-\u003ecount() === 2); ✅\n```\n\n### allLogs()\n\nSimilar to [`logs()`](https://github.com/timacdonald/log-fake#logs), except that it is called on the Facade base and returns a collection of logs from all the channels and stacks.\n\n#### Can be called on\n\n- [x] Facade base ~(default channel)~\n- [ ] Channels\n- [ ] Stacks\n\n#### Example usage\n\n```php\n/*\n * implementation...\n */\n\nLog::info('User logged in.');\n\nLog::channel('slack')-\u003ealert('Stripe request initiated.');\n\n/*\n * example usage...\n */\n\n$logs = Log::allLogs();\n\nassert($logs-\u003ecount() === 2); ✅\n```\n\n## Credits\n\n- [Tim MacDonald](https://github.com/timacdonald)\n- [All Contributors](../../contributors)\n\nAnd a special (vegi) thanks to [Caneco](https://twitter.com/caneco) for the logo ✨\n\n## Thanksware\n\nYou 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.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftimacdonald%2Flog-fake","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftimacdonald%2Flog-fake","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftimacdonald%2Flog-fake/lists"}