
import collections, copy
from StringIO import StringIO
from datetime import datetime
import os

import sys
import traceback

def getStackTrace ( ):
    exc_info = sys.exc_info()
    str_stack_trace = '\n'.join(traceback.format_exception(*(exc_info)))
    return str_stack_trace


queue = collections.deque(maxlen=50)

def getAllLogs():
    buf = StringIO()
    for (timestamp, exception, stack) in copy.copy(queue):
        buf.write("\n%s %s\n"%(timestamp, exception))
        buf.write(stack)
        buf.write("\n")
    return buf.getvalue()


###

import logging
import logging.handlers
from logging.handlers import RotatingFileHandler
import inspect

infraLogger = None

def initLogger(logPath, isDebug = False, logMaxBytes = 4 * 1024 * 1024, logBackupCount = 3):
    logger = logging.getLogger("InfraLogger")
    logger.propagate = False
    if isDebug:
        logger.setLevel(logging.DEBUG)
    else:
        logger.setLevel(logging.INFO)

    formatter = logging.Formatter('[%(asctime)s] [%(levelname)s] [%(wfilename)s:%(wfuncName)s:%(wlineno)d] %(message)s ')

    handler = RotatingFileHandler(
            filename=logPath,
            maxBytes=logMaxBytes,
            backupCount=logBackupCount
            )

    handler.setFormatter(formatter)

    if logger.handlers:
        logger.handlers = []

    logger.addHandler(handler)

    global infraLogger
    infraLogger = logger



def debug(*args):
    frame = inspect.stack()[1]
    filename = frame[1].split('/')[-1]
    lineno = frame[2]
    funcname = frame[3]

    message = " ".join([str(x) for x in args])
    extra = {
            'wfilename': filename,
            'wlineno': lineno, 
            'wfuncName': funcname
    }

    if infraLogger != None:
        infraLogger.debug(message, extra = extra)

def info(*args):
    frame = inspect.stack()[1]
    filename = frame[1].split('/')[-1]
    lineno = frame[2]
    funcname = frame[3]

    message = " ".join([str(x) for x in args])
    extra = {
            'wfilename': filename,
            'wlineno': lineno, 
            'wfuncName': funcname
    }

    if infraLogger != None:
        infraLogger.info(message, extra = extra)

def error(*args):
    frame = inspect.stack()[1]
    filename = frame[1].split('/')[-1]
    lineno = frame[2]
    funcname = frame[3]

    message = " ".join([str(x) for x in args])
    extra = {
            'wfilename': filename,
            'wlineno': lineno, 
            'wfuncName': funcname
    }

    if infraLogger != None:
        infraLogger.error(message, extra = extra)

def debugStack(e):
    debug(e)
    debug(getStackTrace())

def errorStack(e):
    frame = inspect.stack()[1]
    filename = frame[1].split('/')[-1]
    lineno = frame[2]
    funcname = frame[3]

    extra = {
            'wfilename': filename,
            'wlineno': lineno, 
            'wfuncName': funcname
    }

 
    if infraLogger != None:
        infraLogger.error(getStackTrace(), extra = extra)


#TODO thread sync issue
#global queue -> thread local queue change
def logStack(e):
    frame = inspect.stack()[1]
    filename = frame[1].split('/')[-1]
    lineno = frame[2]
    funcname = frame[3]

    extra = {
            'wfilename': filename,
            'wlineno': lineno, 
            'wfuncName': funcname
    }

 
    if infraLogger != None:
        infraLogger.info(getStackTrace(), extra = extra)
    queue.append( (str(e), getStackTrace()) )


