diff --git a/go.mod b/go.mod index af89dda..4fdbd31 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.20 require ( github.com/cjoudrey/gluahttp v0.0.0-20201111170219-25003d9adfa9 + github.com/cosmotek/loguago v1.0.0 github.com/google/subcommands v1.2.0 github.com/gorilla/css v1.0.0 github.com/gorilla/mux v1.8.0 @@ -29,11 +30,13 @@ require ( github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/mitchellh/mapstructure v1.4.3 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rivo/uniseg v0.4.4 // indirect github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect + github.com/yuin/gluamapper v0.0.0-20150323120927-d836955830e7 // indirect golang.org/x/sys v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect diff --git a/go.sum b/go.sum index 370641d..c47faae 100644 --- a/go.sum +++ b/go.sum @@ -5,6 +5,8 @@ github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a/go.mod h1:2GxOXO github.com/cjoudrey/gluahttp v0.0.0-20201111170219-25003d9adfa9 h1:rdWOzitWlNYeUsXmz+IQfa9NkGEq3gA/qQ3mOEqBU6o= github.com/cjoudrey/gluahttp v0.0.0-20201111170219-25003d9adfa9/go.mod h1:X97UjDTXp+7bayQSFZk2hPvCTmTZIicUjZQRtkwgAKY= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/cosmotek/loguago v1.0.0 h1:cM6xoMPoIL1hRPicMenFNVohylundRIPz+OfpadJyY0= +github.com/cosmotek/loguago v1.0.0/go.mod h1:M/3wRiTLODLY6ufA9sVxOgSvnkYv53sYuDTQEqX0lZ4= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -49,6 +51,8 @@ github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZ github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/microcosm-cc/bluemonday v1.0.25 h1:4NEwSfiJ+Wva0VxN5B8OwMicaJvD8r9tlJWm9rtloEg= github.com/microcosm-cc/bluemonday v1.0.25/go.mod h1:ZIOjCQp1OrzBBPIJmfX4qDYFuhU02nx4bn030ixfHLE= +github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs= +github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= @@ -68,6 +72,8 @@ github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf h1:pvbZ0lM0XWPBqUKqFU8cma github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf/go.mod h1:RJID2RhlZKId02nZ62WenDCkgHFerpIOmW0iT7GKmXM= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/yuin/gluamapper v0.0.0-20150323120927-d836955830e7 h1:noHsffKZsNfU38DwcXWEPldrTjIZ8FPNKx8mYMGnqjs= +github.com/yuin/gluamapper v0.0.0-20150323120927-d836955830e7/go.mod h1:bbMEM6aU1WDF1ErA5YJ0p91652pGv140gGw4Ww3RGp8= github.com/yuin/gopher-lua v1.1.0 h1:BojcDhfyDWgU2f2TOzYK/g5p2gxMrku8oupLDqlnSqE= github.com/yuin/gopher-lua v1.1.0/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= diff --git a/pkg/extension/luahost/lua.go b/pkg/extension/luahost/lua.go index 4bfbd4f..00c608f 100644 --- a/pkg/extension/luahost/lua.go +++ b/pkg/extension/luahost/lua.go @@ -47,14 +47,13 @@ func New(conf config.Lua, extHost *extension.Host) (*Host, error) { return nil, err } - return NewFromReader(extHost, bufio.NewReader(file), scriptPath) + return NewFromReader(logContext.Logger(), extHost, bufio.NewReader(file), scriptPath) } // NewFromReader constructs a new Lua Host, loading Lua source from the provided reader. // The provided path is used in logging and error messages. -func NewFromReader(extHost *extension.Host, r io.Reader, path string) (*Host, error) { - logContext := log.With().Str("module", "lua") - logger := logContext.Str("phase", "startup").Str("path", path).Logger() +func NewFromReader(logger zerolog.Logger, extHost *extension.Host, r io.Reader, path string) (*Host, error) { + startLogger := logger.With().Str("phase", "startup").Str("path", path).Logger() // Pre-parse, and compile script. chunk, err := parse.Parse(r, path) @@ -67,10 +66,10 @@ func NewFromReader(extHost *extension.Host, r io.Reader, path string) (*Host, er } // Build the pool and confirm LState is retrievable. - pool := newStatePool(proto) - h := &Host{extHost: extHost, pool: pool, logContext: logContext} + pool := newStatePool(logger, proto) + h := &Host{extHost: extHost, pool: pool, logContext: logger.With()} if ls, err := pool.getState(); err == nil { - h.wireFunctions(logger, ls) + h.wireFunctions(startLogger, ls) // State creation works, put it back. pool.putState(ls) diff --git a/pkg/extension/luahost/lua_test.go b/pkg/extension/luahost/lua_test.go index 0b7dc0d..bbef805 100644 --- a/pkg/extension/luahost/lua_test.go +++ b/pkg/extension/luahost/lua_test.go @@ -9,6 +9,8 @@ import ( "github.com/inbucket/inbucket/v3/pkg/extension" "github.com/inbucket/inbucket/v3/pkg/extension/event" "github.com/inbucket/inbucket/v3/pkg/extension/luahost" + "github.com/rs/zerolog" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" lua "github.com/yuin/gopher-lua" ) @@ -56,10 +58,26 @@ func TestEmptyScript(t *testing.T) { script := "" extHost := extension.NewHost() - _, err := luahost.NewFromReader(extHost, strings.NewReader(script), "test.lua") + _, err := luahost.NewFromReader(zerolog.Nop(), extHost, strings.NewReader(script), "test.lua") require.NoError(t, err) } +func TestLogger(t *testing.T) { + script := ` + local logger = require("logger") + logger.info("_test log entry_", {}) + ` + + extHost := extension.NewHost() + output := &strings.Builder{} + logger := zerolog.New(output) + + _, err := luahost.NewFromReader(logger, extHost, strings.NewReader(script), "test.lua") + require.NoError(t, err) + + assert.Contains(t, output.String(), "_test log entry_") +} + func TestAfterMessageDeleted(t *testing.T) { // Register lua event listener, setup notify channel. script := ` @@ -73,7 +91,7 @@ func TestAfterMessageDeleted(t *testing.T) { end ` extHost := extension.NewHost() - luaHost, err := luahost.NewFromReader(extHost, strings.NewReader(LuaInit+script), "test.lua") + luaHost, err := luahost.NewFromReader(zerolog.Nop(), extHost, strings.NewReader(LuaInit+script), "test.lua") require.NoError(t, err) notify := luaHost.CreateChannel("notify") @@ -104,7 +122,7 @@ func TestAfterMessageStored(t *testing.T) { end ` extHost := extension.NewHost() - luaHost, err := luahost.NewFromReader(extHost, strings.NewReader(LuaInit+script), "test.lua") + luaHost, err := luahost.NewFromReader(zerolog.Nop(), extHost, strings.NewReader(LuaInit+script), "test.lua") require.NoError(t, err) notify := luaHost.CreateChannel("notify") @@ -130,7 +148,7 @@ func TestBeforeMailAccepted(t *testing.T) { end ` extHost := extension.NewHost() - _, err := luahost.NewFromReader(extHost, strings.NewReader(script), "test.lua") + _, err := luahost.NewFromReader(zerolog.Nop(), extHost, strings.NewReader(script), "test.lua") require.NoError(t, err) // Send event to be accepted. diff --git a/pkg/extension/luahost/pool.go b/pkg/extension/luahost/pool.go index 9e14fa7..b89b250 100644 --- a/pkg/extension/luahost/pool.go +++ b/pkg/extension/luahost/pool.go @@ -5,7 +5,9 @@ import ( "sync" "github.com/cjoudrey/gluahttp" + "github.com/cosmotek/loguago" "github.com/inbucket/gopher-json" + "github.com/rs/zerolog" lua "github.com/yuin/gopher-lua" ) @@ -14,12 +16,14 @@ type statePool struct { funcProto *lua.FunctionProto // Compiled lua. states []*lua.LState // Pool of available LStates. channels map[string]chan lua.LValue // Global interop channels. + logger zerolog.Logger // Logger exported to Lua scripts. } -func newStatePool(funcProto *lua.FunctionProto) *statePool { +func newStatePool(logger zerolog.Logger, funcProto *lua.FunctionProto) *statePool { return &statePool{ funcProto: funcProto, channels: make(map[string]chan lua.LValue), + logger: logger, } } @@ -27,9 +31,12 @@ func newStatePool(funcProto *lua.FunctionProto) *statePool { func (lp *statePool) newState() (*lua.LState, error) { ls := lua.NewState() + logger := loguago.NewLogger(lp.logger) + // Load supplemental native modules. ls.PreloadModule("http", gluahttp.NewHttpModule(&http.Client{}).Loader) ls.PreloadModule("json", json.Loader) + ls.PreloadModule("logger", logger.Loader) // Setup channels. for name, ch := range lp.channels { diff --git a/pkg/extension/luahost/pool_test.go b/pkg/extension/luahost/pool_test.go index b033e52..73d37cb 100644 --- a/pkg/extension/luahost/pool_test.go +++ b/pkg/extension/luahost/pool_test.go @@ -4,6 +4,7 @@ import ( "strings" "testing" + "github.com/rs/zerolog" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" lua "github.com/yuin/gopher-lua" @@ -23,7 +24,7 @@ func makeEmptyPool() *statePool { panic(err) } - return newStatePool(proto) + return newStatePool(zerolog.Nop(), proto) } func TestPoolGetsDistinct(t *testing.T) {