首頁 > 軟體

Python實現紀錄檔實時監測的範例詳解

2022-04-06 19:02:02

介紹

觀察者模式:是一種行為型設計模式。主要關注的是物件的責任,允許你定義一種訂閱機制,可在物件事件發生時通知多個"觀察"該物件的其他物件。用來處理物件之間彼此互動。

觀察者模式也叫釋出-訂閱模式,定義了物件之間一對多依賴,當一個物件改變狀態時,這個物件的所有依賴者都會收到通知並按照自己的方式進行更新。

觀察者設計模式是最簡單的行為模式之一。在觀察者設計模式中,物件維護了一個依賴(觀察者)列表,以便主題可以使用觀察者定義的任何方法通知所有觀察者它所發生的變化。

可使用觀察者模式應用場景

在廣播或者釋出訂閱系統的情形中,你會看到觀察者設計模式的用法,它的主要使用場景如下:

1、分散式系統中實現事件服務。

2、廣播或釋出/閱系統情形中。

2、用作新聞機器的框架。

3、股票監測機器人。

觀察者模式類圖

觀察者模式類圖

1、釋出者Publisher:向其他物件傳送值得關注的事件。事件會在釋出者自身狀態改變或執行特定行為後發生。釋出者中包含一個允許新訂閱者加入和當前訂閱者離開列表的訂閱機制。

2、訂閱者Subscriber:定義通知介面。一般情況下,該介面僅包含一個update()更新方法。方法中可以有多個引數,使釋出者能在更新時傳遞事件詳細資訊。

3、使用者端Client:分別建立釋出者和訂閱者物件,然後為訂閱者註冊,釋出者更新。

觀察者模式範例

假如我們對應用函數執行狀態進行監測,當發生異常時報警記錄,可通過觀察者模式進行資訊訂閱:1、簡訊 2、紀錄檔 3、郵件

程式碼實現---subscription_model.py

1、建立訂閱者類

Subscriber訂閱者:所有希望關注釋出者狀態變化的其他物件。

這裡提供了三個主要的訂閱者(觀察者)介面,跟蹤著同一個釋出者類的事件。主要包括:

1)、每個具體訂閱者__init()方法使用attach()方法向釋出者進行註冊以獲取資訊更新。

2)、具體訂閱者的update()更新訊息。

#抽象訂閱者
from abc import ABCMeta,abstractmethod
class Subscriber(metaclass=ABCMeta):
    #向具體訂閱者傳送訊息的方法
    @abstractmethod
    def update(self):
        pass

#具體訂閱者
#1、簡訊訂閱者
class SMSSubscriber(Subscriber):
    def __init__(self,publisher):
        self.publisher = publisher
        self.publisher.attach(self)

    def update(self):
        print(type(self).__name__,self.publisher.getNews())


#2、郵件訂閱者
class EmailSubscriber(Subscriber):
    def __init__(self, publisher):
        self.publisher = publisher
        self.publisher.attach(self)

    def update(self):
        print(type(self).__name__,self.publisher.getNews())
        info = self.publisher.getNews()
        # 傳送郵件
        Sender_mail(info).sender_mail()

#3、紀錄檔訂閱(檔案儲存)
class LoggerSubscriber(Subscriber):

    def __init__(self, publisher):
        log_dir = os.path.expanduser(r".appsMapviewlogs")
        log_file = os.path.join(log_dir, "file_{time}.log")
        logger.add(log_file, rotation="100KB", retention=2)
        self.publisher = publisher
        self.publisher.attach(self)

    def update(self):
        print(type(self).__name__,self.publisher.getNews())
        info=self.publisher.getNews()
        logger.info(f"{info}")

2、建立釋出者類

Publisher釋出者:將自身的狀態改變通知其他物件,為釋出者新增訂閱機制,每個物件都能訂閱或取消訂閱者事件流。

主要包括:

1)self.__subscribers = []:一個用於儲存訂閱物件列表

2)供訂閱者來註冊NewsPublisher或刪除訂閱使用者。

3)幾個用於新增、刪除或檢視列表中訂閱者的公有方法。

