2016-09-02 13 views
8

Tôi đang sử dụng Symfony 3.1 và tôi cố định cấu hình Monolog theo cách như vậy, yêu cầu từ Googlebot không được ghi lại. Đối với điều này tôi đã viết một UserAgentProcessor mà đã hoạt động như dự định. Trong bước tiếp theo tôi đã cố gắng để viết BotFilter mà trông như thế này:Custom HandlerWrapper với MonologBundle

<?php 

namespace AppBundle\Handler; 

use Monolog\Handler\HandlerWrapper; 

class FilterBotsHandler extends HandlerWrapper 
{ 

    /** 
    * {@inheritdoc} 
    */ 
    public function isHandling(array $record) 
    { 
     if (stripos($record['extra']['userAgent'], 'bot') !== false){ 
      return false; 
     } else { 
      return $this->handler->isHandling($record); 
     } 
    } 
} 

này được lấy cảm hứng từ những ý kiến ​​trong lớp trừu tượng HandlerWrapper (hãy xem here).

Bây giờ tôi muốn thêm bộ lọc đó vào cấu hình yahoo monolog của mình. Tôi đã thử thêm nó vào dịch vụ của tôi nhưng điều này là không thể như HandlerWrapper cần một ví dụ Handler cho constructor của nó. Tôi đã nghiên cứu cách tôi có thể sử dụng bộ lọc mà không có một dịch vụ nhưng theo như tôi thấy, gói monolog chỉ chấp nhận các kiểu tích hợp và kiểu dịch vụ chung.

Bây giờ câu hỏi là: Làm cách nào để sử dụng bộ lọc trong cấu hình của tôi?

+0

Bạn muốn di chuyển biểu thức sang cấu hình? Xác định trong cấu hình monolog không phải là vị trí chính xác, bạn có thể tạo một dịch vụ (monolog sử dụng) và chèn biểu thức thông qua các tham số: http://symfony.com/doc/current/components/expression_language.html – Rvanlaak

+0

I don ' nghĩ rằng bạn hiểu câu hỏi của tôi một cách chính xác. Những gì tôi về cơ bản muốn là có thể thiết lập một 'handler' sẽ được gọi bởi' FilterBotsHandler' của tôi. Ví dụ: hãy xem [DeduplcationHandler] (https://github.com/Seldaek/monolog/blob/master/src/Monolog/Handler/DeduplicationHandler.php). Bạn có thể chỉ định một 'Handler'here khác, nó sẽ được gọi bởi' DeduplicationHandler'. Tôi cố gắng làm như vậy. –

Trả lời

6

