1. 程式人生 > >syslog日誌系統——日誌採集

syslog日誌系統——日誌採集

日誌採集的流程

日誌採集流程

客戶端埋點

客戶端埋點就是在客戶系統植入日誌傳送的程式碼,可以是前端頁面、app介面、後端服務等,把需要的日誌資訊傳送到指定的日誌採集介面。 日誌的傳送應該採用非同步方式,這樣不會對客戶系統程式碼的執行造成影響。

日誌採集

日誌採集介面把接收過來的日誌資料寫入到日誌檔案,日誌檔案以天為單位進行儲存。

日誌採集介面程式碼

介面採用@IgnoreToken標記不需要進行令牌校驗。 採用@CrossOrigin標記,讓介面能夠跨域訪問,支援AJAX跨域請求。

    @ApiOperation(value = "提交日誌")
    @ApiImplicitParams({
            @ApiImplicitParam
(name = "logData", value = "日誌資料", dataType = "LogData", paramType = "body") }) @RequestMapping(path = "/log/add", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") @IgnoreToken @CrossOrigin public ResponseData addLog(@RequestBody LogData logData) { String logID =
logService.logToFile(logData); return ResponseData.success(logID); }

日誌檔案格式的設計

日誌以文字格式儲存,每條日誌按行寫入。 日誌行的格式如下:

時間戳|日誌ID|日誌資料JSON

日誌格式截圖 日誌按行儲存的好處是,可以利用BufferedReader的readLine方法進行日誌的按行讀取。 日誌按行儲存,要對日誌資料JSON部分進行處理,把換行符替換掉。

日誌按行儲存的主要程式碼

    public String logToFile(LogData logData){
        LogGroupData groupData =
getLogGroup(logData.getKey()); logData.setGroupID(groupData.getGroupID()); String date = ConvertUtil.formatDate(new Date(), "yyyyMMdd"); String path = PathUtil.combine(logFolder, "LOG" + date + ".log"); String uuid = UUID.randomUUID().toString(); String json = JSON.toJSONString(logData); StringBuilder sb = new StringBuilder(); sb.append("[" + ConvertUtil.formatDate(new Date()) + "]|"); sb.append(uuid + "|"); for (int i = 0; i < json.length(); i++) { char c = json.charAt(i); if (c == '\r' || c == '\n')//換行符替換為空格 sb.append(" "); else sb.append(c); } FileUtil.appendLine(path, sb.toString()); return uuid; }

日誌寫入檔案的主要程式碼

利用RandomAccessFile類寫入,用檔案瑣控制併發。如果是海量日誌的場合,可以部署多幾個採集點。

    public static void appendLine(String path, String line) {

        RandomAccessFile fout = null;
        FileChannel channel = null;
        try {
            File file = new File(path);
            if (!file.getParentFile().exists()) {
                file.getParentFile().mkdirs();
            }
            byte[] bytes = line.getBytes("utf-8");
            fout = new RandomAccessFile(file, "rw");
            long filelength = fout.length();//獲取檔案的長度
            fout.seek(filelength);//將檔案的讀寫指標定位到檔案的末尾
            channel = fout.getChannel();//開啟檔案通道
            FileLock fileLock = null;
            while (true) {
                try {
                    fileLock = channel.tryLock();//不斷的請求鎖,如果請求不到,等一秒再請求
                    break;
                } catch (Exception e) {
                    logger.error("[FileUtil.appendLine]請求瑣失敗。");
                    Thread.sleep(1000);
                }
            }
            fout.write(bytes);
            fout.writeChar('\n');
            fileLock.release();
            channel.close();
            fout.close();

        } catch (Exception e1) {
            logger.error(e1.getMessage(), e1);
        } finally {
            IOUtil.close(channel);
            IOUtil.close(fout);
        }
    }

日誌彙總

通過定時任務,把各個採集點的日誌文字匯入資料庫/大資料儲存。