diff --git a/python/vyos/interface.py b/python/vyos/interface.py
new file mode 100644
index 000000000..6d57d972b
--- /dev/null
+++ b/python/vyos/interface.py
@@ -0,0 +1,131 @@
+# Copyright 2019 VyOS maintainers and contributors <maintainers@vyos.io>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library.  If not, see <http://www.gnu.org/licenses/>.
+
+import vyos
+from vyos.config import Config
+import vyos.interfaces
+
+import re
+import json
+
+import subprocess
+import time
+from datetime import timedelta
+import glob
+from os.path import isfile
+from tabulate import tabulate
+from hurry.filesize import size,alternative
+
+class Interface():
+
+    intf = None
+    intf_type = None
+
+    def __init__(self,intf):
+        self.intf = intf
+        self.intf_type = vyos.interfaces.get_type_of_interface(self.intf)
+
+    def print_interface(self):
+        if (self.intf_type == 'wireguard'):
+            self.print_wireguard_interface()
+
+        self.print_interface_stats()
+
+    def print_interface_stats(self):
+        stats = self.get_interface_stats()
+        rx = [['bytes','packets','errors','dropped','overrun','mcast'],[stats['rx_bytes'],stats['rx_packets'],stats['rx_errors'],stats['rx_dropped'],stats['rx_over_errors'],stats['multicast']]]
+        tx = [['bytes','packets','errors','dropped','carrier','collisions'],[stats['tx_bytes'],stats['tx_packets'],stats['tx_errors'],stats['tx_dropped'],stats['tx_carrier_errors'],stats['collisions']]]
+        output = "RX: \n"
+        output += tabulate(rx,headers="firstrow",numalign="right",tablefmt="plain")
+        output += "\n\nTX: \n"
+        output += tabulate(tx,headers="firstrow",numalign="right",tablefmt="plain")
+        print('  '.join(('\n'+output.lstrip()).splitlines(True)))
+
+    def get_interface_stats(self):
+        interface_stats = dict()
+        devices = [f for f in glob.glob("/sys/class/net/**/statistics")]
+        for dev_path in devices:
+            metrics = [f for f in glob.glob(dev_path +"/**")]
+            dev = re.findall(r"/sys/class/net/(.*)/statistics",dev_path)[0]
+            dev_dict = dict()
+            for metric_path in metrics:
+                metric = metric_path.replace(dev_path+"/","")
+                if isfile(metric_path):
+                    data = open(metric_path, 'r').read()[:-1]
+                    dev_dict[metric] = int(data)
+            interface_stats[dev] = dev_dict
+        return interface_stats[self.intf]
+
+    def print_wireguard_interface(self):
+        output = subprocess.check_output(["wg", "show", self.intf], universal_newlines=True)
+        wgdump = vyos.interfaces.wireguard_dump()[self.intf]
+        c = Config()
+        c.set_level("interfaces wireguard {}".format(self.intf))
+        description = c.return_effective_value("description")
+
+        print ("interface: {}".format(self.intf))
+        """ if the interface has a description, modify the output to include it """
+        if (description):
+            print ("  description: {}".format(description))
+            output = re.sub(r"interface: {}".format(re.escape(self.intf)),"interface: {}\n  Description: {}".format(self.intf,description),output)
+
+        print ("  public key: {}".format(wgdump['public_key']))
+        print ("  private key: (hidden)")
+        print ("  listening port: {}".format(wgdump['listen_port']))
+        print ()
+
+        for peer in c.list_effective_nodes(' peer'):
+            if wgdump['peers']:
+                pubkey = c.return_effective_value("peer {} pubkey".format(peer))
+                if pubkey in wgdump['peers']:
+                    wgpeer = wgdump['peers'][pubkey] 
+
+                    print ("  peer: {}".format(peer))
+                    print ("    public key: {}".format(pubkey))
+
+                    """ figure out if the tunnel is recently active or not """
+                    status = "inactive"
+                    if (wgpeer['latest_handshake'] is None):
+                        """ no handshake ever """
+                        status = "inactive"
+                    else:
+                        if int(wgpeer['latest_handshake']) > 0:
+                            delta = timedelta(seconds=int(time.time() - wgpeer['latest_handshake']))
+                            print ("    latest handshake: {}".format(delta))
+                            if (time.time() - int(wgpeer['latest_handshake']) < (60*5)):
+                                """ Five minutes and the tunnel is still active """
+                                status = "active"
+                            else:
+                                """ it's been longer than 5 minutes """
+                                status = "inactive"
+                        elif int(wgpeer['latest_handshake']) == 0:
+                            """ no handshake ever """
+                            status = "inactive"
+                        print ("    status: {}".format(status))    
+
+                    if wgpeer['endpoint'] is not None:
+                        print ("    endpoint: {}".format(wgpeer['endpoint']))
+
+                    if wgpeer['allowed_ips'] is not None:
+                        print ("    allowed ips: {}".format(",".join(wgpeer['allowed_ips']).replace(",",", ")))
+                    
+                    if wgpeer['transfer_rx'] > 0 or wgpeer['transfer_tx'] > 0: 
+                        rx_size =size(wgpeer['transfer_rx'],system=alternative)
+                        tx_size =size(wgpeer['transfer_tx'],system=alternative)
+                        print ("    transfer: {} received, {} sent".format(rx_size,tx_size))
+
+                    if wgpeer['persistent_keepalive'] is not None:
+                        print ("    persistent keepalive: every {} seconds".format(wgpeer['persistent_keepalive']))
+                print()
diff --git a/python/vyos/interfaces.py b/python/vyos/interfaces.py
index d69ce9d04..ecf061d17 100644
--- a/python/vyos/interfaces.py
+++ b/python/vyos/interfaces.py
@@ -1,56 +1,99 @@
 # Copyright 2018 VyOS maintainers and contributors <maintainers@vyos.io>
 #
 # This library is free software; you can redistribute it and/or
 # modify it under the terms of the GNU Lesser General Public
 # License as published by the Free Software Foundation; either
 # version 2.1 of the License, or (at your option) any later version.
 #
 # This library is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 # Lesser General Public License for more details.
 #
 # You should have received a copy of the GNU Lesser General Public
 # License along with this library.  If not, see <http://www.gnu.org/licenses/>.
 
 import re
 import json
 
+import subprocess
 import netifaces
 
-
 intf_type_data_file = '/usr/share/vyos/interface-types.json'
 
 def list_interfaces():
     interfaces = netifaces.interfaces()
 
     # Remove "fake" interfaces associated with drivers
     for i in ["dummy0", "ip6tnl0", "tunl0", "ip_vti0", "ip6_vti0"]:
         try:
             interfaces.remove(i)
         except ValueError:
             pass
 
     return interfaces
 
 def list_interfaces_of_type(typ):
     with open(intf_type_data_file, 'r') as f:
         types_data = json.load(f)
 
     all_intfs = list_interfaces()
     if not (typ in types_data.keys()):
         raise ValueError("Unknown interface type: {0}".format(typ))
     else:
         r = re.compile('^{0}\d+'.format(types_data[typ]))
         return list(filter(lambda i: re.match(r, i), all_intfs))
 
 def get_type_of_interface(intf):
     with open(intf_type_data_file, 'r') as f:
         types_data = json.load(f)
 
     for key,val in types_data.items():
         r = re.compile('^{0}\d+'.format(val))
         if re.match(r, intf):
             return key
 
     raise ValueError("No type found for interface name: {0}".format(intf))
+
+def wireguard_dump():
+    """Dump wireguard data in a python friendly way."""
+    last_device=None
+    output = {}
+    
+    # Dump wireguard connection data
+    _f = subprocess.check_output(["wg", "show", "all", "dump"]).decode()
+    for line in _f.split('\n'):
+        if not line:
+          # Skip empty lines and last line
+          continue
+        items = line.split('\t')
+
+        if last_device != items[0]:
+            # We are currently entering a new node
+            device, private_key, public_key, listen_port, fw_mark = items
+            last_device = device
+            
+            output[device] = {
+                'private_key': None if private_key == '(none)' else private_key,
+                'public_key': None if public_key == '(none)' else public_key,
+                'listen_port': int(listen_port),
+                'fw_mark': None if fw_mark == 'off' else int(fw_mark),
+                'peers': {},
+                } 
+        else:
+            # We are entering a peer
+            device, public_key, preshared_key, endpoint, allowed_ips, latest_handshake, transfer_rx, transfer_tx, persistent_keepalive = items
+            if allowed_ips == '(none)':
+                allowed_ips = []
+            else:
+                allowed_ips = allowed_ips.split('\t')
+            output[device]['peers'][public_key] = {
+                'preshared_key': None if preshared_key == '(none)' else preshared_key,
+                'endpoint': None if endpoint == '(none)' else endpoint,
+                'allowed_ips': allowed_ips,
+                'latest_handshake': None if latest_handshake == '0' else int(latest_handshake),
+                'transfer_rx': int(transfer_rx),
+                'transfer_tx': int(transfer_tx),
+                'persistent_keepalive': None if persistent_keepalive == 'off' else int(persistent_keepalive),
+           } 
+    return output
diff --git a/src/op_mode/wireguard.py b/src/op_mode/wireguard.py
index f6978554d..6860aa3ea 100755
--- a/src/op_mode/wireguard.py
+++ b/src/op_mode/wireguard.py
@@ -1,197 +1,163 @@
 #!/usr/bin/env python3
 #
 # Copyright (C) 2018 VyOS maintainers and contributors
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License version 2 or later as
 # published by the Free Software Foundation.
 #
 # This program is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 # GNU General Public License for more details.
 #
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #
 #
 
 import argparse
 import os
 import sys
 import shutil
 import subprocess
 import syslog as sl
 import re
