Merge pull request #515 from padloc/feature/better-error-reports-2
Provide better information in error reports. Also added postgres logger
This commit is contained in:
commit
f2b7846072
|
@ -1,7 +0,0 @@
|
|||
<p>The following error occurred at {{ time }}:</p>
|
||||
|
||||
<p>
|
||||
Code: {{ code }} <br />
|
||||
Message: {{ message }} <br />
|
||||
Event ID: {{ eventId }}`
|
||||
</p>
|
|
@ -1,5 +0,0 @@
|
|||
The following error occurred at {{ time }}:
|
||||
|
||||
Code: {{ code }}
|
||||
Message: {{ message }}
|
||||
Event ID: {{ eventId }}`
|
|
@ -0,0 +1,3 @@
|
|||
<pre>
|
||||
{{ message }}
|
||||
</pre>
|
|
@ -0,0 +1 @@
|
|||
{{ message }}
|
|
@ -184,6 +184,22 @@
|
|||
# PL_LOGGING_MONGODB_MAX_SIZE=""
|
||||
# PL_LOGGING_MONGODB_MAX_DOCUMENTS=""
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# POSTGRES
|
||||
#
|
||||
# Use postgresql as log storage: https://www.npmjs.com/package/pg
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# PL_LOGGING_BACKEND=postgres
|
||||
# PL_LOGGING_POSTGRES_HOST=localhost
|
||||
# PL_LOGGING_POSTGRES_PORT=5432
|
||||
# PL_LOGGING_POSTGRES_DATABASE=padloc
|
||||
# PL_LOGGING_POSTGRES_USER=padloc
|
||||
# PL_LOGGING_POSTGRES_PASSWORD=""
|
||||
# PL_LOGGING_POSTGRES_TLS=false
|
||||
# PL_LOGGING_POSTGRES_TLS_CAFILE=""
|
||||
# PL_LOGGING_POSTGRES_TLS_REJECT_UNAUTHORIZED=true
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# MIXPANEL
|
||||
#
|
||||
|
|
|
@ -99,8 +99,10 @@ export class Err extends Error {
|
|||
}
|
||||
|
||||
toString() {
|
||||
return `Time: ${this.time.toISOString()}\nError Code: ${this.code}:\nError Message: ${
|
||||
this.message
|
||||
}\nStack Trace:\n${this.originalError ? this.originalError.stack : this.stack}`;
|
||||
return `Time: ${this.time.toISOString()}
|
||||
Error Code: ${this.code}
|
||||
Error Message: ${this.message}
|
||||
Stack Trace:\n${this.originalError ? this.originalError.stack : this.stack}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,8 +60,8 @@ export class JoinOrgInviteCompletedMessage extends Message<{ orgName: string; op
|
|||
}
|
||||
}
|
||||
|
||||
export class ErrorMessage extends Message<{ code: string; message: string; time: string; eventId: string }> {
|
||||
template = "error";
|
||||
export class PlainMessage extends Message<{ message: string }> {
|
||||
template = "plain";
|
||||
|
||||
get title() {
|
||||
return "Padloc Error Notification";
|
||||
|
|
|
@ -44,7 +44,7 @@ import { Org, OrgID, OrgMember, OrgMemberStatus, OrgRole, ScimSettings } from ".
|
|||
import { Invite } from "./invite";
|
||||
import {
|
||||
ConfirmMembershipInviteMessage,
|
||||
ErrorMessage,
|
||||
PlainMessage,
|
||||
JoinOrgInviteAcceptedMessage,
|
||||
JoinOrgInviteCompletedMessage,
|
||||
JoinOrgInviteMessage,
|
||||
|
@ -2078,8 +2078,6 @@ export class Server {
|
|||
}
|
||||
|
||||
private async _handleError(error: Error, req: Request, res: Response, context: Context) {
|
||||
console.error(error);
|
||||
|
||||
const e =
|
||||
error instanceof Err
|
||||
? error
|
||||
|
@ -2096,6 +2094,8 @@ export class Server {
|
|||
};
|
||||
|
||||
if (e.report) {
|
||||
console.error(error);
|
||||
|
||||
const evt = this.log("error", context, {
|
||||
error: e.toRaw(),
|
||||
request: {
|
||||
|
@ -2108,13 +2108,12 @@ export class Server {
|
|||
try {
|
||||
await this.messenger.send(
|
||||
this.config.reportErrors,
|
||||
new ErrorMessage({
|
||||
time: e.time.toISOString(),
|
||||
code: e.code,
|
||||
message: `Endpoint: ${req.method}\nMessage: ${e.message}\nDevice Info:\n${
|
||||
new PlainMessage({
|
||||
message: `The following error occured at ${e.time.toISOString()}:\n\nEndpoint: ${
|
||||
req.method
|
||||
}\nDevice Info:\n${
|
||||
req.device && JSON.stringify(req.device?.toRaw(), null, 4)
|
||||
}\nStack Trace:\n${e.stack}`,
|
||||
eventId: evt.id,
|
||||
}\n${e.toString()}${evt?.id ? `Event ID: ${evt.id}` : ""}`,
|
||||
})
|
||||
);
|
||||
} catch (e) {}
|
||||
|
|
|
@ -21,6 +21,18 @@ export async function uuid(): Promise<string> {
|
|||
].join("-");
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a random UUID v4
|
||||
* NOT CRYPTOGRAPHICALLY SAFE!
|
||||
*/
|
||||
export function unsafeUUID(): string {
|
||||
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
|
||||
var r = (Math.random() * 16) | 0,
|
||||
v = c == "x" ? r : (r & 0x3) | 0x8;
|
||||
return v.toString(16);
|
||||
});
|
||||
}
|
||||
|
||||
/** Caracters, by category */
|
||||
export const chars = {
|
||||
numbers: "0123456789",
|
||||
|
|
|
@ -82,7 +82,7 @@ export class LoggingConfig extends Config {
|
|||
}
|
||||
|
||||
@ConfigParam()
|
||||
backend: "void" | "mongodb" | "mixpanel" = "void";
|
||||
backend: "void" | "mongodb" | "postgres" | "mixpanel" = "void";
|
||||
|
||||
@ConfigParam()
|
||||
secondaryBackend?: "mongodb" | "mixpanel";
|
||||
|
@ -90,6 +90,9 @@ export class LoggingConfig extends Config {
|
|||
@ConfigParam(MongoDBStorageConfig)
|
||||
mongodb?: MongoDBStorageConfig;
|
||||
|
||||
@ConfigParam(PostgresConfig)
|
||||
postgres?: PostgresConfig;
|
||||
|
||||
@ConfigParam(MixpanelConfig)
|
||||
mixpanel?: MixpanelConfig;
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ import { AuthServer, AuthType } from "@padloc/core/src/auth";
|
|||
import { WebAuthnConfig, WebAuthnServer } from "./auth/webauthn";
|
||||
import { SMTPSender } from "./email/smtp";
|
||||
import { MongoDBStorage } from "./storage/mongodb";
|
||||
import { ConsoleMessenger, ErrorMessage } from "@padloc/core/src/messenger";
|
||||
import { ConsoleMessenger, PlainMessage } from "@padloc/core/src/messenger";
|
||||
import { FSAttachmentStorage, FSAttachmentStorageConfig } from "./attachments/fs";
|
||||
import {
|
||||
AttachmentStorageConfig,
|
||||
|
@ -33,11 +33,11 @@ import { resolve, join } from "path";
|
|||
import { MongoDBLogger } from "./logging/mongodb";
|
||||
import { MixpanelLogger } from "./logging/mixpanel";
|
||||
import { PostgresStorage } from "./storage/postgres";
|
||||
import { ErrorCode } from "@padloc/core/src/error";
|
||||
import { stripPropertiesRecursive } from "@padloc/core/src/util";
|
||||
import { DirectoryProvisioner } from "./provisioning/directory";
|
||||
import { ScimServer, ScimServerConfig } from "./scim";
|
||||
import { DirectoryProvider, DirectorySync } from "@padloc/core/src/directory";
|
||||
import { PostgresLogger } from "./logging/postgres";
|
||||
|
||||
const rootDir = resolve(__dirname, "../../..");
|
||||
const assetsDir = resolve(rootDir, process.env.PL_ASSETS_DIR || "assets");
|
||||
|
@ -75,7 +75,7 @@ async function initDataStorage(config: DataStorageConfig) {
|
|||
}
|
||||
}
|
||||
|
||||
async function initLogger({ backend, secondaryBackend, mongodb, mixpanel }: LoggingConfig) {
|
||||
async function initLogger({ backend, secondaryBackend, mongodb, postgres, mixpanel }: LoggingConfig) {
|
||||
let primaryLogger: Logger;
|
||||
|
||||
switch (backend) {
|
||||
|
@ -83,9 +83,15 @@ async function initLogger({ backend, secondaryBackend, mongodb, mixpanel }: Logg
|
|||
if (!mongodb) {
|
||||
throw "PL_LOGGING_BACKEND was set to 'mongodb', but no related configuration was found!";
|
||||
}
|
||||
const storage = new MongoDBStorage(mongodb);
|
||||
await storage.init();
|
||||
primaryLogger = new MongoDBLogger(storage);
|
||||
const mongoStorage = new MongoDBStorage(mongodb);
|
||||
await mongoStorage.init();
|
||||
primaryLogger = new MongoDBLogger(mongoStorage);
|
||||
break;
|
||||
case "postgres":
|
||||
if (!postgres) {
|
||||
throw "PL_LOGGING_BACKEND was set to 'postgres', but no related configuration was found!";
|
||||
}
|
||||
primaryLogger = new PostgresLogger(new PostgresStorage(postgres));
|
||||
break;
|
||||
case "void":
|
||||
primaryLogger = new VoidLogger();
|
||||
|
@ -302,11 +308,10 @@ async function init(config: PadlocConfig) {
|
|||
try {
|
||||
await emailSender.send(
|
||||
config.server.reportErrors,
|
||||
new ErrorMessage({
|
||||
code: ErrorCode.UNKNOWN_ERROR,
|
||||
message: `${err.message}\n${err.stack}`,
|
||||
time: new Date().toISOString(),
|
||||
eventId: "",
|
||||
new PlainMessage({
|
||||
message: `An uncaught exception occured at ${new Date().toISOString()}:\n${err.message}\n${
|
||||
err.stack
|
||||
}`,
|
||||
})
|
||||
);
|
||||
} catch (e) {}
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
import { Logger, LogEvent } from "@padloc/core/src/logging";
|
||||
import { PostgresStorage } from "../storage/postgres";
|
||||
|
||||
export class PostgresLogger implements Logger {
|
||||
constructor(private _storage: PostgresStorage) {}
|
||||
|
||||
log(type: string, data?: any) {
|
||||
const event = new LogEvent(type, data);
|
||||
event.id = `${event.time.toISOString()}_${Math.floor(Math.random() * 1e6)}`;
|
||||
(async () => {
|
||||
try {
|
||||
this._storage.save(event);
|
||||
} catch (e) {}
|
||||
})();
|
||||
return event;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue