syslog日誌系統——日誌採集
阿新 • • 發佈:2018-12-20
日誌採集的流程
客戶端埋點
客戶端埋點就是在客戶系統植入日誌傳送的程式碼,可以是前端頁面、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);
}
}
日誌彙總
通過定時任務,把各個採集點的日誌文字匯入資料庫/大資料儲存。