Function caller info
Problem
I'm using a custom implementation of a Logger which outputs all logs in the following format:
[current time] [function that invoked log()]: [log message]
My log function looks like this:
function formatCaller(caller: Function): string {
if (!caller) return '{?}:';
else return `{${caller.name}}: `;
}
export function log(...messages: unknown[]): void {
let caller = '{?}:';
try {
caller = formatCaller(log.caller);
} catch {}
const joinedMessage = messages.map((m) => (typeof m === 'string' ? m : JSON.stringify(m))).join(' ');
console.log(caller + joinedMessage);
}
On JSC (iOS) the caller name is correctly retrieved, but on Hermes log.caller evaluates to null because caller information is not available in Hermes bytecode. This makes it extremely difficult to trace breadcrumbs back when trying to find the source of an error that pops up in your Sentry/Crashlytics/...
Solution
Add [currentFunction].caller information. Since the function's code is stored as bytecode, I'm assuming only name and arguments are available properties, toString() should just return the name instead of the function's code.
Hi, I understand the problem, but unfortunately Function.caller is non-standard and we don't have immediate plans to implement it. We would review a PR from the community.
One possible workaround in Hermes is to throw an Error exception and parse the stack string (a hypothetical implementation of Function.caller would do something similar internally - it would crowl the JavaScript stack).
@tmikov I see, didn't know that it was non-standard. Throwing an error on every log() call seems like a very bad idea, but it works if I'm already logging errors. Too bad we can't use something like C#'s [CallerMemberName] attribute 😕 I believe internally this just stores the name of each function, and when that attribute is used, it passes the current function name as a normal argument to the next function.
There are some possibilities. First, as I mentioned, it can be implemented in Hermes, it is just it is not a very high priority for us. Another option is to add a Hermes-specific call, something like HermesInternal.getCallerName(). If the latter works for you, we can add it fairly quickly.
The latter seems like a very good option, unfortunately I'm not experienced enough in language development otherwise I'd help implement it!
@tmikov hate to be that guy, but do you have any updates on this? I realize this is a low-priority issue, but it's a bit hard for us to find errors when no caller info is available :(
Hey @tmikov has anything changed with your prioritization regarding this feature request?
@mrousavy I am no longer actively working on Hermes itself, but I will pass it on to the team.