Repository: wandb/wandb

Issue:
[CLI]: Exception traceback is (still) not visible in wandb log
### Describe the bug

When I run wandb using the context manager form and an exception occurs, then nothing related to the exception (e.g. which exception was raised, the traceback, etc) is visible in the run logs. A similar issue has been voiced by numerous people before (#2387), but the issue was closed and has remained closed despite opposition. Yet the issue clearly persists.

Source file:
```python
#!/usr/bin/env python3
import wandb
with wandb.init(project='Exception'):
	print("Do some work")
	raise ValueError("Something went wrong")
	print("Do some more work")
```
Produced log:
```
Do some work
```
Note however that this works:
```python
#!/usr/bin/env python3
import wandb
wandb.init(project='Exception')
print("Do some work")
raise ValueError("Something went wrong")
print("Do some more work")
```
and produces in the logs:
```
Do some work
Traceback (most recent call last):
  File "PATH/wandb_exc.py", line 5, in <module>
    raise ValueError("Something went wrong")
ValueError: Something went wrong
```
Basically, the problem occurs whenever an exception is raised, and implicitly or explicitly `wandb.finish()` is called within the exception handling code path. This is the case when using a `wandb.Run` as a context manager, but there are definitely other legitimate use cases of this.

I presume the most logical fix for this would be for `wandb.finish()` to append the exception to the log (or just print it) if there is an exception that is currently being handled (and thereby hasn't been printed yet when wandb does its final sync).

My current workaround, which hopefully in future won't be necessary anymore, is:
```python
#!/usr/bin/env python3
import traceback
import contextlib
import wandb

class ExceptionPrinter(contextlib.AbstractContextManager):

	def __enter__(self):
		return self

	def __exit__(self, exc_type, exc_val, exc_tb):
		if exc_type is not None:
			traceback.print_exception(exc_type, exc_val, exc_tb)
		return False

with wandb.init(project='Exception'), ExceptionPrinter():
	print("Do some work")
	raise ValueError("Something went wrong")
	print("Do some more work")
```
This code sneakily prints the exception just in time for wandb to still catch it in the logs (once), but obviously ends up with two copies of the traceback in the terminal where the code was executed (once before the wandb sync, and once afterwards when python exits).

### Additional Files

_No response_

### Environment

WandB version: 0.13.2

OS: Ubuntu 20.04

Python version: 3.9.12

Versions of relevant libraries: None


### Additional Context

_No response_


Discussion:
Hi @pallgeuer, thank you for raising this again and for the reproduction. I just ran this and am seeing the same behavior as you. I'll raise this with the team to make sure we get this addressed and follow up with you once the engineering team has had a chance to review this.

Thank you,
Nate
For people struggling with this issue. While this gets fixed, if you need to debug an error raised by wand.agent and you need more context. Simply replicate the same hyperparameters that led to the error in a normal run without a sweep/agent.
Thanks @marc-gav for the workaround. Also, the engineering team has this on their radar and is aware of the cause. This is waiting to be assigned in an upcoming sprint. I'll update again when we  have a fix on this. 

Resolving patch:
diff --git a/wandb/sdk/wandb_run.py b/wandb/sdk/wandb_run.py
--- a/wandb/sdk/wandb_run.py
+++ b/wandb/sdk/wandb_run.py
@@ -2156,7 +2156,7 @@ def _atexit_cleanup(self, exit_code: Optional[int] = None) -> None:
             self._backend.cleanup()
             logger.error("Problem finishing run", exc_info=e)
             wandb.termerror("Problem finishing run")
-            traceback.print_exception(*sys.exc_info())
+            traceback.print_exc()
         else:
             self._on_final()
         finally:
@@ -3078,9 +3078,12 @@ def __exit__(
         exc_val: BaseException,
         exc_tb: TracebackType,
     ) -> bool:
-        exit_code = 0 if exc_type is None else 1
-        self._finish(exit_code)
-        return exc_type is None
+        exception_raised = exc_type is not None
+        if exception_raised:
+            traceback.print_exception(exc_type, exc_val, exc_tb)
+        exit_code = 1 if exception_raised else 0
+        self._finish(exit_code=exit_code)
+        return not exception_raised
 
     @_run_decorator._noop_on_finish()
     @_run_decorator._attach


Test patch: