Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
3c74ee9
Introducing monitoring
BentiGorlich Jan 14, 2026
0441809
Add filtering, fix some things
BentiGorlich Jan 21, 2026
047cef9
Move to First-In-Last-Out for the twig renders
BentiGorlich Jan 21, 2026
5a0f5cd
Remove control characters from the query parameters
BentiGorlich Jan 21, 2026
e67a541
Swap the property in which the message class is back
BentiGorlich Jan 21, 2026
03d3fb2
End execution context on kernel termination
BentiGorlich Jan 21, 2026
780f98a
Add response sending time to requests
BentiGorlich Jan 21, 2026
bd1a226
Add response sending time to requests
BentiGorlich Jan 21, 2026
3289d42
Space optimizations, more filtering
BentiGorlich Jan 28, 2026
57be742
Fix exception due to routing failing
BentiGorlich Jan 30, 2026
d9858e8
Fix min duration filter not working
BentiGorlich Feb 4, 2026
56fad25
Add more monitoring options
BentiGorlich Feb 17, 2026
4336f27
Fix messages.en.yaml
BentiGorlich Feb 17, 2026
ee7d00a
Remove unnecessary escaping (triggered deprecation)
BentiGorlich Feb 18, 2026
b496acc
Merge branch 'main' into new/monitoring
BentiGorlich Feb 22, 2026
063d684
Add some documentation
BentiGorlich Feb 22, 2026
6491849
Adapt docs, add command to delete monitoring data
BentiGorlich Feb 24, 2026
8fedc31
Show hint at admin page if monitoring is disabled
BentiGorlich Feb 24, 2026
29a7b89
Add docs for the new command
BentiGorlich Mar 3, 2026
dc21c6e
Merge branch 'main' into new/monitoring
BentiGorlich Mar 3, 2026
831f6c5
Move command docs to miscellaneous
BentiGorlich Mar 4, 2026
51619e9
Merge branch 'main' into new/monitoring
BentiGorlich Mar 4, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,27 @@ MBIN_SIDEBAR_SECTIONS_USERS_LOCAL_ONLY=false
# Captcha (also enable in admin panel/settings)
KBIN_CAPTCHA_ENABLED=false

### mbin-monitoring: enabling monitoring can give great insights into performance bottlenecks,
### however it is only useful for advanced users.
### Enabling the persistance of queries, twig or curl requests can lead to a significant size increase of the DB.
# Whether requests and messages should be monitored for performance. If enabled this could impact performance.
# If this is set to false the other monitoring settings do not matter.
MBIN_MONITORING_ENABLED=false
# Whether to monitor query execution, defaults to true
MBIN_MONITORING_QUERIES_ENABLED=true
# Whether the monitored queries are persisted to the database. If this is disabled only the total query time will be persisted.
MBIN_MONITORING_QUERY_PERSISTING_ENABLED=false
# Whether the parameter of database queries should be saved. If enabled the spaces used might increase a lot.
MBIN_MONITORING_QUERY_PARAMETERS_ENABLED=false
# Whether to monitor twig rendering, defaults to true
MBIN_MONITORING_TWIG_RENDERS_ENABLED=true
# Whether to persist the monitored twig renders. If this is disabled only the total rendering time will be persisted.
MBIN_MONITORING_TWIG_RENDER_PERSISTING_ENABLED=false
# Whether to monitor curl requests, defaults to true
MBIN_MONITORING_CURL_REQUESTS_ENABLED=true
# Whether to persist the monitored curl requests. If this is disabled only total request time will be persisted.
MBIN_MONITORING_CURL_REQUEST_PERSISTING_ENABLED=false

###> meteo-concept/hcaptcha-bundle ###
HCAPTCHA_SITE_KEY=
HCAPTCHA_SECRET=
Expand Down
21 changes: 21 additions & 0 deletions .env.example_docker
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,27 @@ MBIN_SIDEBAR_SECTIONS_USERS_LOCAL_ONLY=false
# Captcha (also enable in admin panel/settings)
KBIN_CAPTCHA_ENABLED=false

