parse-log.ts 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. import * as program from 'commander'
  2. import { createReadStream, readdirSync, statSync } from 'fs-extra'
  3. import { join } from 'path'
  4. import { createInterface } from 'readline'
  5. import * as winston from 'winston'
  6. import { labelFormatter } from '../server/helpers/logger'
  7. import { CONFIG } from '../server/initializers/constants'
  8. program
  9. .option('-l, --level [level]', 'Level log (debug/info/warn/error)')
  10. .parse(process.argv)
  11. const excludedKeys = {
  12. level: true,
  13. message: true,
  14. splat: true,
  15. timestamp: true,
  16. label: true
  17. }
  18. function keysExcluder (key, value) {
  19. return excludedKeys[key] === true ? undefined : value
  20. }
  21. const loggerFormat = winston.format.printf((info) => {
  22. let additionalInfos = JSON.stringify(info, keysExcluder, 2)
  23. if (additionalInfos === '{}') additionalInfos = ''
  24. else additionalInfos = ' ' + additionalInfos
  25. return `[${info.label}] ${toTimeFormat(info.timestamp)} ${info.level}: ${info.message}${additionalInfos}`
  26. })
  27. const logger = winston.createLogger({
  28. transports: [
  29. new winston.transports.Console({
  30. level: program['level'] || 'debug',
  31. stderrLevels: [],
  32. format: winston.format.combine(
  33. winston.format.splat(),
  34. labelFormatter,
  35. winston.format.colorize(),
  36. loggerFormat
  37. )
  38. })
  39. ],
  40. exitOnError: true
  41. })
  42. const logLevels = {
  43. error: logger.error.bind(logger),
  44. warn: logger.warn.bind(logger),
  45. info: logger.info.bind(logger),
  46. debug: logger.debug.bind(logger)
  47. }
  48. const logFiles = readdirSync(CONFIG.STORAGE.LOG_DIR)
  49. const lastLogFile = getNewestFile(logFiles, CONFIG.STORAGE.LOG_DIR)
  50. const path = join(CONFIG.STORAGE.LOG_DIR, lastLogFile)
  51. console.log('Opening %s.', path)
  52. const rl = createInterface({
  53. input: createReadStream(path)
  54. })
  55. rl.on('line', line => {
  56. const log = JSON.parse(line)
  57. // Don't know why but loggerFormat does not remove splat key
  58. Object.assign(log, { splat: undefined })
  59. logLevels[log.level](log)
  60. })
  61. function toTimeFormat (time: string) {
  62. const timestamp = Date.parse(time)
  63. if (isNaN(timestamp) === true) return 'Unknown date'
  64. return new Date(timestamp).toISOString()
  65. }
  66. // Thanks: https://stackoverflow.com/a/37014317
  67. function getNewestFile (files: string[], basePath: string) {
  68. const out = []
  69. files.forEach(file => {
  70. const stats = statSync(basePath + '/' + file)
  71. if (stats.isFile()) out.push({ file, mtime: stats.mtime.getTime() })
  72. })
  73. out.sort((a, b) => b.mtime - a.mtime)
  74. return (out.length > 0) ? out[ 0 ].file : ''
  75. }