14

I'm working on enhancing logging in some node.js applications. In the past have used C++'s __ file__ and __ line __ preprocessor macros to help us track down issues when logging events. I haven't found anything similar to it in the node.js world.

Does anyone have suggestions or know how I can get line number and file name in node.js for logging purposes?

I'm looking for something like:

console.log(__FILE__ + "." + __LINE__ + "\t" + new Date().toISOString() + " Message "); 

5 Answers 5

17

see the global object:

__filename 

for the lineNumber see this post: javascript node.js getting line number in try catch?

Sign up to request clarification or add additional context in comments.

Comments

9

See: Accessing line number in V8 JavaScript (Chrome & Node.js)

Then for a filename:

Object.defineProperty(global, '__file', { get: function(){ return __stack[1].getFileName().split('/').slice(-1)[0]; } }); 

You could also just use the process.argv[1] instead of calling the __stack getter but I wanted to keep it similar.

Comments

4

Expanded on the previous answers a bit into here: https://gist.github.com/gavinengel/8572856

Allows setting globals: __line, __file, __ext, __dir

By the way, how do I create?: __function, __method, __class

2 Comments

Thanks for the gist. You should consider making this into a node module, it could be a nice npm module
Sure. Actually, I'd recommend you check out this code which I just realized was out there by the PHPJS team: github.com/kvz/phpjs/tree/master/experimental/language
2

Just use the C preprocesor, adds an extra build step to your code but then it allows stripping out your logging for production code.

3 Comments

Not a bad idea. Never thought about that.
Sounds good, but how, exactly does one "just use the C preprocessor"?
@clozach, both GCC and other C compilers commonly have an option which makes the compiler just run its input through the normal C preprocessor and print out the results. This could be used in a build script for a program written in some other programming language.
0

I found this old post while researching this very question. I had figured out how to shoehorn in __line using an approach like what is in magic-globals (e.g. capturing the error stack, etc). The problem with that is that is SUPER slow if you are calling it frequently. I am using these macros a lot since I am maintaining my own, separate call stack for a transpiled language. The code was 25X slower when constantly capturing the native stack.

I don't know if this option was available in 2014, but as of 2024 you can inject your own loader logic. Example:

const fs = require('fs'), Module = require('module'); /** * * @param {string} ext The file extension to configure the loader for * @param {function(string, Module): boolean} checkExclude Callback to see if we should defer to the original loader * @returns */ function configureExtensionLoader(ext = '.js', checkExclude = false) { const originalRequire = Module._extensions[ext]; /** * * @param {string} filename The file being processed * @param {string} contentIn The content of the file */ function preprocess(filename, contentIn) { const ext = filename.slice(filename.lastIndexOf('.')), content = contentIn.split('\n').map((line, index) => { line = line.replace(/__line/g, index + 1); line = line.replace(/__ext/g, ext); return line; }).join('\n'); // TODO: Add support for __class, __methodName, etc return content; } /** * Load a module * @param {Module} module * @param {string} filename The module file to load */ Module._extensions[ext] = function (module, filename) { const excluded = checkExclude && checkExclude(filename, module); if (!excluded) { const content = fs.readFileSync(filename, 'utf8'); const preprocessedContent = preprocess(filename, content); module._compile(preprocessedContent || content, filename); } else return originalRequire(module, filename); }; return true; } /** * Configure the preprocessor for a list of extensions. * @param {string[]} extensionList The list of extensions to configure * @param {function(string, Module): boolean} checkExclude A callback that can exclude modules from preprocessing */ module.exports = function (extensionList = ['.js'], checkExclude) { for (ext of extensionList) { configureExtensionLoader(ext, checkExclude); } } 

Usage example:

const path = require('node:path'), driverSource = path.join(__dirname, 'src'); // Nothing but the side-effects, mam require('./src/Importer')(['.js'], (filename) => !filename.startsWith(driverSource)); 

I include this in my entry script, and now any require() calls to include modules from my 'src' directory will automatically expand the __line macro to a numeric literal, and __ext will expand to '.js' literal. If I wanted to spend the time, I--or someone else--could write a simple tokenizer to provide __method, __class, __function, etc.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.