diff --git a/EDMarketConnector.py b/EDMarketConnector.py
index 83107598..011f4789 100755
--- a/EDMarketConnector.py
+++ b/EDMarketConnector.py
@@ -369,12 +369,28 @@ class AppWindow:
         except:
             pass
 
-    def system_change(self, system, timestamp):
+    def system_change(self, timestamp, system):
         if self.system['text'] != system:
-            # TODO: EDSM lookup and csv and/or EDSM log
-            self.system['text'] = system
-            self.station['text'] = EDDB.system(system) and self.STATION_UNDOCKED or ''
-            self.status['text'] = strftime(_('Last updated at {HH}:{MM}:{SS}').format(HH='%H', MM='%M', SS='%S').encode('utf-8'), localtime(timestamp)).decode('utf-8')
+            try:
+                self.system['text'] = system
+                self.system['image'] = ''
+                self.station['text'] = EDDB.system(system) and self.STATION_UNDOCKED or ''
+                if config.getint('output') & config.OUT_LOG_FILE:
+                    flightlog.writelog(timestamp, system)
+                if config.getint('output') & config.OUT_LOG_EDSM:
+                    self.status['text'] = _('Sending data to EDSM...')
+                    self.w.update_idletasks()
+                    edsm.writelog(timestamp, system, lambda:self.edsm.lookup(system, EDDB.system(system)))	# Do EDSM lookup during EDSM export
+                else:
+                    self.edsm.start_lookup(system, EDDB.system(system))
+                self.edsmpoll()
+                self.status['text'] = strftime(_('Last updated at {HH}:{MM}:{SS}').format(HH='%H', MM='%M', SS='%S').encode('utf-8'), localtime(timestamp)).decode('utf-8')
+            except Exception as e:
+                if __debug__: print_exc()
+                self.status['text'] = unicode(e)
+                if not config.getint('hotkey_mute'):
+                    hotkeymgr.play_bad()
+
 
     def edsmpoll(self):
         result = self.edsm.result
@@ -412,6 +428,7 @@ class AppWindow:
             self.w.clipboard_append(self.station['text'] == self.STATION_UNDOCKED and self.system['text'] or '%s,%s' % (self.system['text'], self.station['text']))
 
     def onexit(self, event=None):
+        flightlog.close()
         if platform!='darwin' or self.w.winfo_rooty()>0:	# http://core.tcl.tk/tk/tktview/c84f660833546b1b84e7
             config.set('geometry', '+{1}+{2}'.format(*self.w.geometry().split('+')))
         config.close()
diff --git a/edsm.py b/edsm.py
index f10523b0..a3fab9f1 100644
--- a/edsm.py
+++ b/edsm.py
@@ -109,11 +109,16 @@ def export(data, edsmlookupfn):
 
     querytime = config.getint('querytime') or int(time.time())
 
+    writelog(querytime, data['lastSystem']['name'], edsmlookupfn)
+
+
+def writelog(timestamp, system, edsmlookupfn):
+
     try:
         # Look up the system before adding it to the log, since adding it to the log has the side-effect of creating it
         edsmlookupfn()
 
-        r = requests.get('http://www.edsm.net/api-logs-v1/set-log?commanderName=%s&apiKey=%s&systemName=%s&dateVisited=%s' % (urllib.quote(config.get('edsm_cmdrname')), urllib.quote(config.get('edsm_apikey')), urllib.quote(data['lastSystem']['name']), urllib.quote(time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(querytime)))), timeout=EDSM._TIMEOUT)
+        r = requests.get('http://www.edsm.net/api-logs-v1/set-log?commanderName=%s&apiKey=%s&systemName=%s&dateVisited=%s' % (urllib.quote(config.get('edsm_cmdrname')), urllib.quote(config.get('edsm_apikey')), urllib.quote(system), urllib.quote(time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(timestamp)))), timeout=EDSM._TIMEOUT)
         r.raise_for_status()
         reply = r.json()
         (msgnum, msg) = reply['msgnum'], reply['msg']
diff --git a/flightlog.py b/flightlog.py
index d5ff7292..5d3c0c02 100644
--- a/flightlog.py
+++ b/flightlog.py
@@ -12,6 +12,8 @@ from companion import ship_map, commodity_map
 
 
 logfile = None
+last_timestamp = last_system = last_ship = None
+last_commodities = {}
 
 def openlog():
 
@@ -41,24 +43,55 @@ def export(data):
 
     querytime = config.getint('querytime') or int(time.time())
 
-    openlog()
-
     commodities = defaultdict(int)
     for item in data['ship'].get('cargo',{}).get('items',[]):
         if item['commodity'] != 'drones':
             commodities[commodity_map.get(item['commodity'], item['commodity'])] += item['qty']
 
+    writelog(querytime,
+             data['lastSystem']['name'],
+             data['commander']['docked'] and data['lastStarport']['name'],
+             ship_map.get(data['ship']['name'].lower(), data['ship']['name']),
+             commodities)
+
+
+def writelog(timestamp, system, station=None, ship=None, commodities={}):
+
+    global last_timestamp, last_system, last_ship, last_commodities
+    if last_system and last_system != system:
+        _writelog(last_timestamp, last_system, None, last_ship, last_commodities)
+
+    if not station:
+        # If not docked, hold off writing log entry until docked or until system changes
+        last_timestamp, last_system, last_ship, last_commodities = timestamp, system, ship, commodities
+    else:
+        last_system = None
+        _writelog(timestamp, system, station, ship, commodities)
+
+
+def _writelog(timestamp, system, station=None, ship=None, commodities={}):
+
+    openlog()
+
     logfile.write('%s,%s,%s,%s,%s,%s\r\n' % (
-        time.strftime('%Y-%m-%d', time.localtime(querytime)),
-        time.strftime('%H:%M:%S', time.localtime(querytime)),
-        data['lastSystem']['name'],
-        data['commander']['docked'] and data['lastStarport']['name'] or '',
-        ship_map.get(data['ship']['name'].lower(), data['ship']['name']),
+        time.strftime('%Y-%m-%d', time.localtime(timestamp)),
+        time.strftime('%H:%M:%S', time.localtime(timestamp)),
+        system,
+        station or '',
+        ship or '',
         ','.join([('%d %s' % (commodities[k], k)) for k in sorted(commodities)])))
 
     logfile.flush()
 
 
+def close():
+    global last_timestamp, last_system
+
+    if last_system:
+        _writelog(last_timestamp, last_system, None, last_ship, last_commodities)
+        last_system = None
+
+
 # return log as list of (timestamp, system_name)
 def logs():
     entries = []
diff --git a/monitor.py b/monitor.py
index 14869100..bc5b265f 100644
--- a/monitor.py
+++ b/monitor.py
@@ -133,17 +133,21 @@ class EDLogs:
             return False
 
     def start(self):
-        self.stop()
         if not self.logdir or not self.callback:
+            self.stop()
             return False
+        if self.running():
+            return True
         self.observer = threading.Thread(target = self.worker, name = 'netLog worker')
         self.observer.daemon = True
         self.observer.start()
+        return True
 
     def stop(self):
-        if self.observer:
-            self.observer.stop()
-        self.observer = None
+        self.observer = None	# Orphan the worker thread
+
+    def running(self):
+        return self.observer and self.observer.is_alive()
 
     def worker(self):
         regexp = re.compile('{(.+)} System:[^\(]*\(([^\)]+)')
@@ -158,6 +162,10 @@ class EDLogs:
             loghandle = None
 
         while True:
+            # Check whether we're still supposed to be running
+            if threading.current_thread() != self.observer:
+                return	# Terminate
+
             # Check whether new log file started, e.g. client restarted. Assumes logs sort alphabetically.
             logfiles = sorted([x for x in listdir(self.logdir) if x.startswith('netLog.')])
             newlogfile = logfiles and logfiles[-1] or None
@@ -183,9 +191,9 @@ class EDLogs:
                     now = localtime()
                     if now.tm_hour == 0 and visited_struct.tm_hour == 23:
                         # Crossed midnight between timestamp and poll
-                        now = localtime(time()-60)
-                    datetime_struct = datetime(now.tm_year, now.tm_mon, now.tm_mday, visited_struct.tm_hour, visited_struct.tm_min, visited_struct.tm_sec).timetuple()	# still local time
-                    self.callback(system, mktime(datetime_struct))
+                        now = localtime(time()-12*60%60)	# yesterday
+                    time_struct = datetime(now.tm_year, now.tm_mon, now.tm_mday, visited_struct.tm_hour, visited_struct.tm_min, visited_struct.tm_sec).timetuple()	# still local time
+                    self.callback(mktime(time_struct), system)
 
             sleep(10)	# New system gets posted to log file before hyperspace ends, so don't need to poll too often
 
diff --git a/prefs.py b/prefs.py
index 7511b1fe..78621b3e 100644
--- a/prefs.py
+++ b/prefs.py
@@ -199,9 +199,8 @@ class PreferencesDialog(tk.Toplevel):
         # Selectively disable buttons depending on output settings
         self.outvarchanged()
 
-        # disable hotkey and log monitoring for the duration
+        # disable hotkey for the duration
         hotkeymgr.unregister()
-        monitor.stop()
 
         # wait for window to appear on screen before calling grab_set
         self.wait_visibility()
@@ -224,7 +223,7 @@ class PreferencesDialog(tk.Toplevel):
                     self.out_log_auto_text['text'] = "Can't enable automatic logging!"	# Shouldn't happen - don't translate
                     self.out_log_auto_text.grid(row=10, padx=(25,5), sticky=tk.EW)
                 elif monitor.restart_required():
-                    self.out_log_auto_text['text'] = _('Re-start Elite: Dangerous for automatic logging')	# Output settings prompt
+                    self.out_log_auto_text['text'] = _('Re-start Elite: Dangerous to use this feature')	# Output settings prompt
                     self.out_log_auto_text.grid(row=10, padx=(25,5), sticky=tk.EW)
 
 
@@ -337,6 +336,8 @@ class PreferencesDialog(tk.Toplevel):
         if (config.getint('output') & config.OUT_LOG_AUTO) and (config.getint('output') & (config.OUT_LOG_AUTO|config.OUT_LOG_EDSM)):
             monitor.enable_logging()
             monitor.start()
+        else:
+            monitor.stop()
         self.destroy()
 
     if platform == 'darwin':