Create separate log for database events

Breaking: The option `[logger.file]` has been renamed to `[logger.filename]` for consistency.
This commit is contained in:
Florine W. Dekker 2023-03-20 13:55:31 +01:00
parent f43c59c681
commit 80835d6a08
Signed by: FWDekker
GPG Key ID: D3DCFAA8A4560BE0
11 changed files with 71 additions and 38 deletions

View File

@ -17,7 +17,7 @@ This tool regularly checks if people are still alive according to Wikipedia, and
* [npm](https://www.npmjs.com/)
### Setting up
Install the latest dependencies.
Install the dependencies.
Run this after cloning the repo, and each time after pulling new commits.
```shell
composer.phar install
@ -87,10 +87,12 @@ For example, you can add the following lines to your crontab (e.g. using `sudo -
Replace `secret_password` with the password you configured in `config.ini.php`.
### Logs
It is recommended to also use a tool such as `newsyslog` to manage log rotation.
It is recommended to also use a tool such as
[`newsyslog`](https://man.freebsd.org/cgi/man.cgi?query=newsyslog.conf&sektion=5) to manage log rotation.
For example, create the file `/etc/newsyslog.conf.d/death-notifier.conf` with the following contents:
```
/var/www/death-notifier/.death-notifier.log www:www 644 7 * @T00 JpE
/var/www/death-notifier/.death-notifier.log www:www 600 7 * @T00 JE
/var/www/death-notifier/.death-notifier.db.log www:www 600 7 * $W0D23 JpE
```
### Initialize

View File

@ -1,7 +1,7 @@
{
"name": "fwdekker/death-notifier",
"description": "Get notified when a famous person dies.",
"version": "1.0.1", "_comment_version": "Also update version in `package.json`!",
"version": "1.1.0", "_comment_version": "Also update version in `package.json`!",
"type": "project",
"license": "MIT",
"homepage": "https://git.fwdekker.com/tools/death-notifier",

BIN
composer.lock generated

Binary file not shown.

BIN
package-lock.json generated

Binary file not shown.

View File

@ -1,6 +1,6 @@
{
"name": "death-notifier",
"version": "1.0.1", "_comment_version": "Also update version in `composer.json`!",
"version": "1.1.0", "_comment_version": "Also update version in `composer.json`!",
"description": "Get notified when a famous person dies.",
"author": "Florine W. Dekker",
"browser": "dist/bundle.js",

View File

@ -36,7 +36,7 @@ use com\fwdekker\deathnotifier\Util;
require_once __DIR__ . "/.vendor/autoload.php";
$logger = LoggerUtil::with_name();
$logger = LoggerUtil::with_name(); // This also registers error handler
// Wrap everything in try-catch to always return *something* to user

View File

@ -5,13 +5,19 @@
cli_password = REPLACE THIS WITH A SECRET VALUE
[database]
# Relative path to SQLite database.
# File to store SQLite database in.
filename = .death-notifier.db
[logger]
# File to store logs in.
file = .death-notifier.log
# Log level. See https://seldaek.github.io/monolog/doc/01-usage.html#log-levels
# File to store general logs in.
filename = .death-notifier.log
# Log level for general log events. See https://seldaek.github.io/monolog/doc/01-usage.html#log-levels
level = 250
[logger_db]
# File to store database logs in.
filename = .death-notifier.db.log
# Log level for database log events. See https://seldaek.github.io/monolog/doc/01-usage.html#log-levels
level = 250
[mail]

View File

@ -24,7 +24,7 @@ class Database
/**
* @var Logger the logger to use for logging
*/
private readonly Logger $logger;
private readonly Logger $db_logger;
/**
* @var PDO the PDO object that connects to the database
@ -39,7 +39,7 @@ class Database
*/
public function __construct(string $filename)
{
$this->logger = LoggerUtil::with_name($this::class);
$this->db_logger = LoggerUtil::db_with_name($this::class);
$this->conn = new PDO("sqlite:$filename", options: array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
$this->conn->exec("PRAGMA foreign_keys = ON;");
@ -64,7 +64,7 @@ class Database
if ($stmt->fetch()[0] !== 0)
return;
$this->logger->notice("Database does not exist. Installing new database.");
$this->db_logger->notice("Database does not exist. Installing new database.");
// Create `meta` table
$this->conn->exec("CREATE TABLE meta(k TEXT NOT NULL UNIQUE PRIMARY KEY, v TEXT);");
@ -77,7 +77,7 @@ class Database
$user_list->install();
$tracking_list->install();
$this->logger->notice("Installation complete.");
$this->db_logger->notice("Installation complete.");
});
}
@ -96,7 +96,7 @@ class Database
if (Comparator::greaterThanOrEqualTo($db_version, Database::LATEST_VERSION))
return;
$this->logger->notice("Current db is v$db_version. Will migrate to v" . Database::LATEST_VERSION . ".");
$this->db_logger->notice("Current db is v$db_version. Will migrate to v" . Database::LATEST_VERSION . ".");
// Get current version
$stmt = $this->conn->prepare("SELECT v FROM meta WHERE k='version';");
@ -115,7 +115,7 @@ class Database
$stmt->bindValue(":version", Database::LATEST_VERSION);
$stmt->execute();
$this->logger->notice("Completed migration to v" . Database::LATEST_VERSION . ".");
$this->db_logger->notice("Completed migration to v" . Database::LATEST_VERSION . ".");
});
}
@ -127,7 +127,7 @@ class Database
*/
private function migrate_0_5_0(): void
{
$this->logger->notice("Migrating to v0.5.0.");
$this->db_logger->notice("Migrating to v0.5.0.");
$this->conn->exec("ALTER TABLE users
ADD COLUMN email_notifications_enabled INT NOT NULL DEFAULT(1);");
@ -141,7 +141,7 @@ class Database
*/
private function migrate_0_8_0(): void
{
$this->logger->notice("Migrating to v0.8.0.");
$this->db_logger->notice("Migrating to v0.8.0.");
$this->conn->exec("CREATE TABLE new_email_tasks(type TEXT NOT NULL,
recipient TEXT NOT NULL,
@ -163,7 +163,7 @@ class Database
*/
private function migrate_0_10_0(): void
{
$this->logger->notice("Migrating to v0.10.0.");
$this->db_logger->notice("Migrating to v0.10.0.");
$this->conn->exec("CREATE TABLE new_email_tasks(type TEXT NOT NULL,
recipient TEXT NOT NULL,
@ -188,7 +188,7 @@ class Database
*/
private function migrate_0_16_0(): void
{
$this->logger->notice("Migrating to v0.16.0.");
$this->db_logger->notice("Migrating to v0.16.0.");
$this->conn->exec("DROP TABLE email_tasks;");
$this->conn->exec("CREATE TABLE email_tasks(type_key TEXT NOT NULL,
@ -206,7 +206,7 @@ class Database
*/
private function migrate_0_18_0(): void
{
$this->logger->notice("Migrating to v0.18.0.");
$this->db_logger->notice("Migrating to v0.18.0.");
$this->conn->exec("CREATE TABLE new_trackings(user_uuid TEXT NOT NULL,
person_name TEXT NOT NULL,

View File

@ -15,28 +15,49 @@ use Monolog\Logger;
class LoggerUtil
{
/**
* @var Logger|null the main logger instance that other loggers are derived from, or `null` if the main logger has
* not been created yet
* @var Logger|null the logger instance for general log events not covered by other loggers
*/
private static ?Logger $main_logger = null;
private static ?Logger $general_logger = null;
/**
* @var Logger|null the logger instance for database log events
*/
private static ?Logger $db_logger = null;
/**
* Returns a logger with the given name.
* Returns a general logger with the given name.
*
* @param string $name the name of the logger to return
* @return Logger a logger with the given name
* @param string $name the name of the general logger to return
* @return Logger a general logger with the given name
*/
public static function with_name(string $name = "main"): Logger
public static function with_name(string $name = "general"): Logger
{
if (self::$main_logger === null) {
if (self::$general_logger === null) {
$config = Config::get("logger");
self::$main_logger = new Logger("main");
self::$main_logger->pushHandler(new StreamHandler($config["file"], $config["level"]));
ErrorHandler::register(self::$main_logger);
self::$general_logger = new Logger("general");
self::$general_logger->pushHandler(new StreamHandler($config["filename"], $config["level"]));
ErrorHandler::register(self::$general_logger);
}
return self::$main_logger->withName($name);
return self::$general_logger->withName($name);
}
/**
* Returns a database logger with the given name.
*
* @param string $name the name of the database logger to return
* @return Logger a database logger with the given name
*/
public static function db_with_name(string $name = "database"): Logger
{
if (self::$db_logger === null) {
$config = Config::get("logger_db");
self::$db_logger = new Logger("general");
self::$db_logger->pushHandler(new StreamHandler($config["filename"], $config["level"]));
}
return self::$db_logger->withName($name);
}
}

View File

@ -31,6 +31,10 @@ class UpdateTrackingsAction extends Action
* @var Logger the logger to log with
*/
private readonly Logger $logger;
/**
* @var Logger the database logger to log with
*/
private readonly Logger $db_logger;
/**
* @var TrackingList the list of trackings to update
*/
@ -55,6 +59,7 @@ class UpdateTrackingsAction extends Action
public function __construct(TrackingList $tracking_list, Wikipedia $wikipedia, EmailQueue $mailer)
{
$this->logger = LoggerUtil::with_name($this::class);
$this->db_logger = LoggerUtil::db_with_name($this::class);
$this->tracking_list = $tracking_list;
$this->wikipedia = $wikipedia;
$this->mailer = $mailer;
@ -105,21 +110,20 @@ class UpdateTrackingsAction extends Action
// Send mails, log events
// TODO: Restrict number of notifications to 1 per hour (excluding "oops we're not sure" message)
// TODO: Wait for some time after person has been marked as dead before sending the email
$logger = LoggerUtil::with_name($this::class);
$emails = [];
$person_names = $new_deletions + $new_undeletions + array_keys($new_status_changes);
$trackers = $this->tracking_list->list_trackers($person_names);
foreach ($new_deletions as $new_deletion) {
$logger->notice("Deleted article $new_deletion.");
$this->db_logger->notice("Deleted article $new_deletion.");
foreach ($trackers[$new_deletion] as $user_email)
$emails[] = new NotifyArticleDeletedEmail($user_email, $new_deletion);
}
foreach ($new_undeletions as $new_undeletion) {
$logger->notice("Undeleted article $new_undeletion.");
$this->db_logger->notice("Undeleted article $new_undeletion.");
foreach ($trackers[$new_undeletion] as $user_email)
$emails[] = new NotifyArticleUndeletedEmail($user_email, $new_undeletion);
@ -127,7 +131,7 @@ class UpdateTrackingsAction extends Action
foreach ($new_status_changes as $person_name => $person_status) {
if ($person_status === PersonStatus::Alive)
$logger->notice("Person $person_name is now alive again.");
$this->db_logger->notice("Person $person_name is now alive again.");
foreach ($trackers[$person_name] as $user_email)
$emails[] = new NotifyStatusChangedEmail($user_email, $person_name, $person_status->value);

View File

@ -1,6 +1,6 @@
<?php
namespace com\fwdekker\deathnotifier\validation;
namespace com\fwdekker\deathnotifier;
use com\fwdekker\deathnotifier\Config;
use PHPUnit\Framework\TestCase;