overleaf/services/real-time/app/js/EventLogger.js
Eric Mc Sween d9e0215aee Merge pull request #12211 from overleaf/em-camel-case-real-time
Camel case variables in real-time

GitOrigin-RevId: 0a35d2e39d54c258bed017ea4dcdbf9a19a2a9b1
2023-03-21 09:05:37 +00:00

81 lines
2.3 KiB
JavaScript

let EventLogger
const logger = require('@overleaf/logger')
const metrics = require('@overleaf/metrics')
const settings = require('@overleaf/settings')
// keep track of message counters to detect duplicate and out of order events
// messsage ids have the format "UNIQUEHOSTKEY-COUNTER"
const EVENT_LOG_COUNTER = {}
const EVENT_LOG_TIMESTAMP = {}
let EVENT_LAST_CLEAN_TIMESTAMP = 0
// counter for debug logs
let COUNTER = 0
module.exports = EventLogger = {
MAX_STALE_TIME_IN_MS: 3600 * 1000,
debugEvent(channel, message) {
if (settings.debugEvents > 0) {
logger.info({ channel, message, counter: COUNTER++ }, 'logging event')
settings.debugEvents--
}
},
checkEventOrder(channel, messageId) {
if (typeof messageId !== 'string') {
return
}
let result
if (!(result = messageId.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)
if (!previous || count === previous + 1) {
metrics.inc(`event.${channel}.valid`)
return // order is ok
}
if (count === previous) {
metrics.inc(`event.${channel}.duplicate`)
logger.warn({ channel, messageId }, 'duplicate event')
return 'duplicate'
} else {
metrics.inc(`event.${channel}.out-of-order`)
logger.warn(
{ channel, messageId, key, previous, count },
'out of order event'
)
return 'out-of-order'
}
},
_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
},
_cleanEventStream(now) {
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]
}
})
},
}