diff --git a/composer.json b/composer.json
index f3fc0a44cdf7b1e2c98ccda99687a398f6c85c19..f9472203a3e015746d60709a8f6f023ad669d233 100644
--- a/composer.json
+++ b/composer.json
@@ -10,17 +10,16 @@
     "require-dev": {
         "adlawson/vfs": "~0.12.1",
         "camspiers/json-pretty": "~1.0.2",
-        "monolog/monolog": "~1.21.0",
         "php-http/curl-client": "~1.7.0",
         "woohoolabs/yang": "2.3.2",
-        "codeception/codeception": "~4.1.21",
+        "codeception/codeception": "^4.2",
         "codeception/module-asserts": "^1.3",
         "overtrue/phplint": "^3.0",
         "phpstan/phpstan": "^1.8"
     },
     "require": {
         "php": "^7.2",
-        "guzzlehttp/psr7": "~1.4.2",
+        "guzzlehttp/psr7": "^2.3",
         "neomerx/json-api": "4.0.1",
         "spomky-labs/otphp": "^8.3.3",
         "tuupola/cors-middleware": "1.2.1",
@@ -56,6 +55,7 @@
         "symfony/process": "^5.4",
         "jumbojett/openid-connect-php": "^0.9.2",
         "league/oauth2-server": "^8.3",
-        "willdurand/negotiation": "^3.1"
+        "willdurand/negotiation": "^3.1",
+        "monolog/monolog": "^2.8"
     }
 }
diff --git a/composer.lock b/composer.lock
index 64a95d964f0546218fe007a626a0516b511a6896..48089a2887570e5f7f6a56271337c6881ae9291a 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "7a9043e1984ae4fb02e5872928486f0a",
+    "content-hash": "f5e46cc8a302174b53ca3ca2f6a647d2",
     "packages": [
         {
             "name": "algo26-matthias/idna-convert",
@@ -446,38 +446,47 @@
         },
         {
             "name": "guzzlehttp/psr7",
-            "version": "1.4.2",
+            "version": "2.4.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/guzzle/psr7.git",
-                "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c"
+                "reference": "69568e4293f4fa993f3b0e51c9723e1e17c41379"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/guzzle/psr7/zipball/f5b8a8512e2b58b0071a7280e39f14f72e05d87c",
-                "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c",
+                "url": "https://api.github.com/repos/guzzle/psr7/zipball/69568e4293f4fa993f3b0e51c9723e1e17c41379",
+                "reference": "69568e4293f4fa993f3b0e51c9723e1e17c41379",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.4.0",
-                "psr/http-message": "~1.0"
+                "php": "^7.2.5 || ^8.0",
+                "psr/http-factory": "^1.0",
+                "psr/http-message": "^1.0",
+                "ralouphie/getallheaders": "^3.0"
             },
             "provide": {
+                "psr/http-factory-implementation": "1.0",
                 "psr/http-message-implementation": "1.0"
             },
             "require-dev": {
-                "phpunit/phpunit": "~4.0"
+                "bamarni/composer-bin-plugin": "^1.8.1",
+                "http-interop/http-factory-tests": "^0.9",
+                "phpunit/phpunit": "^8.5.29 || ^9.5.23"
+            },
+            "suggest": {
+                "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
             },
             "type": "library",
             "extra": {
+                "bamarni-bin": {
+                    "bin-links": true,
+                    "forward-command": false
+                },
                 "branch-alias": {
-                    "dev-master": "1.4-dev"
+                    "dev-master": "2.4-dev"
                 }
             },
             "autoload": {
-                "files": [
-                    "src/functions_include.php"
-                ],
                 "psr-4": {
                     "GuzzleHttp\\Psr7\\": "src/"
                 }
@@ -487,20 +496,47 @@
                 "MIT"
             ],
             "authors": [
+                {
+                    "name": "Graham Campbell",
+                    "email": "hello@gjcampbell.co.uk",
+                    "homepage": "https://github.com/GrahamCampbell"
+                },
                 {
                     "name": "Michael Dowling",
                     "email": "mtdowling@gmail.com",
                     "homepage": "https://github.com/mtdowling"
                 },
+                {
+                    "name": "George Mponos",
+                    "email": "gmponos@gmail.com",
+                    "homepage": "https://github.com/gmponos"
+                },
+                {
+                    "name": "Tobias Nyholm",
+                    "email": "tobias.nyholm@gmail.com",
+                    "homepage": "https://github.com/Nyholm"
+                },
+                {
+                    "name": "Márk Sági-Kazár",
+                    "email": "mark.sagikazar@gmail.com",
+                    "homepage": "https://github.com/sagikazarmark"
+                },
                 {
                     "name": "Tobias Schultze",
+                    "email": "webmaster@tubo-world.de",
                     "homepage": "https://github.com/Tobion"
+                },
+                {
+                    "name": "Márk Sági-Kazár",
+                    "email": "mark.sagikazar@gmail.com",
+                    "homepage": "https://sagikazarmark.hu"
                 }
             ],
             "description": "PSR-7 message implementation that also provides common utility methods",
             "keywords": [
                 "http",
                 "message",
+                "psr-7",
                 "request",
                 "response",
                 "stream",
@@ -509,9 +545,23 @@
             ],
             "support": {
                 "issues": "https://github.com/guzzle/psr7/issues",
-                "source": "https://github.com/guzzle/psr7/tree/1.4.2"
+                "source": "https://github.com/guzzle/psr7/tree/2.4.1"
             },
-            "time": "2017-03-20T17:10:46+00:00"
+            "funding": [
+                {
+                    "url": "https://github.com/GrahamCampbell",
+                    "type": "github"
+                },
+                {
+                    "url": "https://github.com/Nyholm",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-08-28T14:45:39+00:00"
         },
         {
             "name": "jakeasmith/http_build_url",
@@ -1153,6 +1203,108 @@
             },
             "time": "2016-04-25T07:03:37+00:00"
         },
+        {
+            "name": "monolog/monolog",
+            "version": "2.8.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/Seldaek/monolog.git",
+                "reference": "720488632c590286b88b80e62aa3d3d551ad4a50"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/Seldaek/monolog/zipball/720488632c590286b88b80e62aa3d3d551ad4a50",
+                "reference": "720488632c590286b88b80e62aa3d3d551ad4a50",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.2",
+                "psr/log": "^1.0.1 || ^2.0 || ^3.0"
+            },
+            "provide": {
+                "psr/log-implementation": "1.0.0 || 2.0.0 || 3.0.0"
+            },
+            "require-dev": {
+                "aws/aws-sdk-php": "^2.4.9 || ^3.0",
+                "doctrine/couchdb": "~1.0@dev",
+                "elasticsearch/elasticsearch": "^7 || ^8",
+                "ext-json": "*",
+                "graylog2/gelf-php": "^1.4.2",
+                "guzzlehttp/guzzle": "^7.4",
+                "guzzlehttp/psr7": "^2.2",
+                "mongodb/mongodb": "^1.8",
+                "php-amqplib/php-amqplib": "~2.4 || ^3",
+                "phpspec/prophecy": "^1.15",
+                "phpstan/phpstan": "^0.12.91",
+                "phpunit/phpunit": "^8.5.14",
+                "predis/predis": "^1.1 || ^2.0",
+                "rollbar/rollbar": "^1.3 || ^2 || ^3",
+                "ruflin/elastica": "^7",
+                "swiftmailer/swiftmailer": "^5.3|^6.0",
+                "symfony/mailer": "^5.4 || ^6",
+                "symfony/mime": "^5.4 || ^6"
+            },
+            "suggest": {
+                "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB",
+                "doctrine/couchdb": "Allow sending log messages to a CouchDB server",
+                "elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client",
+                "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)",
+                "ext-curl": "Required to send log messages using the IFTTTHandler, the LogglyHandler, the SendGridHandler, the SlackWebhookHandler or the TelegramBotHandler",
+                "ext-mbstring": "Allow to work properly with unicode symbols",
+                "ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)",
+                "ext-openssl": "Required to send log messages using SSL",
+                "ext-sockets": "Allow sending log messages to a Syslog server (via UDP driver)",
+                "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server",
+                "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)",
+                "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib",
+                "rollbar/rollbar": "Allow sending log messages to Rollbar",
+                "ruflin/elastica": "Allow sending log messages to an Elastic Search server"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "2.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Monolog\\": "src/Monolog"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Jordi Boggiano",
+                    "email": "j.boggiano@seld.be",
+                    "homepage": "https://seld.be"
+                }
+            ],
+            "description": "Sends your logs to files, sockets, inboxes, databases and various web services",
+            "homepage": "https://github.com/Seldaek/monolog",
+            "keywords": [
+                "log",
+                "logging",
+                "psr-3"
+            ],
+            "support": {
+                "issues": "https://github.com/Seldaek/monolog/issues",
+                "source": "https://github.com/Seldaek/monolog/tree/2.8.0"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/Seldaek",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/monolog/monolog",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2022-07-24T11:55:47+00:00"
+        },
         {
             "name": "neomerx/cors-psr7",
             "version": "v1.0.13",
@@ -4351,16 +4503,16 @@
         },
         {
             "name": "codeception/codeception",
-            "version": "4.1.31",
+            "version": "4.2.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/Codeception/Codeception.git",
-                "reference": "15524571ae0686a7facc2eb1f40f600e5bbce9e5"
+                "reference": "b88014f3348c93f3df99dc6d0967b0dbfa804474"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/Codeception/Codeception/zipball/15524571ae0686a7facc2eb1f40f600e5bbce9e5",
-                "reference": "15524571ae0686a7facc2eb1f40f600e5bbce9e5",
+                "url": "https://api.github.com/repos/Codeception/Codeception/zipball/b88014f3348c93f3df99dc6d0967b0dbfa804474",
+                "reference": "b88014f3348c93f3df99dc6d0967b0dbfa804474",
                 "shasum": ""
             },
             "require": {
@@ -4423,11 +4575,11 @@
                 {
                     "name": "Michael Bodnarchuk",
                     "email": "davert@mail.ua",
-                    "homepage": "http://codegyre.com"
+                    "homepage": "https://codegyre.com"
                 }
             ],
             "description": "BDD-style testing framework",
