Skip to content
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
9 changes: 9 additions & 0 deletions lib/GADS/API.pm
Original file line number Diff line number Diff line change
Expand Up @@ -1464,6 +1464,15 @@ get '/api/get_key' => require_login sub {
}
};

post '/api/script_error' => require_login sub {
my $body = _decode_json_body();

info __x "SCRIPT ERROR: {url} - {description}",
url => $body->{url}, description => $body->{description};

_success("Script error logged successfully");
};

sub _success
{ my $msg = shift;
send_as JSON => {
Expand Down
62 changes: 45 additions & 17 deletions src/frontend/js/lib/logging.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,62 @@
import { uploadMessage } from "util/scriptErrorHandler";

class Logging {
constructor() {
this.allowLogging =
window.test ||
location.hostname === 'localhost' ||
location.hostname === '127.0.0.1' ||
location.hostname.endsWith('.peek.digitpaint.nl')
constructor() {
this.allowLogging =
window.test ||
location.hostname === 'localhost' ||
location.hostname === '127.0.0.1' ||
location.hostname.endsWith('.peek.digitpaint.nl')
}

log(...message) {
if(this.allowLogging) {
console.log(message)
}
if (this.allowLogging) {
console.log(message)
} else {
const message = this.formatMessage('log', ...message)
uploadMessage(message)
}
}

info(...message) {
if(this.allowLogging) {
console.info(message)
}
if (this.allowLogging) {
console.info(message)
} else {
const message = this.formatMessage('info', ...message)
uploadMessage(message)
}
}

warn(...message) {
if(this.allowLogging) {
console.warn(message)
}
if (this.allowLogging) {
console.warn(message)
} else {
const message = this.formatMessage('warn', ...message)
uploadMessage(message)
}
}

error(...message) {
if(this.allowLogging) {
console.error(message)
if (this.allowLogging) {
console.error(message)
} else {
const message = this.formatMessage('error', ...message)
uploadMessage(message)
}
}

formatMessage(type, ...message) {
let output = type + ': ';
for (let i = 0; i < message.length; i++) {
if (typeof message[i] === 'object') {
output += JSON.stringify(message[i]);
} else {
// This is wrapped so that anything that's not an object is converted to a string
output += `${message[i]}`;
}
if (i < message.length - 1) output += ' ';
}
return output;
}
}

Expand Down
31 changes: 31 additions & 0 deletions src/frontend/js/lib/util/scriptErrorHandler/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { uploadMessage } from "./lib/MessageUploader";

const createErrorString = (message: string, source: any, lineno: number, colno: number, error: Error | string | null) => {
let errorString = `Error: ${message}\nSource: ${source}\nLine: ${lineno}, Column: ${colno}`;
if (error && (error as Error)?.stack) {
errorString += `\nStack: ${(error as Error)?.stack}`;
}
return errorString;
}

window.onerror = function (message: string, source: any, lineno: number, colno: number, error: Error | string | null) {
if (location.host === 'localhost') {
// If we're on localhost, we log the error to the console. This is useful for development.
console.error("Script error occurred:", message, source, lineno, colno, error);
}
if (location.pathname === '/api/script_error' || location.pathname === '/login') {
// If we're on the script error page, we don't want to log it again.
console.error("Script error occurred but not logged to avoid recursion.");
console.error(createErrorString(message, source, lineno, colno, error));
return;
}

const description = createErrorString(message, source, lineno, colno, error)

uploadMessage(description)
.catch(err => {
console.error("Failed to upload script error:", err);
});
}

export { uploadMessage };
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { describe, it, expect, jest } from '@jest/globals';
import { MessageUploader } from './MessageUploader';

describe('MessageUploader', () => {
class MockUploader {
upload = jest.fn();
}

it('should upload messages correctly', async () => {
const uploader = new MockUploader();
const messageUploader = new MessageUploader(uploader);

const messages = { id: 1, content: 'Test message 1' };

await messageUploader.uploadMessage(JSON.stringify(messages));

expect(uploader.upload).toHaveBeenCalledTimes(1);
expect(uploader.upload).toHaveBeenCalledWith({
description: JSON.stringify(messages),
url: 'http://localhost/'
});
});
});
30 changes: 30 additions & 0 deletions src/frontend/js/lib/util/scriptErrorHandler/lib/MessageUploader.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Uploader } from "util/upload/UploadControl";

export const uploadMessage = async (message: string) => {
const body = {
description: message,
url: window.location.href
};
const uploader = new Uploader('/api/script_error', 'POST');
const messageUploader = new MessageUploader(uploader);
return await messageUploader.uploadMessage(body.description);
};

export class MessageUploader {
constructor(private uploader: Uploader) {
}

async uploadMessage(description: string): Promise<void> {
const csrf_token = document.body.dataset.csrf;
const body = {
description,
url: window.location.href,
csrf_token
};
try {
return await this.uploader.upload(body);
} catch (err) {
console.error("Failed to upload message:", err);
}
}
}
3 changes: 2 additions & 1 deletion src/frontend/js/site.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'bootstrap';
import 'components/graph/lib/chart';
import 'util/filedrag';
import 'util/actionsHandler';
import 'util/scriptErrorHandler';

// Components
import AddTableModalComponent from 'components/modal/modals/new-table';
Expand Down Expand Up @@ -87,4 +88,4 @@ registerComponent(AutosaveComponent);
// Initialize all components at some point
initializeRegisteredComponents(document.body);

handleActions();
handleActions();
Loading