1. 程式人生 > >從Apache的日誌檔案收集和提供統計資料(一個Python外掛架構的簡單實現)

從Apache的日誌檔案收集和提供統計資料(一個Python外掛架構的簡單實現)

從Apache的日誌檔案收集和提供統計資料

這一章我們將介紹基於外掛程式的架構和實現。作為例子,我們將構建一個分析Apache伺服器log檔案的框架。這一次我們不再使用微控制器的方式來建立,而是改為採用模組化的方式。一旦我們有了一個基本框架,我們就可以為它建立一個外掛。這個外掛可以基於請求者的地理位置執行分析。

程式的結構和功能

在資料維護和統計收集領域,很難有一個單一的應用程式可以適合多個使用者的需求。讓我們以分析Apache的web伺服器日誌檔案為例。web伺服器接受到的每一個請求都被記錄在日誌檔案中。在日誌檔案的每一行都記錄著一堆不同的資料,以及請求進來的時間。
讓我們假想你被要求開發一個程式,分析那些日誌檔案,並且生成一個報告。這是那些對統計資訊感興趣使用者通常情況下的要求。顯然,目前你沒有多少資訊可以幫助你處理這個請求,所以你要求知道更多,比如究竟使用者想要在報告中看到什麼內容。因此假設的使用者將更多的參與到設計階段,告訴你他們想看到的是一個特定檔案的下載總量。好,這很容易做到。但是,之後你又拿到了另一個使用者的請求,他想要知道的確是網站每小時的點選量。於是,你又把它寫到指令碼中。之後又有一個使用者要求關聯分析一天中的一個時間的瀏覽器型別。這樣的例子舉不勝舉。即使是你為一個特定的組織編寫工具,需求也是呈多樣化。特別一直處於需求收集階段的話,幾乎不太可能捕捉得到一定的需求。所以,在這樣的情況下你應當怎樣做呢?
通過一些專門提取和處理不同資訊的模組,可以對其自身進行擴充套件的通用應用程式難道不是一個很好的解決辦法嗎?他的每一個模組負責一個特定的計算並生成報告。這些模組根據需要可以被新增或者刪除,而不會影響到系統的其他模組的功能。更重要的是,不會對主程式帶來任何變化。這種模組化的結構通常被稱作外掛架構(plug-in architecture)。
外掛指的是軟體中的一個小程式,它可以擴充套件主程式的功能。這種技術非常受歡迎,並且被用在許許多多不同的應用程式中。一個很好的例子就是瀏覽器。市場上絕大多數的瀏覽器都是支援外掛的。一個網頁可以嵌入一段Adobe的Flash影片,但是瀏覽器本身不知道(也不需要知道)如何處理這個型別的檔案。所以,它會查詢一個有能力處理和顯示Flash影片的外掛。如果找到這樣的外掛,它就將檔案物件傳給外掛進行處理。如果找不到,就簡單地不能顯示給最終的使用者。缺少合適的外掛並不影響網頁被顯示出來。
我們將用這樣的方式建立一個分析Apache日誌檔案的應用程式。讓我們從完成特定統計資料分析任務的應用程式的需求開始。

應用程式需求

在應用程式中,我們需要實現的需求主要有兩個:

  • 主應用程式負責Apache日誌檔案的解析,並且提取每一行日誌的欄位。由於日誌每一行的格式在不同的web伺服器安裝下會有不同,因此主程式需要能夠根據日誌檔案格式進行配置。
  • 程式應當能夠發現已經安裝的外掛,並且將提取的日誌欄位傳送到正確的外掛模組進行進一步的處理。新增新的外掛應對已存在的模組和主程式的功能不產生任何影響。

應用程式設計

需求檔案意味著程式應當被被分成以下兩個部分:

  • 主應用程式:通過命令列引數,主程式得到一個檔案目錄的列表,並對其中日誌檔案進行解析。在一個時間,每個日誌檔案只有一行在被處理。程式不保證日誌檔案按時間順序進行處理。每個日誌行都是以單詞為界,而欄位的分隔符是空格字元。在一些欄位中也可能會有空格字元存在,這要求這些欄位必須用雙引號包起來。如Apache的文件所描述的,為了便於使用,欄位由符合相應日誌格式的欄位程式碼來描述。
  • 外掛管理元件:外掛管理器負責發現和註冊可用的外掛模組。只有一些特殊的Python類將被當做外掛對待。每個外掛只向它感興趣的日誌段進行公開。當主程式在對日誌檔案進行解析時,它會檢查已訂閱外掛的表格,並把相關資訊傳遞給一些有關的外掛。

下面,讓我們看一下如何在Python中實現一個外掛框架。

Python中外掛框架的實現

當在python中實現一個外掛框架時,有好訊息,同時也有壞訊息。壞訊息是目前沒有一個實現外掛架構的標準方式。有許多不同的技術,也同時有商業和開源的產品可以使用。但是,它們解決問題的方式都不相同。可能在某個方面很好的,在其它方面卻有所欠缺。為實現這個架構,你所選擇的方式很大程度上取決於你想要達到什麼。
好訊息是還沒有實現外掛框架的事實標準,我們可以自己寫一個。通過編寫實現程式碼,你可以學到一些Pyhon語言和程式設計技術的新東西,比如型別檢查,鴨子型別,以及動態模組載入。
在我們進入技術細節之前,讓我們先弄清外掛到底是什麼,以及它與主程式或者宿主程式的關係。

外掛框架的機制

