i have written one middle-ware for handling uncaughtExceptions which is working fine but after that server will crashed.
how do i prevent to crash it?
server.js:
const express = require('express');
const winston = require("winston");
const app = express();
//Logging is responsible to log and display errors
require('./startup/logging')();
//routes will contains all the routes list
require('./startup/routes')(app);
//PORT
const port = process.env.PORT || 3000;
app.listen(port,() => winston.info(`Listening on port ${port}....`));
logging.js
const express = require('express');
const winston = require('winston');
// require('express-async-errors');
module.exports = function() {
winston.handleExceptions(
new winston.transports.File({ filename: 'uncaughtExceptions.log' })
);
process.on('unhandledRejection', (ex) => {
throw ex;
});
winston.add(winston.transports.File, { filename: 'error.log' });
}
If you do throw ex; The program will crash, Rather you should send the crash report and message to the respective reporting mechanism that you are using. Heres a small snippet
process.on('unhandledRejection', (reason, promise) => {
console.log('Unhandled Rejection at:', reason.stack || reason)
// Recommended: send the information to sentry.io
// or whatever crash reporting service you use
})
Related
I'm following a tutorial at https://www.woolha.com/tutorials/node-js-google-cloud-pub-sub-basic-examples and having some difficulty..
I've the following code in server.js:-
const express = require('express');
const app = express();
const path = require('path');
const bodyParser = require('body-parser');
const dotenv = require('dotenv');
dotenv.config(); // Reads the .env file from the local folder.
// PubSub constant initialisation
const PubSub = require(`#google-cloud/pubsub`);
const pubsub = new PubSub();
const data = new Date().toString();
const dataBuffer = Buffer.from(data);
const topicName = 'sensehat-led-config';
app.use(bodyParser.urlencoded({ extended: true}));
// Tell the app to use the public folder.
app.use(express.static('public'));
app.get('/', (req,res) => {
res.send('Hello from App Engine!');
})
app.get('/submit', (req, res) => {
res.sendFile(path.join(__dirname, '/views/form.html'));
})
// Need to figure out how to get the css file to work in this. Can't be that hard.
app.get('/sensehat', (req, res) => {
res.sendFile(path.join(__dirname, '/views/sensehat.html'));
})
app.get('/sensehat-publish-message', (req, res) =>{
pubsub
.topic(topicName)
.publisher()
.publish(dataBuffer)
.then(messageId => {
console.log(`Message ${messageId} published`);
})
.catch(err => {
console.error('ERROR:', err);
});
})
app.post('/submit', (req, res) => {
console.log({
name: req.body.name,
message: req.body.message
});
res.send('Thanks for your message!');
})
// Listen to the App Engine-specified port, or 8080 otherwise
const PORT = process.env.PORT || 8080;
app.listen(PORT, () => {
console.log('Server listening on port ${PORT}...');
})
But when I run it I get a '500 Server Error', and looking at the Stackdriver logs I get the following error:-
TypeError: PubSub is not a constructor at Object.<anonymous>
I'm definitely a newbie at NodeJS and feeling my way around. After reading around I think the issue is coming from the
const PubSub = require(`#google-cloud/pubsub`);
const pubsub = new PubSub();
lines, but no idea how to rectify this.
You can try with latest versions of all libraries.
Dependencies in package.json
"dependencies": {
"#google-cloud/pubsub": "1.5.0",
"google-gax": "1.14.1",
"googleapis": "47.0.0"
}
Example code -
const {
PubSub
} = require('#google-cloud/pubsub');
const pubsub = new PubSub({
projectId: process.env.PROJECT_ID
});
module.exports = {
publishToTopic: function(topicName, data) {
return pubsub.topic(topicName).publish(Buffer.from(JSON.stringify(data)));
},
};
Calling file code
const PubSubPublish = require('path to your above file')
let publishResult = await PubSubPublish.publishToTopic(process.env.TOPIC_NAME, data)
Hope it helps!
You require the default export of #google-cloud/pubsub, but what look for is not in the default export.
Change the way you import PubSub to:
const {PubSub} = require(`#google-cloud/pubsub`);
Instead of:
const PubSub = require(`#google-cloud/pubsub`);
Hi in my express project, I have my index file where I require different files to startup my application. These require a database connection file, a file for logging stuff using winston and a file for configuring routes.
I use the require() statement within express to call these files, and when I run the application(using nodemon), I expect some messages to be logged to the terminal verifying that the files have been called, however no messages occur.
Here is my code:
index.js:
const express = require('express')
const app = express()
require('./startup/logging') ()
require('./startup/db') ()
require('./startup/routes') (app)
const port = process.env.PORT || 3000
app.listen(port, () => winston.info(`Listening on port: ${port}`))
db.js:
const mongoose = require('mongoose')
const winston = require('winston')
module.exports = function() {
mongoose.connect('mongodb://localhost/dwg', {useNewUrlParser: true, useUnifiedTopology: true})
.then(() => winston.info('Connected to MongoDB...'))
.catch(err => console.error("Error"))
}
logging.js:
const winston = require('winston');
module.exports = function() {
winston.handleExceptions(
new winston.transports.File({ filename: 'uncaughtExceptions.log' }));
process.on('unhandledRejection', (ex) => {
throw ex;
});
winston.add(winston.transports.File, { filename: 'logfile.log' });
}
routes.js:
const express = require('express');
module.exports = function(app) {
app.use(express.json())
}
No database is created when running the application. I can confirm this by looking at mongodb compass. The message that is meant to be printed by app.listen() is also not printed to the console. Does anybody know the issue? Thank you.
The problem doing it this way is your app starts before it gets a chance to do rest of work like creating db connection etc. You should start the app only when these tasks are done. something like this
const express = require('express')
const app = express()
const logging = require('./startup/logging');
const db = require('./startup/db');
const routes = require('./startup/routes');
const port = process.env.PORT || 3000
app.listen(port, async () => {
await logging();
await db();
await routes();
// assuming you have winston here.
winston.info(`Listening on port: ${port}`)
})
Mongo part is defintely async so need await. Check if routes and logging needs await or not.
i have written one middle-ware for handling uncaughtExceptions which is working fine but after that server will crashed.
how do i prevent to crash it?
server.js:
const express = require('express');
const winston = require("winston");
const app = express();
//Logging is responsible to log and display errors
require('./startup/logging')();
//routes will contains all the routes list
require('./startup/routes')(app);
//PORT
const port = process.env.PORT || 3000;
app.listen(port,() => winston.info(`Listening on port ${port}....`));
logging.js
const express = require('express');
const winston = require('winston');
// require('express-async-errors');
module.exports = function() {
winston.handleExceptions(
new winston.transports.File({ filename: 'uncaughtExceptions.log' })
);
process.on('unhandledRejection', (ex) => {
throw ex;
});
winston.add(winston.transports.File, { filename: 'error.log' });
}
As the documentation states,
By default, winston will exit after logging an uncaughtException. If this is not the behavior you want, set exitOnError = false
const logger = winston.createLogger({ exitOnError: false });
//
// or, like this:
//
logger.exitOnError = false;
It is generally considered a bad practice to not exit after an exception because the consequences are unpredictable. If only some of the exceptions are known to be tolerable, they can be specifically handled with a predicate:
const ignoreWarnings = err => !(err instanceof WarningError);
const logger = winston.createLogger({ exitOnError: ignoreWarnings });
I am able to log every request and error message into separate logfiles(request.log and uncaughtExceptions.log) but want to merge this two files into one file only called logs.log like
var logmsg = {
'Request IP',
'Method':req.method,
'URL':req.originalUrl,
'statusCode':res.statusCode,
'headers':req.headers,
'Time':new Date(),
'ErrorMessage':'Error Message if any with file name with line number and proper error message'
};
Working Code:
const express = require('express');
const winston = require('winston');
require('express-async-errors');
module.exports = function() {
winston.handleExceptions(
new winston.transports.File({ filename: 'uncaughtExceptions.log' }));
process.on('unhandledRejection', (ex) => {
throw ex;
});
winston.add(winston.transports.File, { filename: 'request.log' });
}
What I have Tried:
logging.js
const express = require('express');
const { createLogger, format, transports } = require('winston');
const { combine, timestamp, label, printf } = format;
const myFormat = printf(info => {
return (info.timestamp + " | " +
info.trace[0].file + ":" + info.trace[0].line + " | " +
info.message.split("\n")[0]);
});
module.exports = function() {
const logger = createLogger({
format: combine(timestamp(), myFormat)
});
logger.exceptions.handle(new transports.File({ filename: 'logs.log' }));
process.on('unhandledRejection', (reason, p) => {
throw p;
});
}
it displays strange error message, i have no idea how to resolve it.
Error message:
server.js
const express = require('express');
const winston = require("winston");
const app = express();
//to Log errors
require('./startup/logging')();
//routes will contains all the routes list
require('./startup/routes')(app);
//PORT
const port = process.env.PORT || 3000;
app.listen(port,() => winston.info(`Listening on port ${port}....`));
routes.js
const express = require('express');
const reqres = require('../middlewares/reqreslog');
module.exports = function(app){
//Every Request Response Logging Middleware
app.use(reqres);
app.get('/', async (req, res) => {
res.json("testing"+a);
});
});
reqreslog.js
var winston = require('winston');
module.exports = function(req, res, next) {
var logmsg = {
'Request IP':req.ip,
'Method':req.method,
'URL':req.originalUrl,
'statusCode':res.statusCode,
'headers':req.headers,
'Time':new Date(),
'ErrorMessage':'Display Error If Any for this request'
};
winston.log('info', logmsg);
next();
}
Winston logging works on the basis of log level info,debug,error etc.. If you want to log everything into the same log file you have to give level info.
const logger = winston.createLogger({
levels: winston.config.syslog.levels,
transports: [
new winston.transports.File({
filename: 'combined.log',
level: 'info'
})
]
});
process.on('unhandledRejection', (reason, p) => {
logger.error('exception occur');
throw reason;
});
Read more about log level in winstonjs - https://github.com/winstonjs/winston#using-logging-levels
I have an express app which I need to start on my integration test case.
The express app is exported in the app.js file without listening to any port. So, my test case goes like this:
const app = require('../src/app');
describe('Pact Verification', () => {
const port = 3002;
let server;
beforeAll(done => {
const server = http.createServer(app);
server.listen({ port }, done)
});
afterAll(done => {
server.close(done);
});
it(....
The problem is, once the test is ran with Jest, it hangs. I have to either --forceExit or ^C to exit.
I even updated to Jest 23 to use --detectOpenHandles but I don't see any output in the terminal, it keeps hanging so that's not helping either.
Since the exported app is not listening to any port, and it doesn't have any database connections or such, the problem is unlikely to be there, maybe its in my beforeAll/afterAll block. What am I missing?
Update 1
Here is the content of my app.js
var express = require('express');
var path = require('path');
var logger = require('morgan');
var indexRouter = require('./routes/index');
var app = express();
if (process.env.NODE_ENV !== 'test') {
app.use(logger('dev'));
}
app.use(express.json());
app.use('/api/v1/', indexRouter); // <-- these endpoints just return faker data in JSON format (https://github.com/marak/Faker.js/)
app.use((req, res, next) => {
const err = Error('Not Found');
err.status = 404;
next(err);
});
app.use((err, req, res, next) => {
const { status, message } = err;
const stack = status !== 404 && err.stack || undefined;
res.status(status || 500)
.json({
message,
stack,
});
});
module.exports = app;
The problem is that server is undefined in afterAll because it's assigned in another scope as const server = http.createServer(app). Instead, it should be:
server = http.createServer(app);
There should be an exception, so done is never get called in afterAll. Currently Jest suppresses errors from afterAll, there's Jest open issue that addresses afterAll bug.