diff --git a/src/backend/common/infrastructure/config/source/index.ts b/src/backend/common/infrastructure/config/source/index.ts index b7d7bd13..485f81ea 100644 --- a/src/backend/common/infrastructure/config/source/index.ts +++ b/src/backend/common/infrastructure/config/source/index.ts @@ -43,8 +43,8 @@ export interface ScrobbleThresholds { export interface CommonSourceOptions extends SourceRetryOptions { /** - * If this source has INGRESS to MS (sends a payload, rather than MS GETTING requesting a payload) - * then setting this option to true will make MS log the payload JSON to DEBUG output + * * If this source has INGRESS to MS (sends a payload, rather than MS GETTING requesting a payload) then setting this option to true will make MS log the payload JSON to DEBUG output + * * If this source is POLLING then it will log the raw data for each unique track/response the first time it is seen * * @default false * @examples [false] diff --git a/src/backend/common/infrastructure/config/source/jellyfin.ts b/src/backend/common/infrastructure/config/source/jellyfin.ts index 970aa97e..436d7b6d 100644 --- a/src/backend/common/infrastructure/config/source/jellyfin.ts +++ b/src/backend/common/infrastructure/config/source/jellyfin.ts @@ -90,14 +90,6 @@ export interface JellyApiData extends CommonSourceData { } export interface JellyApiOptions extends CommonSourceOptions { - /* - * Outputs JSON for session data the first time a new media ID is seen - * - * For use when troubleshooting issues - * - * @default false - */ - logPayload?: boolean } export interface JellySourceConfig extends CommonSourceConfig { diff --git a/src/backend/common/infrastructure/config/source/plex.ts b/src/backend/common/infrastructure/config/source/plex.ts index 9a5b6867..c021db70 100644 --- a/src/backend/common/infrastructure/config/source/plex.ts +++ b/src/backend/common/infrastructure/config/source/plex.ts @@ -74,14 +74,6 @@ export interface PlexApiData extends CommonSourceData, PollingOptions { } export interface PlexApiOptions extends CommonSourceOptions { - /* - * Outputs JSON for session data the first time a new media ID is seen - * - * For use when troubleshooting issues - * - * @default false - */ - logPayload?: boolean } export interface PlexApiSourceConfig extends CommonSourceConfig { diff --git a/src/backend/common/logging.ts b/src/backend/common/logging.ts index 9daa88a7..7dc166ee 100644 --- a/src/backend/common/logging.ts +++ b/src/backend/common/logging.ts @@ -1,9 +1,10 @@ -import { childLogger, FileLogOptions, Logger, loggerAppRolling, LogLevel, LogLevelStreamEntry, LogOptions, parseLogOptions, } from '@foxxmd/logging'; +import { childLogger, FileLogOptions, Logger, loggerAppRolling, LogLevel, LogLevelStreamEntry, LogOptions, parseLogOptions } from '@foxxmd/logging'; import { buildDestinationJsonPrettyStream, buildDestinationRollingFile, buildDestinationStdout, buildLogger } from "@foxxmd/logging/factory"; import { PassThrough, Transform } from "node:stream"; import path from "path"; import process from "process"; import { projectDir } from "./index.js"; +import { isDebugMode } from '../utils.js'; export let logPath = path.resolve(projectDir, `./logs`); if (typeof process.env.CONFIG_DIR === 'string') { @@ -22,7 +23,8 @@ export const initLogger = (): [Logger, Transform] => { export const appLogger = async (config: LogOptions = {}): Promise<[Logger, PassThrough]> => { const stream = new PassThrough({objectMode: true}); - const opts = parseLogOptions(config) + const { file } = config; + const opts = parseLogOptions(isDebugMode() ? {...config, file: typeof file === 'object' ? {...file, level: 'debug'} : 'debug', console: 'debug', level: 'debug'} : config); const logger = await loggerAppRolling(config, { logBaseDir: typeof process.env.CONFIG_DIR === 'string' ? process.env.CONFIG_DIR : undefined, logDefaultPath: './logs/scrobble.log', diff --git a/src/backend/scrobblers/AbstractScrobbleClient.ts b/src/backend/scrobblers/AbstractScrobbleClient.ts index 9478e0df..b5bd2ce9 100644 --- a/src/backend/scrobblers/AbstractScrobbleClient.ts +++ b/src/backend/scrobblers/AbstractScrobbleClient.ts @@ -31,6 +31,7 @@ import { CommonClientConfig, UpstreamRefreshOptions } from "../common/infrastruc import { Notifiers } from "../notifier/Notifiers.js"; import { comparingMultipleArtists, + isDebugMode, playObjDataMatch, pollingBackoff, setIntersection, @@ -115,13 +116,13 @@ export default abstract class AbstractScrobbleClient extends AbstractComponent i const { match: { - onNoMatch = false, - onMatch = false, - confidenceBreakdown = false, + onNoMatch = isDebugMode(), + onMatch = isDebugMode(), + confidenceBreakdown = isDebugMode(), } = {}, ...vRest } = verbose - if (onMatch || onNoMatch) { + if (onMatch || onNoMatch || isDebugMode()) { this.logger.warn('Setting verbose matching may produce noisy logs! Use with care.'); } this.verboseOptions = { diff --git a/src/backend/server/jellyfinRoutes.ts b/src/backend/server/jellyfinRoutes.ts index 08ce2f92..4a7529e0 100644 --- a/src/backend/server/jellyfinRoutes.ts +++ b/src/backend/server/jellyfinRoutes.ts @@ -4,7 +4,7 @@ import bodyParser from "body-parser"; import { JellyfinNotifier } from "../sources/ingressNotifiers/JellyfinNotifier.js"; import JellyfinSource from "../sources/JellyfinSource.js"; import ScrobbleSources from "../sources/ScrobbleSources.js"; -import { parseBool, remoteHostIdentifiers } from "../utils.js"; +import { isDebugMode, parseBool, remoteHostIdentifiers } from "../utils.js"; export const setupJellyfinRoutes = (app: ExpressWithAsync, logger: Logger, scrobbleSources: ScrobbleSources) => { @@ -60,7 +60,7 @@ export const setupJellyfinRoutes = (app: ExpressWithAsync, logger: Logger, scrob const logPayload = pSources.some(x => { const { options: { - logPayload = parseBool(process.env.DEBUG_MODE) + logPayload = isDebugMode() } = {} } = x.config; return logPayload; diff --git a/src/backend/server/tautulliRoutes.ts b/src/backend/server/tautulliRoutes.ts index ae4f523d..66f4dd69 100644 --- a/src/backend/server/tautulliRoutes.ts +++ b/src/backend/server/tautulliRoutes.ts @@ -4,7 +4,7 @@ import { ExpressHandler } from "../common/infrastructure/Atomic.js"; import { TautulliNotifier } from "../sources/ingressNotifiers/TautulliNotifier.js"; import ScrobbleSources from "../sources/ScrobbleSources.js"; import TautulliSource from "../sources/TautulliSource.js"; -import { parseBool } from "../utils.js"; +import { isDebugMode, parseBool } from "../utils.js"; export const setupTautulliRoutes = (app: ExpressWithAsync, logger: Logger, scrobbleSources: ScrobbleSources) => { @@ -21,7 +21,7 @@ export const setupTautulliRoutes = (app: ExpressWithAsync, logger: Logger, scrob logger.warn(`Tautulli event specified a config name but the configured source was not a Tautulli type: ${req.body.scrobblerConfig}`); return res.send('OK'); } else { - if((source.config.options?.logPayload ?? parseBool(process.env.DEBUG_MODE)) === true) { + if((source.config.options?.logPayload ?? isDebugMode()) === true) { source.logger.debug(`Received Payload`, req.body); } // @ts-expect-error TS(2339): Property 'handle' does not exist on type 'never'. diff --git a/src/backend/sources/ChromecastSource.ts b/src/backend/sources/ChromecastSource.ts index db47a8f2..0c11f617 100644 --- a/src/backend/sources/ChromecastSource.ts +++ b/src/backend/sources/ChromecastSource.ts @@ -30,7 +30,7 @@ import { PlatformApplicationWithContext, PlatformType } from "../common/vendor/chromecast/interfaces.js"; -import { difference, genGroupIdStr, parseBool } from "../utils.js"; +import { difference, genGroupIdStr, isDebugMode, parseBool } from "../utils.js"; import { findCauseByReference } from "../utils/ErrorUtils.js"; import { discoveryAvahi, discoveryNative } from "../utils/MDNSUtils.js"; import { RecentlyPlayedOptions } from "./AbstractSource.js"; @@ -120,7 +120,7 @@ export class ChromecastSource extends MemoryPositionalSource { useAutoDiscovery } = {}, options: { - logPayload = false + logPayload = isDebugMode() } = {}, } = this.config; @@ -552,7 +552,7 @@ export class ChromecastSource extends MemoryPositionalSource { // its fine just do error without play string } application.logger.verbose(`Skipping status for ${maybePlay !== undefined ? buildTrackString(maybePlay) : 'unknown media'} because it is buffering.`); - if (this.config.options.logPayload) { + if (this.config.options.logPayload || isDebugMode()) { application.logger.debug(`Media Status Payload:\n ${status[0] === undefined || status[0] === null ? 'undefined' : JSON.stringify(status[0])}`); } continue; @@ -564,7 +564,7 @@ export class ChromecastSource extends MemoryPositionalSource { throw e; } - if (this.config.options.logPayload) { + if (this.config.options.logPayload || isDebugMode()) { application.logger.debug(`Media Status Payload:\n ${mediaStatus === undefined || mediaStatus === null ? 'undefined' : JSON.stringify(mediaStatus)}`); } diff --git a/src/backend/sources/JellyfinApiSource.ts b/src/backend/sources/JellyfinApiSource.ts index fb7818ea..76a82d6f 100644 --- a/src/backend/sources/JellyfinApiSource.ts +++ b/src/backend/sources/JellyfinApiSource.ts @@ -56,7 +56,7 @@ import { PlayPlatformId, REPORTED_PLAYER_STATUSES } from "../common/infrastructure/Atomic.js"; import { JellyApiSourceConfig } from "../common/infrastructure/config/source/jellyfin.js"; -import { genGroupIdStr, getPlatformIdFromData, parseBool, } from "../utils.js"; +import { genGroupIdStr, getPlatformIdFromData, isDebugMode, parseBool, } from "../utils.js"; import { joinedUrl } from "../utils/NetworkUtils.js"; import { parseArrayFromMaybeString } from "../utils/StringUtils.js"; import { MemoryPositionalSource } from "./MemoryPositionalSource.js"; @@ -130,7 +130,7 @@ export default class JellyfinApiSource extends MemoryPositionalSource { additionalAllowedLibraryTypes = [], } = {}, options: { - logFilterFailure = (parseBool(process.env.DEBUG_MODE) ? 'debug' : 'warn') + logFilterFailure = (isDebugMode() ? 'debug' : 'warn') } = {} } = this.config; diff --git a/src/backend/sources/JellyfinSource.ts b/src/backend/sources/JellyfinSource.ts index 37a8e420..4319f370 100644 --- a/src/backend/sources/JellyfinSource.ts +++ b/src/backend/sources/JellyfinSource.ts @@ -12,6 +12,7 @@ import { FormatPlayObjectOptions, InternalConfig, PlayPlatformId } from "../comm import { JellySourceConfig } from "../common/infrastructure/config/source/jellyfin.js"; import { doubleReturnNewline, + isDebugMode, parseBool, parseDurationFromTimestamp, playObjDataMatch, @@ -46,7 +47,7 @@ export default class JellyfinSource extends MemorySource { servers, } = {}, options: { - logFilterFailure = (parseBool(process.env.DEBUG_MODE) ? 'debug' : 'warn') + logFilterFailure = (isDebugMode() ? 'debug' : 'warn') } = {} } = this.config; @@ -192,7 +193,7 @@ export default class JellyfinSource extends MemorySource { protected logFilterFailure = (str: string, meta?: any) => { const { options: { - logFilterFailure = (parseBool(process.env.DEBUG_MODE) ? 'debug' : 'warn') + logFilterFailure = (isDebugMode() ? 'debug' : 'warn') } = {} } = this.config; @@ -306,7 +307,7 @@ export default class JellyfinSource extends MemorySource { const currPlay = player.getPlayedObject(); if(currPlay !== undefined && playObjDataMatch(currPlay, playObj)) { const temporalResult = comparePlayTemporally(currPlay, playObj); - if(parseBool(process.env.DEBUG_MODE)) { + if(isDebugMode()) { player.logger.debug(doubleReturnNewline` Play with event UserDataSaved-PlaybackFinished matched => ${trackId} diff --git a/src/backend/sources/PlexApiSource.ts b/src/backend/sources/PlexApiSource.ts index 17a66f94..484bac08 100644 --- a/src/backend/sources/PlexApiSource.ts +++ b/src/backend/sources/PlexApiSource.ts @@ -11,7 +11,7 @@ import { PlayerStateDataMaybePlay, PlayPlatformId, REPORTED_PLAYER_STATUSES } from "../common/infrastructure/Atomic.js"; -import { genGroupIdStr, getFirstNonEmptyString, getPlatformIdFromData, parseBool, } from "../utils.js"; +import { genGroupIdStr, getFirstNonEmptyString, getPlatformIdFromData, isDebugMode, parseBool, } from "../utils.js"; import { buildStatePlayerPlayIdententifyingInfo, parseArrayFromMaybeString } from "../utils/StringUtils.js"; import { GetSessionsMetadata } from "@lukehagar/plexjs/sdk/models/operations/getsessions.js"; import { PlexAPI } from "@lukehagar/plexjs"; @@ -86,7 +86,7 @@ export default class PlexApiSource extends MemoryPositionalSource { librariesBlock = [], } = {}, options: { - logFilterFailure = (parseBool(process.env.DEBUG_MODE) ? 'debug' : 'warn'), + logFilterFailure = (isDebugMode() ? 'debug' : 'warn'), } = {} } = this.config; @@ -423,7 +423,7 @@ export default class PlexApiSource extends MemoryPositionalSource { const play: PlayObject = this.formatPlayObjAware(obj); - if(this.config.options.logPayload && !this.mediaIdsSeen.data.includes(play.meta.trackId)) { + if((this.config.options.logPayload || isDebugMode()) && !this.mediaIdsSeen.data.includes(play.meta.trackId)) { this.logger.debug(`First time seeing media ${play.meta.trackId} on ${msDeviceId} => ${JSON.stringify(play)} Plex Payload: ${JSON.stringify(obj)}`); diff --git a/src/backend/utils.ts b/src/backend/utils.ts index 13767f95..b33979bf 100644 --- a/src/backend/utils.ts +++ b/src/backend/utils.ts @@ -230,7 +230,6 @@ export const parseRetryAfterSecsFromObj = (err: any) => { // } const { response: { - // @ts-expect-error TS(2525): Initializer provides no value for this binding ele... Remove this comment to see the full error message headers, // returned in superagent error } = {}, retryAfter: ra // possible custom property we have set @@ -690,4 +689,6 @@ export const retry = async ( await sleep(retryIntervalMs) return retry(fn, { retries: retries - 1, retryIntervalMs }) } - } \ No newline at end of file + } + +export const isDebugMode = (): boolean => process.env.DEBUG_MODE === 'true'; \ No newline at end of file diff --git a/src/backend/utils/NetworkUtils.ts b/src/backend/utils/NetworkUtils.ts index e64427d6..0d60b1b1 100644 --- a/src/backend/utils/NetworkUtils.ts +++ b/src/backend/utils/NetworkUtils.ts @@ -4,7 +4,7 @@ import address from "address"; import net from 'node:net'; import normalizeUrl from "normalize-url"; import { join as joinPath } from "path"; -import { getFirstNonEmptyVal, parseRegexSingleOrFail } from "../utils.js"; +import { getFirstNonEmptyVal, isDebugMode, parseRegexSingleOrFail } from "../utils.js"; import { URLData } from "../../core/Atomic.js"; export interface PortReachableOpts { @@ -113,7 +113,7 @@ export const getAddress = (host = '0.0.0.0', logger?: Logger): { v4?: string, v6 v4 = address.ip(); v6 = address.ipv6(); } catch (e) { - if (process.env.DEBUG_MODE === 'true') { + if (isDebugMode()) { if (logger !== undefined) { logger.warn(new Error('Could not get machine IP address', {cause: e})); } else {