Winston and Meteor 1.3

Written by Pete Corey on Jul 4, 2016.

Logging is a very important part of any production application. Quality logging provides invaluable, irreplaceable information about the inner workings of your application as it runs.

Winston is a great tool for providing a unified logging interface for a variety of log transports (the console, rotating files, third party services, etc…).

Unfortunately, some of the intricacies of Meteor’s isomorphic build system make using Winston more difficult that it would seem at first glance.

Setting Up Winston

In Meteor 1.3, adding Winston to your project is as simple as installing the NPM package:


meteor npm install winston

Thanks to its stellar documentation, setting up Winston as an ES6 module in your Meteor project is fairly straight forward too:


import winston from "winston";

let console = new winston.transports.Console({
    name: "console",
    timestamp: true
});

export const logger = new winston.Logger({
    transports: [
        console
    ]
});

Now that logger is being exported by our new module, it can be imported anywhere else in the project and used to log vital information:


import { logger } from "/imports/logger";

logger.info("Party time! 🎉");

While this works beautifully on the server, we’ll quickly run into issues when we start up our application and try to do some logging from the client.

Troubles on the Client

After starting up the application, you may see an error like the following in your browser console:


TypeError: fs.readdirSync is not a function

If you spend some time Googling this obtuse error, you’ll eventually land on this open Github issue which explains that Winston currently doesn’t support in-browser logging.

This unfortunate information leaves us with two options. We can either restrict imports of our logger module to only server-side components, or we can wrap our import winston and export logger statements in a Meteor.isServer guard.

Because the first option would be difficult to manage and would be a constant source of bugs, a reasonable solution would be to choose the second option:


import { Meteor } from "meteor/meteor";

if (Meteor.isServer) {

    import winston from "winston";

    let console = new winston.transports.Console({
        name: "console",
        timestamp: true
    });

    export const logger = new winston.Logger({
        transports: [
            console
        ]
    });
    
}

Now that Winston is confined to the server, our client is happy.

A Tale of Two Loggers

Unfortunately, this solutions leaves us in an awkward position. On the server, we can import and use our new logger, but on the client we’re forced to continue using console for all of our logging needs.

Isomorphic code, or code that runs on both the server and the client, amplifies the awkwardness of this situation.

Imagine that a collection has a helper method which can be called from both the client and the server. How would we log an error in that helper? If we’re on the client, we’d have to use console.log or console.error, but if we’re on the server we would want to use logger.error:


Collection.helpers({
    foo() {
        return something()
        .catch((e) => {
            if (Meteor.isServer) {
                logger.error(e);
            }
            else {
                console.error(e);
            }
        });
    }
});

This is far from an ideal situation. Ideally, we’d like to be able to use logger across the board, regardless of if we’re on the client or server.

Creating a Faux-Logger

Thankfully, we can make this ideal situation a reality.

Back in our logger module, we can detect if we’re being imported on the client and, if we are, export an object that looks like a Winston logger, but is actually console.


if (Meteor.isServer) {
    …
}
else {
    export const logger = console;
}

On Chrome this works just as we would expect. If we import logger on the client we can use logger.info, logger.warn, and logger.error because Chrome implements all of these methods (info, warn, and error) in its built-in console object.

However, if you want to target other browsers or environments that don’t natively implement all of these logging methods, we’ll have to implement them in our faux-logger ourselves:


if (Meteor.isServer) {
    …
}
else {
    export const logger = {
        info: console.log,
        warn: console.log,
        error: console.log
    };
}

We can even take this solution to the next level by decorating our calls to console.log and prepending whatever information we need:


function prepend(argument) {
    return function() and{
        let args = [].slice.call(arguments);
        args.unshift(argument);
        console.log.apply(console, args);
    }
}

export const logger = {
    info: console.log,
    warn: prepend("⚠️"),
    error: prepend("☠️")
};

Now our logger module can be imported and used as expected throughout our entire code base.

The browser’s underlying logging framework will be used on the client, and Winston will be used on the server. While the underlying logging changes depending on context, our developer experience does not.

A New Look For East5th

Written by Pete Corey on Jun 27, 2016.

