osm2pgsql-dev / osm2pgsql

OpenStreetMap data to PostgreSQL converter
https://osm2pgsql.org
GNU General Public License v2.0
1.51k stars 474 forks source link

Provide a stack trace on a lua error with flex backend #1136

Closed pnorman closed 4 years ago

pnorman commented 4 years ago

If you have an error in your lua script you get an error message like

Osm2pgsql failed due to ERROR: Failed to execute lua processing function: openstreetmap-carto.lua:533: Error in 'add_row': Trying to add relation to table 'planet_osm_line'

This doesn't provide as much information as a stack trace.

mmd-osm commented 4 years ago

add_row directly calls c++ method output_flex_t::table_add_row(), where the exception Trying to add relation to table 'planet_osm_line' is thrown.

Backtraces for the C++ callstack are available on some platforms. However, they look fairly obscure (example below based on #1137). Maybe you could describe what kind of information you were looking for?

Reading in file: r1377803.osm
Using XML parser.
./osm2pgsql(+0xc9e75)[0x5648c18dee75]
/usr/lib/x86_64-linux-gnu/liblua5.2.so.0(+0xb985)[0x7fae89366985]
/usr/lib/x86_64-linux-gnu/liblua5.2.so.0(+0x17545)[0x7fae89372545]
/usr/lib/x86_64-linux-gnu/liblua5.2.so.0(+0xbcae)[0x7fae89366cae]
/usr/lib/x86_64-linux-gnu/liblua5.2.so.0(+0xb2df)[0x7fae893662df]
/usr/lib/x86_64-linux-gnu/liblua5.2.so.0(+0xbf11)[0x7fae89366f11]
/usr/lib/x86_64-linux-gnu/liblua5.2.so.0(lua_pcallk+0x71)[0x7fae89362db1]
./osm2pgsql(_ZN13output_flex_t21call_process_functionEiRKN6osmium9OSMObjectE+0x427)[0x5648c18d94d7]
./osm2pgsql(_ZN13output_flex_t12relation_addERKN6osmium8RelationE+0x28)[0x5648c18d9e88]
./osm2pgsql(_ZNK9osmdata_t12relation_addERKN6osmium8RelationE+0x40)[0x5648c189d580]
./osm2pgsql(_ZN14parse_osmium_t8relationERKN6osmium8RelationE+0x1ad)[0x5648c18b12dd]
./osm2pgsql(_ZN14parse_osmium_t11stream_fileERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES7_+0x6d3)[0x5648c18b1b33]
./osm2pgsql(main+0x2c9)[0x5648c186cc59]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xe7)[0x7fae8864cb97]
./osm2pgsql(_start+0x2a)[0x5648c186d84a]
node cache: stored: 117(100.00%), storage efficiency: 1.39% (dense blocks: 1, sparse nodes: 116), hit rate: 100.00%
Osm2pgsql failed due to ERROR: Failed to execute lua processing function: /home/mmd/osm2pgsql/flex-config/compatible.lua:569: Error in 'add_row': Trying to add relation to table 'planet_osm_line'
pnorman commented 4 years ago

I don't care about the C++ backtrace, I want the lua stack traceback. I have no idea what function add_row was called from.

The lua interpreter's stack traceback is

lua: ./openstreetmap-carto.lua:555: bad argument #1 to 'ipairs' (table expected, got nil)
stack traceback:
        [C]: in function 'ipairs'
        ./openstreetmap-carto.lua:555: in function 'add_route'
        ./openstreetmap-carto.lua:610: in function 'process_relation'
        test.lua:316: in main chunk
        [C]: in ?
mmd-osm commented 4 years ago

The Lua Interpreter wraps the lua_pcall into another function and adds an error message handler: https://github.com/lua/lua/blob/master/lua.c#L109-L142

Quick and dirty test

diff (click to expand) ```C diff --git a/src/output-flex.cpp b/src/output-flex.cpp index 3ac29fe..44bc5fe 100644 --- a/src/output-flex.cpp +++ b/src/output-flex.cpp @@ -983,6 +983,32 @@ void output_flex_t::add_row(table_connection_t *table_connection, } } +static int msghandler (lua_State *L) { + const char *msg = lua_tostring(L, 1); + if (msg == NULL) { /* is error object not a string? */ + if (luaL_callmeta(L, 1, "__tostring") && /* does it have a metamethod */ + lua_type(L, -1) == LUA_TSTRING) /* that produces a string? */ + return 1; /* that is the message */ + else + msg = lua_pushfstring(L, "(error object is a %s value)", + luaL_typename(L, 1)); + } + luaL_traceback(L, L, msg, 1); /* append a standard traceback */ + return 1; /* return the traceback */ +} + +static int docall (lua_State *L, int narg, int nres) { + int status; + int base = lua_gettop(L) - narg; /* function index */ + lua_pushcfunction(L, msghandler); /* push message handler */ + lua_insert(L, base); /* put it under function and args */ + status = lua_pcall(L, narg, nres, base); + lua_remove(L, base); /* remove message handler from the stack */ + return status; +} + + + void output_flex_t::call_process_function(int index, osmium::OSMObject const &object) { @@ -996,7 +1022,7 @@ void output_flex_t::call_process_function(int index, get_options()->extra_attributes); // the single argument luaX_set_context(lua_state(), this); - if (lua_pcall(lua_state(), 1, 0, 0)) { + if (docall(lua_state(), 1, 0)) { throw std::runtime_error{"Failed to execute lua processing function:" " {}"_format(lua_tostring(lua_state(), -1))}; } ```

Returns:

Setting up table: planet_osm_rels
Using projection SRS 3857 (Spherical Mercator)

Reading in file: r1377803.osm
Using XML parser.
node cache: stored: 117(100.00%), storage efficiency: 1.39% (dense blocks: 1, sparse nodes: 116), hit rate: 100.00%
Osm2pgsql failed due to ERROR: Failed to execute lua processing function: /home/user/osm2pgsql/flex-config/compatible.lua:569: Error in 'add_row': Trying to add relation to table 'planet_osm_line'

stack traceback:
    [C]: in function 'add_row'
    /home/user/osm2pgsql/flex-config/compatible.lua:569: in function </home/user/osm2pgsql/flex-config/compatible.lua:534>

Also works with LuaJIT.