Skip to content

Commit

Permalink
Initial import of logging-bunyan
Browse files Browse the repository at this point in the history
  • Loading branch information
ofrobots committed Feb 10, 2017
1 parent a0a3a1c commit 0e63ff0
Show file tree
Hide file tree
Showing 6 changed files with 1,922 additions and 0 deletions.
89 changes: 89 additions & 0 deletions packages/logging-bunyan/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# @google-cloud/logging-bunyan
> Stackdriver Logging stream for [Bunyan][bunyan]
This module provides an easy to use, higher-level layer for working with Stackdriver Logging, compatible with Bunyan. Simply use this as a raw stream with your existing Bunyan loggers.

For lower-level access to the Stackdriver Logging API, see [@google-cloud/logging][@google-cloud/logging].

> *This module is experimental and should be used by early adopters. This module uses APIs that may be undocumented and subject to change without notice.*
First, install `@google-cloud/logging-bunyan` with npm:

``` sh
$ npm install --save @google-cloud/logging-bunyan
```

If you are running your app on Google Cloud Platform, you won't need to worry about supplying connection configuration options to `@google-cloud/logging-bunyan` — we figure that out for you.

However, if you're running your app elsewhere, you will need to provide project details to authenticate API requests.


``` js
var bunyan = require('bunyan');
var loggingBunyan = require('@google-cloud/logging-bunyan')();

var logger = bunyan.createLogger({
name: 'my-service',
streams: [loggingBunyan.stream('info')]
});

logger.error('warp nacelles offline');
logger.info('shields at 99%');
```

## Authentication

It's incredibly easy to get authenticated and start using Google's APIs. You can set your credentials on a global basis as well as on a per-API basis. See each individual API section below to see how you can auth on a per-API-basis. This is useful if you want to use different accounts for different Google Cloud services.

### On Google Cloud Platform

If you are running this client on Google Cloud Platform, we handle authentication for you with no configuration. You just need to make sure that when you [set up the GCE instance][gce-how-to], you add the correct scopes for the APIs you want to access.

``` js
var bunyan = require('bunyan');
var loggingBunyan = require('@google-cloud/logging-bunyan')();

var logger = bunyan.createLogger({
name: 'my-service',
streams: [loggingBunyan.stream('info')]
});

// ...you're good to go!
```

### Elsewhere

If you are not running this client on Google Cloud Platform, you need a Google Developers service account. To create a service account:

1. Visit the [Google Developers Console][dev-console].
2. Create a new project or click on an existing project.
3. Navigate to **APIs & auth** > **APIs section** and turn on the following APIs (you may need to enable billing in order to use these services):
* Stackdriver Logging API
4. Navigate to **APIs & auth** > **Credentials** and then:
* If you want to use a new service account key, click on **Create credentials** and select **Service account key**. After the account key is created, you will be prompted to download the JSON key file that the library uses to authenticate your requests.
* If you want to generate a new service account key for an existing service account, click on **Generate new JSON key** and download the JSON key file.

``` js
var bunyan = require('bunyan');
var loggingBunyan = require('@google-cloud/logging-bunyan')({
projectId: 'grape-spaceship-123',

// The path to your key file:
keyFilename: '/path/to/keyfile.json'

// Or the contents of the key file:
credentials: require('./path/to/keyfile.json')
});

var logger = bunyan.createLogger({
name: 'my-service',
streams: [loggingBunyan.stream('info')]
});

// ...you're good to go!
```

[bunyan]: https://github.com/trentm/node-bunyan
[@google-cloud/logging]: https://www.npmjs.com/package/@google-cloud/logging
[gce-how-to]: https://cloud.google.com/compute/docs/authentication#using
[dev-console]: https://console.developers.google.com/project
46 changes: 46 additions & 0 deletions packages/logging-bunyan/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"name": "@google-cloud/logging-bunyan",
"version": "0.0.0",
"author": "Google Inc.",
"description": "Stackdriver Logging stream for Bunyan",
"main": "./src/index.js",
"files": [
"src",
"AUTHORS",
"CONTRIBUTORS",
"COPYING"
],
"repository": "googlecloudplatform/google-cloud-node",
"keywords": [
"google apis client",
"google api client",
"google apis",
"google api",
"google",
"google cloud platform",
"google cloud",
"cloud",
"google logging",
"logging",
"stackdriver logging",
"stackdriver",
"bunyan stream",
"winston"
],
"dependencies": {
"@google-cloud/logging": "^0.7.0"
},
"devDependencies": {
"bunyan": "^1.8.5",
"proxyquire": "^1.7.11"
},
"scripts": {
"publish-module": "node ../../scripts/publish.js logging-winston",
"test": "mocha test/*.js",
"system-test": "mocha system-test/*.js --no-timeouts --bail"
},
"license": "Apache-2.0",
"engines": {
"node": ">=0.12.0"
}
}
134 changes: 134 additions & 0 deletions packages/logging-bunyan/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
/*!
* Copyright 2017 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/*!
* @module logging-bunyan
*/

'use strict';

var logging = require('@google-cloud/logging');

/**
* Map of Stackdriver logging levels.
*
* @type {object}
* @private
*/
var BUNYAN_TO_STACKDRIVER = {
60: 'critical',
50: 'error',
40: 'warning',
30: 'info',
20: 'debug',
10: 'debug'
};

