عند دراسة الوحدات النمطية المختلفة لـ Magento 2 ، ستلاحظ أن التسجيل يتم استخدامه بشكل أقل تكرارًا من Magento 1. وهذا يرجع إلى حد كبير إلى حقيقة أن تسجيل الدخول أصبح أكثر صعوبة. أود هنا التركيز على الجانب الفني من المشكلة ، أي كيفية تسجيل البيانات ، وكيفية كتابة السجلات إلى ملفك الخاص ، وما هو مونولوج.
جدول المحتويات
Monolog
ميزات التطبيق في Magento 2
تطبيق
تسجيل باستخدام المسجل القياسية
تسجيل باستخدام مسجل قياسي مع قناة مخصصة
الكتابة إلى ملف مخصص باستخدام معالج الخاصة بك
الكتابة إلى ملف مخصص باستخدام virtualType
تسجيل بيانات سريع
استنتاج
Monolog
لنبدأ مع السؤال الأكثر أهمية - ما هو مونولوج ومن أين يأتي.
Monolog - هذه مكتبة تنفذ معيار PSR-3 لتسجيل البيانات. وهو مونولوج الذي يستخدم في Magento 2 لتسجيل السجلات.
تعد PSR-3 ، بدورها ، معيارًا يصف النهج الشائع لتسجيل البيانات والتوصيات الخاصة بتنفيذ قطع الاشجار التي توفر واجهة مشتركة.
أبرز PSR-31. يجب أن يقوم المسجل (الكائن) بتطبيق واجهة \ Psr \ Log \ LoggerInterface.
2. لدينا مستويات الخطأ التالية (المشار إليها بترتيب الأولوية من الأكبر إلى الأقل):
الطوارئ - النظام غير قابل للاستخدام.
التنبيه - يجب اتخاذ الإجراء على الفور. مثال: تم إيقاف تشغيل موقع الويب بالكامل ، وقاعدة البيانات غير متوفرة ، إلخ.
الحرجة - الظروف الحرجة. مثال: مكون التطبيق غير متاح ، استثناء غير متوقع.
خطأ - أخطاء وقت التشغيل التي لا تتطلب إجراءً فوريًا ولكن يجب مراقبتها عادةً.
تحذير - أحداث استثنائية ليست أخطاء. مثال: استخدام واجهات برمجة التطبيقات المهملة.
إشعار - أحداث عادية ولكنها مهمة.
INFO - أحداث مثيرة للاهتمام. مثال: تسجيل دخول المستخدم ، سجلات SQL.
DEBUG - معلومات تصحيح مفصلة.
3. كل مستوى له طريقته الخاصة (تصحيح ، معلومات ، إشعار ، تحذير ، خطأ ، حرج ، تنبيه ، طارئ / طارئ) ويجب أن يكون هناك أيضًا طريقة سجل ، والتي تأخذ مستوى الخطأ كمعلمة أولى.
4. تقبل الطرق سلسلة أو أي شيء ينفذ __toString () (أي ، يجب استخدام print_r (رسالة $ ، صواب) يدويًا للصفائف أو تمريرها في المعلمة التالية).
5. تقبل جميع الطرق صفيف سياق $ يكمل السجل.
6. يمكن ، ولكن ليس بالضرورة ، تنفيذ استبدال البيانات من صفيف سياق $ في الرسالة. في هذه الحالة ، يوصى بالتنسيق {name} ، حيث name -> مفتاح الصفيف في سياق $.
مونولوج هو سهل جدا للاستخدام. لنلقِ نظرة على المثال التالي.
use Monolog\Logger; use Monolog\Handler\StreamHandler; use Monolog\Formatter\HtmlFormatter;
أبرز أعمال مونولوج التي يجب وضعها في الاعتبار:
نظرًا لأن PSR-3 لا يلزم المطورين بتنفيذ قيم التصحيح التلقائي في النص ، فإن Monolog لا تقوم بذلك افتراضيًا. إذا كتبت -> الطوارئ ('test 1111 {placeholder}' ، ['placeholder' => 'foo']) ستحصل على ما يلي
[2019-08-12 02:57:52] main.EMERGENCY: اختبار 1111 {placeholder} {"placeholder": "foo"} []
لاستبدال العمل ، تحتاج إلى توصيل معالج إضافي - \ Monolog \ Processor \ PsrLogMessageProcessor.
تجدر الإشارة إلى أن Monolog لديها عدد كبير من Formatter ، Processor ، Handler من خارج منطقة الجزاء. يمكنك إما استخدامها أو كتابة الخاصة بك.
ميزات التطبيق في Magento 2
على
موقع Magento الرسمي ، يمكنك العثور على مثال عام لكيفية استخدام المسجل. لسوء الحظ ، فإن المثال المقدم لا يكشف عن جميع التفاصيل ، وللأسف ، لا يجيب على السؤال "كيفية كتابة السجلات إلى ملفك الخاص." لذلك ، دعونا نفهم كل شيء بمزيد من التفصيل.
في أيام Magento 1 ، ربما استخدم الكل عاجلاً أم آجلاً طريقة Mage :: log ، والتي كانت متاحة في كل مكان في الكود ، وكان إدخال السجل الأبسط يشبه Mage :: log ('ALARM!' ، Null ، 'api.log'). نتيجة لذلك ، كان لدينا سجل بالنموذج التالي في ملف var / log / api.log
2019-08-12T01:00:27+00:00 DEBUG (7): ALARM!
التنسيق الافتراضي:٪ timestamp ٪٪ الأفضلية٪ (٪ الأولوية٪):٪ message٪.دعونا نرى كيفية تسجيل البيانات في أبسط الحالات في Magento 2. في أغلب الأحيان ، ستستخدم $ this -> _ logger-> info ('ALARM!') ؛ (إذا كان للكائن خاصية كهذه ، على سبيل المثال ، موروثة).
نتيجة لمثل هذه المكالمة ، حصلنا على الإدخال التالي في ملف var / log / system.log
[2019-08-12 02:56:43] main.INFO: ALARM! [] []
التنسيق الافتراضي هو [٪ datetime٪]٪ channel٪.٪ Level_name٪:٪ message ٪٪ سياق ٪٪ extra٪إذا لم يكن الكائن يحتوي على هذه الخاصية (_logger أو المسجل) ، فعلينا أولاً إضافة التبعية \ Psr \ Log \ LoggerInterface إلى صفك وكتابة الكائن الناتج إلى خاصية $ logger (وفقًا لبند PSR-2 4.2 والمثال المقدم على موقع Magento الإلكتروني ) .
على عكس Magento 1 ، هناك الكثير من الفروق الدقيقة هنا.
1. معلمات للتسجيل.النظر في دعوة عامة لطريقة الكتابة
$this->_logger->{level}($message, $context = []);
1) عندما يكون {level} ، وفقًا لـ PSR-3 ، 1 من الطرق المخصصة لتسجيل مستوى خطأ معين (تصحيح ، معلومات ، إشعار ، تحذير ، خطأ ، حرج ، تنبيه ، الطوارئ / الطوارئ).
2) $ message - على عكس Magento 1 ، يجب أن تكون سلسلة. أي $ object-> getData () لن يعمل هنا. يجب تمرير صفيف البيانات إلى المعلمة التالية. الكائنات \ Exception هي استثناء ، نظرًا لأن تطبيق \ Magento \ Framework \ Logger \ Monolog يعالجها بشكل منفصل ويتم لفه تلقائيًا -> getMessage () كرسالة $ إذا تم تمرير كائن \ Exception كرسالة.
3) سياق السياق هو معلمة اختيارية ، مجموعة.
2. $ المسجل -> _ خاصية التسجيل غير متاحة في كل الفئات.موجودة في: Block ، Helper ، Model ، Collection ، إلخ.
غير متوفر في: ResourceModel ، المراقب ، Comand ، الإعداد ، إلخ.
تعرف على المزيد حول ResourceModel و Collection.يحتوي ResourceModel على الخاصية _logger ، لكن لا يتم ملؤها في المنشئ. يتم ملؤها فقط باستخدام طريقة getLogger الخاصة في \ Magento \ Framework \ Model \ ResourceModel \ AbstractResource. يتم استدعاء الطريقة فقط في حالة حدوث خطأ أثناء الكتابة إلى قاعدة البيانات (في كتلة catch) داخل طريقة الالتزام (). حتى ذلك الحين ، لن يكون لنموذج الموارد مسجل.
public function commit() { $this->getConnection()->commit(); if ($this->getConnection()->getTransactionLevel() === 0) { $callbacks = CallbackPool::get(spl_object_hash($this->getConnection())); try { foreach ($callbacks as $callback) { call_user_func($callback); } } catch (\Exception $e) { $this->getLogger()->critical($e); } } return $this; } … private function getLogger() { if (null === $this->_logger) { $this->_logger = ObjectManager::getInstance()->get(\Psr\Log\LoggerInterface::class); } return $this->_logger; }
جمع لديه مسجل من البداية. يتم تعيينه في المنشئ \ Magento \ Framework \ Data \ Collection \ AbstractDb ثم توارثه لاحقًا.
من المستحيل عدم القول ، ولكن في وحدات التحكم هناك طريقة للحصول على المسجل باستخدام ObjectManager (عبر خاصية $ this -> _ objectManager). لكن هذه ليست ، بالطبع ، الطريقة الصحيحة.
3. المسجل الافتراضي وقائمة المعالجات.في ملف di.xml العام (التطبيق / etc / di.xml) ، يمكنك العثور على أن \ Psr \ Log \ LoggerInterface يتم تنفيذه بواسطة فئة \ Magento \ Framework \ Logger \ Monolog ، التي ترث بدورها من \ Monolog \ Logger. اسم المسجل هو الرئيسي. يتم تعريف عدة معالجات أيضا هناك.
… <preference for="Psr\Log\LoggerInterface" type="Magento\Framework\Logger\Monolog" /> ... <type name="Magento\Framework\Logger\Monolog"> <arguments> <argument name="name" xsi:type="string">main</argument> <argument name="handlers" xsi:type="array"> <item name="system" xsi:type="object">Magento\Framework\Logger\Handler\System</item> <item name="debug" xsi:type="object">Magento\Framework\Logger\Handler\Debug</item> <item name="syslog" xsi:type="object">Magento\Framework\Logger\Handler\Syslog</item> </argument> </arguments> </type> ...
تختلف بعض الفئات عن تلك المذكورة أعلاه (حيث يتم إعادة تعريفها في وحدة Magento \ Developer):
1) Magento \ Framework \ Logger \ Handler \ System (
يستمع إلى INFO)2) Magento \ Developer \ Model \ Logger \ Handler \ Debug (
يستمع إلى DEBUG )
3) Magento \ Developer \ Model \ Logger \ Handler \ Syslog (
يستمع إلى DEBUG )
في الفئات المحددة (Debug و Syslog)
، تتم إضافة القدرة على تعطيل التسجيل (dev / debug / debug_logging و dev / syslog / syslog_logging ، على التوالي).
لاحظ أنه لا يوجد معالج استثناء في قائمة معالجات يكتب إلى استثناء. يطلق عليه في معالج النظام.
الماجنتو \ الإطار \ المسجل \ معالج \ النظام ... public function write(array $record) { if (isset($record['context']['exception'])) { $this->exceptionHandler->handle($record); return; } $record['formatted'] = $this->getFormatter()->format($record); parent::write($record); } ...
واجه Magento 2 إلى 2.2 مشكلة في عدم قدرة المسجل على الانتقال إلى معالج آخر بعد العثور على أول واحد. سبب هذه المشكلة هو أن Monolog توقعت أن يأتي كل معالجاتها في صفيف به مفاتيح رقمية ، ويأتي مع مفاتيح أبجدية (['system' =>، 'debug' =>، ...]). قام مطورو Magento بتصحيح الموقف في وقت لاحق - قاموا بتحويل التجزئة إلى صفيف منتظم مع مفاتيح رقمية قبل تمريره إلى Monolog. لقد غير Monolog الآن أيضًا خوارزمية تعداد المعالج ويستخدم الأسلوب التالي ().
4. إدخال معالج الخاص بك في قائمة تلك القائمة.نأتي إلى الشيء الأكثر إثارة للاهتمام ، والذي يفسد انطباع التنفيذ في Magento 2. قليلاً. لا يمكنك إضافة معالج مخصص إلى قائمة الموجودة باستخدام di.xml دون ... "لفتات إضافية". هذا بسبب مبدأ دمج التكوينات.
هناك العديد من
نطاق التكوين :
1) الأولي (التطبيق / etc / di.xml)
2) عالمي ({moduleDir} /etc/di.xml)
3) خاص بالمنطقة ({moduleDir} / etc / {area} /di.xml ، على سبيل المثال Frontend / adminhtml / crontab / webapi_soap / webapi_rest ، إلخ)
داخل المستوى 1 ، يتم دمج التكوينات ، ولكن المستوى التالي يعيد تعريفها عند الدمج (إذا تم الإعلان عنها أيضًا). هذا يجعل من المستحيل إضافة معالجات في الوحدات النمطية الخاصة بهم إلى القائمة الموجودة ، لأنه يتم الإعلان عنها في النطاق الأولي.
ربما سنرى في المستقبل تطبيقًا يتم فيه نقل إضافة معالجات من النطاق الأولي إلى وحدة أخرى ، وبالتالي يتم نقلها إلى النطاق العالمي.تطبيق
دعونا نلقي نظرة على الطرق الرئيسية لتسجيل السجلات ، والتي يمكن أن تكون مفيدة لنا عند تنفيذ المهام.
1. تسجيل باستخدام المسجل القياسية
تتيح لنا هذه الطريقة كتابة السجلات بسهولة في أحد السجلات القياسية (debug.log ، أو system.log ، أو default.log).
class RandomClass { private $logger; public function __construct(\Psr\Log\LoggerInterface $logger) { $this->logger = $logger; } public function foo() { $this->logger->info('Something went wrong');
يصبح كل شيء أكثر بساطة إذا كان هناك بالفعل تبعية مسجل موروثة في فئتنا.
… $this->_logger->info('Something went wrong');
2. تسجيل باستخدام مسجل قياسي مع قناة مخصصة
تختلف هذه الطريقة عن الطريقة السابقة في إنشاء نسخة من المسجل وتعيين قناة أخرى (الاسم) لها. والتي سوف تبسيط البحث داخل ملف السجل.
class RandomClass { private $logger; public function __construct(\Psr\Log\LoggerInterface $logger) { $this->logger = $logger->withName('api');
للبحث عن السجلات الضرورية ، يكفي الآن استخدام البحث عن طريق "api" (يُطلق على المسجل الافتراضي في Magento 2 اسم رئيسي) في ملفات system.log و debug.log و response.log الموجودة. يمكن استخدامها
grep -rn 'api' var/log/system.log
3. الكتابة إلى ملف مخصص باستخدام معالج الخاصة بك
دعونا ننشئ معالجًا بسيطًا يسجل جميع أخطاء المستوى الحرج والأعلى في ملف منفصل var / log / critical.log. أضف القدرة على حظر جميع معالجات أخرى لمستوى خطأ معين وأعلى. سيؤدي هذا إلى تجنب ازدواجية البيانات في ملفات debug.log و system.log.
<?php namespace Oxis\Log\Logger\Handler; use Magento\Framework\Filesystem\DriverInterface; use Magento\Framework\Logger\Handler\Base; use Monolog\Logger; class Test extends Base { protected $fileName = 'var/log/critical.log'; protected $loggerType = Logger::CRITICAL; public function __construct(DriverInterface $filesystem) { parent::__construct($filesystem,null,null); $this->bubble = false;
في Magento 2 2.2+ في المُنشئ \ Magento \ Framework \ Logger \ Handler \ Base تغيرت طريقة معالجة المسار إلى ملف السجل
لذلك ، في معالجات الأقدم لا يزال بإمكانك العثور على / في بداية $ fileName.
على سبيل المثال ، القليل من التفسير يستحق العطاء. نظرًا لأن Base لا يسمح لك بتعيين خاصية الفقاعة من خلال معلمات المُنشئ ، فسيتعين علينا إما تكرار جزء من الكود من مُنشئ Base لتمرير معلمة الإدخال بشكل صحيح إلى أصل فئة الأساس (والتي ، بالمناسبة ، لديها معلمة إدخال لتعيين هذه الخاصية) أو استخدام هذا النهج. اخترت الخيار الثاني.
use Oxis\Log\Logger\Handler\Test; use Psr\Log\LoggerInterface; class RandomClass { private $logger; public function __construct( LoggerInterface $logger, Test $handler ) { $logger->pushHandler($handler);
هذه الطريقة لإضافة معالج ليست مثالية ، ولكنها تسمح لك بالابتعاد عن Config Scope للمشكلة ، الأمر الذي سيتطلب منا تكرار جميع قطع الاشجار في di.xml الخاص بنا. إذا كان الهدف هو استبدال جميع أجهزة التسجيل بأجهزة تسجيل الدخول الخاصة بك ، فمن الأفضل استخدام نهج virtualType ، والذي سنبحثه أكثر.
4. الكتابة إلى ملف مخصص باستخدام virtualType
يسمح لنا هذا الأسلوب بفرض الفصل الذي نحتاجه لكتابة سجلات إلى ملف السجل المحدد لذلك باستخدام di.xml. يمكنك العثور على نهج مماثل في وحدات Magento \ Payment و Magento \ Shipping. أود أن ألفت انتباهكم إلى حقيقة أن هذا النهج يعمل بدءا من Magento 2 2.2 وما فوق.
في Magento 2 2.2+ ، تمت إضافة معلمة جديدة إلى المُنشئ \ Magento \ Framework \ Logger \ Handler \ Base ، والذي يسمح لك بإنشاء معالج افتراضي وتحديد المسار النسبي للملف من خلال di.xml لكتابة السجل. في السابق ، كان مطلوبًا إما تحديد المسار الكامل من خلال $ filePath ، أو لإنشاء معالج جديد وكتابة المسار النسبي إلى خاصية الملف fileName المحمية.
في di.xml لوحدتنا ، أضف ما يلي
<virtualType name="ApiHandler" type="Magento\Framework\Logger\Handler\Base"> <arguments> <argument name="fileName" xsi:type="string">var/log/api.log</argument> </arguments> </virtualType> <virtualType name="ApiLogger" type="Magento\Framework\Logger\Monolog"> <arguments> <argument name="name" xsi:type="string">api</argument> <argument name="handlers" xsi:type="array"> <item name="default" xsi:type="object">ApiHandler</item> </argument> </arguments> </virtualType> <type name="Oxis\Log\Model\A"> <arguments> <argument name="logger" xsi:type="object">ApiLogger</argument> </arguments> </type>
إضافة فئة مسجل إلى Oxis \ Log \ Model \ A.
namespace Oxis\Log\Model; class A { private $logger; public function __construct(\Psr\Log\LoggerInterface $logger) { $this->logger = $logger; } public function foo() { $this->logger->info('Something went wrong'); } }
الآن ستتم معالجة جميع السجلات التي ستتم كتابتها في فئتنا تمامًا بواسطة إصدار المسجل الخاص بنا ، والذي سيكتب سجلات باستخدام معالجنا إلى ملف var / log / api.log.
4.1. إذا تلقى الفصل المسجل من خلال كائن السياق $ ، وليس من خلال منشئه.تتضمن هذه المنتجات \ Magento \ Catalog \ Model \ Product ، حيث لا تحتوي التبعيات على \ Psr \ Log \ LoggerInterface ، ولكن هناك \ Magento \ Framework \ Model \ Context يتم من خلاله تعيين المسجل على خاصية الفئة. في هذه الحالة ، نحتاج إلى تعقيد الخيار أعلاه قليلاً واستبدال المسجل الموجود في كائن سياق $. وحتى لا يؤثر هذا على Magento بالكامل ، سنستبدل سياق $ لفئتنا فقط بواسطة virtualType.
<virtualType name="ApiHandler" type="Magento\Framework\Logger\Handler\Base"> <arguments> <argument name="fileName" xsi:type="string">var/log/api.log</argument> </arguments> </virtualType> <virtualType name="ApiLogger" type="Magento\Framework\Logger\Monolog"> <arguments> <argument name="name" xsi:type="string">api</argument> <argument name="handlers" xsi:type="array"> <item name="default" xsi:type="object">ApiHandler</item> </argument> </arguments> </virtualType> <virtualType name="ApiLogContainingContext" type="Magento\Framework\Model\Context"> <arguments> <argument name="logger" xsi:type="object">ApiLogger</argument> </arguments> </virtualType> <type name="Oxis\Log\Model\A"> <arguments> <argument name="context" xsi:type="object">ApiLogContainingContext</argument> </arguments> </type>
5. تسجيل البيانات بسرعة
هناك أوقات نحتاج فيها لإضافة التسجيل بسرعة. في أغلب الأحيان ، قد تكون هناك حاجة إلى ذلك إما على خادم الإنتاج أو للاختبار السريع.
... $log = new \Monolog\Logger('custom', [new \Monolog\Handler\StreamHandler(BP.'/var/log/custom.log')]); $log->error('test'); ...
إيجابيات هذا الأسلوب: يكتب تاريخًا ، يوجد سياق (صفيف) ، يضيف \ n تلقائيًا إلى النهايةفي المثال أعلاه ، يتم تطبيق \ Monolog \ Logger على وجه التحديد ، وليس \ Magento \ Framework \ Logger \ Monolog الذي يمتد عليه. والحقيقة هي أنه مع هذا الاستخدام لا يوجد فرق ، ولكن الكتابة أقل (وتذكر أنه أسهل).
\ Monolog \ Handler \ StreamHandler ، بدوره ، يتم استخدامه بدلاً من \ Magento \ Framework \ Logger \ Handler \ Base لأن استخدام Base كمقتطف ليس مناسبًا جدًا بسبب التبعيات الإضافية على فئات الجهات الخارجية.
هناك طريقة أخرى لا يمكن القول عنها وهي ملف file_put_contents القديم الجيد.
... file_put_contents(BP.'/var/log/custom.log', 'test',FILE_APPEND); ...
مزايا هذا النهج: الكتابة بسرعة نسبيا ولا تحتاج إلى حفظ الطبقات.في كلتا الحالتين ، لعبت الدور القيادي من قبل
BP المستمر. إنها تشير دائمًا إلى المجلد الذي يحتوي على أرجواني (مستوى واحد أعلى من الحانة) ، وهو مناسب ويساعدنا دائمًا في كتابة السجلات في المكان المناسب.
استنتاج
آمل أن المعلومات المذكورة أعلاه كانت أو ستكون مفيدة لك.