Update Oct 12:
The issue is fixed now. See this post in aws forum for details.
I wrote a nodejs function simply respond with some Chinese characters. But it respond with wrong characters.
exports.handler = function(event, context) {
context.succeed('Hello 世界!');
};
The function result becomes:
"Hello ������������!"
I came across this problem when I wrote a function to parse some Chinese websites and retrieve their page titles. I manage to convert them into utf-8 (I used needle for the request), and console.log(title) correctly display those Chinese characters. But the result from context.succeed() shows up like the example above. What should I do to deal with these non-latin characters when responding the result?
From AWS Support (August 10, 2015):
Thank you for reaching out AWS Support with your question about
Lambda and UTF-8.
We are presently researching this issue as other customers have
brought this to our attention. There is no eta on when this will be
resolved or if this is something we can resolve.
As in AWS Documentation - Programming Model (Node.js):
Indicates the Lambda function execution and all callbacks completed
successfully. Here's the general syntax:
context.succeed (Object result);
where
Object result – provides the result of the function execution. The
result provided must be JSON.stringify compatible. This parameter is
optional. You can call this method without any parameters (succeed())
or pass a null value (succeed(null)). If AWS Lambda fails to stringify
or encounters another error, an unhandled error is thrown, with the
X-Amz-Function-Error response header set to Unhandled.
So, you can't get the result like this:
Hello 世界!
Because, the string Hello 世界! will be encoded as JSON. So, it will return:
"Hello 世界!"
If you see in the browser using AWS Lambda Console:
"Hello ������!"
Actually it's a valid JSON, you just need to decode it first and then process it.
Try to run this:
exports.handler = function (event, context) {
var jsonStr = JSON.stringify('Hello 世界!');
console.log(jsonStr);
console.log(JSON.parse(jsonStr));
context.succeed('Hello 世界!');
};
The log result will be:
2015-08-07T12:49:54.888Z 12345678-90ab-cdef-1234-567890abcdef "Hello 世界!"
2015-08-07T12:49:54.889Z 12345678-90ab-cdef-1234-567890abcdef Hello 世界!
After you decode it, you can get back your original string.
Related
So I'm trying to recieve data like the clients IP from a pipedream workflow using lua(HTTPGET). And so I have a custom body response in Node.JS with no errors. However, when I print the body response in Lua I get this unusual error. It prints the ip but then says A malformed number is near the clients ip.:
My Node.JS code for pipedream:
await $respond({
status: 200,
immediate: true,
body: `${steps.trigger.event.client_ip}`
})
There are no errors, its fine but heres my Lua code to get the response:
function GetServProtocal()
print(loadstring(game:HttpGet('https://enznhjjype22xb2.m.pipedream.net')))()
end
GetServProtocal()
Also, no errors but the output is weird:
-- I'm using 1.1.1.1 example ip for code so I don't expose my real one.
[string "1.1.1.1"]:1: malformed number near "1.1.1.1"
Remove loadstring from your code. The loadstring function expects some Lua code, which it will turn into an executable function and the string that is being returned by HttpGet is not a valid Lua code, hence the error you get.
I have some node.js based Lambdas that are logging data.
In order to properly query and filter the data etc, I want to log as pure JSON data from my Lambdas.
However, when I do a regular console.log it makes an ordinary string of the data.
console.log({a:1,b:2,x:"xxx"})
Results in this:
2020-04-29T14:46:45.722Z 3f64c499-fbae-4a84-996c-5e5f0cb5302c INFO { a: 1, b: 2, x: 'xxx' }
The logged line above does not seem to be searchable as JSON using the various filter matching options in CloudWatch.
I've tried to call the AWS.CloudWatchLogs API directly but since I'm using lambda I cannot maintain a token between invocations of the functions, so I'm not sure that's the way to go.
Have anyone else had success in logging raw JSON from a Javascript Lambda?
The problem is that console.log() does not go directly to stdout/stderr. You can see that using this Lambda:
const process = require('process');
exports.handler = async (event) => {
console.log("message 1");
process.stdout.write("message 2\n");
};
If you invoke that, you will see output like this:
START RequestId: 6942bebc-1997-42cd-90c2-d76b44c637283 Version: $LATEST
2020-04-29T17:06:07.303Z 6935bebc-1d97-42cd-90c2-d76b4a637683 INFO message 1
message 2
END RequestId: 6942bebc-1997-42cd-90c2-d76b44c637283
So to get the output you want you could either redefine console.log to go to stderr, or write to stdout/stderr directly.
Or you could use a logging framework that writes to stdout/stderr, which may give you more flexibility on how your messages are written. I don't do Node development, but I've heard that Winston is the standard logging framework.
The trick is to use the correct delimiter before the JSON data.
In your example, there is no delimiter before JSON data:
console.log({a:1,b:2,x:"xxx"})
// {a:1,b:2,x:"xxx"}
The official documentation AWS Lambda function logging in Node. js is adding a newline \n character before the data. An example for your code snippet:
console.log('\n%j', {a:1,b:2,x:"xxx"})
// \n{a:1,b:2,x:"xxx"}
That does not work either as of July 2022.
The solution is to use the tab character \t as the delimiter between the message and the data.
console.log('\t%j', {a:1,b:2,x:"xxx"})
// \t{a:1,b:2,x:"xxx"}
An example of building a formatted message and adding structured data:
const name = 'world';
console.log('hello %s\t%j', name, {a:1,b:2,x:"xxx"})
// hello world\t{a:1,b:2,x:"xxx"}
I am trying to mock calls to LUIS via nock, which uses the LuisRecognizer from botbuilder-ai. Here is the relevant information.
The bot itself is calling LUIS and getting the result via const recognizerResult = await this.dispatchRecognizer.recognize(context);. I grabbed the actual result as below:
{"text":"I want to look up my order","intents":{"viewOrder":{"score":0.996454835},"srStatus":{"score":0.0172454268},"expediteOrder":{"score":0.0108480565},"escalate":{"score":0.007967358},"qna":{"score":0.00694736559},"Utilities_Cancel":{"score":0.005627355},"manageProfile":{"score":0.004953466},"getPricing":{"score":0.001781322},"Utilities_Help":{"score":0.0007197641},"getAvailability":{"score":0.0005667514},"None":{"score":0.000321137835}},"entities":{"$instance":{}},"sentiment":{"label":"negative","score":0.171873689},"luisResult":{"query":"I want to look up my order","topScoringIntent":{"intent":"viewOrder","score":0.996454835},"intents":[{"intent":"viewOrder","score":0.996454835},{"intent":"srStatus","score":0.0172454268},{"intent":"expediteOrder","score":0.0108480565},{"intent":"escalate","score":0.007967358},{"intent":"qna","score":0.00694736559},{"intent":"Utilities.Cancel","score":0.005627355},{"intent":"manageProfile","score":0.004953466},{"intent":"getPricing","score":0.001781322},{"intent":"Utilities.Help","score":0.0007197641},{"intent":"getAvailability","score":0.0005667514},{"intent":"None","score":0.000321137835}],"entities":[],"sentimentAnalysis":{"label":"negative","score":0.171873689}}}
For the sake of brevity, I'll just call this "recognizerResult" in the below. I'm successfully intercepting the API call in my test file with nock, with the configuration as follows:
nock('https://westus.api.cognitive.microsoft.com')
.post(/.*/)
.reply(200,{recognizerResult});
I've tried returning both as a JSON object and a string, though I'm almost certain this needs to be JSON object as shown (I'm mocking a call to QnA maker with the same approach that is working). When I run this test via mocha, I get the following error:
TypeError: Cannot read property 'replace' of undefined
at LuisRecognizerV2.normalizeName (node_modules\botbuilder-ai\src\luisRecognizerOptionsV2.ts:96:21)
at luisResult.intents.reduce (node_modules\botbuilder-ai\src\luisRecognizerOptionsV2.ts:104:31)
at Array.reduce (<anonymous>)
at LuisRecognizerV2.getIntents (node_modules\botbuilder-ai\src\luisRecognizerOptionsV2.ts:102:32)
at LuisRecognizerV2.<anonymous> (node_modules\botbuilder-ai\src\luisRecognizerOptionsV2.ts:81:27)
at Generator.next (<anonymous>)
at fulfilled (node_modules\botbuilder-ai\lib\luisRecognizerOptionsV2.js:11:58)
at process._tickCallback (internal/process/next_tick.js:68:7)
I've looked at the code in question within the luisRecognizerOptionsV2.ts file, but can't see where there's an issue. The replace is part of normalizing the intent name, which is there to replace unsupported characters with an "_". The bot runs normally when deployed to Azure (and locally), and the tests work without mocking the call. However, I really want to be able to test this without making actual LUIS calls. Any ideas why I am getting this error and how to fix?
For reference, here is the mock to QnA Maker that is working, though note that I'm using a simple REST call for that instead of the recognizer.
nock('https://myqnaservicename.azurewebsites.net')
.post(/.*/)
.reply(200, {"answers": [{"questions": ["I need an unrecognized utterance for testing"], "answer": "I can hear you now!", "score": 28.48, "id": 1234}]});
The issue is that your {recognizerResult} is what gets saved to const recognizerResult, but is not what gets returned by that API call.
It takes a lot of digging to find it all, but a V2 LUIS client gets the API response, then converts it into recognizerResult.
You've got a few options for "fixing" this:
Set a breakpoint in that node_modules\botbuilder-ai\src\luisRecognizerOptionsV2 file on that const result = line and grab luisResult.
Use something like Fiddler to record the actual API response and use that
Write it manually
For reference, you can see how we do this in our tests:
nock()
Recorded response
You can see that our nock() returns response.v2, which does not contain .topScoringIntent, which is what it's looking for, which is why the error is throwing.
Specifically, the mock response needs to be just the v2/luisResults attributes. In other words, when using the luisRecognizer, the response set in nock needs to be
.reply(200,{ "query": "Sample query", "topScoringIntent": { "intent": "desiredIntent", "score":1}, "entities":[]});
If you look at the test data linked above, there are other attributes in the actual response. But this is the minimum required response if you are just trying to get topIntent to test routing. If you needed other attributes you could add them, e.g. you could add everything within v2 as in this file or some of the more involved files with things like multiple intents.
I am trying to use the google cloud console to test a cloud function. Below is a snippet.
exports.requestCreated = functions.firestore
.document('users/{userId}/requests/{requestId}')
.onWrite((change, context) => {
// execute operation
});
I have tried all sorts of combination of JSON data. E.g.
{"userId":"Xl86pqOpF9T2MAn12p24OJAfYJW2","requestId":"abc1234"}
But I keep getting the following statement in logs:
Request created by {userId}
The actual userId is not being read from the JSON data in the console. Can you help?
This is not a problem with the execution of the cloud function. It's a problem with hardcoding the string.
'users/{userId}/requests/{requestId}' is a hardcoded string. Node.js will not automatically replace {userId} with the value of the variable userId.
Following this previous SO post, try something like this using template strings:
`users/${userId}/requests/${requestId}`
Please note it is surrounded by backticks (`), not single quotes (').
This assumes you already have a userId and requestId variables defined. You must restructure your cloud function like this to retrieve that data. Notice that the specific variable values must be extracted from the event variable.
Thank you, Nareddyt. The function is for Firestore, and the way it is written right now checks if a new document is created under the collection requests. I tried replacing the string as you suggested, but as you pointed out, it requires these variables to be defined. I do not quite understand how to restructure the cloud function because the syntax I have used is how event detection is suggested in the Firestore documentation. My function currently works in its entirety, but testing it is a major pain. I have to go through my mobile app and do the whole userflow to test this function. I am new to Node.js and any guidance would be appreciated.
I'm experimenting with the translation service on the Microsoft bot framework. I've written a method to which I pass a callback function which receives my translated text.
I've got an existing bot that calls an HTTP endpoint to create my output in English. I want to translate the output to the different language before returning it to the user. My unaltered code looks like this:
await request.post(ENDPOINT,
{
headers: HEADERS,
json: BODY
},
async function (error, response, body) {
if (response.statusCode == 202) {
var msg = body.mainResponse.text;
context.sendActivity(msg);
}
});
This runs just fine. Data passed in the HTTP response body gets parsed sent back to the user.
Now I want to plug in my translation service. I've got a single function that I call to do this called Translator.translate(text, callback). I've added this call to my existing function to get:
await request.post(ENDPOINT,
{
headers: HEADERS,
json: BODY
},
async function (error, response, body) {
if (response.statusCode == 202) {
var msg = body.mainResponse.text;
await Translator.translate(msg, function (output) {
context.sendActivity(output);
});
}
}
);
My translation process runs and I get the translation in the output variable, but nothing gets sent back to the user. Looking at the terminal, I see the error "Cannot perform 'get' on a proxy that has been revoked" relating to the context.sendActivity line in my callback.
Can anyone suggest how I keep the context object active?
Thanks in advance.
Many thanks for the assistance everyone - I never completely got to the bottom of this, but I finally fixed it with a complete re-write of the code. I think the problem was caused by a large number of nested synchronous and asynchronous calls. My ultimate solution was to completely get rid of all the nesting - first calling the translation service (and waiting for it), then doing the original call.
I think there are a number of other asynchronous threads inside the methods of both pieces of functionality. I don't have a great understanding of how this works in node, but I'm guessing that the response was getting popped off the stack at the wrong point, which is why I wasn't seeing it. The "cannot perform get" error was a bit of a red herring, it turns out. I get the same error from some of Microsoft's working demo code. I'm sure there's a separate issue there that ought to be fixed, but it wasn't actually caused by this issue. The code was running, but the output was getting lost.