### Summary

If a module calls `fail_json()` and provides `exception=None`, this will crash every callback that uses `_handle_exception` from `CallbackBase`: if verbosity is < 3, it will try to call `split` on `None`, and otherwise it will try to concatenate a string with `None` (which results in `TypeError`).

### Issue Type

Bug Report

### Component Name

lib/ansible/plugins/callback/__init__.py

### Ansible Version

```console
devel
```


### Configuration

```console
*
```


### OS / Environment

*

### Steps to Reproduce

*

### Expected Results

*

### Actual Results

```console
*
```


### Code of Conduct

- [X] I agree to follow the Ansible Code of Conduct
host = result._host.get_name()
        self.playbook_on_import_for_host(host, imported_file)
    
    def v2_playbook_on_not_import_for_host(self, result, missing_file):
        host = result._host.get_name()
        self.playbook_on_not_import_for_host(host, missing_file)
    def v2_playbook_on_play_start(self, play):
        self.playbook_on_play_start(play.name)
    def v2_playbook_on_stats(self, stats):
        self.playbook_on_stats(stats)
    def v2_on_file_diff(self, result):
        if 'diff' in result._result:
            host = result._host.get_name()
            self.on_file_diff(host, result._result['diff'])
    def v2_playbook_on_include(self, included_file):
        pass  
    def v2_runner_item_on_ok(self, result):
        pass
    def v2_runner_item_on_failed(self, result):
        pass
    def v2_runner_item_on_skipped(self, result):
        pass
    def v2_runner_retry(self, result):
        pass
    def v2_runner_on_start(self, host, task):
        """Event used when host begins execution of a task
        .. versionadded:: 2.8
        """
        pass