Get console output of current script - node.js

I want to get the console contents of the current running Node.js script.
I've tried to do this event but it doesn't work:
setInterval(function() { console.log("Hello World!") }, 1000);
process.stdout.on('message', (message) => {
console.log('stdout: ' + message.toString())
})
It doesn't listen to the event.

This is not a fully Node.js solution but it is very good in case you run Linux.
Create a start.sh file.
Put the following into it:
start.sh:
#!/bin/bash
touch ./console.txt
node ./MyScript.js |& tee console.txt &
wait
Now open your Node.js script (MyScript.js) and use this Express.js event:
MyScript.js:
const fs = require('fs');
app.get('/console', function(req, res){
var console2 = fs.readFileSync("./console.txt", 'utf8');
res.send(console2);
});
Always start your Node.js application by calling start.sh
Now calling http://example.com/console should output the console!
A part of this answer was used.
NOTE: To format the line breaks of the console output to be shown correctly in the browsers, you can use a module like nl2br.
An advice: The problems aren't always solved the direct way, most of the problems are solved using indirect ways. Keep searching about the possible ways to achieve what you want and don't search about what you're looking for only.

There's no 'message' event on process.stdout.
I want to make a GET in my Express.js app called /getconsole .. it
should return the console of the current running Node.js script (which
is running the Express.js app too)
What you should use is a custom logger, I recommend winston with a file transport, and then you can read from that file when you issue a request to your endpoint.
const express = require('express');
const fs = require('fs');
const winston = require('winston');
const path = require('path');
const logFile = path.join(__dirname, 'out.log');
const app = express();
const logger = winston.createLogger({
level: 'info',
format: winston.format.json(),
transports: [
new winston.transports.Console({
format: winston.format.simple()
}),
new winston.transports.File({
filename: logFile
})
]
});
// Don't use console.log anymore.
logger.info('Hi');
app.get('/console', (req, res) => {
// Secure this endpoint somehow
fs.createReadStream(logFile)
.pipe(res);
});
app.get('/log', (req, res) => {
logger.info('Log: ' + req.query.message);
});
app.listen(3000);
You can also use a websocket connection, and create a custom winston transport to emit the logs.

stdout, when going to a tty (terminal) is an instance of a writable stream. The same is true of stderr, to which node writes error messages. Those streams don't have message events. The on() method allows solicitation of any named event, even those that will never fire.
Your requirement is not clear from your question. If you want to intercept and inspect console.log operations, you can pipe stdout to some other stream. Similarly, you can pipe stderr to some other stream to intercept and inspect errors.
Or, in a burst of ugliness and poor maintainability, you can redefine the console.log and console.error functions to something that does what you need.
It sounds like you want to buffer up the material written to the console, and then return it to an http client in response to a GET operation. To do that you would either
stop using console.log for that output, and switch over to a high-quality logging npm package like winston.
redefine console.log (and possibly console.error) to save its output in some kind of simple express-app-scope data structure, perhaps an array of strings. Then implement your GET to read that array of strings, format it, and return it.
My first suggestion is more scalable.
By the way, please consider the security implications of making your console log available to malicious strangers.

Related

Redirect Readable object stdout process to file in node

I use an NPM library to parse markdown to HTML like this:
var Markdown = require('markdown-to-html').Markdown;
var md = new Markdown();
...
md.render('./test', opts, function(err) {
md.pipe(process.stdout)
});
This outputs the result to my terminal as intended.
However, I need the result inside the execution of my node program. I thought about writing the output stream to file and then reading it in at a later time but I can't figure out a way to write the output to a file instead.
I tried to play around var file = fs.createWriteStream('./test.html'); but the node.js streams rather give me headaches than results.
I've also looked into the library's repo and Markdown inherits from Readable via util like this:
var util = require('util');
var Readable = require('stream').Readable;
util.inherits(Markdown, Readable);
Any resources or advice would be highly appreciated. (I would also take another library for parsing the markdown, but this gave me the best results so far)
Actually creating a writable file-stream and piping the markdown to this stream should work just fine. Try it with:
const writeStream = fs.createWriteStream('./output.html');
md.render('./test', opts, function(err) {
md.pipe(writeStream)
});
// in case of errors you should handle them
writeStream.on('error', function (err) {
console.log(err);
});

Log all errors and warnings

I am using a third party nodejs application which is quite large and it is using many different things for logging. For instance console.log() and console.error(). I would like to be able to trap all output and log to a specific file. I was thinking about using winston and do something like this:
const winston = require('winston')
const logger = winston.createLogger({
transports: [
new winston.transports.File({ filename: 'error.log', level: 'error' })
]
})
const ce = console.error
console.error = function(...args) {
logger.log.apply('error', args)
ce.apply(args)
}
Is there a better way to handle this kind of situation?
I might also add that some parts of the application is already using winston for logging purposes.
My aim is the create a single file with all errors and warnings generated from within the application.