-import time
 
+from vyos.interface import Interface
 
 from vyos import ConfigError
 from vyos.config import Config
 
 dir = r'/config/auth/wireguard'
 psk = dir + '/preshared.key'
 
 def check_kmod():
     """ check if kmod is loaded, if not load it """
     if not os.path.exists('/sys/module/wireguard'):
         sl.syslog(sl.LOG_NOTICE, "loading wirguard kmod")
         if os.system('sudo modprobe wireguard') != 0:
             sl.syslog(sl.LOG_ERR, "modprobe wireguard failed")
             raise ConfigError("modprobe wireguard failed")
 
-
-def showint(interface):
-    output = subprocess.check_output(["wg", "show", interface], universal_newlines=True)
-    c = Config()
-    c.set_level("interfaces wireguard {}".format(interface))
-    description = c.return_effective_value("description".format(interface))
-    """ if the interface has a description, modify the output to include it """
-    if (description):
-        output = re.sub(r"interface: {}".format(re.escape(interface)),"interface: {}\n  Description: {}".format(interface,description),output)
-    
-    """ pull the last handshake times.  Assume if the handshake was greater than 5 minutes, the tunnel is down """
-    peer_timeouts = {}
-    last_hs_output = subprocess.check_output(["wg", "show", interface, "latest-handshakes"], universal_newlines=True)
-    for match in re.findall(r'(\S+)\s+(\d+)',last_hs_output): 
-        peer_timeouts[match[0]] = match[1]
-
-    """ modify all the peers, reformat to provide VyOS config provided peername, whether the tunnel is up/down """
-    for peer in c.list_effective_nodes(' peer'):
-        pubkey = c.return_effective_value("peer {} pubkey".format(peer))
-        status = ""
-        if int(peer_timeouts[pubkey]) > 0:
-            #Five minutes and the tunnel is still up
-            if (time.time() - int(peer_timeouts[pubkey]) < (60*5)):
-                status = "UP"
-            else:
-                status = "DOWN"
-        elif (peer_timeouts[pubkey] is None):
-            status = "DOWN"
-        elif (int(peer_timeouts[pubkey]) == 0):
-            status = "DOWN"
-
-        output = re.sub(r"peer: {}".format(re.escape(pubkey)),"peer: {}\n  Status: {}\n  public key: {}".format(peer,status,pubkey),output)
-
-    print(output)
-    
 def generate_keypair(pk, pub):
     """ generates a keypair which is stored in /config/auth/wireguard """
     old_umask = os.umask(0o027)
     ret = subprocess.call(
         ['wg genkey | tee ' + pk + '|wg pubkey > ' + pub], shell=True)
     if ret != 0:
         raise ConfigError("wireguard key-pair generation failed")
     else:
         sl.syslog(
             sl.LOG_NOTICE, "new keypair wireguard key generated in " + dir)
     os.umask(old_umask)
 
 
 def genkey(location):
     """ helper function to check, regenerate the keypair """
     pk = "{}/private.key".format(location)
     pub = "{}/public.key".format(location)
     old_umask = os.umask(0o027)
     if os.path.exists(pk) and os.path.exists(pub):
         try:
             choice = input(
                 "You already have a wireguard key-pair, do you want to re-generate? [y/n] ")
             if choice == 'y' or choice == 'Y':
                 generate_keypair(pk, pub)
         except KeyboardInterrupt:
             sys.exit(0)
     else:
         """ if keypair is bing executed from a running iso """
         if not os.path.exists(location):
             subprocess.call(['sudo mkdir -p ' + location], shell=True)
             subprocess.call(['sudo chgrp vyattacfg ' + location], shell=True)
             subprocess.call(['sudo chmod 750 ' + location], shell=True)
         generate_keypair(pk, pub)
     os.umask(old_umask)
 
 
 def showkey(key):
     """ helper function to show privkey or pubkey """
     if os.path.exists(key):
         print (open(key).read().strip())
     else:
         print ("{} not found".format(key))
 
 
 def genpsk():
     """
         generates a preshared key and shows it on stdout,
         it's stored only in the cli config
     """
 
     subprocess.call(['wg genpsk'], shell=True)
 
 def list_key_dirs():
     """ lists all dirs under /config/auth/wireguard """ 
     if os.path.exists(dir):
         nks = next(os.walk(dir))[1]
         for nk in nks:
             print (nk)
 
 def del_key_dir(kname):
     """ deletes /config/auth/wireguard/<kname> """
     kdir = "{0}/{1}".format(dir,kname)
     if not os.path.isdir(kdir):
         print ("named keypair {} not found".format(kname))
         return 1
     shutil.rmtree(kdir)
 
 
 if __name__ == '__main__':
     check_kmod()
     parser = argparse.ArgumentParser(description='wireguard key management')
     parser.add_argument(
         '--genkey', action="store_true", help='generate key-pair')
     parser.add_argument(
         '--showpub', action="store_true", help='shows public key')
     parser.add_argument(
         '--showpriv', action="store_true", help='shows private key')
     parser.add_argument(
         '--genpsk', action="store_true", help='generates preshared-key')
     parser.add_argument(
         '--location', action="store", help='key location within {}'.format(dir))
     parser.add_argument(
         '--listkdir', action="store_true", help='lists named keydirectories')
     parser.add_argument(
         '--delkdir', action="store_true", help='removes named keydirectories')
     parser.add_argument(
         '--showinterface', action="store", help='shows interface details')
     args = parser.parse_args()
 
     try:
         if args.genkey:
             if args.location:
                 genkey("{0}/{1}".format(dir, args.location))
             else:
                 genkey("{}/default".format(dir))
         if args.showpub:
             if args.location:
                 showkey("{0}/{1}/public.key".format(dir, args.location))
             else:
                 showkey("{}/default/public.key".format(dir))
         if args.showpriv:
             if args.location:
                 showkey("{0}/{1}/private.key".format(dir, args.location))
             else:
                 showkey("{}/default/private.key".format(dir))
         if args.genpsk:
             genpsk()
         if args.listkdir:
             list_key_dirs()
         if args.showinterface:
-            showint(args.showinterface)
+            intf = Interface(args.showinterface)
+            intf.print_interface()
         if args.delkdir:
             if args.location:
                 del_key_dir(args.location)
             else:
                 del_key_dir("default")
 
     except ConfigError as e:
         print(e)
         sys.exit(1)