-            "homepage": "http://codeception.com/",
+            "homepage": "https://codeception.com/",
             "keywords": [
                 "BDD",
                 "TDD",
@@ -4437,7 +4589,7 @@
             ],
             "support": {
                 "issues": "https://github.com/Codeception/Codeception/issues",
-                "source": "https://github.com/Codeception/Codeception/tree/4.1.31"
+                "source": "https://github.com/Codeception/Codeception/tree/4.2.2"
             },
             "funding": [
                 {
@@ -4445,7 +4597,7 @@
                     "type": "open_collective"
                 }
             ],
-            "time": "2022-03-13T17:07:08+00:00"
+            "time": "2022-08-13T13:28:25+00:00"
         },
         {
             "name": "codeception/lib-asserts",
@@ -4710,88 +4862,6 @@
             ],
             "time": "2022-03-03T08:28:38+00:00"
         },
-        {
-            "name": "monolog/monolog",
-            "version": "1.21.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/Seldaek/monolog.git",
-                "reference": "f42fbdfd53e306bda545845e4dbfd3e72edb4952"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/Seldaek/monolog/zipball/f42fbdfd53e306bda545845e4dbfd3e72edb4952",
-                "reference": "f42fbdfd53e306bda545845e4dbfd3e72edb4952",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.0",
-                "psr/log": "~1.0"
-            },
-            "provide": {
-                "psr/log-implementation": "1.0.0"
-            },
-            "require-dev": {
-                "aws/aws-sdk-php": "^2.4.9",
-                "doctrine/couchdb": "~1.0@dev",
-                "graylog2/gelf-php": "~1.0",
-                "jakub-onderka/php-parallel-lint": "0.9",
-                "php-amqplib/php-amqplib": "~2.4",
-                "php-console/php-console": "^3.1.3",
-                "phpunit/phpunit": "~4.5",
-                "phpunit/phpunit-mock-objects": "2.3.0",
-                "ruflin/elastica": ">=0.90 <3.0",
-                "sentry/sentry": "^0.13",
-                "swiftmailer/swiftmailer": "~5.3"
-            },
-            "suggest": {
-                "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB",
-                "doctrine/couchdb": "Allow sending log messages to a CouchDB server",
-                "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)",
-                "ext-mongo": "Allow sending log messages to a MongoDB server",
-                "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server",
-                "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver",
-                "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib",
-                "php-console/php-console": "Allow sending log messages to Google Chrome",
-                "rollbar/rollbar": "Allow sending log messages to Rollbar",
-                "ruflin/elastica": "Allow sending log messages to an Elastic Search server",
-                "sentry/sentry": "Allow sending log messages to a Sentry server"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "2.0.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Monolog\\": "src/Monolog"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Jordi Boggiano",
-                    "email": "j.boggiano@seld.be",
-                    "homepage": "http://seld.be"
-                }
-            ],
-            "description": "Sends your logs to files, sockets, inboxes, databases and various web services",
-            "homepage": "http://github.com/Seldaek/monolog",
-            "keywords": [
-                "log",
-                "logging",
-                "psr-3"
-            ],
-            "support": {
-                "issues": "https://github.com/Seldaek/monolog/issues",
-                "source": "https://github.com/Seldaek/monolog/tree/1.x"
-            },
-            "time": "2016-07-29T03:23:52+00:00"
-        },
         {
             "name": "myclabs/deep-copy",
             "version": "1.11.0",
@@ -7105,5 +7175,8 @@
         "ext-dom": "*"
     },
     "platform-dev": [],
-    "plugin-api-version": "2.3.0"
+    "platform-overrides": {
+        "php": "7.2.5"
+    },
+    "plugin-api-version": "2.2.0"
 }
diff --git a/lib/bootstrap.php b/lib/bootstrap.php
index 94fec26eaffb541f30ba9080230ef1ea46cecdf5..f387a6e15b727218c71b295ee2f510d131798797 100644
--- a/lib/bootstrap.php
+++ b/lib/bootstrap.php
@@ -105,14 +105,6 @@ require_once 'lib/functions.php';
 require_once 'lib/language.inc.php';
 require_once 'lib/visual.inc.php';
 
-//setup default logger
-Log::get()->setHandler($GLOBALS['TMP_PATH'] . '/studip.log');
-if (Studip\ENV == 'development') {
-    Log::get()->setLogLevel(Log::DEBUG);
-} else {
-    Log::get()->setLogLevel(Log::ERROR);
-}
-
 // set assets url
 Assets::set_assets_url($GLOBALS['ASSETS_URL']);
 
diff --git a/lib/classes/FilesSearch/FilesIndexManager.php b/lib/classes/FilesSearch/FilesIndexManager.php
index 9f762d5e60a420e4154bfff906e20ba9b86efac2..23bac4e5ce35fe2cfae6a425436c1a5c80f43a36 100644
--- a/lib/classes/FilesSearch/FilesIndexManager.php
+++ b/lib/classes/FilesSearch/FilesIndexManager.php
@@ -4,6 +4,8 @@ namespace FilesSearch;
 
 use DBManager;
 use Log;
