2020-06-23 13:29:38 -04:00
|
|
|
/* eslint-disable
|
|
|
|
camelcase,
|
|
|
|
*/
|
2020-06-23 13:29:44 -04:00
|
|
|
let EventLogger
|
|
|
|
const logger = require('logger-sharelatex')
|
2020-11-25 06:57:22 -05:00
|
|
|
const metrics = require('@overleaf/metrics')
|
2020-06-23 13:29:44 -04:00
|
|
|
const settings = require('settings-sharelatex')
|
2020-06-23 13:29:34 -04:00
|
|
|
|
|
|
|
// keep track of message counters to detect duplicate and out of order events
|
|
|
|
// messsage ids have the format "UNIQUEHOSTKEY-COUNTER"
|
|
|
|
|
2020-06-23 13:29:44 -04:00
|
|
|
const EVENT_LOG_COUNTER = {}
|
|
|
|
const EVENT_LOG_TIMESTAMP = {}
|
|
|
|
let EVENT_LAST_CLEAN_TIMESTAMP = 0
|
2020-06-23 13:29:34 -04:00
|
|
|
|
|
|
|
// counter for debug logs
|
2020-06-23 13:29:44 -04:00
|
|
|
let COUNTER = 0
|
2020-06-23 13:29:34 -04:00
|
|
|
|
2020-06-23 13:29:44 -04:00
|
|
|
module.exports = EventLogger = {
|
|
|
|
MAX_STALE_TIME_IN_MS: 3600 * 1000,
|
2020-06-23 13:29:34 -04:00
|
|
|
|
2020-06-23 13:29:44 -04:00
|
|
|
debugEvent(channel, message) {
|
|
|
|
if (settings.debugEvents > 0) {
|
|
|
|
logger.log({ channel, message, counter: COUNTER++ }, 'logging event')
|
2020-07-07 06:06:02 -04:00
|
|
|
settings.debugEvents--
|
2020-06-23 13:29:44 -04:00
|
|
|
}
|
|
|
|
},
|
2020-06-23 13:29:34 -04:00
|
|
|
|
2020-07-07 06:06:02 -04:00
|
|
|
checkEventOrder(channel, message_id) {
|
2020-06-23 13:29:44 -04:00
|
|
|
if (typeof message_id !== 'string') {
|
|
|
|
return
|
|
|
|
}
|
2020-07-07 06:06:02 -04:00
|
|
|
let result
|
2020-06-23 13:29:44 -04:00
|
|
|
if (!(result = message_id.match(/^(.*)-(\d+)$/))) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
const key = result[1]
|
|
|
|
const count = parseInt(result[2], 0)
|
|
|
|
if (!(count >= 0)) {
|
|
|
|
// ignore checks if counter is not present
|
|
|
|
return
|
|
|
|
}
|
|
|
|
// store the last count in a hash for each host
|
|
|
|
const previous = EventLogger._storeEventCount(key, count)
|
2020-07-07 06:06:02 -04:00
|
|
|
if (!previous || count === previous + 1) {
|
2020-06-23 13:29:44 -04:00
|
|
|
metrics.inc(`event.${channel}.valid`, 0.001) // downsample high rate docupdater events
|
|
|
|
return // order is ok
|
|
|
|
}
|
|
|
|
if (count === previous) {
|
|
|
|
metrics.inc(`event.${channel}.duplicate`)
|
|
|
|
logger.warn({ channel, message_id }, 'duplicate event')
|
|
|
|
return 'duplicate'
|
|
|
|
} else {
|
|
|
|
metrics.inc(`event.${channel}.out-of-order`)
|
|
|
|
logger.warn(
|
|
|
|
{ channel, message_id, key, previous, count },
|
|
|
|
'out of order event'
|
|
|
|
)
|
|
|
|
return 'out-of-order'
|
|
|
|
}
|
|
|
|
},
|
2020-06-23 13:29:34 -04:00
|
|
|
|
2020-06-23 13:29:44 -04:00
|
|
|
_storeEventCount(key, count) {
|
|
|
|
const previous = EVENT_LOG_COUNTER[key]
|
|
|
|
const now = Date.now()
|
|
|
|
EVENT_LOG_COUNTER[key] = count
|
|
|
|
EVENT_LOG_TIMESTAMP[key] = now
|
|
|
|
// periodically remove old counts
|
|
|
|
if (now - EVENT_LAST_CLEAN_TIMESTAMP > EventLogger.MAX_STALE_TIME_IN_MS) {
|
|
|
|
EventLogger._cleanEventStream(now)
|
|
|
|
EVENT_LAST_CLEAN_TIMESTAMP = now
|
|
|
|
}
|
|
|
|
return previous
|
|
|
|
},
|
2020-06-23 13:29:34 -04:00
|
|
|
|
2020-06-23 13:29:44 -04:00
|
|
|
_cleanEventStream(now) {
|
2020-07-07 06:06:02 -04:00
|
|
|
Object.entries(EVENT_LOG_TIMESTAMP).forEach(([key, timestamp]) => {
|
|
|
|
if (now - timestamp > EventLogger.MAX_STALE_TIME_IN_MS) {
|
|
|
|
delete EVENT_LOG_COUNTER[key]
|
|
|
|
delete EVENT_LOG_TIMESTAMP[key]
|
2020-06-23 13:29:44 -04:00
|
|
|
}
|
2020-07-07 06:06:02 -04:00
|
|
|
})
|
2020-06-23 13:29:44 -04:00
|
|
|
}
|
|
|
|
}
|