Skip to content

Commit

Permalink
feat(logger): add logger plugin (#56)
Browse files Browse the repository at this point in the history
* feat(logger): add logger plugin

* feat(logging): add basic logs

* fix: use log level WARNING as default

---------

Co-authored-by: Jonas Scholz <[email protected]>
  • Loading branch information
lksmsr and Code42Cate authored Mar 12, 2023
1 parent e0cffed commit b569b30
Show file tree
Hide file tree
Showing 5 changed files with 166 additions and 10 deletions.
2 changes: 1 addition & 1 deletion app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { LogLevel } from "fsxa-api";
import { FSXAFileConfig } from "./types";

const fsxaConfig: FSXAFileConfig = {
logLevel: LogLevel.NONE,
logLevel: LogLevel.WARNING,
devMode: false,
defaultLocale: "de_DE",
enableEventStream: false,
Expand Down
17 changes: 15 additions & 2 deletions layouts/default.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,39 @@
const { activeLocale } = useLocale();
const { fetchProjectProperties, setProjectProperties } = useProjectProperties();
const { setNavigationData, fetchNavigationData } = useNavigationData();
const { $logger } = useNuxtApp();
// This gets called when the layout is loaded or the locale changes
const { pending } = useAsyncData(
async () => {
// fetch project properties
const projectProperties = await fetchProjectProperties(activeLocale.value!);
if (!projectProperties)
if (!projectProperties) {
$logger.error(
"Project properties could not be fetched for locale: ",
activeLocale.value
);
throw showError({
message: "Project properties could not be fetched",
statusCode: 500,
});
}
setProjectProperties(projectProperties, activeLocale.value!);
// fetch navigationData
const navigationData = await fetchNavigationData(activeLocale.value!);
if (!navigationData)
if (!navigationData) {
$logger.error(
"Navigation data could not be fetched for locale: ",
activeLocale.value
);
throw showError({
message: "Navigation data could not be fetched",
statusCode: 500,
});
}
setNavigationData(navigationData);
},
{ watch: [activeLocale] }
Expand Down
4 changes: 4 additions & 0 deletions middleware/routing.global.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// This can happen on both the client and the server.
export default defineNuxtRouteMiddleware(async (to) => {
const { activeLocale } = useLocale();
const { $logger } = useNuxtApp();

const route = decodeURIComponent(to.path);
const {
Expand All @@ -12,6 +13,7 @@ export default defineNuxtRouteMiddleware(async (to) => {

// "/" does not exist in the navigation tree, so we first need to figure out the mapped route and then navigate to it.
if (route === "/") {
$logger.info("Trying to redirect / to home route...");
return navigateTo({
path: await getIndexRoute(),
hash: to.hash,
Expand All @@ -37,6 +39,8 @@ export default defineNuxtRouteMiddleware(async (to) => {
} catch (_error: unknown) {
// Theoretically this does not have to mean that the page does not exist.
// It could also be a 500 server error or something completely different...
// TODO: Differentiate between 404 and other errors.
$logger.error("Server error or page not found.");
throw createError({
statusCode: 404,
message: "Page not found",
Expand Down
31 changes: 24 additions & 7 deletions pages/[...slug].vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const {
findCachedPageByRoute,
findCachedDatasetByRoute,
} = useContent();
const { $fsxaApi, $setPreviewId } = useNuxtApp();
const { $fsxaApi, $setPreviewId, $logger } = useNuxtApp();
const { activeLocale } = useLocale();
const { activeNavigationItem } = useNavigationData();
const currentRoute = decodeURIComponent(useRoute().path);
Expand All @@ -35,48 +35,65 @@ const previewId = computed(() => {
const { pending } = useAsyncData(async () => {
// This state should not be possible.
// The middleware should have figured out both the locale and our current navigation item
if (!activeNavigationItem.value || !activeLocale.value)
throw new Error("No navigation item found");
if (!activeNavigationItem.value || !activeLocale.value) {
$logger.error(
"The middleware could not determine the navigation state for this route.",
currentRoute,
"Navigation item: ",
activeNavigationItem.value,
"Locale: ",
activeLocale.value
);
throw new Error("No navigation item or locale found");
}
const { caasDocumentId, seoRouteRegex } = activeNavigationItem.value;
const isContentProjection = seoRouteRegex !== null;
let pageId = caasDocumentId;
// for content projections we need to get the dataset first
if (isContentProjection) {
$logger.info("On content projection");
// get dataset
currentDataset.value = findCachedDatasetByRoute(currentRoute) || null;
if (!currentDataset.value) {
$logger.info(
"Dataset not cached yet. Trying to fetch dataset with fsxa api"
);
currentDataset.value = await fetchDatasetByRoute(
$fsxaApi,
currentRoute,
activeLocale.value
);
if (!currentDataset.value)
if (!currentDataset.value) {
$logger.error("Dataset could not be fetched!");
// Although it is recommended to use createError instead, there is a bug that prevents createError from triggering the error page
// https://github.com/nuxt/nuxt/issues/15432
throw showError({
statusMessage: "Dataset not found",
statusCode: 404,
});
}
addToCachedDatasets(currentRoute, currentDataset.value);
}
// get pageRefId from dataset
const firstRoute = currentDataset.value.routes?.[0];
if (!firstRoute)
if (!firstRoute) {
$logger.error("Dataset has no matching route");
throw showError({
statusMessage: "Dataset has no matching route",
statusCode: 404,
});
}
pageId = firstRoute.pageRef;
}
// get page data
currentPage.value = findCachedPageByRoute(currentRoute) || null;
if (!currentPage.value) {
$logger.info("Page data not cached yet. Trying to fetch with fsxa api...");
currentPage.value = await fetchPageById(
$fsxaApi,
pageId,
Expand Down
122 changes: 122 additions & 0 deletions plugins/4.logger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/* eslint no-console: 0 */
// TODO: the logger should be exported from the fsxa api in a future ticket
import { inspect } from "util";
import chalk from "chalk";
import { LogLevel } from "fsxa-api";

const getCircularReplacer = () => {
const seen = new WeakMap();
return (key: any, value: any) => {
if (typeof value === "object" && value !== null) {
if (seen.has(value)) {
const representation = [];
const firstSeen = seen.get(value);
if (firstSeen) representation.push(`first occurence: ${firstSeen}`);
if (value.type) representation.push(`type: ${value.type}`);
if (value.id) representation.push(`id: ${value.id}`);
return `[~circle. ${representation.join(", ")}]`;
}
seen.set(value, key);
}
return value;
};
};

const formatOutput = (...args: any[]) => {
args = args.map((entry) => {
if (typeof entry === "object") {
return JSON.stringify(entry, getCircularReplacer());
}
return entry;
});

return inspect(args.join(" | "), {
showHidden: false,
depth: null,
colors: false,
compact: true,
breakLength: Infinity,
}).replace(/'/g, "");
};

class Logger {
private _logLevel: LogLevel;
private _name: string;

constructor(logLevel: LogLevel, name: string) {
this._logLevel = logLevel;
this._name = name;
}

get logLevel() {
return this._logLevel;
}

debug(...args: any[]) {
if (this._logLevel <= LogLevel.DEBUG) {
console.info(
chalk.gray(
`${chalk.bgWhite.black(" DEBUG ")} ${this._name} | ${formatOutput(
...args
)}`
)
);
}
}

log(...args: any[]) {
this.info(args);
}

info(...args: any[]) {
if (this._logLevel <= LogLevel.INFO) {
console.info(
chalk.blue(
`${chalk.bgBlue.white(" INFO ")} ${this._name} | ${formatOutput(
...args
)}`
)
);
}
}

warn(...args: any[]) {
if (this._logLevel <= LogLevel.WARNING) {
console.warn(
chalk.yellow(
`${chalk.bgYellow.black(" WARN ")} ${this._name} | ${formatOutput(
...args
)}`
)
);
}
}

error(...args: any[]) {
if (this._logLevel <= LogLevel.ERROR) {
console.error(
chalk.red(
`${chalk.bgRed.black(" ERROR ")} ${this._name} | ${formatOutput(
...args
)}`
)
);
}
}
}

export default defineNuxtPlugin(() => {
const { logLevel: logLevelFileConfig } = useAppConfig();
const {
public: { logLevel: logLevelEnv },
} = useRuntimeConfig();

const logLevel = Number(logLevelEnv) || logLevelFileConfig || LogLevel.NONE;

const logger = new Logger(logLevel, "fsxa-nuxt3-pwa");
return {
provide: {
logger,
},
};
});

0 comments on commit b569b30

Please sign in to comment.