Is it possible to change the output of Lua error messages? - lua

I managed to change the output of error messages by modifying the dbg_printf method. However, that method doesn't handle the following error messages:
lua: ?:0: attempt to call global 'log' (a nil value)
Which method(s) handle these types of errors?

The error message is from the file ldebug.c in the function luaG_typeerror. But i guess you are using an older Lua Version because my message is a bit different:
attempt to call a nil value (global 'log')
You sould try to prevent the error if you can:
if type(log) == "function" then
log()
end
or as #lhf said use pcall:
if pcall(log) then
-- no errors while running 'log'
...
else
-- 'log' raised an error: take appropriate actions
...
end

It should be simpler than digging into the C api.
like #lhf says:
if pcal(risky) then
print("this works")
else
print("phooey!")
end
alternatively you can stop the program and get your error message like this:
if pcal(risky) then
print("this works")
else
error("your error message here")
end

Related

Vim global variable check throws error in lua (neovim plugin development)

I'm trying write a neovim plugin using lua, when checking if a variable exists, lua throws an error like: Undefined variable: g:my_var
Method 1:
local function open_bmax_term()
if (vim.api.nvim_eval("g:my_var")) then
print('has the last buff')
else
print('has no the last buff')
end
end
Method 2:
local function open_bmax_term()
if (vim.api.nvim_get_var("my_var")) then
print('has the last buff')
else
print('has no the last buff')
end
end
this is a similar function written in viml which does works: (this does not throw any error)
fun! OpenBmaxTerm()
if exists("g:my_var")
echo "has the last buff"
else
echo "has no the last buff"
endif
endfun
any idea how to get this working in lua? I tried wrapping the condition inside a pcall which had an effect like making it always truthy.
vim.api.nvim_eval("g:my_var") just evaluates a vimscript expression, so accessing a non-existent variable would error just like in vimscript. Have you tried vim.api.nvim_eval('exists("g:my_var")') instead?
Edit: Using vim.g as #andrewk suggested is probably the better solution as using the dedicated API is more elegant than evaluating strings of vim script.
You can use the global g: dictionary via vim.g to reference your variable:
if vim.g.my_var == nil then
print("g:my_var does not exist")
else
print("g:my_var was set to "..vim.g.my_var)
end
You can reference :h lua-vim-variables to see other global Vim dictionaries that are available as well!

How to return a function value from pcall() in lua

My code (psuedo)
function foo(cmd)
return load(cmd) --Note that this could cause an error, should 'cmd' be an invalid command
end
function moo()
return "moo"
end
function yoo(something)
something.do()
end
cmd = io.read() --Note that a syntax error will call an error in load. Therefore, I use pcall()
local result, error = pcall(cmd)
print(result)
This code looks okay, and works, but my problem is if I type in moo() then result will only show whether or not the command was executed without an error (If the command calls an error, error will have its value).
On another note, if I want to call yoo(), I won't get a return value from it, so I want pcall()'s true / false (or any alternate means other than pcall())
Is there an alternate way to call moo(), get a return value, and also be able to catch any errors?
NOTE: I couldn't find any try catch equivalent other then pcall / xpcall.
A bit outdated but still without proper answer...
What you are looking for is a combination of both load() and pcall()
Use load()to compile the entered string cmd into something that can be executed (function).
Use pcall() to execute the function returned by load()
Both functions can return error messages. Get syntax error description from load() and runtime error description from pcall()
function moo()
return "moo"
end
function yoo(something)
something.do_something()
end
cmd = io.read()
-- we got some command in the form of a string
-- to be able to execute it, we have to compile (load) it first
local cmd_fn, err = load("return "..cmd);
if not cmd_fn then
-- there was a syntax error
print("Syntax error: "..err);
else
-- we have now compiled cmd in the form of function cmd_fn(), so we can try to execute it
local ok, result_or_error = pcall(cmd_fn)
if ok then
-- the code was executed successfully, print the returned value
print("Result: "..tostring(result_or_error));
else
-- runtime error, print error description
print("Run error: "..result_or_error)
end
end

How to catch errors in elua (namely NodeMCU)

Let's say I'm importing something with:
t = require("ds18b20")
t.setup(1)
temperatura = t.read()
How do I catch an error like "Failed import"?
Doing stuff like pcall(t.setup(1)) just returns a syntax error.
If the error is raised by require not finding ds18b20, then you can do
ok, t = pcall(require, "ds18b20")
if not ok then
-- handle error, t has error message
else
-- can use t
end

