Using Winston and Morgan to log in Sails - sails.js

In the config/log.js file for Sails this is my code:
var express = require("express");
var app = express();
var winston = require('winston');
var logger = new(winston.Logger)({
transports: [
new(winston.transports.File)({
level: 'info',
timestamp: true,
filename: './logFile.log',
handleExceptions: true,
json: true,
colorize: false
}),
new(winston.transports.Console)({
level: 'debug',
timestamp: true,
handleExceptions: true,
json: false,
colorize: true
})
],
exitOnError: false
});
logger.stream = {
write: function (message, encoding) {
logger.verbose(message);
}
};
app.use(require('morgan')("combined", {"stream": logger.stream}));
module.exports.log = {
level: 'info',
custom: logger
};
I'm trying to use morgan along with winston to log all the HTTP requests. I found an example online that said to do it this way, and this makes sense to me, but for some reason my log file isn't showing any of the requests that are made. The winston part is fine as it is logging all the information that it should be, but I don't know how to get morgan to work with winston. Any advice or suggestions? Thanks!

Morgan is an express middleware so it should be loaded as a custom middleware to Sails.
To do that add the following to config/http.js:
customMiddleware: function(app) {
app.use(require('morgan')("combined", {"stream": sails.config.log.custom.stream}));
}

Related

Error attempting to retrieve CODE sent to gmail account using MailListener Protractor/Jasmine end to end Test

I have already installed MailListener
npm install mail-listener2 --save-dev
In My Config.js file, I have
exports.config = {
directConnect: true,
capabilities: {
browserName: 'chrome',
},
framework: 'jasmine2',
onPrepare: function () {
var AllureReporter = require('jasmine-allure-reporter');
var AllureReporter = require('../index');
jasmine.getEnv().addReporter(new AllureReporter({
resultsDir: 'allure-results'
}));
// Mail Listener
var MailListener = require("mail-listener2");
// here goes your email connection configuration
var mailListener = new MailListener({
username: "myemail#gmail.com",
password: "mygmailpassword!",
host: "imap.gmail.com",
port: 993, // imap port
tls: true,
tlsOptions: { rejectUnauthorized: false },
mailbox: "INBOX", // mailbox to monitor
searchFilter: ["UNSEEN", "FLAGGED"], // the search filter being used after an IDLE notification has been retrieved
markSeen: true, // all fetched email willbe marked as seen and not fetched next time
fetchUnreadOnStart: true, // use it only if you want to get all unread email on lib start. Default is `false`,
mailParserOptions: { streamAttachments: true }, // options to be passed to mailParser lib.
attachments: true, // download attachments as they are encountered to the project directory
attachmentOptions: { directory: "attachments/" } // specify a download directory for attachments
});
mailListener.start();
mailListener.on("server:connected", function () {
console.log("... Mail listener initialized");
});
global.mailListener = mailListener;
},
onCleanUp: function () {
mailListener.stop();
},
// Spec patterns are relative to the current working directory when
// protractor is called.
specs: [
'../e2e/login_spec.js'
],
// Options to be passed to Jasmine.
jasmineNodeOpts: {
defaultTimeoutInterval: 30000
}
};
in my login_spec.js file i have the function
function getLastEmail() {
var deferred = protractor.promise.defer();
console.log("Waiting for an email...");
mailListener.on("mail", function(mail){
deferred.fulfill(mail);
});
return deferred.promise;
};
In the Same login_spec.js
i am trying
var loginData = require('../data.json');
var Login_Objects = require('../page_objects/login_objects');
describe('2Factor Login:', function () {
dataProvider(loginData, function (data) {
Login_Objects.EnterUserName(data.username)
Login_Objects.EnterUserName(data.password)
Login_Objects.ClickLogin()
//Code is sent to email
browser.controlFlow().wait(getLastEmail()).then(function (email){
var pattern = /Code for your transfer (\w+)/g;
var regCode = pattern.exec(email.text)[1];
console.log("Registration code : = "+regCode);
//Pass the code to my methods in the objects file.
//Login_Objects.Enter2FactorCode(regCode)
//Login_Objects.ClickVerify()
})
})
})
here my Login_Objects.Enter2FactorCode(regCode) method will just send keys to the 2factor webelement [but i am not yet at that stage]
At this point i am expecting the email to be printed by the function
console.log("Registration code : = "+regCode);
On the Console I am Getting the message :
... Mail listener initialized
NOTE: I have already allowed unsecure apps to access that gmail account
Findings:
I am getting an error
Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.
My reference is this >> Fetching values from email in protractor test case

testing a site not working in internet explorer-values not able to enter in fields

