在开发现代应用程序时,日志记录应该放在优先级列表的顶部。
日志记录提供了一种在开发和生产中可视化您的应用程序的方法,从而实现透明度和可见性。通过适当结构化的日志记录,现代应用程序可以变得更容易维护,因为我们可以主动识别应用程序中的故障点和性能瓶颈。
Laravel框架带有一个健壮的日志系统,它可以处理所有在配置正确结构化的日志系统时遇到的障碍。Laravel 6.5中引入的这个新的日志系统非常强大,我们将在本文中对其进行探索。
本文将探讨Laravel日志记录的基础知识,以及为什么应该在下一个项目中使用Laravel日志记录。我们将详细讨论结构化日志记录和集中式日志记录。此外,我们将学习如何通过构建一个Todo应用程序来实现Laravel日志记录。
如果您已经掌握了以下内容,您将从本文中获得更多收益:
- 良好的网络开发知识
- Laravel的基本理解
- 使用Laravel构建应用程序
什么是Laravel日志记录?
Laravel日志记录是关于Laravel如何使用称为Monolog的病毒式PHP日志记录系统处理日志记录或自动问题报告的。然而,由于Laravel使用流行的现有库来实现不同框架功能的理念,Laravel使用Monolog来满足其所有日志记录需求。
Monolog是一个高度灵活且流行的PHP日志库,我们可以将其配置为将您的日志发送到文件、套接字、数据库和其他Web服务。Monolog提供了一个熟悉的界面,用于将标准文本文件中的日志写入高级第三方日志管理服务。Laravel通常将Monolog设置为使用标准的日志记录配置文件。
有关Monolog及其功能的更多信息,请查看官方文档,因为这超出了本文的范围。
在我们深入使用Monolog配置和实现Laravel日志之前,让我们探索更多使用Laravel日志和不同类型的原因。
为什么使用Laravel日志记录?
为什么需要日志记录?
Twelve-Factor App宣言将日志记录视为现代应用程序的关键问题之一,因为日志记录是性能和监控的关键。
日志有助于详细了解生产中发生的错误及其来源。此外,通过适当的日志结构,它可以显示特定用户、导致错误的操作以及更快修复和维护错误的可能解决方案。
结构化日志记录是生产应用程序中的救星,它可以帮助解决缺陷并解决生产中的问题。此外,您可以使用专门的日志工具实时监控和收集所有日志消息,以进行实时分析和报告。
由于这些原因,您需要将结构化日志记录作为您下一个现代应用程序项目的重中之重。
让我们看一下可用的不同日志记录样式的概述。
Laravel日志基础
学习日志记录的基础知识将帮助您了解Laravel如何处理日志记录以及如何改进结构化日志记录实践。
让我们检查日志中的两个基本概念,以更好地理解如何实现我们的日志过程。
Laravel结构化日志
在软件开发中,结构化日志记录是为应用程序日志实现预定且一致的消息格式。这种格式允许将消息视为可以比常规文本格式更好地监视、操作和可视化的数据。
您必须在现代应用程序开发中实现结构化日志记录方法,因为当您的应用程序在生产中发生问题时,日志文件是开发人员的重要资产。
由于Laravel使用Monolog,开发者可以通过配置logger接收特定类型的信息,将日志文件以不同格式存储,并将日志发送到各种第三方日志管理服务进行可视化,从而快速实现结构化日志。
Laravel集中式日志记录
集中式日志记录系统是将来自多个来源的日志发送到集中式日志管理 (CLM) 解决方案,以便于整合和可视化。然而,CLM是一种专门的记录器解决方案,它从不同来源收集日志消息并整合数据以便于处理和可视化。
除了数据收集,CLM还有望支持日志数据的分析和分析后的数据清晰呈现。
结构化日志记录与基本日志记录
让我们来看看结构化日志和基本(非结构化)日志之间的区别,以及为什么应该在Laravel项目中使用结构化日志。
基本日志记录
在基本日志记录中,日志文件以原始格式存储,用于查询和识别单个日志的数据有限。
使用基本日志记录时,开发人员将无法使用第三方分析工具来读取、查看和分析日志,除非他们开发自定义工具或坚持使用支持其日志格式的有限工具。
避免使用基本日志记录的三大原因:
- 如果没有额外的支持,集中式日志管理系统无法处理数据。
- 需要定制解决方案来读取和解析基本日志记录解决方案的数据。
- 管理员读取基本日志数据可能具有挑战性,因为它是原始的和非结构化的。
结构化日志
结构化日志通过使用支持标准日志结构的开源第三方日志分析工具来读取、查看和分析日志,从而节省开发人员的时间。
如果日志包含下面列出的正确数据,则日志会很有帮助,这是结构化日志记录的目标。我们可以使用结构化日志记录中包含的数据来创建仪表盘、图形、图表和任何其他有用的可视化,以确定应用程序的运行状况。
这些是我们可以包含在结构化日志消息中的信息的基本示例。此外,您可以完全自定义数据以满足您的需求。
以下是您可以使用结构化日志记录收集的数据的一些示例:
- 用于执行函数的端口
- 事件发生的日期和时间
- 客户用户名或ID
- 事件描述(日志消息)
- 用于执行功能的协议
- 触发事件的位置(表示API或正在运行的应用程序)
- 唯一的事件ID
- 触发的操作类型(日志级别)
日志应包含足够的数据,以便轻松可视化解决方案或日志事件的原因。另外请注意,您不应在日志中存储所有类型的信息,例如密码或敏感数据。
现在我们已经了解了Laravel日志记录的全部内容,让我们继续通过构建一个将日志记录作为一等公民的应用程序来实现Laravel日志记录。
如何使用Todo应用实现Laravel日志记录
现在我们将通过创建一个新的Laravel项目并实现Laravel日志记录来应用到目前为止所学的知识。
如果您以前没有使用过Laravel,您可以阅读Laravel是什么或查看我们的优秀Laravel教程列表以开始使用。
设置Laravel
首先,我们将使用以下命令创建一个新的Laravel实例。您可以查看官方文档了解更多信息。
在运行以下命令之前,打开您的控制台并导航到您存储PHP项目的位置。确保正确安装和配置了Composer。
composer create-project laravel/laravel laravel-logging-app cd laravel-logging-app // Change directory to current Laravel installation php artisan serve // Start Laravel development server
配置和预埋数据库
接下来,我们将建立我们的数据库,创建一个新Todo
模型,并预埋200个假数据进行测试。
打开您的数据库客户端并创建一个新数据库。我们将对名称laravel_logging_app_db
执行相同的操作,然后使用数据库凭据填充我们的.env文件:
DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=laravel_logging_app_db DB_USERNAME=//DB USERNAME HERE DB_PASSWORD=//DB PASSWORD HERE
接下来,我们将运行以下命令来同时创建迁移和Todo
模型:
php artisan make:model Todo -mc
打开新创建的迁移找到database/migrations/xxx-create-todos-xxx.php并粘贴以下代码:
<?php use IlluminateSupportFacadesSchema; use IlluminateDatabaseSchemaBlueprint; use IlluminateDatabaseMigrationsMigration; class CreateTodosTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('todos', function (Blueprint $table) { $table->id(); $table->string('title'); $table->text('description')->nullable(); $table->boolean('is_completed')->default(false); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('todos'); } }
您可以通过学习使用Faker在Laravel中为您的数据库播种来使用伪造数据播种您的待办事项。
独白概述
使用Laravel Monolog,您可以将结构化日志流式传输并发送到不同的渠道,例如电子邮件、Slack、文件、套接字、收件箱、数据库和各种Web服务。在Laravel中,您可以从位于config/logging.php的单个配置文件中配置日志记录。
配置文件带有预定义的日志驱动程序可供选择,默认驱动程序是stack
使用single
通道记录到storage/logs文件夹中的laravel.log文件的驱动程序。我们将使用几个Laravel日志驱动程序来演示结构化日志记录。
Laravel提供了一些与Logs交互的方法,正如稍后在TodosController.php控制器文件中所展示的那样。
在控制器中写入日志消息
打开新创建的TodosController.php控制器文件找到app/Http/Controllers文件夹并粘贴以下代码:
<?php namespace AppHttpControllers; use AppModelsTodo; use IlluminateHttpRequest; use AppHttpControllersController; use IlluminateSupportFacadesAuth; use IlluminateSupportFacadesLog; class TodosController extends Controller { public function index(Request $request) { $todos = Todo::all(); Log::warning('User is accessing all the Todos', ['user' => Auth::user()->id]); return view('dashboard')->with(['todos' => $todos]); } public function byUserId(Request $request) { $todos = Todo::where('user_id', Auth::user()->id)->get(); Log::info('User is accessing all his todos', ['user' => Auth::user()->id]); return view('dashboard')->with(['todos' => $todos]); } public function show(Request $request, $id) { $todo = Todo::find($id); Log::info('User is accessing a single todo', ['user' => Auth::user()->id, 'todo' => $todo->id]); return view('show')->with(['todo' => $todo]); } public function update(Request $request, $id) { # Validations before updating $todo = Todo::where('user_id', Auth::user()->id)->where('id', $id)->first(); Log::warning('Todo found for updating by user', ['user' => Auth::user()->id, 'todo' => $todo]); if ($todo) { $todo->title = $request->title; $todo->desc = $request->desc; $todo->status = $request->status == 'on' ? 1 : 0; if ($todo->save()) { Log::info('Todo updated by user successfully', ['user' => Auth::user()->id, 'todo' => $todo->id]); return view('show', ['todo' => $todo]); } Log::warning('Todo could not be updated caused by invalid todo data', ['user' => Auth::user()->id, 'todo' => $todo->id, 'data' => $request->except('password')]); return; // 422 } Log::error('Todo not found by user', ['user' => Auth::user()->id, 'todo' => $id]); return; // 401 } public function store(Request $request) { Log::warning('User is trying to create a single todo', ['user' => Auth::user()->id, 'data' => $request->except('password')]); # Validations before updating $todo = new Todo; $todo->title = $request->title; $todo->desc = $request->desc; $todo->user_id = Auth::user()->id; if ($todo->save()) { Log::info('User create a single todo successfully', ['user' => Auth::user()->id, 'todo' => $todo->id]); return view('show', ['todo' => $todo]); } Log::warning('Todo could not be created caused by invalid todo data', ['user' => Auth::user()->id, 'data' => $request->except('password')]); return; // 422 } public function delete(Request $request, $id) { Log::warning('User is trying to delete a single todo', ['user' => Auth::user()->id, 'todo' => $id]); $todo = Todo::where('user_id', Auth::user()->id)->where('id', $id)->first(); if ($todo) { Log::info('User deleted a single todo successfully', ['user' => Auth::user()->id, 'todo' => $id]); $todo->delete(); return view('index'); } Log::error('Todo not found by user for deleting', ['user' => Auth::user()->id, 'todo' => $id]); return; // 404 } }
在TodoController
中的每个方法中,我们添加了具有特定日志级别的Log
facade,以定义要发送的错误类型。下面是使用的示例
在方法中记录store
facade。
public function store(Request $request) { Log::warning('User is trying to create a single todo', ['user' => Auth::user()->id, 'data' => $request->except('password')]); # Validations before updating $todo = new Todo; $todo->title = $request->title; $todo->desc = $request->desc; $todo->user_id = Auth::user()->id; if ($todo->save()) { Log::info('User create a single todo successfully', ['user' => Auth::user()->id, 'todo' => $todo->id]); return view('show', ['todo' => $todo]); } Log::warning('Todo could not be created caused by invalid todo data', ['user' => Auth::user()->id, 'data' => $request->except('password')]); return; // 422 }
格式化日志消息
假设你对Laravel使用的默认值LineFormatter
不满意,它在提供可读和有用的消息方面做得很好。
在这种情况下,您可以轻松启动自定义格式化程序对象以适合您的用例并在整个应用程序中使用它。
Monolog官方文档提供了可用格式化程序的完整列表,并且可以轻松创建自定义格式化程序。
在Laravel中,您可以轻松地将任何驱动程序设置为使用您的自定义格式化程序,方法是将其添加到位于config/logging.php的配置文件中的如下列表中:
'daily' => [ 'driver' => 'daily', 'path' => storage_path('logs/laravel.log'), 'level' => env('LOG_LEVEL', 'debug'), 'days' => 14, 'formatter' => MonologFormatterHtmlFormatter::class, 'formatter_with' => [ 'dateFormat' => 'Y-m-d', ] ],
上面的示例使用daily
频道配置中的formatter
和formatter_with
键将自定义MonologFormatterHtmlFormatter
添加到每日驱动程序中,以更改日期格式。
将日志发送到不同的通道
在Monolog的帮助下,Laravel可以将日志同时发送到不同的通道和多个通道。
让我们演示如何按照这些简单的步骤将日志发送到我们的Slack频道。将默认日志通道更改为Slack并在.env文件中添加Slack Webhook URL 。
LOG_CHANNEL=slack LOG_SLACK_WEBBHOOK_URL= Slack_webhook_url_here
接下来,通过使用如下所示的Log
facade在您的应用程序中记录一条消息来测试您的配置:
Log::debug("The API instance is on fire caused by:", ['user' => 1])
您可以打开您的Slack频道以检查在生成Webhook URL时指定的所需频道中打印的错误。
小结
日志记录与应用程序的任何其他因素一样重要,甚至更重要。这就是为什么Twelve-Factor App宣言建议它作为任何现代应用程序最关键的问题之一。
通过有效的日志记录,您可以轻松阅读、查看和可视化生产就绪应用程序中发生的错误和缺陷。为此,从项目开始就在应用程序中实施结构化日志记录非常重要。
在本文中,我们探讨了Laravel日志记录以及为什么要在下一个项目中使用它。我们详细讨论了结构化日志记录和集中式日志记录。此外,我们通过构建Todo应用程序学习了如何实现Laravel日志记录。
评论留言