Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: logging setup and error card error display #349

Merged
merged 1 commit into from
Aug 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion nodemon.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"DANGEROUSLY_DISABLE_SECURE_CSRF_COOKIES": "true",
"ORY_SDK_URL": "http://localhost:4433",
"KRATOS_PUBLIC_URL": "http://localhost:4433",
"KRATOS_ADMIN_URL": "http://localhost:4434"
"KRATOS_ADMIN_URL": "http://localhost:4434",
"NODE_ENV": "development"
}
}
42 changes: 40 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"dependencies": {
"@ory/client": "1.14.3",
"@ory/elements-markup": "0.3.0-rc.1",
"@redtea/format-axios-error": "2.1.1",
"accept-language-parser": "1.5.0",
"axios": "1.7.4",
"body-parser": "1.20.2",
Expand Down
10 changes: 5 additions & 5 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ app.use(baseUrl, router)
const port = Number(process.env.PORT) || 3000

let listener = (proto: "http" | "https") => () => {
console.log(`Listening on ${proto}://0.0.0.0:${port}`)
logger.info(`Listening on ${proto}://0.0.0.0:${port}`)
}

// When using the Ory Admin API Token, we assume that this application is also
Expand All @@ -128,16 +128,16 @@ if (
String(process.env.CSRF_COOKIE_NAME || "").length === 0 ||
String(process.env.CSRF_COOKIE_SECRET || "").length < 8
) {
console.error(
logger.error(
"Cannot start the server without the required environment variables!",
)
console.error(
logger.error(
"COOKIE_SECRET must be set and be at least 8 alphanumerical character `export COOKIE_SECRET=...`",
)
console.error(
logger.error(
"CSRF_COOKIE_NAME must be set! Prefix the name to scope it to your domain `__HOST-` `export CSRF_COOKIE_NAME=...`",
)
console.error(
logger.error(
"CSRF_COOKIE_SECRET must be set and be at least 8 alphanumerical character `export CSRF_COOKIE_SECRET=...`",
)
} else {
Expand Down
30 changes: 28 additions & 2 deletions src/pkg/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,35 @@
import expressWinston from "express-winston"
import winston from "winston"

let format: winston.Logform.Format = winston.format.json()
if (process.env.NODE_ENV === "development") {
format = winston.format.combine(
winston.format.simple(),
winston.format.colorize({
all: true,
colors: {
info: "blue",
error: "red",
warn: "yellow",
},
}),
)
}

const config = {
format: winston.format.json(),
format: winston.format.combine(winston.format.timestamp(), format),
transports: [new winston.transports.Console()],
}
export const logger = winston.createLogger(config)
export const middleware = expressWinston.logger({ winstonInstance: logger })
export const middleware = expressWinston.logger({
winstonInstance: logger,
ignoreRoute: (req) => req.url.startsWith("/assets"),
ignoredRoutes: [
"/theme.css",
"/main.css",
"/content-layout.css",
"/style.css",
"/ory-small.svg",
"/favico.png",
],
})
48 changes: 44 additions & 4 deletions src/routes/500.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,61 @@
// Copyright © 2022 Ory Corp
// SPDX-License-Identifier: Apache-2.0
import { RouteRegistrator } from "../pkg"
import { logger, RouteRegistrator } from "../pkg"
import { UserErrorCard } from "@ory/elements-markup"
import { format } from "@redtea/format-axios-error"
import { NextFunction, Request, Response } from "express"

function formatRequest(req: Request) {
return {
headers: req.headers,
method: req.method,
url: req.url,
httpVersion: req.httpVersion,
body: req.body,
cookies: req.cookies,
path: req.path,
protocol: req.protocol,
query: req.query,
hostname: req.hostname,
ip: req.ip,
originalUrl: req.originalUrl,
params: req.params,
}
}

export const register500Route: RouteRegistrator = (app, createHelpers) => {
app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
console.error(err, err.stack)
let jsonError: string = ""
try {
const formattedError = format(err)

logger.error("An error occurred", {
error: formattedError,
req: formatRequest(req),
})
delete (formattedError as any).config
delete (formattedError as any).isAxiosError
jsonError = JSON.stringify(formattedError)
} catch (e) {
// This shouldn't happen, as the try block should not throw an error.
// But if it does, we log it and render the Error card with a generic error message.
// If this is removed, the server will crash if the error is not serializable.
logger.error("An error occurred while serializing the error", {
error: err,
req: formatRequest(req),
})
}
res.status(500).render("error", {
card: UserErrorCard({
title: "Internal Server Error",
cardImage: createHelpers?.(req, res).logoUrl,
backUrl: req.header("Referer") || "welcome",
error: {
id: "backend-error",
id: "interal_server_error",
error: {
...err,
message:
"An internal server error occurred. Please try again later.",
debug: JSON.parse(jsonError),
},
},
}),
Expand Down
Loading