Transferring Custom UI logs to Forge Logs

Hello everybody,

are there any best practices to transfer the Custom-UI console.log statements to the Forge logs?
I suppose it doesn’t make sense to include external logging services in general.

I tried a simple approach: a resolver logger function which we called via invoke.
But I realized that the Forge-Log-output isn’t always in the order I make the calls.
I made 2 versions with the same result:

  • Synchronous call. Like
function forgeLog(logItem) {
  invoke("logger", logItem);
}
  • Asynchronous call. Like
async function forgeLogAsync(logItem) {
  let rc = await invoke("logger", logItem);
}

On the resolver side I simply definined:

resolver.define("logger", (req) => {
  console.log(">>>LOGGER");
  console.log(req.payload);
  return ["Data logged....", req.payload];
});

Please help me if I’m totally wrong.

Hi @FranzBinder
Looks like you didn’t post the most intriguing part of your message.
You have one sync and one async example and both of them invoke your “logger” function. So what’s different between them from the logs order perspective?

Also, just to clarify, invoke always returns a Promise so even if your function is synchronous (“forgeLog” in your example) it’s in fact async: you just ignore the promise resolving .

Thanks @Dmitrii for your fast reply!
As I mentioned there is no difference. Your explanation makes it even clearer.

When I try to use the Forge Log for debugging purposes in production it can be confusing seeing the logs not in the order they were executed. :unamused:

Is this approach nevertheless correct or are there better ways to do this?
What’s Atlassian suggestion for this purpose?

it can be confusing seeing the logs not in the order they were executed. :unamused:

I’m still not quite following. Could you provide an example where the logs appear in the wrong order?

Custom UI:

  forgeLog("01");
  forgeLog("02");
  forgeLog("03");
  forgeLog({ name: "John", place: "here" });
  let myArray = [99, 44, 66, { aaa: "aaaaaa", bbb: "bbbeee" }];
  forgeLog(myArray);

Forge Logs

invocation: a5b1b6a69fd7efc7 resolverBE.handler
INFO    21:45:12.156  a5b1b6a69fd7efc7  >>>LOGGER
INFO    21:45:12.157  a5b1b6a69fd7efc7  01

invocation: 5bbe4b6d463460a7 resolverBE.handler
INFO    21:45:12.279  5bbe4b6d463460a7  >>>LOGGER
INFO    21:45:12.279  5bbe4b6d463460a7  03

invocation: 77f038635fca2ada resolverBE.handler

invocation: 3d6f89e3b0be4e94 resolverBE.handler
INFO    21:45:12.514  77f038635fca2ada  >>>LOGGER
INFO    21:45:12.514  77f038635fca2ada  02
INFO    21:45:12.529  3d6f89e3b0be4e94  >>>LOGGER
INFO    21:45:12.530  3d6f89e3b0be4e94  [ 99, 44, 66, { aaa: 'aaaaaa', bbb: 'bbbeee' } ]

invocation: 69359111ae834353 resolverBE.handler
INFO    21:45:12.646  69359111ae834353  >>>LOGGER
INFO    21:45:12.647  69359111ae834353  { name: 'John', place: 'here' }

The Forge Log output doesn’t appear in the same order. (The invovation time doesn’t fit to the order in Custom UI ).
The Forge Log output was captured from the forge tunnel.

Got it. Thanks for the example.
Yep, this all happens due to the asynchronicity of the bridge. Whenever you invoke something in your frontend, Custom UI gives you back a promise. If you want to have the same order, you need to wait for the promise to be resolved:

await forgeLog(“01”);
await forgeLog(“02”);
await forgeLog(“03”);
await forgeLog({ name: “John”, place: “here” });

let myArray = [99, 44, 66, { aaa: “aaaaaa”, bbb: “bbbeee” }];
await forgeLog(myArray);``

Thanks @Dmitrii , I already supposted that behaviour.
But waiting for all promises is no solution - I expect in a real application it would be time consuming.

so…

  • What’s the Atlassian suggestion for this purpose?
  • Are there any Best Practices from the community?

Hi @FranzBinder,

I am intrigued by the question and I would like to understand a little bit better what is important to your investigation in regards of logging: performance or readability. Have you attempted investigating logs with the -- verbose --grouped options? This approach would help in terms of organized reading, although it will not resolve the ordering issue.

Adding both the verbose and grouped options shows log statements grouped by Invocation ID with the attached metadata

Hi @heinzen ,
for me it’s right now only to be prepared for problem diagnosis and not for performance measurement.

I suppose that the Custom UI path is used by others as well and so I’m wondering that these kind of questions are not asked so far.
So my last 2 questions are still open for me.