Skip to content
This repository has been archived by the owner on Jun 3, 2019. It is now read-only.

Commit

Permalink
Server logging enhancements (#508)
Browse files Browse the repository at this point in the history
* Improving logging experience + consolidating to single log function

* Adding pretty-error for more readable node error stack

* Fix eslint error

* Logging requests received

* Re-commit logging requests received
  • Loading branch information
oyeanuj authored and Steven Truesdell committed Oct 3, 2017
1 parent 338ecfd commit 111a170
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 27 deletions.
9 changes: 7 additions & 2 deletions config/utils/envVars.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@
*/

import appRootDir from 'app-root-dir';
import colors from 'colors/safe';
import dotenv from 'dotenv';
import fs from 'fs';
import path from 'path';

import ifElse from '../../shared/utils/logic/ifElse';
import removeNil from '../../shared/utils/arrays/removeNil';

import { log } from '../../internal/utils';

// PRIVATES

function registerEnvFile() {
Expand All @@ -40,7 +41,11 @@ function registerEnvFile() {
// If we found an env file match the register it.
if (envFilePath) {
// eslint-disable-next-line no-console
console.log(colors.bgBlue.white(`==> Registering environment variables from: ${envFilePath}`));
log({
title: 'server',
level: 'special',
message: `Registering environment variables from: ${envFilePath}`,
});
dotenv.config({ path: envFilePath });
}
}
Expand Down
16 changes: 12 additions & 4 deletions internal/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,21 @@ export function log(options) {
}

const level = options.level || 'info';
const msg = `==> ${title} -> ${options.message}`;
const msg = `${title}: ${options.message}`;

switch (level) {
case 'warn': console.log(colors.yellow(msg)); break;
case 'error': console.log(colors.bgRed.white(msg)); break;
case 'warn':
console.log(colors.yellow(msg));
break;
case 'error':
console.log(colors.bgRed.white(msg));
break;
case 'special':
console.log(colors.italic.cyan(msg));
break;
case 'info':
default: console.log(colors.green(msg));
default:
console.log(colors.green.dim(msg));
}
}

Expand Down
28 changes: 15 additions & 13 deletions internal/webpack/configFactory.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import path from 'path';
import webpack from 'webpack';
import WebpackMd5Hash from 'webpack-md5-hash';

import { happyPackPlugin } from '../utils';
import { happyPackPlugin, log } from '../utils';
import { ifElse } from '../../shared/utils/logic';
import { mergeDeep } from '../../shared/utils/objects';
import { removeNil } from '../../shared/utils/arrays';
Expand Down Expand Up @@ -44,18 +44,20 @@ export default function webpackConfigFactory(buildOptions) {
const ifDevClient = ifElse(isDev && isClient);
const ifProdClient = ifElse(isProd && isClient);

console.log(
`==> Creating ${isProd
log({
level: 'info',
title: 'Webpack',
message: `Creating ${isProd
? 'an optimised'
: 'a development'} bundle configuration for the "${target}"`,
);
});

const bundleConfig =
isServer || isClient
? // This is either our "server" or "client" bundle.
config(['bundles', target])
config(['bundles', target])
: // Otherwise it must be an additional node bundle.
config(['additionalNodeBundles', target]);
config(['additionalNodeBundles', target]);

if (!bundleConfig) {
throw new Error('No bundle configuration exists for target:', target);
Expand Down Expand Up @@ -124,9 +126,9 @@ export default function webpackConfigFactory(buildOptions) {

target: isClient
? // Only our client bundle will target the web as a runtime.
'web'
'web'
: // Any other bundle must be targetting node as a runtime.
'node',
'node',

// Ensure that webpack polyfills the following node features for use
// within any bundles that are targetting node as a runtime. This will be
Expand Down Expand Up @@ -517,12 +519,12 @@ export default function webpackConfigFactory(buildOptions) {
// paths used on the client.
publicPath: isDev
? // When running in dev mode the client bundle runs on a
// seperate port so we need to put an absolute path here.
`http://${config('host')}:${config('clientDevServerPort')}${config(
'bundles.client.webPath',
)}`
// seperate port so we need to put an absolute path here.
`http://${config('host')}:${config('clientDevServerPort')}${config(
'bundles.client.webPath',
)}`
: // Otherwise we just use the configured web path for the client.
config('bundles.client.webPath'),
config('bundles.client.webPath'),
// We only emit files when building a web bundle, for the server
// bundle we only care about the file loader being able to create
// the correct asset URLs.
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
"modernizr": "3.5.0",
"normalize.css": "7.0.0",
"offline-plugin": "4.8.3",
"pretty-error": "2.1.1",
"prop-types": "15.5.10",
"react": "15.6.1",
"react-async-bootstrapper": "1.1.1",
Expand Down
35 changes: 33 additions & 2 deletions server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import serviceWorker from './middleware/serviceWorker';
import offlinePage from './middleware/offlinePage';
import errorHandlers from './middleware/errorHandlers';
import config from '../config';
import { log } from '../internal/utils';

// Create our express based server.
const app = express();
Expand Down Expand Up @@ -43,14 +44,44 @@ app.use(config('bundles.client.webPath'), clientBundle);
app.use(express.static(pathResolve(appRootDir.get(), config('publicAssetsPath'))));

// The React application middleware.
app.get('*', reactApplication);
app.get('*', (request, response) => {
log({
title: 'Request',
level: 'special',
message: `Received for "${request.url}"`,
});

return reactApplication(request, response);
});

// Error Handler middlewares.
app.use(...errorHandlers);

// Create an http listener for our express app.
const listener = app.listen(config('port'), () =>
console.log(`Server listening on port ${config('port')}`));
log({
title: 'server',
level: 'special',
message: `✓
${config('welcomeMessage')}
${config('htmlPage.defaultTitle')} is ready!
with
Service Workers: ${config('serviceWorker.enabled')}
Polyfills: ${config('polyfillIO.enabled')} (${config('polyfillIO.features').join(', ')})
Server is now listening on Port ${config('port')}
You can access it in the browser at http://${config('host')}/${config('port')}
Press Ctrl-C to stop.
`,
}),
);

// We export the listener as it will be handy for our development hot reloader,
// or for exposing a general extension layer for application customisations.
Expand Down
13 changes: 11 additions & 2 deletions server/middleware/errorHandlers.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
/* eslint-disable no-console */
/* eslint-disable no-unused-vars */

const prettyError = require('pretty-error').start();

// Configure prettyError to simplify the stack trace:

// skip events.js and http.js and similar core node files
prettyError.skipNodeFiles();

// skip all the trace lines about express` core and sub-modules
prettyError.skipPackage('express');

