Skip to content

Commit

Permalink
feat(runtime&server): support display error/log line (#1813)
Browse files Browse the repository at this point in the history
* feat(runtime&server): support display error/log line

* fix

* improve

* chore
  • Loading branch information
0fatal authored Jan 23, 2024
1 parent 59da485 commit faefc11
Show file tree
Hide file tree
Showing 11 changed files with 118 additions and 22 deletions.
18 changes: 18 additions & 0 deletions runtimes/nodejs/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions runtimes/nodejs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
"node-modules-utils": "^1.0.0-beta.14",
"nodemailer": "^6.6.3",
"pako": "^2.1.0",
"source-map-support": "^0.5.21",
"typescript-language-server": "^3.3.2",
"validator": "^13.7.0",
"vscode-languageserver": "^9.0.1",
Expand Down
7 changes: 7 additions & 0 deletions runtimes/nodejs/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ export default class Config {
return (process.env['LOG_LEVEL'] as any) || 'debug'
}

/**
* the logger display line level : 'info', 'warn', 'error', 'debug'
*/
static get DISPLAY_LINE_LOG_LEVEL(): 'debug' | 'info' | 'warn' | 'error' {
return (process.env['DISPLAY_LINE_LOG_LEVEL'] as any) || 'error'
}

/**
* the object depth limit when logging
*/
Expand Down
18 changes: 18 additions & 0 deletions runtimes/nodejs/src/handler/invoke.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,17 @@ async function invokeDebug(
requestId,
})
}

// for debug usage
require('source-map-support').install({
emptyCacheBetweenOperations: true,
overrideRetrieveFile: true,
retrieveFile: (path) =>
funcName === path
? funcData.source.compiled
: FunctionCache.get(path)?.source.compiled,
})

const debugConsole = new DebugConsole(funcName)
const executor = new FunctionDebugExecutor(funcData, debugConsole)

Expand Down Expand Up @@ -218,5 +229,12 @@ async function invokeDebug(
} catch (error) {
debugConsole.error(requestId, 'failed to invoke error', error)
return ctx.response.status(500).send('Internal Server Error')
} finally {
// restore
require('source-map-support').install({
emptyCacheBetweenOperations: true,
overrideRetrieveFile: true,
retrieveFile: (path) => FunctionCache.get(path)?.source.compiled,
})
}
}
7 changes: 7 additions & 0 deletions runtimes/nodejs/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ import url from 'url'

import { LspWebSocket } from './support/lsp'
import { createCloudSdk } from './support/cloud-sdk'
import { FunctionCache } from './support/engine'

require('source-map-support').install({
emptyCacheBetweenOperations: true,
overrideRetrieveFile: true,
retrieveFile: (path) => FunctionCache.get(path)?.source.compiled,
})

