filebeat的javascript插件是怎么run起来的?
filebeat 是由golang 实现的,其间接引用了https://github.com/dop251/goja
包,该包使用纯golang语言实现了 ECMAScript 5.1.
内嵌脚本语言,其实并不少见。比如常用的Lua,就被内嵌在redis中。javascript 相对于lua,是非常灵活的,学习成本也相对较低。
经过调研,实现javascript运行时的包有如下几个:
github.com/robertkrimen/otto
[Star 7.1K]- 最初使的项目
- 性能较低
- go 1.18
- ECMA 不支持严格模式
- 正则不完全兼容
- es6 特性不支持
github.com/dop251/goja
[Star 3.5K]- filebeat使用
- 思想来源于otto
- go 1.16
- ECMAScript 5.1 引擎
- 支持 regex and strict mode
- 在频繁执行较简单的js情况下,性能与otto基本持平,高于v8go
github.com/rogchap/v8go
[Star 2.5K]- 基于google的V8引擎实现(chrome)
- cgo实现,性能最高(在需要执行较长的js代码的情况下),与系统兼容性略差.(windows可能需要自己编译v8)
- javascript兼容性比较好
- 调试困难
otto case
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
| package main
import (
"fmt"
"github.com/robertkrimen/otto"
)
func main() {
vm := otto.New()
// 注入变量
vm.Set("def", map[string]interface{}{"abc": 123})
// 注入方法
vm.Set("Add", func(call otto.FunctionCall) otto.Value {
var a, b int64
a, _ = call.Argument(0).ToInteger()
b, _ = call.Argument(1).ToInteger()
val, _ := vm.ToValue(a + b)
return val
})
// 执行
vm.Run(`
abc = Add(1,2);
console.log("The value of abc is " + abc);
console.log("The value of def is " , def.abc);
`)
// 变量取值
if value, err := vm.Get("abc"); err == nil {
if intVal, err := value.ToInteger(); err == nil {
fmt.Println(intVal)
}
}
}
|
goja case
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
| package main
import (
"fmt"
"github.com/dop251/goja"
)
func main() {
vm := goja.New()
// 返回值
v, _ := vm.RunString("2+2")
fmt.Println(v.Export().(int64))
// 注入方法
vm.Set("add", func(call goja.FunctionCall) goja.Value {
var a, b int64
a = call.Argument(0).ToInteger()
b = call.Argument(1).ToInteger()
val := vm.ToValue(a + b)
return val
})
v, _ = vm.RunString(`add(1,2)`)
fmt.Println(v.Export().(int64))
// 导出方法
vm.RunString(`
function sub(a,b) {
return a - b
}
`)
sub, _ := goja.AssertFunction(vm.Get("sub"))
v, _ = sub(goja.Undefined(), vm.ToValue(10), vm.ToValue(1))
fmt.Println(v.Export().(int64))
}
|
v8go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
package main
import (
"fmt"
v8 "rogchap.com/v8go"
)
func main() {
iso := v8.NewIsolate()
global := v8.NewObjectTemplate(iso)
// 注入方法
fn := v8.NewFunctionTemplate(iso, func(info *v8.FunctionCallbackInfo) *v8.Value {
for _, v := range info.Args() {
fmt.Println(v)
}
val, _ := v8.NewValue(iso, "something")
return val
})
// 注入变量
abc, _ := v8.NewValue(iso, int32(456))
global.Set("abc", abc, v8.ReadOnly)
global.Set("print", fn, v8.ReadOnly)
ctx := v8.NewContext(iso, global)
defer ctx.Close()
ctx.RunScript(`
print("abc", 123, {"abc":123});
print(abc)
`, "")
//获取返回结果
resp, err := ctx.RunScript(`abc + 321`, "")
fmt.Println(resp.Int32(), err)
}
|
性能测试
主要两个方面做性能测试:
- 测试简单的加法操作,主要测试高频的启动js引擎的操作
- 测试js的高频计算,测试在不同引擎中,js源码的执行效率
压测源码
对比如下:
1
2
3
4
5
6
7
8
9
10
11
| goos: darwin
goarch: arm64
pkg: javascripttest
BenchmarkOttoAdd-10 19362 61799 ns/op
BenchmarkGojaAdd-10 15794 75839 ns/op
BenchmarkV8Add-10 4783 260458 ns/op
BenchmarkSumOtto-10 15 70687100 ns/op
BenchmarkSumGoja-10 67 17269518 ns/op
BenchmarkSumV8-10 489 2203052 ns/op
PASS
ok javascripttest 9.329s
|