logging-manager.coffee 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. bunyan = require('bunyan')
  2. module.exports = Logger =
  3. initialize: (name) ->
  4. @logger = bunyan.createLogger
  5. name: name
  6. serializers: bunyan.stdSerializers
  7. return @
  8. initializeErrorReporting: (sentry_dsn, options) ->
  9. raven = require "raven"
  10. @raven = new raven.Client(sentry_dsn, options)
  11. @lastErrorTimeStamp = 0 # for rate limiting on sentry reporting
  12. captureException: (attributes, message, level) ->
  13. # handle case of logger.error "message"
  14. if typeof attributes is 'string'
  15. attributes = {err: new Error(attributes)}
  16. # extract any error object
  17. error = attributes.err or attributes.error
  18. # include our log message in the error report
  19. if not error?
  20. error = {message: message} if typeof message is 'string'
  21. else if message?
  22. attributes.description = message
  23. # report the error
  24. if error?
  25. # capture attributes and use *_id objects as tags
  26. tags = {}
  27. extra = {}
  28. for key, value of attributes
  29. tags[key] = value if key.match(/_id/) and typeof value == 'string'
  30. extra[key] = value
  31. # capture req object if available
  32. req = attributes.req
  33. if req?
  34. extra.req =
  35. method: req.method
  36. url: req.originalUrl
  37. query: req.query
  38. headers: req.headers
  39. ip: req.ip
  40. # recreate error objects that have been converted to a normal object
  41. if !(error instanceof Error) and typeof error is "object"
  42. newError = new Error(error.message)
  43. for own key, value of error
  44. newError[key] = value
  45. error = newError
  46. # send the error to sentry
  47. try
  48. @raven.captureException(error, {tags: tags, extra: extra, level: level})
  49. catch
  50. return # ignore any errors
  51. info : ()->
  52. @logger.info.apply(@logger, arguments)
  53. log : ()->
  54. @logger.info.apply(@logger, arguments)
  55. error: (attributes, message, args...)->
  56. @logger.error(attributes, message, args...)
  57. if @raven?
  58. now = new Date()
  59. rateLimited = (now - @lastErrorTimeStamp) < 30 * 1000
  60. # only report one error every thirty seconds to avoid overload
  61. if not rateLimited
  62. @captureException(attributes, message, "error")
  63. @lastErrorTimeStamp = now
  64. err: () ->
  65. @error.apply(this, arguments)
  66. warn: ()->
  67. @logger.warn.apply(@logger, arguments)
  68. fatal: (attributes, message, callback) ->
  69. @logger.fatal(attributes, message)
  70. if @raven?
  71. cb = (e) -> # call the callback once after 'logged' or 'error' event
  72. callback()
  73. cb = () ->
  74. @captureException(attributes, message, "fatal")
  75. @raven.once 'logged', cb
  76. @raven.once 'error', cb
  77. else
  78. callback()
  79. Logger.initialize("default-sharelatex")