### mbin-monitoring: enabling monitoring can give great insights into performance bottlenecks,
### however it is only useful for advanced users.
### Enabling the persistance of queries, twig or curl requests can lead to a significant size increase of the DB.
# Whether requests and messages should be monitored for performance. If enabled this could impact performance.
# If this is set to false the other monitoring settings do not matter.
MBIN_MONITORING_ENABLED=false
# Whether to monitor query execution, defaults to true
MBIN_MONITORING_QUERIES_ENABLED=true
# Whether the monitored queries are persisted to the database. If this is disabled only the total query time will be persisted.
MBIN_MONITORING_QUERY_PERSISTING_ENABLED=false
# Whether the parameter of database queries should be saved. If enabled the spaces used might increase a lot.
MBIN_MONITORING_QUERY_PARAMETERS_ENABLED=false
# Whether to monitor twig rendering, defaults to true
MBIN_MONITORING_TWIG_RENDERS_ENABLED=true
# Whether to persist the monitored twig renders. If this is disabled only the total rendering time will be persisted.
MBIN_MONITORING_TWIG_RENDER_PERSISTING_ENABLED=false
# Whether to monitor curl requests, defaults to true
MBIN_MONITORING_CURL_REQUESTS_ENABLED=true
# Whether to persist the monitored curl requests. If this is disabled only total request time will be persisted.
MBIN_MONITORING_CURL_REQUEST_PERSISTING_ENABLED=false

###> meteo-concept/hcaptcha-bundle ###
HCAPTCHA_SITE_KEY=
HCAPTCHA_SECRET=
Expand Down
1 change: 1 addition & 0 deletions assets/styles/app.scss
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
@use 'components/suggestions';
@use 'components/login';
@use 'components/modlog';
@use 'components/monitoring';
@use 'components/notification_switch';
@use 'components/notifications';
@use 'components/messages';
Expand Down
73 changes: 73 additions & 0 deletions assets/styles/components/_monitoring.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
.page-admin-monitoring {
h1, h2, h3, h4, h5, h6 {
margin-top: 0;
}
.monitoring-twig-render {
.children {
margin-left: 2rem;
}
}

.more {
background: var(--kbin-bg);
cursor: pointer;
text-align: center;
width: 100%;
margin-top: 1rem;

// bigger button for touch devices
@media (pointer:none), (pointer:coarse) {
margin-top: 2rem;
padding: 0.5rem;
}

i {
padding: .35rem;
pointer-events: none;
}

.rounded-edges & {
border-radius: var(--kbin-rounded-edges-radius);
}
}

input[type=text],
input[type=datetime-local],
select {
padding: 0.65rem;
width: 100%;
}

form div {
margin-bottom: .25rem;
}

table tr {
vertical-align: top;
td.query * {
margin: 0;
overflow: hidden;
}
}

.row {
display: flex;
flex-direction: row;

.col {
flex: 1 1;
margin-bottom: 0;
padding: 0 .25rem;
}

.col-auto {
flex: 0 0 auto;
margin-bottom: 0;
}

.btn-col {
text-align: right;
margin: auto;
}
}
}
11 changes: 11 additions & 0 deletions config/mbin_routes/admin.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,17 @@ admin_cc:
path: /admin/cc
methods: [GET]

admin_monitoring:
controller: App\Controller\Admin\AdminMonitoringController::overview
path: /admin/monitoring
methods: [GET]

admin_monitoring_single_context:
controller: App\Controller\Admin\AdminMonitoringController::single
defaults: { page: overview }
path: /admin/monitoring/{id}/{page}
methods: [GET]

admin_dashboard:
controller: App\Controller\Admin\AdminDashboardController
path: /admin/{statsPeriod}/{withFederated}
Expand Down
18 changes: 18 additions & 0 deletions config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,16 @@ parameters:
mbin_new_users_need_approval: '%env(bool:default::MBIN_NEW_USERS_NEED_APPROVAL)%'
mbin_use_federation_allow_list: '%env(bool:default::MBIN_USE_FEDERATION_ALLOW_LIST)%'

trueVal: 'true'
mbin_monitoring_enabled: '%env(bool:default::MBIN_MONITORING_ENABLED)%'
mbin_monitoring_query_parameters_enabled: '%env(bool:default::MBIN_MONITORING_QUERY_PARAMETERS_ENABLED)%'
mbin_monitoring_queries_enabled: '%env(bool:default:trueVal:MBIN_MONITORING_QUERIES_ENABLED)%'
mbin_monitoring_query_persisting_enabled: '%env(bool:default::MBIN_MONITORING_QUERY_PERSISTING_ENABLED)%'
mbin_monitoring_twig_renders_enabled: '%env(bool:default:trueVal:MBIN_MONITORING_TWIG_RENDERS_ENABLED)%'
mbin_monitoring_twig_render_persisting_enabled: '%env(bool:default::MBIN_MONITORING_TWIG_RENDER_PERSISTING_ENABLED)%'
mbin_monitoring_curl_requests_enabled: '%env(bool:default:trueVal:MBIN_MONITORING_CURL_REQUESTS_ENABLED)%'
mbin_monitoring_curl_request_persisting_enabled: '%env(bool:default::MBIN_MONITORING_CURL_REQUEST_PERSISTING_ENABLED)%'