4)notifySubscribers(self):用於通知所有訂閱者出現新的資訊,傳送者會遍歷訂閱列表並通過內部呼叫具體訂閱者實現的update()方法來實現。

5)建立新訊息和返回最新訊息。

#建立釋出者
class NewsPublisher:
    def __init__(self):
        self.__subscribers = []
        self.__latestNews = None
    
    #將訂閱者新增到佇列中
    def attach(self,subscriber):
        self.__subscribers.append(subscriber)
    
    #從訂閱的主題裡面移除
    def detach(self):
        return self.__subscribers.pop()

    #生成觀察者列表
    def subscribers(self):
        return [type(x).__name__ for x in self.__subscribers]

    #傳送通知給相關的主題訂閱者
    def notifySubscribers(self):
        for sub in self.__subscribers:
            #update()方法由具體的觀察者或訂閱者實現的
            sub.update()  #推播更新
    
    #建立新訊息
    def addNews(self,news):
        self.__latestNews = news
    
    #返回最新訊息,並通知觀察者
    def getNews(self):
        return "Got News:",self.__latestNews

3、應用使用者端-Map_server_client.py

訂閱者通常需要一些上下文資訊正確處理更新。因此,釋出者通常會將一些上下文資料作為通知方法的引數傳遞。

這裡給第一篇文章留下的尾巴補充一下,使用者端範例化get_Map_model方法新增帶引數裝飾器,@fail_data(msg='地圖載入失敗')新增介面呼叫失敗處理機制,追加紀錄檔記錄。這裡可以進一步將更多細節引數新增到紀錄檔中,裝飾器傳參並在介面中宣告通知方法及引數,這樣釋出者在發出通知時傳遞一些上下文資料。

from apps.tools.subscription_model import NewsPublisher,LoggerSubscriber,EmailSubscriber
import functools


#如果載入失敗,呼叫訂閱者
def publisher(info):
    news_publisher = NewsPublisher()
    # for Subscribers in [EmailSubscriber, LoggerSubscriber]:
    for Subscribers in [LoggerSubscriber]:
        # eval(LoggerSubscriber)(news_publisher)
        Subscribers(news_publisher)
        print("nSubscribers", news_publisher.subscribers())
        news_publisher.addNews(f"{info}")
        news_publisher.notifySubscribers()


#處理異常的裝飾器
def fail_data(msg='地圖載入失敗'):
    def catch_exception(origin_func):
        @functools.wraps(origin_func)
        def wrapper(*args, **kwargs):
            try:
                u = origin_func(*args, **kwargs)
                print("這個函數正常執行:%s" % origin_func.__name__)
                return u

            except Exception as e:
                info = f"{msg}:{e.__doc__}"
                """
                介面呼叫失敗處理機制,追加紀錄檔
                """
                print(info)
                publisher(info)
                # news_publisher = NewsPublisher()
                # LoggerSubscriber(news_publisher)
                # print("nSubscribers", news_publisher.subscribers())
                # news_publisher.addNews(f"{info}")
                # news_publisher.notifySubscribers()
        return wrapper
    return catch_exception

4、測試

if __name__ == '__main__':

    from loguru import logger
    from apps.tools.Sender_Email import Sender_mail

    news_publisher =NewsPublisher()
    for Subscribers in [LoggerSubscriber]:
        print(Subscribers)
        Subscribers(news_publisher)

    print("nSubscribers",news_publisher.subscribers())

    news_publisher.addNews("地圖載入失敗!")
    news_publisher.notifySubscribers()

結果

class '__main__.LoggerSubscriber';

Subscribers ['LoggerSubscriber']
LoggerSubscriber ('Got News:', '地圖載入失敗!')
2022-04-05 16:38:00.667 | INFO     | __main__:update:81 - ('Got News:', '地圖載入失敗!')

以上就是實現了一個簡單的釋出訂閱模式,釋出者與訂閱者之間是鬆耦合的,新增新訂閱者無需修改釋出者。所有具體訂閱者類都實現了同樣介面。

到此這篇關於Python實現紀錄檔實時監測的範例詳解的文章就介紹到這了,更多相關Python紀錄檔監測內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com