Skip to content
This repository has been archived by the owner on Jan 22, 2021. It is now read-only.

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
johanbrook committed Feb 24, 2015
0 parents commit 7b162e5
Show file tree
Hide file tree
Showing 11 changed files with 363 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
app/.meteor
.npm/
22 changes: 22 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"rules": {
"brace-style": [2, "1tbs", { "allowSingleLine": true }],
"strict": 0,
"quotes": [2, "single"],
"no-underscore-dangle": 0,
"curly": 0
},

"env": {
"browser": true,
"node": true,
"jquery": true,
"meteor": true
},

"globals": {
"Loggers": true,
"Logger": true,
"logger": true
}
}
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.npm/
.DS_Store
82 changes: 82 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Lookback Logger

A Meteor logger that logs to [Loggly](https://www.loggly.com/) or local `console.log`.

## Install

Lookback Logger is available on [Atmosphere](https://atmospherejs.com/lookback/logger) as `lookback:logger`:

```bash
meteor add lookback:logger
```

## Usage

A global `Logger` object is automatically exported from within the package and available in your app. It has the log level methods `debug`, `warn`, `error` and `info`.

```js
Logger.info('Some logging');
Logger.warn('Watch out!');
Logger.error('Someone screwed up ...');
Logger.debug('Herp-a-derp.');
```

Each `Logger` method takes a message as a string, and optionally an array of tags:

```js
Logger.info('Some logging', ['my-tag']);
```
This can be shown in the Loggly interface.

Additionally, a global `logger` factory function is exported. It is used to create a logger:

```js
someLogger = logger(params);
```

`logger` takes an object of parameters:

```js
myLogger = logger({
// Local logging. Defaults to true.
local: true,

// Loggly options. Defaults to {}. If set, local logging will be disabled.
loggly: {
// Options to send to the Loggly npm module.
logglyModuleOptions: {
token: '<your loggly token>',
subdomain: 'foobar',
json: true
},
// Params to send to Loggly with every request.
baseParams: {
environment: 'development', // Defaults to process.env.NODE_ENV
serverName: 'My Computer'
}
}
});
```
Please refer to the documentation for the [`loggly`](http://npmjs.org/package/loggly) npm module for documentation on the `logglyModuleOptions`.

## Tests

```bash
meteor test-packages lookback:logger
```

Locally:

```bash
meteor test-packages ./
```

## Version history

- `1.0.0` - Initial publish.

## Contributions

Contributions are welcome. Please open issues and/or file Pull Requests.

Made by [Lookback](http://lookback.io).
20 changes: 20 additions & 0 deletions init.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// This really shouldn't be part of the package because its forces the
// developer to set Meteor.settings.logging rather than initing the Logger
// any way they want.
//
// The upside is however that other packages can use the logger package
// directly so we dont have to use a wrapper package just for the config.

var settings = Meteor.settings.logging || {};

// Default to logging locally
var local = true;
if (typeof settings.local !== 'undefined')
local = settings.local;

var loggly = settings.loggly;

Logger = logger({
local: local,
loggly: loggly
});
93 changes: 93 additions & 0 deletions logger.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
var loggly = Npm.require('loggly');

/**
@desc Gives us log levels that will be used with loggly.
E.g. calling MyLogger.info('Merge complete', 'Processing') will
log the message 'Merge complete' with the log level 'info' and the tag
'Processing' to loggly or whatever logger you are using.
@param {(function|array)} loggers - the function or array of functions to do the logging.
@return {object} - Logging methods for each log level
*/
function attachLogLevels(loggers) {
if (_.isFunction(loggers))
loggers = [loggers];

var levels = [
'error',
'warn',
'info',
'debug'
];

return loggers.reduce(function(memo, logger) {
levels.forEach(function(level) {
// Bind level value as first argument to each logger function
memo[level] = _.partial(logger, level);
});

return memo;
}, {});
}

/**
@example - Logger = logger({
loggly: {
logglyModuleOptions: {
token: 'test',
subdomain: 'lookback',
json: true,
},
baseParams: {
environment: 'development',
serverName: 'my dev env' // if you need more than the ip
}
},
local: false,
});
Logger.debug('Init hyperdrive', ['this-is-a-tag', 'and-another-tag']);
@param {object} options
@param {object} [options.loggly] - options for loggly.
@param {object} options.loggly.logglyModuleOptions - options to init the loggly module
@param {object} options.loggly.baseParams - key/values sent to loggly with every request.
@param {object} [options.local] - logs everything locally, and to loggly if thats configured.
useful if you need the log data immediately.
@return {object} - Logger with log methods
*/
logger = function(options) {
options = options || {};
var logglyOptions = options.loggly;

// log locally if loggly isnt enabled or if specifically requested.
var local = options.local || !logglyOptions;

var loggers = [];

if (logglyOptions) {
try {
var logglyClient = loggly.createClient(logglyOptions.logglyModuleOptions);
var baseParams = logglyOptions.baseParams || {};

// Use environment name from options or default to NODE_ENV.
baseParams.environment = baseParams.environment || process.env.NODE_ENV;

baseParams.platform = 'site';

loggers.push(Loggers.loggly(logglyClient, baseParams));
} catch (e) {
console.warn('Error creating Loggly client. No logs will be sent.');
console.warn(e.message);
}
}

if (local) {
loggers.push(Loggers.local);
}

return attachLogLevels(loggers);
};
16 changes: 16 additions & 0 deletions loggers/local.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Local log
Loggers.local = function(level, message, tags) {
var method = (function() {
switch (level) {
case 'info': return 'info';
case 'debug': return 'log';
case 'warn': return 'warn';
case 'error': return 'error';
}
})();

if(tags)
console[method](message, tags);
else
console[method](message);
};
1 change: 1 addition & 0 deletions loggers/loggers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Loggers = {};
34 changes: 34 additions & 0 deletions loggers/loggly.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
Loggers.loggly = function(logglyClient, baseParams) {
baseParams = baseParams || {};

// @desc Log a message with a level and one or more tags to loggly
//
// @param {string} level
// @param {string} message
// @param {(string|array)} [tags]
return function log(level, message, tags) {
if (tags && _.isString(tags))
tags = [tags];

var toLog = {
message: message,
level: level
};

_.extend(toLog, baseParams);

// If the log fails for some reason (bad config, timeout or whatever)
// at least log it to console.
var callback = function(err) {
if (err) {
console.error('Error while logging', { log: toLog, tags: tags });
console.error(err);
}
};

if (tags)
logglyClient.log(toLog, tags, callback);
else
logglyClient.log(toLog, callback);
};
};
32 changes: 32 additions & 0 deletions package.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
Package.describe({
name: 'lookback:logger',
summary: 'Logger for Meteor with Loggly integration',
git: 'https://github.com/lookback/meteor-logger',
version: '0.0.1'
});

Npm.depends({
'loggly': '1.0.8'
});

var where = 'server';

Package.onUse(function (api) {
api.use('underscore', where);

api.addFiles([
'loggers/loggers.js',
'loggers/local.js',
'loggers/loggly.js',
'logger.js',
'init.js'
]
, where);

api.export(['Logger', 'logger'], where);
});

Package.onTest(function(api) {
api.use(['coffeescript', 'practicalmeteor:munit', 'lookback:logger'], where);
api.addFiles(['tests/logger-spec.coffee'], where);
});
59 changes: 59 additions & 0 deletions tests/logger-spec.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
Should = should()

describe 'Logger', ->

beforeEach ->
spies.create 'info', console, 'info'
spies.create 'warn', console, 'warn'
spies.create 'debug', console, 'log'
spies.create 'error', console, 'error'

afterEach ->
spies.restoreAll()

it 'should exist as an object', ->
Logger.should.be.defined
Logger.should.be.an 'object'

it 'should log locally per default', ->
Logger.info 'Foo'
spies.info.should.have.been.calledWith 'Foo'

describe 'Local Logging', ->

it 'should log info', ->
Logger.info 'Foo'
spies.info.should.have.been.calledWith 'Foo'

it 'should log debug', ->
Logger.debug 'Foo'
spies.debug.should.have.been.calledWith 'Foo'

it 'should log warn', ->
Logger.warn 'Foo'
spies.warn.should.have.been.calledWith 'Foo'

it 'should log error', ->
Logger.error 'Foo'
spies.error.should.have.been.calledWith 'Foo'

it 'should log tags', ->
['info', 'warn', 'error', 'debug'].forEach (method) ->
Logger[method]('Foo', ['bar', 'baz'])
spies[method].should.have.been.calledWith 'Foo', ['bar', 'baz']

describe 'logger', ->

it 'should exist as a function', ->
logger.should.be.defined
logger.should.be.a 'function'

it 'should return a logger object', ->
log = logger()
log.should.be.an 'object'

it 'should have all methods', ->
log = logger()

'info debug error warn'.split(' ').forEach (method) ->
log[method].should.be.a 'function'

0 comments on commit 7b162e5

Please sign in to comment.