多行日誌合併處理的內外存方法

上一講中,咱們介紹瞭如何用SPL將一行日誌結構化爲一條記錄,今天則要說一下多行日誌對應一條記錄的狀況,咱們稱之爲不定行日誌。node

 

事實上,集算器本身的輸出日誌就是這種不定行日誌,咱們來看一下集算器節點機下的一個日誌文件rqlog. log,一樣摘錄兩段日誌:函數

[2018-05-14 09:20:20]性能

DEBUG: 臨時文件過時時間爲:12小時。fetch

 

[2018-05-14 09:20:20]線程

DEBUG: Temporary file directory is:日誌

D:\temp\esProc\nodes\127.0.0.1_8281\temp.blog

Files in temporary directory will be deleted on every 12 hours.內存

簡單分析一下這兩段日誌,每一段第一行都是方括號中的時間,緊接着第二行是用冒號分隔的日誌類型和日誌內容,隨後各行都是日誌內容的補充,直至遇到下一個方括號中的時間行。由此能夠肯定,結構化後的字段應該有三個:日誌時間日誌類型日誌內容get

對於這種不定行的日誌,最直接的結構化思路就是逐行加載,並根據條件拼接成相應的字段。但這裏有個麻煩,因爲每條記錄對應的行數不肯定,因此須要另外經過條件判斷來識別每條記錄的起始行。另外一個問題就是當使用遊標分析比較大的文件時,因爲每次fetch的行數不可能老是恰好斷在一條記錄的末尾,因此在fetch的塊與塊之間還要考慮銜接問題。table

因此,對於這種類型的日誌,最理想的方法,是應該能把每一塊日誌與其它塊自動分開。這樣,就能夠直接將每一塊日誌解析到一條記錄,而不須要考慮讀取的行應該屬於上一條記錄仍是下一條記錄。

SPL中就有這樣的分組方式,形如A.group@i(exp),只不過其中的分組表達式exp不能返回枚舉值,而應該返回布爾值。而i選項則表示根據相鄰行計算exp,若是返回true就表示創建一個新組,其後面連續返回false的行都歸於這個組。

有了這樣的分組方式,咱們只要寫出能解析記錄第一行的exp就能夠了。本例中,記錄第一行是以方括號「[」開始的一個日期時間,若是可以肯定後面的內容中不會有以「[」開始的行,那麼分組表達式只需判斷每一行的第一個字符是否爲‘[’就能夠了。

下面是實現的腳本文件convertlog.dfx:

 

A

B

C

D

1

=create(日誌時間, 日誌類型, 日誌內容 )

=now()

   

2

=file@s(fileName:"UTF-8")

=A2.read@n()

=B2.select(~!="")

=C2.group@i(pos(~,"[")==1)

3

=A2.name()

=filename@d(A3)

=filename@n(A3)

 

4

=outFile=B3+"\\"+C3+".btx"

=file(outFile)

>movefile(B4)

 

5

       

6

for D2

=0

   

7

 

for A6

>B6=B6+1

 

8

   

if B6==1

=mid(B7,2,19)

9

     

>A5=datetime(D8,"yyyy-MM-dd   HHss")

10

     

next

11

   

if B6==2

>B5=substr@l(B7,":")

12

     

>C5=C5|substr(B7,":")

13

     

next

14

   

>C5=C5|B7

 

15

 

>A1.record([A5:C5])

>C5=[]

 

16

 

if A1.len()>99999

 

17

   

>B4.export@ab(A1)

18

   

>D4=D4+A1.len()

>output("轉換完成:"/D4)

19

   

>A1.reset()

 

20

>D4=D4+A1.len()

>B4.export@ab(A1)

>output("轉換完成:"/D4)

 

21

=now()

=interval@ms(B1,A21)

Return

 

22

>output("轉換爲 "+outFile+" 成功。耗時 "/B21+" 毫秒。")

表(1)

腳本仍然是一次性將文件所有讀入,只是在分析過程當中,每湊夠十萬行就將其追加到輸出文件。下面是重點代碼的解析:

1)         C2過濾空行,日誌的塊與塊之間可能有不少空行,此處用select函數選出非空行。

2)         D2是本例的重點,按照每一行是否由‘[’開頭來進行分組,分組後的結果是每一塊對應一個序列,再由這些塊序列組成一個大的序列。

3)         第5行空了出來,實際上是預留A5到C5來容納解析後的3個字段。

4)         因爲D2返回的序列已是按照記錄對應的塊作好分組了,因此只需在A6中對D2序列循環便可。

