fix: properly set child log levels on level change from UI

This commit is contained in:
Christian Benincasa
2026-04-04 08:19:49 -04:00
parent 1ab22ccc22
commit 9410efac7a
3 changed files with 48 additions and 34 deletions

View File

@@ -6,7 +6,8 @@ import { SavePlexProgramExternalIdsTask } from '@/tasks/plex/SavePlexProgramExte
import { DateTimeRange } from '@/types/DateTimeRange.js';
import { OpenDateTimeRange } from '@/types/OpenDateTimeRange.js';
import type { RouterPluginAsyncCallback } from '@/types/serverType.js';
import { tag } from '@tunarr/types';
import { LoggerFactory } from '@/util/logging/LoggerFactory.js';
import { LogLevels, tag } from '@tunarr/types';
import { ChannelLineupQuery } from '@tunarr/types/api';
import { ChannelLineupSchema } from '@tunarr/types/schemas';
import dayjs from 'dayjs';
@@ -44,6 +45,23 @@ export const debugApi: RouterPluginAsyncCallback = async (fastify) => {
return res.send(getHeapStatistics());
});
fastify.get(
'/debug/log',
{
schema: {
querystring: z.object({
level: z.enum(LogLevels).default('debug'),
log: z.string().optional(),
}),
},
},
async (req, res) => {
const logger = LoggerFactory.root;
logger[req.query.level](req.query.log ?? 'Test log');
return res.send('ok');
},
);
fastify.get(
'/debug/helpers/playing_at',
{

View File

@@ -31,11 +31,6 @@ import type { SerializedLogger } from './LoggerWrapper.ts';
import { RootLoggerWrapper } from './LoggerWrapper.ts';
import { RollingLogDestination } from './RollingDestination.ts';
export const LogConfigEnvVars = {
level: 'LOG_LEVEL',
directory: 'LOG_DIRECTORY',
} as const;
export function getEnvironmentLogLevel(envVar?: string): Maybe<LogLevels> {
const envLevel = trim(
toLower(process.env[envVar ?? TUNARR_ENV_VARS.LOG_LEVEL_ENV_VAR]),
@@ -108,12 +103,12 @@ export const LogCategories = ['streaming', 'scheduling'] as const;
export type LogCategory = TupleToUnion<typeof LogCategories>;
class LoggerFactoryImpl {
private settingsDB: SettingsDB;
private settingsDB?: SettingsDB;
// private rootLogger: PinoLogger<ExtraLogLevels>;
private rootLogger!: RootLoggerWrapper;
private initialized = false;
private children: Record<string, WeakRef<Logger>> = {};
private currentStreams: MultiStreamRes<LogLevels>;
private currentStreams?: MultiStreamRes<LogLevels>;
private roller?: RollingLogDestination;
constructor() {
@@ -136,7 +131,7 @@ class LoggerFactoryImpl {
}
const currentSettings =
this.settingsDB.systemSettings().logging.logRollConfig;
this.settingsDB?.systemSettings().logging.logRollConfig;
const { level: newLevel } = this.logLevel;
const perCategoryLogLevel = this.perCategoryLogLevel;
@@ -272,12 +267,11 @@ class LoggerFactoryImpl {
return;
}
// Reset the level of the root logger and all children
// We do this by setting the level on the instance directly
// but then for multistream to work, we have to manually reset the streams
// by cloning them with new levels.
this.rootLogger.level = newLevel;
this.rootLogger.updateStreams(this.createLogStreams(newLevel));
// Reset the level of the root logger and all children.
// We set the level on every logger instance directly because pino children
// snapshot the parent's level at creation time and don't follow changes.
// For multistream to work, we also have to manually reset the streams.
this.rootLogger.updateLevel(newLevel, this.createLogStreams(newLevel));
}
private createStreams(logLevel: LogLevels): StreamEntry<LogLevels>[] {

View File

@@ -25,6 +25,7 @@ interface ILoggerWrapper {
args: GetChildLoggerArgs,
opts?: ChildLoggerOptions<LogLevels>,
): ILoggerWrapper;
updateLevel(level: LogLevels, streams: MultiStreamRes<LogLevels>): void;
updateStreams(streams: MultiStreamRes<LogLevels>): void;
logger: Logger;
traverseHierarchy(): Generator<readonly [string, SerializedLogger]>;
@@ -32,7 +33,7 @@ interface ILoggerWrapper {
}
abstract class BaseLoggerWrapper implements ILoggerWrapper {
protected children: Record<string, WeakRef<ILoggerWrapper>> = {};
protected children: Record<string, ILoggerWrapper> = {};
constructor(protected wrappedLogger: Logger) {}
@@ -41,14 +42,20 @@ abstract class BaseLoggerWrapper implements ILoggerWrapper {
opts?: ChildLoggerOptions<LogLevels>,
): ILoggerWrapper;
updateLevel(level: LogLevels, streams: MultiStreamRes<LogLevels>) {
this.wrappedLogger.level = level;
Object.assign(this.wrappedLogger[symbols.streamSym], streams);
for (const child of Object.values(this.children)) {
child.updateLevel(level, streams);
}
}
updateStreams(streams: MultiStreamRes<LogLevels>) {
Object.assign(this.wrappedLogger[symbols.streamSym], streams);
for (const childRef of Object.values(this.children)) {
const child = childRef.deref();
if (child) {
child.updateStreams(streams);
}
for (const child of Object.values(this.children)) {
child.updateStreams(streams);
}
}
@@ -67,8 +74,8 @@ abstract class BaseLoggerWrapper implements ILoggerWrapper {
}
*traverseHierarchy() {
for (const [loggerName, ref] of Object.entries(this.children)) {
const child = ref.deref();
for (const [loggerName, child] of Object.entries(this.children)) {
// const child = ref.deref();
if (!child) {
continue;
}
@@ -110,7 +117,7 @@ export class RootLoggerWrapper extends BaseLoggerWrapper {
{ level: initialLogSettings?.categoryLogLevel?.[category] },
);
const wrapped = new LoggerWrapper(categoryLogger);
this.children[`category:${category}`] = new WeakRef(wrapped);
this.children[`category:${category}`] = wrapped;
this.loggerByCategory.set(category, wrapped);
}
}
@@ -121,7 +128,7 @@ export class RootLoggerWrapper extends BaseLoggerWrapper {
): ILoggerWrapper {
const { caller, className, category, ...rest } = args;
const ref = this.children[className]?.deref();
const ref = this.children[className]; //?.deref();
if (ref) {
return ref;
}
@@ -145,15 +152,11 @@ export class RootLoggerWrapper extends BaseLoggerWrapper {
} else {
const newLogger = this.wrappedLogger.child(childOpts, opts);
const wrapped = new LoggerWrapper(newLogger);
this.children[className] = new WeakRef(wrapped);
this.children[className] = wrapped;
return wrapped;
}
}
set level(newLevel: LogLevels) {
this.wrappedLogger.level = newLevel;
}
updateCategoryLevel(
newLevel: LogLevels,
category: LogCategory,
@@ -164,8 +167,7 @@ export class RootLoggerWrapper extends BaseLoggerWrapper {
return;
}
rootCategoryLogger.logger.level = newLevel;
rootCategoryLogger.updateStreams(newStreamFn());
rootCategoryLogger.updateLevel(newLevel, newStreamFn());
}
}
@@ -189,7 +191,7 @@ export class LoggerWrapper extends BaseLoggerWrapper {
): ILoggerWrapper {
const { caller, className, ...rest } = args;
const ref = this.children[className]?.deref();
const ref = this.children[className]; //?.deref();
if (ref) {
return ref;
}
@@ -208,7 +210,7 @@ export class LoggerWrapper extends BaseLoggerWrapper {
const newChild = new LoggerWrapper(
this.wrappedLogger.child(childOpts, opts),
);
this.children[className] = new WeakRef(newChild);
this.children[className] = newChild;
return newChild;
}
}