Tôi đang sử dụng Symfony 3.1 và tôi cố gắng để cấu hình Monolog theo cách như vậy, rằng các yêu cầu từ GoogleBot chưa đăng nhập ...


  1. Cách nhanh chóng để ngăn chặn robot truy cập trang web của bạn được đặt hai dòng này vào tệp /robots.txt trên máy chủ của bạn. Tạo một file robots.txt trong thư mục 'web' và dán sau nội dung:

    User-agent: * 
    Disallow:/
    

    https://support.google.com/webmasters/answer/6062608?hl=en&visit_id=1-636097099675465769-3677253464&rd=1

    Đó là tùy chọn được đề nghị khi bạn cần tránh truy cập đầy đủ, có nghĩa là trang web của bạn sẽ không còn được các công cụ tìm kiếm và các bot khác lập chỉ mục. Bạn không cần phải cấu hình/thực hiện bất cứ điều gì trong ứng dụng của bạn để đạt được nó.


  1. Bây giờ, nếu bạn cần bot để vào, nhưng bạn không muốn đăng ký nó trong nhật ký.Thay vì viết các tệp nhật ký ở đâu đó, một số trình xử lý được sử dụng để lọc hoặc sửa đổi các mục nhập nhật ký trước khi gửi chúng đến các trình xử lý khác. Một trình xử lý mạnh mẽ được tích hợp sẵn có tên là fingers_crossed được sử dụng trong môi trường prod theo mặc định. Nó lưu trữ tất cả các thông tin đăng nhập trong một yêu cầu nhưng chỉ qua họ một handler thứ hai nếu một trong các thông đạt một action_level:

    # app/config/config.yml 
    monolog: 
        handlers: 
         filter_for_errors: 
          type: fingers_crossed 
          # if *one* log is error or higher, pass *all* to file_log 
          action_level: error 
          handler: file_log 
    
         # now passed *all* logs, but only if one log is error or higher 
         file_log: 
          type: stream 
          path: "%kernel.logs_dir%/%kernel.environment%.log" 
    

    Như vậy, trong tập tin prod.log của bạn sẽ chỉ đăng ký tin nhắn/yêu cầu có chứa một số lỗi, do đó các chương trình không có hiệu lực ở cấp độ này.

    Thông tin chi tiết về vấn đề này http://symfony.com/doc/current/logging.html


  1. gì bạn cố gắng làm không nên, bởi vì handler sẽ phụ thuộc từ yêu cầu http thay vì bản ghi nhật ký, sẽ không nằm trong ngữ cảnh, tuy nhiên bạn có thể đăng ký trình xử lý riêng của mình trong Symfony dễ dàng:

    Hãy tạo e lớp trình xử lý tùy chỉnh:

    namespace AppBundle\Monolog\Handler; 
    
    use Monolog\Handler\AbstractHandler; 
    
    class StopBotLogHandler extends AbstractHandler 
    { 
        public function isBotRequestDetected() 
        { 
         // here your code to detect Bot requests, return true or false 
         // something like this: 
         // return isset($_SERVER['HTTP_USER_AGENT']) && preg_match('/bot|crawl|slurp|spider/i', $_SERVER['HTTP_USER_AGENT']); 
        } 
    
        /** 
        * Checks whether the given record will be handled by this handler. 
        * 
        * This is mostly done for performance reasons, to avoid calling processors for nothing. 
        * 
        * Handlers should still check the record levels within handle(), returning false in isHandling() 
        * is no guarantee that handle() will not be called, and isHandling() might not be called 
        * for a given record. 
        * 
        * @param array $record Partial log record containing only a level key (e.g: array('level' => 100) for DEBUG level) 
        * 
        * @return bool 
        */ 
        public function isHandling(array $record) 
        { 
         return $this->isBotRequestDetected(); 
        } 
    
        /** 
        * Handles a record. 
        * 
        * All records may be passed to this method, and the handler should discard 
        * those that it does not want to handle. 
        * 
        * The return value of this function controls the bubbling process of the handler stack. 
        * Unless the bubbling is interrupted (by returning true), the Logger class will keep on 
        * calling further handlers in the stack with a given log record. 
        * 
        * @param array $record The record to handle 
        * 
        * @return bool true means that this handler handled the record, and that bubbling is not permitted. 
        *    false means the record was either not processed or that this handler allows bubbling. 
        */ 
        public function handle(array $record) 
        { 
         // do nothing, just returns true whether the request is detected as "bot", this will break the handlers loop. 
         //    else returns false and other handler will handle the record. 
    
         return $this->isBotRequestDetected(); 
        } 
    } 
    

    Bất cứ khi nào bạn thêm bản ghi vào nhật ký, nó sẽ vượt qua ngăn xếp trình xử lý. Mỗi trình xử lý quyết định xem nó có xử lý hoàn toàn bản ghi hay không và nếu có, việc sao chép bản ghi sẽ kết thúc ở đó.

    Quan trọng: Đọc phpdoc từ isHandling()handle() phương pháp để biết thêm chi tiết.

    Tiếp theo, hãy đăng ký lớp như dịch vụ "không có thẻ":

    # app/config/services.yml 
    services: 
        monolog.handler.stop_bot_log: 
         class: AppBundle\Monolog\Handler\StopBotLogHandler 
         public: false 
    

    Sau đó, thêm xử lý của nó-handlers danh sách:

    # app/config/config_prod.yml 
    monolog: 
        handlers: 
         # ... 
    
         stopbotlog: 
          type: service 
          id: monolog.handler.stop_bot_log 
          priority: 1 
    

    Lưu ý type tài sản phải bằng service, id phải là tên dịch vụ trước khi được xác định và priority phải lớn hơn 0 để đảm bảo ure rằng bộ xử lý của nó sẽ được thực hiện trước bất kỳ trình xử lý nào khác.

    Khi GoogleBot thực hiện một yêu cầu đến ứng dụng trang web xử lý stopbotlog dừng tất cả xử lý sau anh ta và không đăng ký bất kỳ nội dung log.

    Hãy nhớ rằng đó không phải là cách được khuyến nghị để làm điều đó! Theo nhu cầu của bạn, việc thực hiện tùy chọn 1 hoặc 2 là đủ.


