diff --git a/cluebot-ng.config.php b/cluebot-ng.config.php index 7f16692..845b0a7 100644 --- a/cluebot-ng.config.php +++ b/cluebot-ng.config.php @@ -48,7 +48,6 @@ class Config public static $cb_redis_port = 6379; public static $cb_redis_db = 1; public static $cb_redis_pass = ''; - public static $metrics_enabled = true; public static $metrics_port = 9095; // Bots which are spikey in changes and have very large edit counts public static $bot_whitelist = ['InternetArchiveBot', 'AnomieBOT', 'Jevansen']; @@ -83,10 +82,6 @@ public static function init() self::$mw_mysql_credentials = json_decode($mysql_credentials, true); } - if ($metrics_enabled = getenv('CBNG_METRICS_ENABLED')) { - self::$metrics_enabled = $metrics_enabled === 'true'; - } - if ($port = getenv('CBNG_METRICS_PORT')) { self::$metrics_port = (int) $port; } diff --git a/cluebot-ng.php b/cluebot-ng.php index 558c845..f2e0087 100644 --- a/cluebot-ng.php +++ b/cluebot-ng.php @@ -55,9 +55,7 @@ date_default_timezone_set('UTC'); doInit(); -if (Config::$metrics_enabled) { - MetricServer::run(); -} +MetricServer::run(); HttpFeed::stream(); $logger->info('Waiting for ' . Process::pendingChangesTotal() . ' pending changes'); diff --git a/http_feed_functions.php b/http_feed_functions.php index a5afc5d..3c56529 100644 --- a/http_feed_functions.php +++ b/http_feed_functions.php @@ -173,13 +173,13 @@ private static function process($event) { global $logger; - Metrics::increment('bot_stream_events_received_total', [$event['type'] ?? 'unknown']); + Metrics::increment('bot_stream_events_received_total', [$event['type']]); // Skip these types, they don't directly have revisions, no point spending time constructing // an artificial url to throw them away in the namespace check later. - if ($event['type'] === 'log') { + if (in_array($event['type'], ['log', 'categorize', 'external'])) { $logger->debug('Skipping due to event type: ' . print_r($event, true)); - Metrics::increment('bot_stream_events_skipped_total', ['event_type_log']); + Metrics::increment('bot_stream_events_skipped_total', [$event['type']]); return; } @@ -239,7 +239,7 @@ private static function process($event) $old_revid = $parsedUrlParams['oldid'] ?? 0; } else { $logger->error('Could not determine revision IDs for event: ' . print_r($event, true)); - Metrics::increment('bot_stream_events_skipped_total', ['no_revision_ids']); + Metrics::increment('bot_stream_events_failed_parsing_total'); return; } } diff --git a/metric_functions.php b/metric_functions.php index 782b24b..2e2a4d6 100644 --- a/metric_functions.php +++ b/metric_functions.php @@ -40,17 +40,24 @@ public static function init($seedMetrics = true): void self::registerCounter( 'bot_warnings_issued_total', 'Total warnings issued by level', - ['level'] + ['level'], + [['1'], ['2'], ['3']] ); self::registerCounter( 'bot_stream_events_received_total', 'Total events received from the MediaWiki EventStream', - ['event_type'] + ['event_type'], + ['edit', 'new', 'log', 'categorize', 'external'] ); self::registerCounter( 'bot_stream_events_skipped_total', 'Total events skipped at the stream level', - ['reason'] + ['event_type'], + ['log', 'categorize', 'external'] + ); + self::registerCounter( + 'bot_stream_events_failed_parsing_total', + 'Total events which could not be parsed', ); self::registerCounter( 'bot_edits_received_total', @@ -105,7 +112,19 @@ public static function init($seedMetrics = true): void self::registerCounter( 'bot_revert_decisions_total', 'Total revert decisions made', - ['decision', 'reason'] + ['decision', 'reason'], + [ + ['no', 'Run disabled'], + ['no', 'User is myself'], + ['no', 'Exclusion compliance'], + ['no', 'User is creator'], + ['no', 'User has edit count'], + ['no', 'Reverted before'], + ['yes', 'Angry-reverting on TFA'], + ['yes', 'Angry-reverting on angry-optin'], + ['yes', 'User has edit count, but warns > 10%'], + ['yes', 'Default revert'], + ] ); self::registerCounter( 'bot_reverts_attempted_total', @@ -125,17 +144,47 @@ public static function init($seedMetrics = true): void self::registerCounter( 'bot_reverts_skipped_total', 'Total reverts skipped', - ['reason'] + ['reason'], + [ + ['missing_revisions'], + ['previous_revisions_by_user'], + ['own_account'], + ['friends_account'], + ] ); self::registerCounter( 'bot_mysql_mw_query_failures_total', 'Total replica MySQL query failures', - ['query', 'reason'] + ['query', 'reason'], + [ + ['page_metadata', 'no_data'], + ['page_metadata', 'timeout'], + ['page_metadata', 'error'], + ['page_recent_edits', 'no_data'], + ['page_recent_edits', 'timeout'], + ['page_recent_edits', 'error'], + ['page_recent_reverts', 'no_data'], + ['page_recent_reverts', 'timeout'], + ['page_recent_reverts', 'error'], + ['user_registration', 'no_data'], + ['user_registration', 'timeout'], + ['user_registration', 'error'], + ['user_registration_via_revision', 'no_data'], + ['user_registration_via_revision', 'timeout'], + ['user_registration_via_revision'], + ['user_warnings_count', 'no_data'], + ['user_warnings_count', 'timeout'], + ['user_warnings_count', 'error'], + ['user_distinct_pages', 'no_data'], + ['user_distinct_pages', 'timeout'], + ['user_distinct_pages', 'error'], + ] ); self::registerCounter( 'bot_mysql_mw_credential_conn_limit_total', 'Total times a replica MySQL credential hit its connection limit', - ['user'] + ['user'], + array_map(fn($cred) => [$cred['user']], Config::$mw_mysql_credentials) ); self::registerCounter( 'bot_mysql_mw_connection_retries_total', @@ -153,14 +202,26 @@ public static function init($seedMetrics = true): void [] ); self::registerCounter( - 'bot_mysql_cb_query_failures_total', - 'Total ClueBot MySQL query failures', - ['query'] + 'bot_mysql_cb_query_total', + 'Total ClueBot MySQL queries', + ['query'], + [ + ['vandalism_insert'], + ['vandalism_update_reverted'], + ['vandalism_update_beaten'], + ['beaten_insert'], + ] ); self::registerCounter( - 'bot_redis_operation_failures_total', - 'Total Redis operation failures', - ['operation'] + 'bot_mysql_cb_query_failures_total', + 'Total ClueBot MySQL query failures', + ['query'], + [ + ['vandalism_insert'], + ['vandalism_update_reverted'], + ['vandalism_update_beaten'], + ['beaten_insert'], + ] ); // Gauges @@ -217,9 +278,6 @@ public static function init($seedMetrics = true): void private static function seedMetricsStore(): void { global $logger; - if (!Config::$metrics_enabled) { - return; - } try { @self::registry()->wipeStorage(); } catch (\Throwable $e) { @@ -227,29 +285,38 @@ private static function seedMetricsStore(): void $logger->debug('Failed to wipe metrics storage: ' . $e->getMessage()); } foreach (self::$definitions as $metric_name => $definition) { - if (!empty($definition['labels'])) { - continue; - } - try { - if ($definition['type'] === 'counter') { - @self::registry() - ->getOrRegisterCounter('cbng', $metric_name, $definition['help'], $definition['labels']) - ->incBy(0, []); - } elseif ($definition['type'] === 'gauge') { - @self::registry() - ->getOrRegisterGauge('cbng', $metric_name, $definition['help'], $definition['labels']) - ->set(0, []); + $labelValueSets = empty($definition['labels']) ? [[]] : ($definition['seed'] ?? []); + foreach ($labelValueSets as $labelValues) { + try { + if ($definition['type'] === 'counter') { + @self::registry() + ->getOrRegisterCounter('cbng', $metric_name, $definition['help'], $definition['labels']) + ->incBy(0, $labelValues); + } elseif ($definition['type'] === 'gauge') { + @self::registry() + ->getOrRegisterGauge('cbng', $metric_name, $definition['help'], $definition['labels']) + ->set(0, $labelValues); + } + } catch (\Throwable $e) { + self::$registry = null; + $logger->debug('Failed to seed ' . $metric_name . ': ' . $e->getMessage()); } - } catch (\Throwable $e) { - self::$registry = null; - $logger->debug('Failed to seed ' . $metric_name . ': ' . $e->getMessage()); } } } - private static function registerCounter(string $name, string $help, array $labelNames): void - { - self::$definitions[$name] = ['type' => 'counter', 'help' => $help, 'labels' => $labelNames]; + private static function registerCounter( + string $name, + string $help, + array $labelNames, + array $seedLabelValues = [] + ): void { + self::$definitions[$name] = [ + 'type' => 'counter', + 'help' => $help, + 'labels' => $labelNames, + 'seed' => $seedLabelValues, + ]; } private static function registerGauge(string $name, string $help, array $labelNames): void @@ -294,9 +361,6 @@ public static function getMetricFamilySamples() public static function increment(string $name, array $labelValues = []): void { global $logger; - if (!Config::$metrics_enabled) { - return; - } $definition = self::$definitions[$name] ?? null; if ($definition === null) { $logger->warning("Unknown metric: $name"); @@ -315,9 +379,6 @@ public static function increment(string $name, array $labelValues = []): void public static function set(string $name, float $value, array $labelValues = []): void { global $logger; - if (!Config::$metrics_enabled) { - return; - } $definition = self::$definitions[$name] ?? null; if ($definition === null) { $logger->warning("Unknown metric: $name"); @@ -336,9 +397,6 @@ public static function set(string $name, float $value, array $labelValues = []): public static function observe(string $name, float $value, array $labelValues = []): void { global $logger; - if (!Config::$metrics_enabled) { - return; - } $definition = self::$definitions[$name] ?? null; if ($definition === null) { $logger->warning("Unknown metric: $name");