Skip to content

Commit

Permalink
Move logError to app-level binding
Browse files Browse the repository at this point in the history
  • Loading branch information
bajtos committed Jun 2, 2017
1 parent 0d964a6 commit 74565e2
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 12 deletions.
7 changes: 7 additions & 0 deletions packages/core/src/application.ts
Expand Up @@ -59,6 +59,8 @@ export class Application extends Context {

this.handleHttp = (req: ServerRequest, res: ServerResponse) =>
this._handleHttpRequest(req, res);

this.bind('logError').to(this._logError.bind(this));
}

protected _handleHttpRequest(request: ServerRequest, response: ServerResponse) {
Expand Down Expand Up @@ -100,6 +102,11 @@ export class Application extends Context {
public controller<T>(controllerCtor: Constructor<T>): Binding {
return this.bind('controllers.' + controllerCtor.name).toClass(controllerCtor);
}

protected _logError(err: Error, statusCode: number, req: ServerRequest): void {
console.error('Unhandled error in %s %s: %s %s',
req.method, req.url, statusCode, err.stack || err);
}
}

export interface AppConfig {
Expand Down
10 changes: 3 additions & 7 deletions packages/core/src/http-handler.ts
Expand Up @@ -35,11 +35,12 @@ export class HttpHandler {
this._bindFindRoute(requestContext);
this._bindInvokeMethod(requestContext);

// TODO(bajtos) instantiate the Sequence via ctx.get()
const findRoute = await requestContext.get('findRoute');
const invokeMethod = await requestContext.get('invokeMethod');
const logError = await requestContext.get('logError');
const sequence = new Sequence(findRoute, invokeMethod, logError);

// TODO(bajtos) instantiate the Sequence via ctx.get()
const sequence = new Sequence(findRoute, invokeMethod, this.logError.bind(this));
return sequence.run(parsedRequest, response);
}

Expand Down Expand Up @@ -79,9 +80,4 @@ export class HttpHandler {
};
});
}

logError(err: Error, statusCode: number, req: ServerRequest): void {
console.error('Unhandled error in %s %s: %s %s',
req.method, req.url, statusCode, err.stack || err);
}
}
17 changes: 12 additions & 5 deletions packages/core/test/integration/http-handler.integration.ts
Expand Up @@ -3,7 +3,7 @@
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

import {HttpHandler, Sequence} from '../..';
import {HttpHandler, Sequence, ServerRequest} from '../..';
import {Context} from '@loopback/context';
import {expect, Client, createClientForHandler} from '@loopback/testlab';
import {OpenApiSpec, ParameterObject} from '@loopback/openapi-spec';
Expand Down Expand Up @@ -374,6 +374,12 @@ context('with an operation echoing a string parameter from query', () => {
let handler: HttpHandler;
function givenHandler() {
rootContext = new Context();
rootContext.bind('logError').to(logger);
function logger(err: Error, statusCode: number, req: ServerRequest) {
console.error('Unhandled error in %s %s: %s %s',
req.method, req.url, statusCode, err.stack || err);
}

handler = new HttpHandler(rootContext);
}

Expand All @@ -388,12 +394,13 @@ context('with an operation echoing a string parameter from query', () => {
}

function logErrorsExcept(ignoreStatusCode: number) {
// TODO(bajtos) Rework this code to customize the logger via rootContext.bind()
const oldLogger = handler.logError;
handler.logError = (err, statusCode, req) => {
const oldLogger: Function = rootContext.getSync('logError');
rootContext.bind('logError').to(conditionalLogger);

function conditionalLogger(err: Error, statusCode: number, req: ServerRequest) {
if (statusCode === ignoreStatusCode) return;
// tslint:disable-next-line:no-invalid-this
oldLogger.apply(this, arguments);
};
}
}
});
34 changes: 34 additions & 0 deletions packages/core/test/unit/application/application.test.ts
@@ -0,0 +1,34 @@
// Copyright IBM Corp. 2013,2017. All Rights Reserved.
// Node module: @loopback/core
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

import {expect, ShotRequest} from '@loopback/testlab';
import {Application, ServerRequest} from '../../..';

describe('Application', () => {
describe('"logError" binding', () => {
it('provides a default', async () => {
const app = new Application();
const logError = await app.get('logError');
expect(logError.length).to.equal(3); // (err, statusCode, request)
});

it('can be customized by overriding Application._logError() method', async () => {
let lastLog: string = 'logError() was not called';

class MyApp extends Application {
protected _logError(err: Error, statusCode: number, request: ServerRequest) {
lastLog = `${request.url} ${statusCode} ${err.message}`;
}
}

const app = new MyApp();
const logError = await app.get('logError');
logError(new Error('test-error'), 400, new ShotRequest({url: '/'}));

expect(lastLog).to.equal('/ 400 test-error');
});
});
});

0 comments on commit 74565e2

Please sign in to comment.