/**
* This module provides support for streaming your bunyan logs to
* [Stackdriver Logging]{@link https://cloud.google.com/logging}.
*
* If your app is running on Google Cloud Platform, all configuration and
* authentication is handled for you. We also auto-detect the appropriate
* resource descriptor to report the log entries against.
*
* If you are running your application in anther environment, such as locally,
* on-premise, or on another cloud provider, you will need to provide additional
* configuration.
*
* @constructor
* @alias module:logging-bunyan
*
* @param {object} options - [Configuration object](#/docs). Refer to this link
* for authentication information.
* @param {string=} options.logName - The name of the log that will receive
* messages written to this bunyan stream. Default: `bunyan_Log`.
* @param {object=} options.resource - The monitored resource that the log
* stream corresponds to. On Google Cloud Platform, this is detected
* automatically, but you may optionally specify a specific monitored
* resource. For more infromation see the
* [official documentation]{@link
* https://cloud.google.com/logging/docs/api/reference/rest/v2/MonitoredResource}
*
* @example
* var bunyan = require('bunyan');
* var loggingBunyan = require('@google-cloud/logging-bunyan')({
* projectId: 'grape-spaceship-123',
* keyFilename: '/path/to/keyfile.json',
* resource: {
* type: 'global'
* }
* });
*
* var logger = bunyan.createLogger({
* name: 'my-service',
* streams: [loggingBunyan.stream('info')]
* });
*
*/
function LoggingBunyan(options) {
if (!(this instanceof LoggingBunyan)) {
return new LoggingBunyan(options);
}

options = options || {};

this.logName_ = options.logName || 'bunyan_log';
this.resource_ = options.resource;
this.log_ = logging(options).log(this.logName_);
}

/**
* Convenience method that Builds a bunyan stream object that you can put in
* the bunyan streams list.
*
* @example
* var bunyan = reuqire('bunyan');
* var stackdriverBunyan = require('@google-cloud/logging-bunyan')(options);
* var logger = bunyan.createLogger({
* name: 'my-service',
* streams: [ stackdriverBunyan.stream('info') ]
* });
*
* @param {(string|number)} level - A bunyan logging level. Log entries at or
* above this level would be routed to Stackdriver Logging.
*/
LoggingBunyan.prototype.stream = function(level) {
return {level: level, type: 'raw', stream: this};
};

/**
* Relay a log entry to the logging agent. This is normally called by bunyan.
*
* @param {object} rec - Bunyan log record.
* @private
*/
LoggingBunyan.prototype.write = function(rec) {
if (typeof rec === 'string') {
throw new Error(
'@google-cloud/logging-bunyan only works as a raw bunyan stream type.');
}
var level = BUNYAN_TO_STACKDRIVER[rec.level];
var entryMetadata = {resource: this.resource_, timestamp: rec.time};

var entry = this.log_.entry(entryMetadata, rec);

// Pass a no-op function because otherwise we get an unnecessary promise
// allocated and returned to us.
this.log_[level](entry, function() {});
};

module.exports = LoggingBunyan;
96 changes: 96 additions & 0 deletions packages/logging-bunyan/system-test/logging-bunyan.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*!
* Copyright 2017 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

var assert = require('assert');
var bunyan = require('bunyan');

var env = require('../../../system-test/env.js');

var logging = require('@google-cloud/logging')(env);
var loggingBunyan = require('../')(env);

describe('LoggingBunyan', function() {
var WRITE_CONSISTENCY_DELAY_MS = 20000;

var logger = bunyan.createLogger(
{name: 'system-test', streams: [loggingBunyan.stream('info')]});

describe('write', function() {

it('should properly write log entries', function(done) {
var timestamp = new Date();

var testData = [
{
args: ['first'],
verify: function(entry) {
assert.strictEqual(entry.data.msg, 'first');
assert.strictEqual(entry.data.pid, process.pid);
}
},

{
args: [new Error('second')],
verify: function(entry) {
assert.strictEqual(entry.data.msg, 'second');
assert.strictEqual(entry.data.pid, process.pid);
}
},
];

var earliest = {
args: [{time: timestamp}, 'earliest'],
verify: function(entry) {
assert.strictEqual(entry.data.msg, 'earliest');
assert.strictEqual(entry.data.pid, process.pid);
assert.strictEqual(entry.metadata.timestamp.toString(),
timestamp.toString());
}
};

// Forcibly insert a delay to cause 'third' to have a deterministically
// earlier timestamp.
setTimeout(function() {
testData.forEach(function(test) {
logger.info.apply(logger, test.args);
});
// `earliest` is sent last, but it should show up as the earliest entry.
logger.info.apply(logger, earliest.args);
// insert into list as the earliest entry.
testData.unshift(earliest);
}, 10);

setTimeout(function() {
logging.log('bunyan_log')
.getEntries({pageSize: testData.length}, function(err, entries) {
assert.ifError(err);
assert.strictEqual(entries.length, testData.length);

// Make sure entries are valid and are in the correct order.
entries.reverse().forEach(function(entry, index) {
var test = testData[index];
test.verify(entry);
});

done();
});
}, WRITE_CONSISTENCY_DELAY_MS);
});

});
});
Loading

0 comments on commit 0e63ff0

Please sign in to comment.