Create a duplicated file with fs streams and be able to read it

I'm currently trying to copy the content of a file into another one using Node.js through the fs.createWriteStream and fs.createReadStream functions.
To be more specific, the file is a music sample that I would like to duplicate. Also, I expect the resulting file to be readable by a player like any music or video. It's this last point that I don't manage to perform. The files are indeed duplicated, but the the resulting file is not accepted by my player as a readable file, like if it was corrupted somehow.
I checked its content and there it doesn't seem to be a matter a programmation logic, as the the datas of the original file have been correctly transposed into the copy. Here is my script, if you want to take a look.
const express = require('express')
const app = express()
const fs = require("fs")
var Promise = require("bluebird")
Promise.promisifyAll(fs)
const path = require('path')
const file1 = path.join(__dirname, 'sample1.wav') // The file to copy
const file2 = path.join(__dirname, 'sample2.wav') // The destination of the new file
app.use(async(req,res,next)=>{
let file1_stream = await fs.createReadStream(file1)
let file2_stream = await fs.createWriteStream(file2)
file2_stream.pipe(file2_stream)
next()
})
.listen(8080)
I guess the operation is not as simple as just copying a stream and inject it with a pipe like shown above. if someone has any idea what I am missing here, I am all ears. Thanks by advance.
That code is triggering an error, which you're probably not handling correctly, since you're using an async middleware on express.
Error [ERR_STREAM_CANNOT_PIPE]: Cannot pipe, not readable
You have to use .pipe on the readableStream not on the writeableStream
So the code should be:
file1_stream.pipe(file2_stream);
Also, you don't need to await on fs.createWriteStream. It's doing nothing. The promisify works on callbacks APIs, but createWriteStream & createReadStream don't take a callback as an argument.
app.use((req,res,next)=>{
let readStream = fs.createReadStream(file1);
let writeStream = fs.createWriteStream(file2);
readStream.pipe(writeStream);
// Call next once the file was actually copied
writeStream.on('finish', next);
writeStream.on('error', next); // go to express error handler
readStream.on('error', next);
});

Instrumenting files on the fly with Istanbul

I can instrument a file/folder and write it to disk like so:
$ istanbul instrument public --output public-coverage --embed-source true
however I am wondering if there is a way to instrument files on the fly and serve them to the browser without ever writing the instrumented files to disk. Something like this:
app.use(function(req,res,next){
const file = req.path; // whatever
const k = cp.spawn('istanbul', ['instrument']);
fs.createReadStream(file).pipe(k.stdin).pipe(res);
});
does anyone know if that's possible and how?
Actually it is.
Below is an example where I'd just intercept the request for a normal "main.js" file and return the "instrumented" version instead.
Just a proof of concept, without any error handling and only for a specific file, but I think you get the point.
Alternatively you can load up instanbul in your code "require("istanbul")" and perform the action without actual spawns
app.get("/main.js", (req, res, next) => {
const cmd = path.join(__dirname, "node_modules", ".bin", "istanbul");
const file = path.join(__dirname, "public/main.js");
const s = spawn(cmd, ["instrument", file, "--embed-source", "--no-compact", "--preserve-comments"]);
s.stdout.on("data", (data) => {
res.send(data);
});
});

nodejs - pipe appjs console to a file

I try to pipe appjs console to a file with this code:
var fs = require('fs');
var logStream = fs.createWriteStream(__dirname+ '/log.txt', { flags: 'a' });
process.stdout.pipe(logStream);
process.stderr.pipe(logStream);
console.log("test");
It creates an empty file, but nothing more... With node.exe the "test" goes into the console, not into the log file. The platform is win32, but I don't think it counts.
What's the problem with the code?
conclusion:
Stdout, stderr and a file write stream are all sink type endpoints, so I cannot bind them together. I need to replace stdout and stderr with douplex mock streams so I will be able to bind these mock streams both to the original sinks and the log sink. I am not sure whether console.log and console.error will be affected by replacing the streams with the mechanism supernova suggested, I'd rather use a dedicated logger, which uses the console instead of this workaround.
you have to define getters for process.stdin, process.stdout and process.stderr
var fs = require("fs")
, errlog = fs.createWriteStream("./err.log", { flags: 'a' })
process.__defineGetter__("stderr", function(){
return errlog
})
process.stderr.write("test")
this should work

Resources