// hack: set createCloudSdk to global object to make it available in @lafjs/cloud package
globalThis.createCloudSdk = createCloudSdk
Expand Down
34 changes: 33 additions & 1 deletion runtimes/nodejs/src/support/engine/console.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,26 @@ export class Console {

const fn = chalk.blueBright(`[${this.category}]`)

let location = ''
if (this._shouldDisplayLine(level)) {
try {
throw new Error()
} catch (e) {
try {
// exclude involuntary log
if (e.stack.includes('Executor.invoke')) {
const msgs = e.stack.includes('at DebugConsole._format')
? e.stack.split('\n')[4].split(':')
: e.stack.split('\n')[3].split(':')
const line = msgs[1]
let loc = msgs[0].match(/at (.*?) \(/)[1]
loc = loc === 'default_1' ? 'MAIN' : loc
location = chalk.gray(`(${loc}:${line})`)
}
} catch {}
}
}

const content = params
.map((param) => {
if (typeof param === 'string') return this._colorize(level, param)
Expand All @@ -42,7 +62,7 @@ export class Console {
.join(' ')

// content = this._colorize(level, content)
const data = `${time} ${levelStr} ${fn} ${content}`
const data = `${time} ${levelStr} ${fn}${location} ${content}`
return data
}

Expand Down Expand Up @@ -106,6 +126,18 @@ export class Console {
const configLevelValue = LogLevelValue[configLevel] ?? 0
return LogLevelValue[level] >= configLevelValue
}

protected _shouldDisplayLine(level: LogLevel) {
const LogLevelValue = {
[LogLevel.INFO]: 1,
[LogLevel.WARN]: 2,
[LogLevel.ERROR]: 3,
[LogLevel.DEBUG]: 4,
}
const configLevel = (Config.DISPLAY_LINE_LOG_LEVEL || 'error').toUpperCase()
const configLevelValue = LogLevelValue[configLevel] ?? 3
return LogLevelValue[level] >= configLevelValue
}
}

export class DebugConsole extends Console {
Expand Down
23 changes: 12 additions & 11 deletions runtimes/nodejs/src/support/engine/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ export class FunctionModule {

// build function module
const data = FunctionCache.get(fn)
if (!data) {
throw new Error(`function ${fn} not found`)
}
const mod = this.compile(fn, data.source.compiled, fromModule)

// cache module
Expand Down Expand Up @@ -86,15 +89,15 @@ export class FunctionModule {
consoleInstance,
)
const options: RunningScriptOptions = {
filename: `FunctionModule.${functionName}`,
filename: functionName,
displayErrors: true,
contextCodeGeneration: {
strings: true,
wasm: true,
},
} as any

const script = this.createScript(wrapped, {})
const script = this.createScript(wrapped, options)
return script.runInNewContext(sandbox, options)
}

Expand All @@ -103,15 +106,12 @@ export class FunctionModule {
}

protected static wrap(code: string): string {
return `
const require = (name) => {
__from_modules.push(__filename)
return __require(name, __from_modules, __filename)
}
${code}
module.exports;
`
// ensure 1 line to balance line offset of error stack
return [
`function require(name){__from_modules.push(__filename);return __require(name,__from_modules,__filename);}`,
`${code}`,
`\nmodule.exports;`,
].join(' ')
}

/**
Expand Down Expand Up @@ -162,6 +162,7 @@ export class FunctionModule {
exports: _module.exports,
console: fConsole,
__require: this.require.bind(this),
RegExp: RegExp,
Buffer: Buffer,
setImmediate: setImmediate,
clearImmediate: clearImmediate,
Expand Down
1 change: 1 addition & 0 deletions runtimes/nodejs/src/support/engine/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export interface FunctionModuleGlobalContext {
console: any
__require: RequireFuncType
Buffer: typeof Buffer
RegExp: typeof RegExp
setTimeout: typeof setTimeout
clearTimeout: typeof clearTimeout
setInterval: typeof setInterval
Expand Down
5 changes: 4 additions & 1 deletion server/src/function-template/function-template.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,10 @@ export class FunctionTemplateService {
name: functionTemplateItem.name,
source: {
code: functionTemplateItem.source.code,
compiled: compileTs2js(functionTemplateItem.source.code),
compiled: compileTs2js(
functionTemplateItem.source.code,
functionTemplateItem.name,
),
version: 0,
},
desc: functionTemplateItem.desc || '',
Expand Down
7 changes: 4 additions & 3 deletions server/src/function/function.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export class FunctionService {
name: dto.name,
source: {
code: dto.code,
compiled: compileTs2js(dto.code),
compiled: compileTs2js(dto.code, dto.name),
version: 0,
},
desc: dto.description,
Expand Down Expand Up @@ -110,6 +110,7 @@ export class FunctionService {
{
$set: {
name: dto.newName,
'source.compiled': compileTs2js(func.source.code, dto.newName),
desc: dto.description,
methods: dto.methods,
tags: dto.tags || [],
Expand Down Expand Up @@ -163,7 +164,7 @@ export class FunctionService {
$set: {
source: {
code: dto.code,
compiled: compileTs2js(dto.code),
compiled: compileTs2js(dto.code, func.name),
version: func.source.version + 1,
},
desc: dto.description,
Expand Down Expand Up @@ -311,7 +312,7 @@ export class FunctionService {
source: {
...func.source,
code: dto.code,
compiled: compileTs2js(dto.code),
compiled: compileTs2js(dto.code, func.name),
version: func.source.version + 1,
},
updatedAt: new Date(),
Expand Down
19 changes: 13 additions & 6 deletions server/src/utils/lang.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,19 @@ import * as ts from 'typescript'
* compile typescript code to javascript
* @param source typescript source code
*/
export function compileTs2js(source: string) {
const jscode = ts.transpile(source, {
module: ts.ModuleKind.Node16,
target: ts.ScriptTarget.ES2022,
removeComments: true,
})
export function compileTs2js(source: string, name: string) {
const jscode = ts.transpile(
source,
{
module: ts.ModuleKind.Node16,
target: ts.ScriptTarget.ES2022,
removeComments: true,
inlineSourceMap: true,
},
name,
undefined,
name,
)

return jscode
}
Expand Down

0 comments on commit faefc11

Please sign in to comment.