diff --git a/CHANGELOG.md b/CHANGELOG.md
index 455c45a5297e95c456a6eac64d846190ef94a4fa..e4c3fda811f838a6f83090e271f5ac5bddda9fa7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,7 +13,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ### Changed ###
 
-- the suppression module is now a logging filter
+- The suppression module is now a logging filter.
+- The WebUIHandler is now a python logging formatter.
 - instead of `get_entity`, type-specific functions are used in
   `cfood.py` when the type of the entity in question is known.
 - Logger is used instead of `print` for errors in `crawler.py`.
diff --git a/src/caosadvancedtools/serverside/helper.py b/src/caosadvancedtools/serverside/helper.py
index e824c409b42acf9ccf0bfe0fae93707ed5037851..a09e6cfe867211e27fde8675d83d6b21bd14d456 100644
--- a/src/caosadvancedtools/serverside/helper.py
+++ b/src/caosadvancedtools/serverside/helper.py
@@ -23,7 +23,6 @@ from __future__ import absolute_import
 import argparse
 import datetime
 import json
-import logging
 import sys
 
 import caosdb as db
@@ -141,75 +140,6 @@ def print_error(text):
     print_bootstrap("<b>ERROR:</b> " + text, kind="danger", file=sys.stderr)
 
 
-class WebUI_Handler(logging.StreamHandler):
-    """ allows to make logging to be nicely displayed in the WebUI
-
-    You can enable this as follows:
-    logger = logging.getLogger("<LoggerName>")
-    logger.addHandler(WebUI_Handler())
-    """
-
-    def __init__(self, *args, full_file=None, **kwargs):
-        super().__init__(*args, **kwargs)
-        self.max_elements = 100
-        self.counter = 0
-        self.full_file = full_file
-
-    def format(self, record):
-        """ Return the HTML formatted log record for display on a website.
-
-        Implementation of the format function as defined by
-        logging.StreamHandler.
-
-
-        Parameters
-        ----------
-
-        record :
-
-        Raises
-        ------
-        RuntimeError
-            If the log level of the record is not supported. Supported log
-            levels include logging.DEBUG, logging.INFO, logging.WARNING,
-            logging.ERROR, and logging.CRITICAL.
-
-        Returns
-        -------
-        str
-            The formatted log record.
-
-        """
-        self.counter += 1
-
-        if self.counter == self.max_elements:
-            return wrap_bootstrap_alert(
-                "<b>Warning:</b> Due to the large number of messages, the "
-                "output is stopped here. You can see the full log "
-                " <a href='{}'>here</a>.".format(self.full_file),
-                kind="warning")
-
-        if self.counter > self.max_elements:
-            return ""
-
-        text = str(record.getMessage()).replace("\n", r"</br>")
-        text = text.replace("\t", r"&nbsp;"*4)
-
-        if record.levelno == logging.DEBUG:
-            return wrap_bootstrap_alert(str(record.getMessage()), kind="info")
-        elif record.levelno == logging.INFO:
-            return wrap_bootstrap_alert("<b>Info:</b> " + text, kind="info")
-        elif record.levelno == logging.WARNING:
-            return wrap_bootstrap_alert("<b>Warning:</b> " + text, kind="warning")
-        elif record.levelno == logging.ERROR:
-            return wrap_bootstrap_alert("<b>ERROR:</b> " + text, kind="danger")
-        elif record.levelno == logging.CRITICAL:
-            return wrap_bootstrap_alert("<b>CRITICAL ERROR:</b> " + text, kind="danger")
-        else:
-            raise RuntimeError("Unsupported log level: {}".format(record.levelno))
-
-
-
 class DataModelError(RuntimeError):
     """DataModelError indicates that the server-side script cannot work as
     intended due to missing datat model entities or an otherwise incompatible
diff --git a/src/caosadvancedtools/webui_formatter.py b/src/caosadvancedtools/webui_formatter.py
new file mode 100644
index 0000000000000000000000000000000000000000..c3c5381d96e86a2698cc16d1bf1a2726566dcd7b
--- /dev/null
+++ b/src/caosadvancedtools/webui_formatter.py
@@ -0,0 +1,95 @@
+# encoding: utf-8
+#
+# Copyright (C) 2019, 2020 IndiScale GmbH <info@indiscale.com>
+# Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com>
+# Copyright (C) 2019, 2020 Henrik tom Wörden <h.tomwoerden@indiscale.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# 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 Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+#
+#
+import logging
+
+from .serverside.helper import wrap_bootstrap_alert
+
+
+class WebUI_Formatter(logging.Formatter):
+    """ allows to make logging to be nicely displayed in the WebUI
+
+    You can enable this as follows:
+    logger = logging.getLogger("<LoggerName>")
+    formatter = WebUI_Formatter(full_file="path/to/file")
+    handler = logging.Handler()
+    handler.setFormatter(formatter)
+    logger.addHandler(handler)
+    """
+
+    def __init__(self, *args, full_file=None, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.max_elements = 100
+        self.counter = 0
+        self.full_file = full_file
+
+    def format(self, record):
+        """ Return the HTML formatted log record for display on a website.
+
+        This essentially wraps the text formatted by the parent class in html.
+
+        Parameters
+        ----------
+
+        record :
+
+        Raises
+        ------
+        RuntimeError
+            If the log level of the record is not supported. Supported log
+            levels include logging.DEBUG, logging.INFO, logging.WARNING,
+            logging.ERROR, and logging.CRITICAL.
+
+        Returns
+        -------
+        str
+            The formatted log record.
+
+        """
+        msg = super().format(record)
+        self.counter += 1
+
+        if self.counter == self.max_elements:
+            return wrap_bootstrap_alert(
+                "<b>Warning:</b> Due to the large number of messages, the "
+                "output is stopped here. You can see the full log "
+                " <a href='{}'>here</a>.".format(self.full_file),
+                kind="warning")
+
+        if self.counter > self.max_elements:
+            return ""
+
+        text = msg.replace("\n", r"</br>")
+        text = text.replace("\t", r"&nbsp;"*4)
+
+        if record.levelno == logging.DEBUG:
+            return wrap_bootstrap_alert(msg, kind="info")
+        elif record.levelno == logging.INFO:
+            return wrap_bootstrap_alert("<b>Info:</b> " + text, kind="info")
+        elif record.levelno == logging.WARNING:
+            return wrap_bootstrap_alert("<b>Warning:</b> " + text,
+                                        kind="warning")
+        elif record.levelno == logging.ERROR:
+            return wrap_bootstrap_alert("<b>ERROR:</b> " + text, kind="danger")
+        elif record.levelno == logging.CRITICAL:
+            return wrap_bootstrap_alert("<b>CRITICAL ERROR:</b> " + text,
+                                        kind="danger")
+        else:
+            raise Exception("unknown level")