EventLogger.coffee 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. logger = require 'logger-sharelatex'
  2. metrics = require 'metrics-sharelatex'
  3. settings = require 'settings-sharelatex'
  4. # keep track of message counters to detect duplicate and out of order events
  5. # messsage ids have the format "UNIQUEHOSTKEY-COUNTER"
  6. EVENT_LOG_COUNTER = {}
  7. EVENT_LOG_TIMESTAMP = {}
  8. EVENT_LAST_CLEAN_TIMESTAMP = 0
  9. # counter for debug logs
  10. COUNTER = 0
  11. module.exports = EventLogger =
  12. MAX_STALE_TIME_IN_MS: 3600 * 1000
  13. debugEvent: (channel, message) ->
  14. if settings.debugEvents > 0
  15. logger.log {channel:channel, message:message, counter: COUNTER++}, "logging event"
  16. settings.debugEvents--
  17. checkEventOrder: (channel, message_id, message) ->
  18. return if typeof(message_id) isnt 'string'
  19. return if !(result = message_id.match(/^(.*)-(\d+)$/))
  20. key = result[1]
  21. count = parseInt(result[2], 0)
  22. if !(count >= 0)# ignore checks if counter is not present
  23. return
  24. # store the last count in a hash for each host
  25. previous = EventLogger._storeEventCount(key, count)
  26. if !previous? || count == (previous + 1)
  27. metrics.inc "event.#{channel}.valid", 0.001 # downsample high rate docupdater events
  28. return # order is ok
  29. if (count == previous)
  30. metrics.inc "event.#{channel}.duplicate"
  31. logger.warn {channel:channel, message_id:message_id}, "duplicate event"
  32. return "duplicate"
  33. else
  34. metrics.inc "event.#{channel}.out-of-order"
  35. logger.warn {channel:channel, message_id:message_id, key:key, previous: previous, count:count}, "out of order event"
  36. return "out-of-order"
  37. _storeEventCount: (key, count) ->
  38. previous = EVENT_LOG_COUNTER[key]
  39. now = Date.now()
  40. EVENT_LOG_COUNTER[key] = count
  41. EVENT_LOG_TIMESTAMP[key] = now
  42. # periodically remove old counts
  43. if (now - EVENT_LAST_CLEAN_TIMESTAMP) > EventLogger.MAX_STALE_TIME_IN_MS
  44. EventLogger._cleanEventStream(now)
  45. EVENT_LAST_CLEAN_TIMESTAMP = now
  46. return previous
  47. _cleanEventStream: (now) ->
  48. for key, timestamp of EVENT_LOG_TIMESTAMP
  49. if (now - timestamp) > EventLogger.MAX_STALE_TIME_IN_MS
  50. delete EVENT_LOG_COUNTER[key]
  51. delete EVENT_LOG_TIMESTAMP[key]