services:
# default configuration for services in *this* file
_defaults:
Expand All @@ -138,6 +148,14 @@ services:
$kbinApiItemsPerPage: '%kbin_api_items_per_page%'
$storageUrl: '%kbin_storage_url%'
$publicDir: '%kernel.project_dir%/public'
$monitoringEnabled: '%mbin_monitoring_enabled%'
$monitoringQueryParametersEnabled: '%mbin_monitoring_query_parameters_enabled%'
$monitoringQueriesEnabled: '%mbin_monitoring_queries_enabled%'
$monitoringQueriesPersistingEnabled: '%mbin_monitoring_query_persisting_enabled%'
$monitoringTwigRendersEnabled: '%mbin_monitoring_twig_renders_enabled%'
$monitoringTwigRendersPersistingEnabled: '%mbin_monitoring_twig_render_persisting_enabled%'
$monitoringCurlRequestsEnabled: '%mbin_monitoring_curl_requests_enabled%'
$monitoringCurlRequestPersistingEnabled: '%mbin_monitoring_curl_request_persisting_enabled%'

kbin.s3_client:
class: Aws\S3\S3Client
Expand Down
46 changes: 46 additions & 0 deletions docs/02-admin/03-optional-features/08-monitoring.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Internal Mbin Monitoring

We have a few environment variables that can enable monitoring of the mbin server,
specifically the executed database queries, rendered html components and requested web resources during the execution of
an HTTP request or a message handler (a background job).
Comment thread
blued-gear marked this conversation as resolved.
This allows the admin to collect performance metrics for optimizing the server settings,
or developers to optimize the code.

Enabling monitoring on your server will have a performance impact. It is not necessarily noticeable for your users,
but it will increase the resource consumption.
During an execution context (request or messenger) the server will collect monitoring information according to your settings.
After the execution is finished the collected information will be saved to the DB according to your settings
(which is the main performance impact and happens after a request is finished).

The available settings are:
- `MBIN_MONITORING_ENABLED`: Whether monitoring is enabled at all, if `false` then the other settings do not matter
- `MBIN_MONITORING_QUERIES_ENABLED`: Whether to monitor query execution, defaults to true
- `MBIN_MONITORING_QUERY_PERSISTING_ENABLED`: Whether the monitored queries are persisted to the database. If this is disabled only the total query time will be persisted.
- `MBIN_MONITORING_QUERY_PARAMETERS_ENABLED`: Whether the parameter of database queries should be saved. If enabled the spaces used might increase a lot.
- `MBIN_MONITORING_TWIG_RENDERS_ENABLED`: Whether to monitor twig rendering, defaults to true
- `MBIN_MONITORING_TWIG_RENDER_PERSISTING_ENABLED`: Whether to persist the monitored twig renders. If this is disabled only the total rendering time will be persisted.
- `MBIN_MONITORING_CURL_REQUESTS_ENABLED`: Whether to monitor curl requests, defaults to true
- `MBIN_MONITORING_CURL_REQUEST_PERSISTING_ENABLED`: Whether to persist the monitored curl requests. If this is disabled only total request time will be persisted.

If the monitoring of e.g. queries is enabled, but the persistence is not,
then the execution context will have a total duration of the executed queries,
but you cannot inspect the executed queries.

Depending on your persistence settings the monitoring can take up a lot of space.
The largest amount will come from the queries, then the twig renders and at last the curl requests.