+use Monolog\Logger;
+use Monolog\Handler\StreamHandler;
 use PDOException;
 
 /**
@@ -222,10 +224,10 @@ class FilesIndexManager
      */
     private static function createLogger()
     {
-        @unlink($GLOBALS['TMP_PATH'].'/files_index.log');
-        Log::set('filesindexlog', $GLOBALS['TMP_PATH'].'/files_index.log');
+        $logfile = $GLOBALS['TMP_PATH'] . '/files_index.log';
+        @unlink($logfile);
 
-        return Log::get('filesindexlog');
+        return new Logger('filesindexlog', [new StreamHandler($logfile, Logger::DEBUG)]);
     }
 
     /**
diff --git a/lib/classes/Log.php b/lib/classes/Log.php
index 335572dc1507498b148ee9d3b3ab944000a67078..4bb0e9d80f6b89f02e49803b3a0fd5fa14155549 100644
--- a/lib/classes/Log.php
+++ b/lib/classes/Log.php
@@ -1,256 +1,52 @@
 <?php
+
+use Psr\Log\LoggerInterface;
+
 /**
- * Log.php
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * Usage:
- * @code
- * //logging to $GLOBALS['TMP_PATH'] . '/studip.log'
- * Log::get()->setHandler($GLOBALS['TMP_PATH'] . '/studip.log');
- * Log::warn('log this'); //log a WARNING
- * Log::warning('log this'); //also log a WARNING
- * Log::w('log this'); //also log a WARNING
- * //create additional log
- * Log::set('my', '/tmp/mylog.txt');
- * Log::debug_my('debug to my');
- * //use self defined log handler
- * Log::get('my')
- * ->setHandler(function ($m) {
- *   return mail( mail('noack@data-quest.de', '['.$m['level_name'].']', $m['formatted']););
- *   });
- * Log::alert_my('log via mail');
- * @endcode
- *
- * @author      André Noack <noack@data-quest.de>
- * @copyright   2012 Stud.IP Core-Group
- * @license     http://www.gnu.org/licenses/gpl-2.0.html GPL version 2
- * @category    Stud.IP
- *
- * @method static mixed FATAL (string $message)
- * @method static mixed ALERT (string $message)
- * @method static mixed CRITICAL (string $message)
- * @method static mixed ERROR (string $message)
- * @method static mixed WARNING (string $message)
- * @method static mixed NOTICE (string $message)
- * @method static mixed INFO (string $message)
- * @method static mixed DEBUG (string $message)
-*/
+ * @method static void alert(string $message, array $context = [])
+ * @method static void critical(string $message, array $context = [])
+ * @method static void debug(string $message, array $context = [])
+ * @method static void emergency(string $message, array $context = [])
+ * @method static void error(string $message, array $context = [])
+ * @method static void info(string $message, array $context = [])
+ * @method static void log($level, string $message, array $context = [])
+ * @method static void notice(string $message, array $context = [])
+ * @method static void warning(string $message, array $context = [])
+ */
 class Log
 {
-
-    const FATAL = 0; // All is lost
-    const ALERT = 1; // Immediate action required
-    const CRITICAL = 2; // Critical conditions
-    const ERROR = 3; // An error occurred
-    const WARNING = 4; // Something unexpected happening
-    const NOTICE = 5; // Something worth noting
-    const INFO = 6; // Information, not an error
-    const DEBUG = 7; // Debugging messages
-
-    /**
-     * if string then complete path to logfile
-     * if not schould be callable
-     *
-     * @var mixed
-     */
-    private $log_handler = null;
-
-    /**
-     * maximum log level
-     *
-     * @var integer
-     */
-    private $log_level = 6;
-    /**
-     * an array with log levels, taken from contants
-     * .
-     * @var array
-     */
-    private $log_level_names = [];
-
-    /**
-     * if log_handler is a string
-     * the file pointer
-     *
-     * @var resource
-     */
-    private $file = null;
-
     /**
-     * array of used log instances
+     * The underlying logger.
      *
-     * @var array
+     * @var LoggerInterface
      */
-    private static $instances = [];
+    protected static $instance;
 
     /**
-     * returns a log instance, identified by given name
-     * if name is omitted, the default logger is returned
+     * Handle dynamic, static calls to the object.
      *
-     * @param string $name name of log instance
-     * @throws InvalidArgumentException
-     * @return Log
-     */
-    public static function get($name = '')
-    {
-        $name = mb_strlen($name) ? $name : 0;
-        if ($name === 0 && !isset(self::$instances[$name])) {
-            self::set();
-        }
-        if (!isset(self::$instances[$name])) {
-            throw new InvalidArgumentException('Unknown logger: ' . $name);
-        }
-        return self::$instances[$name];
-    }
-
-    /**
-     * sets a log handler for the named log instance
-     * returns the old handler
-     *
-     * @param string $name
-     * @param mixed $log_handler
+     * @param  string  $method
+     * @param  array  $args
      * @return mixed
      */
-    public static function set($name = '', $log_handler = null)
-    {
-        $name = mb_strlen($name) ? $name : 0;
-        $old = self::$instances[$name] ?? null;
-        self::$instances[$name] = new Log($log_handler);
-        return $old;
-    }
-
-    /**
-     * magic log, intercepts all static method calls
-     * called method names are splitted by an underscore
-     * first part denotes log level, second name of logger if any
-     *
-     * @param string $name
-     * @param array $arguments
-     * @return mixed number of written bytes or return value from callable handler
-     */
-    public static function __callStatic($name, $arguments)
-    {
-        list($level_name, $log_name) = explode('_', $name);
-        $message = $arguments[0];
-        return self::get($log_name)->{$level_name}($message);
-    }
-
-    /**
-     * create new log instance with given handler
-     *
-     * @param mixed $log_handler
-     */
-    function __construct($log_handler = null)
-    {
-        $this->setHandler($log_handler);
-        $r = new ReflectionClass($this);
-        $this->log_level_names = array_flip($r->getConstants());
-    }
-
-    /**
-     * set the maximum log level
-     *
-     * @param integer $level
-     * @return integer
-     */
-    public function setLogLevel($level)
+    public static function __callStatic($method, $args)
     {
-        $old = $this->log_level;
-        $this->log_level = $level;
-        return $old;
-    }
+        $instance = static::getInstance();
 
-    /**
-     * returns the current maximum log level
-     *
-     * @return integer
-     */
-    public function getLogLevel()
-    {
-        return $this->log_level;
+        return $instance->$method(...$args);
     }
 
-    /**
-     * set the log handler
-     * returns the old handler
-     *
-     * @param mixed $log_handler
-     * @return mixed
-     */
-    public function setHandler($log_handler)
+    public static function getInstance(): LoggerInterface
     {
-        $old = $this->log_handler;
-        $this->log_handler = $log_handler;
-        if (is_resource($this->file)) {
-            fclose($this->file);
+        if (!isset(static::$instance)) {
+            static::$instance = app(LoggerInterface::class);
         }
-        return $old;
-    }
 
-    /**
-     * returns the current log handler
-     *
-     * @return mixed
-     */
-    public function getHandler()
-    {
-        return $this->log_handler;
+        return static::$instance;
     }
 
-    /**
-     * log a message
-     *
-     * @param string $message the log message
-     * @param integer $level log level, see constants
-     * @return mixed number of written bytes or return value from callable handler
-     */
-    public function log($message, $level = Log::ERROR)
+    public static function setInstance(LoggerInterface $instance): void
     {
-        if (isset($this->log_handler) && $level <= $this->log_level) {
-            $log_level_name = $this->log_level_names[$level];
-            $formatted_message = date('c') . ' ['.$this->log_level_names[$level].'] ' . $message;
-            if (is_callable($this->log_handler)) {
-                $log_handler = $this->log_handler;
-                return $log_handler(['formatted' => $formatted_message,
-                                          'message' => $message,
-                                          'level' => $level,
-                                          'level_name' => $this->log_level_names[$level],
-                                          'timestamp' => time()
-                                          ]);
-            } else {
-                $logfile = $this->log_handler;
-                $this->file = is_resource($this->file) ? $this->file : @fopen($logfile, 'ab');
-                if ($this->file && flock($this->file , LOCK_EX)) {
-                    $ret = fwrite($this->file, date('c') . ' ['.$this->log_level_names[$level].'] ' . $message . "\n");
-                    flock($this->file, LOCK_UN);
-                    return $ret;
-                } else {
-                    trigger_error(sprintf('Logfile %s could not be opened.', $logfile), E_USER_WARNING);
-                }
-            }
-        }
-    }
-
-    /**
-     * magic log, intercepts all undefined method calls
-     * called method name must be log level name or part of
-     *
-     * @param string $name
-     * @param array $arguments
-     * @return mixed number of written bytes or return value from callable handler
-     */
-    public function __call($name, $arguments)
-    {
-        foreach ($this->log_level_names as $level_num => $level_name) {
-            if (mb_stripos($level_name, $name) === 0) {
-                return $this->log($arguments[0], $level_num);
-            }
-        }
-        throw new BadMethodCallException('Unknown method called: ' . $name);
+        static::$instance = $instance;
     }
 }
diff --git a/lib/classes/admission/RandomAlgorithm.class.php b/lib/classes/admission/RandomAlgorithm.class.php
index c0fa3f0b6f57388116ac0b5f2c2280a6c713f2e5..54d44d7f8402f46308995c76d28d0cf7cbdaa71c 100644
--- a/lib/classes/admission/RandomAlgorithm.class.php
+++ b/lib/classes/admission/RandomAlgorithm.class.php
@@ -44,7 +44,7 @@ class RandomAlgorithm extends AdmissionAlgorithm
      */
     private function distributeByCourses($courseSet)
     {
-        Log::DEBUG('start seat distribution for course set: ' . $courseSet->getId());
+        Log::debug('start seat distribution for course set: ' . $courseSet->getId());
         $groups_quota = [];
         $conditional_rule_filter = array_filter($courseSet->getAdmissionRules(), function ($r) {
             return $r instanceof ConditionalAdmission
@@ -63,14 +63,14 @@ class RandomAlgorithm extends AdmissionAlgorithm
             $waiting_users = [];
             $course = Course::find($course_id);
             if (!$course) {
-                Log::DEBUG(sprintf('course %s not found, continue', $course_id));
+                Log::debug(sprintf('course %s not found, continue', $course_id));
                 continue;
             }
             $free_seats_course = $course->getFreeSeats();
             foreach ($groups_quota as $group_id => $quota) {
                 $claiming_users = AdmissionPriority::getPrioritiesByCourse($courseSet->getId(), $course->id);
                 if (isset($conditiongroups[$group_id])) {
-                    Log::DEBUG(sprintf('found conditiongroup %s with quota %s', $group_id, $quota));
+                    Log::debug(sprintf('found conditiongroup %s with quota %s', $group_id, $quota));
                     foreach(array_keys($claiming_users) as $user_id) {
                         $condition_ok = true;
                         foreach ($conditiongroups[$group_id] as $condition) {
@@ -96,18 +96,18 @@ class RandomAlgorithm extends AdmissionAlgorithm
                                     PHP_INT_MAX :
                                     $claiming_users[$user_id] * $factored_users[$user_id];
                         }
-                        Log::DEBUG(sprintf('user %s gets factor %s', $user_id, $claiming_users[$user_id]));
+                        Log::debug(sprintf('user %s gets factor %s', $user_id, $claiming_users[$user_id]));
                     } else {
                         unset($claiming_users[$user_id]);
-                        Log::DEBUG(sprintf('user %s is already %s, ignoring', $user_id, $course->getParticipantStatus($user_id)));
+                        Log::debug(sprintf('user %s is already %s, ignoring', $user_id, $course->getParticipantStatus($user_id)));
                     }
                 }
                 $free_seats = round($free_seats_course * $quota / 100, 0, PHP_ROUND_HALF_DOWN);
-                Log::DEBUG(sprintf('distribute %s seats on %s claiming in course %s %s', $free_seats, count($claiming_users), $course->id, ($group_id ? 'conditiongroup ' . $group_id . ' quota ' . $quota : '')));
+                Log::debug(sprintf('distribute %s seats on %s claiming in course %s %s', $free_seats, count($claiming_users), $course->id, ($group_id ? 'conditiongroup ' . $group_id . ' quota ' . $quota : '')));
                 $claiming_users = $this->rollTheDice($claiming_users);
-                Log::DEBUG('the die is cast: ' . print_r($claiming_users,1));
+                Log::debug('the die is cast: ' . print_r($claiming_users,1));
                 $chosen_ones = array_slice(array_keys($claiming_users),0 , $free_seats);
-                Log::DEBUG('chosen ones: ' . print_r($chosen_ones,1));
+                Log::debug('chosen ones: ' . print_r($chosen_ones,1));
                 $this->addUsersToCourse($chosen_ones, $course);
                 foreach ($chosen_ones as $one) unset($waiting_users[$one]);
                 if ($free_seats < count($claiming_users)) {
@@ -122,14 +122,14 @@ class RandomAlgorithm extends AdmissionAlgorithm
                 if (!$course->admission_disable_waitlist) {
                     $free_seats_waitlist = $course->admission_waitlist_max ?: count($waiting_users);
                     $waiting_list_ones = array_slice(array_keys($waiting_users), 0, $free_seats_waitlist);
-                    Log::DEBUG('waiting list ones: ' . print_r($waiting_list_ones, 1));
+                    Log::debug('waiting list ones: ' . print_r($waiting_list_ones, 1));
                     $this->addUsersToWaitlist($waiting_list_ones, $course);
                 } else {
                     $free_seats_waitlist = 0;
                 }
                 if ($free_seats_waitlist < count($waiting_users)) {
                     $remaining_ones = array_slice(array_keys($waiting_users),$free_seats_waitlist);
-                    Log::DEBUG('remaining ones: ' . print_r($remaining_ones, 1));
+                    Log::debug('remaining ones: ' . print_r($remaining_ones, 1));
                     $this->notifyRemainingUsers($remaining_ones, $course);
                 }
             }
@@ -146,7 +146,7 @@ class RandomAlgorithm extends AdmissionAlgorithm
      */
     private function distributeByPriorities($courseSet)
     {
-        Log::DEBUG('start seat distribution for course set: ' . $courseSet->getId());
+        Log::debug('start seat distribution for course set: ' . $courseSet->getId());
         $limited_admission = $courseSet->getAdmissionRule('LimitedAdmission');
         //all users with their priorities
         $claiming_users = AdmissionPriority::getPriorities($courseSet->getId());
@@ -199,13 +199,13 @@ class RandomAlgorithm extends AdmissionAlgorithm
         $max_prio = AdmissionPriority::getPrioritiesMax($courseSet->getId());
         //count already manually distributed places
         $distributed_users = $this->countParticipatingUsers($id_courses, array_keys($claiming_users));
-        Log::DEBUG('already distributed users: ' . print_r($distributed_users,1));
+        Log::debug('already distributed users: ' . print_r($distributed_users,1));
         //walk through all prios with all courses
         foreach(range(1, $max_prio) as $current_prio) {
             foreach ($id_courses as $course_id) {
                 $course = Course::find($course_id);
                 if (!$course) {
-                    Log::DEBUG(sprintf('course %s not found, continue', $course_id));
+                    Log::debug(sprintf('course %s not found, continue', $course_id));
                     continue;
                 }
                 $free_seats_course = $course->getFreeSeats();
@@ -215,7 +215,7 @@ class RandomAlgorithm extends AdmissionAlgorithm
                     foreach ($claiming_users as $user_id => $prio_courses) {
                         $condition_ok = true;
                         if (isset($conditiongroups[$group_id])) {
-                            Log::DEBUG(sprintf('found conditiongroup %s with quota %s', $group_id, $quota));
+                            Log::debug(sprintf('found conditiongroup %s with quota %s', $group_id, $quota));
                             foreach ($conditiongroups[$group_id] as $condition) {
                                 if ($condition->isFulfilled($user_id)) {
                                     $condition_ok = true;
@@ -237,7 +237,7 @@ class RandomAlgorithm extends AdmissionAlgorithm
                                             $current_claiming[$user_id] * $factored_users[$user_id];
                                 }
                             } else {
-                                Log::DEBUG(sprintf('user %s is already %s in course %s, ignoring', $user_id, $course->getParticipantStatus($user_id), $course->id));
+                                Log::debug(sprintf('user %s is already %s in course %s, ignoring', $user_id, $course->getParticipantStatus($user_id), $course->id));
                             }
                         }
                     }
@@ -248,12 +248,12 @@ class RandomAlgorithm extends AdmissionAlgorithm
                         }
                     }
                     $free_seats = round($free_seats_course * $quota / 100, 0, PHP_ROUND_HALF_DOWN);
-                    Log::DEBUG(sprintf('distribute %s seats on %s claiming with prio %s in course %s %s', $free_seats, count($current_claiming),$current_prio, $course->id, ($group_id ? 'conditiongroup ' . $group_id . ' quota ' . $quota : '')));
-                    Log::DEBUG('users to distribute: ' . print_r($current_claiming,1));
+                    Log::debug(sprintf('distribute %s seats on %s claiming with prio %s in course %s %s', $free_seats, count($current_claiming),$current_prio, $course->id, ($group_id ? 'conditiongroup ' . $group_id . ' quota ' . $quota : '')));
+                    Log::debug('users to distribute: ' . print_r($current_claiming,1));
                     $current_claiming = $this->rollTheDice($current_claiming);
-                    Log::DEBUG('the die is cast: ' . print_r($current_claiming,1));
+                    Log::debug('the die is cast: ' . print_r($current_claiming,1));
                     $chosen_ones = array_slice(array_keys($current_claiming),0 , $free_seats);
-                    Log::DEBUG('chosen ones: ' . print_r($chosen_ones,1));
+                    Log::debug('chosen ones: ' . print_r($chosen_ones,1));
                     $this->addUsersToCourse($chosen_ones, $course, $prio_mapper($chosen_ones, $course->id));
                     foreach ($chosen_ones as $one) {
                         $distributed_users[$one]++;
@@ -270,13 +270,13 @@ class RandomAlgorithm extends AdmissionAlgorithm
             }
         }
         //distribute to waitlists if applicable
-        Log::DEBUG('waiting list: ' . print_r($waiting_users, 1));
+        Log::debug('waiting list: ' . print_r($waiting_users, 1));
         foreach ($waiting_users as $current_prio => $current_prio_waiting_courses) {
             foreach ($current_prio_waiting_courses as $course_id => $users) {
                 $users = array_filter(array_unique($users), function($user_id) use ($distributed_users, $max_seats_users) {
                     return $distributed_users[$user_id] < $max_seats_users[$user_id];});
                     $course = Course::find($course_id);
-                    Log::DEBUG(sprintf('distribute waitlist of %s with prio %s in course %s', count($users), $current_prio, $course->id));
+                    Log::debug(sprintf('distribute waitlist of %s with prio %s in course %s', count($users), $current_prio, $course->id));
                     if (!$course->admission_disable_waitlist) {
                         if ($course->admission_waitlist_max) {
                             $free_seats_waitlist = $course->admission_waitlist_max - $course->getNumWaiting();
@@ -285,7 +285,7 @@ class RandomAlgorithm extends AdmissionAlgorithm
                             $free_seats_waitlist = count($users);
                         }
                         $waiting_list_ones = array_slice($users, 0, $free_seats_waitlist);
-                        Log::DEBUG('waiting list ones: ' . print_r($waiting_list_ones, 1));
+                        Log::debug('waiting list ones: ' . print_r($waiting_list_ones, 1));
                         $this->addUsersToWaitlist($waiting_list_ones, $course, $prio_mapper($waiting_list_ones, $course->id));
                         foreach ($waiting_list_ones as $one) {
                             $distributed_users[$one]++;
@@ -295,7 +295,7 @@ class RandomAlgorithm extends AdmissionAlgorithm
                     }
                     if ($free_seats_waitlist < count($users)) {
                         $remaining_ones = array_slice($users, $free_seats_waitlist);
-                        Log::DEBUG('remaining ones: ' . print_r($remaining_ones, 1));
+                        Log::debug('remaining ones: ' . print_r($remaining_ones, 1));
                         $this->notifyRemainingUsers($remaining_ones, $course, $prio_mapper($remaining_ones, $course->id));
                     }
             }
@@ -348,7 +348,7 @@ class RandomAlgorithm extends AdmissionAlgorithm
             try {
                 $course->admission_applicants[] = $new_admission_member;
             } catch (InvalidArgumentException $e) {
-                Log::DEBUG($e->getMessage());
+                Log::debug($e->getMessage());
                 continue;
             }
             if ($new_admission_member->store()) {
diff --git a/lib/classes/auth_plugins/StudipAuthCAS.class.php b/lib/classes/auth_plugins/StudipAuthCAS.class.php
index 59faaf667bcbdd06a5467d7f3906b85bea5d5d7f..29deb75bfc7d8a3eca93285d774bbb6edeee5fcd 100644
--- a/lib/classes/auth_plugins/StudipAuthCAS.class.php
+++ b/lib/classes/auth_plugins/StudipAuthCAS.class.php
@@ -70,7 +70,7 @@ class StudipAuthCAS extends StudipAuthSSO
     {
         $userdataclassname = $this->user_data_mapping_class;
         if (!class_exists($userdataclassname)) {
-            Log::ERROR($this->plugin_name . ': no userdataclassname specified or found.');
+            Log::error($this->plugin_name . ': no userdataclassname specified or found.');
             return;
         }
         // get the userdata
diff --git a/lib/cronjobs/check_admission.class.php b/lib/cronjobs/check_admission.class.php
index cac69a5789dce70574a1593e7e254de54a034607..dfd493cfbb8c1c52b1c3ff050b96566f21d60677 100644
--- a/lib/cronjobs/check_admission.class.php
+++ b/lib/cronjobs/check_admission.class.php
@@ -1,4 +1,8 @@
 <?php
+
+use Monolog\Logger;
+use Monolog\Handler\StreamHandler;
+
 /**
 * check_admission.class.php
 *
@@ -64,16 +68,19 @@ class CheckAdmissionJob extends CronJob
         if (count($sets) > 0) {
             if ($verbose) {
                 echo date('r') . ' - Starting seat distribution ' . chr(10);
-                $old_logger = Log::get()->getHandler();
-                $old_log_level = Log::get()->getLogLevel();
-                @mkdir($GLOBALS['TMP_PATH'] . '/seat_distribution_logs');
-                $logfile = $GLOBALS['TMP_PATH'] . '/seat_distribution_logs/' .  date('Y-m-d-H-i') . '_seat_distribution.log';
-                if (is_dir($GLOBALS['TMP_PATH'] . '/seat_distribution_logs')) {
-                    Log::get()->setHandler($logfile);
-                    Log::get()->setLogLevel(Log::DEBUG);
+
+                $oldLogger = Log::getInstance();
+                $logdir = $GLOBALS['TMP_PATH'] . '/seat_distribution_logs';
+                @mkdir($logdir);
+                $logfile = $logdir . '/' .  date('Y-m-d-H-i') . '_seat_distribution.log';
+
+                if (is_dir($logdir)) {
+                    Log::setInstance(
+                        new Logger('seat-distributions', [new StreamHandler($logfile, Logger::DEBUG)])
+                    );
                     echo 'logging to ' . $logfile . chr(10);
                 } else {
-                    echo 'could not create directory ' . $GLOBALS['TMP_PATH'] . '/seat_distribution_logs' . chr(10);
+                    echo 'could not create directory ' . $logdir . chr(10);
                 }
             }
             $i = 0;
@@ -129,8 +136,7 @@ class CheckAdmissionJob extends CronJob
                 }
             }
             if ($verbose) {
-                Log::get()->setHandler($old_logger);
-                Log::get()->setLogLevel($old_log_level);
+                Log::setInstance($oldLogger);
             }
         } else {
             if ($verbose) {
diff --git a/lib/models/Course.class.php b/lib/models/Course.class.php
index 10969a4a877962a8fe490d9e025051064c3b25fa..4500daa59e8e18ac6fe4651a6536f43ca364aaff 100644
--- a/lib/models/Course.class.php
+++ b/lib/models/Course.class.php
@@ -521,7 +521,7 @@ class Course extends SimpleORMap implements Range, PrivacyObject, StudipItem, Fe
             return $semTypes[$this->status];
         }
 
-        Log::ERROR(sprintf('SemType not found id:%s status:%s', $this->id, $this->status));
+        Log::error(sprintf('SemType not found id:%s status:%s', $this->id, $this->status));
         return new SemType(['name' => 'Fehlerhafter Veranstaltungstyp']);
     }