const errorHandlersMiddleware = [
/**
* 404 errors middleware.
Expand All @@ -21,8 +31,7 @@ const errorHandlersMiddleware = [
*/
function unexpectedErrorMiddleware(err, req, res, next) {
if (err) {
console.log(err);
console.log(err.stack);
console.log(prettyError.render(err));
}
res.status(500).send('Sorry, an unexpected error occurred.');
},
Expand Down
13 changes: 9 additions & 4 deletions server/middleware/reactApplication/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import config from '../../../config';

import ServerHTML from './ServerHTML';
import DemoApp from '../../../shared/components/DemoApp';
import { log } from '../../../internal/utils';

/**
* React application middleware, supports server side rendering.
Expand All @@ -26,7 +27,11 @@ export default function reactApplicationMiddleware(request, response) {
if (config('disableSSR')) {
if (process.env.BUILD_FLAG_IS_DEV === 'true') {
// eslint-disable-next-line no-console
console.log('==> Handling react route without SSR');
log({
title: 'Server',
level: 'info',
message: `Handling react route without SSR: ${request.url}`,
});
}
// SSR is disabled so we will return an "empty" html page and
// rely on the client to initialize and render the react application.
Expand Down Expand Up @@ -78,10 +83,10 @@ export default function reactApplicationMiddleware(request, response) {
.status(
reactRouterContext.missed
? // If the renderResult contains a "missed" match then we set a 404 code.
// Our App component will handle the rendering of an Error404 view.
404
// Our App component will handle the rendering of an Error404 view.
404
: // Otherwise everything is all good and we send a 200 OK status.
200,
200,
)
.send(`<!DOCTYPE html>${html}`);
});
Expand Down

0 comments on commit 111a170

Please sign in to comment.