2017-08-01 68 views
1

我想監視查詢在我的API數據庫上花費的時間。我創建了以下函數,使用書架信號,Bookshelf插件。 :跟蹤數據庫查詢時間 - Bookshelf/knex

bookshelf.on('fetching',() => { 
    server.app.fetching = new Date().valueOf(); 
}); 

bookshelf.on('counting',() => { 
    server.app.fetching = new Date().valueOf(); 
}); 

bookshelf.on('fetched',() => { 
    server.statsd.gauge('db_query', new Date().valueOf() - server.app.fetching); 
}); 

......這樣我就可以檢索到剛獲取/計數之前和之後的時間;我做了同樣的刪除刪除和保存保存。

我覺得我無法理解的是獲取和取出都應該被觸發...當我試着看時獲取並取出被觸發時,基本上結束了與此:

'fetching event A' 
'fetching event B' 
'fetching event C' 
'fetched event C' 
'fetched event B' 
'fetched event A' 

導致計時器不經意地返回錯誤的值,你有任何線索/線索嗎?

我也看到可以在Knex上觸發'查詢'事件,並且認爲使用這個作爲替代解決方案。然而,它似乎只有當我指定我查詢表,即作品:

knex('whatever_table').on('query',() => {///}); 

使其成爲行不通的情況下,我想在每一個模型應用的事件處理程序... 我想我應該堅持使用Bookshelf,但我怎麼處理事件的處理方式?

預先感謝您!

回答

1

我剛剛寫了一些小測試代碼如何跟蹤與knex的交易時間。

https://runkit.com/embed/679qu91ylu4w

/** 
* Calculate transaction durations in knex 
* 
*/ 
require('sqlite3'); 
var knex = require("knex")({ 
    client: 'sqlite', 
    connection: ':memory:', 
    pool: { min: 1, max: 10 } 
}); 

function isTransactionStart(querySpec) { 
    return querySpec.sql === 'BEGIN;'; 
} 

function isTransactionEnd(querySpec) { 
    return querySpec.sql === 'COMMIT;' || querySpec.sql === 'ROLLBACK;'; 
} 

const transactionDurations = {}; 

knex.on('query', querySpec => { 
    console.log('On query', querySpec); 

    if (isTransactionStart(querySpec)) { 
    if (transactionDurations[querySpec.__knexUid]) { 
     console.error('New transaction started, before earlier was ended'); 
     return; 
    } 
    transactionDurations[querySpec.__knexUid] = new Date().getTime(); 
    } 

    if (isTransactionEnd(querySpec)) { 
    const startTime = transactionDurations[querySpec.__knexUid]; 
    if (!startTime) { 
     console.error('Transaction end detected, but start time not found'); 
    } 
    const endTime = new Date().getTime(); 
    transactionDurations[querySpec.__knexUid] = null; 
    console.log('TRANSACTION DURATION', endTime - startTime); 
    } 
}); 

// just as an example of other available events to show when they are called 
knex.on('query-response', (res, querySpec) => { 
    // console.log('On query response', res, querySpec); 
}); 

knex.on('query-error', (err, querySpec) => { 
    // console.log('On query error', err, querySpec); 
}); 

try { 
    a = await Promise.all([ 
     knex.transaction(trx => { 
     return trx.raw('select 1'); 
     }), 
     knex.transaction(trx => { 
     return trx.raw('select 2'); 
     }), 
     knex.transaction(trx => { 
     return trx.raw('error me'); 
     }) 
    ]); 
} catch (e) { 
    console.log('Got ERROR:', e); 
} 

的方法相同的國王也應該工作了查詢時間。爲了防止定時器簿記泄漏內存,你應該添加一些清理代碼。

查詢持續時間定時器應在query事件中啓動,並在query-responsequery-error中停止,具體取決於哪一個先觸發。

爲了能夠匹配query - query-responsequerySpec.__knexQueryUid屬性可以使用。

+0

發送DB時間我不知道knex.on()可以實際使用,使一切更容易! 我把我用於特殊情況的代碼放在回覆中:) – smgr

0

基於的MikaelLepistö片斷,我想出了這一點:

const dbEvents = (server, sdc) => { 
    knex.on('query', data => { 
    server.app[data.__knexQueryUid + ''] = new Date().valueOf(); 
    }); 

    knex.on('query-response', (data, obj, builder) => { 
    sdc.counter('db_queries_time', new Date().valueOf() - server.app[obj.__knexQueryUid + '']); 
    sdc.increment('nr_db_queries'); 
    }); 
}; 

然後我調用函數時我啓動服務器 - 我與Hapijs工作。

編輯:SDC是statsd客戶端,我用它來:)