A Lua iterator that fails silently?

I have a very simple problem with a simple iterator.
Let's say that I design a function, files(), that iterates over all the files in a folder:
for file in files("/path/to/folder") do
print(file)
end
Now, this seems perfect, but there's a problem here: What if the the folder doesn't exist, or we don't have read permission to it?
How would we indicate such error?
One solution would be to have files() return nil, "no read permission" in this case. We'd then be able to wrap the call to files() inside assert():
for file in assert(files("/path/to/folder")) do
print(file)
end
This seemingly solves the problem. But this forces our users to always use assert(). What if the user doesn't care about errors? For this kind of users we'd want our files() to behave as if the folder is empty. But Lua --in case files() indicates error-- would try to call the returned nil and this will result in an error ("attempt to call a nil value").
So,
How can we design an iterator, files(), that would cater to both users that care about errors and users that don't?
If it's not possible, what alternative would you suggest?
First: Instead of returning nil + error message consider raising an error in the files function (using error). This way you can't forget the assert call, and you won't get the confusing "attempt to call a nil value" error.
You could pass an extra boolean parameter to files when you don't want to raise errors -- you should return an empty function (function() end) instead of calling error in this case.
A more general approach is the following:
-- an iterator that immediately stops a for loop
local function dummy_iter() end
-- catch errors and skip for loop in that case
function iterpcall( g, ... )
local ok, f, st, var = pcall( g, ... )
if ok then
return f, st, var
else
return dummy_iter
end
end
for file in iterpcall( files, "/path/to/folder" ) do
print( file )
for line in iterpcall( io.lines, file ) do -- works for other iterators as well
print( line )
end
end
The implementation of iterpcall above only handles errors raised in the iterator generator (files or io.lines), not in the iterator function (f) itself. You would have to wrap f in a closure with a pcall to do that.
There also question what you whant to do if you get error in the middle of iteration (e.g. access deny for subfolder with recurcive iteration). In this case assert does not help.
In this case I create 2 variant of iterators (inner and outer).
-- raise error
for file in files(...) do ... end
-- return error
files(...,function(file) ... end)
Or just create 2 different iterators.

Send email everytime php generates a fatal error

How would I write a PHP code that would send me an email everytime I get a
Fatal error: Allowed memory size of 33554432 bytes exhausted (tried to allocate 14373306 bytes) in on line <b>443</b><br />.
I'm running a script wherein a user has this URL and it will be process by my code, but the problem here is that sometimes it results to a Fatal error Allowed memory size exhausted. I want an email to be sent to me that tells me that there has this error at the same time what URL is causing that error.
So the logic is something like this.
if( error == "Fatal Error Allowed memory Size" ) {
mail("myemail#email.com", "Fatal Error - URL: http://google.com");
}
I hope the instruction is pretty clear. Your help would be greatly appreciated and rewarded!
Thanks! :-)
You can look at using register_shutdown_function(). It can be used to execute on E_ERROR(fatal error)
register_shutdown_function('shutdown');
function shutdown()
{
if(!is_null($e = error_get_last()))
{
mail("myemail#email.com", "Fatal Error - ". var_export($e, true));
}
}
I would however echo thoughts in the comments above that this is best handled using log monitoring.
Init following function inside your php file.
register_shutdown_function('mail_on_error'); //inside your php script
/** If any file having any kind of fatal error, sln team will be notified when cron will
become fail : following is the name of handler and its type
E_ERROR: 1 | E_WARNING: 2 | E_PARSE: 4 | E_NOTICE: 8
*/
function mail_on_error() {
global $objSettings;
$error = error_get_last();
//print_r($error);
if ($error['type'] == 1) {
// update file path into db
$objSettings->update_records($id=1,array('fatal_error' => json_encode($error)));
$exception_in_file_path = __FILE__;
fatal_error_structure($exception_in_file_path);
}// end if
}// end mail_on_error
fatal_error_structure should be defined on some global location. like function.inc.php. This will send an email to registered user.
function fatal_error_structure($exception_in_file_path){
$subject = "FATAL: Cron Daemon has failed";
sln_send_mail(nl2br("Please check $exception_in_file_path, This cron having FATAL error."),
$subject, 'email#address.com',$name_reciever='', 'text/plain');
}// end fatal_error_structure
vKj

Resources