無論是日誌解析引擎的日誌,一個瀏覽器的HTML檔案,或者其它型別的檔案,主程式都會對它接受到的資料進行處理。它的工作也完全不會受已存在外掛及其功能的影響。不過,主程式始終為外掛模組提供著服務。
在日誌處理程式中,主程式唯一的職責就是從檔案讀取資料,識別日誌的格式,將資料轉換稱合適的資料結果。這正是它向外掛提供的服務。主程式不關心它生成的資料是否會被它的某一個外掛使用,也不關心被如何使用。
外掛模組很大程度上依賴於主應用程式,讓我們以一個計算請求數量的外掛為例。在取得資料以前,外掛是沒有辦法做任何計數。所以,離開主程式外掛是沒有什麼用的。
你可能疑惑為什麼需要如此在意這樣的分離。為什麼外掛自己不能讀取資料,以及對資料做任何她需要的做的處理?如我們所討論過的,這樣可能存在讓許多不同的應用程式對相同的資料做不同的計算。讓所有程式中的都有一個模組具有對相同的資料進行讀取和解析功能,從開發的角度來說是效率低下的。這將耗費時間一次又一次的去開發相同的處理。
顯然,這只是一個極其簡單的例子。通常來說,最終的使用者並不會注意到主程式和外掛之間的這種分離。使用者體驗到的應用程式是程式與外掛合併的結果。
讓我在思考一下web瀏覽器的例子。HTML頁面由瀏覽器引擎渲染並呈現給使用者。外掛模組則對網頁中的多鍾元件進行渲染。例如,Adobe的Flash影片又Flash外掛進行渲染,Windows播放器檔案則由Windows Media外掛模組進行渲染。使用者只是看到這樣的結果:經過渲染的網頁。通過安裝新的外掛可以很輕鬆的擴充套件應用程式的功能。在部署了新的外掛之後,使用者就可以訪問在安裝外掛之前不能夠正常顯示或訪問的網站。
基於外掛程式的另一個很好例子是Eclipse專案(http://eclipse.org/)。它一開始只是作為Java的一個開發環境。但隨後卻成長為一個的平臺,可以支援多種程式語言,集成了多個版本的控制系統,提供建模和軟體報告。這一切都感謝它的外掛架構。基礎應用程式做不會做太多,但是你可以對它進行擴充套件,用你所需要的適當外掛對程式進行量身定製。因此,同樣的"應用程式"可能會做著完全不同的事情。對我來說,它是一個Python的開發平臺。對其他某個人來說,它可以使一個UML建模工具。

介面模型

正如你可能已經想到的,主應用程式和外掛模組通常是極非常散耦合的實體。因此,兩者之間的互動需要定義一個協議。通常情況,主程式公開一些具備完善文件的服務介面,比如一些函式名。當需要從主程式獲取一些東西的時候,外掛的方法則對這些介面進行呼叫。
類似的,外掛也公開介面。因此,主應用程式可以向它們傳送資料,或者通知外掛正在發生一些事件。這正是事情變得更復雜的地方,通常情況下,外掛模組實現的功能可能不會被主應用程式意識到。因此,外掛需要宣佈它們具有的功能,比如有能力顯示Flash影片檔案。功能的類別通常會與模組的方法名相聯絡。所以,主應用程式知道哪個方法實現這類功能。
我們以一個簡化的瀏覽器模型為例來進行考慮。我們有一個基本應用程式,它接受HTML頁面,並且會下載所有連結的資源。每個資源都有一個MIME型別與之聯絡,Flash物件的型別是application/x-shockwave-flash。當瀏覽器遇到這樣的物件時,它會檢視外掛登錄檔,並且搜尋一個聲稱有能力處理這個型別檔案的外掛。一旦外掛及其方法名被發現,主應用程式就對外掛方法進行呼叫,並將檔案物件傳遞給它。

外掛註冊和發現

那麼主應用程式所檢查的外掛登錄檔到底是什麼呢?簡單一點說,它其實就是可以被主應用程式找到和載入的外掛模組的表單。這個表單通常包含物件例項、功能以及實現這些功能的方法。登錄檔是一個儲存外掛例項的中心。所以,主應用程式在允許時可以找到已註冊的外掛。
外掛登錄檔是在發現外掛的過程中建立的。發現過程在不同實現下會有不同,但一般包括髮現適當的程式檔案以及將其載入到記憶體中。在主程式處理外掛管理的事務中,通常包含一個單獨的處理過程,比如發現、註冊、控制。表6-1顯示的是一個對所有這些元件以及他們之間關係的概覽。

Figure 6-1典型的外掛架構

建立外掛框架

如我所說的,在Python中實現基於外掛架構的方式有許多種。在這裡,我採用其中一種最簡單的方式。它足夠靈活,可以應對大多數的小型應用程式的需求。

— 提示:在2009年PyCon上,André Roberge博士做過一個將許多不同的外掛機制進行比較的報告。你可以在網路上查詢一下,報告的標題是“Plugins and monkeypatching: increasing flexibility,
dealing with inflexibility”。如果你確定需要一個更復雜的實現的話,可以看一看Zope(http://zope.org/)所提供的Grok(http://grok.zope.org/),以及Envisage(http://code.enthought.com/projects/envisage/)的實現。

發現和註冊

這個發現過程實際是基於基類能夠找到它的所有子類。這裡有一個簡單的例子:

  1. classPlugin(object)
  2. pass
  3. classMyPlugin1(Plugin)
  4. def __init__(self):
  5. print'plugin 1'
  6. classMyPlugin2(Plugin)
  7. def __init__(self):
  8. print'plugin 2'
  9. >>>Plugin.__subclass__()
  10. [<class'__main__.MyPlugin1'>,<class'__main__.MyPlugin2'>]

這段程式碼建立了一個基類,並且定義了兩個從它繼承的子類。於是我們可以通過呼叫基類內建的__subclass__()方法,找到所有的從主類中繼承的類。這是一個在不知道子類名字,甚至是不知道載入子類的模組名字的情況下,找出所有子類的強大機制。
一旦這些類被發現,那麼我們就可以創建出每一個類的例項,並把它們新增到一個列表。這就是註冊的過程。在所有物件都註冊以後,主程式就可以開始呼叫它們的方法。

  1. >>> plugins =[]
  2. >>>for cls inPlugin.__subclasses__():
  3. obj = cls()
  4. ... plugins.append(obj)
  5. ...
  6. plugin 1
  7. plugin 2
  8. >>> plugins
  9. [<__main__.MyPlugin1 object at 0x10048c8d0>,<__main__.MyPlugin2 object at 0x10048c910>]
  10. >>>

所以,發現和註冊的過程是按下面的步驟進行:

  • 所有的外掛類都從同一個基類繼承,這個基類被看作是外掛管理器。
  • 外掛管理器匯入一個或者多個包含外掛類定義的模組。
  • 外掛管理器呼叫基類方法__subclass__(),發現所有外掛類(這些類都已通過模組匯入)。
  • 外掛管理器建立例項。

我們現在有了一些問題需要解決。首先,外掛類需要被存放在一個獨立的位置,最好是單獨的檔案中。這樣你可以放心的安裝新的外掛,以及移除過時的外掛,而不必擔心會不小心覆蓋應用程式檔案。所以,我們需要一種機制來匯入任意的包含外掛類定義的Python模組。你可以使用Python內建的__import__,在執行時以模組名來載入一個模組。不過,模組檔案需要放在Python系統的搜尋路徑下。
讓我們就從管理器類的初始化開始。我們將會允許主應用程式傳遞任何的可選引數給外掛物件。這樣,外掛物件就可以執行任何它們需要的執行時初始化。我們完全不知道這些引數是什麼,或者有沒有。因此,我們將只傳遞關鍵字引數來,來代替列表結構中的實際引數。管理器的__init__()方法接受一個字典引數,並將其傳遞給初始化外掛的函式。
我們還需要知道外掛檔案的位置。它可以作為引數傳遞給管理器的建構函式。在這種情況下,它應該是一個絕對路徑。否則,我們將假設一個相對於指令碼位置的名為/ plugins /子目錄:

  1. classPluginManager():
  2. def __init__(self, path=None, plugin_init_args={}):
  3. if path:
  4. self.plugin_dir = path
  5. else:
  6. self.plugin_dir = os.path.dirname(__file__)+'/plugins/'
  7. self.plugins =[]
  8. self._load_plugins()
  9. self._register_plugins(**plugin_init_args)

下一步是將所有的外掛檔案載入為模組。每一個Python應用程式都可以以模組載入。所以,其中所有的方法和類對主應用程式都是可用的。我們不能使用慣常的import語句來載入這些檔案,因為只有在執行時我們才知道它們的名字。所以,我們會使用內建的__import__方法,它允許我們使用一個包含模組名字的變數。但是,這個方法與import方法是一樣的,都意味著試圖載入的模組需要位於Python的一個搜尋路徑之下。顯然,並非一定如此。因此,我們需要將包含外掛模組的目錄新增到系統路徑。那麼,我們可以通過向sys.path陣列追加目錄來做到:

  1. def _load_plugins(self):
  2. sys.path.append(self.plugin_dir)
  3. plugin_files =[fn for fn in os.listdir(self.plugin_dir)if
  4. fn.startswith('plugin_')and fn.endswith('.py')]
  5. plugin_modules =[m.split('.')[0]for m in plugin_files]
  6. for module in plugin_modules:
  7. m = __import__(module)

最後,我們使用__subclass__()方法發現從基類繼承的類,並將例項化後的物件新增到外掛列表中。注意,我們向外掛傳遞的是關鍵字引數:

  1. def _register_plugins(self,**kwargs):
  2. for plugin inPlugin.__subclasses__():
  3. obj = plugin(**kwargs)
  4. self.plugins.append(obj)

在這裡,我們使用了關鍵字引數。這是因為我們不知道外掛類需要的或者使用的引數究竟是什麼,或者有哪些。此外,這些模組會使用或識別不同的引數。使用關鍵字引數,允許模組只對它們感興趣的引數做出反應。程式碼清單6-1顯示了外掛管理器的完整清單。

清單6-1. 外掛的發現和註冊

  1. #!/usr/bin/env python
  2. import sys
  3. import os
  4. classPlugin(object):
  5. pass
  6. classPluginManager():
  7. def __init__(self, path=None, plugin_init_args={}):
  8. if path:
  9. self.plugin_dir = path
  10. else:
  11. self.plugin_dir = os.path.dirname(__file__)+'/plugins/'
  12. self.plugins =[]
  13. self._load_plugins()
  14. self._register_plugins(**plugin_init_args)
  15. def _load_plugins(self):
  16. sys.path.append(self.plugin_dir)
  17. plugin_files =[fn for fn in os.listdir(self.plugin_dir)if \
  18. fn.startswith('plugin_')and fn.endswith('.py')]
  19. plugin_modules =[m.split('.')[0]for m in plugin_files]
  20. 相關推薦

    Apache日誌檔案收集提供統計資料一個Python外掛架構簡單實現

    從Apache的日誌檔案收集和提供統計資料 這一章我們將介紹基於外掛程式的架構和實現。作為例子,我們將構建一個分析Apache伺服器log檔案的框架。這一次我們不再使用微控制器的方式來建立,而是改為採用模組化的方式。一旦我們有了一個基本框架,我們就可以為它建立一

    任意一個英文的純文本文件,統計其中的單詞出現的個數shell python 兩種語言實現

    統計文本英文單詞個數 python shell sort uniq 現有plain text titled test.txt,統計其中的單詞出現的個數。 test.txt的內容: i have have application someday oneday day demo i have some one c

    求兩個整數的最大公約數最小公倍數通過呼叫自定義函式實現

    >#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> int yue(int x, int y); //int yue_2(int

    統計apache日誌檔案裡訪問量前十的ip並按多到少排列

    五月 31, 2012 by FandLR Filed under Linux Leave a comment 解法1: cat access_log | awk ’{print $1}’ | sort | uniq -c | sort -n -r |

    Flume NG原始碼分析使用ExecSource本地日誌檔案收集日誌

    常見的日誌收集方式有兩種,一種是經由本地日誌檔案做媒介,非同步地傳送到遠端日誌倉庫,一種是基於RPC方式的同步日誌收集,直接傳送到遠端日誌倉庫。這篇講講Flume NG如何從本地日誌檔案中收集日誌。 ExecSource是用來執行本地shell命令,並把本地日誌檔案中的資料封裝成Event

    80埠常被佔用的程式 。Apache如何每天生成獨立日誌檔案(access_logerror_log)。magic_quotes_runtime,get_magic_quotes_gpc,ini_

    80埠常被佔用的程式  1,iis不我說,停止即可. 2.安裝sqlserver 2008 後,SQL Server Reporting Services佔用, 3.安裝VS後,MSDEPLOYAGENTSERVICE/佔用 安裝WebDeploy 安裝WebDeplo

    oracle 12c 關閉統計信息收集啟用統計信息收集

    ces dba gin enable cti ucc space 收集 pre oracle 12c 關閉統計信息收集和啟用統計信息收集 --關閉統計信息 col client_name for a60 select client_name,status from DBA_

    shell指令碼限制日誌檔案大小行數

    背景: 專案server在後端持續執行,日誌檔案不斷變大,需及時進行清空。 解決方案:編輯sh指令碼,指定時間間隔輪詢;將超出限制的日誌檔案,先備份,再清空原日誌檔案內容。 清空日誌檔案內容的方法有:             1

    使用mysqlbinlog二進位制日誌檔案中查詢mysql執行過的sql語句

    前提MySQL開啟了binlog日誌操作1. 檢視MySQL是否開啟binlog(進mysql操作)  mysql> show variables like 'log_bin%';       2. 查詢binlog檔名 &nbs

    定時儲存apache日誌檔案

    之前在寫程式碼的時候,發現apache的日誌檔案太大了,就想寫個指令碼定時備份apache日誌檔案。 需要注意,檔案在備份之後,如果直接刪除原日誌檔案,因為apache還是持有原檔案的控制代碼,如果不重啟apache,後面的日誌將會寫入不進去。解決方案是不刪除原日誌檔案,而

    Jenkins高階篇之Pipeline實踐篇-9-SeleniumJenkins持續整合-日誌檔案歸檔外掛rebuild介紹--完結篇

    寫到這裡,我記得我前面提出的兩個需求,引數化構建和報告和日誌顯示就差一個日誌檔案顯示了。本篇就先來介紹如何在jenkins上提供日誌檔案下載,第二個介紹一下rebuild外掛。如果一個jenkins job有十個以上的引數化構建,那麼下一次構建,選擇rebuild選單是最方便,rebuild選單

    Android 應用崩潰日誌收集上傳

    如何將應用崩潰日誌收集起來? Android 應用難以避免的會 crash ,也稱為崩潰,無論你的程式多完美,總是無法避免 crash 的發生。這對使用者來說是很不友好的,也是開發者所不願意看到的。更糟糕的是,當用戶發生了 crash ,開發者卻不知道程式為何

    Flume-ng+Hbase實現日誌收集儲存

    flume ng 日誌處理並存入資料庫: flume-ng裡面的SimpleHbaseEventSerializer只提供了最簡單的資料插入hbase功能,如果還有其他需要,就得自己寫HbaseEve

    CentOS Linux系統下apache日誌檔案設定每天單獨生成一個日誌檔案

    vi /etc/httpd/conf/httpd.conf  #編輯檔案 #ErrorLog logs/error_log  #註釋此行,新增下面這行 ErrorLog "|rotatelogs /var/log/httpd/error_log%Y%m%d.log 8

    使用Servlet微信小程式請求的檔案流獲取檔案內容表單資料

    說明:專案中用到微信小程式上傳檔案,發現檔案放在流中,Struts中request經過封裝無法獲取到此檔案流,嘗試用servlet解決package com.web; import java.io.File; import java.io.FileOutputStream;

    Apache Kafka核心元件流程-協調器消費者組協調器-設計-原理入門教程輕鬆學

    作者:稀有氣體 來源:CSDN 原文:https://blog.csdn.net/liyiming2017/article/details/82805479 版權宣告:本文為博主原創文章,轉載請附上博文連結! 本入門教程,涵蓋Kafka核心內容,通過例項和大量圖表,幫助學習

    收集 Kubernetes 資源統計資料的新工具

    零配置工具簡化了資訊收集,例如在某個名稱空間中運行了多少個 pod。 最近我在紐約的 O'Reilly Velocity 就 Kubernetes 應用故障排除的主題發表了演講,並且在積極的反饋和討論的推動下,我決定重新審視這個領域的工具。結

    STM32 標準韌體庫的下載,檔案介紹工程的建立綜合

    前言 博文基於ARM Cortex-M3核心的STM32F103ZET6晶片和標準3.5.0庫; 博文介紹標準庫中個資料夾的含義和以及一個簡單工程的建立; 如有不足之處還請博友多多指教; 標準庫的下

    PCD檔案中讀取點雲資料Reading Point Cloud data from PCD files

    在本教程中,我們將學習如何從PCD檔案中讀取點雲資料。 #程式碼 首先,在你最喜歡的編輯器中建立一個名為pcd_read.cpp的檔案,並在其中放置下面的程式碼: #include <iostream> #include <pcl/io/pcd

    node檔案讀取過濾、篩選filter

    在node開發過程中,我們經常需要對檔案進行讀取,寫入,以及檔案的引入等相關操作和需求,那麼我們就需要去讀取我們的目錄檔案,並對其加以過濾,得到我們的目標檔案,但是我們要怎麼樣高效率的進行檔案的過濾呢,下面我們介紹了一種方法: 首先我們需要匯入fs模組,然後用readdirSync列出檔案