Skip to content

Instantly share code, notes, and snippets.

@ArtemGr
Last active May 17, 2023 05:18
Show Gist options
  • Save ArtemGr/25fad725870b0ada74df2bce7d115cc1 to your computer and use it in GitHub Desktop.
Save ArtemGr/25fad725870b0ada74df2bce7d115cc1 to your computer and use it in GitHub Desktop.
llog.js
// To add this Gist to a project:
//
// npm install https://gist.github.com/25fad725870b0ada74df2bce7d115cc1.git
/**
* @param {number} level
*/
exports.trace = function (level) {
const obj = {}
const lim = Error.stackTraceLimit
Error.stackTraceLimit = level + 1
Error.captureStackTrace (obj)
Error.stackTraceLimit = lim
const re = /^ at ([^\n]+)?$/mg
// “ at Object.nai [as fun] (NovelAI.js:83:13)”
// “ at exports.trace (c:\Users\...\llog\index.js:12:9)”
// “ at c:\...\grab\grab.js:40:3”
const rel = /[\w:\.\\\/-]*?([\w-]+)\.js:(\d+):\d+\)?$/
let ma, mam; for (let ix = level; 0 < ix; --ix) {
ma = re.exec (obj.stack)
if (ma == null) return null
mam = rel.exec (ma[1])
if (false) console.log (ix, ma[1], mam)
if (mam == null) return null}
return mam}
/** @type {Map<string, number>} */
let COUNTER
/**
* @param {string} uid Location to globally count to, or any other ID
* @returns {number} Count towards how many times we were already at `loc`
*/
exports.count = function (uid) {
if (COUNTER == null) COUNTER = new Map()
const count = (COUNTER.get (uid) ?? 0) + 1
COUNTER.set (uid, count)
return count}
/**
* @param {number} times How many times to return true to the call site
* @returns {boolean} False if the call site evaluated it `times`
*/
exports.times = function (times) {
const ma = exports.trace (3)
if (ma == null) return null // Can't count
const loc = ma[1] + ':' + ma[2]
const count = exports.count (loc)
return count <= times}
/**
* Log a `line` prepending the current file name and line number
* Works in NodeJS but probably not in a browser
* @param {any} line
* @param {number} [times] Log only N `times` from that location
*/
function log (line, times) {
const ma = exports.trace (3)
if (ma == null) {
log.out (line)
} else {
const loc = ma[1] + ':' + ma[2]
if (times) if (exports.count (loc) > times) return
log.out (line, loc)}}
/**
* Override to change destination
*
* @example
* const date = require ('date-and-time');
* const {log} = require ('log');
* log.out = (line, loc) => console.log (date.format (new Date(), 'DD HH:mm]'), (loc ?? '') + ']', line)
*/
log.out = function (line, loc) {loc ? console.log (loc + ']', line) : console.log (line)}
exports.log = log
/**
* Sleep for the given number of milliseconds
* @param {number} ms
*/
exports.snooze = function (ms) {return new Promise (resolve => setTimeout (resolve, ms))}
/**
* NB: Different from `console.assert` in that we're throwing a “normal” `Error`
* which unwinds, interrupting the program
* @param {boolean} condition
* @param {() => string} [message]
*/
exports.assert = function (condition, message) {
if (condition) return
const locᵃ = exports.trace (3)
const loc = locᵃ ? locᵃ[1] + ':' + locᵃ[2] : '_'
if (message) throw new Error ('[' + loc + '] Assertion failed: ' + message())
throw new Error ('[' + loc + '] Assertion failed')}
exports.hash = s=>{for(var i=0,h=9;i<s.length;)h=Math.imul(h^s.charCodeAt(i++),9**9);return h^h>>>9}
{
"name": "llog",
"version": "1.1.1",
"description": "log to console with line number attached",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"contributors": [
"Artemciy"
],
"repository": {
"type": "git",
"url": "https://gist.github.com/25fad725870b0ada74df2bce7d115cc1.git"
},
"license": "MIT"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment