diff --git a/app/src/main/java/info/nightscout/android/medtronic/service/MedtronicCnlAlarmReceiver.java b/app/src/main/java/info/nightscout/android/medtronic/service/MedtronicCnlAlarmReceiver.java
index 49e648c68cc37df7ca643e632c9c76b1457b32f0..75ad384182f5f83a57c0948f2fa0eb649a4eed6c 100644
--- a/app/src/main/java/info/nightscout/android/medtronic/service/MedtronicCnlAlarmReceiver.java
+++ b/app/src/main/java/info/nightscout/android/medtronic/service/MedtronicCnlAlarmReceiver.java
@@ -6,10 +6,11 @@ import android.content.Context;
 import android.content.Intent;
 import android.os.Build;
 import android.support.v4.content.WakefulBroadcastReceiver;
-import android.util.Log;
 
 import java.util.Date;
 
+import info.nightscout.android.utils.Logger;
+
 /**
  * Created by lgoedhart on 14/07/2016.
  */
@@ -19,17 +20,26 @@ public class MedtronicCnlAlarmReceiver extends WakefulBroadcastReceiver {
 
     private static PendingIntent pendingIntent = null;
     private static AlarmManager alarmManager = null;
+    private Logger logger;
+    private Context context;
 
     @Override
     public void onReceive(final Context context, Intent intent) {
         // Start the IntentService
-        Log.d(TAG, "Received broadcast message at " + new Date(System.currentTimeMillis()));
+
+        this.context = context;
+        logger = new Logger(TAG, context.getApplicationContext());
+        logger.d("Received broadcast message at " + new Date(System.currentTimeMillis()));
         Intent service = new Intent(context, MedtronicCnlIntentService.class);
         startWakefulService(context, service);
         restartAlarm();
     }
 
     public void setContext(Context context) {
+        this.context = context;
+
+        logger = new Logger(TAG, context.getApplicationContext());
+
         cancelAlarm();
 
         alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
@@ -46,6 +56,7 @@ public class MedtronicCnlAlarmReceiver extends WakefulBroadcastReceiver {
     public void setAlarm(long millis) {
         if (alarmManager == null || pendingIntent == null)
             return;
+        logger = new Logger(TAG, this.context.getApplicationContext());
 
         cancelAlarm();
 
@@ -53,7 +64,7 @@ public class MedtronicCnlAlarmReceiver extends WakefulBroadcastReceiver {
         if (millis < System.currentTimeMillis())
             millis = System.currentTimeMillis();
 
-        Log.d(TAG, "AlarmManager set to fire   at " + new Date(millis));
+        logger.d("AlarmManager set to fire at " + new Date(millis));
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
             alarmManager.setAlarmClock(new AlarmManager.AlarmClockInfo(millis, null), pendingIntent);
         } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
diff --git a/app/src/main/java/info/nightscout/android/medtronic/service/MedtronicCnlIntentService.java b/app/src/main/java/info/nightscout/android/medtronic/service/MedtronicCnlIntentService.java
index 814f29de870282cf6b54da5c6619dbbadc4f6864..b133a967248eb71fe9d965ffeccd0f69c7dca1ba 100644
--- a/app/src/main/java/info/nightscout/android/medtronic/service/MedtronicCnlIntentService.java
+++ b/app/src/main/java/info/nightscout/android/medtronic/service/MedtronicCnlIntentService.java
@@ -13,7 +13,6 @@ import android.os.Build;
 import android.preference.PreferenceManager;
 import android.support.v4.app.NotificationManagerCompat;
 import android.support.v4.content.LocalBroadcastManager;
-import android.util.Log;
 
 import java.io.IOException;
 import java.security.NoSuchAlgorithmException;
@@ -33,6 +32,7 @@ import info.nightscout.android.model.medtronicNg.ContourNextLinkInfo;
 import info.nightscout.android.model.medtronicNg.PumpInfo;
 import info.nightscout.android.model.medtronicNg.PumpStatusEvent;
 import info.nightscout.android.upload.nightscout.NightscoutUploadReceiver;
+import info.nightscout.android.utils.Logger;
 import info.nightscout.android.xdrip_plus.XDripPlusUploadReceiver;
 import io.realm.Realm;
 import io.realm.RealmResults;
@@ -44,7 +44,10 @@ public class MedtronicCnlIntentService extends IntentService {
     public final static long POLL_PERIOD_MS = 300000L;
     // Number of additional seconds to wait after the next expected CGM poll, so that we don't interfere with CGM radio comms.
     public final static long POLL_GRACE_PERIOD_MS = 30000L;
+
     private static final String TAG = MedtronicCnlIntentService.class.getSimpleName();
+    private Logger logger;
+
     private UsbHidDriver mHidDevice;
     private Context mContext;
     private NotificationManagerCompat nm;
@@ -54,13 +57,6 @@ public class MedtronicCnlIntentService extends IntentService {
         super(MedtronicCnlIntentService.class.getName());
     }
 
-    protected void sendStatus(String message) {
-        Intent localIntent =
-                new Intent(Constants.ACTION_STATUS_MESSAGE)
-                        .putExtra(Constants.EXTENDED_DATA, message);
-        LocalBroadcastManager.getInstance(this).sendBroadcast(localIntent);
-    }
-
     protected void sendMessage(String action) {
         Intent localIntent =
                 new Intent(action);
@@ -71,16 +67,18 @@ public class MedtronicCnlIntentService extends IntentService {
     public void onCreate() {
         super.onCreate();
 
-        Log.i(TAG, "onCreate called");
+        logger = new Logger(TAG, getApplicationContext());
+        logger.d("onCreate called");
         mContext = this.getBaseContext();
         mUsbManager = (UsbManager) mContext.getSystemService(Context.USB_SERVICE);
+
     }
 
     @Override
     public void onDestroy() {
         super.onDestroy();
 
-        Log.d(TAG, "onDestroy called");
+        logger.d("onDestroy called");
 
         if (nm != null) {
             nm.cancelAll();
@@ -88,18 +86,17 @@ public class MedtronicCnlIntentService extends IntentService {
         }
 
         if (mHidDevice != null) {
-            Log.i(TAG, "Closing serial device...");
+            logger.d("Closing serial device...");
             mHidDevice.close();
             mHidDevice = null;
         }
     }
 
     protected void onHandleIntent(Intent intent) {
-        Log.d(TAG, "onHandleIntent called");
+        logger.d("onHandleIntent called");
 
         if (!hasUsbHostFeature()) {
-            sendStatus("It appears that this device doesn't support USB OTG.");
-            Log.e(TAG, "Device does not support USB OTG");
+            logger.e("It appears that this device doesn't support USB OTG.");
             MedtronicCnlAlarmReceiver.completeWakefulIntent(intent);
             // TODO - throw, don't return
             return;
@@ -107,8 +104,7 @@ public class MedtronicCnlIntentService extends IntentService {
 
         UsbDevice cnlStick = UsbHidDriver.getUsbDevice(mUsbManager, USB_VID, USB_PID);
         if (cnlStick == null) {
-            sendStatus("USB connection error. Is the Bayer Contour Next Link plugged in?");
-            Log.w(TAG, "USB connection error. Is the CNL plugged in?");
+            logger.e("USB connection error. Is the Bayer Contour Next Link plugged in?");
 
             // TODO - set status if offline or Nightscout not reachable
             uploadToNightscout();
@@ -128,7 +124,7 @@ public class MedtronicCnlIntentService extends IntentService {
         try {
             mHidDevice.open();
         } catch (Exception e) {
-            Log.e(TAG, "Unable to open serial device", e);
+            logger.e("Unable to open serial device", e);
             MedtronicCnlAlarmReceiver.completeWakefulIntent(intent);
             // TODO - throw, don't return
             return;
@@ -140,8 +136,7 @@ public class MedtronicCnlIntentService extends IntentService {
         realm.beginTransaction();
 
         try {
-            sendStatus("Connecting to the Contour Next Link...");
-            Log.d(TAG, "Connecting to the Contour Next Link.");
+            logger.i("Connecting to the Contour Next Link.");
             cnlReader.requestDeviceInfo();
 
             // Is the device already configured?
@@ -198,7 +193,7 @@ public class MedtronicCnlIntentService extends IntentService {
                 cnlReader.getPumpSession().setKey(MessageUtils.hexStringToByteArray(key));
 
                 long pumpMAC = cnlReader.getPumpSession().getPumpMAC();
-                Log.i(TAG, "PumpInfo MAC: " + (pumpMAC & 0xffffff));
+                logger.d("PumpInfo MAC: " + (pumpMAC & 0xffffff));
                 MainActivity.setActivePumpMac(pumpMAC);
                 PumpInfo activePump = realm
                         .where(PumpInfo.class)
@@ -212,12 +207,10 @@ public class MedtronicCnlIntentService extends IntentService {
 
                 byte radioChannel = cnlReader.negotiateChannel(activePump.getLastRadioChannel());
                 if (radioChannel == 0) {
-                    sendStatus("Could not communicate with the 640g. Are you near the pump?");
-                    Log.i(TAG, "Could not communicate with the 640g. Are you near the pump?");
+                    logger.e("Could not communicate with the 640g. Are you near the pump?");
                 } else {
                     activePump.setLastRadioChannel(radioChannel);
-                    sendStatus(String.format(Locale.getDefault(), "Connected to Contour Next Link on channel %d.", (int) radioChannel));
-                    Log.d(TAG, String.format("Connected to Contour Next Link on channel %d.", (int) radioChannel));
+                    logger.i(String.format(Locale.getDefault(), "Connected to Contour Next Link on channel %d.", (int) radioChannel));
                     cnlReader.beginEHSMSession();
 
                     PumpStatusEvent pumpRecord = realm.createObject(PumpStatusEvent.class);
@@ -230,7 +223,7 @@ public class MedtronicCnlIntentService extends IntentService {
 
                     long pumpTime = cnlReader.getPumpTime().getTime();
                     long pumpOffset = pumpTime - System.currentTimeMillis();
-                    Log.d(TAG, "Time offset between pump and device: " + pumpOffset + " millis.");
+                    logger.d("Time offset between pump and device: " + pumpOffset + " millis.");
 
                     // TODO - send ACTION to MainActivity to show offset between pump and uploader.
                     pumpRecord.setPumpTimeOffset(pumpOffset);
@@ -264,32 +257,24 @@ public class MedtronicCnlIntentService extends IntentService {
                     }
                 }
             } catch (UnexpectedMessageException e) {
-                Log.e(TAG, "Unexpected Message", e);
-                sendStatus("Communication Error: " + e.getMessage());
+                logger.e("Communication Error:", e);
             } catch (NoSuchAlgorithmException e) {
-                Log.e(TAG, "Could not determine CNL HMAC", e);
-                sendStatus("Error connecting to Contour Next Link: Hashing error.");
+                logger.e("Error connecting to Contour Next Link: Hashing error.", e);
             } finally {
-                //TODO : 05.11.2016 has the close to be here?
                 cnlReader.closeConnection();
                 cnlReader.endPassthroughMode();
                 cnlReader.endControlMode();
             }
         } catch (IOException e) {
-            Log.e(TAG, "Error connecting to Contour Next Link.", e);
-            sendStatus("Error connecting to Contour Next Link.");
+            logger.e("Error connecting to Contour Next Link.", e);
         } catch (ChecksumException e) {
-            Log.e(TAG, "Checksum error getting message from the Contour Next Link.", e);
-            sendStatus("Checksum error getting message from the Contour Next Link.");
+            logger.e("Checksum error getting message from the Contour Next Link.", e);
         } catch (EncryptionException e) {
-            Log.e(TAG, "Error decrypting messages from Contour Next Link.", e);
-            sendStatus("Error decrypting messages from Contour Next Link.");
+            logger.e("Error decrypting messages from Contour Next Link.", e);
         } catch (TimeoutException e) {
-            Log.e(TAG, "Timeout communicating with the Contour Next Link.", e);
-            sendStatus("Timeout communicating with the Contour Next Link.");
+            logger.e("Timeout communicating with the Contour Next Link.", e);
         } catch (UnexpectedMessageException e) {
-            Log.e(TAG, "Could not close connection.", e);
-            sendStatus("Could not close connection: " + e.getMessage());
+            logger.e("Could not close connection.", e);
         } finally {
             if (!realm.isClosed()) {
                 if (realm.isInTransaction()) {
@@ -323,7 +308,7 @@ public class MedtronicCnlIntentService extends IntentService {
             final Intent receiverIntent = new Intent(this, XDripPlusUploadReceiver.class);
             final long timestamp = System.currentTimeMillis() + 500L;
             final PendingIntent pendingIntent = PendingIntent.getBroadcast(this, (int) timestamp, receiverIntent, PendingIntent.FLAG_ONE_SHOT);
-            Log.d(TAG, "Scheduling xDrip+ send");
+            logger.d("Scheduling xDrip+ send");
             wakeUpIntent(getApplicationContext(), timestamp, pendingIntent);
         }
     }
diff --git a/app/src/main/java/info/nightscout/android/upload/nightscout/NightscoutUploadIntentService.java b/app/src/main/java/info/nightscout/android/upload/nightscout/NightscoutUploadIntentService.java
index 6ac7129878dfdcf45118b3f1f4cf83538766de24..a084cc4ce692f65ac9ee89a0df0dc468f004083a 100644
--- a/app/src/main/java/info/nightscout/android/upload/nightscout/NightscoutUploadIntentService.java
+++ b/app/src/main/java/info/nightscout/android/upload/nightscout/NightscoutUploadIntentService.java
@@ -8,10 +8,7 @@ import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
 import android.preference.PreferenceManager;
 import android.support.v4.content.LocalBroadcastManager;
-import android.util.Log;
 
-import org.apache.http.HttpResponse;
-import org.apache.http.StatusLine;
 import org.apache.http.client.ResponseHandler;
 import org.apache.http.client.methods.HttpPost;
 import org.apache.http.entity.StringEntity;
@@ -35,6 +32,7 @@ import info.nightscout.android.R;
 import info.nightscout.android.medtronic.MainActivity;
 import info.nightscout.android.model.medtronicNg.PumpStatusEvent;
 import info.nightscout.android.upload.nightscout.serializer.EntriesSerializer;
+import info.nightscout.android.utils.Logger;
 import io.realm.Realm;
 import io.realm.RealmResults;
 
@@ -46,6 +44,8 @@ public class NightscoutUploadIntentService extends IntentService {
     private static final int CONNECTION_TIMEOUT = 30 * 1000;
     Context mContext;
     private Realm mRealm;
+    private Logger logger;
+
 
     public NightscoutUploadIntentService() {
         super(NightscoutUploadIntentService.class.getName());
@@ -62,13 +62,14 @@ public class NightscoutUploadIntentService extends IntentService {
     public void onCreate() {
         super.onCreate();
 
-        Log.i(TAG, "onCreate called");
+        logger = new Logger(TAG, getApplicationContext());
+        logger.d("onCreate called");
         mContext = this.getBaseContext();
     }
 
     @Override
     protected void onHandleIntent(Intent intent) {
-        Log.d(TAG, "onHandleIntent called");
+        logger.d("onHandleIntent called");
         mRealm = Realm.getDefaultInstance();
 
         RealmResults<PumpStatusEvent> records = mRealm
@@ -84,15 +85,15 @@ public class NightscoutUploadIntentService extends IntentService {
             try {
                 if (enableRESTUpload) {
                     long start = System.currentTimeMillis();
-                    Log.i(TAG, String.format("Starting upload of %s record using a REST API", records.size()));
+                    logger.i(String.format("Starting upload of %s record using a REST API", records.size()));
                     doRESTUpload(prefs, records);
-                    Log.i(TAG, String.format("Finished upload of %s record using a REST API in %s ms", records.size(), System.currentTimeMillis() - start));
+                    logger.i(String.format("Finished upload of %s record using a REST API in %s ms", records.size(), System.currentTimeMillis() - start));
                 }
             } catch (Exception e) {
-                Log.e(TAG, "ERROR uploading data!!!!!", e);
+                logger.e("ERROR uploading data!!!!!", e);
             }
         } else {
-            Log.i(TAG, "No records has to be uploaded");
+            logger.i("No records has to be uploaded");
         }
 
         NightscoutUploadReceiver.completeWakefulIntent(intent);
@@ -132,7 +133,7 @@ public class NightscoutUploadIntentService extends IntentService {
         try {
             doRESTUploadTo(uploadUrl, records);
         } catch (Exception e) {
-            Log.e(TAG, "Unable to do REST API Upload to: " + uploadUrl, e);
+            logger.e("Unable to do REST API Upload to: " + uploadUrl, e);
         }
     }
 
@@ -188,7 +189,7 @@ public class NightscoutUploadIntentService extends IntentService {
             }
 
         } catch (Exception e) {
-            Log.e(TAG, "Unable to post data", e);
+            logger.e("Unable to post data", e);
         }
     }
 
@@ -201,7 +202,7 @@ public class NightscoutUploadIntentService extends IntentService {
     }
 
     private boolean uploadToNightscout(URL endpoint, String secret, String httpBody) throws Exception {
-        Log.i(TAG, "postURL: " + endpoint.toString());
+        logger.d("postURL: " + endpoint.toString());
 
         HttpPost post = new HttpPost(endpoint.toString());
 
@@ -226,7 +227,7 @@ public class NightscoutUploadIntentService extends IntentService {
 
         DefaultHttpClient httpclient = new DefaultHttpClient(params);
 
-        Log.i(TAG, "Upload JSON: " + httpBody);
+        logger.d("Upload JSON: " + httpBody);
 
         try {
             StringEntity se = new StringEntity(httpBody);
@@ -237,7 +238,7 @@ public class NightscoutUploadIntentService extends IntentService {
             ResponseHandler responseHandler = new BasicResponseHandler();
             httpclient.execute(post, responseHandler);
         } catch (Exception e) {
-            Log.w(TAG, "Unable to post data to: '" + post.getURI().toString() + "'", e);
+            logger.e("Unable to post data to: '" + post.getURI().toString() + "'", e);
             return false;
         }
 
@@ -276,7 +277,7 @@ public class NightscoutUploadIntentService extends IntentService {
 
         json.put("pump", pumpInfo);
         String jsonString = json.toString();
-        Log.i(TAG, "Device Status JSON: " + jsonString);
+        logger.d("Device Status JSON: " + jsonString);
 
         devicestatusArray.put(json);
     }
diff --git a/app/src/main/java/info/nightscout/android/utils/Logger.java b/app/src/main/java/info/nightscout/android/utils/Logger.java
new file mode 100644
index 0000000000000000000000000000000000000000..f6b06d3f4bcd212c8e594bb4ab1ec8229d52f3c7
--- /dev/null
+++ b/app/src/main/java/info/nightscout/android/utils/Logger.java
@@ -0,0 +1,128 @@
+package info.nightscout.android.utils;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
+import android.support.v4.content.LocalBroadcastManager;
+import android.util.Log;
+
+import info.nightscout.android.R;
+import info.nightscout.android.medtronic.service.MedtronicCnlIntentService;
+
+/**
+ * Wraps android log to send messages to UI
+ */
+
+public class Logger {
+    private final Context context;
+    private final String tag;
+    private int logLevel = Log.ASSERT;
+
+    public Logger(String tag, Context context) {
+        this.tag = tag;
+        this.context = context;
+
+        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context.getApplicationContext());
+        String currentLogLevel = prefs.getString("logLevel", "0");
+        int pos = Integer.parseInt(currentLogLevel) - 1;
+        String[] logLevelNames = context.getResources().getStringArray(R.array.levelList);
+        if (pos >= 0 && pos < logLevelNames.length) {
+            currentLogLevel = logLevelNames[pos].toLowerCase();
+            if ("error".equals(currentLogLevel)) {
+                logLevel = Log.ERROR;
+            } else if ("warning".equals(currentLogLevel)) {
+                logLevel = Log.WARN;
+            } else if ("info".equals(currentLogLevel)) {
+                logLevel = Log.INFO;
+            } else if ("debug".equals(currentLogLevel)) {
+                logLevel = Log.DEBUG;
+            } else if ("verbose".equals(currentLogLevel)) {
+                logLevel = Log.VERBOSE;
+            }
+        }
+    }
+
+    public int v(String msg) {
+        if (logLevel <= Log.VERBOSE) {
+            sendStatus(msg);
+        }
+        return Log.v(tag, msg);
+    }
+
+    public int v(String msg, Throwable tr) {
+        if (logLevel <= Log.VERBOSE) {
+            sendStatus(msg);
+        }return Log.v(tag, msg, tr);
+    }
+
+    public int d(String msg) {
+        if (logLevel <= Log.DEBUG) {
+            sendStatus("(D) " + tag + ": " + msg);
+        }
+        return Log.d(tag, msg);
+    }
+
+    public int d(String msg, Throwable tr) {
+        if (logLevel <= Log.DEBUG) {
+            sendStatus("(D) " + tag + ": " + msg);
+        }
+        return Log.d(tag, msg, tr);
+    }
+
+    public int i(String msg) {
+        if (logLevel <= Log.INFO) {
+            sendStatus(msg);
+        }
+        return Log.i(tag, msg);
+    }
+
+    public int i(String msg, Throwable tr) {
+        if (logLevel <= Log.INFO) {
+            sendStatus(msg);
+        }
+        return Log.i(tag, msg, tr);
+    }
+
+    public int w(String msg) {
+        if (logLevel <= Log.WARN) {
+            sendStatus(msg);
+        }
+        return Log.w(tag, msg);
+    }
+
+    public int w(String msg, Throwable tr) {
+        if (logLevel <= Log.WARN) {
+            sendStatus(msg);
+        }
+        return Log.w(tag, msg, tr);
+    }
+
+    public int w(Throwable tr) {
+        if (logLevel <= Log.WARN) {
+            sendStatus(tr.getMessage());
+        }
+        return Log.w(tag, tr);
+    }
+
+    public int e(String msg) {
+        if (logLevel <= Log.ERROR) {
+            sendStatus("(E): " + msg);
+        }
+        return Log.e(tag, msg);
+    }
+
+    public int e(String msg, Throwable tr) {
+        if (logLevel <= Log.ERROR) {
+            sendStatus("(E): " + msg + "(" + tr.getMessage() + ")");
+        }
+        return Log.e(tag, msg, tr);
+    }
+
+    protected void sendStatus(String message) {
+        Intent localIntent =
+                new Intent(MedtronicCnlIntentService.Constants.ACTION_STATUS_MESSAGE)
+                        .putExtra(MedtronicCnlIntentService.Constants.EXTENDED_DATA, message);
+        LocalBroadcastManager.getInstance(context).sendBroadcast(localIntent);
+    }
+}