I am using protractor version 5.2.2 and cucumber-protractor framework, I have started practising testing for the LinkedIn site, but when I use the internet explorer browser it is only able to open the LinkedIn URL as mentioned in the config file and no scenarios are being executed, can anybody help me?
//config file
var params = require('./browsers.js');
var browser = params.browser;
var multiCapabilities = browser.split(',').map(function(browserName){
return {
browserName: browserName.trim()
};
})
var moment = require('moment')
var timeStamp = moment().format('YYYYMMDD_hhmmss');
exports.config = {
seleniumAddress: 'http://127.0.0.1:4444/wd/hub',
getPageTimeout: 60000,
allScriptsTimeout: 500000,
framework: 'custom',
frameworkPath: require.resolve('protractor-cucumber-framework'),
// Capabilities to be passed to the webdriver instance.
multiCapabilities: multiCapabilities,
// Spec patterns are relative to the current working directory when
// protractor is called.
specs: ['Features/*.feature'],
baseUrl: 'https://www.linkedin.com/',
cucumberOpts: {
require: 'Features/step_definition/searchstep_linkedin.js',
tags: false,
plugin: ['pretty'],
format: 'json:reports/report'+timeStamp+' '+browser+'/results.json',
profile: false,
'no-source': true
},
plugins: [{
package: 'protractor-multiple-cucumber-html-reporter-plugin',
options:{
automaticallyGenerateReport: true,
}
}]
};
//Feature file
Background: I need to go linked in site
Given I go to url ""
Scenario: Should not login with blank username and password
Then I wait for "2000"
When I enter " " in "#login-email"
When I enter " " in "#login-password"
Then I click on "#login-submit"
Then I should see ""
//Spec File
Given(/^I go to url "(.*)"$/, function (url){
return browser.get(url);
});
When(/^I enter "(.*)" in "(.*)"$/, function (value,locator){ /**/
return element(by.xpath(locator)).sendKeys(value);
});
Then(/^I should see "(.*)"$/, function (url){ /**/
browser.sleep(2000);
return
expect(browser.getCurrentUrl()).to.eventually.equal(browser.baseUrl
+ url);
});
Then(/^I click on "(.*)"$/, function (locator){ /**/
return return element(by.xpath(locator)).click();
});

sails lifecycle - custom service and config.log

I defined a l.js under /api/services
exports.i = sails.log.info;
exports.v = sails.log.verbose;
exports.err = sails.log.error;
exports.w = sails.log.warn;
exports.d = sails.log.debug;
It works fine but when I want to define custom logger in /config/log.js
let customLogger = new (winston.Logger)({
transports: [
new (winston.transports.Console, winston.transports.File)({
name: 'file.info',
level: 'info',
filename: logPath + '/server-info.log',
json: true
}),
new (winston.transports.Console, winston.transports.File)({
name: 'file.warning',
level: 'warning',
filename: logPath + '/server-warning.log',
json: true
}),
new (winston.transports.File)({
name: 'file.error',
level: 'error',
filename: logPath + '/server-error.log',
json: true
})
]
});
module.exports.log = {
level: 'info',
custom: customLogger,
};
When I use sails.log.error("123"); l.err("456") in controller, only "123" showed in server-error.log file. "456" only print to console.
When I check sails doc about lifecycle, it seems /config/log.js loaded before /api/services. How should I modify my code?
Thanks
Although config/log.js is loaded before api/services/l.js, (my feeling is) assignment of custom logger defined in log.js to sails.log.<level> happens after the service is loaded.
Hence the behavior.
Re-assigning on lifted event fixes this. Use this code in l.js:
exports.err = sails.log.error;
sails.on('lifted', function() {
console.log('lifted event');
// Re-assign here
exports.err = sails.log.error;
});
Do similarly for other methods of the service.

winston-mongodb log connection fails

My express web app uses Winston for logging, and the logs are saved to a mongolab hosted mongoDB (replica set) using winston-mongodb.
Everything was working fine for a few days, then when traffic picked up a bit the logs just stopped saving/connecting to the DB. Unfortunately this means I have no logs to check to see what went wrong - a frustrating situation. Everything else is still working fine - other collections (like users) are saving and updating correctly, the server is up.
I've tried redeploying/restarting the server to no avail, the logs won't start recording again. I suspect there is some nuanced problem with my server/logger setup, possibly a race condition related to the DB connection, but I'm really lost right now. Here's the code:
//server.js (simplified required modules - only ones possibly relevant to question)
var express = require( 'express' );
var session = require('express-session');
var methodOverride = require('method-override');
var cookieParser = require('cookie-parser');
var mongoose = require( 'mongoose' );
var uriUtil = require('mongodb-uri');
var config = require('config');
var bodyParser = require('body-parser');
var MongoStore = require('connect-mongostore')(session);
var logger = require('./logs/logger.js');
// DATABASE CONNECT
var options = { server: { socketOptions: { keepAlive: 1, connectTimeoutMS: 30000 } },
replset: { socketOptions: { keepAlive: 1, connectTimeoutMS : 30000 } } };
var mongodbUri = "mongodb://<user>:<pw>#ds012345-a0.mongolab.com:12345,ds012345-a1.mongolab.com:12345/<db>"
//use mongo-uri to make sure url is in the correct format
var mongooseUri = uriUtil.formatMongoose(mongodbUri);
mongoose.connect(mongooseUri, options);
var conn = mongoose.connection;
// __Create server__
var app = express();
conn.on('open', function(e) {
var sessionStore = new MongoStore({ mongooseConnection: mongoose.connections[0] });
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
app.use(methodOverride());
app.use(cookieParser());
app.use(session({
store: sessionStore,
secret: config.session.secret,
cookie: {
maxAge: config.session.maxage,
httpOnly: true,
secure: false
//If I set 'secure:true', it prevents the session from working properly.
},
saveUninitialized: true,
resave: true
}));
app.use(passport.initialize());
app.use(passport.session());
app.use( express.static( path.join( __dirname, 'site') ) );
//Routes
app.use('/api/forgot', controllers.forgotpw);
//etc.
});
conn.on('connected', function(){
//Start server
app.listen(config.port, function() {
logger.info( 'Express server listening on port %d in %s mode', config.port, app.settings.env );
logger.info(process.env.NODE_ENV);
});
});
//logger.js
var winston = require('winston');
var config = require('config');
require('winston-mongodb').MongoDB;
if (process.env.NODE_ENV == 'production') {
var winston = new (winston.Logger)({
transports: [
new (winston.transports.Console)({ level: 'warn' }),
new (winston.transports.MongoDB)({
//db : 'atlas_database',
level : 'debug',
//ssl : true,
dbUri : "mongodb://<user>:<pw>#ds012345-a0.mongolab.com:12345,ds012345-a1.mongolab.com:12345/<db>"
})
]
});
winston.info('Chill Winston, the logs are being captured with production settings');
}
module.exports = winston;
Any thoughts on what is causing the logs to no longer function would be greatly appreciated.
When Winston establishes a connection to a Mongo instance, it looks specifically for the replicaSet flag to determine if the connection is a replica set. Otherwise, it connects to the first host in the dbUri. ( Source: https://github.com/indexzero/winston-mongodb/blob/master/lib/winston-mongodb.js#L28 )
To have configure Winston with a connection that will properly handle failovers, use the following URI:
dbUri : "mongodb://<user>:<pw>#ds012345-a0.mongolab.com:12345,ds012345-a1.mongolab.com:12345/<db>?replicaSet=<replsetname>"
If you ever want to test your code to verify that it can handle a replica set failover gracefully, you can use a testing cluster called flip-flop described here: http://mongolab.org/flip-flop/
(Full Disclosure: I work for MongoLab.)

sencha touch rest proxy url

Why if a use a JSON file foo.json my code works but if I change the URL to something.com/foo.json it doesn´t work?
This is working in my project:
var store = Ext.create('Ext.data.Store', {
model: 'Client',
autoLoad: true,
autoSync: true,
proxy: {
type: 'rest',
url : 'clients.json',
reader: {
type: 'json'
}
}
});
What I want is to replace the static file for an URL:
var store = Ext.create('Ext.data.Store', {
model: 'Client',
autoLoad: true,
autoSync: true,
proxy: {
type: 'rest',
url : 'http://rails-api.herokuapp.com/clients.json',
reader: {
type: 'json'
}
}
});
The clients.json file is a copy/paste from http://rails-api.herokuapp.com/clients.json it is the same data.
Where do you run your application? Are you able to track the http requests? Do you get any output on your javascript console?
If i had to guess I'd say that your issue might be related to CORS => http://en.wikipedia.org/wiki/Cross-origin_resource_sharing.
Edit:
Note that you only need to have a look at CORS or use jsonp if you are running your app and the "backend"/api on two different webservers.
Most people will probably...
a) ...run the app on the same webserver as the backend or...
b) ...use native packaging (cordova, phonegap or sencha cmd s own packaging).
In both cases you can simply use the "normal" ajax or rest proxys.
On the server side I had to add the callback, see this question sencha-seems-to-not-like-rails-json also I had to change the type from rest to jsonp and removed some useless code, at the end my code looks like this:
var store = Ext.create('Ext.data.Store', {
model: 'Client',
autoLoad: true,
autoSync: true,
proxy: {
type: 'jsonp',
url : 'http://rails-api.herokuapp.com/clients.json'
}
});
on the server side:
def index
#clients = Client.all
respond_to do |format|
format.html
format.json { render :json => #clients, :callback => params[:callback] }
end
end