diff --git a/common.py b/common.py
index 8b1e179..c93380f 100644
--- a/common.py
+++ b/common.py
@@ -11,7 +11,13 @@
 import socket
 import uuid
 
-CONFIG_FILE = os.path.expanduser("~/pc-autobackup.cfg")
+CONFIG_FILE = os.path.expanduser("~/pc_autobackup.cfg")
+LOG_DATE_FMT = '[%m/%d/%Y %I:%M %p]'
+LOG_FMT = '%(asctime)s[%(name)s] %(levelname)s:%(message)s'
+
+LOG_DEFAULTS = {'level': logging.WARN,
+                'format': LOG_FMT,
+                'datefmt': LOG_DATE_FMT}
 
 
 def LoadOrCreateConfig():
diff --git a/mediaserver.py b/mediaserver.py
index a3b8dc3..1cd823b 100644
--- a/mediaserver.py
+++ b/mediaserver.py
@@ -85,6 +85,7 @@
   backup_objects = {}
 
   def __init__(self):
+    self.logger = logging.getLogger('MediaServer.Backup')
     self.config = common.LoadOrCreateConfig()
 
   def _GenerateObjectID(self, obj_date, length=10):
@@ -96,8 +97,8 @@
 
   def CreateObject(self, obj_name, obj_date, obj_type, obj_size):
     (parent_id, obj_id) = self._GenerateObjectID(obj_date)
-    logging.debug('Creating Backup Object for %s (type:%s size:%s)', obj_name,
-                  obj_type, obj_size)
+    self.logger.debug('Creating Backup Object for %s (type:%s size:%s)',
+                      obj_name, obj_type, obj_size)
     self.backup_objects[obj_id] = {'obj_name': obj_name,
                                    'obj_date': obj_date,
                                    'obj_type': obj_type,
@@ -121,59 +122,67 @@
                            obj_details['obj_date'])
 
     if not os.path.isdir(obj_dir):
-      logging.info('Creating output dir %s', obj_dir)
+      self.logger.info('Creating output dir %s', obj_dir)
       os.makedirs(obj_dir)
 
     obj_file = os.path.join(obj_dir, obj_details['obj_name'])
 
-    logging.info('Saving %s', obj_file)
+    self.logger.info('Saving %s to %s', obj_details['obj_name'], obj_dir)
     with open(obj_file, 'wb') as f:
       f.write(data)
+    self.logger.info('%s saved successfully', obj_details['obj_name'])
 
     del(self.backup_objects[obj_id])
 
 
 class MediaServer(Resource):
 
+  clients = {}
   isLeaf = True
 
   def __init__(self):
+    self.logger = logging.getLogger('MediaServer')
     self.config = common.LoadOrCreateConfig()
 
   def render_GET(self, request):
-    logging.debug('Request Headers: %s', request.getAllHeaders())
+    self.logger.debug('Request Headers: %s', request.getAllHeaders())
     if request.path == '/DMS/SamsungDmsDesc.xml':
-      logging.info('New connection from %s', request.getHeader('user-agent'))
+      self.logger.info('New connection from %s (%s)',
+                       request.getClientIP(),
+                       request.getHeader('user-agent'))
+      self.clients[request.getClientIP()] = request.getHeader('user-agent')
       response = self.GetDMSDescriptionResponse()
     else:
-      logging.error('Unhandled GET request: %s', request.path)
+      self.logger.error('Unhandled GET request: %s', request.path)
       return NoResource()
 
-    logging.debug('Response: %s', response)
+    self.logger.debug('Response: %s', response)
     return response
 
   def render_POST(self, request):
-    logging.debug('Request args: %s', request.args)
-    logging.debug('Request headers: %s', request.getAllHeaders())
+    self.logger.debug('Request args: %s', request.args)
+    self.logger.debug('Request headers: %s', request.getAllHeaders())
 
     if request.path == '/cd/content':
       response = self.ReceiveUpload(request)
     elif request.path == '/upnp/control/ContentDirectory1':
       response = self.GetContentDirectoryResponse(request)
     else:
-      logging.error('Unhandled POST request: %s', request.path)
+      self.logger.error('Unhandled POST request: %s', request.path)
       return NoResource()
 
-    logging.debug('Response: %s', response)
+    self.logger.debug('Response: %s', response)
     return response
 
   def GetContentDirectoryResponse(self, request):
-    logging.debug('Request content: %s', request.content.read())
+    self.logger.debug('Request content: %s', request.content.read())
     request.content.seek(0)
 
     soapaction = request.getHeader('soapaction')
 
     if soapaction == X_BACKUP_START:
+      self.logger.info('Starting backup for %s (%s)', request.getClientIP(),
+                       self.clients[request.getClientIP()])
       response = X_BACKUP_RESPONSE % 'START'
     elif soapaction == CREATE_OBJ:
       soap_xml = request.content.read()
@@ -196,9 +205,11 @@
             'obj_size': obj_size,
             'parent_id': obj_details['parent_id']}
     elif soapaction == X_BACKUP_DONE:
+      self.logger.info('Backup complete for %s (%s)', request.getClientIP(),
+                       self.clients[request.getClientIP()])
       response = X_BACKUP_RESPONSE % 'DONE'
     else:
-      logging.error('Unhandled soapaction: %s', soapaction)
+      self.logger.error('Unhandled soapaction: %s', soapaction)
       return NoResource()
 
     return response
@@ -231,7 +242,10 @@
 
 
 def main():
-  logging.basicConfig(filename='mediaserver.log', level=logging.DEBUG)
+  logging_options = common.LOG_DEFAULTS
+  logging_options['filename'] = 'mediaserver.log'
+  logging_options['level'] = logging.DEBUG
+  logging.basicConfig(**logging_options)
   StartMediaServer()
 
 
