高吞吐koa日誌中間件

Midlog中間件

node服務端開發中少不了日誌打點,而在koa框架下的日誌打點在多進程環境中日誌信息每每沒法對應上下文,並且在高併發下直接進行寫buffer操做(內核調用writev)也會形成內存泄漏,所以Midlog就是爲了緩解這種問題而產生的,其採用多種緩衝調度策略儘量下降writev的代價,減緩內存溢出的速率。node

1

日誌系統的三個關鍵要素:穩定、性能和易用。數組


2

當前log4js遇到的問題。緩存


3

設計新系統的前提。架構


4

回顧node原生模塊--「流」的讀與寫,涉及到了多個緩衝區以及他們緩衝區的實現(stream2.0的 Transform流同時包括了讀寫緩衝區)併發


5

優化點與優化方式。app


6

Midlog系統架構圖,其中reqContainer收集同一個上下文的日誌信息並轉碼;框架

StrategyMaker負責制定雙緩衝緩存策略和超時刷新以及強制刷新策略;koa

Writeable則負責真正的寫buffer操做,內部經過鏈表保存數據;函數


7

詳細介紹每一個模塊的功能。高併發


快速使用

app.js

var koa = require('koa');
var midlog = require('midlog');
var app = koa();

// 配置日誌中間件
var firstValve = midlog({
  env: 'online',
  exportGlobalLogger: true,
  appender: [{
    type: 'INFO',
    logdir: '/tmp/log/midlog',
    pattern: '%d %r %x{name}:%z %p - %m%n',
    rollingFile: false,
    duation: 60000,
    name: 'info.log',
    nameformat: '[info.]HH-mm-ss[.log]',
    tokens: {
      name: 'helloworld'
    },
    cacheSize: 5 * 1024 * 1024,
    flushTimeout: 15000
  },{
  type: 'ERROR',
    logdir: '/tmp/log/midlog',
    pattern: '%d %r %x{name}:%z %p - %m%n',
    rollingFile: false,
    duation: 60000,
    name: 'error.log',
    nameformat: '[info.]HH-mm-ss[.log]',
    tokens: {
      name: 'helloworld'
    },
    cacheSize: 10240,
    flushTimeout: 10000
},{
    type: 'TRACE',
    logdir: '/tmp/log/midlog',
    pattern: '%d %r %x{name}:%z %p - %m%n',
    rollingFile: false,
    duation: 60000,
    name: 'trace.log',
    nameformat: '[info.]HH-mm-ss[.log]',
    tokens: {
      name: 'helloworld'
    },
    cacheSize: 5 * 1024 * 1024,
    flushTimeout: 10000
  }]
});

// 使用全局的logger接口
logger.info('i am the global logger');

// 將midlog放在中間件的前列
app.use(firstValve);

// 業務中間件
app.use(function*(next){
  this.logger.info(this.url+' this is the first valve!! ');
  this.logger.error('midlog tracing' + this.url+' this is the first valve!! ');
  this.logger.trace('midlog tracing' + this.url+' this is the first valve!! ');
  yield next;
});

app.use(function*(){
  this.logger.info(this.url+' this is the 2cd valve!! ');
  this.logger.error('midlog tracing' + this.url+' this is the 2cd valve!! ');
  this.logger.trace('midlog tracing' + this.url+' this is the 2cd valve!!');
  this.body = '<h1>hello midlog</h1>';
});

app.listen(8888);

功能

midlog提供了3種日誌刷新級別:

TRACE、INFO、ERROR

而且提供了兩種寫日誌文件的方式:

  • 單文件寫 (經過設置appender的rollingFile爲false觸發)

  • 文件分時間片寫 (經過設置appender的rollingFile爲true觸發)

midlog採用和log4js相同的layout格式和語法,生成可定製的日誌輸出格式。

最後,midlog採用多級緩衝的架構(針對單文件寫模式採用雙緩衝,文件分時寫模式採用單緩衝),能夠有效的控制Stream寫的頻率,而緩衝的大小和刷新頻率能夠由開發者根據實際須要自由設置。

配置

  • env {String} 環境設置。若設置爲development,則會在控制檯和文件中同時輸出日誌

  • exportGlobalLogger {Boolean} 是否保留全局logger對象。設置爲true,則在全局使用logger對象

  • appender {Array} 日誌類型配置數組。數組每一項描述每種類型日誌的相關信息及緩衝刷新頻率

appender詳解

  • type {String} 日誌類型。能夠爲 「INFO、TRACE和ERROR」 任意一種

  • logdir {String} 日誌文件所在的絕對目錄

  • rollingFile {Boolean} 是否按照時間進行日誌文件分割。設置爲true時則按照設置的duration間隔分割文件

  • duration {Number} 分割日誌文件的間隔。若rollingFile爲true,則按照duration大小分割文件

  • name {String} 日誌文件名稱。name屬性在單文件寫模式下有效,在rollingFile == true時無效

  • nameformat {String} 日誌文件格式匹配定義。nameformat屬性在文件分時間片寫模式下有效,即rollingFile == true
    格式定義的字符串意義以下所示:
'd': 日期和時間,
'h': 主機名稱,
'm': 日誌信息格式化,主要優化錯誤輸出,
'n': 換行符,
'p': 日誌級別,
'r': 時間輸出,
'z': 進程號輸出,
'%': 百分號佔位符,
'x': 用戶自定義變量或函數,搭配{token}屬性
  • tokens {Object} 與nameformat搭配使用,對象的屬性值可爲常亮,也可爲函數

如定義nameformat爲 pattern: '%d %r %x{name}:%z %p - %m%n' 且tokens設置爲 {name: 'helloworld'}

則輸出日誌格式爲:

(%d) (%r) (%x{name}) (%z) (%p) (%m) (%n)
2017-01-16 10:59:55.611 10:59:55 helloworld:13736 INFO - / this is the first valve!!
  • cacheSize {Number} 緩衝大小,單位字節。midlog在單文件寫模式下采用雙緩衝結構控制I/O速率,所以開發者能夠經過定義緩衝大小實現高效的寫入流程,默認爲10kB大小;在文件分時間片寫模式下該選項無效

  • flushTimeout {Number} 緩衝刷新間隔。在單文件寫文件分時間片寫兩種模式下都起做用,定點刷新緩衝

相關文章
相關標籤/搜索