CORD-1743: Redo ofcreate_logger API

Change-Id: I5d71f9a56e5fbd3d2242ceaa456bf9c9d9072624
diff --git a/multistructlog.py b/multistructlog.py
index b4aa19b..960b5bf 100644
--- a/multistructlog.py
+++ b/multistructlog.py
@@ -64,9 +64,13 @@
 
 
 class XOSLoggerFactory:
+    def __init__(self, handlers):
+        self.handlers = handlers
+
     def __call__(self):
         base_logger = logging.getLogger()
-        for h in base_logger.handlers:
+        base_logger.handlers = []
+        for h in self.handlers:
             formatter = FormatterFactory(h.__class__.__name__)()
             h.setFormatter(formatter)
             base_logger.addHandler(h)
@@ -78,62 +82,64 @@
 """ We expose the Structlog logging interface directly. This should allow callers to
     bind contexts incrementally and configure and use other features of structlog directly 
 
-    - config is the root xos configuration
-    - overrides override elements of that config, e.g. level=logging.INFO would cause debug messages to be dropped
-    - overrides can contain a 'processors' element, which lets you add processors to structlogs chain 
-    - overrides can also contain force_create = True which returns a previously created logger. Multiple threads 
-      will overwrite the shared logger. 
-
-    The use of structlog in Chameleon was used as a reference when writing this code.
+    The use of structlog in Chameleon was used for reference when writing this code.
 """
 
 CURRENT_LOGGER = None
-CURRENT_LOGGER_PARMS = (None, None)
+CURRENT_LOGGER_PARMS = None
 
-def create_logger(_config, **overrides):
-    first_entry_elts = []
+def create_logger(_config=None, extra_processors=[], force_create=False, level=None):
+    """
+    Args:
+        _config (dict): 		The standard config for Python's logging module
+        extra_processors(dict): 	Custom structlog processors
+        force_create(bool): 		Forces creation of the logger 
+        level(logging.loglevel): 	Overrides logging level
+
+    Returns:
+        log: structlog logger
+    """
+
+    first_entry_elts = ['Starting']
 
     """Inherit base options from config"""
-    try:
+    if _config:
         logging_config = copy.deepcopy(_config)
-    except AttributeError:
+    else:
         first_entry_elts.append('Config is empty')
-        logging_config = {}
+        logging_config = {'version': 1}
 
     """Check if a logger with this configuration has already been created, if so, return that logger 
        instead of creating a new one"""
     global CURRENT_LOGGER
     global CURRENT_LOGGER_PARMS
-
-    if CURRENT_LOGGER and CURRENT_LOGGER_PARMS == (logging_config, overrides) and not overrides.get('force_create'):
+    if CURRENT_LOGGER and CURRENT_LOGGER_PARMS == (logging_config, extra_processors, level) and not force_create:
         return CURRENT_LOGGER
     
-    first_entry_elts.append('Starting')
-    first_entry_struct = {}
-
-    if overrides:
-        first_entry_struct['overrides'] = overrides
-
-    for k, v in overrides.items():
-        logging_config[k] = v
-
-    default_handlers = [
-        logging.StreamHandler(sys.stdout),
-        logstash.LogstashHandler('localhost', 5617, version=1)
-    ]
+    if level:
+        try:
+            for k,v in logging_config['loggers'].iteritems():
+                v['level'] = level
+        except KeyError:
+            first_entry_elts.append('Level override failed')
 
     logging.config.dictConfig(logging_config)
 
-    # Processors
-    processors = overrides.get('processors', [])
-
+    processors = copy.copy(extra_processors)
     processors.extend([
         structlog.processors.StackInfoRenderer(),
         structlog.processors.format_exc_info,
         structlog.stdlib.ProcessorFormatter.wrap_for_formatter
     ])
+    
+    default_handlers = [
+        logging.StreamHandler(sys.stdout),
+        logstash.LogstashHandler('localhost', 5617, version=1)
+    ]
 
-    factory = XOSLoggerFactory()
+    configured_handlers = logging.getLogger().handlers
+    handlers = configured_handlers if configured_handlers else default_handlers
+    factory = XOSLoggerFactory(handlers)
 
     structlog.configure(
         processors=processors,
@@ -142,12 +148,12 @@
 
     log = structlog.get_logger()
     first_entry = '. '.join(first_entry_elts)
-    log.info(first_entry, **first_entry_struct)
+    log.info(first_entry, level_override=level,**logging_config)
 
     CURRENT_LOGGER = log
-    CURRENT_LOGGER_PARMS = (logging_config, overrides)
+    CURRENT_LOGGER_PARMS = (logging_config, extra_processors, level)
     return log
 
 if __name__ == '__main__':
-    l = create_logger({'logging': {'version': 2, 'loggers':{'':{'level': 'INFO'}}}}, level="INFO")
+    l = create_logger({'version': 2, 'loggers':{'':{'level': 'INFO'}}}, level="INFO")
     l.info("Test OK")
diff --git a/tests/test_logger.py b/tests/test_logger.py
index f76902c..5897fb6 100644
--- a/tests/test_logger.py
+++ b/tests/test_logger.py
@@ -40,17 +40,17 @@
                         'handlers': ['default'],
                         'level': 'INFO',
                         'propagate': True
-                }, 
-            }
+                    }, 
+                }
         }
 
-        self.config = {'logging':self.logging_config}
+        self.config = self.logging_config
 
     @mock.patch('multistructlog.logging')
     def test_reload(self, mock_logging):
-        logger = multistructlog.create_logger({'logging':{'version':1, 'foo':'bar'}})
-        logger0 = multistructlog.create_logger({'logging':{'version':1, 'foo':'bar'}})
-        logger2 = multistructlog.create_logger({'logging':{'version':1, 'foo':'notbar'}})
+        logger = multistructlog.create_logger({'version':1, 'foo':'bar'})
+        logger0 = multistructlog.create_logger({'version':1, 'foo':'bar'})
+        logger2 = multistructlog.create_logger({'version':1, 'foo':'notbar'})
         self.assertEqual(logger, logger0)
         self.assertNotEqual(logger,logger2)
 
@@ -59,7 +59,7 @@
     
     @mock.patch('multistructlog.logging')
     def test_level(self, mock_logging):
-        logger = multistructlog.create_logger({'logging':{'version':1, 'foo':'x'}})
+        logger = multistructlog.create_logger({'version':1, 'foo':'x'})
         logger.info('Test 1')
         logger.debug('Test 2')
 
@@ -68,8 +68,7 @@
 
     @mock.patch('multistructlog.logging')
     def test_override_level(self, mock_logging):
-        self.config['logging']['loggers']['']['level'] = 'DEBUG'
-        logger = multistructlog.create_logger(self.config)
+        logger = multistructlog.create_logger(self.config, level='DEBUG')
 
         logger.info('Test 1')
         logger.debug('Test 2')