diff --git a/CHANGELOG.md b/CHANGELOG.md
index b10d7fa5d2ce00684920515e70ae2b1ea5c4213f..b47ac3d505074a13dc05de4bd31b1ff815731503 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,17 @@
+# v0.1.1 - 2020-02-07
+
+This release contains a series of fixes:
+* Adds logging of the underlying error when a neighbor connection couldn't be established
+* Adds the `RemoteLog` plugin (disabled per default) which sends log messages to a centralized logging service
+* Removes the status screen plugin in favor of the SPA/dashboard
+* Fixes the neighbor send queue being too small causing spam in the log
+* Fixes a deadlock which occurred when a neighbor disconnected while at the same time a `request transaction` 
+packet was getting processed which was received by the disconnected neighbor
+* Fixes memory consumption by disabling BadgerDB's compression
+* Fixes analysis server WebSocket replays freezing the backend code
+* Fixes sending on the neighbor send queue if the neighbor is disconnected
+* Fixes `BufferedConnection`'s read and written bytes to be atomic
+
 # v0.1.0 - 2020-01-31
 
 > Note that this release is a complete breaking change, therefore node operators are instructed to upgrade.
diff --git a/config.json b/config.json
index eff648254ff5add725f321e8a4de6df25ae08b30..43e4801b30afa8dc6198b189c894a62b9ef57b39 100644
--- a/config.json
+++ b/config.json
@@ -1,67 +1,71 @@
-{
-  "analysis": {
-    "client": {
-      "serverAddress": "ressims.iota.cafe:188"
-    },
-    "server": {
-      "port": 0
-    },
-    "httpServer": {
-      "bindAddress": "0.0.0.0:80"
-    }
-  },
-  "autopeering": {
-    "entryNodes": [
-      "V8LYtWWcPYYDTTXLeIEFjJEuWlsjDiI0+Pq/Cx9ai6g=@116.202.49.178:14626"
-    ],
-    "port": 14626
-  },
-  "dashboard": {
-    "bindAddress": "127.0.0.1:8081",
-    "dev": false,
-    "basic_auth": {
-      "enabled": false,
-      "username": "goshimmer",
-      "password": "goshimmer"
-    }
-  },
-  "database": {
-    "directory": "mainnetdb"
-  },
-  "gossip": {
-    "port": 14666
-  },
-  "graph": {
-    "bindAddress": "127.0.0.1:8082",
-    "domain": "",
-    "networkName": "GoShimmer",
-    "socketIOPath": "socket.io-client/dist/socket.io.js",
-    "webrootPath": "IOTAtangle/webroot"
-  },
-  "logger": {
-    "level": "info",
-    "disableCaller": false,
-    "disableStacktrace": false,
-    "encoding": "console",
-    "outputPaths": [
-      "goshimmer.log"
-    ],
-    "disableEvents": false
-  },
-  "network": {
-    "bindAddress": "0.0.0.0",
-    "externalAddress": "auto"
-  },
-  "node": {
-    "disablePlugins": [],
-    "enablePlugins": []
-  },
-  "webapi": {
-    "auth": {
-      "password": "goshimmer",
-      "privateKey": "",
-      "username": "goshimmer"
-    },
-    "bindAddress": "127.0.0.1:8080"
-  }
-}
+{
+  "analysis": {
+    "client": {
+      "serverAddress": "ressims.iota.cafe:188"
+    },
+    "server": {
+      "port": 0
+    },
+    "httpServer": {
+      "bindAddress": "0.0.0.0:80"
+    }
+  },
+  "autopeering": {
+    "entryNodes": [
+      "V8LYtWWcPYYDTTXLeIEFjJEuWlsjDiI0+Pq/Cx9ai6g=@116.202.49.178:14626"
+    ],
+    "port": 14626
+  },
+  "dashboard": {
+    "bindAddress": "127.0.0.1:8081",
+    "dev": false,
+    "basic_auth": {
+      "enabled": false,
+      "username": "goshimmer",
+      "password": "goshimmer"
+    }
+  },
+  "database": {
+    "directory": "mainnetdb"
+  },
+  "gossip": {
+    "port": 14666
+  },
+  "graph": {
+    "bindAddress": "127.0.0.1:8082",
+    "domain": "",
+    "networkName": "GoShimmer",
+    "socketIOPath": "socket.io-client/dist/socket.io.js",
+    "webrootPath": "IOTAtangle/webroot"
+  },
+  "logger": {
+    "level": "info",
+    "disableCaller": false,
+    "disableStacktrace": false,
+    "encoding": "console",
+    "outputPaths": [
+      "stdout",
+      "goshimmer.log"
+    ],
+    "disableEvents": true,
+    "remotelog": {
+      "serverAddress": "remotelog.goshimmer.iota.cafe:5213"
+    }
+  },
+  "network": {
+    "bindAddress": "0.0.0.0",
+    "externalAddress": "auto"
+  },
+  "node": {
+    "disablePlugins": [],
+    "enablePlugins": []
+  },
+  "webapi": {
+    "auth": {
+      "password": "goshimmer",
+      "privateKey": "",
+      "username": "goshimmer"
+    },
+    "bindAddress": "127.0.0.1:8080"
+  }
+}
diff --git a/docker.config.json b/docker.config.json
index 1bb3a722ba424a09aedba0d2ae2fe6d35b9312b8..ff931575eb04575e32fc42797f2a91cbf7d07c41 100644
--- a/docker.config.json
+++ b/docker.config.json
@@ -28,9 +28,7 @@
     "DisableEvents": true
   },
   "node": {
-    "disablePlugins": [
-      "statusscreen"
-    ],
+    "disablePlugins": [],
     "enablePlugins": []
   }
 }
diff --git a/go.mod b/go.mod
index 7b6391201ffdd2f037ffee6bdf8d5f52432d243a..af0a116b1d214e88bc285a9bc55dc794fd1f7aec 100644
--- a/go.mod
+++ b/go.mod
@@ -6,7 +6,6 @@ require (
 	github.com/dgraph-io/badger/v2 v2.0.1
 	github.com/dgrijalva/jwt-go v3.2.0+incompatible
 	github.com/dgryski/go-farm v0.0.0-20191112170834-c2139c5d712b // indirect
-	github.com/gdamore/tcell v1.3.0
 	github.com/gobuffalo/envy v1.8.1 // indirect
 	github.com/gobuffalo/logger v1.0.3 // indirect
 	github.com/gobuffalo/packr/v2 v2.7.1
@@ -14,18 +13,15 @@ require (
 	github.com/googollee/go-engine.io v1.4.3-0.20190924125625-798118fc0dd2
 	github.com/googollee/go-socket.io v1.4.3-0.20191204093753-683f8725b6d0
 	github.com/gorilla/websocket v1.4.1
-	github.com/iotaledger/hive.go v0.0.0-20200121213505-28904d5f037c
+	github.com/iotaledger/hive.go v0.0.0-20200207144536-27b18f10f09e
 	github.com/iotaledger/iota.go v1.0.0-beta.14
 	github.com/labstack/echo v3.3.10+incompatible
 	github.com/labstack/gommon v0.3.0 // indirect
-	github.com/lucasb-eyer/go-colorful v1.0.3 // indirect
 	github.com/magiconair/properties v1.8.1
 	github.com/mattn/go-colorable v0.1.4 // indirect
 	github.com/mattn/go-isatty v0.0.11 // indirect
-	github.com/mattn/go-runewidth v0.0.7 // indirect
 	github.com/pelletier/go-toml v1.6.0 // indirect
 	github.com/pkg/errors v0.9.1
-	github.com/rivo/tview v0.0.0-20191229165609-1ee8d9874dcf
 	github.com/rogpeppe/go-internal v1.5.2 // indirect
 	github.com/spf13/afero v1.2.2 // indirect
 	github.com/spf13/cast v1.3.1 // indirect
@@ -35,10 +31,12 @@ require (
 	github.com/stretchr/objx v0.2.0 // indirect
 	github.com/stretchr/testify v1.4.0
 	github.com/valyala/fasttemplate v1.1.0 // indirect
+	go.uber.org/atomic v1.5.1
 	go.uber.org/zap v1.13.0
-	golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d
+	golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d // indirect
 	golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553
 	golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9 // indirect
+	golang.org/x/text v0.3.2 // indirect
 	golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7 // indirect
 	gopkg.in/ini.v1 v1.51.1 // indirect
 	gopkg.in/yaml.v2 v2.2.7 // indirect
diff --git a/go.sum b/go.sum
index 769edd98ff040c8c9302717d4486feb75fea7d1f..a943eb062fea49c8fdba4266e04f99acc95be135 100644
--- a/go.sum
+++ b/go.sum
@@ -9,7 +9,6 @@ git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGy
 github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
 github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
 github.com/DataDog/zstd v1.4.1 h1:3oxKN3wbHibqx897utPC2LTQU4J+IHWWJO+glkAkpFM=
 github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
 github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
@@ -54,10 +53,6 @@ github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25Kn
 github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
 github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
-github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
-github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
-github.com/gdamore/tcell v1.3.0 h1:r35w0JBADPZCVQijYebl6YMWWtHRqVEGt7kL2eBADRM=
-github.com/gdamore/tcell v1.3.0/go.mod h1:Hjvr+Ofd+gLglo7RYKxxnzCBmev3BzsS67MebKS4zMM=
 github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
 github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
 github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
@@ -128,8 +123,8 @@ github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
 github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
 github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
 github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
-github.com/iotaledger/hive.go v0.0.0-20200121213505-28904d5f037c h1:3T0MLyZIL74kYLqVrmv1xQlwE2ktS1IO8kjM+NyXEMU=
-github.com/iotaledger/hive.go v0.0.0-20200121213505-28904d5f037c/go.mod h1:S+v90R3u4Rqe4VoOg4DhiZrAKlKZhz2UFKuK/Neqa2o=
+github.com/iotaledger/hive.go v0.0.0-20200207144536-27b18f10f09e h1:eM0/mEG3ZPflZRJxOn0cc+/8ZZIpirEAyhzF4rzTKjM=
+github.com/iotaledger/hive.go v0.0.0-20200207144536-27b18f10f09e/go.mod h1:wj3bFHlcX0NiEOWu5+WOg/MI/5N7PKCFnyaziaylB64=
 github.com/iotaledger/iota.go v1.0.0-beta.9/go.mod h1:F6WBmYd98mVjAmmPVYhnxg8NNIWCjjH8VWT9qvv3Rc8=
 github.com/iotaledger/iota.go v1.0.0-beta.14 h1:Oeb28MfBuJEeXcGrLhTCJFtbsnc8y1u7xidsAmiOD5A=
 github.com/iotaledger/iota.go v1.0.0-beta.14/go.mod h1:F6WBmYd98mVjAmmPVYhnxg8NNIWCjjH8VWT9qvv3Rc8=
@@ -156,9 +151,6 @@ github.com/labstack/echo v3.3.10+incompatible h1:pGRcYk231ExFAyoAjAfD85kQzRJCRI8
 github.com/labstack/echo v3.3.10+incompatible/go.mod h1:0INS7j/VjnFxD4E2wkz67b8cVwCLbBmJyDaka6Cmk1s=
 github.com/labstack/gommon v0.3.0 h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0=
 github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
-github.com/lucasb-eyer/go-colorful v1.0.2/go.mod h1:0MS4r+7BZKSJ5mw4/S5MPN+qHFF1fYclkSPilDOKW0s=
-github.com/lucasb-eyer/go-colorful v1.0.3 h1:QIbQXiugsb+q10B+MI+7DI1oQLdmnep86tWFlaaUAac=
-github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
 github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
 github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
 github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
@@ -169,9 +161,6 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
 github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
 github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM=
 github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
-github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
-github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54=
-github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
 github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
 github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
@@ -213,10 +202,6 @@ github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R
 github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
 github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
 github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
-github.com/rivo/tview v0.0.0-20191229165609-1ee8d9874dcf h1:rh73WIukDlFIRqk1lk76or+LExEjTci2789EDvDD67U=
-github.com/rivo/tview v0.0.0-20191229165609-1ee8d9874dcf/go.mod h1:/rBeY22VG2QprWnEqG57IBC8biVu3i0DOIjRLc9I8H0=
-github.com/rivo/uniseg v0.1.0 h1:+2KBaVoUmb9XzDsrx/Ct0W/EYOSFf/nWTauy++DprtY=
-github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
 github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
 github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
@@ -383,10 +368,8 @@ golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191018095205-727590c5006e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9 h1:1/DFK4b7JH8DmkqhUk48onnSfrPzImPoVxuomtbT2nk=
 golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
diff --git a/main.go b/main.go
index 2e10cf29cb90e9f9ca3a8f1cb5efe1513cf980fd..2f94717210c0aea39f96347dd3ba68315da7f130 100644
--- a/main.go
+++ b/main.go
@@ -12,9 +12,8 @@ import (
 	"github.com/iotaledger/goshimmer/plugins/gracefulshutdown"
 	"github.com/iotaledger/goshimmer/plugins/graph"
 	"github.com/iotaledger/goshimmer/plugins/metrics"
+	"github.com/iotaledger/goshimmer/plugins/remotelog"
 	"github.com/iotaledger/goshimmer/plugins/spa"
-	"github.com/iotaledger/goshimmer/plugins/statusscreen"
-	statusscreen_tps "github.com/iotaledger/goshimmer/plugins/statusscreen-tps"
 	"github.com/iotaledger/goshimmer/plugins/tangle"
 	"github.com/iotaledger/goshimmer/plugins/tipselection"
 	"github.com/iotaledger/goshimmer/plugins/webapi"
@@ -37,6 +36,8 @@ func main() {
 	node.Run(
 		node.Plugins(
 			cli.PLUGIN,
+			remotelog.PLUGIN,
+
 			autopeering.PLUGIN,
 			gossip.PLUGIN,
 			tangle.PLUGIN,
@@ -46,9 +47,6 @@ func main() {
 			tipselection.PLUGIN,
 			metrics.PLUGIN,
 
-			statusscreen.PLUGIN,
-			statusscreen_tps.PLUGIN,
-
 			webapi.PLUGIN,
 			webapi_auth.PLUGIN,
 			webapi_gtta.PLUGIN,
diff --git a/packages/database/database.go b/packages/database/database.go
index 793b394489253e1f044c0101c39634096bbc13f8..1a1465ca4a87055e1414a954443d2a3d07ec21ef 100644
--- a/packages/database/database.go
+++ b/packages/database/database.go
@@ -7,6 +7,7 @@ import (
 	"sync"
 
 	"github.com/dgraph-io/badger/v2"
+	"github.com/dgraph-io/badger/v2/options"
 	"github.com/iotaledger/goshimmer/packages/parameter"
 	"github.com/iotaledger/hive.go/database"
 	"github.com/iotaledger/hive.go/logger"
@@ -56,6 +57,13 @@ func GetBadgerInstance() *badger.DB {
 			opts = opts.WithTruncate(true)
 		}
 
+		opts.CompactL0OnClose = false
+		opts.KeepL0InMemory = false
+		opts.VerifyValueChecksum = false
+		opts.ZSTDCompressionLevel = 1
+		opts.Compression = options.None
+		opts.MaxCacheSize = 50000000
+
 		db, err := database.CreateDB(dbDir, opts)
 		if err != nil {
 			// errors should cause a panic to avoid singleton deadlocks
diff --git a/packages/gossip/events.go b/packages/gossip/events.go
index 169ec219b8cd1cd244031347aa6526f560d0fe21..5f96044a39428556b1f3bd009d4a2ff4574b0421 100644
--- a/packages/gossip/events.go
+++ b/packages/gossip/events.go
@@ -16,7 +16,7 @@ var Events = struct {
 	// A TransactionReceived event is triggered when a new transaction is received by the gossip protocol.
 	TransactionReceived *events.Event
 }{
-	ConnectionFailed:    events.NewEvent(peerCaller),
+	ConnectionFailed:    events.NewEvent(peerAndErrorCaller),
 	NeighborAdded:       events.NewEvent(neighborCaller),
 	NeighborRemoved:     events.NewEvent(peerCaller),
 	TransactionReceived: events.NewEvent(transactionReceived),
@@ -27,6 +27,10 @@ type TransactionReceivedEvent struct {
 	Peer *peer.Peer // peer that send the transaction
 }
 
+func peerAndErrorCaller(handler interface{}, params ...interface{}) {
+	handler.(func(*peer.Peer, error))(params[0].(*peer.Peer), params[1].(error))
+}
+
 func peerCaller(handler interface{}, params ...interface{}) {
 	handler.(func(*peer.Peer))(params[0].(*peer.Peer))
 }
diff --git a/packages/gossip/manager.go b/packages/gossip/manager.go
index 7984a9e6d92a3fe5ae9be8d1c0b7141c477a1a01..bc08ab560986e10961893407078a0acae7d1623f 100644
--- a/packages/gossip/manager.go
+++ b/packages/gossip/manager.go
@@ -1,6 +1,7 @@
 package gossip
 
 import (
+	"errors"
 	"fmt"
 	"net"
 	"sync"
@@ -17,6 +18,11 @@ const (
 	maxPacketSize = 2048
 )
 
+var (
+	ErrNeighborManagerNotRunning = errors.New("neighbor manager is not running")
+	ErrNeighborAlreadyConnected  = errors.New("neighbor is already connected")
+)
+
 // GetTransaction defines a function that returns the transaction data with the given hash.
 type GetTransaction func(txHash []byte) ([]byte, error)
 
@@ -78,6 +84,7 @@ func (m *Manager) AddOutbound(p *peer.Peer) error {
 	var srv *server.TCP
 	m.mu.RLock()
 	if m.srv == nil {
+		m.mu.RUnlock()
 		return ErrNotStarted
 	}
 	srv = m.srv
@@ -94,6 +101,7 @@ func (m *Manager) AddInbound(p *peer.Peer) error {
 	var srv *server.TCP
 	m.mu.RLock()
 	if m.srv == nil {
+		m.mu.RUnlock()
 		return ErrNotStarted
 	}
 	srv = m.srv
@@ -104,15 +112,11 @@ func (m *Manager) AddInbound(p *peer.Peer) error {
 
 // NeighborRemoved disconnects the neighbor with the given ID.
 func (m *Manager) DropNeighbor(id peer.ID) error {
-	m.mu.Lock()
-	defer m.mu.Unlock()
-	if _, ok := m.neighbors[id]; !ok {
-		return ErrNotANeighbor
+	n, err := m.removeNeighbor(id)
+	if err != nil {
+		return err
 	}
-	n := m.neighbors[id]
-	delete(m.neighbors, id)
-
-	err := n.Close()
+	err = n.Close()
 	Events.NeighborRemoved.Trigger(n.Peer)
 	return err
 }
@@ -139,12 +143,11 @@ func (m *Manager) SendTransaction(txData []byte, to ...peer.ID) {
 
 func (m *Manager) GetAllNeighbors() []*Neighbor {
 	m.mu.RLock()
+	defer m.mu.RUnlock()
 	result := make([]*Neighbor, 0, len(m.neighbors))
 	for _, n := range m.neighbors {
 		result = append(result, n)
 	}
-	m.mu.RUnlock()
-
 	return result
 }
 
@@ -159,13 +162,12 @@ func (m *Manager) getNeighborsById(ids []peer.ID) []*Neighbor {
 	result := make([]*Neighbor, 0, len(ids))
 
 	m.mu.RLock()
+	defer m.mu.RUnlock()
 	for _, id := range ids {
 		if n, ok := m.neighbors[id]; ok {
 			result = append(result, n)
 		}
 	}
-	m.mu.RUnlock()
-
 	return result
 }
 
@@ -174,7 +176,7 @@ func (m *Manager) send(b []byte, to ...peer.ID) {
 
 	for _, nbr := range neighbors {
 		if _, err := nbr.Write(b); err != nil {
-			m.log.Warnw("send error", "err", err)
+			m.log.Warnw("send error", "err", err, "neighbor", nbr.Peer.Address())
 		}
 	}
 }
@@ -182,7 +184,7 @@ func (m *Manager) send(b []byte, to ...peer.ID) {
 func (m *Manager) addNeighbor(peer *peer.Peer, connectorFunc func(*peer.Peer) (net.Conn, error)) error {
 	conn, err := connectorFunc(peer)
 	if err != nil {
-		Events.ConnectionFailed.Trigger(peer)
+		Events.ConnectionFailed.Trigger(peer, err)
 		return err
 	}
 
@@ -190,12 +192,12 @@ func (m *Manager) addNeighbor(peer *peer.Peer, connectorFunc func(*peer.Peer) (n
 	defer m.mu.Unlock()
 	if !m.running {
 		_ = conn.Close()
-		Events.ConnectionFailed.Trigger(peer)
+		Events.ConnectionFailed.Trigger(peer, ErrNeighborManagerNotRunning)
 		return ErrClosed
 	}
 	if _, ok := m.neighbors[peer.ID()]; ok {
 		_ = conn.Close()
-		Events.ConnectionFailed.Trigger(peer)
+		Events.ConnectionFailed.Trigger(peer, ErrNeighborAlreadyConnected)
 		return ErrDuplicateNeighbor
 	}
 
@@ -215,6 +217,17 @@ func (m *Manager) addNeighbor(peer *peer.Peer, connectorFunc func(*peer.Peer) (n
 	return nil
 }
 
+func (m *Manager) removeNeighbor(id peer.ID) (*Neighbor, error) {
+	m.mu.Lock()
+	defer m.mu.Unlock()
+	if _, ok := m.neighbors[id]; !ok {
+		return nil, ErrNotANeighbor
+	}
+	n := m.neighbors[id]
+	delete(m.neighbors, id)
+	return n, nil
+}
+
 func (m *Manager) handlePacket(data []byte, p *peer.Peer) error {
 	// ignore empty packages
 	if len(data) == 0 {
diff --git a/packages/gossip/manager_test.go b/packages/gossip/manager_test.go
index f4b25a2943ea8bb32c14c2923347c234895733cb..07dda4017bf09849f76c78592985cc9eab05995e 100644
--- a/packages/gossip/manager_test.go
+++ b/packages/gossip/manager_test.go
@@ -310,7 +310,7 @@ func TestDropUnsuccessfulAccept(t *testing.T) {
 	_, closeB, peerB := newTestManager(t, "B")
 	defer closeB()
 
-	e.On("connectionFailed", peerB).Once()
+	e.On("connectionFailed", peerB, mock.Anything).Once()
 
 	err := mgrA.AddInbound(peerB)
 	assert.Error(t, err)
@@ -432,7 +432,7 @@ type eventMock struct {
 	mock.Mock
 }
 
-func (e *eventMock) connectionFailed(p *peer.Peer)                    { e.Called(p) }
+func (e *eventMock) connectionFailed(p *peer.Peer, err error)         { e.Called(p, err) }
 func (e *eventMock) neighborAdded(n *Neighbor)                        { e.Called(n) }
 func (e *eventMock) neighborRemoved(p *peer.Peer)                     { e.Called(p) }
 func (e *eventMock) transactionReceived(ev *TransactionReceivedEvent) { e.Called(ev) }
diff --git a/packages/gossip/neighbor.go b/packages/gossip/neighbor.go
index 6674275b595900a0ac379eb90964a2a675f19e38..07509a5265fba033f4f6714a8936f9a9d2847372 100644
--- a/packages/gossip/neighbor.go
+++ b/packages/gossip/neighbor.go
@@ -19,7 +19,7 @@ var (
 )
 
 const (
-	neighborQueueSize = 1000
+	neighborQueueSize = 5000
 	maxNumReadErrors  = 10
 )
 
@@ -84,7 +84,6 @@ func (n *Neighbor) IsOutbound() bool {
 func (n *Neighbor) disconnect() (err error) {
 	n.disconnectOnce.Do(func() {
 		close(n.closing)
-		close(n.queue)
 		err = n.BufferedConnection.Close()
 	})
 	return
@@ -100,8 +99,9 @@ func (n *Neighbor) writeLoop() {
 				continue
 			}
 			if _, err := n.BufferedConnection.Write(msg); err != nil {
-				// ignore write errors
-				n.log.Warn("Write error", "err", err)
+				n.log.Warnw("Write error", "err", err)
+				_ = n.BufferedConnection.Close()
+				return
 			}
 		case <-n.closing:
 			return
@@ -140,13 +140,15 @@ func (n *Neighbor) readLoop() {
 func (n *Neighbor) Write(b []byte) (int, error) {
 	l := len(b)
 	if l > maxPacketSize {
-		n.log.Errorw("message too large", "len", l, "max", maxPacketSize)
+		n.log.Panicw("message too large", "len", l, "max", maxPacketSize)
 	}
 
 	// add to queue
 	select {
 	case n.queue <- b:
 		return l, nil
+	case <-n.closing:
+		return 0, nil
 	default:
 		return 0, ErrNeighborQueueFull
 	}
diff --git a/packages/gossip/neighbor_test.go b/packages/gossip/neighbor_test.go
index 72a0f8959dc24cc842c2a7c2bff276c4a8ebedb0..fd1e0fc71a0f1a1c978c436946837175a37e4246 100644
--- a/packages/gossip/neighbor_test.go
+++ b/packages/gossip/neighbor_test.go
@@ -35,19 +35,6 @@ func TestNeighborCloseTwice(t *testing.T) {
 	require.NoError(t, n.Close())
 }
 
-func TestNeighborWriteToClosed(t *testing.T) {
-	a, _, teardown := newPipe()
-	defer teardown()
-
-	n := newTestNeighbor("A", a)
-	n.Listen()
-	require.NoError(t, n.Close())
-
-	assert.Panics(t, func() {
-		_, _ = n.Write(testData)
-	})
-}
-
 func TestNeighborWrite(t *testing.T) {
 	a, b, teardown := newPipe()
 	defer teardown()
diff --git a/packages/netutil/buffconn/buffconn.go b/packages/netutil/buffconn/buffconn.go
index 70f51d2feb22849e162034f904b4ee784c202c5d..c1ad9eaa28544f3091a1a3788798a4d2cdf6ae83 100644
--- a/packages/netutil/buffconn/buffconn.go
+++ b/packages/netutil/buffconn/buffconn.go
@@ -9,6 +9,7 @@ import (
 	"time"
 
 	"github.com/iotaledger/hive.go/events"
+	"go.uber.org/atomic"
 )
 
 const (
@@ -40,8 +41,8 @@ type BufferedConnection struct {
 	incomingHeaderBuffer []byte
 	closeOnce            sync.Once
 
-	BytesRead    int
-	BytesWritten int
+	bytesRead    *atomic.Uint32
+	bytesWritten *atomic.Uint32
 }
 
 // NewBufferedConnection creates a new BufferedConnection from a net.Conn.
@@ -53,6 +54,8 @@ func NewBufferedConnection(conn net.Conn) *BufferedConnection {
 		},
 		conn:                 conn,
 		incomingHeaderBuffer: make([]byte, headerSize),
+		bytesRead:            atomic.NewUint32(0),
+		bytesWritten:         atomic.NewUint32(0),
 	}
 }
 
@@ -77,6 +80,16 @@ func (c *BufferedConnection) RemoteAddr() net.Addr {
 	return c.conn.RemoteAddr()
 }
 
+// BytesRead returns the total number of bytes read.
+func (c *BufferedConnection) BytesRead() uint32 {
+	return c.bytesRead.Load()
+}
+
+// BytesWritten returns the total number of bytes written.
+func (c *BufferedConnection) BytesWritten() uint32 {
+	return c.bytesWritten.Load()
+}
+
 // Read starts reading on the connection, it only returns when an error occurred or when Close has been called.
 // If a complete message has been received and ReceiveMessage event is triggered with its complete payload.
 // If read leads to an error, the loop will be stopped and that error returned.
@@ -114,7 +127,7 @@ func (c *BufferedConnection) Write(msg []byte) (int, error) {
 	for bytesWritten := 0; bytesWritten < toWrite; {
 		n, err := c.conn.Write(buffer[bytesWritten:])
 		bytesWritten += n
-		c.BytesWritten += n
+		c.bytesWritten.Add(uint32(n))
 		if err != nil {
 			return bytesWritten, err
 		}
@@ -127,7 +140,7 @@ func (c *BufferedConnection) read(buffer []byte) (int, error) {
 	for bytesRead := 0; bytesRead < toRead; {
 		n, err := c.conn.Read(buffer[bytesRead:])
 		bytesRead += n
-		c.BytesRead += n
+		c.bytesRead.Add(uint32(n))
 		if err != nil {
 			return bytesRead, err
 		}
diff --git a/packages/shutdown/order.go b/packages/shutdown/order.go
index 06594b8c1f6075624cd8e18683f6b0619860fd21..b8347d1eaeac6069fbf3c9cc835d5b598987630e 100644
--- a/packages/shutdown/order.go
+++ b/packages/shutdown/order.go
@@ -2,6 +2,7 @@ package shutdown
 
 const (
 	ShutdownPriorityTangle = iota
+	ShutdownPriorityRemoteLog
 	ShutdownPrioritySolidifier
 	ShutdownPriorityBundleProcessor
 	ShutdownPriorityAnalysis
@@ -13,5 +14,4 @@ const (
 	ShutdownPriorityTangleSpammer
 	ShutdownPrioritySPA
 	ShutdownPriorityBadgerGarbageCollection
-	ShutdownPriorityStatusScreen
 )
diff --git a/plugins/analysis/webinterface/httpserver/data_stream.go b/plugins/analysis/webinterface/httpserver/data_stream.go
index a2d54db771cab43a5c012516942070bf1db3d29e..c096ffeb631cd9bd7b42808c3b7f9d943d80a217 100644
--- a/plugins/analysis/webinterface/httpserver/data_stream.go
+++ b/plugins/analysis/webinterface/httpserver/data_stream.go
@@ -1,7 +1,7 @@
 package httpserver
 
 import (
-	"fmt"
+	"sync"
 
 	"github.com/iotaledger/goshimmer/plugins/analysis/server"
 	"github.com/iotaledger/goshimmer/plugins/analysis/webinterface/recordedevents"
@@ -11,47 +11,87 @@ import (
 )
 
 func dataStream(ws *websocket.Conn) {
-	func() {
-		eventHandlers := &types.EventHandlers{
-			AddNode:         func(nodeId string) { fmt.Fprint(ws, "A"+nodeId) },
-			RemoveNode:      func(nodeId string) { fmt.Fprint(ws, "a"+nodeId) },
-			ConnectNodes:    func(sourceId string, targetId string) { fmt.Fprint(ws, "C"+sourceId+targetId) },
-			DisconnectNodes: func(sourceId string, targetId string) { fmt.Fprint(ws, "c"+sourceId+targetId) },
-			NodeOnline:      func(nodeId string) { fmt.Fprint(ws, "O"+nodeId) },
-			NodeOffline:     func(nodeId string) { fmt.Fprint(ws, "o"+nodeId) },
+	// create a wrapper for the websocket
+	wsChan := NewWebSocketChannel(ws)
+	defer wsChan.Close()
+
+	// variables and factory methods for the async calls after the initial replay
+	var replayMutex sync.RWMutex
+	createAsyncNodeCallback := func(wsChan *WebSocketChannel, messagePrefix string) func(string) {
+		return func(nodeId string) {
+			go func() {
+				replayMutex.RLock()
+				defer replayMutex.RUnlock()
+
+				wsChan.TryWrite(messagePrefix + nodeId)
+			}()
 		}
+	}
+	createAsyncLinkCallback := func(wsChan *WebSocketChannel, messagePrefix string) func(string, string) {
+		return func(sourceId string, targetId string) {
+			go func() {
+				replayMutex.RLock()
+				defer replayMutex.RUnlock()
 
-		addNodeClosure := events.NewClosure(eventHandlers.AddNode)
-		removeNodeClosure := events.NewClosure(eventHandlers.RemoveNode)
-		connectNodesClosure := events.NewClosure(eventHandlers.ConnectNodes)
-		disconnectNodesClosure := events.NewClosure(eventHandlers.DisconnectNodes)
-		nodeOnlineClosure := events.NewClosure(eventHandlers.NodeOnline)
-		nodeOfflineClosure := events.NewClosure(eventHandlers.NodeOffline)
-
-		server.Events.AddNode.Attach(addNodeClosure)
-		server.Events.RemoveNode.Attach(removeNodeClosure)
-		server.Events.ConnectNodes.Attach(connectNodesClosure)
-		server.Events.DisconnectNodes.Attach(disconnectNodesClosure)
-		server.Events.NodeOnline.Attach(nodeOnlineClosure)
-		server.Events.NodeOffline.Attach(nodeOfflineClosure)
-
-		go recordedevents.Replay(eventHandlers)
-
-		buf := make([]byte, 1)
-	readFromWebsocket:
-		for {
-			if _, err := ws.Read(buf); err != nil {
-				break readFromWebsocket
-			}
-
-			fmt.Fprint(ws, "_")
+				wsChan.TryWrite(messagePrefix + sourceId + targetId)
+			}()
 		}
+	}
+
+	// wait with firing the callbacks until the replay is complete
+	replayMutex.Lock()
+
+	// create and register the dynamic callbacks
+	addNodeClosure := events.NewClosure(createAsyncNodeCallback(wsChan, "A"))
+	removeNodeClosure := events.NewClosure(createAsyncNodeCallback(wsChan, "a"))
+	connectNodesClosure := events.NewClosure(createAsyncLinkCallback(wsChan, "C"))
+	disconnectNodesClosure := events.NewClosure(createAsyncLinkCallback(wsChan, "c"))
+	nodeOnlineClosure := events.NewClosure(createAsyncNodeCallback(wsChan, "O"))
+	nodeOfflineClosure := events.NewClosure(createAsyncNodeCallback(wsChan, "o"))
+	server.Events.AddNode.Attach(addNodeClosure)
+	server.Events.RemoveNode.Attach(removeNodeClosure)
+	server.Events.ConnectNodes.Attach(connectNodesClosure)
+	server.Events.DisconnectNodes.Attach(disconnectNodesClosure)
+	server.Events.NodeOnline.Attach(nodeOnlineClosure)
+	server.Events.NodeOffline.Attach(nodeOfflineClosure)
+
+	// replay old events
+	recordedevents.Replay(createEventHandlers(wsChan, createSyncNodeCallback, createSyncLinkCallback))
+
+	// mark replay as complete
+	replayMutex.Unlock()
+
+	// wait until the connection breaks and keep it alive
+	wsChan.KeepAlive()
+
+	// unregister the callbacks
+	server.Events.AddNode.Detach(addNodeClosure)
+	server.Events.RemoveNode.Detach(removeNodeClosure)
+	server.Events.ConnectNodes.Detach(connectNodesClosure)
+	server.Events.DisconnectNodes.Detach(disconnectNodesClosure)
+	server.Events.NodeOnline.Detach(nodeOnlineClosure)
+	server.Events.NodeOffline.Detach(nodeOfflineClosure)
+}
+
+func createEventHandlers(wsChan *WebSocketChannel, nodeCallbackFactory func(*WebSocketChannel, string) func(string), linkCallbackFactory func(*WebSocketChannel, string) func(string, string)) *types.EventHandlers {
+	return &types.EventHandlers{
+		AddNode:         nodeCallbackFactory(wsChan, "A"),
+		RemoveNode:      nodeCallbackFactory(wsChan, "a"),
+		ConnectNodes:    linkCallbackFactory(wsChan, "C"),
+		DisconnectNodes: linkCallbackFactory(wsChan, "c"),
+		NodeOnline:      nodeCallbackFactory(wsChan, "O"),
+		NodeOffline:     nodeCallbackFactory(wsChan, "o"),
+	}
+}
+
+func createSyncNodeCallback(wsChan *WebSocketChannel, messagePrefix string) func(nodeId string) {
+	return func(nodeId string) {
+		wsChan.Write(messagePrefix + nodeId)
+	}
+}
 
-		server.Events.AddNode.Detach(addNodeClosure)
-		server.Events.RemoveNode.Detach(removeNodeClosure)
-		server.Events.ConnectNodes.Detach(connectNodesClosure)
-		server.Events.DisconnectNodes.Detach(disconnectNodesClosure)
-		server.Events.NodeOnline.Detach(nodeOnlineClosure)
-		server.Events.NodeOffline.Detach(nodeOfflineClosure)
-	}()
+func createSyncLinkCallback(wsChan *WebSocketChannel, messagePrefix string) func(sourceId string, targetId string) {
+	return func(sourceId string, targetId string) {
+		wsChan.Write(messagePrefix + sourceId + targetId)
+	}
 }
diff --git a/plugins/analysis/webinterface/httpserver/websocket_channel.go b/plugins/analysis/webinterface/httpserver/websocket_channel.go
new file mode 100644
index 0000000000000000000000000000000000000000..0b75fefe284f958ddbdf54be568035b5a1483ac2
--- /dev/null
+++ b/plugins/analysis/webinterface/httpserver/websocket_channel.go
@@ -0,0 +1,58 @@
+package httpserver
+
+import (
+	"fmt"
+
+	"golang.org/x/net/websocket"
+)
+
+type WebSocketChannel struct {
+	ws   *websocket.Conn
+	send chan string
+}
+
+func NewWebSocketChannel(ws *websocket.Conn) *WebSocketChannel {
+	wsChan := &WebSocketChannel{
+		ws:   ws,
+		send: make(chan string, 1024),
+	}
+
+	go wsChan.writer()
+
+	return wsChan
+}
+
+func (c *WebSocketChannel) Write(update string) {
+	c.send <- update
+}
+
+func (c *WebSocketChannel) TryWrite(update string) {
+	select {
+	case c.send <- update:
+	default:
+	}
+}
+
+func (c *WebSocketChannel) KeepAlive() {
+	buf := make([]byte, 1)
+	for {
+		if _, err := c.ws.Read(buf); err != nil {
+			break
+		}
+
+		_, _ = fmt.Fprint(c.ws, "_")
+	}
+}
+
+func (c *WebSocketChannel) Close() {
+	close(c.send)
+	_ = c.ws.Close()
+}
+
+func (c *WebSocketChannel) writer() {
+	for pkt := range c.send {
+		if _, err := fmt.Fprint(c.ws, pkt); err != nil {
+			break
+		}
+	}
+}
diff --git a/plugins/analysis/webinterface/recordedevents/recorded_events.go b/plugins/analysis/webinterface/recordedevents/recorded_events.go
index 31dba5c72fe285221e16302f30274ff9d090ab74..2e2a9a724b3524f9ce017e6a0fa5e49e40d899ae 100644
--- a/plugins/analysis/webinterface/recordedevents/recorded_events.go
+++ b/plugins/analysis/webinterface/recordedevents/recorded_events.go
@@ -31,7 +31,6 @@ func Configure(plugin *node.Plugin) {
 		defer lock.Unlock()
 
 		delete(nodes, nodeId)
-		//nodes[nodeId] = false
 	}))
 
 	server.Events.NodeOnline.Attach(events.NewClosure(func(nodeId string) {
@@ -76,11 +75,30 @@ func Configure(plugin *node.Plugin) {
 	}))
 }
 
-func Replay(handlers *types.EventHandlers) {
+func getEventsToReplay() (map[string]bool, map[string]map[string]bool) {
 	lock.Lock()
 	defer lock.Unlock()
 
+	copiedNodes := make(map[string]bool)
 	for nodeId, online := range nodes {
+		copiedNodes[nodeId] = online
+	}
+
+	copiedLinks := make(map[string]map[string]bool)
+	for sourceId, targetMap := range links {
+		copiedLinks[sourceId] = make(map[string]bool)
+		for targetId := range targetMap {
+			copiedLinks[sourceId][targetId] = true
+		}
+	}
+
+	return copiedNodes, copiedLinks
+}
+
+func Replay(handlers *types.EventHandlers) {
+	copiedNodes, copiedLinks := getEventsToReplay()
+
+	for nodeId, online := range copiedNodes {
 		handlers.AddNode(nodeId)
 		if online {
 			handlers.NodeOnline(nodeId)
@@ -89,7 +107,7 @@ func Replay(handlers *types.EventHandlers) {
 		}
 	}
 
-	for sourceId, targetMap := range links {
+	for sourceId, targetMap := range copiedLinks {
 		for targetId := range targetMap {
 			handlers.ConnectNodes(sourceId, targetId)
 		}
diff --git a/plugins/autopeering/plugin.go b/plugins/autopeering/plugin.go
index 4688b6b0d72cde21dbcbdc19947bc4cfef6ec1e8..cad1ba419ede64d1fdd73b3d5bdf33625f1e657f 100644
--- a/plugins/autopeering/plugin.go
+++ b/plugins/autopeering/plugin.go
@@ -33,7 +33,7 @@ func run(*node.Plugin) {
 
 func configureEvents() {
 	// notify the selection when a connection is closed or failed.
-	gossip.Events.ConnectionFailed.Attach(events.NewClosure(func(p *peer.Peer) {
+	gossip.Events.ConnectionFailed.Attach(events.NewClosure(func(p *peer.Peer, _ error) {
 		Selection.RemoveNeighbor(p.ID())
 	}))
 	gossip.Events.NeighborRemoved.Attach(events.NewClosure(func(p *peer.Peer) {
diff --git a/plugins/cli/plugin.go b/plugins/cli/plugin.go
index 0b1937b55e97dd17d752d925f27387844708b35a..8fbaeab0e65f804969aa69fc89ef4321ff7d47ac 100644
--- a/plugins/cli/plugin.go
+++ b/plugins/cli/plugin.go
@@ -12,7 +12,7 @@ import (
 
 const (
 	// AppVersion version number
-	AppVersion = "v0.1.0"
+	AppVersion = "v0.1.1"
 	// AppName app code name
 	AppName = "GoShimmer"
 )
diff --git a/plugins/gossip/plugin.go b/plugins/gossip/plugin.go
index f6f5717ed0875c20017c13471e2677743126db22..20e804a15391f6a9245952d63f6e425d36980068 100644
--- a/plugins/gossip/plugin.go
+++ b/plugins/gossip/plugin.go
@@ -59,8 +59,8 @@ func configureEvents() {
 		}()
 	}))
 
-	gossip.Events.ConnectionFailed.Attach(events.NewClosure(func(p *peer.Peer) {
-		log.Infof("Connection to neighbor failed: %s / %s", gossip.GetAddress(p), p.ID())
+	gossip.Events.ConnectionFailed.Attach(events.NewClosure(func(p *peer.Peer, err error) {
+		log.Infof("Connection to neighbor %s / %s failed: %s", gossip.GetAddress(p), p.ID(), err)
 	}))
 	gossip.Events.NeighborAdded.Attach(events.NewClosure(func(n *gossip.Neighbor) {
 		log.Infof("Neighbor added: %s / %s", gossip.GetAddress(n.Peer), n.ID())
diff --git a/plugins/remotelog/plugin.go b/plugins/remotelog/plugin.go
new file mode 100644
index 0000000000000000000000000000000000000000..0ca02c50ccab9b757253fa5613be8c390bef8f62
--- /dev/null
+++ b/plugins/remotelog/plugin.go
@@ -0,0 +1,93 @@
+// remotelog is a plugin that enables log messages being sent via UDP to a central ELK stack for debugging.
+// It is disabled by default and when enabled, additionally, logger.disableEvents=false in config.json needs to be set.
+// The destination can be set via logger.remotelog.serverAddress.
+// All events according to logger.level in config.json are sent.
+package remotelog
+
+import (
+	"encoding/hex"
+	"encoding/json"
+	"fmt"
+	"net"
+	"runtime"
+	"time"
+
+	"github.com/iotaledger/goshimmer/packages/parameter"
+	"github.com/iotaledger/goshimmer/packages/shutdown"
+	"github.com/iotaledger/goshimmer/plugins/autopeering/local"
+	"github.com/iotaledger/hive.go/daemon"
+	"github.com/iotaledger/hive.go/events"
+	"github.com/iotaledger/hive.go/logger"
+	"github.com/iotaledger/hive.go/node"
+	"github.com/iotaledger/hive.go/workerpool"
+)
+
+type logMessage struct {
+	NodeId    string    `json:"nodeId"`
+	Level     string    `json:"level"`
+	Name      string    `json:"name"`
+	Msg       string    `json:"msg"`
+	Timestamp time.Time `json:"timestamp"`
+}
+
+const (
+	CFG_SERVER_ADDRESS = "logger.remotelog.serverAddress"
+	CFG_DISABLE_EVENTS = "logger.disableEvents"
+	PLUGIN_NAME        = "RemoteLog"
+)
+
+var (
+	PLUGIN     = node.NewPlugin(PLUGIN_NAME, node.Disabled, configure, run)
+	log        *logger.Logger
+	conn       net.Conn
+	myID       string
+	workerPool *workerpool.WorkerPool
+)
+
+func configure(plugin *node.Plugin) {
+	log = logger.NewLogger(PLUGIN_NAME)
+
+	if parameter.NodeConfig.GetBool(CFG_DISABLE_EVENTS) {
+		log.Fatalf("%s in config.json needs to be false so that events can be captured!", CFG_DISABLE_EVENTS)
+		return
+	}
+
+	c, err := net.Dial("udp", parameter.NodeConfig.GetString(CFG_SERVER_ADDRESS))
+	if err != nil {
+		log.Fatalf("Could not create UDP socket to '%s'. %v", parameter.NodeConfig.GetString(CFG_SERVER_ADDRESS), err)
+		return
+	}
+	conn = c
+
+	if local.GetInstance() != nil {
+		myID = hex.EncodeToString(local.GetInstance().ID().Bytes())
+	}
+
+	workerPool = workerpool.New(func(task workerpool.Task) {
+		sendLogMsg(task.Param(0).(logger.Level), task.Param(1).(string), task.Param(2).(string))
+
+		task.Return(nil)
+	}, workerpool.WorkerCount(runtime.NumCPU()), workerpool.QueueSize(1000))
+}
+
+func run(plugin *node.Plugin) {
+	logEvent := events.NewClosure(func(level logger.Level, name string, msg string) {
+		workerPool.TrySubmit(level, name, msg)
+	})
+
+	daemon.BackgroundWorker(PLUGIN_NAME, func(shutdownSignal <-chan struct{}) {
+		logger.Events.AnyMsg.Attach(logEvent)
+		workerPool.Start()
+		<-shutdownSignal
+		log.Infof("Stopping %s ...", PLUGIN_NAME)
+		logger.Events.AnyMsg.Detach(logEvent)
+		workerPool.Stop()
+		log.Infof("Stopping %s ... done", PLUGIN_NAME)
+	}, shutdown.ShutdownPriorityRemoteLog)
+}
+
+func sendLogMsg(level logger.Level, name string, msg string) {
+	m := logMessage{myID, level.CapitalString(), name, msg, time.Now()}
+	b, _ := json.Marshal(m)
+	fmt.Fprint(conn, string(b))
+}
diff --git a/plugins/remotelog/server/.env b/plugins/remotelog/server/.env
new file mode 100644
index 0000000000000000000000000000000000000000..68aaea9a63f638a31870bb929bbc323409a12ebc
--- /dev/null
+++ b/plugins/remotelog/server/.env
@@ -0,0 +1 @@
+ELK_VERSION=7.5.2
\ No newline at end of file
diff --git a/plugins/remotelog/server/config/elasticsearch.yml b/plugins/remotelog/server/config/elasticsearch.yml
new file mode 100644
index 0000000000000000000000000000000000000000..1d27fb929c34cb4a28792adbcc440ae82a8075dc
--- /dev/null
+++ b/plugins/remotelog/server/config/elasticsearch.yml
@@ -0,0 +1,5 @@
+## Default Elasticsearch configuration from Elasticsearch base image.
+## https://github.com/elastic/elasticsearch/blob/master/distribution/docker/src/docker/config/elasticsearch.yml
+#
+cluster.name: "docker-cluster"
+network.host: 0.0.0.0
\ No newline at end of file
diff --git a/plugins/remotelog/server/config/kibana.yml b/plugins/remotelog/server/config/kibana.yml
new file mode 100644
index 0000000000000000000000000000000000000000..6d7ef28ad531e7715d8662ec1e9833f5c3fc00da
--- /dev/null
+++ b/plugins/remotelog/server/config/kibana.yml
@@ -0,0 +1,6 @@
+## Default Kibana configuration from Kibana base image.
+## https://github.com/elastic/kibana/blob/master/src/dev/build/tasks/os_packages/docker_generator/templates/kibana_yml.template.js
+#
+server.name: kibana
+server.host: "0"
+elasticsearch.hosts: [ "http://elasticsearch:9200" ]
\ No newline at end of file
diff --git a/plugins/remotelog/server/config/logstash/logstash.yml b/plugins/remotelog/server/config/logstash/logstash.yml
new file mode 100644
index 0000000000000000000000000000000000000000..705bcc94b9e8636a71819557c736e5fb605116e8
--- /dev/null
+++ b/plugins/remotelog/server/config/logstash/logstash.yml
@@ -0,0 +1,4 @@
+## Default Logstash configuration from Logstash base image.
+## https://github.com/elastic/logstash/blob/master/docker/data/logstash/config/logstash-full.yml
+#
+http.host: "0.0.0.0"
\ No newline at end of file
diff --git a/plugins/remotelog/server/config/logstash/pipeline/logstash.conf b/plugins/remotelog/server/config/logstash/pipeline/logstash.conf
new file mode 100644
index 0000000000000000000000000000000000000000..fcc2ccbc0a770d42433a8323a5664fa956f20c8c
--- /dev/null
+++ b/plugins/remotelog/server/config/logstash/pipeline/logstash.conf
@@ -0,0 +1,26 @@
+input {
+	udp {
+        port => 5213
+    }
+}
+
+filter {
+    mutate {
+        split => ["host", "."]
+        add_field => { "shortHostname" => "%{[host][0]}.%{[host][1]}.%{[host][2]}.x" }
+    }
+    mutate {
+        rename => ["shortHostname", "host" ]
+    }
+
+    json {
+        source => "message"
+        target => "log"
+    }
+}
+
+output {
+	elasticsearch {
+		hosts => "elasticsearch:9200"
+	}
+}
\ No newline at end of file
diff --git a/plugins/remotelog/server/docker-compose.yml b/plugins/remotelog/server/docker-compose.yml
new file mode 100644
index 0000000000000000000000000000000000000000..f3c9db883299d439e868473df33a74c6f735357b
--- /dev/null
+++ b/plugins/remotelog/server/docker-compose.yml
@@ -0,0 +1,64 @@
+version: '3.7'
+
+services:
+  elasticsearch:
+    container_name: elasticsearch
+    image: docker.elastic.co/elasticsearch/elasticsearch:${ELK_VERSION}
+    volumes:
+      - type: bind
+        source: ./config/elasticsearch.yml
+        target: /usr/share/elasticsearch/config/elasticsearch.yml
+        read_only: true
+      - type: volume
+        source: elasticsearch
+        target: /usr/share/elasticsearch/data
+    environment:
+      ES_JAVA_OPTS: "-Xmx256m -Xms256m"
+      # Use single node discovery in order to disable production mode and avoid bootstrap checks
+      # see https://www.elastic.co/guide/en/elasticsearch/reference/current/bootstrap-checks.html
+      discovery.type: single-node
+    networks:
+      - elk
+
+  logstash:
+    container_name: logstash
+    image: docker.elastic.co/logstash/logstash:${ELK_VERSION}
+    volumes:
+      - type: bind
+        source: ./config/logstash/logstash.yml
+        target: /usr/share/logstash/config/logstash.yml
+        read_only: true
+      - type: bind
+        source: ./config/logstash/pipeline
+        target: /usr/share/logstash/pipeline
+        read_only: true
+    ports:
+      - "5213:5213/udp"
+    environment:
+      LS_JAVA_OPTS: "-Xmx256m -Xms256m"
+    networks:
+      - elk
+    depends_on:
+      - elasticsearch
+
+  kibana:
+    container_name: kibana
+    image: docker.elastic.co/kibana/kibana:${ELK_VERSION}
+    volumes:
+      - type: bind
+        source: ./config/kibana.yml
+        target: /usr/share/kibana/config/kibana.yml
+        read_only: true
+    ports:
+      - "5601:5601"
+    networks:
+      - elk
+    depends_on:
+      - elasticsearch
+
+networks:
+  elk:
+    driver: bridge
+
+volumes:
+  elasticsearch:
\ No newline at end of file
diff --git a/plugins/spa/plugin.go b/plugins/spa/plugin.go
index fd3215d8de6a81ef237b7ece696856f50028e1c9..829d3609a9bee5d4dac0b822494697fdb5170561 100644
--- a/plugins/spa/plugin.go
+++ b/plugins/spa/plugin.go
@@ -161,8 +161,8 @@ type neighbormetric struct {
 	ID               string `json:"id"`
 	Address          string `json:"address"`
 	ConnectionOrigin string `json:"connection_origin"`
-	BytesRead        int    `json:"bytes_read"`
-	BytesWritten     int    `json:"bytes_written"`
+	BytesRead        uint32 `json:"bytes_read"`
+	BytesWritten     uint32 `json:"bytes_written"`
 }
 
 func neighborMetrics() []neighbormetric {
@@ -186,8 +186,8 @@ func neighborMetrics() []neighbormetric {
 		stats = append(stats, neighbormetric{
 			ID:               neighbor.Peer.ID().String(),
 			Address:          neighbor.Peer.Services().Get(service.GossipKey).String(),
-			BytesRead:        neighbor.BytesRead,
-			BytesWritten:     neighbor.BytesWritten,
+			BytesRead:        neighbor.BytesRead(),
+			BytesWritten:     neighbor.BytesWritten(),
 			ConnectionOrigin: origin,
 		})
 	}
diff --git a/plugins/statusscreen-tps/plugin.go b/plugins/statusscreen-tps/plugin.go
deleted file mode 100644
index dbe6b89276081d1cd08a669eb014d16488f97834..0000000000000000000000000000000000000000
--- a/plugins/statusscreen-tps/plugin.go
+++ /dev/null
@@ -1,56 +0,0 @@
-package statusscreen_tps
-
-import (
-	"strconv"
-	"sync/atomic"
-	"time"
-
-	"github.com/iotaledger/goshimmer/packages/gossip"
-	"github.com/iotaledger/goshimmer/packages/model/value_transaction"
-	"github.com/iotaledger/goshimmer/packages/shutdown"
-	"github.com/iotaledger/goshimmer/plugins/statusscreen"
-	"github.com/iotaledger/goshimmer/plugins/tangle"
-	"github.com/iotaledger/hive.go/daemon"
-	"github.com/iotaledger/hive.go/events"
-	"github.com/iotaledger/hive.go/node"
-)
-
-var receivedTpsCounter uint64
-
-var solidTpsCounter uint64
-
-var receivedTps uint64
-
-var solidTps uint64
-
-var PLUGIN = node.NewPlugin("Statusscreen TPS", node.Enabled, func(plugin *node.Plugin) {
-	gossip.Events.TransactionReceived.Attach(events.NewClosure(func(_ *gossip.TransactionReceivedEvent) {
-		atomic.AddUint64(&receivedTpsCounter, 1)
-	}))
-
-	tangle.Events.TransactionSolid.Attach(events.NewClosure(func(_ *value_transaction.ValueTransaction) {
-		atomic.AddUint64(&solidTpsCounter, 1)
-	}))
-
-	statusscreen.AddHeaderInfo(func() (s string, s2 string) {
-		return "TPS", strconv.FormatUint(atomic.LoadUint64(&receivedTps), 10) + " received / " + strconv.FormatUint(atomic.LoadUint64(&solidTps), 10) + " new"
-	})
-}, func(plugin *node.Plugin) {
-	daemon.BackgroundWorker("Statusscreen TPS Tracker", func(shutdownSignal <-chan struct{}) {
-		ticker := time.NewTicker(time.Second)
-
-		for {
-			select {
-			case <-shutdownSignal:
-				return
-
-			case <-ticker.C:
-				atomic.StoreUint64(&receivedTps, atomic.LoadUint64(&receivedTpsCounter))
-				atomic.StoreUint64(&solidTps, atomic.LoadUint64(&solidTpsCounter))
-
-				atomic.StoreUint64(&receivedTpsCounter, 0)
-				atomic.StoreUint64(&solidTpsCounter, 0)
-			}
-		}
-	}, shutdown.ShutdownPriorityStatusScreen)
-})
diff --git a/plugins/statusscreen/logger.go b/plugins/statusscreen/logger.go
deleted file mode 100644
index 10606990e2659ceb4a58f0267119bb457ed32856..0000000000000000000000000000000000000000
--- a/plugins/statusscreen/logger.go
+++ /dev/null
@@ -1,55 +0,0 @@
-package statusscreen
-
-import (
-	stdlog "log"
-	"sync"
-	"time"
-
-	"github.com/iotaledger/hive.go/logger"
-)
-
-var (
-	mu                sync.Mutex
-	logMessages       = make([]*logMessage, 0)
-	logMessagesByName = make(map[string]*logMessage)
-)
-
-type logMessage struct {
-	time  time.Time
-	name  string
-	level logger.Level
-	msg   string
-}
-
-func stdLogMsg(level logger.Level, name string, msg string) {
-	stdlog.Printf("[ %s ] %s: %s",
-		level.CapitalString(),
-		name,
-		msg,
-	)
-}
-
-func storeLogMsg(level logger.Level, name string, message string) {
-	mu.Lock()
-	defer mu.Unlock()
-
-	logMessages = append(logMessages, &logMessage{
-		time:  time.Now(),
-		name:  name,
-		level: level,
-		msg:   message,
-	})
-
-	if statusMessage, exists := logMessagesByName[name]; !exists {
-		logMessagesByName[name] = &logMessage{
-			time:  time.Now(),
-			name:  name,
-			level: level,
-			msg:   message,
-		}
-	} else {
-		statusMessage.time = time.Now()
-		statusMessage.level = level
-		statusMessage.msg = message
-	}
-}
diff --git a/plugins/statusscreen/plugin.go b/plugins/statusscreen/plugin.go
deleted file mode 100644
index e117234f75f1f2c0c1e5f63171cd49f73755b3a9..0000000000000000000000000000000000000000
--- a/plugins/statusscreen/plugin.go
+++ /dev/null
@@ -1,80 +0,0 @@
-package statusscreen
-
-import (
-	"time"
-
-	"github.com/iotaledger/goshimmer/packages/shutdown"
-	"github.com/iotaledger/hive.go/daemon"
-	"github.com/iotaledger/hive.go/events"
-	"github.com/iotaledger/hive.go/logger"
-	"github.com/iotaledger/hive.go/node"
-)
-
-const (
-	name            = "Statusscreen"
-	repaintInterval = 1 * time.Second
-)
-
-var PLUGIN = node.NewPlugin(name, node.Enabled, configure, run)
-
-var (
-	stdLogMsgClosure   = events.NewClosure(stdLogMsg)
-	storeLogMsgClosure = events.NewClosure(storeLogMsg)
-)
-
-func init() {
-	// use standard go logger by default
-	logger.Events.AnyMsg.Attach(stdLogMsgClosure)
-}
-
-func configure(*node.Plugin) {
-	if !isTerminal() {
-		return
-	}
-
-	// store any log message for display
-	logger.Events.AnyMsg.Attach(storeLogMsgClosure)
-
-	log = logger.NewLogger(name)
-	configureTview()
-}
-
-func run(*node.Plugin) {
-	if !isTerminal() {
-		return
-	}
-
-	stopped := make(chan struct{})
-	if err := daemon.BackgroundWorker(name+" Refresher", func(shutdown <-chan struct{}) {
-		for {
-			select {
-			case <-time.After(repaintInterval):
-				app.QueueUpdateDraw(func() {})
-			case <-shutdown:
-				logger.Events.AnyMsg.Detach(storeLogMsgClosure)
-				app.Stop()
-				return
-			case <-stopped:
-				return
-			}
-		}
-	}, shutdown.ShutdownPriorityStatusScreen); err != nil {
-		log.Errorf("Failed to start as daemon: %s", err)
-		return
-	}
-
-	if err := daemon.BackgroundWorker(name+" App", func(<-chan struct{}) {
-		defer close(stopped)
-
-		// switch logging to status screen
-		logger.Events.AnyMsg.Detach(stdLogMsgClosure)
-		defer logger.Events.AnyMsg.Attach(stdLogMsgClosure)
-
-		if err := app.SetRoot(frame, true).SetFocus(frame).Run(); err != nil {
-			log.Errorf("Error running application: %s", err)
-		}
-	}, shutdown.ShutdownPriorityStatusScreen); err != nil {
-		log.Errorf("Failed to start as daemon: %s", err)
-		close(stopped)
-	}
-}
diff --git a/plugins/statusscreen/statusscreen.go b/plugins/statusscreen/statusscreen.go
deleted file mode 100644
index 40acb01ba3fa40ea593118d47f0e6165210fcf9a..0000000000000000000000000000000000000000
--- a/plugins/statusscreen/statusscreen.go
+++ /dev/null
@@ -1,101 +0,0 @@
-package statusscreen
-
-import (
-	"os"
-
-	"github.com/gdamore/tcell"
-	"github.com/iotaledger/hive.go/daemon"
-	"github.com/iotaledger/hive.go/logger"
-	"github.com/rivo/tview"
-	"golang.org/x/crypto/ssh/terminal"
-)
-
-var (
-	log   *logger.Logger
-	app   *tview.Application
-	frame *tview.Frame
-)
-
-func configureTview() {
-	headerBar := NewUIHeaderBar()
-
-	content := tview.NewGrid()
-	content.SetBackgroundColor(tcell.ColorWhite)
-	content.SetColumns(0)
-	content.SetBorders(false)
-	content.SetOffset(0, 0)
-	content.SetGap(0, 0)
-
-	footer := newPrimitive("")
-	footer.SetBackgroundColor(tcell.ColorDarkMagenta)
-	footer.SetTextColor(tcell.ColorWhite)
-
-	grid := tview.NewGrid().
-		SetRows(10, 0, 1).
-		SetColumns(0).
-		SetBorders(false).
-		AddItem(headerBar.Primitive, 0, 0, 1, 1, 0, 0, false).
-		AddItem(content, 1, 0, 1, 1, 0, 0, false).
-		AddItem(footer, 2, 0, 1, 1, 0, 0, false)
-
-	frame = tview.NewFrame(grid).
-		SetBorders(1, 1, 0, 0, 2, 2)
-	frame.SetBackgroundColor(tcell.ColorDarkGray)
-
-	app = tview.NewApplication()
-	app.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
-		// end the daemon on ctrl+c
-		if event.Key() == tcell.KeyCtrlC || event.Key() == tcell.KeyESC {
-			daemon.Shutdown()
-			return nil
-		}
-		return event
-	})
-
-	app.SetBeforeDrawFunc(func(screen tcell.Screen) bool {
-		headerBar.Update()
-
-		rows := make([]int, 2)
-		rows[0] = 1
-		rows[1] = 1
-		_, _, _, height := content.GetRect()
-		for i := 0; i < len(logMessages) && i < height-2; i++ {
-			rows = append(rows, 1)
-		}
-
-		content.Clear()
-		content.SetRows(rows...)
-
-		blankLine := newPrimitive("")
-		blankLine.SetBackgroundColor(tcell.ColorWhite)
-		content.AddItem(blankLine, 0, 0, 1, 1, 0, 0, false)
-
-		logStart := len(logMessages) - (len(rows) - 2)
-		if logStart < 0 {
-			logStart = 0
-		}
-
-		for i, message := range logMessages[logStart:] {
-			if i < height-2 {
-				content.AddItem(NewUILogEntry(*message).Primitive, i+1, 0, 1, 1, 0, 0, false)
-			}
-		}
-
-		blankLine = newPrimitive("")
-		blankLine.SetBackgroundColor(tcell.ColorWhite)
-		content.AddItem(blankLine, height-1, 0, 1, 1, 0, 0, false)
-
-		return false
-	})
-}
-
-func newPrimitive(text string) *tview.TextView {
-	textView := tview.NewTextView()
-	textView.SetTextAlign(tview.AlignLeft).SetText(" " + text)
-
-	return textView
-}
-
-func isTerminal() bool {
-	return terminal.IsTerminal(int(os.Stdin.Fd()))
-}
diff --git a/plugins/statusscreen/ui_header_bar.go b/plugins/statusscreen/ui_header_bar.go
deleted file mode 100644
index 32762a86749a2a109a7e8cfe430888c4829cb227..0000000000000000000000000000000000000000
--- a/plugins/statusscreen/ui_header_bar.go
+++ /dev/null
@@ -1,151 +0,0 @@
-package statusscreen
-
-import (
-	"fmt"
-	"math"
-	"strconv"
-	"time"
-
-	"github.com/gdamore/tcell"
-	"github.com/iotaledger/goshimmer/plugins/autopeering"
-	"github.com/iotaledger/goshimmer/plugins/autopeering/local"
-	"github.com/iotaledger/goshimmer/plugins/cli"
-	"github.com/rivo/tview"
-)
-
-var start = time.Now()
-
-var headerInfos = make([]func() (string, string), 0)
-
-func AddHeaderInfo(generator func() (string, string)) {
-	headerInfos = append(headerInfos, generator)
-}
-
-type UIHeaderBar struct {
-	Primitive     *tview.Grid
-	LogoContainer *tview.TextView
-	InfoContainer *tview.TextView
-}
-
-func NewUIHeaderBar() *UIHeaderBar {
-	headerBar := &UIHeaderBar{
-		Primitive:     tview.NewGrid(),
-		LogoContainer: tview.NewTextView(),
-		InfoContainer: tview.NewTextView(),
-	}
-
-	headerBar.LogoContainer.
-		SetTextAlign(tview.AlignLeft).
-		SetTextColor(tcell.ColorWhite).
-		SetDynamicColors(true).
-		SetBackgroundColor(tcell.ColorDarkMagenta)
-
-	headerBar.InfoContainer.
-		SetTextAlign(tview.AlignRight).
-		SetTextColor(tcell.ColorWhite).
-		SetDynamicColors(true).
-		SetBackgroundColor(tcell.ColorDarkMagenta)
-
-	headerBar.Primitive.
-		SetColumns(20, 0).
-		SetRows(0).
-		SetBorders(false).
-		AddItem(headerBar.LogoContainer, 0, 0, 1, 1, 0, 0, false).
-		AddItem(headerBar.InfoContainer, 0, 1, 1, 1, 0, 0, false)
-
-	headerBar.printLogo()
-	headerBar.Update()
-
-	return headerBar
-}
-
-func (headerBar *UIHeaderBar) Update() {
-	duration := time.Since(start)
-
-	headerBar.InfoContainer.Clear()
-
-	fmt.Fprintln(headerBar.InfoContainer)
-	fmt.Fprintln(headerBar.InfoContainer, "[::d]COO-LESS IOTA PROTOTYPE  -  [::b]Status: [green::b]SYNCED  ")
-	for i := 0; i < 3-len(headerInfos); i++ {
-		fmt.Fprintln(headerBar.InfoContainer)
-	}
-
-	for _, infoGenerator := range headerInfos {
-		fieldName, fieldValue := infoGenerator()
-		fmt.Fprintf(headerBar.InfoContainer, "[::b]%v: [::d]%40v  ", fieldName, fieldValue)
-		fmt.Fprintln(headerBar.InfoContainer)
-	}
-
-	outgoing := "0"
-	incoming := "0"
-	neighbors := "0"
-	total := "0"
-	myID := "-"
-	if autopeering.Selection != nil {
-		outgoing = strconv.Itoa(len(autopeering.Selection.GetOutgoingNeighbors()))
-		incoming = strconv.Itoa(len(autopeering.Selection.GetIncomingNeighbors()))
-		neighbors = strconv.Itoa(len(autopeering.Selection.GetNeighbors()))
-	}
-	if autopeering.Discovery != nil {
-		total = strconv.Itoa(len(autopeering.Discovery.GetVerifiedPeers()))
-	}
-	if local.GetInstance() != nil {
-		myID = local.GetInstance().ID().String()
-	}
-
-	fmt.Fprintf(headerBar.InfoContainer, "[::b]Node ID: [::d]%40v  ", myID)
-	fmt.Fprintln(headerBar.InfoContainer)
-	fmt.Fprintf(headerBar.InfoContainer, "[::b]Neighbors: [::d]%40v  ", outgoing+" chosen / "+incoming+" accepted / "+neighbors+" total")
-	fmt.Fprintln(headerBar.InfoContainer)
-	fmt.Fprintf(headerBar.InfoContainer, "[::b]Known Peers: [::d]%40v  ", total+" total")
-	fmt.Fprintln(headerBar.InfoContainer)
-	fmt.Fprintf(headerBar.InfoContainer, "[::b]Uptime: [::d]")
-
-	padded := false
-	if int(duration.Seconds())/(60*60*24) > 0 {
-		days := int(duration.Hours()) / 24
-
-		numberLength := int(math.Log10(float64(days))) + 1
-		padLength := 31 - numberLength
-
-		fmt.Fprintf(headerBar.InfoContainer, "%*v", padLength, "")
-
-		padded = true
-
-		// d
-		fmt.Fprintf(headerBar.InfoContainer, "%02dd ", days)
-	}
-
-	if int(duration.Seconds())/(60*60) > 0 {
-		if !padded {
-			fmt.Fprintf(headerBar.InfoContainer, "%29v", "")
-			padded = true
-		}
-		fmt.Fprintf(headerBar.InfoContainer, "%02dh ", int(duration.Hours())%24)
-	}
-
-	if int(duration.Seconds())/60 > 0 {
-		if !padded {
-			fmt.Fprintf(headerBar.InfoContainer, "%33v", "")
-			padded = true
-		}
-		fmt.Fprintf(headerBar.InfoContainer, "%02dm ", int(duration.Minutes())%60)
-	}
-
-	if !padded {
-		fmt.Fprintf(headerBar.InfoContainer, "%37v", "")
-	}
-	fmt.Fprintf(headerBar.InfoContainer, "%02ds  ", int(duration.Seconds())%60)
-}
-
-func (headerBar *UIHeaderBar) printLogo() {
-	fmt.Fprintln(headerBar.LogoContainer, "")
-	fmt.Fprintln(headerBar.LogoContainer, "  GOSHIMMER", cli.AppVersion)
-	fmt.Fprintln(headerBar.LogoContainer, "  ┌──────┬──────┐")
-	fmt.Fprintln(headerBar.LogoContainer, "    ───┐ │ ┌───")
-	fmt.Fprintln(headerBar.LogoContainer, "     ┐ │ │ │ ┌")
-	fmt.Fprintln(headerBar.LogoContainer, "     │ └ │ ┘ │")
-	fmt.Fprintln(headerBar.LogoContainer, "     └ ┌ │ ┐ ┘")
-	fmt.Fprintln(headerBar.LogoContainer, "       │ │ │")
-	fmt.Fprintln(headerBar.LogoContainer, "         â”´")
-}
diff --git a/plugins/statusscreen/ui_log_entry.go b/plugins/statusscreen/ui_log_entry.go
deleted file mode 100644
index 57cbc6e7ebefa986056c8df36a3f1cb5003793f6..0000000000000000000000000000000000000000
--- a/plugins/statusscreen/ui_log_entry.go
+++ /dev/null
@@ -1,76 +0,0 @@
-package statusscreen
-
-import (
-	"fmt"
-
-	"github.com/gdamore/tcell"
-	"github.com/iotaledger/hive.go/logger"
-	"github.com/rivo/tview"
-)
-
-type UILogEntry struct {
-	Primitive         *tview.Grid
-	TimeContainer     *tview.TextView
-	MessageContainer  *tview.TextView
-	LogLevelContainer *tview.TextView
-}
-
-func NewUILogEntry(message logMessage) *UILogEntry {
-	logEntry := &UILogEntry{
-		Primitive:         tview.NewGrid(),
-		TimeContainer:     tview.NewTextView(),
-		MessageContainer:  tview.NewTextView(),
-		LogLevelContainer: tview.NewTextView(),
-	}
-
-	logEntry.TimeContainer.SetBackgroundColor(tcell.ColorWhite)
-	logEntry.TimeContainer.SetTextColor(tcell.ColorBlack)
-	logEntry.TimeContainer.SetDynamicColors(true)
-
-	logEntry.MessageContainer.SetBackgroundColor(tcell.ColorWhite)
-	logEntry.MessageContainer.SetTextColor(tcell.ColorBlack)
-	logEntry.MessageContainer.SetDynamicColors(true)
-
-	logEntry.LogLevelContainer.SetBackgroundColor(tcell.ColorWhite)
-	logEntry.LogLevelContainer.SetTextColor(tcell.ColorBlack)
-	logEntry.LogLevelContainer.SetDynamicColors(true)
-
-	textColor := "black::d"
-	switch message.level {
-	case logger.LevelInfo:
-		fmt.Fprintf(logEntry.LogLevelContainer, " [black::d][ [blue::d]INFO [black::d]]")
-	case logger.LevelWarn:
-		fmt.Fprintf(logEntry.LogLevelContainer, " [black::d][ [yellow::d]WARN [black::d]]")
-
-		textColor = "yellow::d"
-	case logger.LevelError:
-		fallthrough
-	case logger.LevelPanic:
-		fallthrough
-	case logger.LevelFatal:
-		fmt.Fprintf(logEntry.LogLevelContainer, " [black::d][ [red::d]FAIL [black::d]]")
-
-		textColor = "red::d"
-	case logger.LevelDebug:
-		fmt.Fprintf(logEntry.LogLevelContainer, " [black::d][ [black::b]NOTE [black::d]]")
-
-		textColor = "black::b"
-	}
-
-	fmt.Fprintf(logEntry.TimeContainer, "  [black::b]"+message.time.Format("15:04:05"))
-	if message.name == "Node" {
-		fmt.Fprintf(logEntry.MessageContainer, "["+textColor+"]"+message.msg)
-	} else {
-		fmt.Fprintf(logEntry.MessageContainer, "["+textColor+"]"+message.name+": "+message.msg)
-	}
-
-	logEntry.Primitive.
-		SetColumns(11, 0, 11).
-		SetRows(1).
-		SetBorders(false).
-		AddItem(logEntry.TimeContainer, 0, 0, 1, 1, 0, 0, false).
-		AddItem(logEntry.MessageContainer, 0, 1, 1, 1, 0, 0, false).
-		AddItem(logEntry.LogLevelContainer, 0, 2, 1, 1, 0, 0, false)
-
-	return logEntry
-}