All files / src/emulator logger.js

90.91% Statements 30/33
85.71% Branches 12/14
100% Functions 8/8
90.32% Lines 28/31

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116                                                  12x                       12x       12x 12x 12x                 91x 82x 82x     91x 91x 91x       1992x 1992x     3411x 3411x 21x     21x           21x       3411x           5404x 1993x       1993x 1993x 1993x 1993x     1993x     3412x         1993x                
/*
 * Flow JS Testing
 *
 * Copyright 2020-2021 Dapper Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
 
import {EventEmitter} from "events"
 
/**
 * Enum of all logger levels
 * @readonly
 * @enum {number}
 */
export const LOGGER_LEVELS = {
  PANIC: 5,
  FATAL: 4,
  ERROR: 3,
  WARN: 2,
  INFO: 1,
  DEBUG: 0,
  TRACE: -1,
}
 
const LOG_REGEXP =
  // eslint-disable-next-line no-control-regex
  /\x1B\[1;34mLOG\x1B\[0m \x1B\[2m\[[a-z0-9]{6}]\x1B\[0m "(.*)"/
 
export class Logger extends EventEmitter {
  constructor(options) {
    super(options)
    this.handleMessage = this.handleMessage.bind(this)
    this.process = null
  }
 
  /**
   * Sets the emulator process to monitor logs of
   * @param {import("child_process").ChildProcessWithoutNullStreams} process
   * @returns {void}
   */
  setProcess(process) {
    if (this.process) {
      this.process.stdout.removeListener("data", this.handleMessage)
      this.process.stderr.removeListener("data", this.handleMessage)
    }
 
    this.process = process
    this.process.stdout.on("data", this.handleMessage)
    this.process.stderr.on("data", this.handleMessage)
  }
 
  handleMessage(buffer) {
    const logs = this.parseDataBuffer(buffer)
    logs.forEach(({level, msg, ...data}) => {
      // Handle log special case
      const levelMatch =
        level === LOGGER_LEVELS.INFO || level === LOGGER_LEVELS.DEBUG
      if (levelMatch && LOG_REGEXP.test(msg)) {
        let logMessage = msg.match(LOG_REGEXP).at(1)
 
        // if message is string, remove from surrounding and unescape
        Iif (/^"(.*)"/.test(logMessage)) {
          logMessage = logMessage
            .substring(1, logMessage.length - 2)
            .replace(/\\"/g, '"')
        }
 
        this.emit("log", logMessage)
      }
 
      // Emit emulator message to listeners
      this.emit("message", {level, msg, ...data})
    })
  }
 
  fixJSON(msg) {
    // TODO: Test this functionality
    const split = msg.split("\n").filter(item => item !== "")
    return split.length > 1 ? `[${split.join(",")}]` : split[0]
  }
 
  parseDataBuffer(dataBuffer) {
    const data = dataBuffer.toString()
    try {
      Eif (data.includes("msg")) {
        let messages = JSON.parse(this.fixJSON(data))
 
        // Make data into array if not array
        messages = [].concat(messages)
 
        // Map string levels to enum
        messages = messages.map(m => ({
          ...m,
          level: LOGGER_LEVELS[m.level.toUpperCase()],
        }))
 
        return messages
      }
    } catch (e) {
      console.error(e)
    }
    return []
  }
}