Things may look a bit different around here. I’m excited and relieved to finally release a design overhaul that I’ve been working on for the past several weeks.

The main goal of this redesign is to bring all things East5th under a single roof. No longer are things haphazardly scattered between three different subdomains and a variety of hosting services. Everything we have to offer can now be found at www.east5th.co.

All of our old blog content is still alive and well and can now be found at www.east5th.co/blog/. Be sure to check out our newly unified services page, and our brand new collection of case-studies.


When we get down to the nitty gritty details, things are still fundamentally the same. Now, the entire site is a collection of static pages built and generated with Jekyll.

Keeping things simple, we’re still relying on Github Pages for hosting, and using our previously described Zapier setup to schedule and release future blog posts.

Scheduling Posts With Jekyll, Github Pages & Zapier
Zapier Named Variables - Scheduling Posts Part 2

Last, but not least, we’re using a slightly modified Prism for all of our inline and block syntax highlighting needs.


This redesign is just the beginning on a larger set of infrastructure changes planned for East5th.

One of these upcoming changes will involve building out a Meteor backend application that communicates with a Serverless microservice. I’m planning on documenting and publishing the entire process behind building this service.

Stay tuned!

Node Vulnerability Scanners in a 1.3 World

Written by Pete Corey on Jun 20, 2016.

Meteor’s recent transition to using NPM modules has opened up a world of possibilities for Meteor developers. Unfortunately, with great power comes great responsibility.

Along with a host of new functionality, NPM packages also come with a world of vulnerabilities and security concerns. In fact, over 14% of all NPM modules have known vulnerabilities.

Node Security Project

Thankfully, there are teams and tools dedicated to tackling the problem of documenting and cataloging known Node.js module vulnerabilities. A very popular option for scanning and monitoring your NPM dependencies for known vulnerabilities is the Node Security Platform.

In its most basic form, NSP offers a command line tool that scans your package.json or your npm-shrinkwrap.json for know vulnerabilities.

Because all of your NPM dependencies are saved in the package.json file in your project root, using the nsp tool to scan your Meteor project for vulnerabilities is a simple process:


> cd $YOUR_METEOR_PROJECT
> nsp check
(+) No known vulnerabilities found

If NSP finds and vulnerable dependencies, you’ll be given more information and hopefully an upgrade patch that will fix the issue.

Snyk

Snyk is another tool designed to find vulnerable NPM dependencies within your Node.js project. The Snyk command line tool can be used just like the NSP command line tool:


> cd $YOUR_METEOR_PROJECT
> snyk test
✓ Tested ... for known vulnerabilities, no vulnerabilities found.

Snyk even lets you test GitHub repositories or individual NPM modules using their web tool.

I’m a big fan of Snyk. Their VulnDB is built on top of Node Security Project’s advisories database and is taking strides to improve and build upon that great foundation. At the time of writing this article, Snyk has documented 105 Node.js vulnerabilities in their vulnerability database.

The Snyk team also regularly posts insightful blog posts about a variety of security topics.

Meteor Package Dependencies

While NSP and Snyk are great options for testing your base project’s NPM dependencies for known vulnerabilities, there are other avenues for vulnerable Node packages to find their way into your Meteor project.

Pre-1.3 Meteor projects relied on using Meteor packages to pull in NPM dependencies or using the meteorhacks:npm package to simulate direct dependencies within the base project. Both of these techniques obfuscate the actual NPM dependencies being used and make it difficult to scan them using traditional techniques.

Check out my post on Scanning Meteor Projects for Node Vulnerabilities for information on writing a bash script to dive into a Meteor project’s build bundle to call nsp check or snyk test on a project’s entire dependency tree.

Final Thoughts

Both the Node Security Platform and Snyk offer fantastic tools for scanning your Node.js and Meteor projects for known vulnerabilities. I recommend you pick one of these two tools and incorporate this type of vulnerability scanning into your development, deployment, and continuous integration workflow.

Using Snyk or NSP with a Meteor-specific vulnerability scanning tool such as Package Scan will help give you some peace of mind as you move forward developing fantastic Meteor applications.