How to log/debug a Crossbar guest worker? - autobahn

How can I capture output/logs from a guest worker and/or debug it? The worker is a regular Python3 Autobahn WAMP component. Whatever I print or raise or write to stderr is nowhere to be found; or I don't know where to look. Only if the guest terminates with an error is anything output to the Crossbar log. Here's the configuration:
workers:
- type: guest
executable: python3
arguments: ['../foo.py']
options:
stdout: log
stderr: log
The stdout and stderr options seem to make no difference whatsoever.
Versions:
Crossbar.io: 0.10.1
Autobahn|Python: 0.9.5
worker: autobahn.asyncio.wamp.ApplicationSession

By default, Python stdout/stderr is buffered so crossbar won't see the logs from the guest when you might think.
You can either set the environment variable PYTHONUNBUFFERED=1 or pass the -u option to your interpreter.

crossbar check validates stdout: log and stderr: log but Im not sure why it doesn't log the errors.
I normally do it like below but your config looks more clean and handy.
Setup
Follow this (Debugging Crossbar.io app in IntelliJ). Do similar thing for the IDE you use, however, I recommend to use PyPy for crossbar router instead of CPython.
Logging
Follow this (Logging WAMP worker Trace Back Error).
You just gotta enable the Trace Back Error logging feature. You can import traceback and use try except or just use create a simple __init__ function like below:
class MyComponent(ApplicationSession):
def __init__(self, config = None):
ApplicationSession.__init__(self, config)
self.traceback_app = True
Below is a full working example:
Error log
.crossbar/config.yaml
controller: {}
workers:
- realms:
- name: realm1
roles:
- name: anonymous
permissions:
- {call: true, publish: true, register: true, subscribe: true, uri: '*'}
transports:
- endpoint: {port: 8080, type: tcp}
paths:
/: {directory: .., type: static}
ws: {type: websocket}
type: web
type: router
- arguments: [backend.py]
executable: ../../../.pyenv/versions/autobahn/bin/python3
options:
watch:
action: restart
directories: [..]
workdir: ..
type: guest
backend.py
from autobahn.asyncio.wamp import ApplicationSession
from autobahn import wamp
from asyncio import coroutine
import logging
class MyComponent(ApplicationSession):
def __init__(self, config = None):
ApplicationSession.__init__(self, config)
self.traceback_app = True
#wamp.register("com.myapp.add2")
def add2(self, x, y):
if type(y) is str:
error = ' Sorry! Python can not add int with something else :('
logging.critical(error)
return error
return x + y
#coroutine
def onJoin(self, details):
res = yield from self.register(self)
print("{} procedures registered.".format(len(res)))
if __name__ == '__main__':
from autobahn.asyncio.wamp import ApplicationRunner
runner = ApplicationRunner(url="ws://localhost:8080/ws", realm="realm1")
runner.run(MyComponent)
frontend.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
<script>AUTOBAHN_DEBUG = false;</script>
<script src="http://autobahn.s3.amazonaws.com/autobahnjs/latest/autobahn.min.jgz"></script>
<script>
var connection = new autobahn.Connection({
url: "ws://localhost:8080/ws",
realm: "realm1"
});
connection.onopen = function (session, details) {
// Should work
session.call("com.myapp.add2", [1, 2]).then(session.log);
// Expected to log an error
session.call("com.myapp.add2", [2, "three"]).then(session.log);
// Expected to log the trace back error
session.call("com.myapp.add2", ["one", 5]).then(session.log);
};
connection.onclose = function (reason, details) {
console.log("Connection lost: " + reason);
};
connection.open();
</script>
</body>
</html>

I had a similar issue of crossbar not outputting anything after the initial startup. Even though there are console.log() in the code. In my case it is with the node.js crossbar router.
The solution was to add "--loglevel=debug" to the start command
crossbar start --loglevel=debug
Then I started seeing output when console.log() where executed.

Related

How to run nextjs in AWS lambda with `experimental-edge` runtime