Nếu bạn muốn bỏ qua yêu cầu bot cho nhóm xử lý, bạn có thể ghi đè lên các tham số chứa monolog.handler.group.class và ghi đè lên nhóm handler hành vi:

namespace AppBundle\Handler; 

use Monolog\Handler\GroupHandler; 

class NoBotGroupHandler extends GroupHandler 
{ 
    public function isBotRequestDetected() 
    { 
     // here your code to detect Bot requests, return true or false 
    } 

    public function handle(array $record) 
    { 
     if ($this->isBotRequestDetected()) { 
      // ignore bot request for handlers list 
      return false === $this->bubble; 
     } 

     return parent::handle($record); 
    } 
} 

trong bạn config_prod.yml hoặc services.yml:

parameters: 
    monolog.handler.group.class: AppBundle\Handler\NoBotGroupHandler 

Đúng rồi! Bây giờ, bạn có thể ngăn chặn các bản ghi bot cho tùy chỉnh xử lý danh sách:

# config_prod.yml 
monolog: 
    handlers: 
     grouped: 
      type: group 
      members: [main, console, chromephp] 

Cuối cùng, nếu bạn gặp khó khăn để phân tích các bản ghi của bạn tập tin tôi khuyên bạn nên sử dụng công cụ tuyệt vời này: https://github.com/EasyCorp/easy-log-handler

+0

Cảm ơn bạn rất nhiều vì câu trả lời sâu rộng này! Tôi biết rõ 1) và 2). Trong thực tế, tôi đang sử dụng 2) tại thời điểm này để chỉ đăng nhập cấp 'lỗi' và tồi tệ hơn. Tôi không muốn sử dụng 1) vì tôi thực sự muốn rô bốt quét trang. Bây giờ tôi đã thực hiện 3) như đã đề xuất. Không giống như bạn đã đề cập, tôi không phải dựa vào bất cứ thứ gì ngoài bản ghi, vì tôi đã thêm userAgent vào bản ghi với sự trợ giúp của bộ xử lý. Tôi có một câu hỏi còn lại: Giải pháp của bạn bằng cách nào đó có thể được sử dụng cùng với trình xử lý nhóm, sao cho chỉ một nhóm sẽ bị chặn? –

+0

Có, bạn có thể tạo trình xử lý tùy chỉnh từ 'GroupHandler' và áp dụng cùng một logic cho danh sách' handlers'. – yceruto

+0

Theo như tôi có thể nói, kết quả này trong cùng một vấn đề như được mô tả trong câu hỏi ban đầu của tôi: 'GroupHandler' nhận các trình xử lý' khác làm tham số hàm tạo và do đó không thể được sử dụng như một dịch vụ. –

1

Đó là một mẹo khá bẩn, nhưng nếu bạn thực sự cần nó, bạn có thể làm cho nó như thế này.

Giả sử bạn muốn quấn một handler với một loại stream:

Thêm một constructor trong bạn FilterBotsHandler:

public function __constructor($path, $level, $bubble, $permissions) { 
    $this->handler = new Monolog\Handler\StreamHandler($path, $level, $bubble, $permissions); 
} 

Và sau đó xác định lại một tham số monolog.handler.stream.class:

parameters: 
    monolog.handler.stream.class: AppBundle\Handler\FilterBotsHandler 

Đảm bảo rằng thông số này sẽ được xác định sau nó được định nghĩa bởi MonologBundle.

Vậy đó. Nên làm việc.

0

Bạn có thể viết CompilerPass trong AppBundle của bạn, thêm configurator đến monolog dịch vụ. Cấu hình như vậy có thể cũng là một request event listener có thể thay thế tất cả các trình xử lý động theo yêu cầu và phát hiện bot và đẩy các bộ xử lý rỗng tới Logger có thể được giữ trong cuộc gọi của trình cấu hình.

Nói cách cấu hình khác thêm vào DI bởi CompilerPass và thêm vào EventDispatcher như Listener để Kernel sự kiện mà onRequest séc User-Agent tiêu đề tìm bot và sau đó xóa Monolog\Logger (thông qua vào cấu hình) tất cả các bộ xử lý (hoặc đưa một NullHandler nếu xử lý trống mảng thất bại).

Trình cấu hình DI chỉ là cách để thay đổi dịch vụ của bạn trong thời gian chạy có thể được áp dụng làm cấp độ định nghĩa dịch vụ. Định nghĩa như vậy có thể được đính kèm hoặc tách ra nếu không cần thiết và nó không thực sự thay đổi bất cứ điều gì trong ứng dụng của bạn.