2008-11-07 49 views
0

我有一個有趣的問題,並會感謝您的想法的最佳解決方案。 我需要解析一組日誌。日誌由多線程程序生成,單個進程週期生成多行日誌。如何解析由多個線程寫入的日誌?

解析這些日誌時,我需要從每個進程中提取特定的信息 - 當然這些信息是跨越多行的(我想將這些數據壓縮成一行)。由於應用程序是多線程的,因此屬於某個進程的行塊可以作爲其他進程碎片化,同時寫入同一個日誌文件。

幸運的是,每一行都給出了一個進程ID,所以我能夠區分哪些日誌屬於哪個進程。

現在,已經有幾個解析器都擴展了相同的類,但被設計爲從單個線程應用程序(沒有碎片 - 從原始系統)讀取日誌,並在超類中使用readLine()方法。這些解析器將繼續讀取行,直到所有正則表達式匹配一行行(即在單個處理週期中寫入的行)爲止。

那麼,我可以用超級類做些什麼,以便它可以管理碎片日誌,並確保對現有已實現的解析器的更改最小化?

回答

2

這聽起來像是有一些現有的解析器類已經在使用,你希望利用。在這種情況下,我會爲分析器編寫一個decorator,該分析器刪除與正在監視的進程無關的行。

這聽起來像你的類可能是這樣的:

abstract class Parser { 
    public abstract void parse(...); 
    protected String readLine() { ... } 
} 

class SpecialPurposeParser extends Parser { 
    public void parse(...) { 
     // ... special stuff 
     readLine(); 
     // ... more stuff 
    } 
} 

而且我會寫這樣的:

class SingleProcessReadingDecorator extends Parser { 
    private Parser parser; 
    private String processId; 
    public SingleProcessReadingDecorator(Parser parser, String processId) { 
     this.parser = parser; 
     this.processId = processId; 
    } 

    public void parse(...) { parser.parse(...); } 

    public String readLine() { 
     String text = super.readLine(); 
     if(/*text is for processId */) { 
      return text; 
     } 
     else { 
      //keep readLine'ing until you find the next line and then return it 
      return this.readLine(); 
     } 
    } 

然後要修改任何事件將用於這樣的:

//old way 
Parser parser = new SpecialPurposeParser(); 
//changes to 
Parser parser = new SingleProcessReadingDecorator(new SpecialPurposeParser(), "process1234"); 

此代碼片段很簡單且不完整,但可以讓您瞭解裝飾器pa ttern可以在這裏工作。

0

您需要臨時將線存儲在單個線程使用它們的隊列中,並在每個線程集完成後傳遞它們。如果無法通過行數或行內容知道集合是否完整,則可以考慮使用滑動窗口技術,在這種技巧中,您不會收集單個集合,直到某個時間過後已經過去了。

0

會這樣嗎?它爲日誌文件中的每個進程ID運行一個新線程。

class Parser { 
    String currentLine; 
    Parser() { 
     //Construct parser 
    } 
    synchronized String readLine(String processID) { 
     if (currentLine == null) 
     currentLine = readLinefromLog(); 

     while (currentline != null && ! getProcessIdFromLine(currentLine).equals(processId) 
     wait(); 

     String line = currentLine; 
     currentLine = readLinefromLog(); 
     notify(); 
     return line; 
    } 
} 

class ProcessParser extends Parser implements Runnable{ 
    String processId; 
    ProcessParser(String processId) { 
     super(); 
     this.processId = processId; 
    } 

    void startParser() { 
     new Thread(this).start(); 
    } 

    public void run() { 
     String line = null; 
     while ((line = readLine()) != null) { 
      // process log line here 
     } 
    } 

    String readLine() { 
     String line = super.readLine(processId); 
     return line; 
    }  
0

一個簡單的解決方案可能是逐行讀取文件並寫入多個文件,每個文件對應一個進程ID。進程ID列表可以保存在內存中的散列映射中,以確定是否需要新文件,或者確定某個進程ID的行是否已經創建了文件。一旦所有(臨時)文件都被寫入,現有的解析器就可以在每個文件上完成這項工作。

1

我會寫一個簡單的分配器,逐行讀取日誌文件並將它們存儲在內存中的不同VirtualLog對象中 - 一個VirtualLog是一種虛擬文件,實際上只是一個字符串或現有解析器可以應用於。虛擬日誌存儲在以進程ID(PID)爲關鍵字的Map中。當你從日誌中讀取一行時,檢查PID是否已經存在。如果是這樣,請將該行添加到PID各自的VirtualLog。如果沒有,創建一個新的VirtualLog對象並將其添加到地圖。解析器作爲獨立的線程運行,每個虛擬日誌上都有一個線程運行。每一個VirtualLog對象一旦被完全解析,就會被銷燬。