Row-based cleanup throws 'Unknown column id' — cleanup_by_rows is broken as shipped
**Problem/Motivation** `LoggerDbManager::cleanupDatabase()` implements two retention strategies driven by the settings form: cleanup by age (`cleanup_by_time_enabled`) and cleanup by row count (`cleanup_by_rows_enabled`). The row-based branch queries a column named `id`: ```php $minRowId = $this->connection->select(self::DB_TABLE, 'l') ->fields('l', ['id']) ->orderBy('id', 'DESC') ->range($rows - 1, 1) ->execute() ->fetchField(); if ($minRowId) { $this->connection->delete(self::DB_TABLE) ->condition('id', $minRowId, '<') ->execute(); } ``` But the `logger_logs` table has **no `id` column**. Per `logger_db.install`, the table's primary key is `uuid` and its only fields are `uuid, time, severity, channel, message, data`, with indexes on `time` and `(time, severity)`. As a result, whenever an administrator enables "Cleanup by rows" on the settings form, every cron run throws: ``` SQLSTATE[42S22]: Column not found: 1054 Unknown column 'l.id' in 'field list' ``` The row-cap feature therefore never works, and the exception abort `logger_db_cron()` on each run. **Steps to reproduce** 1. Install logger_db 1.0.0-alpha4 and let some log rows accumulate. 2. Go to the settings form (route `logger_db.settings`), enable **Cleanup by rows**, set a limit, save. 3. Run cron (`drush cron`). 4. Observe the `SQLSTATE … Unknown column 'l.id'` exception; no rows are pruned. **Proposed resolution** Key the "keep newest N rows" logic off the existing `time` column, which is exactly what the age-based branch above it already uses and what the table is indexed for. Select the timestamp of the Nth-most-recent row and delete everything older: ```php $cutoffTime = $this->connection->select(self::DB_TABLE, 'l') ->fields('l', ['time']) ->orderBy('time', 'DESC') ->range($rows - 1, 1) ->execute() ->fetchField(); if ($cutoffTime) { $this->connection->delete(self::DB_TABLE) ->condition('time', $cutoffTime, '<') ->execute(); } ``` This preserves the original intent (delete everything older than the Nth most recent row) using only columns that exist, and reuses the `time` index. **Remaining tasks** - Review MR. **Known limitation (for reviewer)** Ordering the cutoff by `time` rather than a monotonic surrogate key means that when several rows share the same `datetime(6)` timestamp, the `time < :cutoff` delete keeps **all** rows at the boundary timestamp, so the table can retain slightly more than N rows. With microsecond precision this is rare and "keep a few extra log rows" is harmless for a retention cap. A fully deterministic cap would need a `(time, uuid)` tiebreak, which is heavier and arguably overkill for a log table.
issue