refactor(logs): move to core package (#4586)

This commit is contained in:
Meier Lukas
2025-12-16 23:37:44 +01:00
committed by GitHub
parent d86af072bf
commit d348abfe4a
145 changed files with 971 additions and 708 deletions

View File

@@ -1,12 +1,15 @@
import AdmZip from "adm-zip";
import { z } from "zod/v4";
import { logger } from "@homarr/log";
import { createLogger } from "@homarr/core/infrastructure/logs";
import { ErrorWithMetadata } from "@homarr/core/infrastructure/logs/error";
import { oldmarrConfigSchema } from "@homarr/old-schema";
import { oldmarrImportUserSchema } from "../user-schema";
import type { analyseOldmarrImportInputSchema } from "./input";
const logger = createLogger({ module: "analyseOldmarrImport" });
export const analyseOldmarrImportForRouterAsync = async (input: z.infer<typeof analyseOldmarrImportInputSchema>) => {
const { configs, checksum, users } = await analyseOldmarrImportAsync(input.file);
@@ -25,7 +28,13 @@ export const analyseOldmarrImportAsync = async (file: File) => {
const configs = configEntries.map((entry) => {
const result = oldmarrConfigSchema.safeParse(JSON.parse(entry.getData().toString()));
if (!result.success) {
logger.error(`Failed to parse config ${entry.entryName} with error: ${JSON.stringify(result.error)}`);
logger.error(
new ErrorWithMetadata(
"Failed to parse oldmarr config",
{ entryName: entry.entryName },
{ cause: result.error },
),
);
}
return {
@@ -57,7 +66,7 @@ const parseUsers = (entry: AdmZip.IZipEntry | undefined) => {
const result = z.array(oldmarrImportUserSchema).safeParse(JSON.parse(entry.getData().toString()));
if (!result.success) {
logger.error(`Failed to parse users with error: ${JSON.stringify(result.error)}`);
logger.error(new Error("Failed to parse users", { cause: result.error }));
}
return result.data ?? [];

View File

@@ -1,7 +1,9 @@
import { createId } from "@homarr/common";
import { logger } from "@homarr/log";
import { createLogger } from "@homarr/core/infrastructure/logs";
import type { OldmarrConfig } from "@homarr/old-schema";
const logger = createLogger({ module: "fixSectionIssues" });
export const fixSectionIssues = (old: OldmarrConfig) => {
const wrappers = old.wrappers.sort((wrapperA, wrapperB) => wrapperA.position - wrapperB.position);
const categories = old.categories.sort((categoryA, categoryB) => categoryA.position - categoryB.position);
@@ -9,9 +11,10 @@ export const fixSectionIssues = (old: OldmarrConfig) => {
const neededSectionCount = categories.length * 2 + 1;
const hasToMuchEmptyWrappers = wrappers.length > categories.length + 1;
logger.debug(
`Fixing section issues neededSectionCount=${neededSectionCount} hasToMuchEmptyWrappers=${hasToMuchEmptyWrappers}`,
);
logger.debug("Fixing section issues", {
neededSectionCount,
hasToMuchEmptyWrappers,
});
for (let position = 0; position < neededSectionCount; position++) {
const index = Math.floor(position / 2);
@@ -38,7 +41,7 @@ export const fixSectionIssues = (old: OldmarrConfig) => {
wrappers.splice(categories.length + 1);
if (wrapperIdsToMerge.length >= 2) {
logger.debug(`Found wrappers to merge count=${wrapperIdsToMerge.length}`);
logger.debug("Found wrappers to merge", { count: wrapperIdsToMerge.length });
}
return {

View File

@@ -1,18 +1,18 @@
import { createId } from "@homarr/common";
import { createLogger } from "@homarr/core/infrastructure/logs";
import type { Database } from "@homarr/db";
import { sections } from "@homarr/db/schema";
import { logger } from "@homarr/log";
import type { OldmarrConfig } from "@homarr/old-schema";
const logger = createLogger({ module: "importSections" });
export const insertSectionsAsync = async (
db: Database,
categories: OldmarrConfig["categories"],
wrappers: OldmarrConfig["wrappers"],
boardId: string,
) => {
logger.info(
`Importing old homarr sections boardId=${boardId} categories=${categories.length} wrappers=${wrappers.length}`,
);
logger.info("Importing old homarr sections", { boardId, categories: categories.length, wrappers: wrappers.length });
const wrapperIds = wrappers.map((section) => section.id);
const categoryIds = categories.map((section) => section.id);
@@ -45,7 +45,7 @@ export const insertSectionsAsync = async (
await db.insert(sections).values(categoriesToInsert);
}
logger.info(`Imported sections count=${wrappersToInsert.length + categoriesToInsert.length}`);
logger.info("Imported sections", { count: wrappersToInsert.length + categoriesToInsert.length });
return idMaps;
};

View File

@@ -1,6 +1,6 @@
import { createId } from "@homarr/common";
import { createLogger } from "@homarr/core/infrastructure/logs";
import { createDbInsertCollectionForTransaction } from "@homarr/db/collection";
import { logger } from "@homarr/log";
import type { BoardSize, OldmarrConfig } from "@homarr/old-schema";
import { boardSizes, getBoardSizeName } from "@homarr/old-schema";
@@ -15,6 +15,8 @@ import type { prepareMultipleImports } from "../../prepare/prepare-multiple";
import { prepareSections } from "../../prepare/prepare-sections";
import type { InitialOldmarrImportSettings } from "../../settings";
const logger = createLogger({ module: "boardCollection" });
export const createBoardInsertCollection = (
{ preparedApps, preparedBoards }: Omit<ReturnType<typeof prepareMultipleImports>, "preparedIntegrations">,
settings: InitialOldmarrImportSettings,
@@ -50,12 +52,12 @@ export const createBoardInsertCollection = (
}
if (settings.onlyImportApps) {
logger.info(
`Skipping boards and sections import due to onlyImportApps setting appCount=${insertCollection.apps.length}`,
);
logger.info("Skipping boards and sections import due to onlyImportApps setting", {
appCount: insertCollection.apps.length,
});
return insertCollection;
}
logger.debug(`Added apps to board insert collection count=${insertCollection.apps.length}`);
logger.debug("Added apps to board insert collection", { count: insertCollection.apps.length });
preparedBoards.forEach((board) => {
if (!hasEnoughItemShapes(board.config)) {
@@ -71,10 +73,10 @@ export const createBoardInsertCollection = (
name: board.name,
});
logger.debug(`Fixed issues with sections and item positions fileName=${board.name}`);
logger.debug("Fixed issues with sections and item positions", { fileName: board.name });
const mappedBoard = mapBoard(board);
logger.debug(`Mapped board fileName=${board.name} boardId=${mappedBoard.id}`);
logger.debug("Mapped board", { fileName: board.name, boardId: mappedBoard.id });
insertCollection.boards.push(mappedBoard);
const layoutMapping = boardSizes.reduce(
@@ -100,7 +102,7 @@ export const createBoardInsertCollection = (
for (const section of preparedSections.values()) {
insertCollection.sections.push(section);
}
logger.debug(`Added sections to board insert collection count=${insertCollection.sections.length}`);
logger.debug("Added sections to board insert collection", { count: insertCollection.sections.length });
const preparedItems = prepareItems(
{
@@ -117,12 +119,15 @@ export const createBoardInsertCollection = (
insertCollection.items.push(item);
insertCollection.itemLayouts.push(...layouts);
});
logger.debug(`Added items to board insert collection count=${insertCollection.items.length}`);
logger.debug("Added items to board insert collection", { count: insertCollection.items.length });
});
logger.info(
`Board collection prepared boardCount=${insertCollection.boards.length} sectionCount=${insertCollection.sections.length} itemCount=${insertCollection.items.length} appCount=${insertCollection.apps.length}`,
);
logger.info("Board collection prepared", {
boardCount: insertCollection.boards.length,
sectionCount: insertCollection.sections.length,
itemCount: insertCollection.items.length,
appCount: insertCollection.apps.length,
});
return insertCollection;
};

View File

@@ -1,10 +1,12 @@
import { encryptSecret } from "@homarr/common/server";
import { createLogger } from "@homarr/core/infrastructure/logs";
import { createDbInsertCollectionForTransaction } from "@homarr/db/collection";
import { logger } from "@homarr/log";
import { mapAndDecryptIntegrations } from "../../mappers/map-integration";
import type { PreparedIntegration } from "../../prepare/prepare-integrations";
const logger = createLogger({ module: "integrationCollection" });
export const createIntegrationInsertCollection = (
preparedIntegrations: PreparedIntegration[],
encryptionToken: string | null | undefined,
@@ -15,7 +17,7 @@ export const createIntegrationInsertCollection = (
return insertCollection;
}
logger.info(`Preparing integrations for insert collection count=${preparedIntegrations.length}`);
logger.info("Preparing integrations for insert collection", { count: preparedIntegrations.length });
if (encryptionToken === null || encryptionToken === undefined) {
logger.debug("Skipping integration decryption due to missing token");
@@ -44,9 +46,10 @@ export const createIntegrationInsertCollection = (
});
});
logger.info(
`Added integrations and secrets to insert collection integrationCount=${insertCollection.integrations.length} secretCount=${insertCollection.integrationSecrets.length}`,
);
logger.info("Added integrations and secrets to insert collection", {
integrationCount: insertCollection.integrations.length,
secretCount: insertCollection.integrationSecrets.length,
});
return insertCollection;
};

View File

@@ -1,11 +1,13 @@
import { createId } from "@homarr/common";
import { createLogger } from "@homarr/core/infrastructure/logs";
import { createDbInsertCollectionForTransaction } from "@homarr/db/collection";
import { credentialsAdminGroup } from "@homarr/definitions";
import { logger } from "@homarr/log";
import { mapAndDecryptUsers } from "../../mappers/map-user";
import type { OldmarrImportUser } from "../../user-schema";
const logger = createLogger({ module: "userCollection" });
export const createUserInsertCollection = (
importUsers: OldmarrImportUser[],
encryptionToken: string | null | undefined,
@@ -21,7 +23,7 @@ export const createUserInsertCollection = (
return insertCollection;
}
logger.info(`Preparing users for insert collection count=${importUsers.length}`);
logger.info("Preparing users for insert collection", { count: importUsers.length });
if (encryptionToken === null || encryptionToken === undefined) {
logger.debug("Skipping user decryption due to missing token");
@@ -30,7 +32,7 @@ export const createUserInsertCollection = (
const preparedUsers = mapAndDecryptUsers(importUsers, encryptionToken);
preparedUsers.forEach((user) => insertCollection.users.push(user));
logger.debug(`Added users to insert collection count=${insertCollection.users.length}`);
logger.debug("Added users to insert collection", { count: insertCollection.users.length });
if (!preparedUsers.some((user) => user.isAdmin)) {
logger.warn("No admin users found, skipping admin group creation");
@@ -58,9 +60,10 @@ export const createUserInsertCollection = (
});
});
logger.info(
`Added admin group and permissions to insert collection adminGroupId=${adminGroupId} adminUsersCount=${admins.length}`,
);
logger.info("Added admin group and permissions to insert collection", {
adminGroupId,
adminUsersCount: admins.length,
});
return insertCollection;
};

View File

@@ -1,9 +1,9 @@
import type { z } from "zod/v4";
import { Stopwatch } from "@homarr/common";
import { createLogger } from "@homarr/core/infrastructure/logs";
import { handleTransactionsAsync } from "@homarr/db";
import type { Database } from "@homarr/db";
import { logger } from "@homarr/log";
import { analyseOldmarrImportAsync } from "../analyse/analyse-oldmarr-import";
import { prepareMultipleImports } from "../prepare/prepare-multiple";
@@ -13,6 +13,8 @@ import { createUserInsertCollection } from "./collections/user-collection";
import type { importInitialOldmarrInputSchema } from "./input";
import { ensureValidTokenOrThrow } from "./validate-token";
const logger = createLogger({ module: "importInitialOldmarr" });
export const importInitialOldmarrAsync = async (
db: Database,
input: z.infer<typeof importInitialOldmarrInputSchema>,
@@ -52,5 +54,5 @@ export const importInitialOldmarrAsync = async (
},
});
logger.info(`Import successful (in ${stopwatch.getElapsedInHumanWords()})`);
logger.info("Import successful", { duration: stopwatch.getElapsedInHumanWords() });
};

View File

@@ -1,9 +1,9 @@
import SuperJSON from "superjson";
import { createId } from "@homarr/common";
import { createLogger } from "@homarr/core/infrastructure/logs";
import type { InferInsertModel } from "@homarr/db";
import type { itemLayouts, items } from "@homarr/db/schema";
import { logger } from "@homarr/log";
import type { BoardSize, OldmarrApp, OldmarrWidget } from "@homarr/old-schema";
import { boardSizes } from "@homarr/old-schema";
@@ -11,6 +11,8 @@ import type { WidgetComponentProps } from "../../../widgets/src/definition";
import { mapKind } from "../widgets/definitions";
import { mapOptions } from "../widgets/options";
const logger = createLogger({ module: "mapItem" });
export const mapApp = (
app: OldmarrApp,
appsMap: Map<string, { id: string }>,
@@ -22,7 +24,10 @@ export const mapApp = (
const sectionId = sectionMap.get(app.area.properties.id)?.id;
if (!sectionId) {
logger.warn(`Failed to find section for app appId='${app.id}' sectionId='${app.area.properties.id}'. Removing app`);
logger.warn("Failed to find section for app. Removing app", {
appId: app.id,
sectionId: app.area.properties.id,
});
return null;
}
@@ -71,15 +76,19 @@ export const mapWidget = (
const kind = mapKind(widget.type);
if (!kind) {
logger.warn(`Failed to map widget type='${widget.type}'. It's no longer supported`);
logger.warn("Failed to map widget type. It's no longer supported", {
widgetId: widget.id,
widgetType: widget.type,
});
return null;
}
const sectionId = sectionMap.get(widget.area.properties.id)?.id;
if (!sectionId) {
logger.warn(
`Failed to find section for widget widgetId='${widget.id}' sectionId='${widget.area.properties.id}'. Removing widget`,
);
logger.warn("Failed to find section for widget. Removing widget", {
widgetId: widget.id,
sectionId: widget.area.properties.id,
});
return null;
}

View File

@@ -1,11 +1,13 @@
import { objectEntries } from "@homarr/common";
import { logger } from "@homarr/log";
import { createLogger } from "@homarr/core/infrastructure/logs";
import type { BoardSize, OldmarrApp, OldmarrConfig, OldmarrWidget } from "@homarr/old-schema";
import { boardSizes } from "@homarr/old-schema";
import { mapColumnCount } from "./mappers/map-column-count";
import type { OldmarrImportConfiguration } from "./settings";
const logger = createLogger({ module: "moveWidgetsAndAppsMerge" });
export const moveWidgetsAndAppsIfMerge = (
old: OldmarrConfig,
wrapperIdsToMerge: string[],
@@ -26,7 +28,7 @@ export const moveWidgetsAndAppsIfMerge = (
]),
);
logger.debug(`Merging wrappers at the end of the board count=${wrapperIdsToMerge.length}`);
logger.debug("Merging wrappers at the end of the board", { count: wrapperIdsToMerge.length });
const offsets = boardSizes.reduce(
(previous, screenSize) => {

View File

@@ -1,4 +1,4 @@
import { logger } from "@homarr/log";
import { createLogger } from "@homarr/core/infrastructure/logs";
import type { BoardSize, OldmarrApp, OldmarrConfig, OldmarrWidget, SizedShape } from "@homarr/old-schema";
import { boardSizes } from "@homarr/old-schema";
@@ -7,6 +7,8 @@ import { generateResponsiveGridFor } from "../../../api/src/router/board/grid-al
import { mapColumnCount } from "../mappers/map-column-count";
import { mapApp, mapWidget } from "../mappers/map-item";
const logger = createLogger({ module: "prepareItems" });
export const prepareItems = (
{ apps, widgets, settings }: Pick<OldmarrConfig, "apps" | "widgets" | "settings">,
appsMap: Map<string, { id: string }>,
@@ -25,15 +27,17 @@ export const prepareItems = (
);
if (incompleteSizes.length > 0) {
logger.warn(
`Found items with incomplete sizes board=${boardId} count=${incompleteSizes.length} sizes=${incompleteSizes.join(", ")}\nHomarr will automatically generate missing sizes`,
);
logger.warn("Found items with incomplete sizes. Generating missing sizes.", {
boardId,
count: incompleteSizes.length,
sizes: incompleteSizes.join(", "),
});
incompleteSizes.forEach((size) => {
const columnCount = mapColumnCount(settings.customization.gridstack, size);
const previousSize = !incompleteSizes.includes("lg") ? "lg" : incompleteSizes.includes("sm") ? "md" : "sm";
const previousWidth = mapColumnCount(settings.customization.gridstack, previousSize);
logger.info(`Generating missing size boardId=${boardId} from=${previousSize} to=${size}`);
logger.info("Generating missing size", { boardId, from: previousSize, to: size });
const items = widgets
.map((item) => mapItemForGridAlgorithm(item, previousSize))

View File

@@ -1,10 +1,12 @@
import { objectEntries } from "@homarr/common";
import { logger } from "@homarr/log";
import { createLogger } from "@homarr/core/infrastructure/logs";
import type { WidgetComponentProps } from "../../../widgets/src/definition";
import type { InversedWidgetMapping, OldmarrWidgetDefinitions, WidgetMapping } from "./definitions";
import { mapKind } from "./definitions";
const logger = createLogger({ module: "mapOptions" });
// This type enforces, that for all widget mappings there is a corresponding option mapping,
// each option of newmarr can be mapped from the value of the oldmarr options
type OptionMapping = {
@@ -192,7 +194,7 @@ export const mapOptions = <K extends OldmarrWidgetDefinitions["id"]>(
oldOptions: Extract<OldmarrWidgetDefinitions, { id: K }>["options"],
appsMap: Map<string, string>,
) => {
logger.debug(`Mapping old homarr options for widget type=${type} options=${JSON.stringify(oldOptions)}`);
logger.debug("Mapping old homarr options for widget", { type, options: JSON.stringify(oldOptions) });
const kind = mapKind(type);
if (!kind) {
return null;
@@ -202,7 +204,7 @@ export const mapOptions = <K extends OldmarrWidgetDefinitions["id"]>(
return objectEntries(mapping).reduce(
(acc, [key, value]: [string, (oldOptions: Record<string, unknown>, appsMap: Map<string, string>) => unknown]) => {
const newValue = value(oldOptions, appsMap);
logger.debug(`Mapping old homarr option kind=${kind} key=${key} newValue=${newValue as string}`);
logger.debug("Mapping old homarr option", { kind, key, newValue });
if (newValue !== undefined) {
acc[key] = newValue;
}