Nodejs監(jiān)聽日志文件的變化的過程解析
最近有在做日志文件的分析,其中有一個需求:A服務器項目需要用Nodejs監(jiān)聽日志文件的變化,當項目產(chǎn)生了新的日志信息,將新的部分通過socket傳輸?shù)紹服務器項目。socket暫時不做分析。
這個需求很簡單,通過分析我們開始擼碼吧。 在擼碼的過程中還能鞏固所學Nodejs的API,何樂而不為呢?
所用的API
fs.watchFile()
語法
fs.watchFile(filename[, options], listener)
參數(shù)解析
filename <string> | <Buffer> | <URL> ——文件名 options <Object> persistent <boolean> 默認值: true。——是否應該繼續(xù)運行 interval <integer> 默認值: 5007。——輪詢目標的頻率 listener <Function> current <fs.Stats> ——當前值 previous <fs.Stats> ——之前值
監(jiān)視 filename 的更改。 每當訪問文件時都會調(diào)用 listener 回調(diào)。
listener 有兩個參數(shù),當前的 stat 對象和之前的 stat 對象
這些 stat 對象是 fs.Stat 的實例。
要在修改文件(而不僅僅是訪問)時收到通知,則需要比較 curr.mtime 和 prev.mtime。
當 fs.watchFile 操作導致 ENOENT 錯誤時,它將調(diào)用一次監(jiān)聽器,并將所有字段置零(或?qū)⑷掌谠O為 Unix 紀元)。 如果文件是在那之后創(chuàng)建的,則監(jiān)聽器會被再次調(diào)用,且?guī)献钚碌?stat 對象。 這是 v0.10 之后的功能變化。
使用 fs.watch() 比 fs.watchFile
和 fs.unwatchFile
更高效。 應盡可能使用 fs.watch 代替 fs.watchFile 和 fs.unwatchFile。
當 fs.watchFile() 正在監(jiān)視的文件消失并重新出現(xiàn)時,第二次回調(diào)事件(文件重新出現(xiàn))返回的 previousStat 會與第一次回調(diào)事件(文件消失)返回的 previousStat 相同。
這種情況發(fā)生在:
- 文件被刪除,然后又恢復。
- 文件被重命名兩次,且第二次重命名回其原來的名稱。
例子
fs.watchFile('message.text', (curr, prev) => { console.log(`當前的最近修改時間是: ${curr.mtime}`); console.log(`之前的最近修改時間是: ${prev.mtime}`); });
fs.open()
語法
fs.open(path[, flags[, mode]], callback)
參數(shù)解析
path <string> | <Buffer> | <URL> ——文件路徑 flags <string> | <number> 默認值: 'r'。——文件系統(tǒng)標志 mode <integer> 默認值: 0o666(可讀寫)?!O置文件模式(權限和粘滯位),但僅限于創(chuàng)建文件的情況 callback <Function> err <Error> ——錯誤 fd <integer>——文件系統(tǒng)流
fs.read()
語法
fs.read(fd, buffer, offset, length, position, callback)
參數(shù)解析
fd <integer> ——文件系統(tǒng)流 buffer <Buffer> | <TypedArray> | <DataView>——數(shù)據(jù)將寫入的緩沖區(qū) offset <integer>—— buffer 中開始寫入的偏移量 length <integer>——要讀取的字節(jié)數(shù) position <integer>——從文件中開始讀取的位置 callback <Function> err <Error> bytesRead <integer> buffer <Buffer>
fs.createReadStream()
語法
fs.createReadStream(path[, options])
參數(shù)解析
path <string> | <Buffer> | <URL>——文件路徑 options <string> | <Object> flags <string> 默認值: 'r'?!募到y(tǒng)標志 encoding <string> 默認值: null?!址幋a fd <integer> 默認值: null?!募到y(tǒng)流 mode <integer> 默認值: 0o666?!O置文件模式(權限和粘滯位),但僅限于創(chuàng)建文件的情況 autoClose <boolean> 默認值: true?!欠褡詣雨P閉文件描述符 start <integer>——文件讀取的開始位置 end <integer> 默認值: Infinity。——文件讀取的結(jié)束位置 highWaterMark <integer> 默認值: 64 * 1024。
返回: <fs.ReadStream> 參閱可讀流。
如果 autoClose 為 false,則即使出現(xiàn)錯誤,也不會關閉文件描述符。 應用程序負責關閉它并確保沒有文件描述符泄漏。 如果 autoClose 設為 true(默認行為),則在 'error' 或 'end' 事件時將自動關閉文件描述符。
mode 用于設置文件模式(權限和粘滯位),但僅限于創(chuàng)建文件的情況。
例子
讀取sample.txt文件的10個字符
fs.createReadStream('sample.txt', { start: 90, end: 99 });
readLine.createInterface
語法
readline.createInterface(options)
參數(shù)解析
options <Object>
input <stream.Readable> 要監(jiān)聽的可讀流。此選項是必需的。
output <stream.Writable> 將逐行讀取數(shù)據(jù)寫入的可寫流。
completer <Function> 用于 Tab 自動補全的可選函數(shù)。
terminal <boolean> 如果 input 和 output 應該被視為 TTY,并且寫入 ANSI/VT100 轉(zhuǎn)義碼,則為 true。 默認值: 實例化時在 output 流上檢查 isTTY。
historySize <number> 保留的最大歷史記錄行數(shù)。 要禁用歷史記錄,請將此值設置為 0。 僅當用戶或內(nèi)部 output 檢查將 terminal 設置為 true 時,此選項才有意義,否則根本不會初始化歷史記錄緩存機制。 默認值: 30。
prompt - 要使用的提示字符串。默認值: '> '。
crlfDelay <number> 如果 \r 與 \n 之間的延遲超過 crlfDelay 毫秒,則 \r 和 \n 將被視為單獨的行尾輸入。 crlfDelay 將被強制轉(zhuǎn)換為不小于 100 的數(shù)字。 可以設置為 Infinity, 這種情況下, \r 后跟 \n 將始終被視為單個換行符(對于使用 \r\n 行分隔符的文件讀取可能是合理的)。 默認值: 100。
removeHistoryDuplicates <boolean> 如果為 true, 則當添加到歷史列表的新輸入行與舊的輸入行重復時,將從列表中刪除舊行。 默認值: false。
escapeCodeTimeout <number> readline 將會等待一個字符的持續(xù)時間(當以毫秒為單位讀取模糊鍵序列時,可以使用輸入讀取到目前為止形成完整的鍵序列,并且可以采取額外的輸入來完成更長的鍵序列)。 默認值: 500。
這個不需要司機,記住常見的即可,需要的時候查找。
當 flag 選項采用字符串時,可用以下標志:
'a' - 打開文件用于追加。如果文件不存在,則創(chuàng)建該文件。
'ax' - 與 'a' 相似,但如果路徑已存在則失敗。
'a+' - 打開文件用于讀取和追加。如果文件不存在,則創(chuàng)建該文件。
'ax+' - 與 'a+' 相似,但如果路徑已存在則失敗。
'as' - 以同步模式打開文件用于追加。如果文件不存在,則創(chuàng)建該文件。
'as+' - 以同步模式打開文件用于讀取和追加。如果文件不存在,則創(chuàng)建該文件。
'r' - 打開文件用于讀取。如果文件不存在,則出現(xiàn)異常。
'r+' - 打開文件用于讀取和寫入。如果文件不存在,則出現(xiàn)異常。
'rs+' - 以同步模式打開文件用于讀取和寫入。指示操作系統(tǒng)繞過本地的文件系統(tǒng)緩存。
這對于在 NFS 掛載上打開文件時非常有用,因為它允許跳過可能過時的本地緩存。 它對 I/O 性能有非常實際的影響,因此除非需要,否則不建議使用此標志。
這不會將 fs.open() 或 fsPromises.open() 轉(zhuǎn)換為同步的阻塞調(diào)用。 如果需要同步的操作,則應使用 fs.openSync() 之類的。
'w' - 打開文件用于寫入。如果文件不存在則創(chuàng)建文件,如果文件已存在則截斷文件。
'wx' - 與 'w' 相似,但如果路徑已存在則失敗。
'w+' - 打開文件用于讀取和寫入。如果文件不存在則創(chuàng)建文件,如果文件已存在則截斷文件。
'wx+' - 與 'w+' 相似,但如果路徑已存在則失敗。
fs.Stats 對象提供有關文件的信息。
Stats { dev: 2114, ino: 48064969, mode: 33188, nlink: 1, uid: 85, gid: 100, rdev: 0, size: 527, blksize: 4096, blocks: 8, atimeMs: 1318289051000.1, mtimeMs: 1318289051000.1, ctimeMs: 1318289051000.1, birthtimeMs: 1318289051000.1, atime: Mon, 10 Oct 2011 23:24:11 GMT, mtime: Mon, 10 Oct 2011 23:24:11 GMT,
ctime: Mon, 10 Oct 2011 23:24:11 GMT,
birthtime: Mon, 10 Oct 2011 23:24:11 GMT }
開始監(jiān)聽日志文件
前提,在app.js中調(diào)用watchFile方法,將需要監(jiān)聽的文件路徑傳入該方法中。
function watchFile(filename) { console.log('Log monitoring...'); // Open the file for reading and appending fs.open(filename, 'a+', function (err, fd) { if (err) { throw err; } var buffer; fs.watchFile(filename, { persistent: true, interval: 1000 }, (curr, prev) => { // Compare the time before and after if (curr.mtime > prev.mtime) { // console.log(`The current latest revision time is: ${curr.mtime}`); // console.log(`The latest modification time is: ${prev.mtime}`); // Changes in the contents of documents buffer = new Buffer(curr.size - prev.size); // (curr.size - prev.size) this is the newly added length of the log file readFile(fd, buffer, (curr.size - prev.size), prev.size); } }); }); }
讀取新增內(nèi)容
function readFile(fd, buffer, length, position) { // read file fs.read(fd, buffer, 0, length, position, function (err, bytesRead, buffer) { if (err) { log.error(err); } console.log('Additional Contents', buffer.toString()); }); }
額外功能:讀取歷史內(nèi)容
function fetchHistoryLogs(filename) { const rl = readLine.createInterface({ input: fs.createReadStream(filename, { enconding: 'utf8' }), output: null, terminal: false }); rl.on('line', (line) => { if (line) { logsArr.push(line.toString()); } }).on('close', () => { for (var i = 0; i < logsArr.length; i++) { // Print the data for each row console.log(`Original data: \n ${logsArr[i]}`); } }); }
總結(jié)
以上所述是小編給大家介紹的Nodejs監(jiān)聽日志文件的變化的過程解析,希望對大家有所幫助,如果大家有任何疑問歡迎給我留言,小編會及時回復大家的!
相關文章
node.js連接mongoose數(shù)據(jù)庫方法詳解
之前我們都是通過shell來完成對數(shù)據(jù)庫的各種操作的,在開發(fā)中大部分時候我們都需要通過程序來完成對數(shù)據(jù)庫的操作。而Mongoose就是一個讓我們可以通過Node來操作MongoDB的模塊2022-08-08node+koa+canvas繪制出貨單、收據(jù)票據(jù)的方法
在生成票據(jù)需求中,我們會想到前端生成或者后端生成返回圖片地址訪問兩個方法,前端生成則不需要調(diào)用接口,而后端是在完成整個流程時就進行生成然后把上傳的地址保存數(shù)據(jù)庫,這篇文章主要介紹了node+koa+canvas繪制出貨單,收據(jù),票據(jù),需要的朋友可以參考下2022-09-09Nodejs Post請求報socket hang up錯誤的解決辦法
這篇文章主要介紹了Nodejs Post請求報socket hang up錯誤的解決辦法,本文因少加了headers字段信息導致出現(xiàn)這個錯誤,本文給出了一個完整的實現(xiàn)代碼,需要的朋友可以參考下2014-09-09