| Traces execution.
    | Any method / definition decorated will have it's execution traced through debug messages.
    | Both object entry and exit are logged.

    Entering in an object::

        INFO    : ---> foundations.environment.get_user_application_data_directory() <<<---

    Exiting from an object::

        INFO   : <--- foundations.environment.get_system_application_data_directory() ^ '...' --->

    :param object: Object to decorate.
    :type object: object
    :return: Object.
    :rtype: object

def tracer(object):
    """
    | Traces execution.
    | Any method / definition decorated will have it's execution traced through debug messages.
    | Both object entry and exit are logged.

    Entering in an object::

        INFO    : ---> foundations.environment.get_user_application_data_directory() <<<---

    Exiting from an object::

        INFO   : <--- foundations.environment.get_system_application_data_directory() ^ '...' --->

    :param object: Object to decorate.
    :type object: object
    :return: Object.
    :rtype: object
    """

    @functools.wraps(object)
    @functools.partial(foundations.trace.validate_tracer, object)
    def tracer_wrapper(*args, **kwargs):
        """
        Traces execution.

        :param \*args: Arguments.
        :type \*args: \*
        :param \*\*kwargs: Keywords arguments.
        :type \*\*kwargs: \*\*
        :return: Object.
        :rtype: object
        """

        global INDENT_LEVEL

        trace_name = foundations.trace.get_trace_name(object)

        code = object.func_code
        args_count = code.co_argcount
        args_names = code.co_varnames[:args_count]
        function_defaults = object.func_defaults or list()
        args_defaults = dict(zip(args_names[-len(function_defaults):], function_defaults))

        positional_args = map(foundations.trace.format_argument, zip(args_names, args))
        defaulted_args = [foundations.trace.format_argument((name, args_defaults[name]))
                          for name in args_names[len(args):] if name not in kwargs]
        nameless_args = map(repr, args[args_count:])
        keyword_args = map(foundations.trace.format_argument, kwargs.items())
        TRACER_LOGGING_FUNCTION(indent_message("---> {0}({1}) <---".format(trace_name,
                                                                           ", ".join(itertools.chain(positional_args,
                                                                                                     defaulted_args,
                                                                                                     nameless_args,
                                                                                                     keyword_args)))))

        INDENT_LEVEL += 1
        value = object(*args, **kwargs)
        INDENT_LEVEL -= 1

        TRACER_LOGGING_FUNCTION(indent_message("<--- {0} ^ {1} --->".format(trace_name, repr(value))))

        return value

    return tracer_wrapper