I'm trying to find a way to run Next.js (v13.0.6) with OG image generation logic (using #vercel/og) in AWS Lambda
Everything works fine locally (in dev and prod mode) but when I try execute lambda handler getting "statusCode": 500,
It only fails for apis that involve ImageResponse (and runtime: 'experimental-edge' as a requirement for #vercel/og)
I'm pretty sure the problem is caused by Edge Runtime is not being configured correctly
There is my handler code
next build with next.config.js output: 'standalone' creates folder .next/standalone
insde standalone handler.js
const { parse } = require('url');
const NextServer = require('next/dist/server/next-server').default
const serverless = require('serverless-http');
const path = require('path');
process.env.NODE_ENV = 'production'
process.chdir(__dirname)
const currentPort = parseInt(process.env.PORT, 10) || 3000
const nextServer = new NextServer({
hostname: 'localhost',
port: currentPort,
dir: path.join(__dirname),
dev: false,
customServer: false,
conf: {...} // copied from `server.js` in there same folder
});
const requestHandler = nextServer.getRequestHandler();
// this is a AWS lambda handler that converts lambda event
// to http request that next server can process
const handler = serverless(async (req, res) => {
// const parsedUrl = parse(req.url, true);
try {
await requestHandler(req, res);
}catch(err){
console.error(err);
res.statusCode = 500
res.end('internal server error')
}
});
module.exports = {
handler
}
testing it locally with local-lambda, but getting similar results when test against AWS deployed lambda
what is confusing is that server.js (in .next/standalone) has a similar setup, it only involves http server on top of of it
update:
aws lambda logs show
ERROR [Error [CompileError]: WebAssembly.compile(): Compiling function #64 failed: invalid value type 'Simd128', enable with --experimental-wasm-simd #+3457 ]
update 2:
the first error was fixed by selecting Node 16 for AWS lambda, now getting this error
{
"errorType": "Error",
"errorMessage": "write after end",
"trace": [
"Error [ERR_STREAM_WRITE_AFTER_END]: write after end",
" at new NodeError (node:internal/errors:372:5)",
" at ServerlessResponse.end (node:_http_outgoing:846:15)",
" at ServerlessResponse.end (/var/task/node_modules/next/dist/compiled/compression/index.js:22:783)",
" at NodeNextResponse.send (/var/task/node_modules/next/dist/server/base-http/node.js:93:19)",
" at NextNodeServer.handleRequest (/var/task/node_modules/next/dist/server/base-server.js:332:47)",
" at processTicksAndRejections (node:internal/process/task_queues:96:5)",
" at async /var/task/index.js:34:5"
]
}
At the moment of writing Vercel's runtime: 'experimental-edge' seems to be unstable (run into multiple issues with it)
I ended up recreating #vercel/og lib without wasm and next.js dependencies, can be found here
and simply use it in AWS lambda. It depends on #resvg/resvg-js instead of wasm version, which uses binaries, so there should not be much perf loss comparing to wasm

AWS Typescript CDK: Lambda Version Internal Failure

I have the following code:
const func = new NodejsFunction(this, <function name>, {
memorySize: 2048,
timeout: Duration.seconds(60),
runtime: Runtime.NODEJS_14_X,
handler: 'handler',
role: <role>,
entry: path.join(__dirname, <filePath>),
currentVersionOptions: {
description: `Version created on ${new Date(Date.now())}`,
},
});
const version = func.currentVersion;
const alias = new Alias(this, 'VersionAlias', {
aliasName: 'current',
version,
});
I do this with a handful of Lambda functions all in the same stack. The first deployment works, however the lambda functions are created with random version numbers (some have v4, some with v5, some with v7).
Subsequent deployments then fail with a vague Internal Failure error message. So I check the CloudTrail logs and find a series of ResourceNotFoundException errors. The "Version" resources are unable to be updated because they have the incorrect version number stemming from the first deploy. How can I force CloudFormation to start at #1 for versioning my lambda functions?
For anyone visiting this later, the problem was with the following code:
currentVersionOptions: {
description: `Version created on ${new Date(Date.now())}`,
},
Apparently you can't have a dynamic description as it is an immutable field

systematic failure when trying to execute a system command with Cypress

I'm new to Cypress and Javascript
I'm trying to send system commands through Cypress. I've been through several examples but even the simplest does not work.
it always fails with the following message
Information about the failure:
Code: 127
Stderr:
/c/Program: Files\Git\usr\bin\bash.exe: No such file or directory`
I'm trying cy.exec('pwd') or 'ls' to see where it is launched from but it does not work.
Is there a particular include I am missing ? some particular configuration ?
EDIT :
indeed, I'm not clear about the context I'm trying to use the command in. However, I don't set any path explicitely.
I send requests on a linux server but I also would like to send system commands.
My cypress project is in /c/Cypress/test_integration/cypress
I work with a .feature file located in /c/Cypress/test_integration/cypress/features/System and my scenario calls a function in a file system.js located in /c/Cypress/test_integration/cypress/step_definitions/generic.
System_operations.features:
Scenario: [0004] - Restore HBox configuration
Given I am logging with "Administrator" account from API
And I store the actual configuration
...
Then I my .js file, I want to send a system command
system.js:
Given('I store the actual configuration', () => {
let nb_elem = 0
cy.exec('ls -l')
...
})
I did no particular path configuration in VS Code for the use of bash command (I just configured the terminal in bash instead of powershell)
Finally, with some help, I managed to call system functions by using tasks.
In my function I call :
cy.task('send_system_cmd', 'pwd').then((output) => {
console.log("output = ", output)
})
with a task created as follows:
on('task', {
send_system_cmd(cmd) {
console.log("task test command system")
const execSync = require('child_process').execSync;
const output = execSync(cmd, { encoding: 'utf-8' });
return output
}
})
this works at least for simple commands, I haven't tried much further for the moment.
UPDATE for LINUX system commands as the previous method works for WINDOWS
(sorry, I can't remember where I found this method, it's not my credit. though it fulfills my needs)
This case requires node-ssh
Still using tasks, the function call is done like this
cy.task('send_system_cmd', {cmd:"<my_command>", endpoint:<address>,user:<ssh_login>, pwd:<ssh_password>}).then((output) => {
<process output.stdout or output.stderr>
})
with the task being build like this:
// send system command - remote
on('task', {
send_system_cmd({cmd, endpoint, user, pwd}) {
return new Promise((resolve, reject) => {
const { NodeSSH } = require('node-ssh')
const ssh = new NodeSSH()
let ssh_output = {}
ssh.connect({
host: endpoint,
username: user,
password: pwd
})
.then(() => {
if(!ssh.isConnected())
reject("ssh connection not set")
//console.log("ssh connection OK, send command")
ssh.execCommand(cmd).then(function (result) {
ssh_output["stderr"] = result.stderr
ssh_output["stdout"] = result.stdout
resolve(ssh_output)
});
})
.catch((err)=>{
console.log(err)
reject(err)
})
})
}
})

Using SocketIo Manager with a default URL

My goal is to add a token in the socketio reconnection from the client (works fine on the first connection, but the query is null on the reconnection, if the server restarted while the client stayed on).
The documentation indicates I need to use the Manager to customize the reconnection behavior (and add a query parameter).
However, I'm getting trouble finding how to use this Manager: I can't find a way to connect to the server.
What I was using without Manager (works fine):
this.socket = io({
query: {
token: 'abc',
}
});
Version with the Manager:
const manager = new Manager(window.location, {
hostname: "localhost",
path: "/socket.io",
port: "8080",
query: {
auth: "123"
}
});
So I tried many approaches (nothing, '', 'http://localhost:8080', 'http://localhost:8080/socket.io', adding those lines to the options:
hostname: "localhost",
path: "/socket.io",
port: "8080" in the options,
But I couldn't connect.
The documentation indicates the default URL is:
url (String) (defaults to window.location)
For some reasons, using window.location as URL refreshes the page infinitely, no matter if I enter it as URL in the io() creator or in the new Manager.
I am using socket.io-client 3.0.3.
Could someone explain me what I'm doing wrong ?
Thanks
Updating to 3.0.4 solved the initial problem, which was to be able to send the token in the initial query.
I also found this code in the doc, which solves the problem:
this.socket.on('reconnect_attempt', () => {
socket.io.opts.query = {
token: 'fgh'
}
});
However, it doesn't solve the problem of the Manager that just doesn't work. I feel like it should be removed from the doc. I illustrated the problem in this repo:
https://github.com/Yvanovitch/socket.io/blob/master/examples/chat/public/main.js

Issues running BrowserStackLocal for website behind firewall

I'm trying to run browserstack behind the firewall.
I tried to run this command on terminal:
RK$ ./BrowserStackLocal --key <key> --force-local
BrowserStackLocal v7.0
You can now access your local server(s) in our remote browser.
Press Ctrl-C to exit
I opened another terminal and I ran the command
npm run test:functional:cr:mobile
I get the following error:
1) Run sample test flow page:
Uncaught WebDriverError: [browserstack.local] is set to true but local testing through BrowserStack is not connected.
This is my config.js
'use strict'
import webdriver from 'selenium-webdriver'
let driver
module.exports = {
getDriverConfiguration: function (testTitle, browserName) {
var capabilities = {
'browserName': process.env.BROWSER || 'Chrome',
'realMobile': 'true',
'os': 'android',
'deviceName': process.env.DEVICE || 'Samsung Galaxy S8',
'browserstack.user': 'USER',
'browserstack.key': 'KEY',
'browserstack.debug': 'true',
'build': 'Build for mobile testing',
'browserstack.local' : 'true',
'browserstack.localIdentifier' : 'Test123'
}
driver = new webdriver.Builder().withCapabilities(capabilities).usingServer('http://hub-cloud.browserstack.com/wd/hub').build()
driver.manage().deleteAllCookies()
return driver
}
}
I enabled browserstack.local to true but I still get this error.
Not sure where I'm going wrong.
Please kindly help.
The error [browserstack.local] is set to true but local testing through BrowserStack is not connected. is returned if your BrowserStackLocal connection (the one you established using ./BrowserStackLocal --key --force-local) is disconnected.
I would suggest you use the following approach instead, to avoid the additional step and easily manage your local testing connection:
npm install browserstack-local
Once you have installed the browserstack-local module, use the following code snippet as reference to modify your code and start browserstack-local from your code itself(before the line driver = new webdriver.Builder().withCapabilities(capabilities).usingServer('http://hub-cloud.browserstack.com/wd/hub').build()), instead of starting it from a separate terminal window:
var browserstack = require('browserstack-local');
//creates an instance of Local
var bs_local = new browserstack.Local();
// replace <browserstack-accesskey> with your key. You can also set an environment variable - "BROWSERSTACK_ACCESS_KEY".
var bs_local_args = { 'key': '<browserstack-accesskey>', 'forceLocal': 'true' };
// starts the Local instance with the required arguments
bs_local.start(bs_local_args, function() {
console.log("Started BrowserStackLocal");
});
// check if BrowserStack local instance is running
console.log(bs_local.isRunning());
// stop the Local instance
bs_local.stop(function() {
console.log("Stopped BrowserStackLocal");
});

Resources