def start(token, client_id, loop, on_ready_handler=None):
    """Start the Discord client and log Modis into Discord."""
    import discord
    import asyncio

    # Create client
    logger.debug("Creating Discord client")
    asyncio.set_event_loop(loop)
    client = discord.Client()
    from . import _client
    _client.client = client

    from .. import datatools
    if datatools.has_data():
        data = datatools.get_data()
    else:
        # Create a blank data file
        data = {"discord": {}}

    # Save default server info to data
    if "servers" not in data["discord"]:
        data["discord"]["servers"] = {}

    # Save default key info to data
    if "keys" not in data["discord"]:
        data["discord"]["keys"] = {}

    # Save logger info to data
    if "log_level" not in data:
        data["log_level"] = "DEBUG"

    data["discord"]["token"] = token
    data["discord"]["client_id"] = client_id
    datatools.write_data(data)

    # Import event handlers
    logger.debug("Importing event handlers")
    event_handlers = _get_event_handlers()

    # Create event handler combiner
    logger.debug("Compiling event handlers")

    def create_event_handler(event_handler_type):
        async def func(*args, **kwargs):
            for module_event_handler in event_handlers[event_handler_type]:
                # Check for errors in the module event
                try:
                    module_event_handler_func = getattr(module_event_handler,
                                                        event_handler_type)
                    await module_event_handler_func(*args, **kwargs)
                except Exception as module_exception:
                    logger.error("An error occured in '{}'".format(module_event_handler))
                    logger.exception(module_exception)

            if on_ready_handler is not None and event_handler_type == "on_ready":
                await on_ready_handler()

        func.__name__ = event_handler_type
        return func

    # Register event handlers
    logger.debug("Registering event handlers into client")
    for event_handler in event_handlers.keys():
        client.event(create_event_handler(event_handler))

    # Run the client loop
    logger.info("Connecting to Discord")
    try:
        client.loop.run_until_complete(client.login(token))
    except Exception as e:
        logger.exception(e)
        logger.critical("Could not connect to Discord")
    else:
        logger.debug("Running the bot")
        try:
            client.loop.run_until_complete(client.connect())
        except KeyboardInterrupt:
            client.loop.run_until_complete(client.logout())
            pending = asyncio.Task.all_tasks(loop=client.loop)
            gathered = asyncio.gather(*pending, loop=client.loop)
            try:
                gathered.cancel()
                client.loop.run_until_complete(gathered)

                # we want to retrieve any exceptions to make sure that
                # they don't nag us about it being un-retrieved.
                gathered.exception()
            except Exception as e:
                logger.exception(e)
        except Exception as e:
            logger.exception(e)
            pending = asyncio.Task.all_tasks(loop=client.loop)
            gathered = asyncio.gather(*pending, loop=client.loop)
            gathered.exception()
        finally:
            try:
                client.loop.run_until_complete(client.logout())
            except Exception as e:
                logger.exception(e)

            logger.critical("Bot stopped\n")
            client.loop.close()