import inspect


def get_caller_name(depth=2, mod=True, cls=False, mth=False):
    """
    Gets the name of the calling module/class/method with format [module][.class][.method]

    :param int depth: the depth of the caller if passing through multiple methods (optional)
    :param bool mod: include module in name (optional)
    :param bool cls: include class in name (optional)
    :param bool mth: include method in name (optional)
    :return: caller name as [module][.class][.method]
    :rtype: str
    """
    stack = inspect.stack()
    start = 0 + depth
    if len(stack) < start + 1:
        return ''
    parent_frame = stack[start][0]
    name = []
    module = inspect.getmodule(parent_frame)
    if module and mod:
        name.append(module.__name__)
    if cls and 'self' in parent_frame.f_locals:
        name.append(parent_frame.f_locals['self'].__class__.__name__)
    if mth:
        codename = parent_frame.f_code.co_name
        if codename != '<module>':
            name.append(codename)
    del parent_frame, stack
    return '.'.join(name)