5)         B7到C14將每一塊日誌結構化到各個字段。

6)         A20到C20將最後一段不夠十萬行的數據,寫到文件。

 

下面是當前代碼的執行結果:

                                              undefined

圖(1)

 

上面這個例子介紹瞭如何用分組來結構化不定行的日誌。不過,分析前仍然導入了整個文件,佔用的內存較大。爲了減小內存佔用,咱們可使用遊標來處理。和上面這個例子很是相似,從文件獲得遊標後,緊接着的是和序列幾乎同樣的過濾、分組方法。細微的區別是因爲遊標中返回的分組是序表,而再也不是序列,所以須要用字段名‘_1’來引用各行的值。另外,使用遊標後,每次fetch獲得的是一個序表的序列,所以相對於全文導入,要多一層循環處理。

下面是實現的腳本文件convertLogCursor.dfx:

 

A

B

C

D

E

1

=create(日誌時間, 日誌類型, 日誌內容 )

=now()

     

2

=file@s(fileName:"UTF-8")

=A2.cursor@s()

=B2.select(_1!="")

=C2.group@i(pos(_1,"[")==1)

 

3

=A2.name()

=filename@d(A3)

=filename@n(A3)

   

4

=outFile=B3+"\\"+C3+".btx"

=file(outFile)

>movefile(B4)

   

5

         

6

for C2,10000

for A6

=0

   

7

   

for B6

>C6=C6+1

 

8

     

if C6==1

=mid(C7._1,2,19)

9

       

>A5=datetime(E8,"yyyy-MM-dd   HHss")

10

       

next

11

     

if C6==2

>B5=substr@l(C7._1,":")

12

       

>C5=C5|substr(C7._1,":")

13

       

next

14

     

>C5=C5|C7._1

 

15

   

>A1.record([A5:C5])

>C5=[]

 

16

   

if A1.len()>99999

 

17

     

>B4.export@ab(A1)

 

18

     

>D4=D4+A1.len()

>output("轉換完成:"/D4)

19

     

>A1.reset()

 

20

>D4=D4+A1.len()

>B4.export@ab(A1)

>output("轉換完成:"/D4)

 

21

=now()

=interval@ms(B1,A21)

   

22

>output("轉換爲 "+outFile+" 成功。耗時 "/B21+" 毫秒。")

表(2)

能夠看到,除了用遊標時,表達式中須要使用缺省字段名‘_1’,以及多了一層循環取數,這個腳本和前面所有讀入文件的方式徹底一致。執行後能夠看到結果也跟convertLog.dfx徹底同樣。

         看到這裏,細心的讀者可能會想到,是否是也能夠像上一講同樣,使用多路遊標來提高性能?答案是確定的,不過須要調整一下方法。若是隻是簡單使用cursor@m返回多路遊標的話,因爲線程遊標是由SPL自動建立的,每一個遊標會被自動分配一段屬於本身的數據,這就有可能會將原本屬於同一條記錄的數據塊,分配給了兩個線程,從而形成線程內部難以處理數據缺失的部分。若是不介意部分數據不完整,那麼能夠稍稍調整一下腳本,直接跳過殘缺的記錄。而若是對數據的完整性要求很嚴格的話,就須要將不完整的記錄頭和記錄尾返回給主程序,讓主程序來集中處理了。但要注意的是多路遊標的各線程遊標是自動建立的,線程之間的順序很差肯定,因此主程序拿到這些不完整的記錄頭和記錄尾,也會由於次序無法肯定而沒法正確銜接。所以,這時就須要改用 fork to(n)語句來主動建立順序線程了。fork語句所在的格子值就是當前線程的序號,而後在代碼段中建立局部遊標,並加載相應的數據段就能夠了。 不過,不管如何都會麻煩一些,因不是很常見,這裏也就再也不舉例了,有興趣的同窗能夠將它做爲一個練習題。

最後總結一下,不定行日誌的處理關鍵是肯定幾行日誌能夠「湊」成一條記錄。而利用集算器SPL中group函數的@i選項,就能夠定義日誌塊的分隔條件,從而簡潔方便地「庖丁解牛」了。

更多精彩內容,詳情請閱讀原文

相關文章
相關標籤/搜索