I'm using Winston and Morgan for all the back-end logging in Sails.js and I need to be able to log the responses from HTTP get requests. I need to log them in a file. My logFile currently takes shows all the http requests but it does not show the responses. I have searched all the options for Morgan and Winston and can't find a way/option to do this. I was just wondering if any of you had any advice on how to accomplish this?
Thanks!
You can write a middleware function for ExpressJS that will log the body once a response is sent. Basing it off of Node's http module to see how Connect (and therefore Express) manages the response body (which is a stream): you can hook into the two methods that write to that stream to grab the chunks and then concat/decode them to log it. Simple solution and could be made more robust but it shows the concept works.
function bodyLog(req, res, next) {
var write = res.write;
var end = res.end;
var chunks = [];
res.write = function newWrite(chunk) {
chunks.push(chunk);
write.apply(res, arguments);
};
res.end = function newEnd(chunk) {
if (chunk) { chunks.push(chunk); }
end.apply(res, arguments);
};
res.once('finish', function logIt() {
var body = Buffer.concat(chunks).toString('utf8');
// LOG BODY
});
next();
}
And then set it before any routes are assigned in the main app router:
app.use(bodyLog);
// assign routes
I would assume you could also use this as an assignment for a variable in Morgan but I haven't looked into how async variable assignment would work.
Related
My Google Actions project points to a Google Cloud Function as a webhook. In the google cloud function I am able to create the conversation responses using conv.ask(...).
However, what I am trying to do is: build a generic conversation content framework that resides on another server (also google cloud function) where I would like to compose the response and send it back to the webhook function.
The relevant code in both these servers are like this:
// in the webhook function
app.intent('actions.intent.MAIN', (conv, input) => {
// here I would like to call the second google function by
// passing, say, the input and receiving a response that can
// be passed on to the conv
// something like
// assume request-promise is being used
//
var options = {
method: 'POST',
uri: '..',
body: {...},
json: true
};
rp(options)
.then(resp => {
conv.ask(resp) // this is what I would like to do
});
});
In the second Google Functions server, I am using express as middleware. Here on some logic templated responses get built
const ..
const {
SimpleResponse,
BasicCard,
...
} = require('actions-on-google');
...
const express = require('express');
var app = express();
...
app.post('/main', function(req, res, next) {
// here I would like to compose the response
// and send it to the earlier function
var convresp = new SimpleResponse({...});
..
res.send(convresp);
// this seems to be only sending the json
// and causes the receiving response to give an error
// when applying to conv.ask in the above code
});
Question is: how should the response be sent from the second function so that it can be "pasted" to the conv.ask functionality in the first function?. Thanks
How to write the http module function to read data from local json file? I am now using this to read the data. I want the function to read the data from this url - http://localhost:8000/app/source.json
var observableModule = require("data/observable");
var source = require("./source.json");
var properties = require("./properties.json");
function HomeViewModel() {
var viewModel = new observableModule.Observable();
viewModel.set("categoricalSource", source.categoricalSource);
viewModel.set("categoryProperty", properties.categoryProperty);
viewModel.set("valueProperty", properties.valueProperty);
return viewModel;
}
module.exports = HomeViewModel;
To access localhost from the Android emulator, refer to Accessing localhost:port from Android emulator
In short - http://10.0.2.2:<hostport> replaces localhost:<hostport>
Refer to the NativeScript docs on http for making http requests. To access http://localhost:8000/app/source.json yours should look like so:
http.getJSON("http://10.0.2.2:8000/source.json").then(function (r) {
//// Argument (r) is JSON!
}, function (e) {
//// Argument (e) is Error!
//console.log(e);
});
And finally, if you need to read a JSON from the application directory, a require should suffice.
So I've searched and I think a saw the entire internet but no solution regarding the issue I encounter.
I have multiple http request which I want to mock. All request have the same url but deviate based on the requestPayload which contain a graphQl query. Based on this query I want to return a specific json file. All proxy settings I have found can handle parameters but do not handle responses based on requestPayload.
Have you taken a look over this functionality?
https://webpack.js.org/configuration/dev-server/#devserver-before
as far as webpack-dev-server is an instance of express app you are able to setup it in the before/after hooks. Hooks get app (server) instance as a first argument.
so for your case your webpack development config would look like:
module.exports = {
//...
devServer: {
before: function(app) {
var bodyParser = require('body-parser');
app.use(bodyParser.json());
app.get('/some/path/graphql', function(req, res) {
var query = req.body;
// ...your custom logic of
// specific query handling goes here
if (condition(query)) {
res.json({ mockedResponse: 'foo' });
} else {
res.json({ mockedResponse: 'bar' });
}
});
}
}
};
UPD: keep in mind if you're using proxy config for devServer you might want to use after hook instead of before to let your requests be proxified if needed.
Quick question guys. I think i got the logic down but I am messed up because express doesnt have a pipe method?
anyways, I have this for my express endpoint
app.get('/:report/top', function(req, res) {
readDataTop(global[req.params.report], function(err, obj) {
res.header("Cache-Control", "max-age=3600");
res.json(obj);
});
});
and currently i am doing this to get data for it.
function readDataTop (x, callback) {
console.log("Read "+x[6]+" and Sent Cached Top Half");
jf.readFile( "loadedreports/top"+x[6], 'utf8', callback);
};
(jf just makes writing json.parse and with try/catch blocks easier) anyways I want to instead of just using fs.readfile i want to open a stream because these files are getting huge.
How would I pipe stuff to express but still use json?
Something like this?
function readDataTop (x, callback) {
console.log("Read "+x[6]+" and Sent Cached Top Half");
var rstream = fs.createReadStream("loadedreports/top"+req.params.report+".json");
rstream.pipe(callback);
};
Any ideas? Req is undefined but I thought im passing it through the pipe correctly?
I'm looking for a way to access the JSON being sent back to the requestor in the "after" filter for a controller.
var locomotive = require('locomotive');
var myController = new locomotive.Controller();
myController.after('myAction', function(next) {
var response = {}; //I want to access the JSON being sent back in myAction: {'hello':'world'}
console.log(response); //this should log "{'hello':'world'}"
next();
});
myController.myAction = function myAction() {
this.res.json({'hello':'world'});
}
module.exports = myController;
If anyone has any way of doing this, it would be much appreciated.
In your main action, assign your json to an object on this (res is reserved):
myController.myAction = function myAction() {
this.model = {'hello':'world'};
this.res.json(this.model);
}
Then you can access it in your after filter:
myController.after('myAction', function(next) {
var model = this.model;
console.log(model);
next();
});
I found a "hack" solution... It's not the cleanest, and requires changing the code within the express response.js file in "node_modules"...
If anyone has a better option where you can access the json being sent in response to the request within the controller action (or controller filter) itself, I'd greatly appreciate it.
Thanks.
in the ~/node_modules/locomotive/node_modules/express/lib/response.js file, I altered the "res.json" function (line 174 for me) to include the following line after the declaration of the body variable (which is passed to the send function).
this.responseJSON = body;
This allows you to access this.responseJSON within a controller's after filter, as follows:
myController.after('myAction', function(next) {
**var response = this.res.responseJSON; //ACCESS RESPONSE JSON HERE!!!!!**
console.log(response); //Now logs "{'hello':'world'}"
next();
});
Like I said, not the most elegant, but gets the job done in a pinch. Any more elegant solutions welcome...