> [!TIP]
> To delete you monitoring data see [cli docs](../04-running-mbin/05-cli.md#delete-monitoring-data).

## UI

At `/admin/monitoring` is the overview of the monitoring. There you can see a chart of the longest taking execution contexts.
Underneath that is a table containing the most recent execution contexts according to your filter settings.
The chart also takes the filter settings into account.

By clicking the alphanumeric string in the first column of the table (part of the GUID of the execution context)
you get to the overview of that context, containing the meta information about this context.

> [!TIP]
> The percentage numbers of "SQL Queries", "Twig Renders" and "Curl Requests" do not necessarily add up to 100% or even below 100%,
> because "Twig Renders" could execute database queries for example.
1 change: 1 addition & 0 deletions docs/02-admin/03-optional-features/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ Like setting-up:
- [Image metadata cleaning](05-image_metadata_cleaning.md) - Clean-up and remove metadata from images using `exiftool`.
- [S3 storage](06-s3_storage.md) - Configure an object storage service (S3) compatible bucket for storing images.
- [Anubis](07-anubis.md) - A service for weighing the incoming requests and may present them with a proof-of-work challenge. It is useful if your instance gets hit a lot of bot traffic that you're tired of filtering through
- [Monitoring](08-monitoring.md) - Internal monitoring of requests and messengers
27 changes: 27 additions & 0 deletions docs/02-admin/04-running-mbin/05-cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,7 @@ Arguments:

## Images


### Remove old federated images

This command allows you to remove old federated images, without removing the content.
Expand Down Expand Up @@ -378,6 +379,32 @@ php bin/console mbin:cache:build

## Miscellaneous

### Delete monitoring data

> [!HINT]
> For information about monitoring see [Optional Features/Monitoring](../03-optional-features/08-monitoring.md).

This command allows you to delete monitoring data according to the passed parameters.

Usage:

```bash
php bin/console mbin:monitoring:delete-data [-a|--all] [--queries] [--twig] [--requests] [--before [BEFORE]]
```

Options:
- `-a`|`--all`: delete all contexts, including all linked data (queries, twig renders and curl requests)
- `--queries`: delete all query data (this is the most space consuming data)
- `--twig`: delete all twig rendering data (this is the second most space consuming data)
- `--requests`: delete all curl request data
- `--before [BEFORE]]`: if you want to limit the data deleted by their creation date, including via the `-a|--all` option. You can pass something like _"now - 1 day"_

As an example you could delete all query data by running
`php bin/console mbin:monitoring:delete-data --queries --before "now - 8 hours"`.
This way you could still view the average request times without the query data for every request older than 8 hours
and the newer requests would not be affected at all. This way you can limit the space consumed by query data.
You can also mix and match the `--queries`, `--twig` and `--requests` options.

### Search for duplicate magazines or users and remove them

This command provides a guided tour to search for, and remove duplicate magazines or users.
Expand Down
55 changes: 55 additions & 0 deletions migrations/Version20260120175744.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

declare(strict_types=1);

namespace DoctrineMigrations;

use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;

final class Version20260120175744 extends AbstractMigration
{
public function getDescription(): string
{
return 'Add initial monitoring tables';
}

public function up(Schema $schema): void
{
$this->addSql('CREATE SEQUENCE monitoring_curl_request_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
$this->addSql('CREATE SEQUENCE monitoring_query_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
$this->addSql('CREATE SEQUENCE monitoring_twig_render_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
$this->addSql('CREATE TABLE monitoring_curl_request (id INT NOT NULL, context_id UUID DEFAULT NULL, url VARCHAR(255) NOT NULL, method VARCHAR(255) NOT NULL, was_successful BOOLEAN NOT NULL, exception VARCHAR(255) DEFAULT NULL, created_at TIMESTAMP(0) WITH TIME ZONE NOT NULL, started_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, started_at_microseconds DOUBLE PRECISION NOT NULL, ended_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, ended_at_microseconds DOUBLE PRECISION NOT NULL, duration_milliseconds DOUBLE PRECISION NOT NULL, PRIMARY KEY(id))');
$this->addSql('CREATE INDEX IDX_19A4B8546B00C1CF ON monitoring_curl_request (context_id)');
$this->addSql('CREATE TABLE monitoring_execution_context (uuid UUID NOT NULL, execution_type VARCHAR(255) NOT NULL, path VARCHAR(255) NOT NULL, handler VARCHAR(255) NOT NULL, user_type VARCHAR(255) NOT NULL, status_code INT DEFAULT NULL, exception VARCHAR(255) DEFAULT NULL, stacktrace VARCHAR(255) DEFAULT NULL, response_sending_duration_milliseconds DOUBLE PRECISION DEFAULT NULL, query_duration_milliseconds DOUBLE PRECISION NOT NULL, twig_render_duration_milliseconds DOUBLE PRECISION NOT NULL, curl_request_duration_milliseconds DOUBLE PRECISION NOT NULL, created_at TIMESTAMP(0) WITH TIME ZONE NOT NULL, started_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, started_at_microseconds DOUBLE PRECISION NOT NULL, ended_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, ended_at_microseconds DOUBLE PRECISION NOT NULL, duration_milliseconds DOUBLE PRECISION NOT NULL, PRIMARY KEY(uuid))');
$this->addSql('CREATE TABLE monitoring_query (id INT NOT NULL, context_id UUID DEFAULT NULL, query_string_id VARCHAR(40) DEFAULT NULL, parameters JSONB DEFAULT NULL, created_at TIMESTAMP(0) WITH TIME ZONE NOT NULL, started_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, started_at_microseconds DOUBLE PRECISION NOT NULL, ended_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, ended_at_microseconds DOUBLE PRECISION NOT NULL, duration_milliseconds DOUBLE PRECISION NOT NULL, PRIMARY KEY(id))');
$this->addSql('CREATE INDEX IDX_760D8AF36B00C1CF ON monitoring_query (context_id)');
$this->addSql('CREATE INDEX IDX_760D8AF3BCAEFD40 ON monitoring_query (query_string_id)');
$this->addSql('CREATE TABLE monitoring_query_string (query_hash VARCHAR(40) NOT NULL, query TEXT NOT NULL, PRIMARY KEY(query_hash))');
$this->addSql('CREATE TABLE monitoring_twig_render (id INT NOT NULL, context_id UUID DEFAULT NULL, parent_id INT DEFAULT NULL, short_description TEXT NOT NULL, template_name VARCHAR(255) DEFAULT NULL, name VARCHAR(255) DEFAULT NULL, type VARCHAR(255) DEFAULT NULL, memory_usage INT DEFAULT NULL, peak_memory_usage INT DEFAULT NULL, profiler_duration DOUBLE PRECISION DEFAULT NULL, created_at TIMESTAMP(0) WITH TIME ZONE NOT NULL, started_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, started_at_microseconds DOUBLE PRECISION NOT NULL, ended_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, ended_at_microseconds DOUBLE PRECISION NOT NULL, duration_milliseconds DOUBLE PRECISION NOT NULL, PRIMARY KEY(id))');
$this->addSql('CREATE INDEX IDX_55BA2A536B00C1CF ON monitoring_twig_render (context_id)');
$this->addSql('CREATE INDEX IDX_55BA2A53727ACA70 ON monitoring_twig_render (parent_id)');
$this->addSql('ALTER TABLE monitoring_curl_request ADD CONSTRAINT FK_19A4B8546B00C1CF FOREIGN KEY (context_id) REFERENCES monitoring_execution_context (uuid) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE monitoring_query ADD CONSTRAINT FK_760D8AF36B00C1CF FOREIGN KEY (context_id) REFERENCES monitoring_execution_context (uuid) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE monitoring_query ADD CONSTRAINT FK_760D8AF3BCAEFD40 FOREIGN KEY (query_string_id) REFERENCES monitoring_query_string (query_hash) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE monitoring_twig_render ADD CONSTRAINT FK_55BA2A536B00C1CF FOREIGN KEY (context_id) REFERENCES monitoring_execution_context (uuid) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE monitoring_twig_render ADD CONSTRAINT FK_55BA2A53727ACA70 FOREIGN KEY (parent_id) REFERENCES monitoring_twig_render (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
}

public function down(Schema $schema): void
{
$this->addSql('DROP SEQUENCE monitoring_curl_request_id_seq CASCADE');
$this->addSql('DROP SEQUENCE monitoring_query_id_seq CASCADE');
$this->addSql('DROP SEQUENCE monitoring_twig_render_id_seq CASCADE');
$this->addSql('ALTER TABLE monitoring_curl_request DROP CONSTRAINT FK_19A4B8546B00C1CF');
$this->addSql('ALTER TABLE monitoring_query DROP CONSTRAINT FK_760D8AF36B00C1CF');
$this->addSql('ALTER TABLE monitoring_query DROP CONSTRAINT FK_760D8AF3BCAEFD40');
$this->addSql('ALTER TABLE monitoring_twig_render DROP CONSTRAINT FK_55BA2A536B00C1CF');
$this->addSql('ALTER TABLE monitoring_twig_render DROP CONSTRAINT FK_55BA2A53727ACA70');
$this->addSql('DROP TABLE monitoring_curl_request');
$this->addSql('DROP TABLE monitoring_execution_context');
$this->addSql('DROP TABLE monitoring_query');
$this->addSql('DROP TABLE monitoring_query_string');
$this->addSql('DROP TABLE monitoring_twig_render');
}
}
Loading
Loading