invidious-companion-patches/patches/0013-metrics-track-unidentified-innertube-errors.patch
Fijxu a5b522acf2
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 1m0s
add 0020
2025-04-22 17:01:06 -04:00

225 lines
7.6 KiB
Diff
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

From 9621e0ecc940cff15269c31c082cbcacc06ab015 Mon Sep 17 00:00:00 2001
From: Fijxu <fijxu@nadeko.net>
Date: Mon, 14 Apr 2025 01:24:57 -0400
Subject: [PATCH 13/20] metrics: track unidentified innertube errors
---
src/lib/helpers/metrics.ts | 142 +++++++++++++++++++++++++++++--------
1 file changed, 111 insertions(+), 31 deletions(-)
diff --git a/src/lib/helpers/metrics.ts b/src/lib/helpers/metrics.ts
index 5dee540..2464fe7 100644
--- a/src/lib/helpers/metrics.ts
+++ b/src/lib/helpers/metrics.ts
@@ -5,11 +5,16 @@ export class Metrics {
private METRICS_PREFIX = "invidious_companion_";
public register = new Registry();
- public createCounter(name: string, help?: string): Counter {
+ public createCounter(
+ name: string,
+ help?: string,
+ labels?: string[],
+ ): Counter {
return new Counter({
name: `${this.METRICS_PREFIX}${name}`,
help: help || "No help has been provided for this metric",
registers: [this.register],
+ labelNames: Array.isArray(labels) ? labels : [],
});
}
@@ -26,6 +31,7 @@ export class Metrics {
private innertubeErrorStatusUnknown = this.createCounter(
"innertube_error_status_unknown_total",
"Number of times that an unknown status has been returned by Innertube API",
+ ["error"],
);
private innertubeErrorReasonSignIn = this.createCounter(
@@ -41,11 +47,13 @@ export class Metrics {
private innertubeErrorReasonUnknown = this.createCounter(
"innertube_error_reason_unknown_total",
"Number of times that an unknown reason has been returned by the Innertube API",
+ ["error"],
);
private innertubeErrorSubreasonUnknown = this.createCounter(
"innertube_error_subreason_unknown_total",
"Number of times that an unknown subreason has been returned by the Innertube API",
+ ["error"],
);
public innertubeSuccessfulRequest = this.createCounter(
@@ -66,26 +74,70 @@ export class Metrics {
private checkStatus(videoData: IRawResponse) {
const status = videoData.playabilityStatus?.status;
- return {
- unplayable: status ===
- "UNPLAYABLE",
- contentCheckRequired: status ===
- "CONTENT_CHECK_REQUIRED",
- loginRequired: status === "LOGIN_REQUIRED",
+ interface Error {
+ unplayable: boolean;
+ contentCheckRequired: boolean;
+ loginRequired: boolean;
+ unknown: string | undefined;
+ }
+
+ const error: Error = {
+ unplayable: false,
+ contentCheckRequired: false,
+ loginRequired: false,
+ unknown: undefined,
};
+
+ switch (status) {
+ case "UNPLAYABLE":
+ error.unplayable = true;
+ return error;
+ // Sensitive content videos
+ // Example video id: `VuSU7PcEKpU`
+ case "CONTENT_CHECK_REQUIRED":
+ error.contentCheckRequired = true;
+ return error;
+ case "LOGIN_REQUIRED":
+ error.loginRequired = true;
+ return error;
+ default:
+ error.unknown = status;
+ return error;
+ }
}
private checkReason(videoData: IRawResponse) {
- const reason = videoData.playabilityStatus?.reason;
-
- return {
- signInToConfirmAge: reason?.includes(
- "Sign in to confirm your age",
- ),
- SignInToConfirmBot: reason?.includes(
- "Sign in to confirm youre not a bot",
- ),
+ // On specific status like `CONTENT_CHECK_REQUIRED`, the reason is
+ // contained inside `errorScreen`, just like how we check subReason.
+ const reason = videoData.playabilityStatus?.reason ||
+ videoData.playabilityStatus?.errorScreen
+ ?.playerErrorMessageRenderer
+ ?.reason?.simpleText;
+
+ interface Error {
+ signInToConfirmAge: boolean;
+ SignInToConfirmBot: boolean;
+ unknown: string | undefined;
+ }
+
+ const error: Error = {
+ signInToConfirmAge: false,
+ SignInToConfirmBot: false,
+ unknown: undefined,
};
+
+ switch (true) {
+ case reason?.includes("Sign in to confirm youre not a bot"):
+ error.SignInToConfirmBot = true;
+ return error;
+ // Age restricted videos
+ case reason?.includes("Sign in to confirm your age"):
+ error.signInToConfirmAge = true;
+ return error;
+ default:
+ error.unknown = reason;
+ return error;
+ }
}
private checkSubreason(videoData: IRawResponse) {
@@ -93,39 +145,67 @@ export class Metrics {
?.playerErrorMessageRenderer
?.subreason?.runs?.[0]?.text;
- return {
- thisHelpsProtectCommunity: subReason?.includes(
- "This helps protect our community",
- ),
+ interface Error {
+ thisHelpsProtectCommunity: boolean;
+ unknown: string | undefined;
+ }
+
+ const error: Error = {
+ thisHelpsProtectCommunity: false,
+ unknown: undefined,
};
+
+ switch (true) {
+ case subReason?.includes("This helps protect our community"):
+ error.thisHelpsProtectCommunity = true;
+ return error;
+ default:
+ error.unknown = subReason;
+ return error;
+ }
}
public checkInnertubeResponse(videoData: IRawResponse) {
this.innertubeFailedRequest.inc();
- const status = this.checkStatus(videoData);
+ const status = this.checkStatus(videoData);
if (status.contentCheckRequired || status.unplayable) return;
+ if (status?.unknown) {
+ this.innertubeErrorStatusUnknown.labels({
+ error: status.unknown,
+ }).inc();
+ }
+
+ const reason = this.checkReason(videoData);
+ if (reason.signInToConfirmAge) return;
+
+ if (reason.unknown) {
+ this.innertubeErrorReasonUnknown.labels({
+ error: reason.unknown,
+ }).inc();
+ }
+
+ // On specific `playabilityStatus.status` like `CONTENT_CHECK_REQUIRED`,
+ // `subReason` doesn't come with a `playabilityStatus.reason`
+ // key. So we need to check this separately from `reason`
+ const subReason = this.checkSubreason(videoData);
+ if (subReason.unknown) {
+ this.innertubeErrorSubreasonUnknown.labels({
+ error: subReason.unknown,
+ }).inc();
+ }
+
if (status.loginRequired) {
this.innertubeErrorStatusLoginRequired.inc();
- const reason = this.checkReason(videoData);
-
- if (reason.signInToConfirmAge) return;
if (reason.SignInToConfirmBot) {
this.innertubeErrorReasonSignIn.inc();
- const subReason = this.checkSubreason(videoData);
if (subReason.thisHelpsProtectCommunity) {
this.innertubeErrorSubreasonProtectCommunity.inc();
- } else {
- this.innertubeErrorSubreasonUnknown.inc();
}
- } else {
- this.innertubeErrorReasonUnknown.inc();
}
- } else {
- this.innertubeErrorStatusUnknown.inc();
}
}
}
--
2.49.0