diff --git a/pc-autobackup.py b/pc-autobackup.py
deleted file mode 100644
index 4d9afb7..0000000
--- a/pc-autobackup.py
+++ /dev/null
@@ -1,63 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright 2013 Jeff Rebeiro (jeff@rebeiro.net) All rights reserved
-# Main runnable for PC Autobackup
-
-__author__ = 'jeff@rebeiro.net (Jeff Rebeiro)'
-
-import logging
-import optparse
-
-from twisted.internet import reactor
-from twisted.web.server import Site
-
-import common
-import ssdp
-import mediaserver
-
-
-def main():
-  parser = optparse.OptionParser()
-  parser.add_option('-b', '--bind', dest='bind',
-                    help='bind the server to a specific IP',
-                    metavar='IP')
-  parser.add_option('-d', '--debug', dest='debug', action='store_true',
-                    default=False, help='debug output')
-  parser.add_option('--log_file', dest='log_file',
-                    help='output log to file', metavar='FILE')
-  parser.add_option('-o', '--output_dir', dest='output_dir',
-                    help='output directory for files', metavar='DIR')
-  parser.add_option('-v', '--verbose', dest='verbose', action='store_true',
-                    default=False, help='verbose output')
-  (options, args) = parser.parse_args()
-
-  logging_options = {'level': logging.WARN}
-
-  if options.verbose:
-    logging_options['level'] = logging.INFO
-  if options.debug:
-    logging_options['level'] = logging.DEBUG
-  if options.log_file:
-    logging_options['filename'] = options.log_file
-
-  logging.basicConfig(**logging_options)
-
-  logging.info('pc-autobackup started')
-
-  config = common.LoadOrCreateConfig()
-  if options.bind:
-    config.set('AUTOBACKUP', 'default_interface', options.bind)
-  if options.output_dir:
-    config.set('AUTOBACKUP', 'backup_dir', options.output_dir)
-
-  resource = mediaserver.MediaServer()
-  factory = Site(resource)
-  reactor.listenMulticast(1900, ssdp.SSDPServer())
-  logging.info('SSDPServer started')
-  reactor.listenTCP(52235, factory)
-  logging.info('MediaServer started')
-  reactor.run()
-
-
-if __name__ == '__main__':
-  main()
diff --git a/pc_autobackup.py b/pc_autobackup.py
new file mode 100644
index 0000000..1e22d58
--- /dev/null
+++ b/pc_autobackup.py
@@ -0,0 +1,91 @@
+#!/usr/bin/python
+#
+# Copyright 2013 Jeff Rebeiro (jeff@rebeiro.net) All rights reserved
+# Main runnable for PC Autobackup
+
+__author__ = 'jeff@rebeiro.net (Jeff Rebeiro)'
+
+import logging
+import optparse
+import platform
+import socket
+
+from twisted.internet import reactor
+from twisted.web.server import Site
+
+import common
+import ssdp
+import mediaserver
+
+
+def GetSystemInfo():
+  logger = logging.getLogger('PCAutoBackup')
+  logger.debug('Python Version: %s', platform.python_version())
+  logger.debug('System Information (platform): %s', platform.platform())
+  logger.debug('System Information (uname): %s', ' '.join(platform.uname()))
+  logger.debug('System Information (node): %s', platform.node())
+  logger.debug('System Information (hostname): %s', socket.gethostname())
+
+  config = common.LoadOrCreateConfig()
+  for section in config.sections():
+    for option in config.options(section):
+      logger.debug('Config (%s): %s = %s', section, option,
+                   config.get(section, option))
+
+
+def main():
+  parser = optparse.OptionParser()
+  parser.add_option('-b', '--bind', dest='bind',
+                    help='bind the server to a specific IP',
+                    metavar='IP')
+  parser.add_option('-d', '--debug', dest='debug', action='store_true',
+                    default=False, help='debug output')
+  parser.add_option('--log_file', dest='log_file', default='backup.log',
+                    help='output log to file', metavar='FILE')
+  parser.add_option('-o', '--output_dir', dest='output_dir',
+                    help='output directory for files', metavar='DIR')
+  parser.add_option('-v', '--verbose', dest='verbose', action='store_true',
+                    default=False, help='verbose output')
+  (options, args) = parser.parse_args()
+
+  logging_options = common.LOG_DEFAULTS
+
+  if options.verbose:
+    logging_options['level'] = logging.INFO
+  if options.debug:
+    logging_options['level'] = logging.DEBUG
+
+  logging_options['filename'] = options.log_file
+
+  logging.basicConfig(**logging_options)
+
+  console = logging.StreamHandler()
+  console.setLevel(logging_options['level'])
+  formatter = logging.Formatter('%(asctime)s %(message)s', common.LOG_DATE_FMT)
+  console.setFormatter(formatter)
+  logging.getLogger('').addHandler(console)
+
+  config = common.LoadOrCreateConfig()
+  if options.bind:
+    config.set('AUTOBACKUP', 'default_interface', options.bind)
+  if options.output_dir:
+    config.set('AUTOBACKUP', 'backup_dir', options.output_dir)
+
+  logger = logging.getLogger('PCAutoBackup')
+  logger.info('PCAutoBackup started on %s', config.get('AUTOBACKUP',
+                                                        'default_interface'))
+
+  if options.debug:
+    GetSystemInfo()
+
+  resource = mediaserver.MediaServer()
+  factory = Site(resource)
+  reactor.listenMulticast(1900, ssdp.SSDPServer())
+  logger.info('SSDPServer started')
+  reactor.listenTCP(52235, factory)
+  logger.info('MediaServer started')
+  reactor.run()
+
+
+if __name__ == '__main__':
+  main()
diff --git a/ssdp.py b/ssdp.py
index 0327979..4a0009d 100644
--- a/ssdp.py
+++ b/ssdp.py
@@ -29,6 +29,7 @@
 class SSDPServer(DatagramProtocol):
 
   def __init__(self):
+    self.logger = logging.getLogger('SSDPServer')
     self.config = common.LoadOrCreateConfig()
 
   def startProtocol(self):
@@ -40,8 +41,10 @@
     if m:
       # TODO(jrebeiro): Verify that MediaServer is the only discovery request
       #                 PCAutoBackup responds to.
-      logging.debug('Received M-SEARCH for %s from %r', m.group(3), address)
+      self.logger.debug('Received M-SEARCH for %s from %s', m.group(3),
+                        address[0])
       if m.group(3) == 'MediaServer':
+        self.logger.info('Received discovery request from %s', address[0])
         self.SendSSDPResponse(address)
 
   def SendSSDPResponse(self, address):
@@ -54,7 +57,7 @@
                                                 'default_interface'),
                                 self.config.get('AUTOBACKUP', 'uuid'))
     self.transport.write(response, address)
-    logging.debug('Response: %s', response)
+    self.logger.debug('Response: %s', response)
 
 
 def StartSSDPServer():
@@ -64,7 +67,10 @@
 
 
 def main():
-  logging.basicConfig(filename='ssdp.log', level=logging.DEBUG)
+  logging_options = common.LOG_DEFAULTS
+  logging_options['filename'] = 'ssdpserver.log'
+  logging_options['level'] = logging.DEBUG
+  logging.basicConfig(**logging_options)
   StartSSDPServer()